本帖最后由 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秒钟后再快速闪烁。
|