ESP32 WROOM: reboot all'avvio del programma

Salve a tutti,

ho acquistato un ESP32 WROOM, l’ho collegato con un display della Waveshare da 1.47” e risoluzione 320x172, equipaggiato con un ST7789V3.
Per testarlo ho fatto un programma che visualizza data e ora e si sincronizza con un NTP, già che c’ero ho incluso anche le informazioni meteo scaricandole dal LAMMA.
Tutto funziona ma quando lo accendo o lo resetto con il tastino, il programma parte, si blocca e l’ESP si resetta in automatico.
Dopodichè il 90% delle volte il programma funziona senza problemi, a volte si resetta un paio di volte prima di funzionare regolarmente.
Tramite il Serial Monitor ho rilevato queste info:

Avvio test display ST7789...
Display inizializzato.
Connecting to CASA2 .. CONNECTED
E (23671) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:
E (23671) task_wdt: - IDLE0 (CPU 0)
E (23671) task_wdt: Tasks currently running:
E (23671) task_wdt: CPU 0: tiT
E (23671) task_wdt: CPU 1: loopTask
E (23671) task_wdt: Aborting.
E (23671) task_wdt: Print CPU 0 (current core) backtrace

Backtrace: 0x400d4fc6:0x3ffb33a0 0x400d6699:0x3ffb3400 0x400d673d:0x3ffb3440 0x400d2fd5:0x3ffb34a0 0x400ebdd9:0x3ffb3540 0x400ebeb1:0x3ffb3580 0x400ee5e6:0x3ffb35b0 0x400f6745:0x3ffb35e0 0x400f9d1b:0x3ffb3620 0x400fedc2:0x3ffb3650 0x400ee1ae:0x3ffb3670 0x4008dcb1:0x3ffb36a0

ELF file SHA256: 74f5c7369

Rebooting...
ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:4980
load:0x40078000,len:16612
load:0x40080400,len:3500
entry 0x400805b4

dopo il “Connecting to CASA2 .. CONNECTED” l’ESP si è resettato.
Quale può essere la causa?
Grazie, saluti.

Roberto

Quindi cosa funziona?

Da quello che ho capito pare che qualcosa nel programma porti il watchdog a resettare l’ESP32 ma ancora non ho capito cosa.

Io proverei a fare una “semplificazione”.

Provare solo la gestione del display, oppure solo l’accesso al wifi.

Posta lo sketch, così è difficile aiutarti.

Credo di aver trovato la magagna.
Tra le impostazioni dell’ESP32 (nel menu “Tools”) ho verificato che l’opzione “Events Run on:” e “Arduino Runs on:” erano impostate su due core diversi.
In particolare la prima opzione su “Core 1” e la seconda su “Core 0”, ho impostato la prima su “Core 0”, ricompilato e non ha più fatto il reset dopo l’avvio del programma.
Leggendo in giro sembra che la prima opzione, se settata su “Core 0” abbia effetti disastrosi su bluetooth e WiFi, ma nel mio caso avviene esattamente il contrario: impostati entrambi su Core 0 i reset sono cessati.

Roberto

Ma predefinito per Arduino dovrebbe essere core1...

Core 0 o PRO_CPU: è il core che si occupa dei servizi di sistema e è bene NON utilizzarlo per le proprie applicazioni.

Core 1 o APP_CPU: è il core dove devono girare la applicazioni utente.

NO, non l'hai trovata, per qualche strana coincidenza la stai sono temporaneamente aggirando ... la cosa migliore e vedere perché va in crash il programma analizzando le informazioni che vengono date al momento del crash e risolvendo il problema, poi ...

... fai tu :roll_eyes: ... ma ricorda che stai girando in un ambite multitask gestito da FreeRTOS™.

Guglielmo

Seguendo il tuo suggerimento ho reimpostato le 2 opzioni, i reset sono ricominciati.
Le informazioni sui reset sono quelle che ho postato nel primo post, sembrano dovute al fatto che il watchdog effettua il reset, ma non è chiaro quali sono le condizioni di questo “trigger”.
Il 90% del codice è lo stesso che ho utilizzato per un altro progetto con un ESP8266 e gira ininterrottamente da circa 3 anni senza problemi.
Le differenze riguardano il driver/libreria usato per il display (ESP8266 con ILI9341, ESP32 con ST7789V3) ed il fatto che, con l’ESP32, ho utilizzato le funzionalità per sincronizzare l’orologio con un NTP esterno (libreria “time.h”).

... per l'analisi del crash e sapere (più o meno) la linea che lo provoca, con Arduino IDE 1.8.19 (legacy) puoi utilizzare il "esp exception decoder" da installare tra i tools, con Arduino 2.x (minimo 2.2), dato che ancora non supporta i tools aggiuntivi, puoi utilizzare l'ottimo plugin che trovi QUI (ci sono anche le istruzioni per installarlo).

Guglielmo

Grazie per il suggerimento, ho la versione 2.3.6 quindi mi leggerò come installare il plugin.

Roberto

Ho installato il plugin e fatto un test, come mi aspettavo si è resettato 1 volta ed il risultato del plugin è stato il seguente:

PC -> ??
Fault -> ??

0x400d3fdf: TFT_eSPI::setWindow (long, long, long, long) at c:\Users\r.guardamagna\Documents\Arduino\libraries\TFT_eSPI\TFT_eSPI.cpp:3486
0x400d4b0c: TFT_eSPI::fillRect (long, long, long, long, unsigned long) at c:\Users\r.guardamagna\Documents\Arduino\libraries\TFT_eSPI\TFT_eSPI.cpp:4688
0x400d447d: TFT_eSPI::drawChar (long, long, unsigned short, unsigned long, unsigned long, unsigned char) at c:\Users\r.guardamagna\Documents\Arduino\libraries\TFT_eSPI\TFT_eSPI.cpp:3250
0x400d4b8d: TFT_eSPI::drawChar (unsigned short, long, long, unsigned char) at c:\Users\r.guardamagna\Documents\Arduino\libraries\TFT_eSPI\TFT_eSPI.cpp:5199
0x400d6699: TFT_eSPI::drawString (char const*, long, long, unsigned char) at c:\Users\r.guardamagna\Documents\Arduino\libraries\TFT_eSPI\TFT_eSPI.cpp:5655
0x400d673d: TFT_eSPI::drawString (String const&, long, long, unsigned char) at c:\Users\r.guardamagna\Documents\Arduino\libraries\TFT_eSPI\TFT_eSPI.cpp:5494
0x400d2e6f: printLocalTime () at C:\Sorgenti ESP32\NTP Watch ST7789\ntp_watch_ST7789V3\ntp_watch_ST7789V3.ino:256
0x400d2ff1: timeavailable (timeval*) at C:\Sorgenti ESP32\NTP Watch ST7789\ntp_watch_ST7789V3\ntp_watch_ST7789V3.ino:334
0x400ebdd9: sntp_sync_time () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/apps/sntp/sntp.c:62
0x400ebeb1: sntp_set_system_time () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/apps/sntp/sntp.c:146
0x400ee5e6: sntp_recv () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/lwip/src/apps/sntp/sntp.c:331
0x400f6745: udp_input () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/lwip/src/core/udp.c:404
0x400f9d1b: ip4_input () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/lwip/src/core/ipv4/ip4.c:780
0x400fedc2: ethernet_input () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/lwip/src/netif/ethernet.c:186
0x400ee1ae: tcpip_thread () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/lwip/src/api/tcpip.c:179
0x4008dcb1: vPortTaskWrapper () at /home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:139

puoi chiarirmi il significato di quello che vedo?
Grazie

A guardarlo così mi sembra che il problema sia legato all'uso di NTP ...
... metti il codice così vediamo che librerie stai usando e come :roll_eyes:

Guglielmo

//****************************************************************
//****************************************************************
//
//  CONFIGURARE LA SCHEDA COME ESP32 DEV MODULE
//
//****************************************************************
//****************************************************************

#include <SPI.h>
#include <TFT_eSPI.h> // Includi la libreria
#include <WiFi.h>
#include "time.h"
#include "esp_sntp.h"
#include "esp32_small.h"
//#include "clock.h"
#include "wifi_24.h"

//ICONE LAMMA METEO
#include "LAMMA_img/sereno.c"
#include "LAMMA_img/sereno_luna.c"
#include "LAMMA_img/coperto.c"
#include "LAMMA_img/coperto2.c"
#include "LAMMA_img/coperto_luna.c"
#include "LAMMA_img/foschia.c"
#include "LAMMA_img/foschia_luna.c"
#include "LAMMA_img/nebbia.c"
#include "LAMMA_img/neve.c"
#include "LAMMA_img/neve_debole.c"
#include "LAMMA_img/neve_sole.c"
#include "LAMMA_img/neve_sole_luna.c"
#include "LAMMA_img/neve_sole2.c"
#include "LAMMA_img/neve_sole2_luna.c"
#include "LAMMA_img/nuvoloso.c"
#include "LAMMA_img/nuvoloso_luna.c"
#include "LAMMA_img/pioggia_debole.c"
#include "LAMMA_img/pioggia_debole1.c"
#include "LAMMA_img/pioggia_neve.c"
#include "LAMMA_img/pioggia_sole2.c"
#include "LAMMA_img/pioggia_sole2_luna.c"
#include "LAMMA_img/pioggia_sole3.c"
#include "LAMMA_img/pioggia_sole3_luna.c"
#include "LAMMA_img/poco_nuvoloso.c"
#include "LAMMA_img/poco_nuvoloso_luna.c"
#include "LAMMA_img/stratificata2.c"
#include "LAMMA_img/stratificata2_luna.c"
#include "LAMMA_img/temporale.c"
#include "LAMMA_img/temporale_pom.c"
#include "LAMMA_img/temporale_pom_luna.c"
#include "LAMMA_img/question.c"

#define WEATHERSRV_IP "192.168.1.122"  //macchina da cui scaricare i dati LAMMA (PowerPi)
#define WEATHERSRV_PORT 8555

#define FW_VER "v1.2"

//time zone
#define MY_TZ "CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00"  //timezone desiderata
#define NTP_SERVER "ntp1.inrim.it"  //server ntp

const char *ssid = "CASA2";
const char *password = "********";

String giornoSett[] = { "dom", "lun", "mar", "mer", "gio", "ven", "sab"};

/*const char *ntpServer1 = "ntp1.inrim.it";
const char *ntpServer2 = "ntp2.inrim.it";
const long gmtOffset_sec = 0;
const int daylightOffset_sec = 3600;*/

//const char *time_zone = "CET-1CEST,M3.5.0,M10.5.0/3";  // TimeZone rule for Europe/Rome including daylight adjustment rules (optional)
                         	
// Crea un'istanza della libreria
TFT_eSPI tft = TFT_eSPI();

WiFiClient LAMMA_clt;

//struttura per dati LAMMA
typedef struct
{
  String desMeteo;
  String nomeImg;  
} dLAMMA;

dLAMMA LDati[0];

int currFascia;
int oldFascia;

void setup() 
{
  currFascia = 0;
  oldFascia = -1;
  
  //ESP_Watchdog_Setup();

  Serial.begin(115200);
  Serial.println("Avvio test display ST7789...");

  // Inizializza il display
  tft.init();
  tft.setRotation(3); // Prova 0, 1, 2, 3 per la rotazione desiderata

  // Opzionale: accendi la retroilluminazione se hai definito TFT_BL
  #ifdef TFT_BL
    pinMode(TFT_BL, OUTPUT);
    digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
  #endif

  Serial.println("Display inizializzato.");

  // Riempie lo schermo di nero
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.setTextSize(1);

  //tft.drawString("Connessione a " + String(ssid), 10, 10, 2);

  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);

  // Calcola la posizione centrale o desiderata per il logo
  int xPos = (tft.width() - 72) / 2;
  int yPos = (tft.height() - 112) / 2;
  
  // 2. Disegna la Bitmap
  // pushImage(x, y, larghezza, altezza, array_dati)
  // Swap the colour byte order when rendering
  tft.setSwapBytes(true);

  // Draw the icons
  tft.pushImage(xPos, yPos, 72, 112, esp32_small);

  tft.drawString("ESP32 powered - " + String(FW_VER), 160, 155, 2);
  delay(500);

  /**
   * NTP server address could be acquired via DHCP,
   *
   * NOTE: This call should be made BEFORE esp32 acquires IP address via DHCP,
   * otherwise SNTP option 42 would be rejected by default.
   * NOTE: configTime() function call if made AFTER DHCP-client run
   * will OVERRIDE acquired NTP server address
   */
  esp_sntp_servermode_dhcp(1);  // (optional)

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

  // 3. Ottieni l'indirizzo IP come oggetto IPAddress
  IPAddress localIP = WiFi.localIP();
    
  tft.fillScreen(TFT_BLACK);  
  tft.drawLine(0, 27, 320, 27, tft.color565(150, 150, 150));
  tft.drawLine(0, 145, 320, 145, tft.color565(150, 150, 150));
  //tft.drawString(localIP.toString(), 200, 155, 2);
  tft.drawString(localIP.toString(), 160, 5, 2);
  tft.drawString(NTP_SERVER, 20, 5, 2);
  Serial.println(" CONNECTED");

  //tft.pushImage(0, 50, 64, 64, orologio);
  //tft.pushImage(0, 40, 72, 68, pioggia_debole);

  if (WiFi.status() == WL_CONNECTED)
  {
    tft.pushImage(280, 0, 24, 24, wifi_24);
    
    // set notification call-back function
    
    sntp_set_time_sync_notification_cb(timeavailable);

    /**
    * This will set configured ntp servers and constant TimeZone/daylightOffset
    * should be OK if your time zone does not need to adjust daylightOffset twice a year,
    * in such a case time adjustment won't be handled automagically.
    */
    //configTime(gmtOffset_sec, daylightOffset_sec, ntpServer1, ntpServer2);
    
    configTime(0, 0, NTP_SERVER); // 0, 0 because we will use TZ in the next line  
    setenv("TZ", MY_TZ, 1); // Set environment variable with your time zone
    tzset();
  }
   
  //ScaricaDatiLAMMA();
  //configTzTime("Europe/Rome", "ntp1.inrim.it");
}

void loop() 
{
  struct tm timeinfo;

  timeinfo = printLocalTime();
  if (IsWeather(timeinfo))
  {    
    ScaricaDatiLAMMA();  
  }

  //yield();
  //tft.drawString(String(currFascia), 300, 135, 2);  

  delay(50);
  
}

tm printLocalTime() 
{
  struct tm timeinfo;
  String ora="";
  String sec="";
  String data="";
  uint16_t coloreTesto = 0;
  int gs = 0;
  int ss = 0;

  if (!getLocalTime(&timeinfo)) 
  {
    Serial.println("[printLocalTime] orario non ancora disponibile");
    return timeinfo;
  }

  ora = ConvertiHHMM(timeinfo);
  sec = ConvertiSEC(timeinfo);
  ss = timeinfo.tm_sec;
  data = ConvertiData(timeinfo);
  gs = timeinfo.tm_wday;

  SecBar(ss);

  // Imposta i colori e la dimensione del testo
  tft.setTextColor(TFT_WHITE, TFT_BLACK); // Colore testo, Colore sfondo
  //tft.setTextSize(2); // Dimensione 2

  //ora
  tft.setTextSize(4);  
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawString(ora, 85, 55, 1);
  coloreTesto = tft.color565(255, 80, 80);
  tft.setTextColor(coloreTesto, TFT_BLACK);
  tft.drawString(sec, 207, 55, 1);

  //data
  tft.setTextSize(3);
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawString(data, 93, 100, 1);
  
  //ripristino il valore di default
  tft.setTextSize(2);
  tft.drawString(giornoSett[gs], 15, 112, 2);

  //Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

  return timeinfo;
}

void SecBar(int sec)
{
  //disegna la barra di avanzamento dei secondi
  int16_t col = TFT_ORANGE;

  tft.drawRect(178, 158, 123, 14, col);

  if (sec == 0)
    tft.fillRect(180, 160, 120, 10, TFT_BLACK);
  else
    tft.fillRect(180, 160, sec * 2, 10, col); 

}

String ConvertiData(const struct tm &timeinfo)
{
  char timeStringBuff[11];
  strftime(timeStringBuff, sizeof(timeStringBuff), "%d/%m/%Y", &timeinfo);

  return String(timeStringBuff);
}

String ConvertiHHMM(const struct tm &timeinfo)
{
  //ritorna una stringa HH:MM
  char timeStringBuff[6];
  strftime(timeStringBuff, sizeof(timeStringBuff), "%H:%M", &timeinfo);

  return String(timeStringBuff);
}

String ConvertiSEC(const struct tm &timeinfo)
{
  //ritorna una stringa contenente solo i secondi
  char timeStringBuff[4];
  strftime(timeStringBuff, sizeof(timeStringBuff), ":%S", &timeinfo);

  return String(timeStringBuff);
}

String ConvertiOra(const struct tm &timeinfo)
{
  char timeStringBuff[9];
  strftime(timeStringBuff, sizeof(timeStringBuff), "%H:%M:%S", &timeinfo);

  return String(timeStringBuff);
}

// Callback function (gets called when time adjusts via NTP)
void timeavailable(struct timeval *t) 
{
  struct tm timeinfo;
  String ora="";
  
  if (!getLocalTime(&timeinfo)) 
  {
    Serial.println("[timeavailable] orario non ancora disponibile");
    return;
  }
  else
  {
    ora = ConvertiOra(timeinfo);
    tft.setTextSize(1);
    tft.drawString("ultimo agg.to: " + ora, 20, 155, 2);    
  }
  
  Serial.println("effettuato sync con NTP!");
  printLocalTime();
}

void ScaricaDatiLAMMA()
{
  //scarica i dati LAMMA da PowerPi
  
  String line="";
  dLAMMA LD;
  
  if (WiFi.status() == WL_CONNECTED) 
  {    
    if (!LAMMA_clt.connect(WEATHERSRV_IP, WEATHERSRV_PORT))
    {
      //ClearDisplay();
      tft.pushImage(0, 40, 72, 72, question);
      Serial.println("PowerPi non raggiungibile");
    }
    else
    {
      Serial.println("Connesso a LAMMA_srv");
      LAMMA_clt.setTimeout(3500);
      LAMMA_clt.print("*"); 
            
      while (LAMMA_clt.connected() || LAMMA_clt.available())
      {
        if (LAMMA_clt.available())
        {
          line = LAMMA_clt.readStringUntil('*');
          //String line = LAMMA_clt.read();
          Serial.println(line);
        }
      }
      LAMMA_clt.stop(); 
      //estrae i dati dalla stringa ricevuta
      LD= ConvertiDatiLAMMA(line);
      //visualizza dati meteo
      //ClearDisplay();       
      LDati[0].nomeImg= LD.nomeImg;
      //descrMeteo= LD.desMeteo;
      
      //seleziono la bitmap da mostrare      
      if (LDati[0].nomeImg=="sereno") tft.pushImage(0, 40, 72, 68, sereno);
      if (LDati[0].nomeImg=="sereno_luna") tft.pushImage(0, 40, 72, 68, sereno_luna);
      if (LDati[0].nomeImg=="coperto") tft.pushImage(0, 40, 72, 68, coperto);
      if (LDati[0].nomeImg=="coperto_luna") tft.pushImage(0, 40, 72, 68, coperto_luna);
      if (LDati[0].nomeImg=="coperto2") tft.pushImage(0, 40, 72, 68, coperto2);
      if (LDati[0].nomeImg=="foschia") tft.pushImage(0, 40, 72, 68, foschia);
      if (LDati[0].nomeImg=="foschia_luna") tft.pushImage(0, 40, 72, 68, foschia_luna);
      if (LDati[0].nomeImg=="nebbia") tft.pushImage(0, 40, 72, 68, nebbia);
      if (LDati[0].nomeImg=="nebbia_luna") tft.pushImage(0, 40, 72, 68, nebbia);
      if (LDati[0].nomeImg=="neve") tft.pushImage(0, 40, 72, 68, neve);
      if (LDati[0].nomeImg=="neve_luna") tft.pushImage(0, 40, 72, 68, neve);
      if (LDati[0].nomeImg=="neve_debole") tft.pushImage(0, 40, 72, 68, neve_debole);
      if (LDati[0].nomeImg=="neve_debole_luna") tft.pushImage(0, 40, 72, 68, neve_debole);
      if (LDati[0].nomeImg=="neve_sole") tft.pushImage(0, 40, 72, 68, neve_sole);
      if (LDati[0].nomeImg=="neve_sole_luna") tft.pushImage(0, 40, 72, 68, neve_sole_luna);
      if (LDati[0].nomeImg=="neve_sole2") tft.pushImage(0, 40, 72, 68, neve_sole2);
      if (LDati[0].nomeImg=="neve_sole2_luna") tft.pushImage(0, 40, 72, 68, neve_sole2_luna);
      if (LDati[0].nomeImg=="nuvoloso") tft.pushImage(0, 40, 72, 68, nuvoloso);
      //if (LDati[0].nomeImg=="nuvoloso nuvoloso") tft.pushImage(0, 40, 72, 68, nuvoloso);
      if (LDati[0].nomeImg=="nuvoloso_luna") tft.pushImage(0, 40, 72, 68, nuvoloso_luna);
      //if (LDati[0].nomeImg=="nuvoloso nuvoloso_luna") tft.pushImage(0, 40, 72, 68, nuvoloso_luna);
      if (LDati[0].nomeImg=="pioggia_debole") tft.pushImage(0, 40, 72, 68, pioggia_debole);      
      if (LDati[0].nomeImg=="pioggia_debole1") tft.pushImage(0, 40, 72, 68, pioggia_debole1);
      if (LDati[0].nomeImg=="pioggia_debole1_luna") tft.pushImage(0, 40, 72, 68, pioggia_debole1);
      if (LDati[0].nomeImg=="pioggia_debole_luna") tft.pushImage(0, 40, 72, 68, pioggia_sole2_luna);
      if (LDati[0].nomeImg=="pioggia_neve") tft.pushImage(0, 40, 72, 68, pioggia_neve);
      if (LDati[0].nomeImg=="pioggia_neve_luna") tft.pushImage(0, 40, 72, 68, pioggia_neve);
      if (LDati[0].nomeImg=="pioggia_sole2") tft.pushImage(0, 40, 72, 68, pioggia_sole2);
      if (LDati[0].nomeImg=="pioggia_sole2_luna") tft.pushImage(0, 40, 72, 68, pioggia_sole2_luna);
      if (LDati[0].nomeImg=="pioggia_sole3") tft.pushImage(0, 40, 72, 68, pioggia_sole3);
      if (LDati[0].nomeImg=="pioggia_sole3_luna") tft.pushImage(0, 40, 72, 68, pioggia_sole3_luna);
      if (LDati[0].nomeImg=="poco_nuvoloso") tft.pushImage(0, 40, 72, 68, poco_nuvoloso);
      if (LDati[0].nomeImg=="poco_nuvoloso_luna") tft.pushImage(0, 40, 72, 68, poco_nuvoloso_luna);
      if (LDati[0].nomeImg=="stratificata2") tft.pushImage(0, 40, 72, 68, stratificata2);
      //if (LDati[0].nomeImg=="velato stratificata2") tft.pushImage(0, 40, 72, 68, stratificata2);
      if (LDati[0].nomeImg=="stratificata2_luna") tft.pushImage(0, 40, 72, 68, stratificata2_luna);
      //if (LDati[0].nomeImg=="velato stratificata2_luna") tft.pushImage(0, 40, 72, 68, stratificata2_luna);
      if (LDati[0].nomeImg=="temporale") tft.pushImage(0, 40, 72, 68, temporale);
      if (LDati[0].nomeImg=="temporale_luna") tft.pushImage(0, 40, 72, 68, temporale);
      if (LDati[0].nomeImg=="temporale_pom") tft.pushImage(0, 40, 72, 68, temporale_pom);
      if (LDati[0].nomeImg=="temporale_pom_luna") tft.pushImage(0, 40, 72, 68, temporale_pom_luna);
      if (LDati[0].nomeImg=="question") tft.pushImage(0, 40, 72, 68, question);
      if (LDati[0].nomeImg=="") tft.pushImage(0, 40, 72, 68, question);
      //descrizione meteo
      //testoXY(90, 35, 1, ILI9341_WHITE, LD.desMeteo, false); 
      //Blynk.virtualWrite(FORECAST_CHAN, LD.desMeteo);                  
    }
  }
  else
  {
    //ClearDisplay();
    Serial.println("WiFi non connesso");
  }
  
  //DisplayData(dataOra);
}

dLAMMA ConvertiDatiLAMMA(String strDati)
{
  //ritorna una struttura con i dati ricevuti dal LAMMA srv (TankPI)
  dLAMMA LD;
  int posiz=0;
  String str="";

  LD.desMeteo="";
  LD.nomeImg="";
    
  //estraggo i vari dati, data ultimo agg.to
  posiz= strDati.indexOf(",");
  if (posiz>0)
  {
    str= strDati.substring(0, posiz);        
    //LD.desMeteo= str;
    //elimino il dato trovato
    strDati.replace(str+",", "");
    Serial.println("ult. agg.: "+str);    
  }
    
  //descrizione meteo
  posiz = strDati.indexOf(",");
  if (posiz>0)
  {
    str= strDati.substring(0, posiz);        
    LD.desMeteo= str;
    //elimino il dato trovato
    strDati.replace(str+",", "");
    Serial.println("descr. meteo: "+str);    
  }

  //nome immagine da visualizzare
  strDati.replace(".png", "");
  strDati.replace("*", "");
  LD.nomeImg= strDati;
  Serial.println("nome immagine: "+strDati);    
    
  return LD;   
}

bool IsWeather(const struct tm &timeinfo)
{ //ritorna true se l'orario casca all'inizio di una delle fasce previste per il cambio meteo
  //le fasce sono:
  //mattina:    8:00-10:59
  //mattina2:   11:00-13:59
  //pomeriggio:  14:00-16:59
  //pomeriggio2: 17:00-19:59
  //sera:        20:00-22:59
  //sera2:       23:00-01:59
  //notte        02:00-04:59
  //Notte2       05:00-07:59
  //
  //converto la stringa dell'ora corrente in un intero e poi faccio i confronti.

  int oraInt = 0;
  
  String ora = ConvertiOra(timeinfo);
  ora.replace(":", "");
  oraInt = ora.toInt();

  if ((oraInt >= 80000) && (oraInt <=105959)) currFascia = 1;
  if ((oraInt >= 110000) && (oraInt <=135959)) currFascia = 2;
  if ((oraInt >= 140000) && (oraInt <=165959)) currFascia = 3;
  if ((oraInt >= 170000) && (oraInt <=195959)) currFascia = 4;
  if ((oraInt >= 200000) && (oraInt <=225959)) currFascia = 5;
  if ((oraInt >= 230000) && (oraInt <=235959)) currFascia = 6;
  if ((oraInt >= 0) && (oraInt <=15959)) currFascia = 6;
  if ((oraInt >= 20000) && (oraInt <=45959)) currFascia = 7;
  if ((oraInt >= 50000) && (oraInt <=75959)) currFascia = 8;

  if (currFascia != oldFascia)
  {
    //cambio fascia, deve richiedere nuovi dati
    oldFascia=currFascia;
    return true;
  }
  
  return false;
}

Allego l’immagine di quello che viene visualizzato sul display.

Il plugin ti mostra lo stato della memoria e lo stack delle chiamate a funzione al momento in cui c'è l'errore.

Il problema è che il tuo è un errore di reset del Watch dog del task che detta in parole povere significa che il tuo task ovvero il tuo loop sta impiegando troppo tempo a far qualcosa.

Secondo me con il plugin non ottieni molte informazioni utili perché questa cosa può accadere in qualsiasi momento perché dipende da fattori aleatori che sono esterni al tuo firmware.

Devi concentrare le analisi su tutti quei pezzi di codice che potrebbero rimanere bloccati a tempo indefinito: connessioni a server esterni gestiti senza timeout ad esempio oppure cicli while che possono durare troppo.

Se non ricordo male il task Watch dog di default è impostato a 5 secondi che per alcune connessioni a server esterni ad esempio possono anche essere troppo pochi.

Al momento ti scrivo dallo smartphone, ma appena ho 5 minuti prova a darci uno sguardo anch'io.

Mi sembrava che questa cosa fosse valida per ESP8266 ... ESP32, con FreeRTOS™ e Core separati NON dovrebbe essere soggetto a questi problemi ... :roll_eyes:

O hanno implementato un meccanismo a tempo anche per Core 1 ???

Guglielmo

No il task watchdog è attivo comunque.

Si può di certo allungare se necessario, ma con il sdkconfig predefinito per il framework Arduino non mi sembra che si possa disattivare (ma sto andando a memoria, sarebbe da verificare)

Allora, questo è vero per il "Idle task", per gli altri lo devi attivare a mano:

The Task Watchdog Timer (TWDT) is used to monitor particular tasks, ensuring that they are able to execute within a given timeout period. The TWDT primarily watches the Idle Tasks of each CPU, however any task can subscribe to be watched by the TWDT. By watching the Idle Tasks of each CPU, the TWDT can detect instances of tasks running for a prolonged period of time wihtout yielding. This can be an indicator of poorly written code that spinloops on a peripheral, or a task that is stuck in an infinite loop.

The TWDT is built around the Hardware Watchdog Timer in Timer Group 0. When a timeout occurs, an interrupt is triggered. Users can define the function esp_task_wdt_isr_user_handler in the user code, in order to receive the timeout event and extend the default behavior.

Però, probabilmente, se il "Idle task" non riesce a girare perchè altri task lo bloccano, allora il TWDT scatta ... :roll_eyes:

Forse sarebbe il caso di aggiungere nel codice degli yield() per dare tempo al tutto di girare.

Guglielmo

P.S.: riferimento Watchdogs - ESP32 - — ESP-IDF Programming Guide v5.1.3 documentation

Però…se il watchdog ha un timeout di 5 secondi, all’avvio il programma non impiega più di 5 secondi per fare tutto quelle che deve anzi “visivamente” dopo che ha caricato la prima bitmap il reset avviene non appena viene “disegnata” la schermata.
Solitamente la stringa dell’ora appare incompleta e poi avviene il reset.
Visualizzando il Serial Monitor con il timestamp attivo risulta che:

  • alle 17:28:33.173 c’è stato l’avvio del programma
  • alle 17:28:36.856 il reset (-> assert failed: xTaskPriorityDisinherit tasks.c:5156 (pxTCB == pxCurrentTCBs[ xPortGetCoreID() ]))