Soft WDT reset Exception(4) su ESP8266-01

Ciao a tutti,

ho scritto un piccolo codice per creare un orologio digitale con un modulo ESP8266-01S e un display i2c TM1637 che si aggiorna ogni giorno ad una certa ora tramite WiFi e server NTP.

Funziona perfettamente, si connette al WiFi domestico, ottiene l'ora correttamente e poi chiude la connessione WiFi. Questo subito dopo il primo avvio.

Al successivo aggiornamento programmato, durante la fase di connessione all'AP, cioè durante l'esecuzione del ciclo while()

 while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

ottengo un Soft WDT reset Exception(4)

Dopo questo soft reset tutto funziona come al primo avvio, si connette al WiFi e acquisisce l'ora quindi in pratica non è di fatto un grosso problema ma mi piacerebbe capire se e dove sbaglio. Sono conscio del fatto che con un processore single core come l'8266 i loop bloccanti possono essere un problema, ma vorrei capire... come mai alla prima esecuzione il reset non avviene?

Ho provato ad abbassare il delay a 250, ho anche provato ad aggiungere uno yield() nel ciclo while ma non c'è verso, anzi con lo yield() ottengo un Soft WDT reset Panic __yield().

Questa è la funzione nella quale avviene il reset:

void UpdateTime() {
  ITimer.detach(); //ferma il timer
  disp.point(false); //spegne i due punti sul display
  disp.displayByte(_t, _U, _P, _d); //visualizza tUPd sul display
  delay(1000); 

  // Connect to Wi-Fi
  Serial.printf("\n\nUpdate time from NTP Server");
  Serial.printf("\nConnecting to WiFi");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.printf("\nWiFi succesfully connected to %s", ssid);
  Serial.print("\nLocal IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.println();

  //Init and get the time
  configTzTime(TZ_Europe_Rome, ntpServer1, ntpServer2);

  if (getLocalTime(&timeinfo)) {
    Serial.println("Date and time succesfully acquired from NTP Server");
    //disconnect WiFi as it's no longer needed
    Serial.println("Disconnect from WiFi\n");
    WiFi.disconnect(true);
    WiFi.mode(WIFI_OFF);
  } else {
    Serial.println("Failed to obtain time");
    return;
  }
  
  ITimer.attach(Tick_Second, TimerHandler); //riattiva il timer (500 ms)
}

Grazie anticipate per i suggerimenti

Questo è il log copiato dal serial monitor con parte dello Stack dump:

14:53:02.986 -> Update time from NTP Server
14:53:02.986 -> Connecting to WiFi....
14:53:04.342 -> --------------- CUT HERE FOR EXCEPTION DECODER ---------------
14:53:04.342 -> 
14:53:04.342 -> Soft WDT reset
14:53:04.342 -> 
14:53:04.342 -> Exception (4):
14:53:04.342 -> epc1=0x40106ac7 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
14:53:04.342 -> 
14:53:04.342 -> >>>stack>>>
14:53:04.342 -> 
14:53:04.342 -> ctx: sys
14:53:04.342 -> sp: 3fffecb0 end: 3fffffb0 offset: 0160
14:53:04.342 -> 3fffee10:  3ffeebb8 0001db4c 000000d9 40202f15  
14:53:04.342 -> 3fffee20:  0001db4c 000000fa 0001db2b 40202f8a  
14:53:04.342 -> 3fffee30:  00000000 0001db2b 03958106 022569bc  
14:53:04.342 -> 3fffee40:  4023bb4f fffffffc 00000001 3ffe8640  
14:53:04.342 -> 3fffee50:  3ffeeae8 0001db2b 000000fa 40203574  
14:53:04.342 -> 3fffee60:  3ffeeae8 3ffeeb1c 3ffeeb50 402011c8  
14:53:04.342 -> 3fffee70:  68121d2c 00000000 3e9f7e25 3fffd9d0  
14:53:04.342 -> 3fffee80:  00000000 00000000 00000000 00000003  
14:53:04.342 -> 3fffee90:  3ffeeab8 00000000 0000000e 40201311  
14:53:04.342 -> 3fffeea0:  40201f2c 3ffeeadc 00000000 40201f11  
14:53:04.342 -> 3fffeeb0:  3ffeeaf4 00000001 00000000 401002bc  
14:53:04.342 -> 3fffeec0:  3fffeee0 00000001 00000002 401002bc  
14:53:04.342 -> 3fffeed0:  00000035 00000003 0000007d 0000001e  
14:53:04.342 -> 3fffeee0:  00000001 3ffee600 3ffeeae8 40201d8d  
14:53:04.342 -> 3fffeef0:  3fffef10 3ffeeaf4 402340f7 60000600  
14:53:04.342 -> 3fffef00:  3ffeeaf4 3ffee600 3ffeeae8 40201dd4  
14:53:04.342 -> 3fffef10:  402013c0 feefeffe 402058c4 402058bc  
14:53:04.342 -> 3fffef20:  00000002 3ffeeb08 3ffee600 07217f8d  
14:53:04.342 -> 3fffef30:  07217f8d 3ffee600 3ffeeb08 402390b1  
14:53:04.342 -> 3fffef40:  402390f6 3fffdab0 00000000 3fffdcb0  
14:53:04.342 -> 3fffef50:  3ffee618 3fffdad0 3ffeebe0 40202d5a  

Purtroppo gli ESP8266 soffrono di questo problema, dato che il "core" è uno solo e deve far tutto (WiFi, Bluetooth, tuo programma ...) se il tuo codice fa qualche cosa che dura troppo e l'ESP8266 non riesce a far girare gli altri processi, scatta il WDT ... :confused:

Questa cosa NON avviene con gli ESP32 che, oggi come oggi, costando praticamente quanto costavano gli ESP8266, andrebbero utilizzati ... molto più veloci, efficienti, multi "core" e quindi esenti dal suddetto problema.

Comunque, individua dove perdi troppo tempo (normalmente in cicli while che durano troppo) e prova ad inserire in tali cicli che durano troppo, una riga:

yield();

... che permette ai task di sistema di svolgere il proprio lavoro.

Guglielmo

Grazie Guglielmo, come ho già scritto l'istruzione yield() l'ho già provata peggiora le cose.
Come si nota dal log che ho postato, alla seconda riga dopo "Connecting to WiFi" ci sono 4 puntini prima dell'eccezione, dato che il delay() è di 0.5 secondi, in pratica l'eccezione avviene nel ciclo while() dopo 2 secondi. Ma ripeto, questo avviene solo al secondo tentativo di connessione. Infatti sia alla prima esecuzione dopo il flash del codice tramite l'IDE e conseguente reset hardware, sia dopo il reset software causato dall'eccezione WDT reset, tutto funziona regolarmente.

Mi sto studiando la libreria ESP8266WiFi.h, appena posso provo a vedere se lasciando attiva la connessione WiFi anzichè chiuderla dopo l'aggiornamento dal server, risolvo.
Inoltre ho visto che la libreria WiFiState.h contiene le funzioni WiFi.shutdown() e WiFi.resumeFromShutdown().
Spesso a causa della scarsa documentazione bisogna basarsi sugli esempi quindi... provare... provare... provare...

Grazie

... strano, è nata proprio per dare tempo al sistema di fare le sue cose :thinking:

Altro non saprei, ho abbandonato da molto tempo gli ESP8266 a favore degli ESP32 :wink:

Guglielmo

Sono daccordo, ma ho già un paio di questi piccolissimi moduli, che sono perfetti da montare dietro il display proprio per via delle dimensioni ridotte, dato che in fondo mi servono solo 2 pin digitali per l'i2c del display, gli ESP32 sono decisamente più ingombranti.

Le soluzioni sono due se non riesco a evitare il reset: o ignoro il problema tanto funziona tutto, oppure uso un Arduino Nano ESP32 che già possiedo.
Proverò a cercare altri moduli ESP32 simili al nano per dimensioni.

Assolutamente NO, ci sono moduli che hanno le stesse piccole dimensioni ...

... cerca WeMos D1 mini ESP32 e, prima di ordinarli, verifica sempre che siano veramente ESP32 (scrivono ESP32 e nella descrizione ti ritrovi ESP8266 :enraged_face:).

Guglielmo

Questo è anche più piccolo del Nano, solo non ha l'antenna del wi-fi integrata.

Ciao, Ale.

Gli XIAO sono una famiglia di dev-board fantastica!

Io ne ho una bella manciata, sia ESP32xxx che nRF52840.
Avevo anche un SAMD21, ma non riesco più a trovarlo... chissà che fine ha fatto.

Per quanto riguarda gli ESP32 ci sono anche le ESP32-C3 Super Mini... grandi quanto una moneta da 2€ che è più o meno anche il costo medio.

Per quanto riguarda l'ESP8266, invece di aspettare in un while la connessione al wifi, prova ad usare un approccio "event based".

Dai un'occhiata all'esempio incluso nel core Arduino.

L'esempio fa vedere solo gli eventi associati alla connessione delle station quando lìESP è in AP mode, però è possibile usare lo stesso sistema con tutti i tupi di eventi WiFi e quindi anche quando è l'ESP a connettersi come station.

Io di solito uso l'evento associato al momento in cuio il DHCP server assegna l'indirizzo IP (che non coincide con la connessione) cosi sono sicuro che il micro ha accesso alla rete.

Una possibile "pezza" potrebbe essere quella di reimpostare il timeout del watchdog ad un valore sufficientemente ampio (e poi magari ripristinarlo a quello di default).

Io quando non ho altre soluzioni uso questa funzione che va bene sia per ESP32 che per ESP8266.

void setTaskWdt(uint32_t timeout) {
  #if defined(ESP32)
      #if ESP_ARDUINO_VERSION_MAJOR > 2
      esp_task_wdt_config_t twdt_config = {
          .timeout_ms = timeout,
          .idle_core_mask = (1 << portNUM_PROCESSORS) - 1,    // Bitmask of all cores
          .trigger_panic = false,
      };
      ESP_ERROR_CHECK(esp_task_wdt_reconfigure(&twdt_config));
      #else
      ESP_ERROR_CHECK(esp_task_wdt_init(timeout / 1000, 0));
      #endif
  #elif defined(ESP8266)
      ESP.wdtDisable();
      ESP.wdtEnable(timeout);
  #endif
  }

Certo, infatti come dicevo prima mi sto studiando le librerie del WiFi, compresi gli eventi.

Nessuno riesce a dare una risposta alla mia domanda principale?
Cioè:

come mai il codice funziona senza problemi alla prima connessione WiFi ma al secondo tentativo genera una eccezione e, successivamente dopo il reset software da questa causato, tutto funziona come alla prima connessione?

Nel frattempo ho visto questo

che con i suoi 18mm di larghezza è perfetto considerando che il display TM1637 è alto 27mm. 2 pezzi per circa 11,00€, direi che è perfetto!

Su Aliexpress, se non hai fretta costa molto meno.

Per quanto riguarda la domanda, è da molto che non uso ESP8266, ma ricordo che ogni tanto il micro non si connetteva ad oltranza fino a quando non eseguivo un reset hardware.
Forse hai una situazione del genere?

Prova anche a valutare quali canali WiFi sono liberi intorno a te e ad impostare di conseguenza il micro.
Di default sta tutto sul canale 10, io avevo un sacco di problemi di connessione fino a quando non ho spostato gli ESP sul canale WiFi 4 che era quello più libero al momento.

Interessante, quindi una chiamata prima e una dopo la connessione WiFi potrebbe risolvere il mio problema. Il valore di timeout di default da usare nella seconda chiamata quale deve essere?

Non si tratta di un problema di connessione e/o di canali WiFi.
Come ho scritto più volte dopo l'upload del codice e il relativo reset manuale funziona e si connette in 2 o 3 secondi. Stessa cosa dopo il reset software causato dalla Exception(4).
Sto provando ad effettuare la connessione WiFi nel Setup() e lasciarla attiva anche dopo aver acquisito i dati dal server NTP. Il mio router porterà pazienza! :laughing:

Mi dava fastidio sapere di avere una connessione WiFi attiva h24 inutilmente.
Alla fine per attivare l'aggiornamento alle 3:00 ho risolto così, in modo drastico!

if (hour == 3 && min == 0 && sec == 0) ESP.restart();