3.27. Licznik czasu watchdog

Licznik czasu watchdog to element sprzętu, który resetuje mikrokontroler, jeśli działający skrypt kiedykolwiek przestanie go okresowo szturchać. Skrypt „karmi” watchdoga z miejsca, o którym wie, że wykonuje zdrowy kod; jeśli błąd, zawieszenie lub nieoczekiwany wyjątek kiedykolwiek uniemożliwi kamerze nakarmienie watchdoga w skonfigurowanym czasie, układ sam się zresetuje, a skrypt rusza od nowa.

Na wdrożonym urządzeniu, przy którym nie ma człowieka mogącego wykonać cykl zasilania, jest to różnica między przejściowym błędem, po którym urządzenie wraca do pracy w ciągu kilku sekund, a martwym sprzętem wymagającym wizyty serwisowej.

Wykres licznika watchdoga w czasie. Licznik zaczyna od wartości czasu limitu, spada liniowo w stronę zera i jest przeładowywany do wartości limitu za każdym razem, gdy skrypt wywołuje feed(). Po trzech udanych wywołaniach feed() czwarty interwał nie zawiera feed() i licznik osiąga zero, wyzwalając reset MCU.

Licznik watchdoga odlicza w dół od swojego limitu czasu. Każde feed() przeładowuje go; jeśli osiągnie zero, układ się resetuje.

3.27.1. Klasa machine.WDT

machine.WDT włącza watchdoga i udostępnia jedną metodę, feed(). Po uruchomieniu watchdoga nie da się go zatrzymać – jedynym wyjściem jest karmienie go zgodnie z harmonogramem albo dopuszczenie do zresetowania układu:

from machine import WDT

wdt = WDT(timeout=2000)    # reset if not fed within 2 seconds

while True:
    do_work()
    wdt.feed()

timeout jest podawany w milisekundach. Właściwa wartość zależy od tego, jak długo trwa najdłuższa uprawniona iteracja głównej pętli, z komfortowym zapasem – pętla o czasie 100 ms z limitem 2 s ma duży margines na powolną iterację bez uciążliwych resetów.

3.27.2. Gdzie wywoływać feed()

Miejsce, w którym żyje feed(), jest kluczową decyzją projektową; watchdog wyłapuje błędy tylko w tych częściach kodu, które nie wykonują się między karmieniami.

  • Wywołuj z głównej pętli, na jej górze lub dole. Najpopularniejszy wzorzec. Watchdog wyłapuje wszystko, co zawiesza główną pętlę – zakleszczenie, nieskończone while, urządzenie peryferyjne, które nigdy nie zwraca sterowania – i resetuje układ z powrotem do pętli.

  • Nie wywołuj z procedury obsługi przerwania. Sensem watchdoga jest wyłapywanie zawieszeń w normalnej ścieżce kodu. Procedura ISR, która zgłasza się niezależnie od tego, czy główna pętla utknęła, karmiłaby watchdoga, który powinien się wyzwolić.

  • Nie wywołuj z wnętrza długiej operacji blokującej. Żądanie sieciowe lub odczyt sensora trwający dziesięć sekund to dokładnie ten rodzaj zawieszenia, które watchdog powinien wyłapać. Umieszczenie w nim feed() niweczy tę ochronę.

Wytyczna, która sprawdza się w większości programów: karm raz na iterację głównej pętli, z limitem czasu ustawionym na kilkukrotność oczekiwanego czasu trwania pętli. Jeśli pojedyncza iteracja w uzasadniony sposób potrzebuje więcej czasu niż limit – na przykład celowa faza kalibracji – zbuduj tę fazę jako serię mniejszych fragmentów z feed() pomiędzy nimi, albo zmień limit czasu za pomocą timeout_ms() (tam, gdzie jest obsługiwane) przed jej rozpoczęciem.

3.27.3. Dostępność

Watchdog jest udostępniony na większości kamer OpenMV, ale nie na wszystkich – sprzęt jest obecny na każdym układzie, ale API Pythona nie wszędzie jest jeszcze podpięte. Sprawdź Płytki OpenMV lub spróbuj skonstruować WDT i przechwyć AttributeError, jeśli nie jest obsługiwany.

Nawet na kamerach, na których WDT nie jest udostępniony, urządzenie wdrożone w terenie może użyć programowego odpowiednika – osobnego zadania lub kroku głównej pętli, który monitoruje postęp i wyzwala machine.reset(), jeśli cokolwiek wygląda na zacięte. Jest to mniej niezawodne niż sprzętowy watchdog (zacięta procedura obsługi przerwania może pociągnąć za sobą także programowy monitor), ale obejmuje te same przypadki na poziomie aplikacji.