poniedziałek, 16 stycznia 2017

[7] STM32F7 - Watchdog

Ten post chciałbym poświęcić na opisanie niezależnego watchdoga (ang. Independent Watchdog) mikrokontrolera STM32F7.

Jest on taktowany zegarem LSI RC o częstotliwości 32 kHz.


Rejestry IWDG zostały umieszczone w domenie 1.8V voltage domain (CORE). Natomiast funkcje w VDD voltage domain. Dzięki temu może on pracować w trybach o obniżonym poborze prądu. LSI ma możliwość wykorzystywania 8 bitowego dzielnika. Gdy osiągnie wartość 0 następuje reset. Z tego powodu należy go cyklicznie odświeżać w czasie mniejszym niż czas potrzebny do odliczenia do wartości 0.

Dodatkowym trybem jest tzw. Window option. Jeśli jest on włączony reset musi być wywoływana właśnie w tym oknie. Inaczej nastąpi wygenerowanie resetu.

Po starcie układu, blok zliczający w dół (12 bitowy) rozpoczyna pracę od wartości 0xFFF.

Nie ma potrzebny włączać go z poziomu CubeMx ponieważ jest on bardzo prosty w implementacji.

Opis rejestrów został umieszczony na stronie 860 dokumentu RM0385.

Poniżej znajduje się elementy zawarte w pliku nagłówkowym:

  1. //Ustawienie timeout
  2. typedef enum {
  3.     Internal_WDG_Timeout_5ms = 0x00,
  4.     Internal_WDG_Timeout_10ms = 0x01,
  5.     Internal_WDG_Timeout_15ms = 0x02,
  6.     Internal_WDG_Timeout_30ms = 0x03,
  7.     Internal_WDG_Timeout_60ms = 0x04,
  8.     Internal_WDG_Timeout_120ms = 0x05,
  9.     Internal_WDG_Timeout_250ms = 0x06,
  10.     Internal_WDG_Timeout_500ms = 0x07,
  11.     Internal_WDG_Timeout_1s = 0x08,
  12.     Internal_WDG_Timeout_2s = 0x09,
  13.     Internal_WDG_Timeout_4s = 0x0A,
  14.     Internal_WDG_Timeout_8s = 0x0B,
  15.     Internal_WDG_Timeout_16s = 0x0C,
  16.     Internal_WDG_Timeout_32s = 0x0D
  17. }Internal_WDG_Timeout_t;

Powyższa definicja typu wyliczeniowego zawiera dostępne wartości opóźnień dla watchdoga. Zostają one obliczone z następującego wzoru:

t_IWDG(ms) = t_LSI(ms) * 4 * (2^(IWDG_PR[2:0])) * (IWDG_RLR[11:0]+1)

t_LSI(ms) jest czasem obliczony na podstawie częstotliwości kwarcu (1/32k) = 1/32000 = 0.03125.

W tym pliku dodatkowo znajduje się prototyp funkcji, oraz definicja wywołania resetu dla rejestru, co wykonuje się poprzez przeładowanie IWDG_KR (ang. Key Register).

  1. #define IWDG_Reset()     (IWDG->KR = 0xAAAA)
  2. uint8_t Internal_WDG_Init(Internal_WDG_Timeout_t time_wdg);

Teraz została jeszcze do zaimplementowania funkcja odpowiedzialna za inicjalizację układu.

  1. uint8_t Internal_WDG_Init(Internal_WDG_Timeout_t time_wdg)
  2. {
  3.     uint8_t result_value = 0;
  4.     uint16_t reload_value = 0;
  5.     if (RCC->CSR & RCC_CSR_IWDGRSTF)            //Sprawdzenie co wywolalo reset
  6.     {
  7.         result_value = 1;                       //Reset od watchdogaa
  8.         RCC->CSR |= RCC_CSR_RMVF;               //Czyszczenie wszystkich flag
  9.     }
  10.     IWDG->KR = 0x5555;                          //Odblokowanie mozliwosci wpisywania danych do rejestrow
  11.     if (timeout >= Internal_WDG_Timeout_8s)     //Ustawienie odpowiedniej wartosci zegara dla timeoutu
  12.     {
  13.         IWDG->PR = 0x07;                        //IWDG counter clock: LSI/256 = 128Hz
  14.     }
  15.     else
  16.     {
  17.         IWDG->PR = 0x03;                        //IWDG counter clock: LSI/32 = 1024Hz
  18.     }
  19.     switch(time_wdg)
  20.     {
  21.         case Internal_WDG_Timeout_5ms:
  22.             reload_value = 5;
  23.             break;
  24.         case Internal_WDG_Timeout_10ms:
  25.             reload_value = 10;
  26.             break;
  27.         case Internal_WDG_Timeout_15ms:
  28.             reload_value = 15;
  29.             break;
  30.         case Internal_WDG_Timeout_30ms:
  31.             reload_value = 31;
  32.             break;
  33.         case Internal_WDG_Timeout_60ms:
  34.             reload_value = 61;
  35.             break;
  36.         case Internal_WDG_Timeout_120ms:
  37.             reload_value = 123;
  38.             break;
  39.         case Internal_WDG_Timeout_250ms:
  40.             reload_value = 255;
  41.             break;
  42.         case Internal_WDG_Timeout_500ms:
  43.             reload_value = 511;
  44.             break;
  45.         case Internal_WDG_Timeout_1s:
  46.             reload_value = 1023;
  47.             break;
  48.         case Internal_WDG_Timeout_2s:
  49.             reload_value = 2047;
  50.             break;
  51.         case Internal_WDG_Timeout_4s:
  52.             reload_value = 4095;
  53.             break;
  54.         case Internal_WDG_Timeout_8s:
  55.             reload_value = 1023;
  56.             break;
  57.         case Internal_WDG_Timeout_16s:
  58.             reload_value = 2047;
  59.             break;
  60.         case Internal_WDG_Timeout_32s:
  61.             reload_value = 4095;
  62.             break;
  63.     }
  64.     IWDG->RLR = reload;                         //Ustawienie czasu przeladowania
  65.     IWDG->KR = 0xAAAA;                          //Odswiezenie wartosci licznika, Window option Disable,
  66.     IWDG->KR = 0xCCCC;                          //Wlaczenie internal wdg, lsi wlaczone zostanie przez hardware
  67.     return result_value;                        //Czy reset od watchdoga
  68. }

W pętli głównej należy włączyć watchdoga z jedną z wartości zdeklarowanych jako typ wyliczeniowy. Po czym w pętli while, bądź w cyklicznych przerwaniach od timera należy resetować układ poprzez podanie wartości 0xAAAA do rejestru KR.