EEPROM Initialization/State Recovery

Problem:
When the Arduino starts up I am reading values from the EEPROM to get the status before the Arduino did shut down the last time, i.e based on the value in the EEPROM I am trying to restore the state before the Arduino did shut down.

Question:
How do I handle the situation where I start up the Arduino for the very first time? In this case the Arduino never ran before and therefore never wrote any values to the EEPROM. So what I would read is just some random value, i.e. whatever the previous program did write to the EEPROM.

Thinking about it, maybe the entire EEPROM is reset to 0xff each time a new program is downloaded to the Arduino. So assume I store the program ‘version’ at EEPROM address 0 and the program version is <0xff. So if I read a value <0xff I know my program was ran before and I can restore the previous state. However, if the value is 0xff then I know the program never ran before and I set the value to a default value.

How do I handle the situation where I start up the Arduino for the very first time?

Method 1 : Write a small EEPROM initialisation sketch to set the values for the first time

Method 2 : Store a value or string in the EEPROM that will indicate that the program has previously been run when saving values. If the value/string is not there or is wrong on startup set your values to defaults. Save the flag value/string when you save the values so it is there next time

Thanks UKHeliBob. Having a separate sketch to set the values for the first time is not practical in my case. So I guess I will just use the first 4 bytes for a predefined 'IsInitialized' flag. If the EEPROM status can be considered random then there would be a 1:4billion chance that I pick up wrong values. I can further reduce that chance by applying some constraints to those values. It seems to me that's the best way to go. Thanks!

I just joined here, so your timing fortuitous. I have a similar problem - saving and restoring global state from EEProm.

I wrote a support class to do all that, and also to do wear levelling so that no one piece of EEProm wears out.

Basically, you create a structure with your global data, and wrap this template around it. It adds a bit of extra data (3 bytes) for a signature and to implement wear levelling.

I'll try to clean it up and post it here tomorrow, it might give you some ideas, or if it works for you just use it if you like.

Here’s code I have, there’s a very simple sketch attached to show how it’s used.

EEPromStorage.h (6.33 KB)

sketch_feb23a.ino (1.81 KB)

Over time, you’ll add or change how the EEPROM is organised with revisions of your code.
I store an int in the EEPROM with a version number and check bits… then when starting up, read that int, verify it’s the correct EEPROM layout for the current code - and move forward.
If the EEPROM signature is wrong or out of range, prompt the user and initialise the EEPROM to the current default startup values.

lastchancename:
Over time, you’ll add or change how the EEPROM is organised with revisions of your code.
I store an int in the EEPROM with a version number and check it... then when starting up, read that int, verify it’s the correct EEPROM layout for the current code - and move forward.
If the EEPROM signature is wrong or out of range, prompt the user and initialise the EEPROM to the current default startup values.

That is the method I use, and I use a structure to store the variables I want to save. I make my "version" the LAST member of the structure, such that if I change the number of variables, or their sizes, it will surely be at a different starting byte in the EEPROM data. That will then force a re-initialisation of the stored data to my defaults.

Here's an example of my last post....

before setup()

// EEPROM Addresses
const String SETTINGS_ID = "MyProject";
const int SETTINGS_ADDRESS = 64;

// Create the settings udt
// This data is written to EEPROM when the "Save_Settings" button is pressed.
struct udt_Settings {
  bool    PHop_Rev;       // 0 = Normal, 1 = Reversed 
  bool    SHop_Rev;       // 0 = Normal, 1 = Reversed 
  bool    PHkr_Rev;       // 0 = Normal, 1 = Reversed 
  bool    SHkr_Rev;       // 0 = Normal, 1 = Reversed 
  int8_t  HopperTrim;     // -100 to 100%
  int8_t  StbdHopper;     // 0 to 100%
  int8_t  PortHopper;     // 0 to 100% 
  int8_t  HookRelTrim;    // -100 to 100% 
  int8_t  StbdHookRel;    // 0 to 100% 
  int8_t  PortHookRel;    // 0 to 100%
  float   Batt_Offset;    // 
  float   Batt_Gain;      //
  float   Batt_Low_Thr;   // 
  byte    HopperLEDTime;  // 
  String  id;             // this is last to catch structure changes
};

//Create the settings data of type udt_Settings
udt_Settings settings;

in setup()

  // retrieve settings from EEPROM
  
settingsLOAD();

// initialise start-up settings if not present
if (settings.id != SETTINGS_ID) {
  settings.PortHopper = 75;   // 0 to 100 % : set low to protect servo
  settings.StbdHopper = 75;   // 0 to 100 % : set low to protect servo 
  settings.PortHookRel = 75;  // 0 to 100 % : set low to protect servo
  settings.StbdHookRel = 75;  // 0 to 100 % : set low to protect servo
  settings.PHkr_Rev = 0;      // 0 = Normal, 1 = Reversed 
  settings.SHop_Rev = 0;      // 0 = Normal, 1 = Reversed 
  settings.PHop_Rev = 0;      // 0 = Normal, 1 = Reversed 
  settings.SHkr_Rev = 0;      // 0 = Normal, 1 = Reversed 
  settings.HopperTrim = 0;    // -100 to +100 : centred 
  settings.HookRelTrim = 0;   // -100 to +100 : centred 
  settings.Batt_Offset = 0;
  settings.Batt_Gain = 0;
  settings.Batt_Low_Thr = 0;
  settings.id = SETTINGS_ID;
     
settingsSAVE();
}

I write to the EEPROM maybe once a day max (probably more like once a week). The EEPROM supposedly should be good for 100,000 modifications before becoming unstable. That should be good for about 270 years if I write once a day. Of course, for other scenarios a ‘write leveling’ makes sense.

Daba, why would you write the version at the end? Well, you did explain it but I am not sure this makes much sense. Assume you are changing your structure and where you expect the version to be you now have some value but that value happens to be the same as your version. Maybe it’s not very likely but why take that risk. When I use versioning I make it a case to use the very first value as the version. That way I can also easily handle different versions. When the version is 1 then I know I need to read it as version 1, when the version is 2 then I know I need to read it as version 2, etc.

mulu:
Thinking about it, maybe the entire EEPROM is reset to 0xff each time a new program is downloaded to the Arduino.

It is not. The EEPROM is not touched by normal Arduino programming.

An unused chip will have all of it's EEPROM values initialized to FF. If you're loading the sketch onto a new chip, you just need to detect FF then overwrite it with something to indicate it's been initialized.

A separate EEPROM wiping sketch is only necessary if you're loading this onto a chip that already had its EEPROM messed with by another sketch. In that case you just need to load the wiping program and let it run once, then load this sketch. You only need to clear the EEPROM if some other sketch messed around with it. Why would this be impractical?

mulu:
Daba, why would you write the version at the end? Well, you did explain it but I am not sure this makes much sense. Assume you are changing your structure and where you expect the version to be you now have some value but that value happens to be the same as your version. Maybe it's not very likely but why take that risk. When I use versioning I make it a case to use the very first value as the version. That way I can also easily handle different versions. When the version is 1 then I know I need to read it as version 1, when the version is 2 then I know I need to read it as version 2, etc.

My method means I don't have to remember to change the version number each time I upload the sketch, it will automatically detect that the EEPROM data structure may have changed in some way and re-intialise default values.

On the subject of the number and frequency of writes, if you use EEPROM.put(address, data) it will only write to EEPROM if the data byte(s) have changed, which is of course exactly what you need, so it is safe to .put as often as you want to... at least that is how I read it ... and I'm sure I have read somewhere that .write uses .put, which in turn uses .update, only writing if the byte has changed.

Since my "version" is a string, the likelihood of getting identical values at those byte locations from previous data is astronomically remote.