/* independent watchdog support */ #include "hal.h" #include "watchdog.h" #include "stm32_util.h" #ifndef IWDG_BASE #if defined(STM32H7) #define IWDG_BASE 0x58004800 #elif defined(STM32F7) || defined(STM32F4) #define IWDG_BASE 0x40003000 #elif defined(STM32F1) || defined(STM32F3) #define IWDG_BASE 0x40003000 #else #error "Unsupported IWDG MCU config" #endif #endif #ifndef RCC_BASE #error "Unsupported IWDG RCC MCU config" #endif /* define for controlling how long the watchdog is set for. */ #ifndef STM32_WDG_TIMEOUT_MS #define STM32_WDG_TIMEOUT_MS 2048 #endif #if STM32_WDG_TIMEOUT_MS > 4096 || STM32_WDG_TIMEOUT_MS < 20 #error "Watchdog timeout out of range" #endif /* defines for working out if the reset was from the watchdog */ #if defined(STM32H7) #define WDG_RESET_STATUS (*(__IO uint32_t *)(RCC_BASE + 0xD0)) #define WDG_RESET_CLEAR (1U<<16) #define WDG_RESET_IS_IWDG (1U<<26) #define WDG_RESET_IS_SFT (1U<<24) #elif defined(STM32F7) || defined(STM32F4) #define WDG_RESET_STATUS (*(__IO uint32_t *)(RCC_BASE + 0x74)) #define WDG_RESET_CLEAR (1U<<24) #define WDG_RESET_IS_IWDG (1U<<29) #define WDG_RESET_IS_SFT (1U<<28) #elif defined(STM32F1) || defined(STM32F3) #define WDG_RESET_STATUS (*(__IO uint32_t *)(RCC_BASE + 0x24)) #define WDG_RESET_CLEAR (1U<<24) #define WDG_RESET_IS_IWDG (1U<<29) #define WDG_RESET_IS_SFT (1U<<28) #elif defined(STM32G4) || defined(STM32L4) || defined(STM32L4PLUS) #define WDG_RESET_STATUS (*(__IO uint32_t *)(RCC_BASE + 0x94)) #define WDG_RESET_CLEAR (1U<<23) #define WDG_RESET_IS_IWDG (1U<<29) #define WDG_RESET_IS_SFT (1U<<28) #else #error "Unsupported IWDG MCU config" #endif typedef struct { __IO uint32_t KR; /*!< IWDG Key register, Address offset: 0x00 */ __IO uint32_t PR; /*!< IWDG Prescaler register, Address offset: 0x04 */ __IO uint32_t RLR; /*!< IWDG Reload register, Address offset: 0x08 */ __IO uint32_t SR; /*!< IWDG Status register, Address offset: 0x0C */ __IO uint32_t WINR; /*!< IWDG Window register, Address offset: 0x10 */ } IWDG_Regs; #define IWDGD (*(IWDG_Regs *)(IWDG_BASE)) static uint32_t reset_reason; static bool watchdog_enabled; /* setup the watchdog */ void stm32_watchdog_init(void) { // setup the watchdog timeout // t = 4 * 2^PR * (RLR+1) / 32KHz IWDGD.KR = 0x5555; IWDGD.PR = 3; // changing this would change the definition of STM32_WDG_TIMEOUT_MS IWDGD.RLR = STM32_WDG_TIMEOUT_MS - 1; IWDGD.KR = 0xCCCC; watchdog_enabled = true; } /* pat the dog, to prevent a reset. If not called for STM32_WDG_TIMEOUT_MS after stm32_watchdog_init() then MCU will reset */ void stm32_watchdog_pat(void) { if (watchdog_enabled) { IWDGD.KR = 0xAAAA; } } /* save reason code for reset */ void stm32_watchdog_save_reason(void) { if (reset_reason == 0) { reset_reason = WDG_RESET_STATUS; } } /* clear reason code for reset */ void stm32_watchdog_clear_reason(void) { WDG_RESET_STATUS = WDG_RESET_CLEAR; } /* return true if reboot was from a watchdog reset */ bool stm32_was_watchdog_reset(void) { stm32_watchdog_save_reason(); return (reset_reason & WDG_RESET_IS_IWDG) != 0; } /* return true if reboot was from a software reset */ bool stm32_was_software_reset(void) { stm32_watchdog_save_reason(); return (reset_reason & WDG_RESET_IS_SFT) != 0; } /* save persistent watchdog data */ void stm32_watchdog_save(const uint32_t *data, uint32_t nwords) { set_rtc_backup(1, data, nwords); } /* load persistent watchdog data */ void stm32_watchdog_load(uint32_t *data, uint32_t nwords) { get_rtc_backup(1, data, nwords); }