diff --git a/arch/arm/src/stm32h7/hardware/stm32_wdg.h b/arch/arm/src/stm32h7/hardware/stm32_wdg.h index e19008048b3..d68a2c0a3fd 100644 --- a/arch/arm/src/stm32h7/hardware/stm32_wdg.h +++ b/arch/arm/src/stm32h7/hardware/stm32_wdg.h @@ -118,12 +118,16 @@ #define WWDG_CFR_W_SHIFT (0) /* Bits 6:0 W[6:0] 7-bit window value */ #define WWDG_CFR_W_MASK (0x7f << WWDG_CFR_W_SHIFT) -#define WWDG_CFR_WDGTB_SHIFT (7) /* Bits 8:7 [1:0]: Timer Base */ -#define WWDG_CFR_WDGTB_MASK (3 << WWDG_CFR_WDGTB_SHIFT) -# define WWDG_CFR_PCLK1 (0 << WWDG_CFR_WDGTB_SHIFT) /* 00: CK Counter Clock (PCLK1 div 4096) div 1 */ -# define WWDG_CFR_PCLK1d2 (1 << WWDG_CFR_WDGTB_SHIFT) /* 01: CK Counter Clock (PCLK1 div 4096) div 2 */ -# define WWDG_CFR_PCLK1d4 (2 << WWDG_CFR_WDGTB_SHIFT) /* 10: CK Counter Clock (PCLK1 div 4096) div 4 */ -# define WWDG_CFR_PCLK1d8 (3 << WWDG_CFR_WDGTB_SHIFT) /* 11: CK Counter Clock (PCLK1 div 4096) div 8 */ +#define WWDG_CFR_WDGTB_SHIFT (11) /* Bits 13:11 [2:0]: Timer Base */ +#define WWDG_CFR_WDGTB_MASK (7 << WWDG_CFR_WDGTB_SHIFT) +# define WWDG_CFR_PCLK1 (0 << WWDG_CFR_WDGTB_SHIFT) /* 000: CK Counter Clock (PCLK1 div 4096) div 1 */ +# define WWDG_CFR_PCLK1d2 (1 << WWDG_CFR_WDGTB_SHIFT) /* 001: CK Counter Clock (PCLK1 div 4096) div 2 */ +# define WWDG_CFR_PCLK1d4 (2 << WWDG_CFR_WDGTB_SHIFT) /* 010: CK Counter Clock (PCLK1 div 4096) div 4 */ +# define WWDG_CFR_PCLK1d8 (3 << WWDG_CFR_WDGTB_SHIFT) /* 011: CK Counter Clock (PCLK1 div 4096) div 8 */ +# define WWDG_CFR_PCLK1d16 (4 << WWDG_CFR_WDGTB_SHIFT) /* 100: CK Counter Clock (PCLK1 div 4096) div 16 */ +# define WWDG_CFR_PCLK1d32 (5 << WWDG_CFR_WDGTB_SHIFT) /* 101: CK Counter Clock (PCLK1 div 4096) div 32 */ +# define WWDG_CFR_PCLK1d64 (6 << WWDG_CFR_WDGTB_SHIFT) /* 110: CK Counter Clock (PCLK1 div 4096) div 64 */ +# define WWDG_CFR_PCLK1d128 (7 << WWDG_CFR_WDGTB_SHIFT) /* 111: CK Counter Clock (PCLK1 div 4096) div 128 */ #define WWDG_CFR_EWI (1 << 9) /* Bit 9: Early Wakeup Interrupt */ diff --git a/arch/arm/src/stm32h7/stm32_wwdg.c b/arch/arm/src/stm32h7/stm32_wwdg.c index 888ad15ebac..293b6e53d09 100644 --- a/arch/arm/src/stm32h7/stm32_wwdg.c +++ b/arch/arm/src/stm32h7/stm32_wwdg.c @@ -49,7 +49,7 @@ /* The minimum frequency of the WWDG clock is: * - * Fmin = PCLK1 / 4096 / 8 + * Fmin = PCLK1 / 4096 / 128 * * So the maximum delay (in milliseconds) is then: * @@ -57,11 +57,11 @@ * * For example, if PCLK1 = 42MHz, then the maximum delay is: * - * Fmin = 1281.74 - * 1000 * 64 / Fmin = 49.93 msec + * Fmin = 42,000,000 / 4096 / 128 = ~80.11 Hz + * 1000 * 64 / Fmin = ~798.92 msec */ -#define WWDG_FMIN (STM32_PCLK1_FREQUENCY / 4096 / 8) +#define WWDG_FMIN (STM32_PCLK1_FREQUENCY / 4096 / 128) #define WWDG_MAXTIMEOUT (1000 * (WWDG_CR_T_MAX+1) / WWDG_FMIN) /* Configuration ************************************************************/ @@ -334,6 +334,10 @@ static int stm32_start(struct watchdog_lowerhalf_s *lower) wdinfo("Entry\n"); DEBUGASSERT(priv); + /* Clear the pending interrupt bit */ + + modifyreg32(STM32_WWDG_SR, WWDG_SR_EWIF, 0); + /* The watchdog is always disabled after a reset. It is enabled by setting * the WDGA bit in the WWDG_CR register, then it cannot be disabled again * except by a reset. @@ -454,13 +458,13 @@ static int stm32_getstatus(struct watchdog_lowerhalf_s *lower, /* Get the time remaining until the watchdog expires (in milliseconds) */ reload = (stm32_getreg(STM32_WWDG_CR) >> WWDG_CR_T_SHIFT) & 0x7f; - elapsed = priv->reload - reload; + elapsed = (WWDG_CR_T_RESET | priv->reload) - reload; status->timeleft = (priv->timeout * elapsed) / (priv->reload + 1); wdinfo("Status :\n"); wdinfo(" flags : %08x\n", status->flags); wdinfo(" timeout : %d\n", status->timeout); - wdinfo(" timeleft : %d\n", status->flags); + wdinfo(" timeleft : %d\n", status->timeleft); return OK; } @@ -548,7 +552,7 @@ static int stm32_settimeout(struct watchdog_lowerhalf_s *lower, wdinfo("wdgtb=%d fwwdg=%d reload=%d timeout=%d\n", wdgtb, fwwdg, reload, 1000 * (reload + 1) / fwwdg); #endif - if (reload <= WWDG_CR_T_MAX || wdgtb == 3) + if (reload <= WWDG_CR_T_MAX || wdgtb == 7) { /* Note that we explicitly break out of the loop rather than using * the 'for' loop termination logic because we do not want the diff --git a/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c b/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c index 1c9293b05c1..77e6e6b4118 100644 --- a/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c +++ b/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c @@ -595,6 +595,30 @@ static inline void rcc_enableapb3(void) regval |= RCC_APB3ENR_LTDCEN; #endif +#ifdef CONFIG_STM32H7_WWDG + + /* RM0433 Rev 8 + * Reference manual - STM32H742, STM32H743/753 and STM32H750 Value line + * advanced Arm-based 32-bit MCUs + * https://www.st.com/resource/en/reference_manual/rm0433-stm32h742- + * stm32h743753-and-stm32h750-value-line-advanced-armbased-32bit-mcus- + * stmicroelectronics.pdf + * (Access date: 10-09-2025) + * Reset and Clock Control (RCC) -> RCC clock block functional + * description --> Kernel clock selection -> Watchdog clocks (page 365) + * "before enabling the WWDG1, the application must set the WW1RSC + * bit to 1. + * If the WW1RSC remains 0, when the WWDG1 is enabled, the behavior is + * not guaranteed" + */ + + uint32_t rcc_gcr = getreg32(STM32_RCC_GCR); + rcc_gcr |= RCC_GCR_WW1RSC; + putreg32(rcc_gcr, STM32_RCC_GCR); + regval |= RCC_APB3ENR_WWDG1EN; + +#endif + putreg32(regval, STM32_RCC_APB3ENR); /* Enable peripherals */ }