Become a subscriber (Free)

Join 29,000 other subscribers to receive subscriber sale discounts and other free resources.
:
:
Don't worry -- youre-mail address is totally secure. I promise to use it only to send you MicroZine.

Arduino EEPROM

The Arduino EEPROM  (Electrically Erasable Programmable Read Only Memory) is a high endurance Flash memory block. It is dedicated to saving data between sessions (power down and power up of the microcontroller).


On this page your can find out how to preserve the life of EEPROM as well as sketches showing how to save and restore multiple data elements.

There are two rewritable memories and it is useful to compare their capabilities. The Flash memory area of the microcontroller (that stores your program) is capable of being re-written (when you download a new program to the Arduino!). This memory, however, has a lower rewrite capability:

  Device Memory Type Size Rewrites
  AtMega328P (Arduino Uno) Flash 32kB>10,000
  AtMega328P (Arduino Uno) EEPROM 1kB >100,000

Flash lifetime

A useful thing to do, is to see how long normal Flash memory will last if you write to it 10 times per day. It turns out that it will last at least 10000.0/10.0 = 1000 Days or 2.7 years). Of course you won't update a program every day and you will use a new device for new projects, so it will last far longer than that.

EEPROM lifetime

Using the EEPROM 10 times a day the  EEPROM life will be 100000/10 # 10000 Days or 27 Years!

In reality EEPROM is use differently to FLASH memory, since an EEPROM is designed for updated data. The program itself will update EEPROM for saving parameters that are required between power up and power down. You can store any data e.g. calibration parameters or current instrument settings.

How to preserve EEPROM

I was once at a firm that managed to have their units randomly fail.

The EEPROM was being written continuously to the same location to save data as parameters changed. The problem was that the data was always written every time round the program loop, so even with the huge lifetime of the EEPROM it was written so much that the EEPROM wore out.

The solution they chose was to move the starting write address after every block of data was written so that the same area of EEPROM was not continuously used; Extending the life of the EEPROM.

A better way is to make sure you only write to the EEPROM at a defined time. For instance if a user starts a calibration sequence - only write it once after that has ended. Alternatively update parameters on brown-out detection or power down initiation.

Never write to the same address in EEPROM memory from within a for loop!

Note: Reading from the EEPROM does not degrade the memory. You can read an EEPROM address as many times as you want.

TIP: To extend EEPROM life first read the contents to be written - if it is the same as the value you want to write, then don't write to it!

TIP: Each time you write a set of data - read it back to ensure it was written correctly. If it fails then retry. If there are multiple failures then generate an error e.g an message to a screen or light a red LED.

A write of one byte takes 3.3ms [source Arduino documentation] - however it seems faster (see output from programs below).

Arduino EEPROM functions

EEPROM Read and Write Bytes

The basic unit of an EEPROM transaction is a byte. To read and write these bytes you can use the following functions:

    EEPROM.write(address, byteValue);
    EEPROM.read(address);         // returns a byte.

EEPROM Write a Changed byte

    EEPROM.update(address, bytevalue);

This function will only perform a write operation if the current value is not the same as bytevalue. So it saves you from wearing out EEPROM if you try and write the same byte to the EEPROM.

Really, this is the function you should use to preserve the EEPROM memory. The only reason not to do so, is that it must perform a read first so it will be slower than an EEPROM.write operation.

EEPROM Write Standard type or Structure

It is Ok writing bytes, but there's an easier way to write a set of data to the EEPROM and that us by using the put function (get is the equivalent for retrieval).

The put function writes out a set of bytes using the update function. In addition it measures the size of the data type being used to write out the correct number of bytes.

You can use this function to write out an char, int, long or float type object without knowing the number of bytes used by the type object. So this function is portable across different compilers (that use different type sizes).

The really useful point about this function is that it can also write out your own defined types e.g. if you create a struct type (with lots if variables inside) then it will write a variable of this type to EEPROM without you having to know the number of bytes that the type occupies.

The upshot is, if you bundle your data into a structure then it is easy to put and get it, to and from EEPROM.

    EEPROM.put(address,data);
    EEPROM.get(address,data);

Multi variable EEPROM read/write

The previous member functions are useful for writing single bytes or single struct objects to/from EEPROM but quite often want to switch between sets of data (or store more than just a single variable).

This is especially useful for a system where you are trying out different options (and you don't want to recompile each time just to change a few control parameters!).

You just want to select from a set of previously saved data.

Single Type Method Sketch1

The Idea here is to store a set of simple type variables sequentially in the EEPROM at a specific EEPROM address.

Just attach a push button connected to ground and pin 5 of the Arduino. On start up the EEPROM values are retrieved from the EEPROM and sent to serial Monitor.

When you push the button random values are saved to the EEPROM. To retrieve the values simply press the reset button on the Arduino and these same numbers are displayed (having been read from the EEPROM).

When you hit the button you can also see write execution time.

// Storing variables in EEPROM
// Sequential read / write of variables.
#include <EEPROM.h>

#define BUTTON_TEST 5
#define EEADDR 166 // Start location to write EEPROM data.

static unsigned int minx,maxx,miny,maxy;

void show_vars(void) {
   Serial.print("MIN x "); Serial.println(minx);
   Serial.print("MAX x "); Serial.println(maxx);
   Serial.print("MIN y "); Serial.println(miny);
   Serial.print("MAX y "); Serial.println(maxy);
}

void setup() {

   pinMode(BUTTON_TEST,INPUT_PULLUP);
   pinMode(LED_BUILTIN,OUTPUT);
   digitalWrite(LED_BUILTIN,LOW);

   Serial.begin(115200);

   Serial.println("EEPROM variable read and write.");

   // Read EEPROM
   int EEAddr = EEADDR;
   EEPROM.get(EEAddr,minx); EEAddr +=sizeof(minx);
   EEPROM.get(EEAddr,maxx); EEAddr +=sizeof(maxx);
   EEPROM.get(EEAddr,miny); EEAddr +=sizeof(miny);
   EEPROM.get(EEAddr,maxy); EEAddr +=sizeof(maxy);

   show_vars();
}

void loop() {
     static unsigned long timeWas, timeNow;

     int r = random(100, 65535);
     minx = r;
     maxx = r+1;
     miny = r+2;
     maxy = r+3;

     Serial.println("Press button to write to EEPROM");

     if (digitalRead(BUTTON_TEST)==0) {
        digitalWrite(LED_BUILTIN,HIGH);

        int EEAddr = EEADDR;
        timeWas = micros();
        EEPROM.put(EEAddr,minx); EEAddr +=sizeof(minx);
        EEPROM.put(EEAddr,maxx); EEAddr +=sizeof(maxx);
        EEPROM.put(EEAddr,miny); EEAddr +=sizeof(miny);
        EEPROM.put(EEAddr,maxy); EEAddr +=sizeof(maxy);
        timeNow = micros();

        Serial.println("EEPROM Written");
        show_vars();

        Serial.print("EEPROM Write time  (us) ");
        Serial.println(timeNow-timeWas);
        Serial.print("EEPROM Write time per byte (us) ");
        Serial.println((timeNow-timeWas)/(4*sizeof(minx))); // same type.

        delay (500);
        digitalWrite(LED_BUILTIN,LOW);
     }
     delay(500);
}
[eeprom1.ino]


Here's an example of the output from the serial monitor:

Press button to write to EEPROM
EEPROM Written
MIN x 58478
MAX x 58479
MIN y 58480
MAX y 58481
EEPROM Write time  (us) 23300
EEPROM Write time per byte (us) 2912
Press button to write to EEPROM
Press button to write to EEPROM
Press button to write to EEPROM
Press button to write to EEPROM
EEPROM variable read and write.
MIN x 58478
MAX x 58479
MIN y 58480
MAX y 58481
Press button to write to EEPROM

The lower text beginning 'MIN X' is the read-back output after hitting the reset button. The first one is the 'write action' after hitting the push button.

Struct type Method Sketch2

The Idea here is to use a structure to store data at a specific EEPROM address.

Using a struct object allows you to group variables together and use the EEPROM.put() and get() to access the EEPROM. These functions make it trivial to store and retrieve the structure data to/from the EEPROM.

The following program is very similar to the above but uses a struct variable instead of lots of different ones. Note how you could use multiple struct variables in the program since pointers are used to display the contents of the struct variable 'StoreData'.

// Storing struct variables in EEPROM
// Sequential read / write of variables.
#include <EEPROM.h>

#define BUTTON_TEST 5
#define EEADDR 166 // Start location to write EEPROM data.

// Put variables into structure.
struct StoreData_s {
   float kp;       // kp, ki and kd store normalised values to 1000ms
   float ki;       // They are recalculated in the PID algorithm
   float kd;       // proportional to the sample time.
   int dt;         // SampleTime
   int limitR;     // limit roll
   int limitP;     // limit pitch
};

StoreData_s StoreData = {1,0.1,0,1000,30,60};

void show_vars(StoreData_s *p) {
   Serial.print("Kp "); Serial.println(p->kp);
   Serial.print("Ki "); Serial.println(p->ki);
   Serial.print("Kd "); Serial.println(p->kd);
   Serial.print("dt "); Serial.println(p->dt);
   Serial.print("LR "); Serial.println(p->limitR);
   Serial.print("LP "); Serial.println(p->limitP);
}

void setup() {

   pinMode(BUTTON_TEST,INPUT_PULLUP);
   pinMode(LED_BUILTIN,OUTPUT);
   digitalWrite(LED_BUILTIN,LOW);

   Serial.begin(115200);

   Serial.println("EEPROM struct read and write.");

   // Read EEPROM
   EEPROM.get(EEADDR, StoreData);
   show_vars(&StoreData);
}

void loop() {
     static unsigned long timeWas, timeNow;

     int r = random(100, 65535);
     StoreData.kp = r++;
     StoreData.ki  = r++;
     StoreData.kd  = r++;
     StoreData.dt  = r++;
     StoreData.limitR  = r++;
     StoreData.limitP  = r++;

     Serial.println("Press button to write struct to EEPROM");

     if (digitalRead(BUTTON_TEST)==0) {
        digitalWrite(LED_BUILTIN,HIGH);

        timeWas = micros();
        EEPROM.put(EEADDR,StoreData);
        timeNow = micros();

        Serial.println("EEPROM Written");
        show_vars(&StoreData);

        Serial.print("EEPROM Write time  (us) ");
        Serial.println(timeNow-timeWas);
        Serial.print("EEPROM Write time per byte (us) ");
        Serial.println( (timeNow-timeWas)/(sizeof(StoreData)) );

        delay (500);
        digitalWrite(LED_BUILTIN,LOW);
     }
     delay(500);
}

[eeprom2.ino]

Here an example of the output from the serial monitor:

Press button to write struct to EEPROM
EEPROM Written
Kp -4639.00
Ki -4638.00
Kd -4637.00
dt -4636
LR -4635
LP -4634
EEPROM Write time  (us) 46596
EEPROM Write time per byte (us) 2588
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
Press button to write struct to EEPROM
EEPROM struct read and write.
Kp -4639.00
Ki -4638.00
Kd -4637.00
dt -4636
LR -4635
LP -4634
Press button to write struct to EEPROM
The top data is displayed after pressing the button while the lower data is displayed after pressing reset on the Arduino.

Note: Write times will vary if the same data is detected in the EEPROM. For accurate timing use the write function (you would write your own version of put() that does not perform a read).

Frequently Asked Questions

How to reset an EEPROM.

The EEPROM can be erased during programming using the chip erase function.

The EEPROM does not really need resetting since it stores whatever was programmed into it (there is no EEPROM reset operation). You are probably wanting to initialise it.

One way is to perform a write to EEPROM during normal program operation - or use a button input to indicate rewrite (as in above programs - but choose another button).

Alternatively create a separate sketch and loop 0 to 999, write each byte as 0xFF.

Note: The erased state of the EEPROM is 0xff.

How to clear Arduino EEPROM.

You have to to write to it as above or use the chip erase function (during serial programming).

How to erase Arduino EEPROM.

Same as above.

Arduino EEPROM vs Progmem

As described earlier, Flash memory (PROGMEM) has a lower lifetime than EEPROM. So EEPROM is useful for data that should be stored between sessions (or logged in a data logging application).

Arduino EEPROM vs Flash

Same as above.

Arduino EEPROM vs SD card.

The advantage of an EEPROM is that it is fast .
The disadvantage of an EEPROM is that it is small (1k Byte)

The advantage of an SD card is that it is huge (Giga Bytes).
The disadvantage of an SD card is that it is slow.
The disadvantage of an SD card interface is that it needs a RAM buffer (probably 2 of about 512 bytes of SRAM each).

The SD card takes time to write - hence the need for a double buffer. One buffer is updated while the other is written.

Comparisons of EEPROM member functions

Arduino EEPROM put vs update

    update() operates on a single byte.
        It reads, and then writes to an address only if the byte is different.
        This is the byte primitive function used by put().

    put() writes multiple bytes starting from an address.
        The number of bytes written is the size of the type.
        put() uses the update function
            (which only overwrites data if it has changed - to preserve memory).

Arduino EEPROM update vs write

   update() operates on a single byte.
        It reads, and then writes to an address only if the byte is different.
        This is the byte primitive function used by put().      

    write() operates on a single byte.
        It writes a single byte to an address. 

Arduino EEPROM get vs read

   read() operates on a single byte.
        It reads a single byte from an address.        

    get() reads multiple bytes starting from an address.
        The number of bytes read is the size of the type.

Arduino EEPROM write vs put   

    write() operates on a single byte.
        It writes a single byte to an address.

    put() writes multiple bytes starting from an address.
        The number of bytes written is the size of the type.
        put() uses the update function
            (which only overwrites data if it has changed - to preserve memory).


New! Comments

Have your say about what you just read! Leave me a comment in the box below.




Privacy Policy | Contact | About Me

Site Map | Terms of Use



Visit our Facebook Page:
To Visit Click Here


Recent Articles

  1. How to use Arduino shiftOut() for controlling chips with a 3 wire serial interface

    The Arduino shiftOut() function can simply control many different serial interfaced chips. Find out how it works and how fast it operates.

    Read more

  2. How to use the ADS1115

    A tutorial on using the ADS1115 precision 16 bit ADC for low power use.

    Read more

  3. The TP4056: Lithium Ion/polymer Battery Charger IC

    Learn how to use the TP4056 properly. There's a right, and a wrong way, to use it to safely charge Lithium Ion batteries.

    Read more

  4. How to use the MCP4922, a versatile 2 channel analogue output device

    The MCP4922 chip is an SPI interfaced 12 bit DAC but how fast can it go? Find out here.

    Read more

  5. How to use the MCP4725, a versatile and tiny (SOT-23-6) analogue output device

    The MCP4725 chip is a 12 bit DAC with memory that outputs voltage that you can use for many dfferent purposes. Find out what they are in this page.

    Read more

  6. How to use the MCP4728, a versatile four channel DAC with built in voltage reference.

    The MCP4728 chip is a four channel 12 bit DAC, with memory that outputs voltage that you can use for calibration, anywhere you want a fixed voltage.

    Read more

Readers Comments

"I wanted to thank
you so so so much
for all the information
you have provided in
your site it's

SUPERB and FANTASTIC."

- Ranish Pottath

"This site really is
the best and my favorite.
I find here many useful
projects and tips."

- Milan

bursach<at>gmail.com<

"Awesome site,
very, very easy and nice
to navigate!"


- Matt
matt_tr<at>
wolf359.cjb.net


Learn Microcontrollers

"Interested in
Microcontrollers?"

Sign up for The
Free 7 day guide:

FREE GUIDE : CLICK HERE


"I am a newbie to PIC
and I wanted to say
 how great your
site has been for me."


- Dave

de_scott<at>bellsouth.net

"Your site is a great
and perfect work.
congratulations."


- Suresh

integratredinfosys<at>
yahoo.com

"I couldn't find the correct
words to define
yourweb site.

Very useful, uncovered,
honest and clear.

Thanks so much for
your time and works.
Regards."


- Anon

Back to Top