Building a working flash memory programmer.

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 -

/*
   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;
}

And here is the rest of the code -

// 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;
   }
}

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

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.

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.

FlaskProgBoard.png

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 GitHub - ComputerNerd/sst39sf040-avr: This is the avr-side of the SST39F040 flash programmer. 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 GitHub - ComputerNerd/sst39sf040-computerside: This is the other part of the SST39F040 that runs on the computer. Note that I do not take credit for rs232.c and rs232.h 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.

Got a schematic?

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.