arduino-esp8266eeprom

I Can't load the EEPROM stored data from an ESP-01S when its restarted from WIFI configuration, the device freezes and then restarts


how are you?.

I'm making a project where one part of it its the classic AP mode where the network details are stored to make the connection once the device is restarted.

In my case the data is apparently stored correctly in the EEPROM but after the reset, once the EEPROM is initializated the device keeps trying to execute the function EEPROM.get() and keeps restarting at that code line.

Please don't pay attention to initWifi() since that function works as expected.

wifi_usuario.accesoAP is a flag to know if the EEPROM has been written.

Follows the code

struct wifiConfig {
  String ssid;
  String clave;
  String ipDir;
  String gatewaydir;
  bool accesoAP;
} wifi_usuario = {"","","","",false}, wifi_usuario_leida = {"","","","",false};

void setup()
{
    EEPROM.begin(sizeof(struct wifiConfig));
    EEPROM.get(0, wifi_usuario_leida);
    if(!wifi_usuario.accesoAP)
    {
        Serial.println("Almacenado por primera vez datos en la EEPROM");
        EEPROM.put(0, wifi_usuario);
        EEPROM.commit();
    }
    else if(wifi_usuario_leida.accesoAP)

    {
        Serial.println("Se leerán los datos del wifi almacenados desde el modo AP");
        EEPROM.get(0, wifi_usuario_leida);
        Serial.println("Los datos de la red a conectarse han sido previamente grabados");
        Serial.println("Asignando parámetros de red inalámbrica");
        ssid = wifi_usuario_leida.ssid;
        Serial.print("Asignado el ssid: ");
        Serial.println(ssid);
        pass = wifi_usuario_leida.clave;
        Serial.print("Asignado el pass: ");
        Serial.println(pass);
        ip = wifi_usuario_leida.ipDir;
        Serial.print("Asignada la IP: ");
        Serial.println(ip);
        gateway = wifi_usuario_leida.gatewaydir;
        Serial.print("Asignado el gateway: ");
        Serial.println(gateway);
        Serial.println("Parámetros de red inalámbrica asignados");
    }
    if(initWifi())
    {
        //Do some stuff to configure the ESP as STA mode.
    }
    else
    {
        //Do some stuff to configure the ESP as AP mode to store wifi credentials.
        //In this part of the code the data is stored in the EEPROM like follows
         WiFi.softAP("PORTÓN-WIFI-MANAGER", NULL);
         IPAddress IP = WiFi.softAPIP();
         Serial.print("AP IP address: ");
         Serial.println(IP);
         Serial.println("Almacenando parámetros de red en la estructura.");
         wifi_usuario.ssid = ssid;
         wifi_usuario.clave = pass;
         wifi_usuario.ipDir = ip;
         wifi_usuario.gatewaydir = gateway;
         wifi_usuario.accesoAP = true;
         Serial.println("Almacenados los datos en la estructura, almacenando estructura en la EEPROM");
         EEPROM.put(0, wifi_usuario);
         if(EEPROM.commit())
    {
    Serial.println("Datos almacenados en la EEPROM");
    EEPROM.get(0, wifi_usuario_leida);
    Serial.println(wifi_usuario_leida.ssid);
    Serial.println(wifi_usuario_leida.clave);
    Serial.println(wifi_usuario_leida.ipDir);
    Serial.println(wifi_usuario_leida.gatewaydir);
    Serial.println(wifi_usuario_leida.accesoAP);
  }
  request->send(200, "text/plain", "Red configurada. El módulo se reiniciará, por favor conéctese a su enrutador y vaya a la dirección IP: " + ip);
  Serial.println("En 4 segundos se estará reiniciando el ESP.");
  delay(4000);
  ESP.restart();
    }
}

Is just the second line after the setup() line, I mean, the line EEPROM.put(0, wifi_usuario); the one that makes the device resets itself when I dont' want it, bassicaly it keeps trying to read the EEPROM on that line (I think) and after some time the watchdog resets de module. I was thinking that once the EEPROM was written once only needed to be read to retrieve the data but is not working and I don't know why.

Please help me on how to read the stored data to connect to the wifi network.

NOTE: there are a lot more code not shown because is not important to solve this problem.

UPDATE: Note that I think the problem is that when I declare the members of the structure some of them are declared as strings but empty in the definitions. So when the device is restarted then the get function doesn't know the new size of the structure and because of that it doesn't read the complete structure or doesn't read it at all and it restarts after that, but anyway, I don't know how to solve it.

Thanks in advance for the help.


Solution

  • A String within a struct does not store the string literal that you think it was. A String object is a 12-byte fixed length that describe the String object and whereabout the actual String object located in the Heap memory. When you serialised it and trying to store it in EEPROM, it does not store the actual String literals that you want to store. Here is a sketch that shows what's going on within the struct.

    struct wifiConfig {
      String ssid = "";
      String clave = "";
      String ipDir = "";
      String gatewaydir = "";
      bool accesoAP = false;
    } wifi_s;
    
    void setup() {
      Serial.begin(115200);
      delay(1000);
      Serial.println();
    
      //since we are using esp8266, we can use Serial.printf()
      Serial.printf("Size of struct %zu\n", sizeof(wifi_s));
    
      // Print out the struct to see its content
      uint8_t * ptr = (uint8_t *) &wifi_s;
      for (int i=0; i<sizeof(wifi_s); i++) {
        Serial.printf("%02x ", *ptr++);
      }
      Serial.println();
    
      wifi_s.ssid = "String String String String";
      wifi_s.clave = "Hello  Hello  Hello  Hello";
      wifi_s.ipDir = "abcdefghijklmnopqrstuvwxyz";
    
      // Print out the struct again to see its content
      ptr = (uint8_t *) &wifi_s;
      for (int i=0; i<sizeof(wifi_s); i++) {
        Serial.printf("%02x ", *ptr++);
      }
      Serial.println();
    
      Serial.printf("%s %zu\n", ssid.c_str(), sizeof(ssid));
      
    }
    
    void loop() {
    
    }
    

    and here is the print out results:

    Size of struct 52
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
    5c f4 fe 3f 1f 00 1b 00 00 00 00 80 84 f4 fe 3f 1f 00 1a 00 00 00 00 80 ac f4 fe 3f 1f 00 1a 00 00 00 00 80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
    

    Another thing is that String is dynamically created in the Heap memory and the 12-bytes data within the struct that describes whereabout of the actual String literal located in the Heap, but when you restart the MCU, the Heap memory get clean-up and no longer exist, so what you read back from the EEPROM does not point to any valid String.

    If you really need to store a struct in EEPROM, I would suggest to define each string as a char array with fixed length:

    struct wifiConfig {
      char ssid[15] = "";
      char clave[15] = "";
      char ipDir[15] = "",
      char gatewaydir[15] = ""; 
      bool accesoAP = false;
    } wifi_s;