Is the ESP32-S2 EEPROM persistent when power cycling and reset?

I’m using the [SparkFun Thing Plus - ESP32-S2 WROOM and an IoT Wifi Manager library that needs to save WiFi configuration settings to the EEPROM. I have been able to successfully write to the EEPROM, but the values appear to be erased when I power cycle the board (unplug, and reattach USB cable) or when I hit the onboard reset button.

My basic question is should the EEPROM data remain when the board is power cycled? If so, should it remain when the reset button is pressed?

I built a simple project to test just the EEPROM to remove any of the WiFi manager complications and isolate the EEPROM. It writes data and I can read the data no problem. It all just disappears when I reset the board or cycle power. Is this expected?

Here is the code I used to test this.

This is the PlatformIO configuration I used for the project.

[env:arduino-esp32s2]
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
board = esp32-s2-saola-1
monitor_speed = 115200
framework = arduino
build_flags = 
  -DCORE_DEBUG_LEVEL=5
  -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG

Then I used one of the EEPROM examples to build a simple app that uses one button to write to the EEPROM and another to read from it. Here is that code in case you want to try it.

/*
   EEPROM Write
   Stores random values into the EEPROM.
   These values will stay in the EEPROM when the board is
   turned off and may be retrieved later by another sketch.
*/

#include "EEPROM.h"
#define LED_BUILTIN 13
#define WRITE_PIN 17
#define READ_PIN 0
int writeButtonState = 1; 
int readButtonState = 1; 

// Declaring fucntions for later use.
void generateTestData();
void readTestData();

// the current address in the EEPROM (i.e. which byte
// we're going to write to next)
int addr = 0;
#define EEPROM_SIZE 64
void setup()
{
  Serial.begin(115200);
  Serial.println("start...");

  pinMode(WRITE_PIN, INPUT_PULLUP); // Setting the test button to normally hot.
  pinMode(READ_PIN, INPUT_PULLUP); // Setting the test button to normally hot.
  pinMode(LED_BUILTIN, OUTPUT);
  
  if (!EEPROM.begin(EEPROM_SIZE))
  {
    Serial.println("failed to initialise EEPROM"); delay(1000000);
  }
  Serial.println(" bytes read from Flash . Values are:");
  for (int i = 0; i < EEPROM_SIZE; i++)
  {
    Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
  }
  Serial.println();
  Serial.println("Press test button to write to EEPROM.");
}

void loop()
{
  readButtonState = digitalRead(READ_PIN);
  writeButtonState = digitalRead(WRITE_PIN);

  // When write button is pressed.
  if (writeButtonState == LOW) {
    digitalWrite(LED_BUILTIN, HIGH);
    generateTestData();
    delay(500);
    writeButtonState = 1;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
  // When read button is pressed.
  if (readButtonState == LOW) {
    digitalWrite(LED_BUILTIN, HIGH);
    readTestData();
    delay(250);
    readButtonState = 1;
    digitalWrite(LED_BUILTIN, LOW);
    delay(250);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(250);
    digitalWrite(LED_BUILTIN, LOW);
  }
}

// Fuction to read the EEPROM at will.
void readTestData() {
  if (!EEPROM.begin(EEPROM_SIZE))
  {
    Serial.println("failed to initialise EEPROM"); delay(1000000);
  }
  Serial.println(" bytes read from Flash . Values are:");
  for (int i = 0; i < EEPROM_SIZE; i++)
  {
    Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
  }
}

// Function to generate data to push into the EEPROM
void generateTestData() {
  // need to divide by 4 because analog inputs range from
  // 0 to 1023 and each byte of the EEPROM can only hold a
  // value from 0 to 255.
  // int val = analogRead(10) / 4;
  int val = byte(random(10020));
  // write the value to the appropriate byte of the EEPROM.
  // these values will remain there when the board is
  // turned off.
  EEPROM.write(addr, val);
  Serial.print(val); Serial.print(" ");
  // advance to the next address.  there are 512 bytes in
  // the EEPROM, so go back to 0 when we hit 512.
  // save all changes to the flash.
  addr = addr + 1;
  if (addr == EEPROM_SIZE)
  {
    Serial.println();
    addr = 0;
    EEPROM.commit();
    Serial.print(EEPROM_SIZE);
    Serial.println(" bytes written on Flash . Values are:");
    for (int i = 0; i < EEPROM_SIZE; i++)
    {
      Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
    }
    Serial.println(); Serial.println("----------------------------------");
  }
}

](SparkFun Thing Plus - ESP32-S2 WROOM - WRL-17743 - SparkFun Electronics)

I updated the sample code to make it easier to test. The EEPROM.commit() now happens each time an update is made.

/*
   EEPROM Write
   Stores random values into the EEPROM.
   These values will stay in the EEPROM when the board is
   turned off and may be retrieved later by another sketch.
*/

#include "EEPROM.h"
#define LED_BUILTIN 13
#define WRITE_PIN 17
#define READ_PIN 0
int writeButtonState = 1; 
int readButtonState = 1; 

// Declaring fucntions for later use.
void generateTestData();
void readTestData();

// the current address in the EEPROM (i.e. which byte
// we're going to write to next)
int addr = 0;
#define EEPROM_SIZE 64
void setup()
{
  Serial.begin(115200);
  Serial.println("start...");

  pinMode(WRITE_PIN, INPUT_PULLUP); // Setting the test button to normally hot.
  pinMode(READ_PIN, INPUT_PULLUP); // Setting the test button to normally hot.
  pinMode(LED_BUILTIN, OUTPUT);
  
  if (!EEPROM.begin(EEPROM_SIZE))
  {
    Serial.println("failed to initialise EEPROM"); delay(1000000);
  }
  Serial.println(" bytes read from Flash . Values are:");
  for (int i = 0; i < EEPROM_SIZE; i++)
  {
    Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
  }
  Serial.println();
  Serial.println("Press test button to write to EEPROM.");
}

void loop()
{
  readButtonState = digitalRead(READ_PIN);
  writeButtonState = digitalRead(WRITE_PIN);

  // When write button is pressed.
  if (writeButtonState == LOW) {
    digitalWrite(LED_BUILTIN, HIGH);
    generateTestData();
    delay(500);
    writeButtonState = 1;
    digitalWrite(LED_BUILTIN, LOW);
  }
  
  // When read button is pressed.
  if (readButtonState == LOW) {
    digitalWrite(LED_BUILTIN, HIGH);
    readTestData();
    delay(250);
    readButtonState = 1;
    digitalWrite(LED_BUILTIN, LOW);
    delay(250);
    digitalWrite(LED_BUILTIN, HIGH);
    delay(250);
    digitalWrite(LED_BUILTIN, LOW);
  }
}

// Fuction to read the EEPROM at will.
void readTestData() {
  if (!EEPROM.begin(EEPROM_SIZE))
  {
    Serial.println("failed to initialise EEPROM"); delay(1000000);
  }
  Serial.println(" bytes read from Flash . Values are:");
  for (int i = 0; i < EEPROM_SIZE; i++)
  {
    Serial.print(byte(EEPROM.read(i))); Serial.print(" ");
  }
  Serial.println();
}

// Function to generate data to push into the EEPROM
void generateTestData() {
  // need to divide by 4 because analog inputs range from
  // 0 to 1023 and each byte of the EEPROM can only hold a
  // value from 0 to 255.
  // int val = analogRead(10) / 4;
  int val = byte(random(10020));
  // write the value to the appropriate byte of the EEPROM.
  // these values will remain there when the board is
  // turned off.
  EEPROM.write(addr, val);
  Serial.print("Updating flash with value:");
  Serial.print(val); Serial.print(" ");
  Serial.println();
  EEPROM.commit();
}

I haven’t experimented with the EEPROM library (which uses Flash instead of genuine EEPROM), but I find the tutorials from RandomNerds to be very helpful.

Cycling the power should never erase the Flash memory, so I suspect you are somehow misusing the library. Try this tutorial and see if you get the same result. https://randomnerdtutorials.com/esp32-flash-memory/

I think I found the root of the problem. I installed the Arduino 2.0 IDE and was able to successfully build and deploy the example code I provide in this thread.

This leads me to believe that there is a problem with my PlatformIO configuration in Visual Studio Code. Does anyone have an example or tutorial on how to setup the SparkFun Thing Plus - ESP32-S2 WROOM in Platform.IO using the Arduino framework instead of the ESPIoT framework?

After a bunch of reading and tinkering I made changes to my PlatformIO.ini file and got this working. Here is the updated INI file for reference.

[env:esp32-s2-saola-1]
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
framework = arduino
board = esp32-s2-saola-1
monitor_speed = 115200
board_build.flash_mode = dio

build_flags = 
  -DCORE_DEBUG_LEVEL=5
  -DLOG_LOCAL_LEVEL=ESP_LOG_DEBUG
  -DBOARD_HAS_PSRAM
  -mfix-esp32-psram-cache-issue

I managed to figure this out after reading this [issue post on GitHub about the Arduino library talking about using QIO to write to the flash. From there I went back to the [documentation from EspressIf and found a collection of configuration options for the flash on these boards. After some trial and error I found a combination that worked. This is only tested for preferences, I haven’t done deeper testing to validate SPIFFS, but my issue is solved. Hope this helps someone else.](Espressif 32 — PlatformIO latest documentation)](Is ESP32-S2 SPIFFS not supported with Arduino Framework? · Issue #546 · platformio/platform-espressif32 · GitHub)