How to make EEPROM data static

Arduino IDE 1.8.19
Board WEMOS D1 Mini

Basically, does uploading a project overwrite the current EEPROM data stored on the board ?

Here's the project I'm working on, and the intention is that I should only be able to force an EEPROM data "initialisation" on "build_no" change, but it appears that every upload causes the "default" values to be asserted, even though I keep the same build number.

That's not what I want at all, changing the code shouldn't affect the EEPROM data.

To be fair, this project only has 2 parameters, and it's easy to put them back to what they might have been, but what if there was a bigger data structure, that would be a nightmare...

I've used this technique before on Nano projects, and it has appeared to work ok, is there something different with the WEMOS ?

// pRojeCt Bird Scarer
// 

#include "Remote_XY.hpp" 
#include <EEPROM.h>

// define I/O pins
#define         gas_supply D2
#define         ignition D1

// constants
#define         dormant 0       // state engine
#define         timing 1        // state engine
#define         gassing 2       // state engine
#define         firing 3        // state engine
#define         finished 4      // state engine

#define         GUI RemoteXY    // easier to type !


#define         build_no 35     // Build number, change this and the 
                                // EEPROM data will get reset !!

// EEPROM Addresses
#define         eeAddress  0    // start of the eeprom storage space

// volatile data
unsigned long   time_now;
uint16_t        fire_pulse = 3;          //tenth of seconds
uint8_t         cycle = 0;


// Create the EEPROM data structure
struct udt_eeData {
int16_t   runaway_time;     // seconds
int16_t   gassing_time;     // seconds
uint8_t   id;               // this is last to catch structure changes
};

//Create the EEPROM data of type udt_eeData
udt_eeData eeData;

// **********************************************************************

void setup() 
{
  RemoteXY_Init (); 
  
  // set output pin modes and intialise
  pinMode (ignition, OUTPUT);
  digitalWrite(ignition, LOW);
  pinMode (gas_supply, OUTPUT);
  digitalWrite(gas_supply, LOW);

  // retrieve eeData from EEPROM
  EEPROM.get(eeAddress, eeData);

  // initialise eeData if NOT already present
  // THIS SHOULD ONLY OCCUR IF BUILD has changed !!
  if (eeData.id != build_no) 
    {
    eeData.runaway_time = 30;
    eeData.gassing_time = 3;  
    eeData.id = build_no;
    EEPROM.put(eeAddress, eeData);
    }

  // retrieve the settings from eeData
  GUI.runaway_time = eeData.runaway_time;
  GUI.gassing_time = eeData.gassing_time;
  
  // start the serial monitor
  Serial.begin(9600);

  // intialise the operation cycle
  cycle = dormant;
  
  // start our internal time reference
  time_now = millis();
 
} // end setup()

// LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP
void loop() 
  { 
 
  RemoteXY_Handler ();
  
  switch(cycle) 
    {
    case dormant:
      // set output states
      digitalWrite(gas_supply, LOW);
      digitalWrite(ignition, LOW);

      // indications
      GUI.led_ready = 1; 
      GUI.led_timing = 0;
      GUI.led_gassing = 0;
      GUI.led_firing = 0;
      GUI.sound_1 = 0;

      // update EEPROM data if any settings changed
      if(GUI.runaway_time != eeData.runaway_time) 
        {
        eeData.runaway_time = GUI.runaway_time;
        EEPROM.put(eeAddress, eeData);
        }
      if(GUI.gassing_time != eeData.gassing_time) 
        {
        eeData.gassing_time = GUI.gassing_time;
        EEPROM.put(eeAddress, eeData);
        }

      // wait fire button pressed
      if(GUI.fire_button == 1) 
        {
        GUI.runaway_time = eeData.runaway_time;
        GUI.gassing_time = eeData.gassing_time;
        cycle++;  // advance to next stage 
        time_now = millis();
        }
      break;
  
    case timing:
      // indications
      GUI.led_ready = 0; 
      GUI.led_timing = 1;
      GUI.led_gassing = 0;
      GUI.led_firing = 0;
      GUI.sound_1 = 2021;
      if(GUI.runaway_time > 0) 
        {
        // countdown runaway_time
        if(millis() > time_now + 1000) 
          {
          GUI.runaway_time--;
          time_now = millis();
          }
        }
        // have we timed out ?
        if(GUI.runaway_time == 0) 
          {
          cycle++;  // advance to next stage 
          time_now = millis();
          }
      break;

    case gassing: 
      // set output states
      digitalWrite(gas_supply, HIGH);
      // indications
      GUI.led_ready = 0; 
      GUI.led_timing = 0;
      GUI.led_gassing = 1;
      GUI.led_firing = 0;
      GUI.sound_1 = 2011;
      if(GUI.gassing_time > 0)
        {
          // countdown gassing_time
          if(millis() > time_now + 1000) 
            {
            GUI.gassing_time--;
            time_now = millis();
            }
        }
        // have we timed out ?
        if(GUI.gassing_time == 0) 
          {
          cycle++;  // advance to next stage 
          time_now = millis();
          } 
        break;
      
    case firing:
      // set output states
      digitalWrite(gas_supply, LOW);
      digitalWrite(ignition, HIGH);
      // indications
      GUI.led_ready = 0; 
      GUI.led_timing = 0;
      GUI.led_gassing = 0;
      GUI.led_firing = 1;
      if(fire_pulse > 0)
        {
        // countdown fire_pulse (0.1s)
        if(millis() > time_now + 100) 
          {
          fire_pulse--;
          time_now = millis();
          }
        }
      if(fire_pulse == 0) 
        {
        cycle++;  // 
        digitalWrite(ignition, LOW);
        time_now = millis();
        }
      break;

    case finished:
      // reset our volatile data from the constants
      GUI.runaway_time = eeData.runaway_time;
      GUI.gassing_time = eeData.gassing_time;
      fire_pulse = 3;
      cycle = dormant;
    break;
      
  } //switch(cycle):
  
// catchall "abort" button pressed
if(GUI.abort_button) 
  {
  GUI.runaway_time = eeData.runaway_time;
  GUI.gassing_time = eeData.gassing_time;
  fire_pulse = 3;
  cycle = dormant;
  }

  // Serial monitoring
  // values in [ ] are eeData
  Serial.print(build_no);
  
  Serial.print("[");
  Serial.print(eeData.id);
  Serial.print("]");  
    
  Serial.print(" Cycle : ");
  Serial.print(cycle);
  Serial.print(" Delay ");
  Serial.print(GUI.runaway_time);
  
  Serial.print("[");
  Serial.print(eeData.runaway_time);
  Serial.print("]");  
  
  Serial.print(" : Gas ");
  Serial.print(GUI.gassing_time);
  
  Serial.print("[");
  Serial.print(eeData.gassing_time);
  Serial.print("]");  
  
  Serial.print(" : Fire ");
  Serial.println(fire_pulse);

  } //void loop()

I've not posted the GUI (RemoteXY) header block, as it's not relevant

I suggest write out both values to the monitor at this point to confirm their contents (you will need to move Serial.begin() earlier in setup).

I've confirmed that the EEPROM data gets reset to the "default" values after an upload, even though I have this in the code ...

  // initialise eeData if NOT already present
  // THIS SHOULD ONLY OCCUR IF BUILD has changed !!
  if (eeData.id != build_no) 
    {
    eeData.runaway_time = 30;
    eeData.gassing_time = 3;  
    eeData.id = build_no;
    EEPROM.put(eeAddress, eeData);
    }

After upload, those values are always put back, even if the build_no doesn't change.

Actually... if this is an ESP based board then you probably need an EEPROM.commit() after the put.

ESP boards don't have a"real" EEPROM.

I'm fully prepared to admit I've done something daft if you can see what ....

Ahh, so it's virtual EEPROM ?

The WEMOS D1 Mini is an ESP8266 board.

Where does "commit()" write the data to, and is there a way to make it persistent data ?

It's not that important, tbh, probably won't be using an ESP board often, I just thought it should work the same (in my ignorance)

The ESP8266 does not have EEPROM memory, but there is an emulation of it using Flash memory.

The only difference when using is that to persist data you need to "commit" after writing it.

I'll try it, thanks for the heads-up ...

Examples here...

Does not appear to have done the necessary. I've put EEPROM.commit() after every EEPROM.put(...), and it is still re-initialising the EEPROM default values.

No problem, in this project ....

perhaps it's to do with the declaration of the EEPROM address. Does it have be located in a "special" memory area ?


#include "Remote_XY.hpp" 
#include <EEPROM.h>

// define I/O pins
#define         gas_supply D2
#define         ignition D1

// constants
#define         dormant 0       // state engine
#define         timing 1        // state engine
#define         gassing 2       // state engine
#define         firing 3        // state engine
#define         finished 4      // state engine

#define         GUI RemoteXY    // easier to type !


#define         build_no 35     // Build number, change this and the 
                                // EEPROM data will get reset !!

// EEPROM Addresses
#define         eeAddress  0    // start of the eeprom storage space

// volatile data
unsigned long   time_now;
uint16_t        fire_pulse = 3;          //tenth of seconds
uint8_t         cycle = 0;


// Create the EEPROM data structure
struct udt_eeData {
int16_t   runaway_time;     // seconds
int16_t   gassing_time;     // seconds
uint8_t   id;               // this is last to catch structure changes
};

//Create the EEPROM data of type udt_eeData
udt_eeData eeData;

// **********************************************************************

void setup() 
{
  RemoteXY_Init (); 
  
  // set output pin modes and intialise
  pinMode (ignition, OUTPUT);
  digitalWrite(ignition, LOW);
  pinMode (gas_supply, OUTPUT);
  digitalWrite(gas_supply, LOW);

  // retrieve eeData from EEPROM
  EEPROM.get(eeAddress, eeData);

  // initialise eeData if NOT already present
  // THIS SHOULD ONLY OCCUR IF BUILD has changed !!
  if (eeData.id != build_no) 
    {
    eeData.runaway_time = 30;
    eeData.gassing_time = 3;  
    eeData.id = build_no;
    EEPROM.put(eeAddress, eeData);
    EEPROM.commit();
    }

  // retrieve the settings from eeData
  GUI.runaway_time = eeData.runaway_time;
  GUI.gassing_time = eeData.gassing_time;
  
  // start the serial monitor
  Serial.begin(9600);

  // intialise the operation cycle
  cycle = dormant;
  
  // start our internal time reference
  time_now = millis();
 
} // end setup()

// LOOP - LOOP - LOOP - LOOP - LOOP - LOOP - LOOP
void loop() 
  { 
 
  RemoteXY_Handler ();
  
  switch(cycle) 
    {
    case dormant:
      // set output states
      digitalWrite(gas_supply, LOW);
      digitalWrite(ignition, LOW);

      // indications
      GUI.led_ready = 1; 
      GUI.led_timing = 0;
      GUI.led_gassing = 0;
      GUI.led_firing = 0;
      GUI.sound_1 = 0;

      // update EEPROM data if any settings changed
      if(GUI.runaway_time != eeData.runaway_time) 
        {
        eeData.runaway_time = GUI.runaway_time;
        EEPROM.put(eeAddress, eeData);
        EEPROM.commit();
        }
      if(GUI.gassing_time != eeData.gassing_time) 
        {
        eeData.gassing_time = GUI.gassing_time;
        EEPROM.put(eeAddress, eeData);
        EEPROM.commit();
        }

      // wait fire button pressed
      if(GUI.fire_button == 1) 
        {
        GUI.runaway_time = eeData.runaway_time;
        GUI.gassing_time = eeData.gassing_time;
        cycle++;  // advance to next stage 
        time_now = millis();
        }
      break;
  
    case timing:
      // indications
      GUI.led_ready = 0; 
      GUI.led_timing = 1;
      GUI.led_gassing = 0;
      GUI.led_firing = 0;
      GUI.sound_1 = 2021;
      if(GUI.runaway_time > 0) 
        {
        // countdown runaway_time
        if(millis() > time_now + 1000) 
          {
          GUI.runaway_time--;
          time_now = millis();
          }
        }
        // have we timed out ?
        if(GUI.runaway_time == 0) 
          {
          cycle++;  // advance to next stage 
          time_now = millis();
          }
      break;

    case gassing: 
      // set output states
      digitalWrite(gas_supply, HIGH);
      // indications
      GUI.led_ready = 0; 
      GUI.led_timing = 0;
      GUI.led_gassing = 1;
      GUI.led_firing = 0;
      GUI.sound_1 = 2011;
      if(GUI.gassing_time > 0)
        {
          // countdown gassing_time
          if(millis() > time_now + 1000) 
            {
            GUI.gassing_time--;
            time_now = millis();
            }
        }
        // have we timed out ?
        if(GUI.gassing_time == 0) 
          {
          cycle++;  // advance to next stage 
          time_now = millis();
          } 
        break;
      
    case firing:
      // set output states
      digitalWrite(gas_supply, LOW);
      digitalWrite(ignition, HIGH);
      // indications
      GUI.led_ready = 0; 
      GUI.led_timing = 0;
      GUI.led_gassing = 0;
      GUI.led_firing = 1;
      if(fire_pulse > 0)
        {
        // countdown fire_pulse (0.1s)
        if(millis() > time_now + 100) 
          {
          fire_pulse--;
          time_now = millis();
          }
        }
      if(fire_pulse == 0) 
        {
        cycle++;  // 
        digitalWrite(ignition, LOW);
        time_now = millis();
        }
      break;

    case finished:
      // reset our volatile data from the constants
      GUI.runaway_time = eeData.runaway_time;
      GUI.gassing_time = eeData.gassing_time;
      fire_pulse = 3;
      cycle = dormant;
    break;
      
  } //switch(cycle):
  
// catchall "abort" button pressed
if(GUI.abort_button) 
  {
  GUI.runaway_time = eeData.runaway_time;
  GUI.gassing_time = eeData.gassing_time;
  fire_pulse = 3;
  cycle = dormant;
  }

  // Serial monitoring
  // values in [ ] are eeData
  Serial.print(build_no);
  
  Serial.print("[");
  Serial.print(eeData.id);
  Serial.print("]");  
    
  Serial.print(" Cycle : ");
  Serial.print(cycle);
  Serial.print(" Delay ");
  Serial.print(GUI.runaway_time);
  
  Serial.print("[");
  Serial.print(eeData.runaway_time);
  Serial.print("]");  
  
  Serial.print(" : Gas ");
  Serial.print(GUI.gassing_time);
  
  Serial.print("[");
  Serial.print(eeData.gassing_time);
  Serial.print("]");  
  
  Serial.print(" : Fire ");
  Serial.println(fire_pulse);

  } //void loop()
  

For using the emulated eeprom of the esp8266 along with EEPROM.commit() you also need to put this line in setup to tell the device how much of the nonvolatile memory to reserve for the "eeprom".

EEPROM.begin(number of bytes)

Thanks - I try ....

BOOM ! - That's perfect cattledog !

It survived a power-cycle ....

And thanks to red_car too for the "commit" tip.

You guys are the best ....

I went OTT and reserved 128 bytes for the emulated EEPROM space, just in case I expand the structure size, but it shouldn't be an issue ....

Sketch uses 281221 bytes (26%) of program storage space. Maximum is 1044464 bytes.
Global variables use 28248 bytes (34%) of dynamic memory, leaving 53672 bytes for local variables. Maximum is 81920 bytes.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.