Read & Write 24LC1025 with wire.h okay but problem after 65536 address

Hello all,
I decided to reopen an old debat…
I have some strange beavier also!
Did test the code from the topic http://forum.arduino.cc/index.php?topic=243895.0
If i write in a single place and read it again it works ok the problem is that if i try to write to a new address it replace an old data and repeat it every to times i don’t know if i can explain it well.
here is an example of the data i receaved:
15-8-11,20:1:29,0,29
15-8-11,20:1:55,0,29
15-8-11,20:1:55,0,29
0-1-1,0:36:24,0,33
0-1-1,0:36:24,0,33
0-1-1,0:55:3,0,33
0-1-1,0:55:3,0,33
0-1-1,0:59:12,0,33
the problem only hapens after address 65536

As i would like to use the 24LC1025 to record data in a data logger formated like:
yy-mm-dd,hh:mm:ss,data1,data2
i use the internal eeprom address 9 10 and 11 of the arduino to record where will be the next record start point.
code to write and read data is this:

void gravarDados(){
   a = EEPROM.read(9);
   b = EEPROM.read(10);
   c = EEPROM.read(11);
   address = (a + (256 * b) + (65536 * c));
    writeEEPROM(disk1,address,year);
    Serial.print(address);
    Serial.print(",");
    address++;
    writeEEPROM(disk1,address,month);
    Serial.print(address);
    Serial.print(",");
    address++;
    writeEEPROM(disk1,address,day);
    Serial.print(address);
    Serial.print(",");
    address++;
    writeEEPROM(disk1,address,hoour);
    Serial.print(address);
    Serial.print(",");
    address++;
    writeEEPROM(disk1,address,minute);
    Serial.print(address);
    Serial.print(",");    
    address++;
    writeEEPROM(disk1,address,second);
    Serial.print(address);
    Serial.print(",");
    address++;
    writeEEPROM(disk1,address,new);
    Serial.print(address);
    Serial.print(",");
    address++;
    writeEEPROM(disk1,address,temp);
    Serial.print(address);
    Serial.println(",");  
    address++;
  in = address;
  contagens();
}

void lerDados(){
   a = EEPROM.read(9);
   b = EEPROM.read(10);
   c = EEPROM.read(11);
   address = (a + 256 * b + 65536 * c);  
   unsigned long ad = address;
   for (address = 0; address < ad; address++ ){
        Serial.print(readEEPROM(disk1, address), DEC);
        Serial.print("-");
        address++;
        Serial.print(readEEPROM(disk1, address), DEC);
        Serial.print("-");
        address++;
        Serial.print(readEEPROM(disk1, address), DEC);
        Serial.print(",");    
        address++;
        Serial.print(readEEPROM(disk1, address), DEC);
        Serial.print(":");
        address++;
        Serial.print(readEEPROM(disk1, address), DEC);
        Serial.print(":");    
        address++;
        Serial.print(readEEPROM(disk1, address), DEC);
        Serial.print(",");
        address++;
        Serial.print(readEEPROM(disk1, address), DEC);
        Serial.print(",");
        address++;
        Serial.println(readEEPROM(disk1, address), DEC); }
}

void writeEEPROM(int deviceaddress, unsigned long eeaddress, byte data )
{
 
  if( eeaddress > 65535 )
    eeaddress = eeaddress | B00001000;   
    
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
  delay(5);
}

byte readEEPROM(int deviceaddress,unsigned long eeaddress)
{
  byte rdata = 0xFF;
 
   if( eeaddress > 65535 )
    eeaddress = eeaddress | B00001000;   

  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

Thanks
Timóteo

timoteo_mendes: Hello all, I decided to reopen an old debat... I have some strange beavier also!

The 24LC1025 EEPROM is 128k, It acts Like two 64K devices.

its I2C address is built up from fixed values + A0,A1 pin value + address bit 17 (Block 0 or 1).

So, if you wire it with A0,A1 tied to GND and are access address 0..65535 the I2C address for the Memory Chip is 0x50. If you want to access memory between 65536..131071 the Chip address is 0x54

you cannot write across the 65535..65536 byte boundary with breaking the operation into two write() calls. One to chip 0x50, the other to chip 0x54.

and this eeprom has a 128byte writePage. This means that if you attempt to write a block of data that laps over a 7bit boundary 127..128, 255..256, 383..385, the information will not be stored where you expect it to be.

for example, lets say you want write "Now is the" to the EEPROM at address 125, here is code that you would expect to do this:

void writeChar(uint8_t i2cChip, uint16_t address, char ch[]){
Wire.beginTransmission(i2cChip);
Wire.write(highByte(address));
Wire.write(lowByte(address));
uint8_t i = 0;
while(ch[i])Wire.write((uint8_t)ch[i++]);
Wire.endTransmission();
}

Now since the writePage buffer inside the chip is 128byts long this is actually what was written:

address
0 1 2 3 4 5 6 7 8 9 10 11    .....   125 126 127 128 129 130
  i s   t h e   t i  m e              N   O   W

To actually do a block write you need to account for the writePage size

void writeChar(uint8_t i2cChip, uint16_t address, char ch[]){
uint16_t tAddr;
uint8_t writeLen; // actual number of byte written must be less than 32 because of Wire. buffers
uint8_t pageSize = 128;
uint8_t len=length(ch);
uint8_t index = 0;
bool ready; // has the chip finished any prior write command?
while(len>0){
  do{ // wait for chip to complete prior Write operation
     Wire.beginTransmission(i2cChip);
     ready = (Wire.endTransmission()==0);
     }while(!ready);

  writeLen = len;
  tAddr = address + len -1;
  if((tAddr/pageSize)!=(address/pageSize)){ // end of block is on different writepage
    tAddr = ((address/pageSize)+1)*pageSize; // first address of new page
    writeLen = tAddr - address; // maximum number of bytes before wrap around writepage
    }
  if(writeLen>30) writeLen=30; // Wire buffer can hold 31 bytes max
  len = len -writeLen;    

  Wire.beginTransmission(i2cChip);
  Wire.write(highByte(address));
  Wire.write(lowByte(address));
  address = address + writeLen;
  while(writeLen){
    Wire.write((uint8_t)ch[index++]); 
    writelen--;
    }   
  Wire.endTransmission();
  }
}

Also I noticed your 65536 constant did not have the L (long type marker) use 65536L or the complier will mess the value up.

Chuck.

Your code does not follow the successful code presented in reply 9 of the thread you cite. http://forum.arduino.cc/index.php?topic=243895.0

You need to be modifying the device address not the storage address for values over 65536. Please read the thread again. It is complex.

As chucktodd explains the two device address are 0x50 and 0x54. That is the same as the solution given in the thread, but the thread uses a more complex binary representation or the two i2c address, and bit shifting for a 7 bit address.

There is also information in the thread about the need for pin A2 on the eeprom to be tied to 5v.

Hello chucktodd,

The 24LC1025 EEPROM is 128k, It acts Like two 64K devices.

its I2C address is built up from fixed values + A0,A1 pin value + address bit 17 (Block 0 or 1).

So, if you wire it with A0,A1 tied to GND and are access address 0..65535 the I2C address for the Memory Chip is 0x50. If you want to access memory between 65536..131071 the Chip address is 0x54

you cannot write across the 65535..65536 byte boundary with breaking the operation into two write() calls. One to chip 0x50, the other to chip 0x54.

where did you found this information? The eeprom is an 128K x 8 (1024K bit), this mean it have 8 pages to write? do you know the address? I also have the A2 connected to the VCC, as explained in the data sheet.

and this eeprom has a 128byte writePage. This means that if you attempt to write a block of data that laps over a 7bit boundary 127..128, 255..256, 383..385, the information will not be stored where you expect it to be. This is not the problem the strage is that if i write to address: 65632,65633,65634,65635,65636,65637,65638,65639, 65640,65641,65642,65643,65644,65645,65646,65647, The first line is ok but after i write down the second line it is correct the second and the same value is in the first line... This does not hapen if i write it before address 65536. The L marker is not necessary in the due version.

Thanks

timoteo_mendes: Hello chucktodd,where did you found this information? The eeprom is an 128K x 8 (1024K bit), this mean it have 8 pages to write? do you know the address? I also have the A2 connected to the VCC, as explained in the data sheet.

Page 8 of the MicroChip DataSheet 24LC1025

|333x500

In Figure 5.1, The section labeled Slave Address 1010 B0 A1 A0. B0 is the bank ID either 0, or 1, A1,A0 are the hardware address selection pins. You have to interpret it as B101 or 5, 0 B0 A1 A2 where B0 is the A17 bit of your memory Address.

On this page; Left Column, Last paragraph: "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"

512K bits is 64k Bytes (0..65535).

When you use Wire.beginTransmission(i2cAddr); the i2cAddr address is 7bits, excluding R/_W. in your Code where you used: if (address>65535) chipAddr = chipAddr | B00001000; It should have been chipAddr = chipAddr | B00000100;

Here is where it talks about the Write Page Limitations: Page 9. |350x500

timoteo_mendes: The L marker is not necessary in the due version.

Good to know, I have never used the Due.

chuck.

Hello all,

I have follow the sugestion of Catledog and implement a modified scketch but now i have experienced some strange beavier, way do i have to use the address #define disk1 B10100000 and not the X050? Can you explain it please.
Lets say i decide to record a count 65722 this is multiple by 8 since my data is 8 values.
The problem is that it record every 8192 position or an increment of 65536 bits.
how can i resolve the problem.
The code is:

#define disk1 B10100000

void writeEEPROM(int deviceaddress, unsigned long eeaddress, byte data )
{
 
  if( eeaddress > 65535 )
    deviceaddress = deviceaddress | B00001000;   
   
  deviceaddress = deviceaddress >> 1; 
    
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
  delay(5);
}

byte readEEPROM(int deviceaddress,unsigned long eeaddress)
{
  byte rdata = 0xFF;
 
   if( eeaddress > 65535 )
    deviceaddress = deviceaddress | B00001000;   
   
    deviceaddress = deviceaddress >> 1; 

  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

Chucktodd thanks for your explanation but now i am a bit confused, if it is separate it as to use 2 diferent memory I2C addresses is that? Or does it have to use more addresses?
I was expecting that as long i use the correct address it will record in the wright place but that is not true.
Here you can found a record data i took from the 24LC1025.
Can you both please have a look.
Thanks

Timóteo

B10100000 >> 1 is B01010000 decimal 80 or hex 0x50.

B10100000 | B00001000 is B10101000 and >>1 is B01010100 decimal 84 or hex 0x54.

The bit shifting is in there because the device uses 7 bit i2c address and for some reason, the example code was written with 8 bit binary representation of the numbers knowing they would be bit shifted.

The format you are using is helpful if you want to refer back to the data sheet and understand what you are doing with the added address bit. It may be less confusing to just use the two addresses 0x50 and 0x54 to read/write from the two halves of the memory space.

Lets say i decide to record a count 65722 this is multiple by 8 since my data is 8 values. The problem is that it record every 8192 position or an increment of 65536 bits. how can i resolve the problem.

I was expecting that as long i use the correct address it will record in the wright place but that is not true. Here you can found a record data i took from the 24LC1025.

Can you please explain more about your problem. I do not understand.

Hello all,

Still no luck with my problem... From what i have read from cattledog post it seens that the eeprom is like two 512 memorys in one boxe that have the address of the first half 0x50 and 0x54 of the second half. Is it correct? chucktodd, after read the datasheet more than once it still does not ring a bell. Can you explain by steps what should i do to write per example in the position 65537? Do you sugest the memory have 8 diferent addresses to one for each 8192 cells? Sorry my confusions but i was expecting that one librarie for this memories would be very simple.

Thanks for your time,

Timóteo Mendes

timoteo_mendes:
Hello all,

Still no luck with my problem…
From what i have read from cattledog post it seens that the eeprom is like two 512 memorys in one boxe that have the address of the first half 0x50 and 0x54 of the second half. Is it correct?
chucktodd, after read the datasheet more than once it still does not ring a bell.
Can you explain by steps what should i do to write per example in the position 65537?
Do you sugest the memory have 8 diferent addresses to one for each 8192 cells?
Sorry my confusions but i was expecting that one librarie for this memories would be very simple.

Thanks for your time,

Timóteo Mendes

Treat that device as if it is two memory chips, one at address 0x50, with memory addresses from 0…0xffff or( 0…65535). And the other ‘chip’ with an I2C address of 0x54, with memory address from 0…0xffff or (0…65535).

This device has a 128byte write page, therefor any single write must be limited to not cross a 128 byte address boundry. i.e 0…127, 128…255, 256…383, 384…511 … or hexidecimal ( 0… 0x007F, 0x0080…0x00FF, 0x0100…0x017F, 0x0180…0x01FF …

To follow these limitations, you must either do:

  • use Wire.write() to write single bytes
  • write a function that breaks bigger data block across 128 byte boundarys

Attached is a sketch that has a routine which handles this problem.

Chuck.

eepromWrap.ino (5.21 KB)

Hello Chuck

Thanks for your reply and your skecht but is a bit to much for me i am a beginner :). Lests make your explanations in code: to write

  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
  delay(5);

to read

  byte rdata = 0xFF;
  Wire.beginTransmission(deviceaddress);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;

And the device address is 0x50 for the first half and 0x54 fot the second half. But doing this i do not have the complete 128K memory or am I confusing bits and bytes? As i could read from the manual the eeprom is 128K x 8 bytes as i would like to record an 8 bytes data for each entry is should be 128000 entries and not 128000 / 8 that is the maximum i can record if use the way you sugest. When read in page 5 "Each device has internal addressing boundary limitations. This divides each part into two segments of 512K bits. The block select bit ‘B0’ controls access to each “half”." I tried to manipulate the control byte like but that did not work: to write

  byte control = B10100000;
  if( eeaddress > 65535 ){
    control = B10101000; }     
  Wire.beginTransmission(deviceaddress);
  Wire.write(control);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
  delay(5);

to read

  byte control = B10100001;
  byte rdata = 0xFF; 
   if( eeaddress > 65535 ){
    control = B10101001;}
  Wire.beginTransmission(deviceaddress);
  Wire.write(control);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;

Any ideia or am I just complicate what is already made? Thanks Timóteo

timoteo_mendes:
Hello Chuck

And the device address is 0x50 for the first half and 0x54 fot the second half.
But doing this i do not have the complete 128K memory or am I confusing bits and bytes?
As i could read from the manual the eeprom is 128K x 8 bytes as i would like to record an 8 bytes data for each entry is should be 128000 entries and not 128000 / 8 that is the maximum i can record if use the way you sugest.

The eeprom is 128K bytes or 128k x 8 bits, so if you are writing 8 byte blocks, you can write 16k * 8bytes.

So Each 64k section (0x50,0x54) will hold 8k records.

timoteo_mendes:
When read in page 5
“Each device has internal addressing boundary
limitations. This divides each part into two segments of
512K bits. The block select bit ‘B0’ controls access to
each “half”.”
I tried to manipulate the control byte like but that did not work:
to write

Your control byte is wrong, it should be:

byte control = B01010000;

The Wire library appends the read/write bit to the I2C chip address internally, so you pass Wire a 7bit address.
When you passed it B10100000 (0xA0), it shifted the value Left, loosing the top bit and resulting in an address of (0x40), then it applied the read/Write bit to generate the actual I2C value for the bus.

since 0x40 is not 0x50, your memory chip never responded.

and your ‘control’ variable is the device address, use it in the Wire.beginTransmission() call.

  byte control = B01010000;
  if( eeaddress > 65535 ){
    control = B01010100; }     
  Wire.beginTransmission(control);

I do not like how you wrote this next section, How I would interpret it is:

  Wire.write((int)(eeaddress >>8));
/*
   Take the value of eeaddress, shift is right 8 bits
   Pass Wire.write(), a 16bit integer, base on the previous shift
   Wire.write() is told to send a byte of 0, (the high byte), 
   then the low byte.

   Your code actually works because inside the Wire library, there are multiple
   definitions for Wire.write() that only use the low byte,
   If I set eeaddress=0x1234, and call
   Wire.write((int)eaddress);  the call only transmits 0x34, it ignores the high byte

   A better coding, because it does exactly what the code states is:

   Wire.write(highByte(eeaddress)); // highByte is a compiler function the returns a byte value
   Wire.write(lowByte(eeaddress));
*/

timoteo_mendes:

  Wire.write((int)(eeaddress >> 8));   // MSB

Wire.write((int)(eeaddress & 0xFF)); // LSB
 Wire.write(data);
 Wire.endTransmission();
 delay(5);

you do not need to ‘build’ the control byte to add the read/Write bit, Wire will do it for you.
Just pass the correct 7bit device address.
instead of this code:

timoteo_mendes:
to read

  byte control = B10100001;

byte rdata = 0xFF;
  if( eeaddress > 65535 ){
   control = B10101001;}
 Wire.beginTransmission(deviceaddress);
 Wire.write(control);
 Wire.write((int)(eeaddress >> 8));   // MSB
 Wire.write((int)(eeaddress & 0xFF)); // LSB
 Wire.endTransmission();
 Wire.requestFrom(deviceaddress,1);
 if (Wire.available()) rdata = Wire.read();
 return rdata;

  byte control = deviceaddress;

   if( eeaddress > 65535 ){
    control = control | B00000100;  // turn on bit2, address bit 17
    }
  Wire.beginTransmission(control);
  Wire.write(highByte(eeaddress));   // MSB
  Wire.write(lowByte(eeaddress)); // LSB
  Wire.endTransmission();
  Wire.requestFrom(control,1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;

try this code, Also I wrote another example, It is attached. It is two files because I wanted to use a typedef as a function parameter.

Chuck.

LC1025.h (218 Bytes)

LC1025.ino (5.96 KB)

Hello chucktodd,

You program in a level that i do not understand already i need to practice a lot more... I did not understand your program and i like to know what i do use :).

The eeprom is 128K bytes or 128k x 8 bits, so if you are writing 8 byte blocks, you can write 16k * 8bytes.

Just to clarify, 8 bits alow me to write a number from 0 to 255 decimal so the memory is just 1024K and not 1024M as i was expecting :(.

Here is the code i change follow your sugestions and add the second part of the memory:

#define disk1 0x50    //Address of 24LC1025 eeprom chip part 1
#define disk11 0x54    //Address of 24LC1025 eeprom chip part 2

void writeEEPROM(int deviceaddress, unsigned long eeaddress, byte data )
{ 
  if( eeaddress > 65535 ){
    deviceaddress = disk11; }
   else {
    deviceaddress = disk1; } 
    
  Wire.beginTransmission(deviceaddress);
  Wire.write(highByte(eeaddress)); // highByte is a compiler function the returns a byte value
  Wire.write(lowByte(eeaddress));
  Wire.write(data);
  Wire.endTransmission();
  delay(5);
}

byte readEEPROM(int deviceaddress,unsigned long eeaddress)
{
  byte rdata = 0xFF;

  if( eeaddress > 65535 ){
    deviceaddress = disk11; }
   else {
    deviceaddress = disk1; } 

  Wire.beginTransmission(deviceaddress);
  Wire.write(highByte(eeaddress)); // highByte is a compiler function the returns a byte value
  Wire.write(lowByte(eeaddress));
  Wire.endTransmission();
  Wire.requestFrom(deviceaddress,1);
  if (Wire.available()) rdata = Wire.read();
  return rdata;
}

If a need more memory space the better option is to use a second 24LC1025 and use the that extra memory addresses to expand the space i'm i correct? Do you know any other eeprom memory that has bigger space and is low power still.

Thanks for your help.

Timóteo Mendes

According to the data sheet you can put four of the 24LC1025 on the i2c bus with different addresses. You could also take a look at spi flash memory.

2.1 A0, A1 Chip Address Inputs The A0 and A1 inputs are used by the 24XX1025 for multiple device operations. The levels on these inputs are compared with the corresponding bits in the slave address. The chip is selected if the comparison is true. Up to four devices may be connected to the same bus by using different Chip Select bit combinations. In most applications, the chip address inputs A0 and A1 are hard-wired to logic ‘0’ or logic ‘1’. For applications in which these pins are controlled by a microcontroller or other programmable device, the chip address pins must be driven to logic ‘0’ or logic ‘1’ before normal device operation can proceed. 2.2 A2 Chip Address Input The A2 input is non-configurable Chip Select. This pin must be tied to VCC in order for this device to operate. If left floating or tied to VSS, device operation will be undefined.

Hello cattledog,

I have checked the datasheet and have implement a second memory in order to obtain 32k of possible loggs. Thanks for the sugestion have you ever used that memories? Is it simple to implement? Because the price is ok, Do you advise a model?

Thanks, Timóteo

Thanks for the sugestion have you ever used that memories? Is it simple to implement?

I have no direct experience with the spi flash memory, so I can’t really help you. From what I have seen looking around on the web, I doubt it will be as simple as the i2c external eeprom, especially as there are hardware issues to address around mounting the chips (although there may be break-out boards available) and possible level shifting if you are using a 5v arduino, as the spi flash is 3.3v.

What is your application that you do not wish to use an SD card for large quantity storage?

Thanks for the sugestion have you ever used that memories? Is it simple to implement?

I have no direct experience with the spi flash memory chips, so I can't really help you. From what I have seen looking around on the web, I doubt it will be as simple as the i2c external eeprom, especially as there are hardware issues to address around mounting the chips (although there may be break-out boards available) and possible level shifting if you are using a 5v arduino, as the spi flash is 3.3v.

What is your application that you do not wish to use an SD card for large quantity storage?

Hello Cattledog,

The principal goal is to have an in field long term logger working and the sd card have huge power needs compare with the eeprom that is really a low power solution. Thanks you all for your help the problem is now fixed and the logger working.

Timóteo

The principal goal is to have an in field long term logger working and the sd card have huge power needs compare with the eeprom that is really a low power solution.

Modern SD cards sleep at less than 100 µA.

Here is a link to a Cave Data Logger. This logger records environmental conditions in caves over long periods.

After some work, the Cave Data Logger achieved this:

With a 3xAA power pack now providing almost a year of operation for some sensor configurations.