How store int type on 24LC256 ?

I am a newbie and use Arduino DUE with Atmel ARM core.
I would like to write and read an "int" data type on external EEPROM 24LC256 .
I arose some doubt about how to do.
I find it difficult to manage both an address and data 32bit.
What could be the solution. Could someone help me to understand how it can be done?
Thank you

Hi Simon_C

I've written two small C++ libraries for the 24LC256 called "ExtEEPROM" and "EEPROMAnything2", that used in conjuction with each other will allow you to read or write any data type or structure. These libraries should work with any Arduino. I've used them with both the Arduino Zero and Due.

"ExtEEPROM" is based on the example code from Hobbytronics and allows you to read and write bytes to and from the external EEPROM, just like the EEPROM library. It works with the 24LC256's I2C address set to 0x50, (all the chip address inputs A0, A1 and A2 pulled low or left unconnected).

"EEPROMAnything2" is a modification of the EEPROMAnything library that allows you to read and write any data structure or array to and from the external EEPROM.

The zip file "EEPROM.zip" containing the libraries, together with example code can be found on the Arduino Zero forum page: EEPROM by emulation?? - Arduino Zero - Arduino Forum.

Just expand the zip file and place the folders in your Arduino/libraries directory.

Thanks Martinl. I downloaded EEPROM.zip.
What I do not understand, for my inexperience, it is this:
At function,normally, have passed 2 parameters:

The first parameter is an "int address". In Arduino Uno is 16-bit.
This is then split into MSB and LSB. OK!

In Arduino DUE this is 32-bit. It always took Low 16 and the other ar lost?

The second parameter, normally, is a "byte data" in 8 bits.
But if I want to write an "unsigned int" or a "float" 32bit, how do I pass this parameter?
The statements and instructions inside the function change or remain equal ???
Thank you again

Hi,

First add following includes at the beginning of your sketch:

#include <Wire.h>
#include <ExtEEPROM.h>
#include <EEPROMAnything2.h>

The EEPROM_writeAnything() and EEPROM_readAnything() functions have two parameters. The first argument is the address, this is an "int" type, while the second is the data, which can be cast (or in other words converted) to any data type.

The address references the 24LC256's 16-bit address, starting at 0, whose location contains a single byte value. The data itself however, be it simple data type (byte, int, long, etc..) or data structure, is stored within the EEPROM at consecutive addresses as byte values.

So for example to store a floating point number at address 0:

EEPROM_writeAnything(0, (float)1.24567);

...and to read it back:

float y;
EEPROM_readAnything(0, y);

As a float takes 4 bytes and each location in the 24LC256 is only one byte long, to store the next piece of data we need to use address: 4 and so on.

This leads on to how to address data withing the EEPROM itself. It can be useful to store your EEPROM data in a large structure. Using EEPROM_Anything functions makes it possible either to transfer large data structures between EEPROM and the Due's RAM in one line of code, or to access individual pieces of data within the structure itself.

The reason for using the unsigned long (aka uint32_t) casts in the example code, is that it's useful for storing and retrieving data from a structure. What's happening is that we're taking the base address of the structure in the Due's (RAM) memory, hence 32-bits, then subtracting the address of the data (again in the Due's RAM) we want from within the structure. This gives the offset address of the data relative to the start of the structure. So, if we store this same data structure in the EEPROM at address 0, the members of that structure are offset relative to this 0 address.

The example code below demonstrates how this works. Just hook up your Due to the your 24LC256 EEPROM, connect the Due to the programming port and try the code. You'll see that it's possible to store the TestStruct to EEPROM then retrieve or change its data members individually:

#include <Wire.h>
#include <ExtEEPROM.h>
#include <EEPROMAnything2.h>

struct TestStruct   // Create a test structure
{
  int32_t x;
  float y;
  uint8_t z;
} testStruct = { 5, 1.23483748, 0x08 };

void setup()
{
  Serial.begin(115200);                   // Initialise the Serial port
  Wire.begin();                           // Initialise the I2C library
  Serial.println("Begin Test...");       

  EEPROM_writeAnything(0, testStruct);    // Write the test structure to EEPROM
 
  int32_t valueX;
  float valueY;
  uint8_t valueZ;
 
  EEPROM_readAnything((uint32_t)&testStruct.y - (uint32_t)&testStruct, valueY);   // Read the EEPROM values individually
  EEPROM_readAnything((uint32_t)&testStruct.z - (uint32_t)&testStruct, valueZ);
  EEPROM_readAnything((uint32_t)&testStruct.x - (uint32_t)&testStruct, valueX);
  Serial.println(valueX);                                                         // Display the values
  Serial.println(valueY, 6);
  Serial.println(valueZ);
  EEPROM_writeAnything((uint32_t)&testStruct.y - (uint32_t)&testStruct, (float)3.35343);  // Change the float value
  EEPROM_readAnything((uint32_t)&testStruct.y - (uint32_t)&testStruct, valueY);   // Read the EEPROM values individually
  EEPROM_readAnything((uint32_t)&testStruct.z - (uint32_t)&testStruct, valueZ);
  EEPROM_readAnything((uint32_t)&testStruct.x - (uint32_t)&testStruct, valueX);
  Serial.println(valueX);                                                         // Display the values again
  Serial.println(valueY, 6);
  Serial.println(valueZ);
  EEPROM_readAnything(0, testStruct);     // Read from EEPROM back to the test structure
  Serial.println(testStruct.x);           // Display the test structure
  Serial.println(testStruct.y, 6);
  Serial.println(testStruct.z);
  Serial.println("End Test...");
}

void loop() {}

Hi MartinL,
I think I've figured out how to turn the smoke!
The examples are very clear.
Thanks again Ciao.

Hi, I made this test:

EEPROM_writeAnything(10,(int)124567);

int y;
EEPROM_readAnything(10,y);

Serial.print (10,DEC);
Serial.print ( " : ");
Serial.print (y,DEC);
Serial.print ("\n");

The serial Monitor gives me back:

10 : -1

What is the mistake that I make? Where am I wrong?

Thank's

Hi,

It's probably because you didn't include Wire.begin() in your setup code.

The code:

#include <Wire.h>
#include <ExtEEPROM.h>
#include <EEPROMAnything2.h>

void setup() 
{
  int y;
  
  Serial.begin(115200);
  Wire.begin();
  EEPROM_writeAnything(10, (int)1234567);
  EEPROM_readAnything(10, y);
  Serial.print (10);
  Serial.print(F(" : "));
  Serial.println(y);
}

void loop() {}

...outputs:

10 : 1234567

You are quite right. I had missed.
It all works perfectly, Martin.
I would not know how to thank you.

MartinL:
Hi Simon_C

I've written two small C++ libraries for the 24LC256 called "ExtEEPROM" and "EEPROMAnything2", that used in conjuction with each other will allow you to read or write any data type or structure. These libraries should work with any Arduino. I've used them with both the Arduino Zero and Due.

"ExtEEPROM" is based on the example code from Hobbytronics and allows you to read and write bytes to and from the external EEPROM, just like the EEPROM library. It works with the 24LC256's I2C address set to 0x50, (all the chip address inputs A0, A1 and A2 pulled low or left unconnected).

"EEPROMAnything2" is a modification of the EEPROMAnything library that allows you to read and write any data structure or array to and from the external EEPROM.

The zip file "EEPROM.zip" containing the libraries, together with example code can be found on the Arduino Zero forum page: EEPROM by emulation?? - Arduino Zero - Arduino Forum.

Just expand the zip file and place the folders in your Arduino/libraries directory.

Thank you Martin for writing these two libs, this has helped me out greatly and is the first lib I have found that works easily & straight away with external EEPROMs.

I know this is an old thread but I truly think your work deserves credit.

One last thing, would it be difficult to implement an equivalent EEPROM.update(); function in the libs, not a huge lose if not as at the moment I use an IF statement that does a READ first and compares that value to a new value from my sensor & if it does not match, then performs a WRITE:

float y;
float NEWy;
EEPROM_readAnything(0, y);  
if (y != NEWy){
  EEPROM_writeAnything(0, (float)NEWy);
}

thank you :wink:

I am having a small issue with comparing a value read back from the EEPROM & have been going around in circles trying to figure the error.

I would appreciate it if someone could point out my obvious error, thanks.

For simplicity & testing purposes I have split my sketch in two, one writes the values to the EEPROM and also reads them back to output to the serial monitor, the other sketch is purely just to read the values and compare them to a fixed value and then output a message to the serial monitor if the value matches or not.

WRITE CODE:

#include <Wire.h>
#include <ExtEEPROM.h>
#include <EEPROMAnything2.h>

float sensorT = 23.5, battV = 4.155, CbattV = 3.045, sT = 0.0, bV = 0.0, CbV = 0.0;

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  Serial.println();
  Serial.println("Begin Test...");

  EEPROM_writeAnything(0, sensorT);
  EEPROM_writeAnything(4, battV);
  EEPROM_writeAnything(8, CbattV);

  EEPROM_readAnything(0, sT);
  EEPROM_readAnything(4, bV);
  EEPROM_readAnything(8, CbV);

  Serial.println(sT,1);
  Serial.println(bV,3);
  Serial.println(CbV,3);

  Serial.println("End Test...");

}

void loop() {}

OUTPUT FROM SERIAL MONITOR:

Begin Test...
23.5
4.155
3.045
End Test...

all completely normal & as it should be.

READ CODE:

#include <Wire.h>
#include <ExtEEPROM.h>
#include <EEPROMAnything2.h>

float sT = 0.0, bV = 0.0, CbV = 0.0;

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  Serial.println();
  Serial.println("Begin Test...");

  EEPROM_readAnything(0, sT);
  
  if( sT != 23.5 ){
    Serial.println("sensorT does not match EEPROM, new write needed");
    }
  else{
    Serial.println("sensorT does match EEPROM, no need to write new");
  }

  EEPROM_readAnything(4, bV);

  if( bV != 4.155 ){
    Serial.println("battV does not match EEPROM, new write needed");
    }
  else{
    Serial.println("battV does match EEPROM, no need to write new");
  }

  EEPROM_readAnything(8, CbV);

  if( CbV != 3.045 ){
    Serial.println("CbattV does not match EEPROM, new write needed");
    }
  else{
    Serial.println("CbattV does match EEPROM, no need to write new");
  }

  Serial.println(sT,1);
  Serial.println(bV,3);
  Serial.println(CbV,3);

  Serial.println("End Test...");
}

void loop() {}

OUTPUT FROM SERIAL MONITOR:

Begin Test...
sensorT does match EEPROM, no need to write new
battV does not match EEPROM, new write needed
CbattV does not match EEPROM, new write needed
23.5
4.155
3.045
End Test...

as you can see, battV & CbattV show as not matching the fixed value when compared but the read does indeed show that they do match perfectly.

Any help is much appreciated..,

Regards.

Typically after spending most of the day trying to figure this out, I did 5 mins after posting above.

I had to cast the fixed values, as simple as that.

NEW READ CODE:

#include <Wire.h>
#include <ExtEEPROM.h>
#include <EEPROMAnything2.h>

float sT = 0.0, bV = 0.0, CbV = 0.0;

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  Serial.println();
  Serial.println("Begin Test...");

  EEPROM_readAnything(0, sT);
  
  if(sT != float(23.5)){
    Serial.println("sensorT does not match EEPROM, new write needed");
    }
  else{
    Serial.println("sensorT does match EEPROM, no need to write new");
  }

  EEPROM_readAnything(4, bV);

  if(bV != float(4.155)){
    Serial.println("battV does not match EEPROM, new write needed");
    }
  else{
    Serial.println("battV does match EEPROM, no need to write new");
  }

  EEPROM_readAnything(8, CbV);

  if(CbV != float(3.045)){
    Serial.println("CbattV does not match EEPROM, new write needed");
    }
  else{
    Serial.println("CbattV does match EEPROM, no need to write new");
  }

  Serial.println(sT,1);
  Serial.println(bV,3);
  Serial.println(CbV,3);

  Serial.println("End Test...");
}

void loop() {}

Thanks anyway for looking.

Hello , thanks for this library . I struggle to use with multiple i2c adress. I wish if possible it supports function such as EEPROM_readAnything(i2c adreess, eeprom index ,data);
I try to modify class function ExtEEPROM.CPP WITH NO LUCK.

Hi Avinashpudale,

It should just be a matter of adding an I2C address parameter to both functions in "EEPROMAnything.h" file:

#include <ExtEEPROM.h>
#include <Arduino.h>  // for type definitions

template <class T> int EEPROM_writeAnything(unsigned int i2c_address, int ee, const T& value)
{
  const byte* p = (const byte*)(const void*)&value;
  unsigned int i;
  for (i = 0; i < sizeof(value); i++)
  {
    ExtEEPROM.write(i2c_address, ee++, *p++);
  }
  return i;
}

template <class T> int EEPROM_readAnything(unsigned int i2c_address, int ee, T& value)
{
  byte* p = (byte*)(void*)&value;
  unsigned int i;
  for (i = 0; i < sizeof(value); i++)
  {
    *p++ = ExtEEPROM.read(i2c_address, ee++);
  }
  return i;
}

Also in the "ExtEEPROM.h" and "ExtEEPROM.cpp files:

#ifndef ExtEEPROM_h
#define ExtEEPROM_h

#include <Arduino.h>
#include <Wire.h>

class ExtEEPROMClass
{
 public:
 void write(unsigned int, unsigned int, byte); 
 byte read(unsigned int, unsigned int);
};

extern ExtEEPROMClass ExtEEPROM;

#endif
#include "ExtEEPROM.h"

void ExtEEPROMClass::write(unsigned int i2c_address, unsigned int eeaddress, byte data) 
{ 
  Wire.beginTransmission(i2c_address);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
  
  delay(6);
}
 
byte ExtEEPROMClass::read(unsigned int i2c_address, unsigned int eeaddress) 
{
  byte rdata = 0xFF;
 
  Wire.beginTransmission(i2c_address);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
 
  Wire.requestFrom(i2c_address, 1);
  if (Wire.available()) 
  {
  rdata = Wire.read();
  }
  return rdata;
}

ExtEEPROMClass ExtEEPROM;

hello MartinL ,
thanks for replay . i do what you suggest still i am getting an issue .
here is test code

#include <Wire.h>
#include <ExtEEPROM.h>
#include <EEPROMAnything2.h>

void setup()
{
  int y;
 
  Serial.begin(115200);
  Wire.begin();
  EEPROM_writeAnything(0x50,10, (int)1234567);
  EEPROM_readAnything(0x50,10, y);
  Serial.print (10);
  Serial.print(F(" : "));
  Serial.println(y);
}

void loop() {}

i got error messages as follows

Arduino: 1.8.10 (Windows 10), Board: "Arduino/Genuino Uno"

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility\twi.c: In function '__vector_24':

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility\twi.c:447:49: warning: this statement may fall through [-Wimplicit-fallthrough=]

       twi_masterBuffer[twi_masterBufferIndex++] = TWDR;

                                                 ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility\twi.c:448:5: note: here

     case TW_MR_SLA_ACK:  // address sent, ack received

     ^~~~

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility\twi.c:529:9: warning: this statement may fall through [-Wimplicit-fallthrough=]

       if(0 == twi_txBufferLength){

         ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src\utility\twi.c:534:5: note: here

     case TW_ST_DATA_ACK: // byte sent, ack returned

     ^~~~

C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM\ExtEEPROM.cpp: In member function 'void ExtEEPROMClass::write(unsigned int, unsigned int, byte)':

C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM\ExtEEPROM.cpp:5:37: error: call of overloaded 'beginTransmission(unsigned int&)' is ambiguous

   Wire.beginTransmission(i2c_address);

                                     ^

In file included from C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM\ExtEEPROM.h:5:0,

                 from C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM\ExtEEPROM.cpp:1:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src/Wire.h:57:10: note: candidate: void TwoWire::beginTransmission(uint8_t)

     void beginTransmission(uint8_t);

          ^~~~~~~~~~~~~~~~~

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src/Wire.h:58:10: note: candidate: void TwoWire::beginTransmission(int)

     void beginTransmission(int);

          ^~~~~~~~~~~~~~~~~

C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM\ExtEEPROM.cpp: In member function 'byte ExtEEPROMClass::read(unsigned int, unsigned int)':

C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM\ExtEEPROM.cpp:18:37: error: call of overloaded 'beginTransmission(unsigned int&)' is ambiguous

   Wire.beginTransmission(i2c_address);

                                     ^

In file included from C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM\ExtEEPROM.h:5:0,

                 from C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM\ExtEEPROM.cpp:1:

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src/Wire.h:57:10: note: candidate: void TwoWire::beginTransmission(uint8_t)

     void beginTransmission(uint8_t);

          ^~~~~~~~~~~~~~~~~

C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\Wire\src/Wire.h:58:10: note: candidate: void TwoWire::beginTransmission(int)

     void beginTransmission(int);

          ^~~~~~~~~~~~~~~~~

Multiple libraries were found for "ExtEEPROM.h"
 Used: C:\Users\R&D\Documents\Arduino\libraries\ExtEEPROM
Multiple libraries were found for "EEPROMAnything2.h"
 Used: C:\Users\R&D\Documents\Arduino\libraries\EEPROMAnything2
Multiple libraries were found for "Wire.h"
 Used: C:\Program
exit status 1
Error compiling for board Arduino/Genuino Uno.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

after this i do following modification

"EEPROMAnything.h" file

#include <ExtEEPROM.h>
#include <Arduino.h>  // for type definitions

template <class T> int EEPROM_writeAnything(uint8_t i2c_address, int ee, const T& value)
{
  const byte* p = (const byte*)(const void*)&value;
  unsigned int i;
  for (i = 0; i < sizeof(value); i++)
  {
    ExtEEPROM.write(i2c_address, ee++, *p++);
  }
  return i;
}

template <class T> int EEPROM_readAnything(uint8_t  i2c_address, int ee, T& value)
{
  byte* p = (byte*)(void*)&value;
  unsigned int i;
  for (i = 0; i < sizeof(value); i++)
  {
    *p++ = ExtEEPROM.read(i2c_address, ee++);
  }
  return i;
}

Also in the "ExtEEPROM.h"

#ifndef ExtEEPROM_h
#define ExtEEPROM_h

#include <Arduino.h>
#include <Wire.h>

class ExtEEPROMClass
{
 public:
 void write(uint8_t , unsigned int, byte);
 byte read(uint8_t , unsigned int);
};

extern ExtEEPROMClass ExtEEPROM;

#endif

"ExtEEPROM.cpp files:

#include "ExtEEPROM.h"

void ExtEEPROMClass::write(uint8_t i2c_address, unsigned int eeaddress, byte data)
{
  Wire.beginTransmission(i2c_address);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.write(data);
  Wire.endTransmission();
  
  delay(6);
}
 
byte ExtEEPROMClass::read(uint8_t i2c_address, unsigned int eeaddress)
{
  byte rdata = 0xFF;
 
  Wire.beginTransmission(i2c_address);
  Wire.write((int)(eeaddress >> 8));   // MSB
  Wire.write((int)(eeaddress & 0xFF)); // LSB
  Wire.endTransmission();
 
  Wire.requestFrom(i2c_address, 1);
  if (Wire.available())
  {
  rdata = Wire.read();
  }
  return rdata;
}

ExtEEPROMClass ExtEEPROM;

above complied and upload but getting following serial output

10 : -10617

Hi Avinashpudale,

The reason is that you're using an Arduino Uno. On the Arduino Uno the int data type can only store values between -32768 and 32767. In other words int stores only a 16-bit value.

In your test code you're casting the value 1234567 to an int, as this value is larger than 32767 it causes this register to overflow.

I'd try defining variable "y" and casting to a long instead, or use an ARM based Arduino, such as the Due where the int data type is 32-bits.

More information about the int data type can be found here: int - Arduino Reference.

thanks for pointing me int .
now works as expected .

l

MartinL:
Hi,

First add following includes at the beginning of your sketch:

I added the libraries as instructed, did a copy and paste of your code using an ESP8266 device (32 bit int), uploaded and got the following output (with the crap at the beginning, for reasons unclear to me ...)

p⸮dsl{$p⸮o⸮ ⸮d ⸮⸮ co⸮|d⸮ ⸮b⸮⸮gn⸮Begin Test...

-1
nan
255
-1
nan
255
-1
nan
255
End Test...

I'm pretty sure the EEPROM is working and wired correctly, as other test sketches (that store strings) work as expected. As I need to store "numbers", not "letters", your code is of interest, but I'm kinda stumped. Any ideas?