ESP32 Preserving EEPROM for as long as possible

Thread Starter

zazas321

Joined Nov 29, 2015
856
Hello. I have developed ESP32 program where I must save some values to internal EEPROM so the devices can read it back during a restart. I must save 2 values to EEPROM :
1. Serial number
2. Quantity.

I am writing to the EEPROM as following:
int address = 0
EEPROM.writeUShort(address, quantity);
address += sizeof(unsigned short);
EEPROM.writeString(address, "string);
EEPROM.commit();

I always start from address 0 an write 2 values, next time I want to update data, I am reinitialzing address and replacing the values in EEPROM.
I read something about wear leveling and would like to implement something simmilar.

I want to preserve it for as long as possible as I do not want to have any problems in the future regarding wore down EEPROM. Have anyone implemented something simmilar or have any ideas?

Also, I would like to know what happens when the EEPROM is fully worn? Will the device stop working? or I just wont be able to save data there anymore
 

Thread Starter

zazas321

Joined Nov 29, 2015
856
Hi. The problem is that my EEPROM write operation frequency will vary depending on many factors.. Even though I may be able to get away without breaking my EEPROM for a year or more, that is still not acceptable for this volume of ESP32 devices, we have over 100 of them running at the same place.

I have found some library that is written based on original EEPROM library for ESP32. It performs some EEPROM rotation which supposed to save life time for EEPROM. I have been reading a bit about that and tried to run his example code, but cannot fully understand what is supposed to happen. See full code here:

Code:
/*
 *  This sketch shows sector hoping across reboots
 */

#include <EEPROM32_Rotate.h>

EEPROM32_Rotate EEPROMr;

void setup() {

    // Init DEBUG --------------------------------------------------------------

    Serial.begin(115200);
    delay(2000);
    Serial.println();
    Serial.println();

    // Init EEPROM32_Rotate ----------------------------------------------------

    // You can add partitions manually by name
    EEPROMr.add_by_name("eeprom");
    EEPROMr.add_by_name("eeprom2");

    // Or add them by subtype (it will search and add all partitions with that subtype)
    //EEPROMr.add_by_subtype(0x99);

    // Offset where the magic bytes will be stored (last 16 bytes block)
    EEPROMr.offset(0xFF0);

    // Look for the most recent valid data and populate the memory buffer
    EEPROMr.begin(4096);

    // -------------------------------------------------------------------------

    uint8_t data;
    uint8_t quantity;
    quantity = 10;
    Serial.printf("Position 0: 0x%02X\n", EEPROMr.read(0));
    Serial.printf("Position 1: 0x%02X\n", EEPROMr.read(1));
    Serial.printf("Position 2: 0x%02X\n", EEPROMr.read(2));
    Serial.printf("Data      : 0x%02X\n", data = EEPROMr.read(0));

    Serial.println();
    Serial.printf("Writing 0x%02X to data\n", quantity);
    //EEPROMr.write(0, data + 1);
    EEPROMr.writeUShort(0, 10);

    Serial.println();
    Serial.printf("Commit %s\n", EEPROMr.commit() ? "OK" : "KO");
    Serial.printf("Position 0: 0x%02X\n", EEPROMr.read(0));
    Serial.printf("Position 1: 0x%02X\n", EEPROMr.read(1));
    Serial.printf("Position 2: 0x%02X\n", EEPROMr.read(2));
    Serial.printf("Data      : 0x%02X\n", data = EEPROMr.read(0));

}

void loop() {}
I have data quantity which I set to 10 and then i write to ti EEPROM 0 address. I am not certain how do I read it back later? After writing I perform EEPROMr.read() on the same address , but the value returned is not 10, is 0.
1611727352130.png
 

Thread Starter

zazas321

Joined Nov 29, 2015
856
hi zazas,
This video explains the technique for extending the life of the internal EEPROM,
What you think.?
E


I dont think he ever mentioned about extending the life of internal EEPROM. In his example program, he is continuely overwriting address 0 of EEPROM so I dont see any wear leveling implementation here. He is going to wear down address 0 of EEPROM very fast.

The whole idea of wear leveling is to avoid overwriting the same address over and over again

Is my understanding wrong?
 

ericgibbs

Joined Jan 29, 2010
12,908
hi,
It was a simple demo, showing how to count the number of write to a EEPROM location, after a given number of writes, the EEPROM write address is changed. ie: R/W levelling
Did you notice that.?
E
 

ericgibbs

Joined Jan 29, 2010
12,908
hi,
I would create a counter in the EEPROM, which increments on every reset event.
After a reset event, test the counter value, if greater than a prefixed value update the EEPROM start write address for your data block.
You will have store the start address for the data block in EEPROM.

That should extend the life of the EEPROM, how often do you expect a Reset to occur.??

E
 

ericgibbs

Joined Jan 29, 2010
12,908
hi,
OK, let us know how is goes.
I would suggest that you use the high address area for initial testing, keep the lower addresses clean.
E
 

Thread Starter

zazas321

Joined Nov 29, 2015
856
hi,
I would create a counter in the EEPROM, which increments on every reset event.
After a reset event, test the counter value, if greater than a prefixed value update the EEPROM start write address for your data block.
You will have store the start address for the data block in EEPROM.

That should extend the life of the EEPROM, how often do you expect a Reset to occur.??

E

Okay, my latest findings..

I have setup o global variable eeprom_counter and prev_eeprom_couter
Initially, eeprom_counter is initialized as 0 , but once the program starts, I have a function:


Code:
void initial_eeprom_values(){
  eeprom_counter = EEPROM.read(0);
  Serial.print("Initial eeprom values = ");
  Serial.println(eeprom_counter);
  if(eeprom_counter >= 12)
    prev_eeprom_counter = eeprom_counter -12;
    
  EEPROM.get(prev_eeprom_counter,item_inside.quantity);
  Serial.print("quantity inside initial=");
  Serial.println(item_inside.quantity);
  if(item_inside.quantity == 65535){
    item_inside.quantity=0;
  }
  
  prev_eeprom_counter += sizeof(unsigned short);
  EEPROM.get(prev_eeprom_counter,item_inside.serial);
  prev_eeprom_counter = prev_eeprom_counter +10;
  Serial.print("serial isnide initial=");
  Serial.println(item_inside.serial);
}

The function above is being executed when the ESP32 device starts, it reads from the EEPROM address 0 and sets the counter to whatever has been stored in there. If it is more than 12, that means I have previously written some data to EEPROM and want to access whatever was written before, so I decrement 12 and get the quantity and serial values. That seems to be working so far.

When the restart is initiated, I run the following code:
Code:
        Serial.print("EEPPROM counter = ");
        Serial.println(eeprom_counter);
        if(eeprom_counter >= 996)
        eeprom_counter = 0;
        

        
        EEPROM.writeUShort(eeprom_counter, item_inside.quantity);               // 2^16 - 1
        eeprom_counter += sizeof(unsigned short);
        Serial.print("address after quantity=");
        Serial.println(eeprom_counter);
        
        EEPROM.writeString(eeprom_counter, item_inside.serial);
        eeprom_counter = eeprom_counter + 10;
        Serial.print("address after string=");
        Serial.println(eeprom_counter);
        
        //UPDATE THE eeprom counter
        EEPROM.write(0,eeprom_counter);
        EEPROM.commit();
        
        ESP.restart();
The code above will update the values and write new eeprom counter value to address 0. After that, it is going to perform restart and the device again will call function initial_eeprom_values() where it finds the last updated values


Everything seems to make sense, however, as you can see, I always use address 0 to update the counter, so address 0 will wear down much faster than any other address.

I cant really think of a way to overcome this problem, if I use an address that varies everytime, after a restart, there is no way for me to know what was the last value. I hope you understand what I mean and have some ideas
 

ericgibbs

Joined Jan 29, 2010
12,908
Everything seems to make sense, however, as you can see, I always use address 0 to update the counter, so address 0 will wear down much faster than any other address.
hi z,
Thats looking good.:)
You dont use the same EEPROM address for the counter when moving the data block start address, you also move the counter location in the EEPROM block.

E
 

Thread Starter

zazas321

Joined Nov 29, 2015
856
Are you suggesting something like?
Instead of
EEPROM.write(0,eeprom_counter);
I can do:
EEPROM.write(eeprom_counter,eeprom_counter);// writing the eeprom_counter to the address that is equal to eeprom_counter

If thats the case, after the restart, how do I do with this function?:
eeprom_counter = EEPROM.read(0);

Since reading address 0 is no longer valid, and after reset I dont know what was the last eeprom_counter
 

ericgibbs

Joined Jan 29, 2010
12,908
hi,
You would not have that eeprom_counter = EEPROM.read(0); command in the initialise void initial_eeprom_values() directly, make it a conditional statement.
E
 

Thread Starter

zazas321

Joined Nov 29, 2015
856
Thanks for helping, but I am still not sure how can will I know what is the eeprom_counter in the initial_eeprom_values() function after the device restarts.


Code:
void initial_eeprom_values()
{
  eeprom_counter = EEPROM.read(0);
  Serial.print("Initial eeprom values = ");
  Serial.println(eeprom_counter);
  if(eeprom_counter >= 12)
    prev_eeprom_counter = eeprom_counter -12;
    
  EEPROM.get(prev_eeprom_counter,item_inside.quantity);
  Serial.print("quantity inside initial=");
  Serial.println(item_inside.quantity);
  if(item_inside.quantity == 65535){
    item_inside.quantity=0;
  }
Can you clarify how this function is going to know what is the eeprom_counter after the restart?
 

ericgibbs

Joined Jan 29, 2010
12,908
hi z,
I am having a problem getting my Arduino > ESP32 to run today, will not connect, still chasing the cause.
E

Update:
The MCU I have is a ESP8266 V3 Lolin. :(
So until I get a ESP32 I cannot run your sketches.
 
Last edited:

ErnieM

Joined Apr 24, 2011
8,152
Hello. I have developed ESP32 program where I must save some values to internal EEPROM so the devices can read it back during a restart. I must save 2 values to EEPROM :
If the restart does not mean the power goes off you can just stick them into regular RAM variable declared "RTC_NOINIT_ATTR"
 

Thread Starter

zazas321

Joined Nov 29, 2015
856
If the restart does not mean the power goes off you can just stick them into regular RAM variable declared "RTC_NOINIT_ATTR"
Unfortunately, Restart in my case means power off. When a restart is initiated, I power cycle the device to make sure it fresh again with all the variables initialized back to the initial state.

Perhaps I should think of a way to do a restart without actually powering off the devices, But I think at some point I will still need to do a power off restart. It is mostly used when something goes wrong and since I wont be there at all times operating and using these devices and the person who will does not know anything about them, it is easiest for the person to just restart all devices and start working again
 

Thread Starter

zazas321

Joined Nov 29, 2015
856
hi z,
I am having a problem getting my Arduino > ESP32 to run today, will not connect, still chasing the cause.
E

Update:
The MCU I have is a ESP8266 V3 Lolin. :(
So until I get a ESP32 I cannot run your sketches.
Okay! Let me know how it goes. I will still be thinking about this and update if I figure something out
 
Top