WatchDog na ochranu kódu pred chybami a zacyklením

Programový kód mikrokontroléra sa môže z rôznych príčin zaseknúť alebo nežiaduco zacykliť. Nakoľko sa mikrokontroléry používajú na riadenie rôznych zariadení, alebo na zber údajov, znamenalo by takéto zaseknutie veľký problém.

Napríklad pri regulácii teploty v akváriu by rybičky trpeli prehriatím, alebo naopak zimou, podľa toho, v akom stave spínacieho prvku vyhrievacieho telesa by sa program riadiaceho mikrokontroléru zasekol. Preto je k dispozícii takzvaný watchdog, čiže mechanizmus, ktorý mikroprocesor v prípade akéhokoľvek „zaseknutia“ programu vyvedie z tohto nežiadúceho stavu resetom. Princíp fungovania watchdogu je vo videu. V závere videa je upútavka na tému ovládania motorov a robotických vozidiel. Je tam ukázaná stavebnica robotického vozidla komplet s podvozkom, motormi, Arduinom a modulom na ovládanie motorov. Cena stavebnice je 20 eur.

Watchdog je neodmysliteľnou súčasťou systémov, kde nemôže obsluha včas reagovať na chyby. V takýchto zariadeniach sa riadiaci systém musí vedieť v primeranom čase zotaviť sám. Z hľadiska princípu je to mechanizmus veľmi podobný čítaču, nezávislý od CPU, ktorý sa inkrementuje a v okamihu keď počítadlo dosiahne nastavenú hodnotu, mikrokontrolér resetuje. Aby sa tak nestalo, je potrebné periodicky nulovať hodnotu tohto počítadla. Počas bežnej prevádzky programový kód toto počítadlo pravidelne nuluje, takže nastavená hodnota sa nikdy nedosiahne. Ak v dôsledku chyby hardvéru alebo programu nedokáže programový kód počítadlo resetovať, počítadlo dosiahne nastavenú hodnotu, pri ktorej je potrebné vykonať akciu na nápravu situácie. Najčastejšie sa mikrokontrolér v takom prípade resetuje, alebo sa vygeneruje prerušenie.

Po resete, ktorý spôsobí watchog začne program mikrokontroléra bežať znovu. A v prípade ak chybu, pre ktorú sa program zasekne, alebo zacyklí nenájdete, sa watchdog znovu aktivuje. Preto je dôležité stav, kedy sa mikrokontrolér resetoval z dôvodu watchdogu nejakým spôsobom indikovať, napríklad rozsvietením LED diódy signalizujúcej poruchový stav. Periodické nastavovanie registra watchdogu je potrebné vložiť do hlavnej slučky programu aj do všetkých cyklov v procedúrach, ktoré trvajú dlhšie.

Watchdog sa okrem vyvedenia mikrokontroléra z chybového stavu občas využíva aj ako časovač, na periodické spúšťanie nejakej sekvencie kódu, alebo na periodické „prebúdzanie“ mikrokontroléra z režimu hibernácie, do ktorého sa uvádza za účelom minimalizácie spotreby energie z batérie.

Mikrokontrolér ATmega 328, ktorý je srdcom mnohých prototypových dosiek Arduino má časovač Watchdog Timer (WDT), ktorý je taktovaný interným oscilátorom s taktom 128 kHz. WDT vyvolá prerušenie, alebo reset, ak čítač dosiahne nastavený časový limit. Pri inicializácii tohoto mechanizmu je potrebné nastaviť takzvanú prahovú hodnotu časovača, po prekročení ktorej sa mikrokontrolér resetuje. Môžete nastaviť konštanty v rozsahu od 15 milisekúnd až po 8 sekúnd. Tieto konštanty majú hodnoty WDTO_15MS, WDTO_30MS, WDTO_60MS, WDTO_120MS, WDTO_250MS, WDTO_500MS, WDTO_1S, WDTO_2S, WDTO_4S a WDTO_8S. Konštantu nastavíte v závislosti od účelu programu. Ak je normálne, že nejaká časť trvá približne sekundu, nastavíte čas WDTO_2S, čiže 2 sekundy. Pokiaľ je riadiaci systém časovo kritický a nesmie vypadnúť na dlhší čas, nastavíte krátky interval, napríklad 15 ms (konštanta WDTO_15MS) a resetovací príkaz wdt_reset();  budete musieť pri dlhšie trvajúcich akciách pozostávajúcich s dlhších cyklov vkladať aj no ich vnútra.

Tlačidlo bdelosti rušňovodiča

Dobrou analógiou fungovania watchdogu je tlačidlo bdelosti rušňovodiča. Funguje to presne rovnako. Ak je rušňovodič v poriadku, to znamená, že je bdelý a neprišlo mu zle, stláča v periodických intervaloch tlačidlo.  Ak by dostal mikrospánok a tlačidlo v stanovenom časovom limite nestlačil, spustí sa núdzový mechanizmus. Najskôr sa riadiaci systém lokomotívy pokúsi nejakým zvukom rušňovodiča prebudiť a ak sa to nepodarí, aktivuje sa brzdiaci mechanizmus, ktorý zastaví vlak. Presne takto bude fungovať prvý príklad.

Časový limit na stlačenie tlačidla bude 4 sekundy.  Reset, či už prvý po zavedení programu, alebo každý ďalší bude identifikovaný bliknutím zelenej LED.  Fungovanie kódu bude signalizované rýchlym blikaním oranžovej LED diódy na doske. Rýchlym preto, aby sa v sľučke tohoto jednoduchého kódu čo najčastejšie čítal stav tlačidla na pine 2.

#include <avr/wdt.h> //WatchDogTimer funkcie
 
int zelenaLED = 12;
int oranzovaLED = 13;
 
void setup()
{
 wdt_disable(); //zakazanie WDT
 pinMode(zelenaLED, OUTPUT); 
 pinMode(oranzovaLED, OUTPUT); //LED na doske
 pinMode(2,INPUT); //Pin 2 ako vstupný
 digitalWrite(zelenaLED, HIGH); 
 delay(200);
 digitalWrite(zelenaLED, LOW); 
 wdt_enable(WDTO_4S);
}
 
void loop()
{
 if(digitalRead(2) == HIGH)
  { //čítanie tlačidla resetujúceho WDT
   wdt_reset();  //reset WDT 
  }
  
 digitalWrite(oranzovaLED, HIGH);
//blikaj oranzovou LED
 delay(100); //pauza 500 ms
 digitalWrite(oranzovaLED,LOW); 
 delay(100);  
}

Po spustení programu zelená LED blikne a ak budete tlačidlo stláčať v kratších ako 4 sekundových intervaloch zostane LED dióda zhasnutá. Ak to nestihnete, pretečie časovač

Tlačidlo rušňovodiča je dobrým námetom na príklad aj z iného dôvodu. Ak riadiaci systém lokomotívy musí strojvodcu budiť zvukovým signálom, táto udalosť sa zaznamená. Veľmi ľahko by sa dalo urobiť zadanie na ďalší príklad. Ak došlo k resetu z dôvodu prekročenia doby watchdogu, zostane svietiť druhá červená LED. To sa však ľahšie zadá, než zrealizuje. Kam by ste umiestnili kód, ktorý by si zapamätal, že aspoň raz zasiahol watchdog a kde by ste umiestnili premennú tak, aby sa po resete od watchdogu jej stav nevynuloval?

Po resete sa totiž všetky premenné nastavia buď na hodnotu uvedenú v deklarácii premennej, alebo na nulu ak pri deklarácii hodnota premennej nie je uvedená. Môžete si to vyskúšať na jednoduchom kóde, kedy v prechode cez reset budete inkrementovať stav premennej a vypisovať na sériový port. Nie je to zbytočný príklad, v aplikácii na monitorovanie sériovej komunikácie môžete podľa počtu výpisov zistiť, či, a ak áno tak koľkokrát sa aktivoval watchdog.

#include <avr/wdt.h> //WatchDogTimer funkcie
 
int oranzovaLED = 13;
int zelenaLED = 12;
 
static int nWDT;
 
void setup()
{
 wdt_disable(); //zakazanie WDT
 pinMode(zelenaLED, OUTPUT);
 pinMode(oranzovaLED, OUTPUT); //LED na doske 
 pinMode(2,INPUT); //Pin 2 ako vstupný
  // inicializácia sériovej komunikácie
 Serial.begin(9600);
 digitalWrite(zelenaLED, HIGH); 
 delay(200);
 digitalWrite(zelenaLED, LOW); 
  nWDT++;
 Serial.print("nWDT = ");
 Serial.println(nWDT);
   
 wdt_enable(WDTO_4S);
}
 
void loop()
{
 if(digitalRead(2) == HIGH)
 { //čítanie tlačidla resetujúceho WDT
   wdt_reset();  //reset WDT 
 }
 
 digitalWrite(oranzovaLED, HIGH);
 //blikaj oranzovou LED
 delay(100); //pauza 500 ms
 digitalWrite(oranzovaLED,LOW); 
 delay(100);  
}

Našťastie mikrokontroler Arduina má aj pamäť typu EEPROM, čiže elektricky preprogramovateľnú pamäť, ktorá je primárne určená na ukladanie konfiguračných hodnôt. Takže odpoveď na druhú otázku kam informáciu o tom, že došlo k zásahu watchdogu vieme – do EEPROM. A prezradíme aj odpoveď na prvú otázku, kde umiestniť kód, ktorý do EEPROM zapíše informáciu, že došlo k watchdogu – urobíme to v obsluhe prerušenia vyvolanom pretečením WDT časovača. Tejto problematike sa budeme venovať v budúcom pokračovaní…


Převzato z webu Nextech se souhlasem autora.