arch/arm/stm32h7: Fix and enhance WWDG (Window Watchdog) support
This patch addresses several issues and adds enhancements to the WWDG (Window Watchdog) implementation for the STM32H7 platform. The changes include: - Extend the definitions of WWDG_CFR_PCLK1 macros to support dividers up to 128, and update the stm32_settimeout() function to consider this extended range. - Fix the "elapsed" calculations in the stm32_getstatus() function to ensure correct time remaining calculations. - Clear the EWIF (Early Wakeup Interrupt Flag) bit in the stm32_start() function, as this bit might be set by hardware before the watchdog is actually started. - Initialize the WWDG clock in the RCC_APB3ENR register and set the RCC_GCR_WW1RSC bit as per the STM32 reference manual to ensure proper behavior when enabling the WWDG1. Signed-off-by: Szymon Magrian <szymon.magrian@hexagon.com>
This commit is contained in:
parent
3af0ab64bb
commit
94ad260843
3 changed files with 45 additions and 13 deletions
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue