Unable to write/read to all areas of 25LC1024 EEPROM

Hi,

I am using a library for the 25LC1024 EEPROM that I found here. I had to modify it very slightly to make it work with the Particle Photon.

Reading and writing works fine except across a specific page boundary at address 32,768 (max int16, coincidence?)

I can write and read across page boundary’s before and after the boundary at 37,768.
I can write and read within pages either side of the boundary at 32,768.

Here is the code I am using to test the writing and reading:

char buffer[]="{1458215700,c=1,t=0}";
uint16_t length = strlen(buffer) + 1;
uint32_t address = 32762; <-- Change this to set start of write and read

//Create check buffer
char checkBuffer[length];
checkBuffer[0] = '\0';

Serial.printf("Address: %d\r\n", address);
Serial.printf("Length: %d\r\n", length);

//Save item to EEPROM
buffer[length - 1] = '.'; //Replace '\0' with '.'
Serial.printf("Write success: %d\r\n", _spieep->writen(address, buffer, length));
buffer[length - 1] = '\0';
Serial.printf("Write buffer: %s\r\n", buffer);

//Read back item from EEPROM
Serial.printf("Read success: %d\r\n", _spieep->readn(address, checkBuffer, length));
checkBuffer[length - 1] = '\0';
Serial.printf("Read buffer: %s\r\n", checkBuffer);

Here are the write and read functions from the library with my extra logging added in:

boolean SPIEEP::writen(uint32_t p, byte *buf, uint16_t len) {
  uint32_t idx, e, pg_i_e, wrlen, i;  /* idx = start of current read block, e = last read address + 1,
                                       * pg_i_e = address of last byte in idx's current page + 1,
                                       * wrlen = # bytes to write in current block
                                       */

  if (!verify_enabled()) return false;

  if ((p+len-1) > _highestaddr) return false;

  idx = p;
  e = p+len;
  do {
    pg_i_e = (idx/_pagesize)*_pagesize + _pagesize;
    Serial.printf("WRITE. Page size: %d, idx: %d, pg: %d\r\n", _pagesize, idx, pg_i_e);
    if (e > pg_i_e)
    {
      wrlen = pg_i_e - idx;
      Serial.printf("Writing over page bounday. wrlen: %d\r\n", wrlen);
    }
    else
    {
      wrlen = e - idx;
      Serial.printf("Writing within page bounday. wrlen: %d\r\n", wrlen);
    }

      // Perform write for this block
      wren();
      if (!is_wren())
        return false;  // Couldn't enable WREN for some reason?
      digitalWrite(_cspin, LOW);
      if (_is_25LC040)
        SPI.transfer(_compose_instruction_addrbit(idx, SPIEEP_WRITE));
      else
        SPI.transfer(SPIEEP_WRITE);
        _write_address(idx);
        for (i=0; i<wrlen; i++)
        {
          SPI.transfer(buf[idx-p+i]);
          Serial.printf("Writing byte no: %d, which holds: %c\r\n", idx-p+i, (char)buf[idx-p+i]);
        }
      digitalWrite(_cspin, HIGH);

      if (!_write_validation())
        return false;  // A failed write, abort before performing any more.

      idx += wrlen;
  } while (idx < e);

  return true;
}

boolean SPIEEP::readn(uint32_t p, byte *buf, uint16_t len) {
  uint32_t idx, e, pg_i_e, rdlen, i;  /* idx = start of current read block, e = last read address + 1,
                                       * pg_i_e = address of last byte in idx's current page + 1,
                                       * rdlen = # bytes to read in current block
                                       */

  if (!verify_enabled()) return false;

  if ((p+len-1) > _highestaddr) return false;

  idx = p;
  e = p+len;
  do {
    pg_i_e = (idx/_pagesize)*_pagesize + _pagesize;
    Serial.printf("READ. Page size: %d, idx: %d, pg: %d\r\n", _pagesize, idx, pg_i_e);
    if (e > pg_i_e)
    {
      rdlen = pg_i_e - idx;
      Serial.printf("Reading over page bounday. rdlen: %d\r\n", rdlen);
    }
    else
    {
      rdlen = e - idx;
      Serial.printf("Reading within page bounday. rdlen: %d\r\n", rdlen);
    }

      // Perform read for this block
      digitalWrite(_cspin, LOW);
      if (_is_25LC040)
        SPI.transfer(_compose_instruction_addrbit(idx, SPIEEP_READ));
      else
        SPI.transfer(SPIEEP_READ);
        _write_address(idx);
        for (i=0; i<rdlen; i++)
        {
          buf[idx-p+i] = SPI.transfer(0x0);
          Serial.printf("Reading byte no: %d, which holds: %c\r\n", idx-p+i, (char)buf[idx-p+i]);
        }
      digitalWrite(_cspin, HIGH);

      idx += rdlen;
  } while (idx < e);

  return true;
}

and I get the following results (last result is the one that writes over the page boundary at 37,768 and does not work correctly)

Writing within first page - NOT CROSSING BOUNDARY
INFO LOG - Thu Mar 17 11:55:00 2016 - Saving item: {1458215700,c=1,t=0}
Address: 128
Length: 21
WRITE. Page size: 256, idx: 128, pg: 256
Writing within page bounday. wrlen: 21
Writing byte no: 0, which holds: {
Writing byte no: 1, which holds: 1
Writing byte no: 2, which holds: 4
Writing byte no: 3, which holds: 5
Writing byte no: 4, which holds: 8
Writing byte no: 5, which holds: 2
Writing byte no: 6, which holds: 1
Writing byte no: 7, which holds: 5
Writing byte no: 8, which holds: 7
Writing byte no: 9, which holds: 0
Writing byte no: 10, which holds: 0
Writing byte no: 11, which holds: ,
Writing byte no: 12, which holds: c
Writing byte no: 13, which holds: =
Writing byte no: 14, which holds: 1
Writing byte no: 15, which holds: ,
Writing byte no: 16, which holds: t
Writing byte no: 17, which holds: =
Writing byte no: 18, which holds: 0
Writing byte no: 19, which holds: }
Writing byte no: 20, which holds: .
Write success: 1
Write buffer: {1458215700,c=1,t=0}
READ. Page size: 256, idx: 128, pg: 256
Reading within page bounday. rdlen: 21
Reading byte no: 0, which holds: {
Reading byte no: 1, which holds: 1
Reading byte no: 2, which holds: 4
Reading byte no: 3, which holds: 5
Reading byte no: 4, which holds: 8
Reading byte no: 5, which holds: 2
Reading byte no: 6, which holds: 1
Reading byte no: 7, which holds: 5
Reading byte no: 8, which holds: 7
Reading byte no: 9, which holds: 0
Reading byte no: 10, which holds: 0
Reading byte no: 11, which holds: ,
Reading byte no: 12, which holds: c
Reading byte no: 13, which holds: =
Reading byte no: 14, which holds: 1
Reading byte no: 15, which holds: ,
Reading byte no: 16, which holds: t
Reading byte no: 17, which holds: =
Reading byte no: 18, which holds: 0
Reading byte no: 19, which holds: }
Reading byte no: 20, which holds: .
Read success: 1
Read buffer: {1458215700,c=1,t=0}

Writing within first page - CROSSING BOUNADRY
INFO LOG - Thu Mar 17 11:57:00 2016 - Saving item: {1458215820,c=1,t=0}
Address: 250
Length: 21
WRITE. Page size: 256, idx: 250, pg: 256
Writing over page bounday. wrlen: 6
Writing byte no: 0, which holds: {
Writing byte no: 1, which holds: 1
Writing byte no: 2, which holds: 4
Writing byte no: 3, which holds: 5
Writing byte no: 4, which holds: 8
Writing byte no: 5, which holds: 2
WRITE. Page size: 256, idx: 256, pg: 512
Writing within page bounday. wrlen: 15
Writing byte no: 6, which holds: 1
Writing byte no: 7, which holds: 5
Writing byte no: 8, which holds: 8
Writing byte no: 9, which holds: 2
Writing byte no: 10, which holds: 0
Writing byte no: 11, which holds: ,
Writing byte no: 12, which holds: c
Writing byte no: 13, which holds: =
Writing byte no: 14, which holds: 1
Writing byte no: 15, which holds: ,
Writing byte no: 16, which holds: t
Writing byte no: 17, which holds: =
Writing byte no: 18, which holds: 0
Writing byte no: 19, which holds: }
Writing byte no: 20, which holds: .
Write success: 1
Write buffer: {1458215820,c=1,t=0}
READ. Page size: 256, idx: 250, pg: 256
Reading over page bounday. rdlen: 6
Reading byte no: 0, which holds: {
Reading byte no: 1, which holds: 1
Reading byte no: 2, which holds: 4
Reading byte no: 3, which holds: 5
Reading byte no: 4, which holds: 8
Reading byte no: 5, which holds: 2
READ. Page size: 256, idx: 256, pg: 512
Reading within page bounday. rdlen: 15
Reading byte no: 6, which holds: 1
Reading byte no: 7, which holds: 5
Reading byte no: 8, which holds: 8
Reading byte no: 9, which holds: 2
Reading byte no: 10, which holds: 0
Reading byte no: 11, which holds: ,
Reading byte no: 12, which holds: c
Reading byte no: 13, which holds: =
Reading byte no: 14, which holds: 1
Reading byte no: 15, which holds: ,
Reading byte no: 16, which holds: t
Reading byte no: 17, which holds: =
Reading byte no: 18, which holds: 0
Reading byte no: 19, which holds: }
Reading byte no: 20, which holds: .
Read success: 1
Read buffer: {1458215820,c=1,t=0}


Writing within page after address 32,768 - NOT CROSSING BOUNDARY
INFO LOG - Thu Mar 17 11:52:00 2016 - Saving item: {1458215520,c=1,t=0}
Address: 32800
Length: 21
WRITE. Page size: 256, idx: 32800, pg: 33024
Writing within page bounday. wrlen: 21
Writing byte no: 0, which holds: {
Writing byte no: 1, which holds: 1
Writing byte no: 2, which holds: 4
Writing byte no: 3, which holds: 5
Writing byte no: 4, which holds: 8
Writing byte no: 5, which holds: 2
Writing byte no: 6, which holds: 1
Writing byte no: 7, which holds: 5
Writing byte no: 8, which holds: 5
Writing byte no: 9, which holds: 2
Writing byte no: 10, which holds: 0
Writing byte no: 11, which holds: ,
Writing byte no: 12, which holds: c
Writing byte no: 13, which holds: =
Writing byte no: 14, which holds: 1
Writing byte no: 15, which holds: ,
Writing byte no: 16, which holds: t
Writing byte no: 17, which holds: =
Writing byte no: 18, which holds: 0
Writing byte no: 19, which holds: }
Writing byte no: 20, which holds: .
Write success: 1
Write buffer: {1458215520,c=1,t=0}
READ. Page size: 256, idx: 32800, pg: 33024
Reading within page bounday. rdlen: 21
Reading byte no: 0, which holds: {
Reading byte no: 1, which holds: 1
Reading byte no: 2, which holds: 4
Reading byte no: 3, which holds: 5
Reading byte no: 4, which holds: 8
Reading byte no: 5, which holds: 2
Reading byte no: 6, which holds: 1
Reading byte no: 7, which holds: 5
Reading byte no: 8, which holds: 5
Reading byte no: 9, which holds: 2
Reading byte no: 10, which holds: 0
Reading byte no: 11, which holds: ,
Reading byte no: 12, which holds: c
Reading byte no: 13, which holds: =
Reading byte no: 14, which holds: 1
Reading byte no: 15, which holds: ,
Reading byte no: 16, which holds: t
Reading byte no: 17, which holds: =
Reading byte no: 18, which holds: 0
Reading byte no: 19, which holds: }
Reading byte no: 20, which holds: .
Read success: 1
Read buffer: {1458215520,c=1,t=0}


Writing with page before address 32,768 - CROSSING BOUNDARY
INFO LOG - Thu Mar 17 12:00:00 2016 - Saving item: {1458216000,c=1,t=0}
Address: 32762
Length: 21
WRITE. Page size: 256, idx: 32762, pg: 32768
Writing over page bounday. wrlen: 6
Writing byte no: 0, which holds: {
Writing byte no: 1, which holds: 1
Writing byte no: 2, which holds: 4
Writing byte no: 3, which holds: 5
Writing byte no: 4, which holds: 8
Writing byte no: 5, which holds: 2
WRITE. Page size: 256, idx: 32768, pg: 33024
Writing within page bounday. wrlen: 15
Writing byte no: 6, which holds: 1
Writing byte no: 7, which holds: 6
Writing byte no: 8, which holds: 0
Writing byte no: 9, which holds: 0
Writing byte no: 10, which holds: 0
Writing byte no: 11, which holds: ,
Writing byte no: 12, which holds: c
Writing byte no: 13, which holds: =
Writing byte no: 14, which holds: 1
Writing byte no: 15, which holds: ,
Writing byte no: 16, which holds: t
Writing byte no: 17, which holds: =
Writing byte no: 18, which holds: 0
Writing byte no: 19, which holds: }
Writing byte no: 20, which holds: .
Write success: 1
Write buffer: {1458216000,c=1,t=0}
READ. Page size: 256, idx: 32762, pg: 32768
Reading over page bounday. rdlen: 6
Reading byte no: 0, which holds: {
Reading byte no: 1, which holds: 1
Reading byte no: 2, which holds: 4
Reading byte no: 3, which holds: 5
Reading byte no: 4, which holds: 8
Reading byte no: 5, which holds: 2
READ. Page size: 256, idx: 32768, pg: 33024
Reading within page bounday. rdlen: 15
Reading byte no: 6, which holds: Reading byte no: 7, which holds: 6 <-- looks like even byte numbers contain '\0'?
Reading byte no: 8, which holds: Reading byte no: 9, which holds: 0
Reading byte no: 10, which holds: Reading byte no: 11, which holds: ,
Reading byte no: 12, which holds: Reading byte no: 13, which holds: =
Reading byte no: 14, which holds: Reading byte no: 15, which holds: ,
Reading byte no: 16, which holds: Reading byte no: 17, which holds: =
Reading byte no: 18, which holds: Reading byte no: 19, which holds: }
Reading byte no: 20, which holds: Read success: 1
Read buffer: {14582

It looks like all the even bytes are being set to ‘\0’?

The weird thing is the data sheet says you can read back data in one go without worrying about page boundaries but the library does read in blocks up to each boundary. I tried reading all in one go but that prevented any cross boundary read from giving the correct data back.

I would really appreciate any advice on potential causes for this.

Cheers

Hi @joe4465

You don’t show in your code how you setup the SPIEEP class with the values passed into the contructor for page size, etc. I would check those since they are critical to the calculation being done about whether or not a page boundary is being crossed. If the code gets the page boundary wrong, the part will just wrap the address in the same 256-byte page.

This part also has hardware write protection via the Write Status Register so that is worth checking as well. Can you write addresses above 32768 in general?

Try using a more unique data stream for testing since if wrapping is occurring, you might not notice with static data like you have now.

It looks like you have raised an issue for the library author as well, so maybe he or she can help you out.

I checked the WRSR register using the following code so I don’t think the write protection is turned on.

byte ret = readstatus();
if(((ret >> SPIEEP_STATUS_BP0) & 0x1) == 0x1) Serial.printf("bp0: 1\r\n");
if(((ret >> SPIEEP_STATUS_BP1) & 0x1) == 0x1) Serial.printf("bp1: 1\r\n");

Cheers

1 Like

Hi,

I have stripped my code right back to a main.ino that replicates the issue.

#include "application.h"
#include "SPIEEP.h"

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);

SPIEEP* _spieep;

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

    _spieep = new SPIEEP(24, 256, 131072);
    _spieep->begin_spi(A2);

    Serial.printf("Finished setup\r\n");
}

void loop()
{
    static uint32_t addr = 0;
    static uint8_t retry = 0;

    char writeBuffer[] = "{1458299823,c=1,t=0}";
    uint8_t length = strlen(writeBuffer) + 1;

    char readBuffer[length];
    readBuffer[0] = '\0';

    //Serial.printf("writeBuffer: %s\r\n", writeBuffer);

    if(!_spieep->writen(addr, writeBuffer, length)) Serial.println("Writing failed");
    if(!_spieep->readn(addr, readBuffer, length)) Serial.println("Reading failed");
    readBuffer[length - 1] = '\0';

    //Serial.printf("readBuffer: %s\r\n", readBuffer);

    if(strcmp(writeBuffer, readBuffer) != 0 && retry < 3) ++retry;
    else if(strcmp(writeBuffer, readBuffer) != 0  && retry == 3)
    {
        Serial.printf("Data does not match at address: %d\r\n", addr);
        retry = 0;
        addr += 10;
    }
    else addr += 10;

    if(addr == 131010) delay(1200000);
    if(addr % 10000 == 0) Serial.printf("Address: %d\r\n", addr);

    delay(5);
}

With this code I can write/read successfully between 0 - 32,750 and between 65,440 - 98,290. I cannot write/read successfully between 32,750 - 65,440 and 98,290 - 130,980. Essentially I can write to the first and third quarters and I cannot write to the second and fourth quarters.

I have looked through the library and it seems to match the data sheet.

To modify the library I removed the #include <Arduino.h> line from the top of SPIEEP.h and replaced it with #include "application.h". I also changed the begin() function from:

void SPIEEP::begin(int cspin) {
  // SPI needs to be enabled prior to initialization of this object
  if ((SPCR >> SPE) & 0x1) {
    _cspin = cspin;
    pinMode(_cspin, OUTPUT);
    digitalWrite(_cspin, HIGH);  // CS pin is high when idle.
  } else
    _cspin = -1;  // If SPI was not enabled, disable this library!
}

to:

void SPIEEP::begin(int cspin) {
  _cspin = cspin;
  pinMode(_cspin, OUTPUT);
  digitalWrite(_cspin, HIGH);
}

Any ideas?

Cheers

Hi @joe4465

Those numbers don’t make sense to me as a software problem.

Have you tried another 25LC1024 or other SPI EEPROM?

Hi @bko

I have tried 3 different PCB’s that are all the same design and contain a photon and a 25LC1024.
All of them exhibit the same behavior.

The writes between 0 and 32,740 succeed as none of them cross the page boundary at 32,768
The write at 32,750 fails as it crosses the page boundary at 32,768. All subsequent writes up to and crossing the page boundary at 65,536 fail.
The writes between 65,540 and 98,280 succeed as none of them cross the page boundary at 65,536 and 98,304.
The write at 98,290 fails as it crosses the page boundary at 98,304. All subsequent writes up to the page boundary at 131,072 fail.

One thing I have noticed is that in the quarters that do not work I can write to the pages when the start address is at least 23 bytes into the page and the write does not roll over to the next page.

e.g. address 65,303 in page 255 does not work whilst address 65,304 in page 255 does work
e.g. address 39,959 in page 156 does not work whilst address 39,960 in page 156 does work

Thanks for you help.

Well, that is great information and you most likely have software problem if you have identical results on three boards. I searched all the code you pointed to for an int16_t type which could wrap and cause problems somewhat similar to what you are seeing, but did not find any.

Have you tried reading and writing one byte at a time instead in a block using the read() and write() methods? That uses a different code path in the library.

It is still not clear to me if you have reading or a writing problem–can you tell for sure which side is failing? Maybe the byte read/writes will tell you.

Have you tried the test_chip() method?

I would try making your serial debug statements shorter (just on general principle) since you can take a lot of time queuing bytes for the UART in the middle of some of the SPI functions. This is not likely to be hurting you right now and is more of a general concern.

Thanks @bko,

The test chip method always passes and I have had this in my code all along - good point to check though.

At the moment I do not know whether it is the read or write which is failing. However I think its the read - if you look at the last test result in the first post the read does work but only for the odd numbered bytes after the page boundary. Do you have any idea how I could find out for sure which side is failing?

I have just tried the byte write/read. It fails at address 65,303 and works at address 65,304. It fails at address 39,959 and works at address 39,960. Byte write/read code snippet below.

void loop()
{

    static uint32_t addr = 39960;
    byte b = (byte)255;
    byte c = (byte)0;

    Serial.printf("b before: %x\r\n", b);
    Serial.printf("c before: %x\r\n", c);

    if (!_spieep->write(addr, b)) {
        Serial.println("Trouble writing to EEPROM address 0x0010!");
    }

    c = _spieep->read(addr);

    Serial.printf("b after: %x\r\n", b);
    Serial.printf("c after: %x\r\n", c);
}

I’m looking at the signal with a logic analyser now but struggling to see the data on MISO and MOSI even when a write/read is successful. Do these settings sound correct? MSB first, 8 bits per transfer, CPOL = 0, CPHA = 1, CS is active low.

Thanks again

2 Likes

ahhhhhh just noticed this in the particle SPI documentation:

SPI.setClockDividerReference(SPI_CLK_ARDUINO);

I added that line and I can now read and write to all areas of the EEPROM :smile:

Going to do some more tests now but it looks promising… I hate these kinds of half working bugs lol

Thanks @bko for all your help.

2 Likes