[Solved] Flash Memory Programmer "AM29F040B"

When it works then try to read the flash. If the flash is programmed you may try to read first 8 addresses for example (when the flash is not programmed, erased, you will read FF).
Usually reading a byte from flash means:
0. CS, WE, OE are high - the default (these 3 signals must be normally high, except the read/write sequence)

  1. set the address
  2. CS to low
  3. OE to low
  4. small delay (ie 70ns) but not important to do it with arduino, as the arduino is slow enough
  5. read the data bus
  6. OE high
  7. CS high

Writing the flash is more complicated - to write a byte into the flash require ie. 4 bytes to be written at specific addresses in a special sequence (see datasheet):
5555H: AAH
2AAAH: 55H
5555H: A0H
Your_Address: Your_Data
Wait 10ms or do DATA POLLING

A byte is written:
0. CS, WE, OE are high - the default

  1. set the address and data
  2. CS to low
  3. WE to low
  4. if you write the special sequence byte a small delay (ie 70ns) but not important to do it with arduino, as the arduino is slow enough
  5. if you write Your_Data - wait ie 10ms or do POLLING of a specific DATA bit (see datasheet)
  6. WE high
  7. CS high

Erasing requires a special sequence too.

You have to study the writing algorithm, described on pages 9-17, or find a ready sw somewhere. The detailed timing diagrams are not important for you when working with arduino, except the write process - either you have to wait long enough, or you have to poll certain data bits until the flash is written (reading a flash takes 50-70ns, writing takes several msecs usually).
HTH

I appreciated your help pito,

In the attachement is the screenshot from command definition table of this Flash memory.

Regarding the read operation, I think it's very clear but can you be more specific about this :

  1. CS, WE, OE are high - the default (these 3 signals must be normally high, except the read/write sequence)

CS, WE, OE must be high except "Read/Write Sequence", So since we are in a read operation they can be LOW at the beginning no ?

Second thing, and this is what I can't understand. The writing require a command at special address and send a special data. So, If I understand what do you said and what the screenshot mean:

To write data I must do as following, correct me if I'm wrong:
0- OE goes HIGH.
1- set the address and data
2- CS to low
3- WE to low
4- Small delay or not.
5- Write "0x555" so it will be "0000000010101010101 in binary" and it will goes from A18 to A0.
6- Delay 70ns or not.
7- Send Special craft of data "0xAA" which is "10101010 in binary" and it will goes from D7 to D0.
8- Delay 10ms.
9- Write "0x2AA" which will be "0000000001010101010" and it will goes from A18 to A0.
10- Delay 70ns or not.
11- Send "0x55" data which will be "0010 10101" and it will goes from D7 to D0.
12- Delay 10ms.
13- Write "0x555" so it will be "0000000010101010101 in binary" and it will goes from A18 to A0.
14- Delay 70ns or not.
15- Send "0xA0" data which will be "10100000" and it will goes from D7 to D0.
16- Delay 10ms.
17- CS to Low.
18- WE to LOW.

I have some questions:

1- Is this a kind of algorithm or we can say instructions flow which I should write in arduino sketch to write data to the flash ?

2- How can I find out if I should send command (CS, OE, WE) at first after the set of the address, or after a sent of data. Can you show me that in the datasheet please ?

3- in the instructions above especially "Special command/sequence" are that what we called "operations unlock" ?

4- Are the delays important in Flash memory programming ?

5- the "command defintion" in the screenshot shows that must drive at first the 6 cycles at first to write (Special command/sequences) and there are no delays between them. Where you found that ?

I hope that those questions don't mind you, I have many others (about what should be first and the last ...) but I stop here until I understand those things or leave them for later. This is my first time which I use a Flash memory, so I'm a noob.

Regards.

Hello,

I did what you have said and I studied the timing diagram of reading and writing operations (Special command / Sequence).
I also tested my code below but without any result.

Below is my code:

Writing:

#define SERIALDATA 10
#define SERIALCLK 12
#define STORECLK 11

#define WE A3
#define OE A4
#define CE A5

#define OUT 0
#define IN  1

unsigned int addr = 0;
int count = 0;
unsigned int unlock = 0;

void ChangeMode(byte io)
{
  if (io) {
    pinMode(2, INPUT);
    pinMode(3, INPUT);
    pinMode(4, INPUT);
    pinMode(5, INPUT);
    pinMode(6, INPUT);
    pinMode(7, INPUT);
    pinMode(8, INPUT);
    pinMode(9, INPUT);
  }
  else
  {
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT);
    pinMode(4, OUTPUT);
    pinMode(5, OUTPUT);
    pinMode(6, OUTPUT);
    pinMode(7, OUTPUT);
    pinMode(8, OUTPUT);
    pinMode(9, OUTPUT);
  }
}

void setup()
{
  Serial.begin(19200);
  //Data read or write D0 - D7 - Pin9 - Pin2
  ChangeMode(OUT);
  
  //Shiftregister pins
  pinMode(STORECLK, OUTPUT);
  pinMode(SERIALCLK, OUTPUT);
  pinMode(SERIALDATA, OUTPUT);
  
  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(A5, OUTPUT);
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(A2, OUTPUT);
  
  digitalWrite(WE, HIGH);
  digitalWrite(CE, HIGH);
  digitalWrite(OE, HIGH);
  
}

void loop()
{ 
  Serial.println("START WRITING ...");
  
  for (addr = 0; addr <= 0xFFF; addr++)
  {
    //Send address to the memory  ...
  
    digitalWrite(STORECLK, LOW);
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (addr>>8));
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (addr&0xFF));
    digitalWrite(STORECLK, HIGH);
    
    //write the same data ...
    delay(1);
    
    digitalWrite(2, HIGH);
    digitalWrite(3, HIGH);
    digitalWrite(4, HIGH);
    digitalWrite(5, HIGH);
    
    digitalWrite(6, LOW);
    digitalWrite(7, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    
    digitalWrite(WE, LOW); //Write disabled
    digitalWrite(CE, LOW); //Chip disable
    
    //Write 0x555 
    unlock = 0x555;
    
    digitalWrite(STORECLK, LOW);
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (unlock>>8));
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (unlock&0xFF));
    digitalWrite(STORECLK, HIGH);
    delay(1);
    //Write 0xAA
    digitalWrite(2, LOW);
    digitalWrite(3, HIGH);
    digitalWrite(4, LOW);
    digitalWrite(5, HIGH);
    digitalWrite(6, LOW);
    digitalWrite(7, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
     
    delayMicroseconds(10);
    
    //Write 2AA
    unlock = 0x2AA;
    
    digitalWrite(STORECLK, LOW);
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (unlock>>8));
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (unlock&0xFF));
    digitalWrite(STORECLK, HIGH);
    delay(1);
    //send 0x55 data
    digitalWrite(2, HIGH);
    digitalWrite(3, LOW);
    digitalWrite(4, HIGH);
    digitalWrite(5, LOW);
    digitalWrite(6, HIGH);
    digitalWrite(7, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(9, LOW);
    
    delayMicroseconds(10);
    
    //Write again 0x555 §Sequence
    
    unlock = 0x555;
    
    digitalWrite(STORECLK, LOW);
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (unlock>>8));
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (unlock&0xFF));
    digitalWrite(STORECLK, HIGH);
    
    //Write 0xA0 command
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    digitalWrite(6, LOW);
    digitalWrite(7, HIGH);
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
    
    delayMicroseconds(10);
    
    digitalWrite(WE, HIGH);
    digitalWrite(CE, HIGH);
  }
  
  Serial.print("FINAL STEP, PLEASE WAIT ");
  for (int c = 0; c < 3; c++) {
    Serial.print(".");
    delay(1000);
  }
  delay(1000);
  Serial.println("");
  Serial.println("WRITING COMPLETE.");
  
  while(1)
  delay(50);
}

Reading:

#define SERIALDATA 10
#define SERIALCLK 12
#define STORECLK 11

#define WE A3
#define OE A4
#define CE A5

#define OUT 0
#define IN  1

unsigned int addr = 0;
byte data = 0;
int counter = 0;
boolean val = LOW;

void ChangeMode(byte io)
{
  if (io) {
    pinMode(2, INPUT);
    pinMode(3, INPUT);
    pinMode(4, INPUT);
    pinMode(5, INPUT);
    pinMode(6, INPUT);
    pinMode(7, INPUT);
    pinMode(8, INPUT);
    pinMode(9, INPUT);
  }
  else
  {
    pinMode(2, OUTPUT);
    pinMode(3, OUTPUT);
    pinMode(4, OUTPUT);
    pinMode(5, OUTPUT);
    pinMode(6, OUTPUT);
    pinMode(7, OUTPUT);
    pinMode(8, OUTPUT);
    pinMode(9, OUTPUT);
  }
}

void setup()
{
  Serial.begin(19200);
  //Data read or write D0 - D7 - Pin9 - Pin2
  ChangeMode(IN);
  
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(A5, OUTPUT);
  
  //Shiftregister pins
  pinMode(STORECLK, OUTPUT);
  pinMode(SERIALCLK, OUTPUT);
  pinMode(SERIALDATA, OUTPUT);
  
  //Command register - default
  digitalWrite(WE, HIGH);
  digitalWrite(CE, HIGH);
  digitalWrite(OE, HIGH);
}

void loop()
{ 
  Serial.println("START READING");
  
  for (addr = 0; addr < 0xFFF; addr++)
  {
    digitalWrite(STORECLK, LOW);
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (addr>>8));
    shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (addr&0xFF));
    digitalWrite(STORECLK, HIGH);
    
    digitalWrite(CE, LOW);
    digitalWrite(OE, LOW);
    
    delayMicroseconds(7);
    
    for (int i = 2, j = 0; i <= 9; i++, j++)
    {
        val = digitalRead(i);
        if (val == HIGH)
            bitWrite(data, j, HIGH); 
    }
    
    digitalWrite(CE, HIGH);
    digitalWrite(OE, HIGH);
    
    Serial.print(data, HEX);
    Serial.print(" ");
    if (++counter == 32) {
      Serial.println("");
      counter = 0;
    }
    
  }
  
  Serial.println("");
  Serial.println("READING FINISH");
   
  while(1);
}

The reading always return 0xFF even if I execute the write code. Really, I don't understand why it's so easy when you read the datasheet but in real world is much complicated.

The datasheet is in the attachement file for a person who want to help me.

Thanks in advance.

AM29F040B.pdf (826 KB)

Try to create the following functions, ie.:

flash_ctrl_deselect(); // OE=HIGH, WE=HIGH, CS=HIGH, in this sequence
flash_ctrl_rd(); // CS=LOW, OE=LOW, in this sequence
flash_ctrl_wr(); // CS=LOW, WE=LOW, in this sequence

flash_addr_set(uint32 address);  // puts the flash address on the addressbus
flash_data_set(uint8 data); // writes data on the databus
uint8 flash_data_get(); // reads data from the databus

uint8 flash_read(uint32 address}; // reads the flash

boolean flash_get_DQ7(); // get DQ7 value
boolean flash_get_DQ6(); // get DQ6 value
boolean flash_get_DQ5(); // get DQ5 value
boolean flash_get_DQ3(); // get DQ3 value
boolean flash_get_DQ2(); // get DQ2 value
boolean flash_byte_write_poll(); // write polling, TRUE - byte write under process, FALSE - done
..
other pollings if required

flash_write_command(uint32 address, uint8 data); // writes a command to the flash command buffer
flash_write(uint32 address, uint8 data); // writes the data to the flash

flash_erase(); // erase the entire flash

Hi Pito,

As requested, this is code that I have wrote. Erase function still remain for later when write and read are functionnal:

#define SERIALDATA 10
#define SERIALCLK 12
#define LATCH 11

#define WE A3
#define OE A4
#define CE A5

#define A18 A0
#define A17 A1
#define A16 A2

#define OUT 0
#define IN  1

//Change pinMode of D0- D7
void flash_change_pins_mode(boolean io)
{
  if (io) {
    for (int i = 2; i < 10; i++)
    pinMode(i, INPUT);
  }
  else
  {
    for (int i = 2; i < 10; i++)
    pinMode(i, OUTPUT);
  }
}

void flash_ctrl_deselect()
{
  digitalWrite(OE, HIGH);
  digitalWrite(WE, HIGH);
  digitalWrite(CE, HIGH);
}

void flash_ctrl_rd_enable()
{
  digitalWrite(CE, LOW);
  digitalWrite(OE, LOW);
}

void flash_ctrl_rd_disable()
{
  digitalWrite(CE, HIGH);
  digitalWrite(OE, HIGH);
}

void flash_ctrl_wr_enable()
{
  digitalWrite(CE, LOW);
  digitalWrite(WE, LOW);
}

void flash_ctrl_wr_disable()
{
  digitalWrite(CE, HIGH);
  digitalWrite(WE, HIGH);
}

void flash_addr_set(unsigned int address)
{
  digitalWrite(LATCH, LOW);
  shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (address>>8));
  shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (address&0xFF));
  digitalWrite(LATCH, HIGH);
}

void flash_data_set(byte data)
{
  flash_change_pins_mode(OUT);
  for (int i = 0; i < 8; i++)
  {
    if (data&bit(i))
    digitalWrite(i+2, HIGH);
    else
    digitalWrite(i+2, LOW);
  }
}

byte flash_data_get()
{
  byte data = 0;
  boolean state = LOW;
  
  flash_change_pins_mode(IN);
  for (int i = 2, j = 0; i <= 9; i++, j++)
  {
        state = digitalRead(i);
        if (state == HIGH)
            bitWrite(data, j, HIGH); 
  }
  return data;
}

byte flash_read(unsigned int address)
{
  byte data = 0;
  
  flash_ctrl_deselect();
  flash_change_pins_mode(IN);
  
  flash_addr_set(address);
  flash_ctrl_rd_enable();
 
  delayMicroseconds(7);
  
  data = flash_data_get();
  flash_ctrl_rd_disable();
  return data;
}

boolean flash_get_DQ7()
{
  boolean state = LOW;
  
  pinMode(9, INPUT);
  state = digitalRead(9);
  if (state == HIGH)
  return true;
  else return false;
}

boolean flash_get_DQ6()
{
  unsigned long duration = 0;
  
  pinMode(8, INPUT);
  duration = pulseIn(8, HIGH);
  if (duration > 0)
  return true;
  else return false;
}

boolean flash_get_DQ5()
{
  boolean state = LOW;
  
  pinMode(7, INPUT);
  state = digitalRead(7);
  if (state == HIGH)
  return true;
  else return false;
}

boolean flash_get_DQ3()
{
  boolean state = LOW;
  
  pinMode(5, INPUT);
  state = digitalRead(5);
  if (state == HIGH)
  return true;
  else return false;
}

boolean flash_get_DQ2()
{
  boolean state = LOW;
  
  pinMode(4, INPUT);
  state = digitalRead(4);
  if (state == HIGH)
  return true;
  else return false;
}

//Check data
boolean flash_byte_write_poll()
{
  boolean state = LOW;
  state = flash_get_DQ7();
  if (state)
  return true; //Under process
  else return false; //Done
}

//Sequence/Command
void flash_write_command(unsigned int address, byte data)
{
    flash_change_pins_mode(OUT);
    flash_addr_set(address);
    flash_data_set(data);
}

void flash_write(unsigned int address, byte data)
{
  
  flash_ctrl_deselect();
  flash_change_pins_mode(OUT);
  
  //Set address and data
  flash_addr_set(address);
  flash_data_set(data);
  flash_ctrl_wr_enable();
  
  //Send command sequence
  flash_write_command(0x555, 0xAA);
  flash_write_command(0x2AA, 0x55);
  flash_write_command(0x555, 0xA0);
  
  flash_ctrl_wr_disable();
}

void flash_erase()
{
}

void setup()
{
  Serial.begin(9600);
  
  //Init A16 - A18 flash pins
  pinMode(A17, OUTPUT);
  pinMode(A16, OUTPUT);
  pinMode(A18, OUTPUT);
  
  //Init pin's shoft register
  pinMode(LATCH, OUTPUT);
  pinMode(SERIALCLK, OUTPUT);
  pinMode(SERIALDATA, OUTPUT);
  
  //Init flash command pins
  pinMode(WE, OUTPUT);
  pinMode(CE, OUTPUT);
  pinMode(OE, OUTPUT);
}

void loop()
{
  if (Serial.available() > 0)
  {
    if (Serial.read() == 'r') {
      int count = 0;
      Serial.println("");
      for (unsigned int addr = 0; addr < 0xFF; addr++) {
        Serial.print(flash_read(addr), HEX);
        Serial.print(" ");
        if (++count == 15) {
        Serial.println("");
        count = 0;
        }
      }
    }
    Serial.flush();
  }
  
  if (Serial.available() > 0)
  {
    if (Serial.read() == 'w')
    {
      for (unsigned int addr = 0; addr < 100; addr++)
      {
        byte value = 0xAB;
        Serial.println("");
        flash_write(addr, value);
        while (flash_byte_write_poll()) {
          Serial.print("*");
          delay(5);
        }  
        Serial.print("Byte ");
        Serial.print(addr);
        Serial.println(" Written");
      }  
      Serial.println("Operation complete");
    }
    Serial.flush();
  }
}

I tested it out but still no result.
There is one thing which I can't understand why I should execute device command at last ? shouldn't be at first ?

What I'm supposed to do now ?

Thanks.

First glance:
use only these 3 functions:

void flash_ctrl_deselect()
{
  digitalWrite(OE, HIGH);
  digitalWrite(WE, HIGH);
  digitalWrite(CE, HIGH);
}

void flash_ctrl_rd()
{
  digitalWrite(CE, LOW);
  digitalWrite(OE, LOW);
}

void flash_ctrl_wr()
{
  digitalWrite(CE, LOW);
  digitalWrite(WE, LOW);
}

Mind - for the addresses: the "unsigned int" is 16bit, you need "unsigned long" (or simply uint32).. !! 16+8bit!!

// read a single byte from flash
byte flash_read(unsigned long address)
{
  byte data = 0;  
  flash_ctrl_deselect();
  flash_change_pins_mode(IN);  
  flash_addr_set(address);
  flash_ctrl_rd();  // rd/oe goes LOW
  delayMicroseconds(1);  // 1usec is ok when reading the flash (70ns is min)  
  data = flash_data_get();
  flash_ctrl_deselect();  // rd/oe goes HIGH, cs goes HIGH
  return data;
}

BTW: Polling a bit on the data bus require "while()":

boolean flash_get_DQ7()
{...
while (...) ... ;
..
}

Mind - for the address: the "unsigned int" is 16bit, you need "unsigned long" (or simply uint32).. !! 16+8bit!!

void flash_addr_set(unsigned long address)
{
  digitalWrite(LATCH, LOW);

  // YOU HAVE TO SET THE HIGHEST 8BITS SOMEWHERE !!
  // for example a function:
  set_highest_flash_address(address>>16);

  shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (address>>8));
  shiftOut(SERIALDATA, SERIALCLK, MSBFIRST, (address&0xFF));
  digitalWrite(LATCH, HIGH);
}
// write flash Command - using min 70ns long write
void flash_write_command(unsigned long address, byte data)
{
    flash_ctrl_deselect();  
    flash_change_pins_mode(OUT);
    flash_addr_set(address);
    flash_data_set(data);
    flash_ctrl_wr();  //wr goes LOW
    delayMicroseconds(1);  // for example 1us delay
    flash_ctrl_deselect();    //wr goes HIGH, cs goes HIGH
}

YOU NEED:

// write flash memory Data byte - with 10ms delay or POLLING the data bit - see the datasheet
void flash_write_data(unsigned long address, byte data)
{
    flash_ctrl_deselect();  
    flash_change_pins_mode(OUT);
    flash_addr_set(address);
    flash_data_set(data);
    flash_ctrl_wr();   //wr goes LOW
    delay(10);  // for example 10ms delay OR POLLING THE DQ7
    flash_ctrl_deselect();    //wr goes HIGH, cs goes HIGH
}
// write single byte into the flash (Commands + Data)
void flash_write(unsigned long address, byte data)
{  
  //Send the command sequence
  flash_write_command(0x555, 0xAA);  //this is with 1usec delay (70ns is enough)
  flash_write_command(0x2AA, 0x55);  //this is with 1usec delay (70ns is enough)
  flash_write_command(0x555, 0xA0);  //this is with 1usec delay (70ns is enough)

//HERE YOU HAVE TO WRITE THE BYTE INTO THE FLASH:
  flash_write_data(address, data);  //this is a write with 10ms delay or with POLLING THE DQ7  
}

The last function in setup() shall be "flash_ctrl_deselect();" that is the default state !

Usually the next step is to check each function, whether it works properly or not (call the single function and check the pins with voltmeter or oscilloscope or logic analyzer). All above functions must work properly.

Be aware of pin direction setting. Double check.

Mind your address is more than 16bit! Try to write a single byte, and read it back. Do it for few addresses, step by step.
Do not expect it will work on the first attempt. It takes time.. There is a lot of signals and wirings you have to clean up.. It takes time..

Do not try to optimize/simplify the code unless it works - it means you flashed/erased your memory successfully at least 20x :slight_smile:

Do not use polling yet - use the 10-20ms delay as described above - 10ms is usually enough flash write time. Do not decrease the time yet. Rather wait few minutes to write the entire flash. When it works rock stable then you may start with code optimization and/or polling the DQx instead of using the fixed delay..
HTH

Hi pito and everyone,

Sorry for the late response.

I'm agree with you that programming flash will take time, this is why I decided to study and read over and over the datasheet to understand how the chip really works. However, I'm struggling to understand some sentences in the datasheet, if someone please can help me to find out what these phrases mean:

Byte Program Command Sequence

Programming is a four bus cycle operation. The program command sequence is initiated by writing two unlock write cycles, followed by the program set-up command. The program address and data are written next, which in turn initiate the Embedded Program algorithm. The system is not required to provide further controls or timings. The device automatically provides internally generated program pulses and verify the programmed cell margin. The command definitions take shows the address and data requirements for the byte program command sequence.

What's set-up command ? is the (CE#, OE#, WE#) command register ?
Is unlock write cycles contain address and data ?

Another one:

Programming is allowed in any sequence and across sector boundaries. A bit cannot be programmed from a "0" back to a "1". Attempting to do so may halt the operation and set DQ5 to "1".

Is that means that only erase operation can do this ?
How can I know if command registers (CS, WE, OE) are sent after a set of address and data or before ?

Please those questions are important for me to understand.

Regards.

What's set-up command ? is the (CE#, OE#, WE#) command register ?
Is unlock write cycles contain address and data ?

Read carefully the table 4.
Programming Set-up command is writing the 0Ah at the address 555h ("cycle" n.3).
(CE#, OE#, WE#) - those are just signals you have to bitbang during each cycle as required.
Unlock write cycles does contain address and data:
adr data

  1. cycle: 555 aa //unlock
  2. cycle: 2aa 55 //unlock
  3. cycle: 555 0a // setup command
  4. cycle: PA PD // actual address and data to be written into flash

Is that means that only erase operation can do this ?
How can I know if command registers (CS, WE, OE) are sent after a set of address and data or before ?

Yes.
(CS, WE, OE) - those are not command registers but signals. Those signals are set by calling
void flash_ctrl_deselect()
void flash_ctrl_rd()
void flash_ctrl_wr()..
You know where to sent them because you know how a typical rd/wr into a memory works.

Thanks for you quick reply,

Can you please be more specific about this:

You know where to sent them because you know how a typical rd/wr into a memory works.

My question was when can I send them ? Because reading the datasheet especially in Table 1 (Device bus operations), they just mention the requirements to read or write data, there is any order how to send them. To be more clear this is an example of what I mean

Should do like this:

1- flash_addr_set()
2-flash_data_set()
3-flash_ctrl_rd() //send address and data then enable read operation

or like this:

1- flash_ctrl_rd() //Enable read operation and send address and data
2-flash_addr_set()
3-Flash_data_set()

I would like to know the same thing about write and erase operation.

Thanks.

Set the address and data first, then do flash_ctrl_rd(). The same with write. Mind the delays. Erase is a sequence of commands (see table 4).

I made an sst39sf040 programmer you can base your programmer off my code see
This will run on your arduino uno note that I used avr-gcc to compile it instead of the arduino ide GitHub - ComputerNerd/sst39sf040-avr: This is the avr-side of the SST39F040 flash programmer.
This will run on your computer 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

Hi everyone,

Regarding the flash memory programming, I can say now that I can read the eeprom. I cleaned up the circuit (Pulldown resistors & shift registers ...). I'm sure now because when I take WE off it returns 0 rather than FF. (may be wrong please advise)

I used this logic to get data, any other way won't work I'll get just 0s:
flash_ctrl_deselect();
flash_ctrl_rd();
flash_addr_set();
flash_get_data();
flash_ctrl_deselect();

Howewer, the remaining challenge now is Writing program I can't actually figure out how to do this. I tried several algorithm from the writing timing Diagram without success.

Please in the attachement the timing diagram of Write operation, and below the flow of what I have understood from it. If there is any recommandation or correction please don't hesistate to do it to help me out:

Scenario 1:

  • CE high to low
  • OE HIGH
  • WE HIGH
  • Command 555
  • WE to LOW
  • Data command
  • WE to HIGH
  • CE High to low
  • PA
  • WE to LOW
  • PD
  • WE to HIGH
  • delay 10 us

Scenario 2:

  • CE high & WE HIGH & OE HIGH/li]
  • Address command 555h
  • CE to LOW
  • WE to LOW
  • data command A0h
  • WE to HIGH
  • PA
  • CE High to low
  • WE to LOW
  • PD
  • WE to HIGH
  • CE to HIGH
  • delay 10 us

What do you think about them ? what's the one that you think it may work for me.

Any other clue or idea will be appreciated.

Thanks.

Timing is critical when you are trying to run fast - like connected in circuit to a CPU. To read data -t is important that you properly set the address inputs before you try to set the chip selects. * WE or *OE can be set before the *OE. Timings on the chart are generally the minimums - meaning that there is a minimum time from the address line being set before the *CE and then some delay between the *CE before the *OE or *WE have to be stable. But a best practice is set the *OE or *WE at he same time the *OE is set.

To use some of the features - sector erase for instance - you do need to be able to control all address pins.

Thanks for this discussion - I missed it when I asked if anyone had any experience with these devices... I am preparing to build a Z80 CPM single board computer, and maybe even a 65C02 based board to play with. Will be making a Flash Programmer shield to program these devices.

Thanks for your reply kf2qd,

If understand, the timing is critical for any operations. I was thinking if it's possible to bypass this problem especially for those who are not familiar with electronics, to just use the AVR interrupts and check if there is any data coming from an external device (Like EEPROM or Flash) in the reading operation for instance.

I was thinking of that, because even my reading algorithm doesn't work too, and I try to figure out if there is any missing thing that I forgot (shiftregister didn't give the correct address, timings) . I have changed my code from the arduino style to AVR style to increase the speed of the functions, unfortunately, no result too. The remaining idea that I have now is the pinchange interrupts, after that, if nothing seems to work ... :.

I have a questions if someone can clarify these for me:
using the avr style code, Can I be able to receive and detect if there is any input coming from an external device even if the arduino pins are in output mode and not set to HIGH (Read PIND or PINB) ?
If the answer of the above question is yes why we whould change the pin mode ?
How can I test if my flash are working or not ? Because it's very weird that til now nothing is working for me.

Thanks and sorry for the inconvenience.

The timing is not critical with your application, as the arduino's bitbanging is much slower than the minimal timing requirements of the flash memory. As I wrote previously, try to get the stuff working in slow mode, speed optimization is long way to go (and not required for your programmer..

I was thinking of that, because even my reading algorithm doesn't work too

How do you know that? Do you have a programmed chip with known data in it? Or do you try to read empty chips?

You can take a memory chip. put it on a breadboard and wire it fir an address and then wire the *OE to ground and then wire the *CE to ground and it will put the data for that address on the data lines. timing is not a problem. That timing chart just shows the minimum times. Can't run the chip any faster than those timings. Can run it way slower...

Are you sure what you are putting on the address lines? Verify address inputs before you worry about anything else. If they aren't correct then everything else is a waste of time.

Several decades back we programmed PROMS and EEPROMs with 16+8 dil switches with 24 10k pullups, a 27V power source (w/ a pnp high side switch) and a push button (with a 7400 10ms mono). And it worked fine :slight_smile:

To answer you Pito,

How do you know that? Do you have a programmed chip with known data in it? Or do you try to read empty chips?

In fact, I don't know If the flash are empty or not, because I found a weird behavior: when I try to send a command sequence to the flash, the data is put too no problem here, however when I try to read data, is always equal the data puted before even if i changed the pins in the input mode. This is why I asked this question:

using the avr style code, Can I be able to receive and detect if there is any input coming from an external device even if the arduino pins are in output mode and not set to HIGH (Read PIND or PINB) ?

After several checks the data is always 0 not 0xFF as the flash should be, this is the reason that I was thinking about interrupts.
To answer you kf2qd I'am sure about the address lines I checked one by one using multiple addresses.

If you need something to check from your side (Code or circuit) don't hesitate to tell me.

Many thanks.

Here's a drawing of the schematic that will work with the programs that PITO created.

If there are any errors,please let me know Pito.

Pito - with your programs - how are you feeding the data to the programmer?

sst39sf010 PROGRAMMER.bmp (1.72 MB)

In fact, I don't know If the flash are empty or not, because I found a weird behavior: when I try to send a command sequence to the flash, the data is put too no problem here, however when I try to read data, is always equal the data puted before even if i changed the pins in the input mode.

When reading the flash you do not issue any special command sequence - you just read the flash with for example:

// read a single byte from flash
byte flash_read(unsigned long address)
{
  byte data = 0x00;  //try to change to 0xFF to see the difference
  flash_ctrl_deselect();
  flash_change_data_pins_mode(IN);  
  flash_addr_set(address);
  flash_ctrl_rd();  // rd/oe goes LOW
  delayMicroseconds(1);  // 1usec is ok when reading the flash (70ns is min)  
  data = flash_data_get();
  flash_ctrl_deselect();  // rd/oe goes HIGH, cs goes HIGH
  return data;
}

Pito - with your programs - how are you feeding the data to the programmer?

Frankly, last time I built my pc controlled eeprom programmer was in '87 where I did it by wiring a 8255A to Atari520ST' ACSI bus (an SCSI HDD bus), wrote a driver in asm, and the main program in gfbasic (or something called like that). I opened a file on the diskette, read binary and flashed a 27C512 EEPROM (Atari TOS upgrade,, six eeproms). That is all I can say to this topic.. :slight_smile:
Based on my experience with this stuff, it works fine when:

  1. you carefully check the wiring (many times..)
  2. you build the sw routines step by step, testing each function carefully
  3. you do not try to speedup/optimize the sw - do it slow and simple, ie connect LEDs to cs, oe, we (such it lits when active), add delays so you can see the sequence, when it works properly remove the delays.
  4. mind that by wiring error swapped data or address lines will write/read the flash properly (against the binary), but it will not work in your final hardware (unless you swap the lines there in the same way too)..

Feeding the data: that is the last issue I would mess with at this stage. First, try to flash several bytes (ie 4) to 4 addresses somewhere. Verify. Erase, and do it again (different data, different addresses). Repeat many times. When it works fine, then start to think how to pass the data (via serial, from an sdcard, etc).

@kf2qd: Your schematics: I would use 74HC or HCT 595 shifters, and do care about all its input pins (10.11.12.13.14) somehow..
PS: I would put pullups (ie an 8x10k sip module) on the data bus, thus I will read 0xFF even the memory is deselected.