0

I bought an ESP32-WROOM-32 and I realize that there are some things which are not the same compared to Arduino Nano, Arduino Uno or Arduino Mega 2560.

One of the things that I realized which is different is how to store and read data from the controller. I want to save some data to EEPROM, to retain that value even when the device is switched off.

I have the following code that I use all the time in my small projects with Arduino boards. The code consists of creating an OLED menu where I can navigate true pages and change integer values and these values are stored in the EEPROM.

The same code I uploaded to the ESP32 without any problem and the menu works fine. I can change the integer values. The problem is that after switching OFF/ON the board, the values are not persisted.

I was already looking at some tutorials in the Internet about EEPROM and ESP32 and tried to implement it, but unfortunately without a result.

#include <EEPROM.h>
#include <OneButton.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define DISP_RESET -1

const char*Vartext[] {"Data_0", "Data_1", "Data_2"};

const byte maxAnz = sizeof(Vartext) / sizeof(Vartext[0]);

const int mindata[maxAnz] {0, 0, 0};
const int maxdata[maxAnz] {10000, 200, 300};

uint32_t longstart;
byte Varindex;
byte Page = 0;
bool input;
bool changed;
bool datachanged ;

// Data in struct to save in EEPROM
struct mydaten {
  int VarData[maxAnz];
} mydata;

const byte pinsel = 16;   // Select button
const byte pinplus = 4;   // Plus button
const byte pinminus = 5;  // Minus button

OneButton Btnsel(pinsel, true);
OneButton Btnplus(pinplus, true);
OneButton Btnminus(pinminus, true);
Adafruit_SSD1306 DISP(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, DISP_RESET);

void setup() {
  Serial.begin(115200);

  EEPROM.get(0, mydata); // Read Data from EEPROM
  for (byte i = 0; i < maxAnz; i++) {
    checkminmax();
  }
  changed = true;

  Btnsel.attachClick(selClick);
  Btnsel.attachDoubleClick(selDblClick);
  Btnplus.attachClick(plusClick);
  Btnplus.attachDuringLongPress(plusDurPress);
  Btnplus.attachLongPressStart(LongStart);
  Btnminus.attachClick(minusClick);
  Btnminus.attachDuringLongPress(minusDurPress);
  Btnminus.attachLongPressStart(LongStart);

  DISP.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  DISP.clearDisplay();
  DISP.setTextWrap(false);
  DISP.setTextSize(2);
  DISP.setTextColor(WHITE);
  DISP.setCursor(20, 30); DISP.print(F("Menu"));
  DISP.setTextSize(2);
  DISP.display();
  delay(2000);
}


//--------------------------------------
void loop() {
  Btnsel.tick();
  Btnplus.tick();
  Btnminus.tick();
  if (input)
    Displayinput();
  else
    Display(Page);
}

//--------------------------------------
void saveEEprom() {
  if (datachanged) {
    datachanged = false;

#ifdef debug
    Serial.println("Save in EEprom");
#endif

    EEPROM.put(0, mydata);
  }
}

//--------------------------------------
void selClick() {
  changed = true;
  if (input) {
    Varindex++;
    if (Varindex >= maxAnz)
      Varindex = 0;
  }
  else {
    Page++;
    if (Page >= 3)
      Page = 0;
  }
}

//--------------------------------------
void selDblClick() {
  if (input)
    saveEEprom();
  input = !input;
  changed = true;
}

void plusClick() {
  click(1);
}

void minusClick() {
  click(-1);
}

void plusDurPress() {
  longclick(1);
}

void minusDurPress() {
  longclick(-1);
}

void LongStart() {
  longstart = millis();
}

void click(int inc) {
  if (input) {
    changed = true;
    datachanged = true;
    mydata.VarData[Varindex] += inc;
    checkminmax();
  }
}

void longclick(int direction) {
  static uint32_t oldtime;
  int inc = 10;
  if (millis() - longstart > 5000)
    inc = 100;
  if (millis() - oldtime >= 100 && input) {
    oldtime = millis();
    changed = true;
    datachanged = true;
    mydata.VarData[Varindex] += inc * direction;
    checkminmax();
  }
}

void checkminmax() {
  if (mydata.VarData[Varindex] < mindata[Varindex]) {
    mydata.VarData[Varindex] = mindata[Varindex];
  }
  if (mydata.VarData[Varindex] > maxdata[Varindex]) {
    mydata.VarData[Varindex] = maxdata[Varindex];
  }
}

void Displayinput() { // Display bei input
  if (changed) {
    changed = false;
    DISP.clearDisplay();
    DISP.setTextSize(2);
    DISP.setCursor(0, 0); DISP.print("input");
    DISP.setCursor(0, 20); DISP.print(Vartext[Varindex]);
    DISP.setCursor(10, 40); DISP.print(mydata.VarData[Varindex]);
    DISP.display();
  }
}

void Display(byte Page) {
  if (changed) {
    changed = false;
    DISP.clearDisplay();
    if (Page == 0) {
      DISP.setTextSize(1);
      DISP.setCursor(0, 0);
      DISP.print("variable Value");
      for (byte i = 0; i < maxAnz; i++) {
        byte row = i * 10 + 10;
        DISP.setCursor(0, row);
        DISP.print(Vartext[i]);
        DISP.setCursor(80, row);
        DISP.print(mydata.VarData[i]);
      }
    }
    else if (Page == 1) {
      DISP.setTextSize(2);
      DISP.setCursor(0, 0); DISP.print("Page 1");
    }
    else if (Page == 2) {
      DISP.setTextSize(2);
      DISP.setCursor(0, 0); DISP.print("Page 2");
    }
    DISP.display();
  }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Carlos Costa
  • 123
  • 3
  • 11

2 Answers2

5

The first thing to know is that, unlike Arduino, the ESP32 doesn't have an EEPROM. Instead it emulates it using flash storage. The EEPROM library for the ESP32 is deprecated; new code should use the Preferences library. You can also persist data using the filesystem if you want.

To answer the question:

First, you should call EEPROM.begin() at the start of the program. So:

#define EEPROM_SIZE LARGEST_SIZE_YOU_MAY_EVER_USE

void setup() {
  Serial.begin(115200);

  EEPROM.begin(EEPROM_SIZE);

  EEPROM.get(0, mydata); // Read Data from EEPROM

Set EEPROM_SIZE to a value which will be the largest number of bytes you'll need.

Then after you're done writing you need to call EEPROM.commit(). So:

void saveEEprom() {
  if (datachanged) {
    datachanged = false;
#ifdef debug
    Serial.println("Save in EEprom");
#endif
    EEPROM.put(0, mydata);
  }
  EEPROM.commit();
}

This lets the EEPROM library minimize the number of writes to flash storage, which has rather limited durability. If you call it when nothing was put then nothing will happen. If you don't call it, the data you put will not be saved.

You can also find this out for yourself by checking out the EEPROM library's examples.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
romkey
  • 6,218
  • 3
  • 16
  • 12
  • 1
    OMG, Thanks for your help and reply . I was missing one line of code . "EEPROM.commit();" It persist the values with your help. Could you show me using my code how i would need to use Preferences library or persist data using the filesystem. – Carlos Costa Oct 10 '21 at 17:25
  • 1
    A lot of people miss it, not just you! I would check out the examples in the [Preferences library](https://github.com/espressif/arduino-esp32/tree/master/libraries/Preferences) that I linked to - they'll show you everything you need if you want to try it out. – romkey Oct 10 '21 at 20:05
  • Opinion: Because 1) Preferences lib is 548 bytes bigger, 2) takes more runtime variables to manage and 3) arguably doesn't support procedural generated calls as cleanly as the Eeprom library: in ~0.1% of cases the Eeprom library is still handy to have. – Shaedo Mar 17 '23 at 12:54
  • **WARNING:** `EEPROM.commit()` takes 30ms during which interrupts aren't handled - so any interrupts happening during that time more than once will be lost. A huge problem if you do pulse counting. – Maxim Kachurovskiy May 07 '23 at 11:31
1

There is a file system that is very easy to use, called SPIFFS.

If you are using the Arduino IDE you will find an example program named SPIFFS_test. It is pretty straightforward, showing how to open files, list directories and such.

Menu FileExamplesExamples for ESP32SPIFFSSPIFFS_test

The functions and how they are used are very similar, maybe even identical, to the standard C file system functions.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Christian
  • 187
  • 5
  • As of Arduino IDE 2.0 SPIFFS no longer works with ESP32 (Mar 2023 - this may change with future IDE updates) – Shaedo Mar 17 '23 at 12:44