Haxorware Forums
Flashing 25L SPI EEPROM with Arduino - Printable Version

+- Haxorware Forums (http://www.haxorware.com/forums)
+-- Forum: General (http://www.haxorware.com/forums/forumdisplay.php?fid=6)
+--- Forum: Modems (http://www.haxorware.com/forums/forumdisplay.php?fid=7)
+--- Thread: Flashing 25L SPI EEPROM with Arduino (/showthread.php?tid=3775)



Flashing 25L SPI EEPROM with Arduino - oreo999 - 08-10-2015

Hi,

Here's how you can flash your 25L series using Arduino if you don't want to buy some jtag thing you can't reuse. I think you can even get these locally now.

Code modified from http://www.sodnpoo.com/posts.xml/arduino_mx25l_4mb_flash.xml

Code:
/*
MX25L3205D

Requires PC side sending \n (Newline) as line ending
*/

#include <SPI.h>

const int slaveSelectPin = 48;

void setup() {
  Serial.begin(115200);

  pinMode (slaveSelectPin, OUTPUT);

  // initialize SPI:
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV16);
}

void Print_Help(){
  Serial.println(" h        : print help");  
  Serial.println(" d        : print RDID");  
  Serial.println(" s        : print RDSR");  
  Serial.println(" u<x> <y> : dump from x for y bytes");
  Serial.println(" m<x> <y> : Write x for y bytes");
  Serial.println(" w        : WREN (write enable)");
  Serial.println(" i        : WRDI (write disable)");
  Serial.println(" e<sector>: SE (sector erase)");
  Serial.println(" b<block> : BE (block erase)");
  Serial.println(" q<x> <y> : PP write byte y at address x");
}

unsigned long SerialReadLongUntil(char until){
  String s;
  char c = 0;        
  while(c != until){
    if(Serial.available() > 0){
      c = Serial.read();
      s += c;
    }
  }
  char buf[16];
  s.toCharArray(buf, 16);
  return (unsigned long)strtol(buf, NULL, 0);  
}

void loop() {

  if (Serial.available() > 0) {
    switch(Serial.read()){
      
      case 'h':
        Print_Help();
      break;
      case 'd':
        Print_RDID();
      break;
      case 's':
        Print_RDSR();
      break;
      
      case 'u': { //some validation would be nice...
        unsigned long start = SerialReadLongUntil(' ');
        unsigned long len = SerialReadLongUntil('\n');
        Dump(start, len);
        break;
      }
      case 'm': { //some validation would be nice...
        unsigned long start = SerialReadLongUntil(' ');
        unsigned long len = SerialReadLongUntil('\n');
        WriteChunk(start, len);
        break;
      }
      case 'w':
        WREN();
      break;
      case 'i':
        WRDI();
      break;
//      case 'c':
//        CE();
//      break;
      case 'e': {
        unsigned long addr = SerialReadLongUntil('\n');
        _SE(addr);
        break;
      }
      case 'b': {
        unsigned long addr = SerialReadLongUntil('\n');
        BE(addr);
        break;
      }
      
      case 'q': { //write a single byte
        unsigned long addr = SerialReadLongUntil(' ');
        byte val = SerialReadLongUntil('\n');
        WritePP1(addr, val);
        Dump(addr, 1);
        break;
      }
      
    }
  }

}

/*
(6) Read Data Bytes (READ)
The read instruction is for reading data out. The address is latched on rising edge of SCLK, and data shifts out on the falling
edge of SCLK at a maximum frequency fR. The first address byte can be at any location. The address is automatically
increased to the next higher address after each byte data is shifted out, so the whole memory can be read out at a single
READ instruction. The address counter rolls over to 0 when the highest address has been reached.
The sequence of issuing READ instruction is: CS# goes low-> sending READ instruction code-> 3-byte address on SI
-> data out on SO-> to end READ operation can use CS# to high at any time during data out. (see Figure. 17)
*/
void READ(){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x03); //READ
  SPI.transfer(0x00); // start at 0x000000
  SPI.transfer(0x00);
  SPI.transfer(0x00);
  unsigned long addr = 0x000000;
  while(addr <= 0x3FFFFF){ //3FFFFFh 32 Mb
    byte val = SPI.transfer(0x00);
    Serial.println(val, HEX);
    addr++;
  }
  digitalWrite(slaveSelectPin,HIGH);  
}
/*
(3) Read Identification (RDID)
The RDID instruction is for reading the manufacturer ID of 1-byte and followed by Device ID of 2-byte. The MXIC
Manufacturer ID is C2(hex), the memory type ID is 20(hex) as the first-byte device ID, and the individual device ID of
second-byte ID are listed as table of "ID Definitions".
The sequence of issuing RDID instruction is: CS# goes low-> sending RDID instruction code -> 24-bits ID data out on SO
-> to end RDID operation can use CS# to high at any time during data out. (see Figure. 14)
While Program/Erase operation is in progress, it will not decode the RDID instruction, so there's no effect on the cycle of
program/erase operation which is currently in progress. When CS# goes high, the device is at standby stage.
*/
void RDID(byte *manufacturerID, byte *memorytypeID, byte *memory){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x9f);
  *manufacturerID = SPI.transfer(0x00);
  *memorytypeID = SPI.transfer(0x00);
  *memory = SPI.transfer(0x00);
  digitalWrite(slaveSelectPin,HIGH);
}

void Print_RDID(){
  byte manufacturerID, memorytypeID, memory;
  RDID(&manufacturerID, &memorytypeID, &memory);
  
  Serial.print("manufacturerID: ");
  Serial.println(manufacturerID, HEX);
  Serial.print("memorytypeID:   ");
  Serial.println(memorytypeID, HEX);
  Serial.print("memory:         ");
  Serial.println(memory, HEX);
}

/*
(4) Read Status Register (RDSR)
The RDSR instruction is for reading Status Register Bits. The Read Status Register can be read at any time (even in
program/erase/write status register condition) and continuously. It is recommended to check the Write in Progress (WIP)
bit before sending a new instruction when a program, erase, or write status register operation is in progress.
The sequence of issuing RDSR instruction is: CS# goes low-> sending RDSR instruction code-> Status Register data out
on SO (see Figure. 15)
*/
void RDSR(byte *rdsr){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x05);
  *rdsr = SPI.transfer(0x00);
  digitalWrite(slaveSelectPin,HIGH);  
}

void Print_RDSR(){
  byte rdsr = 0;
  RDSR(&rdsr);
  
  Serial.print("WIP : ");
  Serial.println(rdsr & 1);
  Serial.print("WEL : ");
  Serial.println(rdsr >> 1 & 1);
  Serial.print("BP0 : ");
  Serial.println(rdsr >> 2 & 1);
  Serial.print("BP1 : ");
  Serial.println(rdsr >> 3 & 1);
  Serial.print("BP2 : ");
  Serial.println(rdsr >> 4 & 1);
  Serial.print("BP3 : ");
  Serial.println(rdsr >> 5 & 1);
  Serial.print("CP  : ");
  Serial.println(rdsr >> 6 & 1);
  Serial.print("SRWD: ");
  Serial.println(rdsr >> 7 & 1);
}

/*
(1) Write Enable (WREN)
The Write Enable (WREN) instruction is for setting Write Enable Latch (WEL) bit. For those instructions like PP, CP, SE,
BE, CE, and WRSR, which are intended to change the device content, should be set every time after the WREN instruction
setting the WEL bit.
The sequence of issuing WREN instruction is: CS# goes low-> sending WREN instruction code-> CS# goes high. (see
Figure 12)
*/
void WREN(){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x06);
  digitalWrite(slaveSelectPin,HIGH);  
}

/*
The Write Disable (WRDI) instruction is for resetting Write Enable Latch (WEL) bit.
The sequence of issuing WRDI instruction is: CS# goes low-> sending WRDI instruction code-> CS# goes high. (see Figure
13)
*/
void WRDI(){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x04);
  digitalWrite(slaveSelectPin,HIGH);  
}

/* chip erase */
void CE(){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x60);
  digitalWrite(slaveSelectPin,HIGH);  
}

/* sector erase */
//needs the damn underscore as SE is defined elsewhere...
void _SE(unsigned long addr){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0xd8);
  SPI.transfer(addr >> 16 & 0xff);
  SPI.transfer(addr >> 8 & 0xff);
  SPI.transfer(addr & 0xff);
  digitalWrite(slaveSelectPin,HIGH);  
}
/* block erase */
void BE(unsigned long addr){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0xd8);
  SPI.transfer(addr >> 16 & 0xff);
  SPI.transfer(addr >> 8 & 0xff);
  SPI.transfer(addr & 0xff);
  digitalWrite(slaveSelectPin,HIGH);  
}

void PP(){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x02);
  SPI.transfer(0x00); // start at 0x000000
  SPI.transfer(0x00);
  SPI.transfer(0x00);

  SPI.transfer('A');
  SPI.transfer('B');
  SPI.transfer('C');
  SPI.transfer('D');
  SPI.transfer('E');
  SPI.transfer('F');
  SPI.transfer('G');
  SPI.transfer('H');
  SPI.transfer('I');
  SPI.transfer('J');
  SPI.transfer('K');

  digitalWrite(slaveSelectPin,HIGH);  
}

void DumpStart(unsigned long count){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x03); //READ
  SPI.transfer(0x00); // start at 0x000000
  SPI.transfer(0x00);
  SPI.transfer(0x00);
  unsigned long addr = 0x000000;
  while(addr < count){ //3FFFFFh 32 Mb
    byte val = SPI.transfer(0x00);
    Serial.print(addr, HEX);
    Serial.print('\t');
    Serial.print('\t');
    Serial.print(val, HEX);
    Serial.print('\t');
    Serial.println(char(val));
    addr++;
    //delay(100);
  }
  digitalWrite(slaveSelectPin,HIGH);  
}

void Dump(unsigned long addr, unsigned long count){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x03); //READ
  SPI.transfer(addr >> 16 & 0xff);
  SPI.transfer(addr >> 8 & 0xff);
  SPI.transfer(addr & 0xff);
  //Serial.print("Begin Dump at ");
  //Serial.print(addr,HEX);
  //Serial.print(" for ");
  //Serial.print(count,HEX);
  //Serial.println("::::::");
  count = addr + count;
  while(addr < count){ //3FFFFFh 32 Mb
    byte val = SPI.transfer(0x00);
    //Serial.print(addr, HEX);
    //Serial.print('\t');
    //Serial.print('\t');
    //Serial.print(val, HEX);
    //Serial.print('\n');
    Serial.write(val);
    //Serial.print('\t');
    //Serial.println(char(val));
    addr++;
  }
  //Serial.println("::::::");
  digitalWrite(slaveSelectPin,HIGH);  
}

//char bigBuff[4096];

void waitWIP()
{
  byte WIPdone;
  while(1) {
    RDSR(&WIPdone);
    if ((WIPdone & 1) == 0)
      return;
  }
  
}

void WriteChunk(unsigned long addr, unsigned long len) {
  WREN();
  
  unsigned long blockStart=addr;
  while(blockStart < addr+len) {
    BE(blockStart);
    Serial.print("Erase Block: ");
    Serial.print(blockStart,HEX);
    Serial.println("\n");
    blockStart+=0x10000;
    waitWIP();
    WREN();
  }

  Serial.println("Ready for Data!");

  unsigned long numRx=0;
  char newVal;
  char isStopped=0;
  char numInBlock=256;
  while(numRx < len) {
    if(Serial.available() > 0) {
      newVal=Serial.read();
      WREN();
      WritePP1(addr+numRx,newVal);
      waitWIP();
      numRx++;
    }
    if(Serial.available() > 32 && isStopped == 0) {
      Serial.write(0x19);//Stop
      isStopped=1;
    }else if (Serial.available() <= 32 && isStopped == 1){
      Serial.write(0x17);//Start
      isStopped=0;
    }

    
    
  }

  Serial.println("Rx All Data!");
  
  
  WRDI();
  
}

void WritePP1(unsigned long addr, byte val){
  digitalWrite(slaveSelectPin,LOW);
  SPI.transfer(0x02);
  SPI.transfer(addr >> 16 & 0xff);
  SPI.transfer(addr >> 8 & 0xff);
  SPI.transfer(addr & 0xff);
  SPI.transfer(val);
  digitalWrite(slaveSelectPin,HIGH);  
}


Wire it up like this:
Arduino Pins
Look up your EEPROM's datasheet, but probably like this:
Pin 2: VCC (+ Volts)
Pin 7: Pin 48/some Digital Arduino pin--note, put a 10 ohm resistor in series here
Pin 8: MISO , connect directly
Pin 10: Ground, pick any pin on the arduino, make sure your ground for the 3.3v source and the arduino as well
Pin 15: MOSI , connect through a voltage divider like 1.3k ohm in series with 3.3k ohm to ground
Pin 16: SCLK , do the same voltage divider here

Power the board with 3.3v through the pin 2 or the ICSP power port. I used a pickit3 to do this, but you can just get a fixed 3.3v regulator and feed it from a wall wart.


Get RealTerm http://sourceforge.net/projects/realterm/ , run in XP compat mode.

Flash your arduino project then connect the realterm to the usb uart, via 115200. Type h to get the help thing to list, then type d and make sure the device ID matches your datasheet. If you get 00 or FF you need to power cycle, check voltages, etc. If you get garbage, it's probably a loose connection, ground loop, or the voltage on the chip is too high or too low. (probably too high)

To dump your flash, go to realterm, go to capture box, start capture to a file
Go to send, type u0 8388608\n in the box 1 and click send (start address, number of bytes 8MB is 8388608). You'll see Char Count go up to 8388608, then go to capture, click stop. Now that file is your full dump.

To write the flash, check out the boundaries for the images you want, for example from usbjtag. So you want to overwrite Image0, put m262144 3866624\n for starting address decimal 262144 number of bytes decimal 3866624. Press send and wait for it to say Ready for Data! -- it will erase all the blocks in the range.

Now go to Send and click send file, go to your image (the image size MUST match the number of bytes to write). Send that thing, you'll see some messages Xon Xoff but don't worry about it. If it stops doing anything and you don't get RX All Data! then you need to lower the baud rate of the serial (in Arduino and RealTerm) and try again.


Happy Flashing!


RE: Flashing 25L SPI EEPROM with Arduino - sebichef - 22-02-2016

Hello, thanks for your enthusiasm. Have anybody done this? Have anybody flashed SB5101 with this?