piątek, 10 lutego 2017

[5] Atmega328p - Watchdog

Ten post chciałbym poświęcić na przedstawienie konfiguracji Watchdoga w mikrokontrolerze ATmega328p.

Watchdog taktowany jest oddzielnym zegarem 128kHz. Pozwala na generowanie przerwań czy reset mikrokontrolera. 

Rejestry konfiguracyjne zostały opisane w dokumentacji na stronie 54. 


 W rejestrze konfiguracyjnym można ustawić takie parametry jak:


  • WDIF - flaga ustawiana gdy licznik się zapełni
  • WDIE - włączenie przerwania
  • WDCE - dostęp do prescalera
  • WDE - odpowiada WDRF z rejestru MCUSR. Ustawiany gdy wystąpi reset
  • WDP[3-0] - ustawie dzielnika dla czasu potrzebnego na zapełnienie licznika

Poniższy przykład przedstawia konfigurację watchdoga w włączonymi przerwaniami. Przerwanie jest wywoływane gdy licznik timera się przepełni i nie zostanie zresetowany.

Cały plik nagłówkowy, w którym zawarłem też potrzebne funkcje wygląda następująco:

  1. #ifndef WATCHDOG_LIBRARY_H_
  2. #define WATCHDOG_LIBRARY_H_
  3. #define     WDT_TIME_TAKE   10     
  4. //===============================================================================================
  5. #if WDT_TIME_TAKE==1
  6.     #define WDT_16ms()              WDTCSR = (1<<WDIE)|(1<<WDE)                                 //1
  7. #elif WDT_TIME_TAKE==2                             
  8.     #define WDT_32ms()              WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP0)                       //2
  9. #elif WDT_TIME_TAKE==3
  10.     #define WDT_64ms()              WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP1)                       //3
  11. #elif WDT_TIME_TAKE==4
  12.     #define WDT_0125s()             WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP1)|(1<<WDP0)             //4
  13. #elif WDT_TIME_TAKE==5
  14.     #define WDT_025s()              WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP2)                       //5
  15. #elif WDT_TIME_TAKE==6
  16.     #define WDT_05s()               WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP2)|(1<<WDP0)             //6
  17. #elif WDT_TIME_TAKE==7
  18.     #define WDT_1s()                WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP2)|(1<<WDP1)             //7
  19. #elif WDT_TIME_TAKE==8
  20.     #define WDT_2s()                WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP2)|(1<<WDP1)|(1<<WDP0)   //8
  21. #elif WDT_TIME_TAKE==9
  22.     #define WDT_4s()                WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP3)                       //9
  23. #elif WDT_TIME_TAKE==10
  24.     #define WDT_8s()                WDTCSR = (1<<WDIE)|(1<<WDE)|(1<<WDP3)|(1<<WDP0)             //10
  25. #endif
  26. //===============================================================================================          
  27. #define WDT_Inter_ENABLE()      WDTCSR = (1<<WDCE)|(1<<WDE)
  28. //===============================================================================================
  29. void WDT_init(void)
  30. {
  31.     cli();  //wylaczenie przerwan
  32.    
  33.     MCUSR = 0;    

  34.     wdt_disable();
  35.     wdt_reset();
  36.    
  37.     WDT_Inter_ENABLE();
  38.    
  39.     #if WDT_TIME_TAKE==1
  40.         WDT_16ms();
  41.     #elif WDT_TIME_TAKE==2
  42.         WDT_32ms();
  43.     #elif WDT_TIME_TAKE==3
  44.         WDT_64ms();
  45.     #elif WDT_TIME_TAKE==4
  46.         WDT_0125s();
  47.     #elif WDT_TIME_TAKE==5
  48.         WDT_025s();
  49.     #elif WDT_TIME_TAKE==6
  50.         WDT_05s();
  51.     #elif WDT_TIME_TAKE==7
  52.         WDT_1s();
  53.     #elif WDT_TIME_TAKE==8
  54.         WDT_2s();
  55.     #elif WDT_TIME_TAKE==9
  56.         WDT_4s();
  57.     #elif WDT_TIME_TAKE==10
  58.         WDT_8s();
  59.     #endif
  60.        
  61.     sei();  //Wlaczenie przerwan
  62. }
  63. //===============================================================================================
  64. ISR(WDT_vect)
  65. {
  66.     //Mruganie dioda, komunikat, usart, czy cokolwiek innego
  67.     USART_SEND(COM0,"Watchdog RESET",RX_END_CRLF);;
  68. }
  69. #endif /* WATCHDOG_LIBRARY_H_ */

Jak widać powyżej uruchomienie wachdoga jest mało skomplikowane. Na samym początku wybierana jest instrukcja inicjalizacji czasu dla watchdoga. W zależności od wprowadzonego numeru następuje wykonanie odpowiedniej instrukcji.

W głównej funkcji przerwania na początku zostają wyłączone, po czym następuje wyczyszczenie rejestru MCUSR oraz wyłączenie i zresetowanie watchdoga. Kolejny krok włącza przerwania po czym następuje wgranie odpowiednich ustawień do mikrokontorlera. Na samym końcu przerwania zostają ponownie właczone.

W programie głównym należy wywołać funkcje inicjalizującą z odpowiednimi parametrami, które zostały zdefiniowane jako typy wyliczeniowe. Następnie cyklicznie np. w pętli while bądź w przerwaniach od timera należy wywoływać funkcje, a dokładniej makro wdt_reset();. Została ona zdefiniowana  w bibliotece wdt.h.