本帖最后由 slotg 于 2020-1-1 22:49 编辑
学习笔记+适用于STM32F0系列的STM32Cube固件例程
学习笔记+STM32F0系列的STM32Cube固件例程 DMA
学习笔记+STM32F0系列的STM32Cube固件例程 IWDG
STM32F0 的另一个看门狗就是 WWDG,也就是 Window watchdog 窗口看门狗,与 IWDG 不同的地方是 IWDG 使用内部 LSI 做为时钟驱动,而 WWDG 是使用 PCLK 时钟驱动。 WWDG 窗口看门狗的计数器下限值是固定在 0x40,上限值是由使用者设定,低于下限值的时间喂狗不行,超过上限值的时间喂狗也不行。
WWDG_Example
在固件库 Projects\STM32F030R8-Nucleo\Examples\WWDG\WWDG_Example 里面的这一个例程:
程序的基本架构跟前面的 IWDG 例程类似,main() 开始的地方也是有一个判断语句判断程序的复位原因是否是因为 WWDG 所产生的?是的话点亮 LD2 4秒钟。
- /*##-1- Check if the system has resumed from WWDG reset ####################*/
- if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET)
- {
- /* WWDGRST flag set: Turn LED2 on */
- BSP_LED_On(LED2);
- /* Insert 4s delay */
- HAL_Delay(4000);
- /* Prior to clear WWDGRST flag: Turn LED2 off */
- BSP_LED_Off(LED2);
- }
WWDG 的结构如下:
WWDG 的设定:
- /*##-2- Init & Start WWDG peripheral ######################################*/
- /* WWDG clock counter = (PCLK1 (48MHz)/4096)/8) = 1464.8 Hz (~683 us)
- WWDG Window value = 80 means that the WWDG counter should be refreshed only
- when the counter is below 80 (and greater than 64 (63+1)) otherwise a reset will
- be generated.
- WWDG Counter value = 127, WWDG timeout = ~683 us * 64 = 43.7 ms
- In this case the refresh window is comprised between : ~683 * (127-80) = 32.1 ms and ~683 * 64 = 43.7 ms
- */
- WwdgHandle.Instance = WWDG;
- WwdgHandle.Init.Prescaler = WWDG_PRESCALER_8;
- WwdgHandle.Init.Window = 0x50;
- WwdgHandle.Init.Counter = 0x7F;
- WwdgHandle.Init.EWIMode = WWDG_EWI_DISABLE;
PCLK 的频率设定在 48MHz,经过一个 4096 除频之后再进入 WWDG 的预除器,程序中设定预除器为 8,所以 WWDG 计数器的输入频率为:
48MHz / 4096 = 11718.75Hz
11718.75Hz / 8 = 1464.84Hz --> 约 683us
WWDG 从 0x7F 开始往下计数,计数到 0x50 时进入 WWDG 可喂狗的下限值,这时间为:
127 - 80 = 47
47 x 683us = 32101us --> 约 32.1ms
WWDG 窗口的上限值是 0x40,这是可喂狗时间的最长时间,这时间为:
127 - 64 = 63
(63+1) x 683us = 43712us --> 约 43.7ms
也就是喂狗时间必须是在 32.1ms ~ 43.7ms 之间。
例程中设定了喂狗周期的 delay 变数:
- /* calculate delay to enter window. Add 1ms to secure round number to upper number */
- delay = TimeoutCalculation((WwdgHandle.Init.Counter-WwdgHandle.Init.Window) + 1) + 1;
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] Timeout calculation function.
- * This function calculates any timeout related to
- * WWDG with given prescaler and system clock.
- * @param timevalue: period in term of WWDG counter cycle.
- * @retval None
- */
- static uint32_t TimeoutCalculation(uint32_t timevalue)
- {
- uint32_t timeoutvalue = 0;
- uint32_t pclk1 = 0;
- uint32_t wdgtb = 0;
- /* considering APB divider is still 1, use HCLK value */
- pclk1 = HAL_RCC_GetPCLK1Freq();
- /* get prescaler */
- wdgtb = (1 << ((WwdgHandle.Init.Prescaler) >> 7)); /* 2^WDGTB[1:0] */
- /* calculate timeout */
- timeoutvalue = ((4096 * wdgtb * timevalue) / (pclk1 / 1000));
- return timeoutvalue;
- }
例程设定了喂狗时间为:
32.1ms + 1ms = 33.1ms
while(1) 回圈:
- /* Infinite loop */
- while (1)
- {
- /* Toggle LED2 */
- BSP_LED_Toggle(LED2);
- /* Insert calculated delay */
- HAL_Delay(delay);
- if (HAL_WWDG_Refresh(&WwdgHandle) != HAL_OK)
- {
- Error_Handler();
- }
- }
因此程序运行时可以看到板载 LD2 快速闪烁。当我们按下使用者键时会产生按键中断,中断函数里对地址 0xA0003000 写入数据 0xFF,由于这个地址的写入动作是无效的因此会产生一个 Hardfault 错误事件。
- void EXTI4_15_IRQHandler(void)
- {
- /* As the following address is invalid (not mapped), a Hardfault exception
- will be generated with an infinite loop and when the WWDG counter falls to 63
- the WWDG reset occurs */
- *(__IO uint32_t *) 0xA0003000 = 0xFF;
- }
在 Hardfault 响应函数中我们放了一个无限回圈让程序回不去。
- void HardFault_Handler(void)
- {
- /* Go to infinite loop when Hard Fault exception occurs */
- while (1)
- {
- }
- }
由于程序回不去了因此主回圈就没有办法喂狗,所以 WWDG 会复位 MCU,重启后 LD2 点亮 4秒钟后再快速闪烁。
|