Go Down

Topic: [SOLVED] Issuses with Programming Flash Memory AT49F040 Arduino UNO (Read 1 time) previous topic - next topic

jaching

Hey guys! First off, let me start off by saying that I really appreciate these forums because up until now I've been able to debug any Arduino related issues with a simple search on these forums.  

I'm posting here today regarding an issue with using the Arduino UNO as a NOR Flash chip programmer for an Atmel AT49F040 chip (Datasheet here).  The goal with this project is to build a programmable Gameboy Cartridge but I won't get into to much detail about that.

To tackle the problem of not enough I/O I decided to use 3 TI SN54HC595 Shift Registers and below is a block diagram of my current hardware setup.  The Arduino is connected to the address pins of the AT49F040 via the 3 shift registers, which share a Clock and Over-Riding Clear pins. IO0-IO7, OE,CE, and WE are connected directly to the Arduino.  The shift registers and the AT49F040 are powered by an external 5V supply.



Also the pinout if anybody's interested:
Code: [Select]

const int sDta = 10;
const int sClk = 11;
const int sLtch = 12;

const int oE = A0;
const int wE = A1;
const int cE = A2;

const int io0 = 2;
const int io1 = 3;
const int io2 = 4;
const int io3 = 5;
const int io4 = 6;
const int io5 = 7;
const int io6 = 8;
const int io7 = 9;


This is a strong assumption but I believe that I'm able to read an arbitrary address since (according to the datasheet) the read sequence is just:
  • Load the desired address on A0-A18
  • Set CE low
  • Set OE low
  • Read IO0-IO7


This leads to believe that the following code snippet should achieve just that.  (Where sDta is the Serial Data pin, sLtch is Over Ride Clear pin, sClk is the clock pin, and setInput() and setOutput() change pins IO0-IO7 to be inputs or outputs respectively.)

Code: [Select]

byte readChip(byte addrLsb, byte addrMsb)
{
  byte data = 0;
  setInput();  
    
  digitalWrite(sLtch, LOW);
  shiftOut(sDta, sClk, MSBFIRST, 0);
  shiftOut(sDta, sClk, MSBFIRST, addrMsb);
  shiftOut(sDta, sClk, MSBFIRST, addrLsb);
  digitalWrite(sLtch, HIGH);
  
  digitalWrite(cE, LOW);
  digitalWrite(oE, LOW);
  
  bitWrite(data, 0, digitalRead(io0));
  bitWrite(data, 1, digitalRead(io1));
  bitWrite(data, 2, digitalRead(io2));
  bitWrite(data, 3, digitalRead(io3));
  bitWrite(data, 4, digitalRead(io4));
  bitWrite(data, 5, digitalRead(io5));
  bitWrite(data, 6, digitalRead(io6));
  bitWrite(data, 7, digitalRead(io7));
  
  digitalWrite(cE, HIGH);
  digitalWrite(oE, HIGH);
  
  setOutput();

  return data;
}



The results I receive seem promising since I receive 0xFF and that is the default value for every address.  However, since I'm having trouble with writing to the device this might not mean anything.  I've changed the timing of the read to wait one clock cycle after dropping OE but that also returned 0xFF along with reading just before dropping OE which gave 0. This leads me to further believe that reading isn't a problem.

The write is a bit trickier but from what I've gathered writing a byte can be done like so:

  • Load the address
  • Set CE and WE to LOW in either order
  • Wait a min of 50ns
  • Load the Data
  • Set CE and WE to HIGH in whichever order you chose


But to actually write to the device you need to do the 4 bus cycle operation which consists of:
  • 5555 on the Address Bus, Load AA on the Data
  • 2AAA on the Address Bus,Load 55 on the Data
  • 5555 on the Address Bus,Load A0 on the Data
  • Your desired Address, Load the Data to write in


For loading a single byte I've tried the following snippet:

Code: [Select]

void loadByte(byte hiByte, byte midByte, byte lowByte, byte data){
  digitalWrite(sLtch, LOW);
  shiftOut(sDta, sClk, MSBFIRST, hiByte);
  shiftOut(sDta, sClk, MSBFIRST, midByte);
  shiftOut(sDta, sClk, MSBFIRST, lowByte);
  digitalWrite(sLtch, HIGH);
  
  digitalWrite(wE, LOW);
  digitalWrite(cE, LOW);
  
  __asm__("nop\n\t");

  digitalWrite(io0, bitRead(data, 7));
  digitalWrite(io1, bitRead(data, 6));
  digitalWrite(io2, bitRead(data, 5));
  digitalWrite(io3, bitRead(data, 4));
  digitalWrite(io4, bitRead(data, 3));
  digitalWrite(io5, bitRead(data, 2));
  digitalWrite(io6, bitRead(data, 1));
  digitalWrite(io7, bitRead(data, 0));
  
  digitalWrite(wE, HIGH);
  digitalWrite(cE, HIGH);
}


I tried using the above snippet for the four bus cycle write operation but upon reading an address to verify I still get 0xFF.  I've also wondered if it's possible that the Arduino takes too long to load the data so I also attempted this next snippet with the same result:

Code: [Select]

void loadByte(byte hiByte, byte midByte, byte lowByte, byte data){
  digitalWrite(sLtch, LOW);
  shiftOut(sDta, sClk, MSBFIRST, hiByte);
  shiftOut(sDta, sClk, MSBFIRST, midByte);
  shiftOut(sDta, sClk, MSBFIRST, lowByte);
  digitalWrite(sLtch, HIGH);
  
  digitalWrite(io0, bitRead(data, 7));
  digitalWrite(io1, bitRead(data, 6));
  digitalWrite(io2, bitRead(data, 5));
  digitalWrite(io3, bitRead(data, 4));
  digitalWrite(io4, bitRead(data, 3));
  digitalWrite(io5, bitRead(data, 2));
  digitalWrite(io6, bitRead(data, 1));
  digitalWrite(io7, bitRead(data, 0));

  digitalWrite(wE, LOW);
  digitalWrite(cE, LOW);
  
  __asm__("nop\n\t");


  digitalWrite(wE, HIGH);
  digitalWrite(cE, HIGH);
}


So what I'm wondering if it's possible that I'm either reading the timing sheet for the AT49F040 incorrectly or if the Arduino UNO is too slow to use as a programmer for this chip?

If anybody has any possible insight towards this issue I'd very much appreciate it.  Also, if you feel I'm missing any information please let me know as well.

Thanks,

Josh

jaching

For those interested, I ended up finding out the issue.  The functions provided by Arduino for setting individual pin logic levels are pretty slow so after some further research I found a library from jrraines that is significantly faster and interrupt safe.
 http://forum.arduino.cc/index.php?topic=46896.0

I also decided to use the SPI library to transfer which in turn changed the placement of the clock, and data pins to their respective slots in the library for SPI and also placed the latch on pin 10.  Below is my modified method for loadByte.

Code: [Select]

void loadByte(byte hiByte, byte midByte, byte loByte, byte data[])
{
  digitalWriteFast(sLtch, LOW);
  SPI.transfer(hiByte);
  SPI.transfer(midByte);
  SPI.transfer(loByte);
  digitalWriteFast(sLtch, HIGH);
 
  digitalWriteFast(wE, LOW);
  digitalWriteFast(cE, LOW);
 
  digitalWriteFast(io0, data[0]);
  digitalWriteFast(io1, data[1]);
  digitalWriteFast(io2, data[2]);
  digitalWriteFast(io3, data[3]);
  digitalWriteFast(io4, data[4]);
  digitalWriteFast(io5, data[5]);
  digitalWriteFast(io6, data[6]);
  digitalWriteFast(io7, data[7]);
 
  __asm__("nop\n\t"); 
 
  digitalWriteFast(wE, HIGH);
  digitalWriteFast(cE, HIGH);
}

CrossRoads

Have you got the SPI speed increased? Default is 4 MHz, 8 MHz is also available.

Instead of SPI.transfer, this can also be used to increase speeds at 8 MHz:
spdr = hiByte; nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
spdr = midByte; nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
spdr = loByte; nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;

vs waiting for the SPI.transfer library to interrupt out of the sequence
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.

fabian_12345

Your application is interesting, I would serve to fix some radios to those who fails AT49F040 in TSOP32 and like you to imagine the programmer and adapter for that in Argentina is very expensive, so if I can implement your solution would be spectacular.
You could spend more information ???
Thanks Fabian de Buenos Aires.

Go Up