Watchdog je typicky HW counter, jehož účel je resetovat systém pokud dosáhne 0. Proto ho systém musí periodicky obnovovat. Tím dá systém najevo, že je zdravý a korektně funguje.


STM watchdogs

STM32F4 ma dva typy watchdogu - kazdy slouzi k automatickemu resetu MCU pokud se firmware zasekne.

IWDG (Independent Watchdog)

Vzorec pro timeout:

timeout = (prescaler × (RL + 1)) / 32000   [sekundy]

Tabulka timeoutů:

Prescaler PR bity Min timeout (RL=0x000) Max timeout (RL=0xFFF)
/4 0 0.125 ms 512 ms
/8 1 0.25 ms 1024 ms
/16 2 0.5 ms 2048 ms
/32 3 1 ms 4096 ms
/64 4 2 ms 8192 ms
/128 5 4 ms 16384 ms
/256 6 8 ms 32768 ms (~32.8s)

Příklad: timeout 1 sekundu → prescaler /32 (PR=3), RL=999 (0x3E7): (32 × 1000) / 32000 = 1.0s

RL nemusí být mocnina 2 — hardware je prostý down-counter, na hodnotě nezáleží.

HAL API:

IWDG_HandleTypeDef hiwdg;
hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_32;
hiwdg.Init.Reload = 999;
HAL_IWDG_Init(&hiwdg);

// Pravidelně volat před vypršením timeoutu:
HAL_IWDG_Refresh(&hiwdg);

WWDG (Window Watchdog)

Priority přerušení (NVIC)

HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);   // preempt priorita 2
HAL_NVIC_SetPriority(USART2_IRQn, 1, 0);   // preempt priorita 1 (vyšší)

Dva parametry priority:

Zkušenosti

Pracoval jsem s watchdogem

IWDG refresh v SysTick handleru

Refresh IWDG jsem umístil do SysTick_Handler (volá se každou 1 ms). Tím je watchdog “nakopnut” každou milisekundu — při timeoutu 1s je to víc než dost. HAL_IWDG_Refresh je jen jeden zápis do registru, takže vysoká frekvence refreshe nevadí.

Aby šlo definovat SysTick_Handler v main.c (odevzdává se jeden soubor), v stm32f4xx_it.c se dá originální definice označit jako __weak — linker pak preferuje tu bez __weak.

Testování watchdogu

Při testování IWDG (nekonečná smyčka v EXTI callbacku) to vypadalo, že watchdog nefunguje — MCU se resetovalo, ale program naběhl do stejného stavu a nebylo to vidět.

Řešení: přidat na začátek main() viditelnou signalizaci (rozsvítit všechny LED na 1s), aby byl reset vizuálně rozpoznatelný.

LED abstrakce

Pro práci s LED diodami přes PWM (TIM4) se osvědčila tabulka mapující pin → timer channel:

typedef struct {
  uint32_t pin;
  uint32_t channel;
} LedConfig;

LedConfig led_channel_mapping[LED_CNT] = {
  {LED_GREEN,  TIM_CHANNEL_1},
  {LED_ORANGE, TIM_CHANNEL_2},
  {LED_RED,    TIM_CHANNEL_3},
  {LED_BLUE,   TIM_CHANNEL_4},
};

LED definice (LED_GREEN = LD4_Pin atd.) jsou bitové masky GPIO pinů — díky tomu funguje bitový OR pro ovládání více LED najednou: led_set(LED_GREEN | LED_RED, 255).

Funkce iterují přes tabulku a testují bitmask:

void led_set(uint16_t leds, uint8_t duty_cycle) {
  for (int i = 0; i < LED_CNT; i++) {
    if (led_channel_mapping[i].pin & leds)
      __HAL_TIM_SET_COMPARE(&htim4, led_channel_mapping[i].channel, duty_cycle);
  }
}