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:
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).
Teraz została jeszcze do zaimplementowania funkcja odpowiedzialna za inicjalizację układu.
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.
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:
- //Ustawienie timeout
- typedef enum {
- Internal_WDG_Timeout_5ms = 0x00,
- Internal_WDG_Timeout_10ms = 0x01,
- Internal_WDG_Timeout_15ms = 0x02,
- Internal_WDG_Timeout_30ms = 0x03,
- Internal_WDG_Timeout_60ms = 0x04,
- Internal_WDG_Timeout_120ms = 0x05,
- Internal_WDG_Timeout_250ms = 0x06,
- Internal_WDG_Timeout_500ms = 0x07,
- Internal_WDG_Timeout_1s = 0x08,
- Internal_WDG_Timeout_2s = 0x09,
- Internal_WDG_Timeout_4s = 0x0A,
- Internal_WDG_Timeout_8s = 0x0B,
- Internal_WDG_Timeout_16s = 0x0C,
- Internal_WDG_Timeout_32s = 0x0D
- }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).
- #define IWDG_Reset() (IWDG->KR = 0xAAAA)
- uint8_t Internal_WDG_Init(Internal_WDG_Timeout_t time_wdg);
Teraz została jeszcze do zaimplementowania funkcja odpowiedzialna za inicjalizację układu.
- uint8_t Internal_WDG_Init(Internal_WDG_Timeout_t time_wdg)
- {
- uint8_t result_value = 0;
- uint16_t reload_value = 0;
- if (RCC->CSR & RCC_CSR_IWDGRSTF) //Sprawdzenie co wywolalo reset
- {
- result_value = 1; //Reset od watchdogaa
- RCC->CSR |= RCC_CSR_RMVF; //Czyszczenie wszystkich flag
- }
- IWDG->KR = 0x5555; //Odblokowanie mozliwosci wpisywania danych do rejestrow
- if (timeout >= Internal_WDG_Timeout_8s) //Ustawienie odpowiedniej wartosci zegara dla timeoutu
- {
- IWDG->PR = 0x07; //IWDG counter clock: LSI/256 = 128Hz
- }
- else
- {
- IWDG->PR = 0x03; //IWDG counter clock: LSI/32 = 1024Hz
- }
- switch(time_wdg)
- {
- case Internal_WDG_Timeout_5ms:
- reload_value = 5;
- break;
- case Internal_WDG_Timeout_10ms:
- reload_value = 10;
- break;
- case Internal_WDG_Timeout_15ms:
- reload_value = 15;
- break;
- case Internal_WDG_Timeout_30ms:
- reload_value = 31;
- break;
- case Internal_WDG_Timeout_60ms:
- reload_value = 61;
- break;
- case Internal_WDG_Timeout_120ms:
- reload_value = 123;
- break;
- case Internal_WDG_Timeout_250ms:
- reload_value = 255;
- break;
- case Internal_WDG_Timeout_500ms:
- reload_value = 511;
- break;
- case Internal_WDG_Timeout_1s:
- reload_value = 1023;
- break;
- case Internal_WDG_Timeout_2s:
- reload_value = 2047;
- break;
- case Internal_WDG_Timeout_4s:
- reload_value = 4095;
- break;
- case Internal_WDG_Timeout_8s:
- reload_value = 1023;
- break;
- case Internal_WDG_Timeout_16s:
- reload_value = 2047;
- break;
- case Internal_WDG_Timeout_32s:
- reload_value = 4095;
- break;
- }
- IWDG->RLR = reload; //Ustawienie czasu przeladowania
- IWDG->KR = 0xAAAA; //Odswiezenie wartosci licznika, Window option Disable,
- IWDG->KR = 0xCCCC; //Wlaczenie internal wdg, lsi wlaczone zostanie przez hardware
- return result_value; //Czy reset od watchdoga
- }
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.