Go Down

Topic: Building a working flash memory programmer. (Read 18747 times) previous topic - next topic

CrossRoads

Cool. Using direct port manipulation also for the control lines?
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

kf2qd

#16
Dec 10, 2013, 11:43 pm Last Edit: Dec 10, 2013, 11:51 pm by kf2qd Reason: 1
Haven't gotten there yet....

Some calulations, the right combination of ands and ors and iI should be able to make it work. The 3 control pins can all be set to HIGH when setting up the address pins so that does simplify the work to set the address lines. then the read and the write functions will do the ands and ors.    Hmmm, what's the idle state of the serial pins?

Got sidetracked playing with Eagle and produced a routed board in about 2 hours. And then I got distracted by trying to create some boards for the z80 CPM computer, can't call it a single board computer because of the board size limits fir the free version of Eagle mean I will need to stack a couple boards....

kf2qd

I got the board working using Direct Port Manipulation for all i/o to the SST39sf010 and the results are up in the air.

PORTA - PINA - write and read teh data lines.

PORTC - write address lines A0 - A7
PORTB - write address lines A8-A15

PORTD PD0 & PD1 are serial0, PD2 - A16, PD3 - A17, PD4 - A18, PD5 - ChipEnable, PD6 - OutputEnable, PD7 - WriteEnable.

Code: [Select]

void LoadAddr(unsigned long AddressL)
{
   unsigned long workAddrL;
   unsigned int PDHold;
   workAddrL = AddressL;
   PORTC = lowByte(workAddrL);
   PORTB = highByte(workAddrL);

   PDHold = PORTD & 0xE3;   // mask out the control bits and the serial port bits.
   PDHold= PDHold  | ((workAddrL >> 14) & 0x1C);  // address bits 16, 17, 18 to PORTD bits 2, 3, 4
   PORTD = PDHold;

/*   
   workAddrL= workAddrL >> 16;
   digitalWrite(AB16, workAddrL & 1);
   workAddrL= workAddrL >> 1;
   digitalWrite(AB17, workAddrL & 1);
   workAddrL= workAddrL >> 1;
   digitalWrite(AB18, workAddrL & 1);
*/ 

}


I need to compare the highByte() and lowByte() functions to this -
   PORTC = workAddrL & 0xFF;
   workAddrL = workAddrL >> 8;
   PORTB = workAddrL & 0xFF;
  workAddrL = WorkAddrL >> 6;  // shift 6 because the 2 lowest bits of PORTD are the serial port
   workAddrL = workAddrL & 0x1C; // just bits 3, 4, 5
   PORTD = workAddrL | 0xE0; // top 3 bits need to be HIGH , are active LOW and I am just setting the address bits here.


I had to add 2 delays to give the control signals time to stabilize and have time to read or write the data to/from the device and I didn't gain any significant speedup over using digitalWrite s to set the top 3 address bits and 2 of the 3 enable pins. I am doing 32bit math, so the next thing would be to see if I could do 16 bit math and see if that would speed anything up, or if the extra code would just slow things down someplace else.

CrossRoads

Seems like the hard way to do things.
Just keep track of the address in 3 chunks. lower 8, next 8, upper whatever is left.
increment each individually, when one rolls over increment the next one.

lower8 = lower8 +1;
if (lower8 == 0){
upper8 = upper8 +1;
if (upper8 == 0){
highBits = highBits +1;
// and reset highBits to 0s when you start a new write sequence.
}
}
}
then
PORTB = lower8;
PORTC = upper8;
PORTD = PORTD & 0b11111000; // clear out the 3 bits
PORTD = PORTD | (highBits);

that's got to be a lot faster than 32 bit math and all that shifting.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

kf2qd

One step at a time. Make it function, and then change one thing at a time and keep it functioning.

kf2qd

Okay - Not got the 3 8-bit register stuff working, been playing around with Eagle and making schematics and related things.

But here's where the code is at for now.
I am controlling the address and control lines with Direct Port Manipulation. PORTA is the data lines(D0 - D7). PORTD is the lower 8 address lines (A0 - A7), PORTB is the middle 8 address lines (A8- A15) and PORTD is the upper 3 address lines and the Chip ENable lines (A16 - A18, !CE, !OE, !WE)


And here is the first part of the code, setuo and the shared functions -

Code: [Select]

/*
  FlashProgrammer for
  SST39SF010/020/040 series Flash Proms
  010 - 131,072 bytes
  020 - 262,144 bytes
  040 - 524,288 bytes  
 
  This code should work with ATMega164/324/644/1284
 
*/
// PORTA is data bits 0-7

// PORTC is address bits 0-7
// PORTB is address bits 8-15

int AB16 = 10;
int AB17 = 11;
int AB18 = 12;

int ChipEN = 13;
int ReadEN = 14;
int WriteEN = 15;

void setup()
{
  Serial.begin(115200);
 
  // set control signals to HIGH, all are active LOW
  pinMode(ChipEN,OUTPUT);
  digitalWrite(ChipEN,HIGH);
  pinMode(ReadEN,OUTPUT);
  digitalWrite(ReadEN,HIGH);
  pinMode(WriteEN,OUTPUT);
  digitalWrite(WriteEN,HIGH);
 
  // configure the address lines and set them all to LOW
  DDRC = 255;
  PORTC = 0;
  DDRB = 255;
  PORTB = 0;
  pinMode(AB16,OUTPUT);
  digitalWrite(AB16,0);
  pinMode(AB17,OUTPUT);
  digitalWrite(AB17,0);
  pinMode(AB18,OUTPUT);
  digitalWrite(AB18,0);
  Serial.println();
  Serial.println("SST39SF010/020/040 Flash Programmer");
}

// takes an address as an unsigned long and loads it into the address bits.
// when finished the address will be on the address lines and
// ChipEN, WriteEN, and ReadEN will be HIGH.
void LoadAddr(unsigned long AddressL)
{
  unsigned long workAddrL;
  unsigned int PDHold;
  workAddrL = AddressL;
  PORTC = lowByte(workAddrL);
  PORTB = highByte(workAddrL);

  PDHold = PORTD & 0xE3;
  PDHold= PDHold  |((workAddrL >> 14) & 0x1C);
  PORTD = PDHold;
}

// takes an address and returns the byte at that address
// calls LoadAddr()
byte DoRead(unsigned long readAddr)
{
  byte readVal;
  unsigned int PDHold;
  LoadAddr(readAddr);
  DDRA = 0;    // set port A as all inputs from Flash Data Lines
  PORTA=0xFF;
  PDHold = PORTD ;       // save PORTD bits
  PORTD = PDHold & 0x9F; // WriteEN HIGH, ChipEN & ReadEN LOW
  delay(1);              // let the signals settle
  readVal = PINA;        // Read the data
  PORTD = PDHold;        // Write the original value back to PORT D, All Enable bits high
  return readVal;
}

// takes an unsigned long address and a byte and writes them to the Flash
// calls LoadAddr()
void DoWrite(unsigned long writeAddr, byte writeVal)
{
   LoadAddr(writeAddr);
   DDRA = 255;    // set port A as all outputs to Flash Data Lines
   PORTA = writeVal;      // load the value to PORTA
   PORTD = PORTD & 0x5F;  // set ChipEN and WriteEN LOW
   delay(1);              // let the signals settle
   PORTD = PORTD | 0xE0;  // set ChipEN and WriteEN HIGH
}

// gets the device ID codes from the Flash.
// calls DoWrite() and DoRead()
void DeviceID()
{
  byte WorkByte;
  Serial.println();
  Serial.println("Device Identification");
  Serial.println();
  DoWrite(0x5555L,0xAA);   // First output byte of Software ID Entry
  DoWrite(0x2AAAL,0x55);   // Second output byte of Software ID Entry
  DoWrite(0x5555L,0x90);   // Third output byte of Software ID Entry
  WorkByte = DoRead(0L);   // Read address 0 for manufacturer ID
  if (WorkByte == 0xBF)
  {
     Serial.println("Chip Manufactured by SST");
  }
  else
  {
     Serial.print("Unkmown manufacturer : ");
     Serial.println(WorkByte,HEX);
  }
  WorkByte = DoRead(1L);   // Read address 1 for Chip ID
  if (WorkByte == 0xB5)
  {
     Serial.println("SST39SF010");
     Serial.println("128Kx8 Device");
     Serial.println("131,072 Bytes");
  }
  else if (WorkByte == 0xB6)
  {
     Serial.println(" SST39SF020");
     Serial.println("256Kx8 Device");
     Serial.println("262,144 Bytes");
  }
  else if (WorkByte == 0xB7)
  {
     Serial.println(" SST39SF040");
     Serial.println("512Kx8 Device");
     Serial.println("524,288 Bytes");
  }
  else
  {
     Serial.print(" Unknown Device : ");
     Serial.println(WorkByte,HEX);
  }
  Serial.println();
  DoWrite(0x5555L,0xF0);   // Exit ID Mode
}

// print an unsigned long as 5 HEX digits
void PrintHex5(unsigned long PrintVal)
{
  Serial.print((PrintVal >> 16) & 0xF,HEX);
  Serial.print((PrintVal >> 12) & 0xF,HEX);
  Serial.print((PrintVal >> 8) & 0xF,HEX);
  Serial.print((PrintVal >> 4) & 0xF,HEX);
  Serial.print(PrintVal & 0xF,HEX);
}  

// take 5 HEX digits and convert to unsigned long
unsigned long Asc52Long(char *srcStr)
{
  int ctr;
  int tmpChar;
  unsigned long tmpLong = 0L;
  for (ctr = 0; ctr < 5; ctr++)
  {
      tmpChar = srcStr[ctr];
      tmpChar = tmpChar & 0x4F;
      if (tmpChar > 9)
      {
         tmpChar = (tmpChar & 0xF) + 9;
      }
      tmpLong = (tmpLong << 4) + tmpChar;
  }
  return tmpLong;  
}

// take 2 hex digits and convert to byte
byte Asc22Byte(char *srcStr)
{
  int ctr;
  char tmpChar;
  char workChar = 0;
  for (ctr = 0; ctr < 2 ; ctr++)
  {
      tmpChar = srcStr[ctr];
      tmpChar = tmpChar & 0x4F;
      if (tmpChar > 9)
      {
         tmpChar = (tmpChar & 0xF) + 9;
      }
      workChar = (workChar << 4) + tmpChar;
  }
  return workChar;
}




kf2qd

And here is the rest of the code -

Code: [Select]

// reads 16 bytes from Flash starting at the address requested
// calls Asc52Long(), PrintHex5(), DoRead()
void ReadFlash()
{
   unsigned long ctr;
   unsigned long ReadAddrL;
   char ReadNiblLo, ReadNiblHi;
   char ctrPrt, readVal;
   
   char strAddress[8]={'\0','\0','\0','\0','\0','\0','\0','\0'};
   do
   {
      Serial.readBytes(strAddress,5);
   }while(strAddress[0]==0);
   ReadAddrL = Asc52Long(strAddress);
   //Serial.print("Starting address = ");
   //PrintHex5(ReadAddrL);
   //Serial.println();

   PrintHex5(ReadAddrL);
   Serial.print(":");
   for (ctr = ReadAddrL; ctr < (ReadAddrL + 0x10); ctr++)
   {
       readVal = DoRead(ctr);
       ReadNiblLo = readVal & 0xF;
       ReadNiblHi = (readVal >>4) &0xF;
       Serial.print(ReadNiblHi,HEX);
       Serial.print(ReadNiblLo,HEX);
   }
   Serial.println();
}
// Erases teh requested sector of the flash.
// flash is divided in to 4K blocks or sectors.
// a 2 digit HEX value is given and this is loaded
// into address lines 12 - 18, with all other adderss bits set to 0
// calls DoWrite()
void SectorErase()
{
   unsigned long EraseAddrL;
   char Sector[3]={'\0','\0','\0'};
   //Serial.println();
   //Serial.println("Write to Flash");
   //Serial.println("Sector to Write -");
   //Serial.println("00 to 1F for SST39SF010");   
   //Serial.println("00 to 3F for SST39SF020");   
   //Serial.println("00 to 7F for SST39SF040");   
   do
   {
      Serial.readBytesUntil(13,Sector,2);
   }while(Sector[0]==0);
   Sector[0]= Sector[0] & 0x0F;
   Sector[0]= Sector[0] <<4;
   Sector[1]= Sector[1] - 0x30;
   if (Sector[1] > 0x9)
   {
      Sector[1] = (Sector[1] & 0xF) + 9;
   }
   EraseAddrL = Sector[0] | Sector[1];
   EraseAddrL = EraseAddrL << 12;
   //Serial.print("Starting address = ");
   PrintHex5(EraseAddrL);
   Serial.println();
   DoWrite(0x5555L,0xAA);   // First output byte of Sector Erase
   DoWrite(0x2AAAL,0x55);   // Second output byte of Sector Erase
   DoWrite(0x5555L,0x80);   // Third output byte of Sector Erase
   DoWrite(0x5555L,0xAA);   // Fourth output byte of Sector Erase
   DoWrite(0x2AAAL,0x55);   // Fifth output byte of Sector Erase
   DoWrite(EraseAddrL,0x30);   // Sector Address and 0x30 Sector Erase Command
}

// writes 16 bytes to Flash starting at the given address
// command format is a "W", 5 HEX digits, a colon":", and 16 bytes as 2 digit HEX
// after writing the 16 bytes are read and sent to the Serial port.
// calls Asc52Long(), Asc22byte(),DoWrite(), PrintHex5(); DoRead()
void WriteFlash()
{
    unsigned long ctr;
   unsigned long WriteAddrL;
   char ReadNiblLo, ReadNiblHi;
   char  readVal, writeVal, hexVal[3];
   char strAddress[8]={'\0','\0','\0','\0','\0','\0','\0','\0'};
   char chkColon[3] ={'\0','\0','\0'};
   char WriteData[33] = {'\0','\0','\0','\0','\0','\0',
                         '\0','\0','\0','\0','\0','\0',
                         '\0','\0','\0','\0','\0','\0',
                         '\0','\0','\0','\0','\0','\0',
                         '\0','\0','\0','\0','\0','\0',
                         '\0','\0','\0'};
   do
   {
      Serial.readBytes(strAddress,5);
   }while(strAddress[0]==0);
   WriteAddrL = Asc52Long(strAddress);
   //Serial.println(WriteAddrL,HEX);
   do
   {
      Serial.readBytes(chkColon,1);
   }while(chkColon[0]==0);
   do
   {
      Serial.readBytes(WriteData,32);
   }while(WriteData[0]==0);
   for (ctr = 0 ; ctr <  16; ctr++)
   {
      hexVal[0] = WriteData[ctr *2];
      hexVal[1] = WriteData[ctr *2 + 1];
      hexVal[3] = 0;
      writeVal = Asc22Byte(hexVal);
      DoWrite(0x5555L,0xAA);   // First output byte of Byte Program
      DoWrite(0x2AAAL,0x55);   // Second output byte of Byte Program
      DoWrite(0x5555L,0xA0);   // Third output byte of of Byte Program
      DoWrite(WriteAddrL+ctr,writeVal);   // Address and Data to store
      delay(1);
   }
   PrintHex5(WriteAddrL);
   Serial.print(":");   
   for (ctr = 0 ; ctr <  16; ctr++)
   {
      readVal = DoRead(WriteAddrL+ctr);
      ReadNiblLo = readVal & 0xF;
      ReadNiblHi = (readVal >>4) &0xF;
      Serial.print(ReadNiblHi,HEX);
      Serial.print(ReadNiblLo,HEX);
   }
   Serial.println();
}


void Help()
{
   Serial.println();
   Serial.println("(I)d - to read the SoftwareID");
   Serial.println("(R)ead - to Read the contents of a sector");
   //Serial.println("(E)rase - to Erase the entire chip");
   Serial.println("(S)ector - to erase a Sector");
   Serial.println("(W)rite - to Write code to the Flash");
   Serial.println();
}

void loop()
{
   char Command[3];
   Command[0]=0;
   Command[1]=0;
   Command[2]=0;
   //Serial.print("Command(IRESW?) - ");
   do
   {
      Serial.readBytesUntil(13,Command,1);
   }while(Command[0]==0);
   
   Command[0] = Command[0] &0x5F;
   delay(100);
   // Serial.println(Command[0],HEX);
   switch (Command[0])
   {
      case 0x1f: // '?' display Help
                 Help();
                 break;
      case 0x45: // 'Ee' Erase device
                 // not implemented.
                 break;
      case 0x49: // 'Ii' device Id
                 DeviceID();
                 break;
      case 0x52: // 'Rr' Read flash
                 // command is in the form R00000
                 // address is 5 digit HEX
                 // will print 00000:000102030405060708090a0b0c0d0e0f
                 // 5 digit HEX address, colon, 32 HEX digits forrepresenting 16 bytes
                 ReadFlash();
                 break;
      case 0x53: // Ss' erase Sector
                 // command is in the form S00
                 // address is 2 digit HEX
                 SectorErase();
                 break;
      case 0x57: // 'Ww' Write to flash
                 // command is in the form W00000:000102030405060708090a0b0c0d0e0f
                 // "W", 5 HEX digits, a colon, and 16 2digit HEX bytes to be written
                 // Will return a Read of the written bytes in the same format as the read command.
                 WriteFlash();
                 break;
   }
}

kf2qd

#22
Dec 19, 2013, 05:59 pm Last Edit: Dec 20, 2013, 03:41 am by kf2qd Reason: 1
I have added a wire list - I exported from Eagle and edited. Inserted here using the TELETYPE button.

U$1 is an ATMega164/324/644/1284
U$2 is an SST39SF010/020/040 or equiv.
U$3 is a 10K Resistor
U$4 is a Normally Open Push Button sWITCH ( Switch has 4 pins, pins 1 & 2 re wired together, pins 3 & 4 are wired together)
U$5 is a 16MHz resonator
P$nn is a pin number

And I have also uploaded the schematic.

Here's the wire list.

Signal   Part     Pad      Pin   to   Part     Pad      Pin

!CE      U$1      P$19     PD5        U$2      P$22     *CE
!OE      U$1      P$20     PD6        U$2      P$24     *OE
!WE      U$1      P$21     PD7        U$2      P$31     *WE

A0       U$1      P$22     PC0        U$2      P$12     A0
A1       U$1      P$23     PC1        U$2      P$11     A1
A2       U$1      P$24     PC2        U$2      P$10     A2
A3       U$1      P$25     PC3        U$2      P$9      A3
A4       U$1      P$26     PC4        U$2      P$8      A4
A5       U$1      P$27     PC5        U$2      P$7      A5
A6       U$1      P$28     PC6        U$2      P$6      A6
A7       U$1      P$29     PC7        U$2      P$5      A7
A8       U$1      P$1      PB0        U$2      P$27     A8
A9       U$1      P$2      PB1        U$2      P$26     A9
A10      U$1      P$3      PB2        U$2      P$23     A10
A11      U$1      P$4      PB3        U$2      P$25     A11
A12      U$1      P$5      PB4        U$2      P$4      A12
A13      U$1      P$6      PB5        U$2      P$28     A13
A14      U$1      P$7      PB6        U$2      P$29     A14
A15      U$1      P$8      PB7        U$2      P$3      A15
A16      U$1      P$16     PD2        U$2      P$2      A16
A17      U$1      P$17     PD3        U$2      P$30     P$2
A18      U$1      P$18     PD4        U$2      P$1      P$1

D0       U$1      P$40     PA0        U$2      P$13     D0
D1       U$1      P$39     PA1        U$2      P$14     D1
D2       U$1      P$38     PA2        U$2      P$15     D2
D3       U$1      P$37     PA3        U$2      P$17     D3
D4       U$1      P$36     PA4        U$2      P$18     D4
D5       U$1      P$35     PA5        U$2      P$19     D5
D6       U$1      P$34     PA6        U$2      P$20     D6
D7       U$1      P$33     PA7        U$2      P$21     D7

+5V      U$1      P$10     VCC
        U$1      P$30     AVCC  
        U$2      P$32     *5V
        U$3      P$1      P$1
        U$6      P$5      +5V

GND      U$1      P$11     GND
        U$1      P$31     GND
        U$2      P$16     GND
        U$4      P$3      P$2
        U$4      P$4      P$2
        U$5      P$1      GND
        U$6      P$4      GND

RESET    U$1      P$9      *RESET
        U$3      P$2      P$2
        U$4      P$1      P$1
        U$4      P$2      P$1

XTAL     U$1      P$13     XTAL1      U$5      P$2      XLAL1
        U$1      P$12     XTAL2      U$5      P$3      XTAL2

TXD      U$1      P$15     TX0        U$6      P$3      RXD

RXD      U$1      P$14     RX0        U$6      P$2      TXD



CrossRoads

That .png is tough to read.
White background would be easier to see.
Would also help if you could crop it so the actual schematic part is larger.
Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

kf2qd

And here is a board layout. Single Sided, Red lines are wires on the top side of the board, and blue are teh traces on the bottom.

Mr_arduino

Just reading this topic and and though my information would be relevant.
I made a sst39sf040 programmer using an arduino uno and 3 74hc595.Here is the wiring: Pin refers to the numbering on the arduino uno. The D0:D4 to go A0 to A4 D5:D7 go to Pins digital pins 5 to 7 Pin 11 CE# Pin 12 OE# Pin 13 WE# Pin 10 is the serial strobe for the shift register this must be connected to all 3 shift registers Pin 9 is the storage register this also must be connected to all 3 shift registers. Pins 2,3 and 4 is the serial output pins 2 is the LSB. Unlike pin 9 and 10 those are different per each shift register. A0:A18 goto the output from the 3 shift registers. Make sure you have which one is LSB and MSB right. I will warn you that this can get messy as there are lots of wires be careful and check your work. My program verifies every byte if you see any errors check your wiring. Here is the part that runs on the arduino uno https://github.com/ComputerNerd/sst39sf040-avr Note that I used avr-gcc instead of the arduino IDE to compile this if you do not have avr-gcc it can be modified with ease just change int main() to void setup() and add void loop() {} at the bottom of the program and I think it will compile just fine in the arduino IDE. And here is the part that runs on your computer I have only tested it on linux but I used a cross platform library so it may work on windows https://github.com/ComputerNerd/sst39sf040-computerside Also my code can be easily adapted to run on the very similar lower capacity chips. The sst39sf020a and the sst39sf010a. Just change the main for loop to run for less bytes.

CrossRoads

Designing & building electrical circuits for over 25 years.  Screw Shield for Mega/Due/Uno,  Bobuino with ATMega1284P, & other '328P & '1284P creations & offerings at  my website.

Mr_arduino

No I never bothered to make one. I did explain how to wire it and I do have a picture of it but the wires are messy.

Go Up