EEPROM issues on ESP32

Im using a LOLIN32 Lite board, and it seems that i lose stuff that's stored in the EEPROM every time i flash a new version of my code onto it. Is this normal?

Im using the PUT & GET examples from here : https://docs.arduino.cc/learn/programming/eeprom-guide

I only added:

#include <EEPROM.h>
#define EEPROM_SIZE 4095

and

EEPROM.begin(EEPROM_SIZE);

Other than that, i did not change anything. And if i flash the PUT first, and then the GET. It just reads garbage.

I had a more complex code going, but wanted to check by using some simple example. Because it worked as long as i did the save before reading.

GET EXAMPLE

#include <EEPROM.h>
#define EEPROM_SIZE 4095

void setup() {

  EEPROM.begin(EEPROM_SIZE);

  float f = 0.00f;   //Variable to store data read from EEPROM.

  int eeAddress = 0; //EEPROM address to start reading from

  Serial.begin(115200);

  delay(1000);

  Serial.print("Read float from EEPROM: ");

  //Get the float data from the EEPROM at position 'eeAddress'

  EEPROM.get(eeAddress, f);

  Serial.println(f, 3);    //This may print 'ovf, nan' if the data inside the EEPROM is not a valid float.

  /***

    As get also returns a reference to 'f', you can use it inline.

    E.g: Serial.print( EEPROM.get( eeAddress, f ) );

  ***/

  /***

    Get can be used with custom structures too.

    I have separated this into an extra function.

  ***/

  secondTest(); //Run the next test.
}

struct MyObject {

  float field1;

  byte field2;

  char name[10];
};

void secondTest() {

  int eeAddress = sizeof(float); //Move address to the next byte after float 'f'.

  MyObject customVar; //Variable to store custom object read from EEPROM.

  EEPROM.get(eeAddress, customVar);

  Serial.println("Read custom object from EEPROM: ");

  Serial.println(customVar.field1);

  Serial.println(customVar.field2);

  Serial.println(customVar.name);
}

void loop() {

  /* Empty loop */
}

PUT EXAMPLE:

#include <EEPROM.h>
#define EEPROM_SIZE 4095

struct MyObject {

  float field1;

  byte field2;

  char name[10];
};

void setup() {

 
  EEPROM.begin(EEPROM_SIZE);

  Serial.begin(115200);

   delay(1000);

  float f = 123.456f;  //Variable to store in EEPROM.

  int eeAddress = 0;   //Location we want the data to be put.

  //One simple call, with the address first and the object second.

  EEPROM.put(eeAddress, f);

  Serial.println("Written float data type!");

  /** Put is designed for use with custom structures also. **/

  //Data to store.

  MyObject customVar = {

    3.14f,

    65,

    "Working!"

  };

  eeAddress += sizeof(float); //Move address to the next byte after float 'f'.

  EEPROM.put(eeAddress, customVar);

  Serial.print("Written custom data type! \n\nView the example sketch eeprom_get to see how you can retrieve the values!");
}

void loop() {

};

Please post your code

The code is on the example page. Its the PUT & GET example like i mentioned.

What did you understand when you read this?

" Hardware Required

All of the following boards have an EEPROM:"

ESP32 does have an EEPROM, it uses the Flash as EEPROM. Or am i wrong about this?

Flash is not EEPROM.
EEPROM is not flash.

Ill wait until someone less angry answers :slight_smile: I dont have time for this.

:slight_smile:

Me neither

Thats an Arduino reference for EEPROM and the ESP32 is not an Arduino.

For full details on how the 'EEPROM' emulation works on an ESP32 there ought to be an Espressif reference somewhere, they produce and support the ESP32 plugin for the Arduino IDE.

ESP32 does NOT have a EEPROM. EEPROM, depreciated on an ESP32, does not retain data between reloads because EEPROM on an ESP32 uses flash.

Use littleFS to store data on a ESP32 that can be preserved between flashing.

1 Like

Ok, thanks for confirming this! And i do know it does not have an EEPROM. Just thought that the emulation would have been better and used part of the flash that is not wiped when reflashed.

I would assume that this is a quite common issue, and that there would be solutions to this.

But now i know my code was not the problem and can at least proceed.

I will look into the littleFS, thanks for that.

1 Like

For simple non volatile storage of a struct like you want, you should also take a look at Preferences.h which is a part of the Arduino core for the esp32. It uses a simple key value pair method for nonvolatile storage. You will find many online examples of how to use Preferences.h. For the struct, the putBytes() function is what you will use, and if you look at the library documentation you will see all the other put/get functions available.

Here's a simple example of the use

#include <Preferences.h>
Preferences prefs;

int dataStore[3] = {12345, 45689, 78901};
int dataRetrieve[3];

void setup() {
  Serial.begin(115200);
  prefs.begin("IntegerArray"); //namespace
  //bytes can be put/get in namespace directly see prefs2struct example
  //prefs.putBytes("IntegerArray", (byte*)(&dataStore), sizeof(dataStore));
  //SavedIntegers is Key
  prefs.putBytes("SavedIntegers", (byte*)(&dataStore), sizeof(dataStore));
  prefs.getBytes("SavedIntegers", &dataRetrieve, sizeof(dataRetrieve));
  Serial.println(dataRetrieve[0]);
  Serial.println(dataRetrieve[1]);
  Serial.println(dataRetrieve[2]);
}

void loop() {}
1 Like

Whilst it may have gone down in value, it's deprecated.

I came across this preferences method while searching for solution, so it will retain its values even after reflashing a new version? That would be great. I just skipped it as i was thinking i had problems in code and did not want to try something new before i got the old code to work.

I need to have a database of structs, that from i can then load one into variables. I was a bit confused about this "namespace" thing. Is that like one set namespace for the whole storage? Or for single stored struct?

So "SavedIntegers" is the name for the stored struct, and it can then always find it by using this name?

Yes, i think i got this. This actually simplifies this a lot, damn.. my last version still had all manual seeking byte per byte and even this get & put system and storing whole structs made my things so much simpler.

Is that like one set namespace for the whole storage? Or for single stored struct?

The namespace is for a block of storage which can hold many structs.

So "SavedIntegers" is the name for the stored struct, and it can then always find it by using this name?

Yes.

I think you have it. If you can't get the storage and retrieval of several structs to work, post your code using Preferences.h and I will take a look.

1 Like

It works, thanks! It was way easier than i thought. And with this system, no need to worry about the sizes. I don't need to define fixed sizes.. much easier if i need to change the dataset sizes in the future.

I can really post the code as its way too big project. It was pretty much a single line fix, just replaced all the eeprom stuff with this preferences stuff.

It kinda suspected that there must be a easy way to do this. Its 2022 dang diddly doo dang. Cant be bothered to go through stuff byte by byte.

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