Strony

piątek, 12 października 2012

Watchdog AVR - prostsze niż myślisz

Witam,

Ponieważ ostatnimi czasy dostaję także sporo zapytań na temat Watchdoga w AVR i widzę, iż pomimo rzekomej prostoty temat ten budzi wciąż wiele wątpliwości i niezrozumienia, chciałbym napisać kilka zdań. Ale panowie i Panie, zanim coś napiszę to najpierw jednak skieruję waszą uwagę na właściwe tory jeśli chodzi o to jak sobie radzić samemu w takich kwestiach. Tym bardziej, że czasem zastanawiam się aż - co tutaj pisać, skoro wystarczyłyby prawie przysłowiowe 2-3 zdania i temat omówiony. Dlatego dziwię się, jakimi drogami próbują nieraz niektóre osoby dochodzić do sedna sprawy. Przede wszystkim zanim się zada pytanie na tego typu temat warto sięgnąć do dokumentacji, którą się ma na dysku, do pliku nagłówkowego, do internetu itp. Nie chcę przez to broń Boże udawać cwaniaczka, co to odsyła wszystkich do dokumentacji zamiast wytłumaczyć, ale jednak postanowiłem podpowiedzieć jak ja np próbuję do czegoś dojść najpierw sam. Może to na przyszłość i wam ułatwi lepsze posługiwanie się dokumentacją bo rozumiem też, że na początku to zwykle człowiek nie wie jak się poruszać w tym gąszczu nowych informacji. A zatem, do rzeczy...

Pierwsze co robimy to rzucamy okiem do pliku jak na obrazku i proszę sobie to zapamiętać. Nawet nie trzeba wielce znać angielskiego żeby coś tam wypatrzeć, czując nawet tylko piąte przez dziesiąte o co chodzi:

Tak tak, każdy z nas posiada na własnym dysku w takim folderze ten plik PDF ;) .... proszę od niego zaczynać, zamiast od żmudnych poszukiwań w internecie, tym bardziej, że zwykle początkujący w tym internecie trafia na jakieś bardzo dziwne strony na których otrzymuje często bardzo pokrętne wyjaśnienia. Szukamy więc interesujących nas haseł, w tym przypadku WDT i otwieramy PDF'a na początku rozdziału opisującego plik ngałówkowy "wdt.h"

Nie będę tu wklejał całego tekstu z PDF, ale chcę tylko pokazać, że jest w nim o tym mowa, a jeśli nawet ciężko nam idzie z angielskim to na kolejnych stronach mamy zaledwie kilka fajnych i prostych poleceń, tak że wystarczy tylko rzucić okiem i już wszystko układa się w przejrzystą całość:
Gdy to ujrzymy to w zasadzie widać od razu wszystko co nam potrzeba odnośnie Watchdoga jeśli chodzi o AVR GCC ;) Od góry patrząc mamy 3 polecenia (funkcje)


  • wdt_reset()
  • wdt_enable( value )
  • wdt_disable()


oraz nazwy wartości 'value' które możemy przekazać jako argument do wdt_enable(). Na prawdę, proszę częściej zaglądać do tego pliku ;) .... ale w przypadku Watchdoga wystarczy nawet samo ECLIPSE, wystarczy bowiem dołączyć plik nagłówkowy na górze kodu



a następnie trzymając wciśnięty lewy klawisz CTRL kliknąć myszką w nazwę wdt.h i zostaniemy przeniesieni do tegoż pliku w nowej zakładce gdzie również z opisów będzie można domyślić się zasady działania. Ale to nie wszystko, w Eclipse działa także podpowiedź kontekstowa z klawiszami CTRL+SPACE, wystarczy zatem wpisać sobie wdt_ i kliknąć CTRL+SPACE

Proszę bardzo i od razu mamy przepiękną podpowiedź jakie komendy dostaje użytkownik do swoich łapek. Tymczasem jak przyjrzeć się wielu pytaniom na forach czy też nadsyłanym na maila - gdy patrzę na te kody źródłowe to zastanawiam się gdzie niektórzy z was drodzy koledzy poszukiwali informacji, pisząc we własnym kodzie takie odwołania się do bezpośrednich rejestrów i bitów odpowiedzialnych za Watchdoga w AVR skoro mamy przygotowane już piękne i dobrze działające gotowe funkcje. A funkcje te zwalniają nas właśnie z tej zabawy na poziomie bitów i rejestrów jeśli chodzi o pracę z Wartchdogiem.

Dobrze tyle tytułem wstępu i propozycji podejmowania poszukiwań we własnym zakresie na początku. A teraz szczypta teorii po polsku. Cóż to za zwierzę ten Watchdog?



Jest to ni mniej ni więcej jak tylko pewien specyficzny rodzaj timera sprzętowego (zakładam już, że wiesz co to są timery sprzętowe i mniej więcej chociaż jak działają). A zatem posiada on także swój własny preskaler dzięki czemu można ustawiać temu timerowi różną częstotliwość na wejściu. Po co ?  Otóż mechanizm ten działa od wieków prawie zawsze tak samo.


  1. Odpalamy timer watchdoga
  2. Zaczyna on zliczać impulsy zgodnie z ustawionym preskalerem
  3. Gdy doliczy do końca, czyli się przepełni to wywołuje bezwzględny RESET procesora


Dzięki preskalerowi możemy ustawiać niejako różne czasy odliczania od zera do przepełnienia - czyli do resetu, wyrażane zwykle w milisekundach. Stąd wyżej widziałeś takie definicje tych wartości 'value' , argumentu funkcji wdt_enable(). Teraz już chyba zaczyna ci się wszystko klarować. Tylko trzy polecenia!

wdt_enable( value );

posłuży nam do załączenia (wystartowania tegoż timera Watchdoga). Co oznacza, że gdy zacznie odliczać to jak tykanie bomby zegarowej ;) .... gdy dojdzie do końca to może nie nastąpi wybuch ale na pewno RESET procesora. Teraz trzeba się zastanowić czy my jako programista mamy jakąś możliwość zadziałania jak saper i jak to bywa w filmach przecięcia kabelka aby zatrzymać tykającą bombę. Zastanawiać się tylko będziemy czy przeciąć zielony czy czerwony, czerwony czy zielony ;) ..... itd

a na poważnie - sam chyba już widzisz, że jednym z poleceń do przecięcia kabelka będzie:

wdt_disable()

co chyba jest oczywiste jak to że posmarowana kromka chleba zawsze spadnie ze stołu tą strona na której jest masło ;) Co oznacz tylko tyle że po prostu wdt_disable() wyłącza, natomiast wdt_enable(value) włącza tykanie naszej bomby albo innymi słowy mówiąc spuszcza z łańcucha psa który pilnuje czy procesor się nie zawiesi ?

No dobrze, ale właśnie - co teraz gdy procesor się zawiesi, jak tego używać w praktyce i do czego jest to trzecie polecenie

wdt_reset() 

Otóż jest to kolejne polecenie do przecięcia kabelka ale niestety ono nie zatrzyma na stałe odliczania bomby (watchdoga) a spowoduje tylko małe odroczenie, to znaczy, że timer zostanie zresetowany do zera i będzie odliczał od nowa. O!!!

I tu zbliżamy się do sedna. Używanie Watchdoga polega na tym, że np tuż przed pętlą główną programu startujemy Watchdoga a następnie w każdym krytycznym momencie, czyli tam gdzie nieco dłużej musi trwać jakiś fragment programu, musimy dokonywać tego odraczania czyli zerowania timera. Robimy to świadomie bo przecież nie chcemy aby Watchdog co chwilę resetował nam procka. Niekiedy możemy użyć go w całkiem przeciwnym celu, właśnie specjalnie po to aby zresetował nam procesor ;) .... Np gdy chcemy wywołać Bootloader. Naturalnie gdy program zawiesi się w nieprzewidzianym przez nas miejscu, na czas dłuższy niż podaliśmy VALUE dla wdt_enable(), to także nastąpi RESET. Ale lepszy reset i przynajmniej próba podjęcia przez procesor i program normalnej pracy niż trwanie w stanie bezczynności w zawieszeniu prawda ? Spójrz więc na kod poniżej i spróbuj powiedzieć co on ma za zadanie?
-------------------------------------------
-------------------------------------------
Jak się domyślasz w pierwszej linii uruchamiamy Watchdoga. W drugiej linii wyłączamy przerwania, bo gdzieś może w którymś z nich mogło być pozostawione polecenie wdt_disable() albo wdt_reset(), więc mamy pewność że żadne z nich się nie wykona ;) a następnie w trzeciej linii tworzymy pętlę nieskończoną, która także nie zawiera wyłączenia czy też zresetowania watchdoga. Ustawiliśmy możliwie najkrótszy czas do przepełnienia timera (ilość dostępnych czasów zależy od wersji procka jakim się posługujemy). A zatem gdy ta pętla będzie się wykonywać, to podziała ona tylko przez 15 ms i CIACH, nastąpi RESET procesora. Tak tak - to właśnie najprostszy sposób na programowy RESET procesora i to prawidłowy reset procesora. Dlatego dobrze go sobie zapamiętaj bo czasem może ci się przydać.

Spróbujmy jednak zobaczyć w jaki sposób najczęściej wykorzystujemy Watchdoga, czyli do pilnowania czy procek się nie zawiesił/zapętlił itp..... W takich wypadkach, po wystartowaniu Watchdoga musimy od razu w ważnych miejscach programu dokonywać ciągłego resetowania timera watchdoga, a szczególnie w tych miejscach gdzie pewne funkcje mogą się dłużej wykonywać. Ale najpierw podstawa - przykład:
--------------------------------
--------------------------------
Załóżmy ustawiamy Watchdoga aż na 1 sekundę jeśli nasz procesor na taką opcję pozwala. Od tej pory jesteśmy wręcz zmuszeni aby cyklicznie i wciąż resetować timer watchdoga i to w czasie zawsze krótszym niż 1 sekunda. W przypadku kodu powyżej na szczęście taka pętla główna wykona się wręcz wiele milionów razy na sekundę a więc nie grozi nam reset. Gdyby jednak doszło do zawieszenia się programu podczas wywołania, którejś z w funkcji wołanych w pętli głównej i nie nastąpiłby powrót do pętli głównej przez co nie wykonałoby się polecenie wdt_reset() to już się spodziewasz co mogłoby się stać? znowu RESET! Czy jednak jest sens kilka milionów razy na sekundę dokonywać tego resetowania ? w tym przypadku akurat nie - bo to też (chociaż nie na długo) ale jakoś tam spowalnia działanie pętli głównej - a po co ? Trzeba się zatem zastanowić gdzie warto takie resetowanie rozmieścić. Czyli w jakich momentach kodu rozminowywać naszą tykającą bombę żeby to nie przeszkadzało całości. Otóż mamy tu wywołanie timera programowego, które odbywa się akurat równo co pół sekundy (tak go załóżmy sobie skonfigurowałem) Zatem lepiej będzie z punktu optymalizacji programu jeśli ja to resetowanie Watchdoga będę dokonywał w tym timerze programowym co pół sekundy. Nadal pozwoli mi to uniknięcia RESETU. --------------------------------
--------------------------------
Jednak pewnie dobrze zdajesz sobie sprawę, że gdybym teraz zmienił czas inicjalizacji watchdoga z 1 sekundy (WDTO-1S), na np. 15 ms, to niestety w tej pętli głównej wykonałoby się tylko kilka poleceń może np z pierwszej wywoływanej funkcji (zakładając że jej czas trwania np miałby wuynieść 40 ms) ... i RESET! Dlatego jak mówię posługiwanie się Watchdogiem to jak praca sapera, trzeba po założeniu pola minowego, zwracać baczną uwagę w których miejscach programu odbezpieczać ścieżkę dla naszych wojsk, czyli rozminowywać po drodze Watchdoga. Jeśli to dobrze zrobimy, a nasza najnowsza wersja Firmware, którą piszemy właśnie do nowego sterownika, niestety gdzieś się zawiesi - to na szczęście pilnujący Pies co się wabi Watchdog, przypilnuje procka, ugryzie go i zresetuje ;) Mam nadzieję, że to chyba nie jest jakieś trudne i skomplikowane do zrozumienia? Ale z drugiej strony zdaję sobie sprawę, że osoba, która całkowicie początkuje może mieć jeszcze jakieś wątpliwości czy pytania - więc proszę śmiało i bez żadnych ogródek pytać. Ale UWAGA!!! Nie w każdym procesorze Watchdog działa do końca tak samo. W nowszych prockach takich jak np te z serii ATmega88/168/328 i wiele innych wbudowany jest tzw EXTENDED WATCHDOG. Co to oznacza? Otóż może on po doliczeniu do końca spowodować nie tylko RESET procesora ale także wygenerować specjalne przerwanie. Bywa to bardzo przydatny mechanizm bo później za pomocą odpowiednich bitów w rejestrach Watchdoga można jeszcze programowo sprawdzić, czy jeśli nastąpił RESET - to czy przypadkiem był on spowodowany właśnie Watchdogiem czy też innym zewnętrznym czynnikiem jak np. chwilowy brak zasilania czy może ręczny RESET operatora. Po szczegóły to już odeślę do noty PDF, jeśli zechcesz z tego skorzystać, ja tylko powiem jedną ważną rzecz. Bardzo ważną rzecz. Otóż niektórzy ludzi dziwią się bardzo, że po tym gdy raz odpalą w takich prockach posiadających Extended Watchdog, timer watchdoga a następnie wystąpi reset z jego powodu to domyślnie Watchdog ten jest nadal aktywny po takim RESECIE, co powoduje przedziwny dla niektórych efekt, jakby się ATmega88 "zbiesiła" czyli nagle przestała działać na AMEN, jakby się zawiesiła i nie chciała zareagować nawet na fizyczne zwarcie nogi RESET do GND. Co jest ???? myślą niektórzy podejrzewając nawet że właśnie procek odszedł do krainy wiecznych łowów ;) Ale nagle po wyłączeniu zasilania i ponownym włączeniu procek ŻYJE i daje oznaki że działa. Więc o co chodzi ? Otóż w tych procesorach bezwzględnie TRZEBA NATYCHMIAST po starcie wyłączyć watchdoga. Tyle że niestety - czasem może się okazać że polecenie wdt_disable() wykonane w głównej funkcji main(), będzie już za późno bo np procedury inicjalizacyjne zajęły więcej czasu niż np 15ms i nadal procesor będzie w stanie wiecznej ekstazy - wiecznego RESETU aż do wyłączenia fizycznego zasilania i włączenia. Jak sobie radzić w takich przypadkach ? Na szczęście jest na to proste rozwiązanie. Fajnie jest pokazane przy okazji omawiania bootloadera (pod koniec strony) z linku poniżej:


 W skrócie, chodzi o to aby wyłączenia Watchdoga dokonać na jak najwcześniejszym etapie startu programu, jeszcze dużo wcześniej niż wystartuje główna funkcja programu main(). Do tego celu służą specjalne przewidziane w AVR GCC specjalne sekcje inicjalizacyjne. Normalnie większość z nich dokonuje odpowiedniej inicjalizacji pamięci (np zerowanie zmiennych globalnych) itp ... ale niektóre z nich są przeznaczone dla użytkownika, czyli dla nas ;) np sekcja INIT3. Dlatego to w niej można wrzucić w takich procesorach kod służący do tego celu, tak jak ten przedstawiony na dole strony w linku, który podałem wyżej. Możesz go wprost skopiować i wkleić gdzieś na początku programu - wtedy zostanie wkompilopwany pomiędzy inne sekcje inicjalizacyjne i nastąpi prawidłowe wyłączenie Watchdoga. Nie musisz się wtedy martwić że znowu coś nie zdąży zadziałać ;)

To by było na tyle..... (zapraszam ew do zadawania pytań uzupełniających).

15 komentarzy:

  1. Witam, a czy możliwe jest zawieszenie się samego watchdoga?:) Że nasz procesor zawiesi się razem z nim? Pozdrawiam

    OdpowiedzUsuń
    Odpowiedzi
    1. No oczywiście - np gdy podłączysz napięcie 230V do procesora i odparuje mu struktura - wtedy przestanie działać watchdog i procesor ;) - to pół żartem pół serio

      w innym przypadku NIE, watchdog to moduł sprzętowy i niezależny od programu - więc jak się ma zawiesić ? ;)

      Usuń
    2. teoretycznie TAK!!!

      W sytuacji ustawienia zbyt krótkiego czasu do resetu,
      watchdog zadziałał,
      watchdog został przypadkowo włączony za pomocą wskaźnika lub
      timer watchdog pozostał włączony
      i co dalej...
      RESET....i Ciach....RESET....i Ciach.... itd...
      Pamiętać należy aby podczas inicjalizacji
      usuwać flagę WDRF i bit WDE
      NAWET JEŚLI NIE UŻYWAMY watchdog-a:)
      Dziękuję.->
      Bardzo OGÓLNIKOWE podejście autora do tematu.

      Usuń
    3. Ogólnikowe powiadasz? ;) ... hmmm widzisz, jakby ci to powiedzieć - bo to jest dla ludzi myślących

      Usuń
  2. Brakuje jeszcze opisu Watchdoga z możliwością użycia go do generowania przerwań co jakiś określony czas (i ew resetu, jeśli przerwanie watchdoga nie zostanie wykonane). Np ATTiny13(A) ma dodatkowe bity rejestru Watchdoga, gdzie można ustawić takie działanie.

    OdpowiedzUsuń
    Odpowiedzi
    1. Ja myślę, że jeszcze nawet paru innych rzeczy brakuje ale to miał być temat wprowadzenie i w zasadzie wyjaśnienie podstaw co to za zwierzę ten WatchDog osobom, które jeszcze go w ogóle nie znały albo bały się go używać z uwagi na niezrozumienie podstaw jego działania. Myślę że po takim wstępie na pewno warto zawsze zajrzeć do noty każdego z procków i doczytać czym różnią się wersje wbudowanych watchdogów, bo na pewno są także takie zastosowania czy funkcjonalności jak pisze kolega.

      Usuń
    2. Akurat jestem początkującym "programistą" i głównie bawię się na ATTiny13A. Myślałem, że generowanie przerwania to także podstawowa funkcja, jednak nota np ATMega8 mówi coś innego a to chyba najpopularniejszy układ, tyle, że tam są 3 Timery i taka funkcja w Watchdogu już by chyba była zbędna.
      W ATTiny natomiast miałem problem, bo po resecie wywoływanym cyklicznie przez Watchdoga (wychodzenie z trybu uśpienia) nie wystarczy wdt_reset czy też wdt_disable ale trzeba wyzerować bit w MCUSR nazwany WDRF: Watchdog Reset Flag, o czym również nie ma informacji w tym artykule jak i chyba większości w necie (w nocie jest). Z 3h mi zajęło znalezienie tego "błędu" ale się udało i przy okazji poznałem dokładniej działanie WD w tym procesorze. Z WD jako generatora przerwań pewnie skorzystam jeszcze z racji braku drugiego sprzętowego Timera i zrobię na nim programowy Timer, dokładnie taki jak stosujesz u siebie w przykładach. Przerwanie co 125ms powinno mi w zupełności wystarczyć do odmierzania czasu.

      Usuń
    3. I bardzo dobry, wręcz genialny sposób kolega sobie znalazł na zastosowanie Watchdoga ;)

      Usuń
  3. Przykładowy kod zawiera niewielki błąd (race condition):

    wdt_enable(WDTO_15MS );
    cli();
    while(1);

    W przypadku wystąpieniu przerwania zawierającego wyłączenie watchdog-a po instrukcji wdt_enable() a przed cli(), pętla while nigdy się nie skończy (bo watchdog wyłączony) i procesor 'zawiesi' się na dobre.

    Wystarczy zamienić te instrukcje miejscami - najpierw cli a później watchdog_enable - by uniknąć tej możliwości.

    OdpowiedzUsuń
  4. Jestem na początku programowania i uczę się ustawiać watchdog'a ale program avr studio nie kompiluje programu a nie wiem gdzie jest błąd

    #include
    #include
    #include

    int main(void)

    {
    WDTCR |= (1<<WDTOE)|(1<<WDE);
    DDRA=0b11111111;;
    PORTA=0xFF;
    int i;
    int liczba =3;
    wdt_enable(WDT0_3s);
    for(i=0;i<8;i++)
    PORTA=~liczba;
    liczba =liczba*2;
    _delay_ms(200);
    wdt_reset();
    }

    OdpowiedzUsuń
    Odpowiedzi
    1. I uważasz że to dobry pomysł wklejać tutaj kod na blogu z którego prawie nic nie widać ? czyżbyś nie widział w moich poradnikach - nie słyszał - jak mówię o naszym forum?

      www.forum.atnel.pl

      tam zapraszam z takimi pytaniami ok?

      Usuń
    2. No rzeczywiście kolega wkleił kod z którego wiele widać:)

      Usuń
  5. Czy resetowanie Watchdoga w przerwaniu to dobry pomysł?

    OdpowiedzUsuń
    Odpowiedzi
    1. Resetować można WSZĘDZIE, również w przerwaniu - co za problem. Trzeba tylko przemyśleć to dobrze - jak jest skonstruowany program. Pomyśl co się stanie w twoim programie, gdy np ZAWIESI się gdzieś program główny - a przerwanie będzie działać ? To wtedy KLOPS - wachdog nie zrestartuje procka. No ale jak mówię - różnie może być - to na prawdę indywidualne kwestie projektu.

      Usuń