Watchdog, come evitare i dead loop
Il watchdog è un sistema molto interessante impiegato per supervisionare il normale ciclo di istruzioni eseguite dalla cpu.
L’idea è quella di monitorare l’esecuzione del programma per evitare blocchi o cicli infiniti (dead loop), dovuti a bug logici o situazioni esterne che portano il microcontrollore ad attender, per esempio, a input che non arriveranno mai.
In questo caso il watchdog interviene resettando il microcontrollore e riavviando automaticamente l’esecuzione del codice.
Questo meccanismo è solitamente implementato in hardware e, anche Arduino, basato sul microcontrollore ATMega328, supporta questa funzione
Se il programma che andiamo a scrivere per la board Arduino è progettato considerando tutti gli aspetti e le variabili che possono bloccare la cpu, non è necessario gestire il Watchdog, che di default è disabilitato.
Capita comunque che si verificano delle particolari condizioni che portano il programma a rimanere in attesa, ad esempio, di un particolare input che per cause esterne, non gestibili, potrebbe non arrivare mai.
Il watchdog quindi attende per un certo periodo e se, allo scadere di questo tempo l’input non è arrivato il Watchdog resetta la cpu facendola riavviare. In caso contrario, quando l’input arriva entro questo tempo, è fondamentale che il codice resetti il watchdog per evitare che questo resetti continuamente la cpu.
Il diagramma a blocchi seguente illustra in modo banale il meccanismo del watchdog
Codice da utilizzare
Per utilizzare il Watchdog inseriamo nello sketch il riferimento alla libreria wdt.h
#include <avr/wdt.h>
I tempi di reset del Watchdog sono prestabiliti e possono essere scelti utilizzando i valori specificati nella tabella seguente
Tempo reset | Parola Chiave |
15mS | WDTO_15MS |
30mS | WDTO_30MS |
60mS | WDTO_60MS |
120mS | WDTO_120MS |
250mS | WDTO_250MS |
500mS | WDTO_500MS |
1S | WDTO_1S |
2S | WDTO_2S |
4S | WDTO_4S |
8S | WDTO_8S |
Nel blocco setup() decidiamo di abilitare il watchdog specificando il tempo di reset utilizzando la seguente funzione:
//abilito il watchdog e imposto come tempo di reser 2 secondi wdt_enable(WDTO_2S);
questo significa che se entro 2 secondi non resettiamo il conteggio del watchdog, esso eseguirà automaticamente il reset della cpu.
Per resettarlo impieghiamo la seguente funzione:
//resetto il watchdog wdt_reset();
Il codice seguente mostra meglio il funzionamento del sistema
#include <avr/wdt.h> void setup() { //attivo il watchdog e lo imposto //per una soglia di tempo di 2 Secondi wdt_enable(WDTO_2S); } void loop() { //eseguo qualcosa... delay(500); //resetto il watchdog wdt_reset(); }
All’interno del blocco loop() eseguo un delay di 500 ms e poi resetto il watchdog, in questo caso il watchdog non resetterà mai la cpu poiché non arriverà mai a contare i due secondi preimpostati, dato che il reset avviene ogni 500 ms.
Vediamo invece questa situazione:
#include <avr/wdt.h> void setup() { //attivo il watchdog e lo imposto //per una soglia di tempo di 2 Secondi wdt_enable(WDTO_2S); } void loop() { //eseguo qualcosa... delay(3000); //3 secondi //resetto il watchdog wdt_reset(); }
Il codice precedente mette in funzione il sistema di auto reset in quanto, il delay di 3 secondi, fa in modo che il watchdog arrivi a contare i 2 secondi preimpostati facendo resettare la cpu.
Di fatto l’istruzione wdt_reset() non verrà mai eseguita.
Consiglio di utilizzare questo meccanismo in tutte le situazioni critiche che richiedono una certezza che la cpu esegua costantemente il suo compito evitando blocchi che porterebbero all’interruzione del servizio.