Michael BOUVY
CTO E-commerce

EEPROM advanced usage on Arduino Uno / ATMega328

atmel atmega328 arduino eeprom
Published on 2013/06/17

Storing values in the flash memory of your microcontroller is easy and fast : simply define any variable and assign it a value, you're done. But hat happens if your µC is reset ?

You see where this is going, right ? EEPROM (Electrically-Erasable Programmable Read-Only Memory) is a persistent memory that allows you to store up to 1024 bytes (1 kilobyte) in your microncontroller, even when it's turned off.

Arduino offers a native EEPROM library that allows us to easily deal with the EEPROM of the ATMega328 (or whatever Atmel µC your Arduino is running). Writing and reading values is as simple as following :

 

That said, I guess you're now telling yourself that storing bytes might be quite limiting, and that you'd also like to store ints, chars, or whatever.

Remember, ATMega328 (used in the Arduino Uno) is based on Atmel's AVR architecture, which allows us to use AVR LibC EEPROM functions, of which :

  • void eeprom_write_word (uint16_t *__p, uint16_t __value)
  • void eeprom_write_float (float *__p, float __value)
  • void eeprom_write_block (const void *__src, void *__dst, size_t __n)

As you probably already know, int variables are stored on 2 bytes, and are hence 16 bits long. Also good to know, the type uint16_t is actually (and basically) ... an unsigned int !

Value from analog reading storage example

Let's say you'd like to store into your EEPROM a value read from one of your analog inputs, which will be an integer between 0 and 1023 (10-bits ADC)  :

#include <avr/interrupt.h> 
#include <avr/eeprom.h> 
int addr = 1; 
int sensorValue = 0; 
int readValue = 0; 
void setup() { 
  Serial.begin(9600); 
  while (!eeprom_is_ready()); // Wait for EEPROM to be ready 
  cli(); 
  eeprom_write_word((uint16_t*)addr, sensorValue); // Let's initialize our value into EEPROM 
  sei(); 
} 

void loop() { 
  sensorValue = analogRead(A0); // Value between 0 and 1023 
  while (!eeprom_is_ready()); 
  cli(); 
  if(eeprom_read_word((uint16_t*)addr) != sensorValue) { 
    eeprom_write_word((uint16_t*)addr, sensorValue); 
  } 
  sei(); 
  while (!eeprom_is_ready()); 
  cli(); 
  readValue = eeprom_read_word((uint16_t*)addr); // => sensorValue 
  sei(); 
  Serial.print("Sensor value = "); 
  Serial.println(readValue); 
  delay(1000);
}

Before you begin

  • Always check that EEPROM is ready before reading/writing to it (eeprom_is_ready function)
  • EEPROM storage can handle a limited quantity of erase / write cycles : about 100.000 according to Atmel's specifications
  • Always prefer the "update" functions rather than the "write" ones, as "update" checks first if the stored data is different than the data, so it erases / writes the new data only if it has changed. Edit on June 19th : update functions are not implemented on Arduino ; however, you may (as updated in the example above) check first if the value has changed before writing, or even use the EEPROMex alternative EEPROM Arduino library.
  • Read / write operations on EEPROM should never be interrupted : you should always disable/clear interrupts (cli()) before any operation and re-enable/set interrupts after (sei()).

1 KB's not enough ? External I2C EEPROM

One kilobyte of EEPROM storage may not be enough for your project : there are several external EEPROM chips available, as Microchip's 24AA256 32 KB I2C-enabled EEPROM.

Michael BOUVY

I'm Michael BOUVY, CTO and co-founder of Click&Mortar, a digital agency based in Paris, France, specialized in e-commerce.

Over the last years, I've worked as an Engineering Manager and CTO for brands like Zadig&Voltaire and Maisons du Monde.

With more than 10 years experience in e-commerce platforms, I'm always looking for new challenges, feel free to get in touch!