Reading and Writing an External I2C 24LC256 EEPROM
This code demonstrates how to read and write any data type, such as strings to an external I2C EEPROM. I am sharing this code as I wasn’t happy with the other examples I found on the Internet, which I found to be too complicated.
#include <Wire.h> #include "i2ceeprom.h" // struct containing a text array for storage in the EEPROM struct text_t { char text[100]; }; int address = 0; void setup() { Wire.begin(); Serial.begin(115200); } void loop() { text_t input; while (Serial.available() < 1) { delay(100); } // obtain array of characters from Serial port uint8_t i = 0; while (Serial.available() > 0) { input.text[i++] = (char) Serial.read(); } input.text[i++] = '\0'; // Write the input object (which contains a text array) // to the i2C EEPROM. This does not work with an array directly // as the array must be within a struct. address += eeWrite(address, input); config.count++; eeWrite(0, config); // loop through all of the output text unsigned int output_address = config.start; text_t output; while (output_address < config.start+(sizeof(output)*config.count)) { Serial.print(output_address); Serial.print(" "); output_address += eeRead(output_address, output); Serial.print(output.text); } }
Here is the header file to include that includes the related functions.
#include <Arduino.h> // for type definitions #define DEVICE 0x50 // Read one byte byte eeReadByte(unsigned int address) { byte read_data = 0xFF; Wire.beginTransmission(DEVICE); Wire.write((int)(address >> 8)); // MSB Wire.write((int)(address & 0xFF)); // LSB Wire.endTransmission(); // Request 1 byte from device Wire.requestFrom(DEVICE, 1); // if successful return if (Wire.available()) read_data = Wire.read(); return read_data; } // Write one byte (could be made faster by using page write) // but I've decided not to implement this as speed is not a consideration // for my projects (I can wait for the data to be written while I do other things) void eeWriteByte(unsigned int address, byte data) { if (data == eeReadByte(address)) return; // minimize data writes for speed // and wear on memory Wire.beginTransmission(DEVICE); Wire.write((int)(address >> 8)); // MSB Wire.write((int)(address & 0xFF)); // LSB Wire.write(data); // Write byte Wire.endTransmission(); // Writing in I2C DEVICE takes ~5ms (even if I2C writing already done) delay(5); } // eeWrite is the user function that converts an object into // a byte stream and then calls eeWriteByte to write the data // // int ee = Address to write // const T& = Any type of object (EXCEPT ARRAY) to write, such as // byte, int, char, struct. If you want to save // an array of any type such as a character array, // you should put the array within in a struct // or use another non-array type like the string class. template <class T> int eeWrite(int ee, const T& obj) { // cast object to a void then to a byte const byte* p = (const byte*)(const void*)&obj; // for each byte, write it for (unsigned int i = 0; i < sizeof(obj); i++) eeWriteByte(ee++, *p++); // return the size of data written so we can increment // our address variable to know the location of the next address return sizeof(obj); } // eeRead is the user function that converts an object into // a byte stream and then calls eeReadByte to write the data // // int ee = Address to start of reading // const T& = Any type of object (EXCEPT ARRAY) to read, such as // byte, int, char, struct. That number of bytes will // be fetched from the eeprom, with data converted back // into the proper data type. template <class T> int eeRead(int ee, T& obj) { byte* p = (byte*)(void*)&obj; for (unsigned int i = 0; i < sizeof(obj); i++) *p++ = eeReadByte(ee++); return sizeof(obj); }
1 Comment
Hi Andy?
Thanks for sharing this code.
Being Dutch I stumbled searching for more info about this code on your site on the Dutch settlement state forest. The name must be very old.
I was very happy to find a example to write more than 32 bytes to EEPROM after many attemps to write it myself.
Unfortunately when compiling for an Arduino Uno I get an error.
The use of templates in C++ like:
template int eeRead(int ee, T& obj) { byte* p = (byte*)(void*)&obj;
is just too much for me to debug.
Where is the config. coming from? Or is is an old Wire command
Can you help me with this error?
All the best
Ed
C:\Users\ednie\Documents\Files\Arduino\DS3231_EEPROM\RWEEPROM\RWEEPROM.ino: In function ‘void loop()’:
RWEEPROM:35:3: error: ‘config’ was not declared in this scope
config.count++;
^~~~~~
C:\Users\ednie\Documents\Files\Arduino\DS3231_EEPROM\RWEEPROM\RWEEPROM.ino:35:3: note: suggested alternative: ‘cosf’
config.count++;
^~~~~~
cosf
exit status 1
‘config’ was not declared in this scope