Search code examples
memoryembeddedmsp430eeprom

Unable to write large buffers to EEPROM


I'm trying to interface a M95M02-DR 256KB EEPROM memory chip with a MSP430 microcontroller. As a sample test, I tried to write the following string to it:

CHAPTER I. Down the Rabbit-Hole. Alice was beginning to get very tired of sitting by her sister on the bank,

When I try to read the data back from the chip, this is what I get:

CHAPTER I. Down the Rabbit-Hole. Alice was beginning to get very tired of sitting by her sister on the b?????

The ?'s are junk data. The thing is, if I reduce the size of the string by a few characters then there is no problem. Previously I had tried to read data from a file on an SD card and write to the EEPROM chip in 256 byte blocks. Nothing was written in that case. But when I performed the same operation byte by byte, then there was no problem.

This is the code that I'm using

  static uint32_t i=0x025698;

  static unsigned char message[120] = "CHAPTER I. Down the Rabbit-Hole."\
  "Alice was beginning to get very tired of sitting by her sister on the bank, "; 

  static int size ;

  unsigned char input[120];

  size = strlen(message);

  eeprom_spi_init();
  eeprom_write( i ,message,size);

  __delay_cycles(2500);

  eeprom_read( i, input,size);

  input[size]='\0';

  ax_log_msg(E_LOG_INFO,input);  //print command

The low level SPI Functions are as:

  void eeprom_write(uint32_t ui_addr, uint8_t *puc_wrData, uint8_t ui_dataLen)
  {

    uint8_t uac_wrBuf[260] = {0x00,};
    uint8_t i = 0;

    EEPROM_wrEnable();

    uac_wrBuf[i++] = WRITE; /* Write Instruction */
    uac_wrBuf[i++] = (uint8_t)((ui_addr >> 16) & 0xFF); /* First 8-bit MSB of 24-bit address  */
    uac_wrBuf[i++] = (uint8_t)((ui_addr >> 8) & 0xFF);  /* Second 8-bit MSB of 24-bit address */
    uac_wrBuf[i++] = (uint8_t)((ui_addr) & 0xFF);       /* Third 8-bit MSB of 24-bit address  */

    while(ui_dataLen--) {
      uac_wrBuf[i++] = *puc_wrData++;
    }
    uac_wrBuf[i++] = 0xFF;

    EEPROM_ON();
    EEPROM_sendFrame(uac_wrBuf, i);
    EEPROM_OFF();

    __delay_cycles(250000);
  }



  void eeprom_read(uint32_t ui_addr, uint8_t *puc_wrData, uint8_t ui_dataLen)
  {

    uint8_t uac_rdBuf[260] = {0x00,};
    uint8_t uac_rdCmd[4];
    uint8_t i = 0;

    uac_rdCmd[i++] = READ;
    uac_rdCmd[i++] = (uint8_t)((ui_addr >> 16) & 0xFF); /* First 8-bit MSB of 24-bit address  */
    uac_rdCmd[i++] = (uint8_t)((ui_addr >> 8) & 0xFF);  /* Second 8-bit MSB of 24-bit address */
    uac_rdCmd[i++] = (uint8_t)((ui_addr) & 0xFF);       /* Third 8-bit MSB of 24-bit address  */

    EEPROM_ON();
    EEPROM_sendFrame(uac_rdCmd, i);
    EEPROM_readFrame(puc_wrData, ui_dataLen);
    EEPROM_OFF();

  }

The EEPROM_sendFrame and EEPROM_readFrame are working fine as I use them for the SD card as well.

Any help at all would be appreciated. If there is any information I have forgotten to mention, please tell me and I will add it.

Thanks


Solution

  • You're hitting a page boundary. All EEPROMs can only write to one page per transaction. The M95M02 has 256-byte pages, so within any single call to eeprom_write, all your target addresses have to match in every byte except the least significant one.

    In your example, you start writing at address 0x025698.

    page{start=0x025600, offset=0x98}

    Each data byte autoincrements until you reach the end of the page.

    page{start=0x025600, offset=0xFF}

    Then it all wraps back around to the beginning of the page. Where you want to write 0x25700, you're actually writing to 0x25600.

    page{start=0x025600, offset=0x00 = 0x100 & 0xFF}

    If you do a read afterwards, you'll see the remainder of your content down there at 0x025600.

    To solve this problem, you have to break up your write into segments that don't cross page boundaries.

    Here's a suggestion: rename your current eeprom_write to eeprom_write_page and wrap it with the following code (apologies for any errors -- I didn't have time to actually compile it):

    void eeprom_write(uint32_t addr, uint8_t* data, uint32_t datalen)
    {
      while (0 < datalen)
      {
        uint32_t pagelen = (addr|0xFF) - addr + 1;
        uint32_t writelen = min(datalen, pagelen);
    
        eeprom_write_page(addr, data, (uint8_t)writelen);
    
        addr += writelen;
        data += writelen;
        datalen -= writelen;
      }
    }
    

    This also gives you the benefit of being able to pass in data longer than 256 bytes. The wrapper function can take care of all that chunking for you.