diff options
Diffstat (limited to 'chip/stm32/watchdog.c')
-rw-r--r-- | chip/stm32/watchdog.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/chip/stm32/watchdog.c b/chip/stm32/watchdog.c index 1fd84b2f43..a25e2576ca 100644 --- a/chip/stm32/watchdog.c +++ b/chip/stm32/watchdog.c @@ -26,11 +26,31 @@ #define IWDG_PRESCALER 6 #define IWDG_PRESCALER_DIV (1 << ((IWDG_PRESCALER) + 2)) +/* + * We use the WWDG as an early warning for the real watchdog, which just + * resets. Since it has a very short period, we need to allow several cycles + * of this to make up one IWDG cycle. The WWDG's early warning kicks in + * half way through the cycle, with a maximum time of 65.54ms at 32 MHz. + */ +#define WATCHDOG_CYCLES_BEFORE_RESET \ + (WATCHDOG_PERIOD_MS / (65540 * 32000 / CPU_CLOCK)) + +/* Keep a track of how many WWDG cycles we have had */ +static unsigned int watchdog_count; + + +static void watchdog_reset_count(void) +{ + watchdog_count = WATCHDOG_CYCLES_BEFORE_RESET; +} + void watchdog_reload(void) { /* Reload the watchdog */ STM32_IWDG_KR = 0xaaaa; + + watchdog_reset_count(); } @@ -44,7 +64,17 @@ void watchdog_reload(void) */ void watchdog_check(uint32_t excep_lr, uint32_t excep_sp) { - /* This is not actually called for now, since we reset instead */ + /* Reset the windowed watchdog here */ + STM32_WWDG_CR = 0xff; + STM32_WWDG_SR = 0; + + /* If the count has expired, output a trace */ + if (!--watchdog_count) { + /* Reset here, to give the UART enough time to send trace */ + watchdog_reset_count(); + watchdog_trace(excep_lr, excep_sp); + watchdog_reset_count(); + } } @@ -86,5 +116,19 @@ int watchdog_init(void) /* Start the watchdog (and re-lock registers) */ STM32_IWDG_KR = 0xcccc; + watchdog_reset_count(); + +#ifdef CONFIG_WATCHDOG_HELP + /* enable clock */ + STM32_RCC_APB1ENR |= 1 << 11; + + STM32_WWDG_SR = 0; + STM32_WWDG_CR = 0xff; + STM32_WWDG_CFR = 0x7f | STM32_WWDG_TB_8 | STM32_WWDG_EWI; + + /* Enable watchdog interrupt */ + task_enable_irq(IRQ_WATCHDOG); +#endif + return EC_SUCCESS; } |