Watchdog Timer su ESP32: firmware che non si blocca mai

Published on 17/07/2026 ESP32

Un ESP32 che si blocca in produzione — magari per un sensore I2C che smette di rispondere, o un while che aspetta una condizione che non arriva mai — è un problema serio se il dispositivo è installato in un posto difficile da raggiungere. Il Watchdog Timer (WDT) è la rete di sicurezza integrata nel chip: se il firmware non "dà segno di vita" entro un tempo stabilito, il watchdog forza un reset.

Due watchdog diversi, da non confondere

L'ESP32 espone due meccanismi distinti:

  • Task Watchdog Timer (TWDT) — gestito da FreeRTOS, sorveglia che i task registrati "resettino" periodicamente il proprio contatore chiamando una funzione di conferma.
  • Watchdog hardware (RTC WDT) — di livello più basso, interviene anche se l'intero sistema (incluso FreeRTOS) è bloccato. Su Arduino IDE è già attivo di default con una configurazione conservativa.

Per la maggior parte dei progetti basta configurare bene il Task Watchdog.

Abilitare e configurare il Task WDT

#include "esp_task_wdt.h"

#define WDT_TIMEOUT_S 5

void setup() {
  Serial.begin(115200);
  esp_task_wdt_init(WDT_TIMEOUT_S, true);  // true = panic (reset) allo scadere
  esp_task_wdt_add(NULL);                  // registra il task corrente (loop)
}

void loop() {
  leggiSensore();
  esp_task_wdt_reset();   // "sono vivo": azzera il contatore
  delay(1000);
}

Se leggiSensore() dovesse bloccarsi per più di 5 secondi (ad esempio un sensore I2C che tiene il bus occupato), esp_task_wdt_reset() non verrebbe mai chiamato: il watchdog scade e il chip riparte da solo, senza bisogno di intervento umano.

Registrare più task in FreeRTOS

Nei progetti che usano più task (es. uno per l'acquisizione sensori, uno per la connettività WiFi/MQTT), ogni task va registrato singolarmente e deve resettare il proprio watchdog:

void taskSensori(void *pv) {
  esp_task_wdt_add(NULL);
  for (;;) {
    acquisisci();
    esp_task_wdt_reset();
    vTaskDelay(pdMS_TO_TICKS(500));
  }
}

void taskRete(void *pv) {
  esp_task_wdt_add(NULL);
  for (;;) {
    gestisciMQTT();
    esp_task_wdt_reset();
    vTaskDelay(pdMS_TO_TICKS(200));
  }
}

Se anche un solo task registrato smette di confermare, l'intero chip viene riavviato: il watchdog non isola il singolo task bloccato, ma protegge il sistema nel suo complesso.

Capire perché si è riavviato: leggere la causa del reset

Dopo un reset da watchdog è utile loggarlo, per distinguere un blocco reale da uno spegnimento normale:

#include "esp_system.h"

void setup() {
  Serial.begin(115200);
  esp_reset_reason_t motivo = esp_reset_reason();
  if (motivo == ESP_RST_TASK_WDT || motivo == ESP_RST_WDT) {
    Serial.println("Riavviato dal watchdog: controllare il codice che si blocca");
  }
}

Errore comune: watchdog troppo aggressivo

Un timeout troppo corto (es. 1 secondo) su operazioni legittimamente lente — una scrittura su flash, una richiesta HTTPS, un aggiornamento OTA — genera riavvii "fantasma" che sembrano bug ma sono solo un watchdog mal tarato. Regola pratica: il timeout deve coprire il caso peggiore realistico del ciclo più lento, con un margine del 50-100%, non il caso medio.

Consiglio pratico: durante lo sviluppo tieni il timeout largo (8-10s) per non essere disturbato da falsi allarmi; una volta stabilizzato il firmware, restringilo al valore minimo che non scatta mai in condizioni normali — è quello il vero indicatore di un blocco reale.