Go Down

Topic: ESP8266 & ESP32: Confusion about WiFi.persistent() (Read 683 times) previous topic - next topic

Amiga

Having read a lot (really!) about possible flash corruption of ESP8266 caused by writing the hard coded WiFi credentials to flash with every call of WiFi.begin(), I still couldn't figure out the current state of this issue (ESP Core 2.6.2).
There are many Github topics about that and I read the official documentation, but nevertheless I'm missing some clear and definite answers. I hope there's someone in here, who has profound knowlege about this.

I often read the general advice to use WiFi.persistent(false) to prevent the flash storage from being destroyed by too many writing processes. I'm wondering if this is still the case. So my questions are:

1.) If I set WiFi.persistent(true) [the standard setting?] - are the hard coded WiFi credentials always written to flash or does this only happen if the hard coded credentials are different to the ones that are in already in flash?


2.) If it is still necessary to set WiFi.persistent(false) - do I have to set this parameter only once in setup or before every call of WiFi.begin()?

---

3.) How does the widely used library WifiManager (by tzapu, available via Arduino Library Manager) handle this problem?

----

4.) Is WiFi.persistent() already implemented in the current ESP32 core? I can set this parameter without any error or warning messages during compiling, but I doubt the use of WiFi.persistent() has any effects.

Thanks in advance and best regards!




Juraj

persistent is default and the settings are written only if they change. but if you have persistent settings, don't call WiFi.begin, because it starts connecting again and you loose the advantage of persistent settings

WiFiManager doesn't need to handle anything. if the SDK already connected to AP with persistent settings, WiFiManager doesn't do anything

Amiga

Thanks for your answer!

So if I use persistent settings and ssid & password are already in flash, I don't theoretically need any connect function in setup because the SDK connects before the sketch is started? That would mean, in this case there's no need to define any WiFi parameters in setup?

If I nevertheless call WiFi.begin(ssid, password) during setup or loop, ssid and password are only written to flash if they are different to the ones which are already saved in flash?


Juraj

Thanks for your answer!

So if I use persistent settings and ssid & password are already in flash, I don't theoretically need any connect function in setup because the SDK connects before the sketch is started? That would mean, in this case there's no need to define any WiFi parameters in setup?

If I nevertheless call WiFi.begin(ssid, password) during setup or loop, ssid and password are only written to flash if they are different to the ones which are already saved in flash?


yes and yes

I only use WiFi.waitForConnectResult() and the ssid and password are set with a different sketch


but persistent are only the ssid and password of station interface. it doesn't apply for STA static IP configuration with WiFi.config

Amiga

Thank you, that really helped me a lot!
That was the clear and simple explanation I was looking for!

Do you know if the implementation is exactly the same on ESP32?

Best regards!




Idahowalker

#7
Dec 09, 2019, 07:36 pm Last Edit: Dec 09, 2019, 07:42 pm by Idahowalker
this is IDF framework, not Arduino
Which happens to work in the Arduino IDE.

As an example here is IDF Framework code https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/ulp_macros.html:
Code: [Select]
void ULP_BLINK_RUN(uint32_t us)
{
  size_t load_addr = 0;
  int rtcAddress2047 = 2047; // rtc address to store state R0
  RTC_SLOW_MEM[rtcAddress2047] = 0; // set initial state to address location
  ulp_set_wakeup_period(0, us);
  const ulp_insn_t  ulp_blink[] =
  {
    I_MOVI(R3, rtcAddress2047),             // #rtcAddress2047 -> R3
    I_LD(R0, R3, 0),                        // R0 = RTC_SLOW_MEM[R3(#rtcAddress2047)]
    M_BL(1, 1),                             // GOTO M_LABEL(1) IF R0 < 1
    I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 1),  // RTC_GPIO2 = 1
    I_SUBI(R0, R0, 1),                      // R0 = R0 - 1, R0 = 1, R0 = 0
    I_ST(R0, R3, 0),                        // RTC_SLOW_MEM[R3(#rtcAddress2047)] = R0
    M_BX(2),                                // GOTO M_LABEL(2)
    M_LABEL(1),                             // M_LABEL(1)
    I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 0),// RTC_GPIO2 = 0
    I_ADDI(R0, R0, 1),                    // R0 = R0 + 1, R0 = 0, R0 = 1
    I_ST(R0, R3, 0),                      // RTC_SLOW_MEM[R3(#rtcAddress2047)] = R0
    M_LABEL(2),                             // M_LABEL(2)
    I_HALT()                                // HALT COPROCESSOR
  };
  const gpio_num_t led_gpios[] =
  {
    GPIO_NUM_2,
    // GPIO_NUM_0,
    // GPIO_NUM_4
  };
  for (size_t i = 0; i < sizeof(led_gpios) / sizeof(led_gpios[0]); ++i) {
    rtc_gpio_init(led_gpios[i]);
    rtc_gpio_set_direction(led_gpios[i], RTC_GPIO_MODE_OUTPUT_ONLY);
    rtc_gpio_set_level(led_gpios[i], 0);
  }
  size_t size = sizeof(ulp_blink) / sizeof(ulp_insn_t);
  ulp_process_macros_and_load( load_addr, ulp_blink, &size);
  ulp_run( load_addr );
} // void ULP_BLINK_RUN(uint32_t us)

and https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/spi_master.html
Code: [Select]
int fInitializeSPI_Devices( spi_device_handle_t &h, int csPin)
{
  esp_err_t intError;
  spi_device_interface_config_t dev_config = { };  // initializes all field to 0
  dev_config.address_bits     = 0;
  dev_config.command_bits     = 0;
  dev_config.dummy_bits       = 0;
  dev_config.mode             = 3 ;
  dev_config.duty_cycle_pos   = 0;
  dev_config.cs_ena_posttrans = 0;
  dev_config.cs_ena_pretrans  = 0;
  dev_config.clock_speed_hz   = 7000000;
  dev_config.spics_io_num     = csPin;
  dev_config.flags            = 0;
  dev_config.queue_size       = 1;
  dev_config.pre_cb           = NULL;
  dev_config.post_cb          = NULL;
  spi_bus_add_device(HSPI_HOST, &dev_config, &h);
  // return intError;
  // return h;
} // void fInitializeSPI_Devices()

that works in the Arduino IDE.

Juraj

Which happens to work in the Arduino IDE.

As an example here is IDF Framework code:
Code: [Select]
void ULP_BLINK_RUN(uint32_t us)
{
  size_t load_addr = 0;
  int rtcAddress2047 = 2047; // rtc address to store state R0
  RTC_SLOW_MEM[rtcAddress2047] = 0; // set initial state to address location
  ulp_set_wakeup_period(0, us);
  const ulp_insn_t  ulp_blink[] =
  {
    I_MOVI(R3, rtcAddress2047),             // #rtcAddress2047 -> R3
    I_LD(R0, R3, 0),                        // R0 = RTC_SLOW_MEM[R3(#rtcAddress2047)]
    M_BL(1, 1),                             // GOTO M_LABEL(1) IF R0 < 1
    I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 1),  // RTC_GPIO2 = 1
    I_SUBI(R0, R0, 1),                      // R0 = R0 - 1, R0 = 1, R0 = 0
    I_ST(R0, R3, 0),                        // RTC_SLOW_MEM[R3(#rtcAddress2047)] = R0
    M_BX(2),                                // GOTO M_LABEL(2)
    M_LABEL(1),                             // M_LABEL(1)
    I_WR_REG(RTC_GPIO_OUT_REG, 26, 27, 0),// RTC_GPIO2 = 0
    I_ADDI(R0, R0, 1),                    // R0 = R0 + 1, R0 = 0, R0 = 1
    I_ST(R0, R3, 0),                      // RTC_SLOW_MEM[R3(#rtcAddress2047)] = R0
    M_LABEL(2),                             // M_LABEL(2)
    I_HALT()                                // HALT COPROCESSOR
  };
  const gpio_num_t led_gpios[] =
  {
    GPIO_NUM_2,
    // GPIO_NUM_0,
    // GPIO_NUM_4
  };
  for (size_t i = 0; i < sizeof(led_gpios) / sizeof(led_gpios[0]); ++i) {
    rtc_gpio_init(led_gpios[i]);
    rtc_gpio_set_direction(led_gpios[i], RTC_GPIO_MODE_OUTPUT_ONLY);
    rtc_gpio_set_level(led_gpios[i], 0);
  }
  size_t size = sizeof(ulp_blink) / sizeof(ulp_insn_t);
  ulp_process_macros_and_load( load_addr, ulp_blink, &size);
  ulp_run( load_addr );
} // void ULP_BLINK_RUN(uint32_t us)

and
Code: [Select]
int fInitializeSPI_Devices( spi_device_handle_t &h, int csPin)
{
  esp_err_t intError;
  spi_device_interface_config_t dev_config = { };  // initializes all field to 0
  dev_config.address_bits     = 0;
  dev_config.command_bits     = 0;
  dev_config.dummy_bits       = 0;
  dev_config.mode             = 3 ;
  dev_config.duty_cycle_pos   = 0;
  dev_config.cs_ena_posttrans = 0;
  dev_config.cs_ena_pretrans  = 0;
  dev_config.clock_speed_hz   = 7000000;
  dev_config.spics_io_num     = csPin;
  dev_config.flags            = 0;
  dev_config.queue_size       = 1;
  dev_config.pre_cb           = NULL;
  dev_config.post_cb          = NULL;
  spi_bus_add_device(HSPI_HOST, &dev_config, &h);
  // return intError;
  // return h;
} // void fInitializeSPI_Devices()

that works in the Arduino IDE.
yes, you can code in assembly with Arduino IDE too.

but how is IDF related to the original post?

Idahowalker

yes, you can code in assembly with Arduino IDE too.

but how is IDF related to the original post?
That is not assembler, it is the ESP32 API.

Consider when one uses delay() on the ESP32, one is, after drilling down, calling vTaskDelay(). On an ESP32 calling delay is calling a wrapper around vTaskDelay. If you take a look at https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/freertos.html, you will see that vTaskDelay is part of the OS of the ESP32, freeRTOS, which is part of the ESP32's API. The relation is the ESP32 core for the Arduino IDE wraps the ESP32 API.

Amiga

Thanks for your hints; but this goes a little bit beyond my current knowledge...

What I found out after some tests with an ESP32:
The ESP32 doesn't seem to have this autoconnect feature on startup; though having saved WiFi credentials in flash memory, it only connects after an explicit call of WiFi.begin() in setup. In opposite to the ESP8266, it also doesn't reconnect if it has lost its WiFi connection during runtime. You have to implement a function in loop, which monitors WiFi.status and initializes a reconnect, if connection has been lost.

Beside that, I'm facing a strange and obviously rare issue, which seems to occur in combination with certain routers/APs.

Juraj

Thanks for your hints; but this goes a little bit beyond my current knowledge...

What I found out after some tests with an ESP32:
The ESP32 doesn't seem to have this autoconnect feature on startup; though having saved WiFi credentials in flash memory, it only connects after an explicit call of WiFi.begin() in setup. In opposite to the ESP8266, it also doesn't reconnect if it has lost its WiFi connection during runtime. You have to implement a function in loop, which monitors WiFi.status and initializes a reconnect, if connection has been lost.

Beside that, I'm facing a strange and obviously rare issue, which seems to occur in combination with certain routers/APs.

it remembers the autoconnect setting too (of course)

Juraj

That is not assembler, it is the ESP32 API.

Consider when one uses delay() on the ESP32, one is, after drilling down, calling vTaskDelay(). On an ESP32 calling delay is calling a wrapper around vTaskDelay. If you take a look at https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/freertos.html, you will see that vTaskDelay is part of the OS of the ESP32, freeRTOS, which is part of the ESP32's API. The relation is the ESP32 core for the Arduino IDE wraps the ESP32 API.
yes I know. arduino-esp32 project wraps SDK C functions in C++ Arduino like API. so if someone decides to use the Arduino API then they want to know how  to achieve what they need with the Arduino API, if it is possible

if you are so into the SDK, use only IDF framework without Arduino

Amiga

it remembers the autoconnect setting too (of course)
Yes, it should do so, but in my case it doesn't.

Using the following code on ESP8266 everything works fine and connection is established automatically on start up.
The retry part in the while loop is never called because the connection is immediately established after start up.

Code: [Select]
void wificonnect(){
   
 
   while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.print("Not yet connected...retrying");
    WiFi.begin();
    }
}


On ESP32 the connection isn't established on startup. It workls only after the call of wifi.begin(). That means reading credentials from flash must work, because I didn't define ssid and password in my code. Nevetheless the connection isn't made on start up.
It's the same with reconnecting when connection is lost during runtime. The ESP32 doesn't reconnect automatically, only if I call WiFi.begin() again.



Beside that, in combination with a certain AP I face the connection issue mentioned above.

So I changed my code, added a retry counter to fix this AP issue:

Code: [Select]
void wificonnect(){
   uint8_t  wifi_retry=0;   // COUNTER SOLVES ESP32-BUG WITH CERTAIN ROUTERS: CONNECTION ONLY ESTABLISHED EVERY SECOND TIME
 
   while (WiFi.waitForConnectResult() != WL_CONNECTED && wifi_retry < 3) {
 
    Serial.print("Not yet connected...retrying");
    WiFi.begin();
    delay(3000);
    wifi_retry++;
    }

    if(wifi_retry >= 3) {
       
        Serial.println("no connection, restarting");
        ESP.restart;
       
        }
 
    if (WiFi.waitForConnectResult() == WL_CONNECTED){
     
      Serial.print("connected as: ");
      Serial.println(WiFi.localIP());
     
      }
  }


This works for me, but it isn't satisfiying because I found no explanation why the autoconnect on start up doesn't work. Neither I found a reason for the mentioned "second time" issue.

I wonder if this could be a hardware problem?
There's a little LED Matrix Display attached to my ESP32 for which I use the following pins:
Code: [Select]
//I'm using a DOIT ESP32 DEVKIT V1

  #define CLK_PIN     18                         
  #define DATA_PIN    23                         
  #define CS_PIN      5


Beyond that, I didn't define any pins.


Juraj

I tested ESP32 AT firmware last week and it did autoconnect and had no problems to connect. But it uses a different SDK version then the arduino-esp32 project.

Go Up