Problem with Page Write to 24AA1025 EEPROM (Wire library)

Hello people!

I'm trying to log sensor data continously to EEPROM (24AA1025)!

The datasheet says that the page buffer of the EEPROM is 128byte and only can be written continously within a physical page size.

So i implemented following methods for continous write to the EEPROM:

unsigned long startWriteAddressEEPROM;
unsigned long writtenBytesEEPROM;
unsigned long currentPageStartAddress;
unsigned long nextPageStartAddress;
unsigned long pageSize = 128;

void startContinousWriteToEEPROM(unsigned long address) {
  Wire.beginTransmission(0b1010000 | (byte)((address>>14)&0b0000100));
  Wire.send((byte)((address >> 8) & 0xFF)); // MSB
  Wire.send((byte)(address & 0xFF)); // LSB
  startWriteAddressEEPROM = address;
  writtenBytesEEPROM = 0;
  currentPageStartAddress = (address/pageSize)*pageSize;
  nextPageStartAddress = currentPageStartAddress + pageSize;
  
}

void writeContinousByteToEEPROM(byte data) {
  Wire.send(data);
  writtenBytesEEPROM++;
  unsigned long absoluteAddress = startWriteAddressEEPROM + writtenBytesEEPROM;
  if(absoluteAddress >= nextPageStartAddress) {
    endContinousWriteToEEPROM();
    startContinousWriteToEEPROM(absoluteAddress);
  }
}

void writeContinousDoubleByteToEEPROM(unsigned int data) {
  writeContinousByteToEEPROM((byte)(data>>8));
  writeContinousByteToEEPROM((byte)data);
}

void writeContinousTripleByteToEEPROM(unsigned long data) {
  writeContinousByteToEEPROM((byte)(data>>16));
  writeContinousByteToEEPROM((byte)(data>>8));
  writeContinousByteToEEPROM((byte)data);
}


void endContinousWriteToEEPROM() {
  Wire.endTransmission();
  delay(5); // also tried delay(500);
}

The problem with the code is, that only the first 30 bytes of the page buffer are written to the EEPROMs memory.
If i set the pageSize to 30, the continous writing also do not seems to work correctly - some bytes in the EEPROM will not get written.
The only way to write continous without failures was setting the pagesize<16 ???

Here is the code of my testing sketch for writing the numbers 1,2,3,4,...127,128 to the first 10 pages, and readig them back to the serial for debugging:

#include <Wire.h>

void setup() {
  Serial.begin(9600);
  Wire.begin();
  Serial.println("START FORMATTING");
  for(long i=0; i<10*128; i++) {
    writeByteToEEPROM(i,0xFF);
  }
  Serial.println("FINISHED FORMATTING");
  Serial.println("START WRITING");
  startContinousWriteToEEPROM(0);
  for(long i=0; i<10; i++) {
    for(long j=0;j<128;j++) {
      writeContinousByteToEEPROM(j);
    }
  }
  endContinousWriteToEEPROM();
  Serial.println("FINISHED WRITING");
  Serial.println("START READING");
  for(long i=0; i<10*128; i++) {
    Serial.print("Read from ");
    Serial.print(i);
    Serial.print(" - value = ");
    Serial.print(readByteFromEEPROM(i), DEC);
    Serial.println("");    
  }  
  Serial.println("FINISHED READING");  
}

void loop() {}

I'm working on this for about a week and can't find my fault.

Please can anybody help me finding the bug?

Thanks!

Sers Hartl! 8)

why do you use unsigned long (4byte) for addressing when you only need 2byte. should be no problem-just saying.

I can't find anything wrong with your code. but i suggest to do a simple 128byte page write
start 10100100 00000000 00000000 128databytes stop
first address filled with 128 bytes.
Should this work you definitely have some addressing issues. Or your readBytefromEEPROM function is the issue.You should post that function too. :.

Daniel

Hello!

The address space of the 24AA1025 EEPROM is from 0x00000 to 0x1FFFF - so you need 17bits for the possibility to use the whole memory - thats why i use unsigned long for storing the address variables.
Remeber that the msb of the address will be transmitted with the control byte as B0 (see datasheet)

The readByteFromEEPROM() function works - i have testet it with writeByteFromEEPROM() - here're the codes:

byte readByteFromEEPROM(unsigned long address) {
  byte rdata = 0xFE;
  Wire.beginTransmission((int) (0b1010000 | ((address>>14)&0b0000100)));
  Wire.send((int)((address >> 8) & 0xFF)); // MSB
  Wire.send((int)(address & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(0b1010000 | (address>>16),1);
  while(!Wire.available()) {delay(1);}
  rdata = Wire.receive();
  return rdata;
}

void writeByteToEEPROM(unsigned long address, byte data) {
  Wire.beginTransmission(0b1010000 | (byte)((address>>14)&0b0000100));
  Wire.send((int)((address >> 8) & 0xFF)); // MSB
  Wire.send((int)(address & 0xFF)); // LSB
  Wire.send(data);
  Wire.endTransmission();
  delay(5);
}

Next i tested like you suggested just to write the first 128 bytes - but still have the same problem.
here the new test sketch:

#include <Wire.h>

void setup() {
  Serial.begin(9600);
  Wire.begin();
  Serial.println("START FORMATTING");
  for(long i=0; i<128; i++) {
    writeByteToEEPROM(i,0xFF);
  }
  Serial.println("FINISHED FORMATTING");
  Serial.println("STARTED WRITING");
  unsigned long address = 0x0;
  Wire.beginTransmission(0b1010000 | (byte)((address>>14)&0b0000100));
  Wire.send((byte)((address >> 8) & 0xFF)); // MSB
  Wire.send((byte)(address & 0xFF)); // LSB
  for(unsigned char i=0; i<128; i++) {
    Wire.send(i);
  }
  Wire.endTransmission();
  delay(500);
  Serial.println("FINISHED WRITING");  
  Serial.println("START READING");
  for(long i=0; i<128; i++) {
    Serial.print("Read from ");
    Serial.print(i);
    Serial.print(" - value = ");
    Serial.print(readByteFromEEPROM(i), DEC);
    Serial.println("");    
  }  
  Serial.println("FINISHED READING");
}

void loop() {}

Any other suggestions?

Tanks!

:relaxed:

hmmm....

  • the page write time takes up 3ms. Maybe you should do at least an 3ms delay after each 128bytes.
  • the controlbyte B0 must be set after the first 512kBit are written to switch to the next Block. (but since it doesnt work with 128bytes either... :~)
    Quote:

This device has an internal addressing boundary
limitation that is divided into two segments of 512K bits.
Block select bit ‘B0’ to control access to each segment.

  • Do an ACK polling by sending another write controllbyte and see if the slave responds or is still busy ( you can do that after every 128byte write cycle)
  • i know its stupid, but use bigger delays(or ACK polling)
  • regarding your read Function... the manual states that after sending the address:

the master issues an acknowledge
as opposed to the Stop condition used in a random
read.

but you send the address and then Wire.endTransmission. that would be a stop condition.
AND there is only ONE Data Byte when reading! Couse you can only read either the first 512kbit or the last 512kbit! moi stupido
-why are you sending typeconvertet (int) now? instead of (byte) XD

Thanks for your answers!

Emence:

  • the page write time takes up 3ms. Maybe you should do at least an 3ms delay after each 128bytes.

I have a "delay(5);" at the end of the endContinousWriteToEEPROM() function - is this what you mean?

Emence:

  • the controlbyte B0 must be set after the first 512kBit are written to switch to the next Block. (but since it doesnt work with 128bytes either... :~)

this is done within "Wire.beginTransmission((int) (0b1010000 | ((address>>14)&0b0000100)));" - setting the 17th bit of the address to B0!

Emence:

  • Do an ACK polling by sending another write controllbyte and see if the slave responds or is still busy ( you can do that after every 128byte write cycle)

how i can do "ack polling" with wire library? Can you give me a hint?

Emence:

  • i know its stupid, but use bigger delays(or ACK polling)

i tried "delay(5);" and also "delay(500);" - both with the same results...

Emence:

  • regarding your read Function... the manual states that after sending the address:...
    but you send the address and then Wire.endTransmission. that would be a stop condition.

i don't have problems with reading (single bytes - didn't tried page read yet)
i have tried to comment the Wire.endTransmission() line in my read function - but now it seems not to work correctly.
i think the endTransmission() (-or something similiar) is needed to write the buffer of the wire lib to the device.
What would you change on my read-function?

Emence:
-why are you sending typeconvertet (int) now? instead of (byte) XD

hmm - i don't know ... i changed it - but still works the same...

THX - greetz!

IIRC - the underlying wire library works in smaller chuncks (32 bytes?)

Had a similar problem in my I2C lib (pagesize 64), so check - Arduino Playground - LibraryForI2CEEPROM -

While I understand this is an old post, I think this is the best place to post this info. I have just gone through the process of getting an ATxmega device to write to a 25AA1025 using the page write procedure, and I believe I understand the reason for the author's problem.

I struck what I believe is the same problem, in that the bytes I read did not match those written. In my case, I was trying to write 48 bytes to EEPROM location 96. The first 32 bytes seemed fine but the last 16 were not programmed. I laboured over this for a couple of days, even going so far as verifying the I2C protocol and checking that all bytes were acked. I read and reread the datasheet. I took note of the rule that disallows writing across the 64K block boundary. I used ack-polling and also tried ludicrously long inter-write delays. Nothing worked.

Then a colleague pointed me to the following paragraphs in the MicroChip datasheet (which I had read twice) and advised I read it word for word, very carefully....

"Note: Page write operations are limited to writing bytes within a single physical page, regardless of the number of bytes actually being written. Physical page boundaries start at addresses that are integer multiples of the page buffer size (or ‘page size’) and end at addresses that are integer multiples of [page size – 1]. If a Page Write command attempts to write across a physical page boundary, the result is that the data wraps around to the beginning of the current page (overwriting data previously stored there), instead of being written to the next page as might be expected. It is therefore, necessary for the application software to prevent page write operations that would attempt to cross a page boundary."

The page size is 128 bytes. What this note is saying is that not only can you not write across the block boundary, but you cannot write across a physical page boundary, that is any address that is a multiple of 128 bytes, either.

In my case I was writing to address 96, so there are only 32 bytes to the page boundary, hence the final 16 bytes from address 128 to 143 inclusive were not programmed. What happened? These 16 bytes were in fact written at address 0 to 15 inclusive!

Bottom line is that the if your write spans a page boundary you have to start a new write at the following page boundary. In my case this meant writing 32 bytes to address 96 and 16 bytes to address 128. Of course you can write as many as 128 bytes if you start on a page boundary.

NB: This rule does not apply to a read. There it is possible to read 48 bytes from address 96 without worrying about page boundaries (and there is no reference to them in the datasheet).

All the hype about not writing across block boundaries is probably less important that not writing across page boundaries. If you read the term block and page as the same thing then you you will miss the point as I did.

All in all, it's an example of [poor] asymmetric chip design (writes being different to reads) and lackluster documentation.

Hope this helps.

x0xbanderer:
Hello people!

I'm trying to log sensor data continously to EEPROM (24AA1025)!

The datasheet says that the page buffer of the EEPROM is 128byte and only can be written continously within a physical page size.

So i implemented following methods for continous write to the EEPROM:

unsigned long startWriteAddressEEPROM;

unsigned long writtenBytesEEPROM;
unsigned long currentPageStartAddress;
unsigned long nextPageStartAddress;
unsigned long pageSize = 128;

void startContinousWriteToEEPROM(unsigned long address) {
 Wire.beginTransmission(0b1010000 | (byte)((address>>14)&0b0000100));
 Wire.send((byte)((address >> 8) & 0xFF)); // MSB
 Wire.send((byte)(address & 0xFF)); // LSB
 startWriteAddressEEPROM = address;
 writtenBytesEEPROM = 0;
 currentPageStartAddress = (address/pageSize)*pageSize;
 nextPageStartAddress = currentPageStartAddress + pageSize;
 
}

void writeContinousByteToEEPROM(byte data) {
 Wire.send(data);
 writtenBytesEEPROM++;
 unsigned long absoluteAddress = startWriteAddressEEPROM + writtenBytesEEPROM;
 if(absoluteAddress >= nextPageStartAddress) {
   endContinousWriteToEEPROM();
   startContinousWriteToEEPROM(absoluteAddress);
 }
}

void writeContinousDoubleByteToEEPROM(unsigned int data) {
 writeContinousByteToEEPROM((byte)(data>>8));
 writeContinousByteToEEPROM((byte)data);
}

void writeContinousTripleByteToEEPROM(unsigned long data) {
 writeContinousByteToEEPROM((byte)(data>>16));
 writeContinousByteToEEPROM((byte)(data>>8));
 writeContinousByteToEEPROM((byte)data);
}

void endContinousWriteToEEPROM() {
 Wire.endTransmission();
 delay(5); // also tried delay(500);
}





The problem with the code is, that only the first 30 bytes of the page buffer are written to the EEPROMs memory.
If i set the pageSize to 30, the continous writing also do not seems to work correctly - some bytes in the EEPROM will not get written.
The only way to write continous without failures was setting the pagesize<16 ???


Here is the code of my testing sketch for writing the numbers 1,2,3,4,...127,128 to the first 10 pages, and readig them back to the serial for debugging:



#include <Wire.h>

void setup() {
 Serial.begin(9600);
 Wire.begin();
 Serial.println("START FORMATTING");
 for(long i=0; i<10128; i++) {
   writeByteToEEPROM(i,0xFF);
 }
 Serial.println("FINISHED FORMATTING");
 Serial.println("START WRITING");
 startContinousWriteToEEPROM(0);
 for(long i=0; i<10; i++) {
   for(long j=0;j<128;j++) {
     writeContinousByteToEEPROM(j);
   }
 }
 endContinousWriteToEEPROM();
 Serial.println("FINISHED WRITING");
 Serial.println("START READING");
 for(long i=0; i<10
128; i++) {
   Serial.print("Read from ");
   Serial.print(i);
   Serial.print(" - value = ");
   Serial.print(readByteFromEEPROM(i), DEC);
   Serial.println("");    
 }  
 Serial.println("FINISHED READING");  
}

void loop() {}





I'm working on this for about a week and can't find my fault.

Please can anybody help me finding the bug?

Thanks!

The problem is simple,:

The Wire.h library uses an internal 32byte buffer for all transmissions. So, when you send a block through Wire.h:

 Wire.beginTransmission( address); // byte is stored as I2Caddress
 Wire.write(HighAddress); // byte is place in buffer at address 0
 Wire.write(LowAddress); // byte is placed in buffer at address 1

 // fill with data
 Wire.write( byte#30);  // byte is paced in buffer at address 31, the thirty second position of the buffer
// Try to fill a 32 byte buffer with more bytes
 Wire.write(byte#31); // Wire.h discards

// Actually send the i2c transmission
  Wire.endTransmission(); // send the 32 bytes in the buffer 2 addr, 30 data.

// everybody HappY now?

To handle the WritePage problem:

bool writeBin(const uint8_t id,uint16_t adr, char data[],const uint16_t len,const uint8_t pageSize){
// Have to handle write page wrapping,
// 24lc512 has 128 byte 
// 24lc64 has 32 byte
uint16_t bk = len; // byte to actually send
bool abort=false;
uint8_t i;
uint16_t j=0;
uint32_t timeout;
uint16_t mask = pageSize-1;
while((bk>0)&&!abort){
  i =30; // internal Wire.h maximum block size
  if(i>bk) i=bk;
  if(((adr)&~mask)!=((((adr)+i)-1)&~mask)){ // over page!
    i = (((adr)|mask)-(adr))+1; // calculate how many bytes before the page boundary!
    }
  timeout = millis();
  bool ready=false;
  while(!ready&&(millis()-timeout<10)){ // wait up to 10ms for chip to complete prior write
    Wire.beginTransmission((uint8_t)id);
    ready=(Wire.endTransmission(true)==0); // wait for device to become ready!
    }
  if(!ready){
    abort=true;
    Serial.print(id,HEX);
    Serial.println(" chip timeout");
    break;
    }

  Wire.beginTransmission((uint8_t)id);
  Wire.write((uint8_t)highByte(adr));
  Wire.write((uint8_t)lowByte(adr));

  bk = bk -i;
  adr = (adr) + i;

  while(i>0){
    Wire.write((uint8_t)data[j++]);
    i--;
    }
 
  uint8_t err=Wire.endTransmission();
  if(err!=0){
    Serial.print("write Failure=");
    Serial.println(err,DEC);
    abort = true;
    break;
    }
  }
return !abort;
}

Chuck.