stm32l4系列启用看门狗后,调用HAL_IWDG_Refreh()就复位
问题描述:在stm32L431cct6芯片上想启用看门狗,但配置完后发现一调用喂狗函数,就会导致单片机复位,调用一次复位一次。
问题背景:在原有HAL库工程上添加看门狗时,采用手动配置来初始化看门狗,并没有使用CubeMX生成的看门狗初始化函数,手动配置时缺少一个参数的配置,导致问题出现。
1. 手动配置代码如下
void MX_IWDG_Init(void)
{hiwdg.Instance = IWDG;hiwdg.Init.Prescaler = IWDG_PRESCALER_64;hiwdg.Init.Reload = 4095;if (HAL_IWDG_Init(&hiwdg) != HAL_OK){Error_Handler();}
}
2. CubeMX生成的代码如下
static void MX_IWDG_Init(void)
{/* USER CODE END IWDG_Init 1 */hiwdg.Instance = IWDG;hiwdg.Init.Prescaler = IWDG_PRESCALER_64;hiwdg.Init.Window = 4095; //CubeMX多配置的参数hiwdg.Init.Reload = 4095;if (HAL_IWDG_Init(&hiwdg) != HAL_OK){Error_Handler();}
}
可以看出区别就是CubeMX多配置了hiwdg.Init.Window,那么这是什么东西呢?
在回答这个问题之前,我们可以先看看数据手册(图1)如何描述L4系列的IWDG功能,主要注意红框内的内容,复位条件有两点:
1. 向下计数器的计数值到达0及0以下(看门狗计时溢出)
2. 向下计数器在窗口外被重置计数值(在窗口外喂狗)

根据第二点,我们就可以推断出`hiwdg.Init.Window`该参数是用来限制喂狗时机的,效果如下图:

数据手册里的说明更加详细:

在我手动初始化IWDG_WINR寄存器之后,喂狗便不再发生复位。
问题已解决,但仍有一点无法解释的地方,IWDG_WINR寄存器的复位值默认是4095(如上图3所示),理论上来讲即使我不手动配置它,喂狗也不会导致单片机复位,正如数据手册中所描述的,如果不更新该寄存器,那么window option是被禁用的。那么有没有可能是因为该值被更新了呢?
我们接着往下阅读参考手册,发现有禁用状态下配置IWDG的流程如下:
为了一探究竟,这里查看一下HAL库是如何初始化IWDG的,与上述描述有何异同
/*** @brief Initialize the IWDG according to the specified parameters in the* IWDG_InitTypeDef and start watchdog. Before exiting function,* watchdog is refreshed in order to have correct time base.* @param hiwdg pointer to a IWDG_HandleTypeDef structure that contains* the configuration information for the specified IWDG module.* @retval HAL status*/
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg)
{uint32_t tickstart;/* Check the IWDG handle allocation */if (hiwdg == NULL){return HAL_ERROR;}/* Check the parameters */assert_param(IS_IWDG_ALL_INSTANCE(hiwdg->Instance));assert_param(IS_IWDG_PRESCALER(hiwdg->Init.Prescaler));assert_param(IS_IWDG_RELOAD(hiwdg->Init.Reload));assert_param(IS_IWDG_WINDOW(hiwdg->Init.Window));/* Enable IWDG. LSI is turned on automatically */__HAL_IWDG_START(hiwdg);/* Enable write access to IWDG_PR, IWDG_RLR and IWDG_WINR registers by writing0x5555 in KR */IWDG_ENABLE_WRITE_ACCESS(hiwdg);/* Write to IWDG registers the Prescaler & Reload values to work with */hiwdg->Instance->PR = hiwdg->Init.Prescaler;hiwdg->Instance->RLR = hiwdg->Init.Reload;/* Check pending flag, if previous update not done, return timeout */tickstart = HAL_GetTick();/* Wait for register to be updated */while (hiwdg->Instance->SR != 0x00u){if ((HAL_GetTick() - tickstart) > HAL_IWDG_DEFAULT_TIMEOUT){return HAL_TIMEOUT;}}/* If window parameter is different than current value, modify windowregister */if (hiwdg->Instance->WINR != hiwdg->Init.Window){/* Write to IWDG WINR the IWDG_Window value to compare with. In any case,even if window feature is disabled, Watchdog will be reloaded by writingwindows register */hiwdg->Instance->WINR = hiwdg->Init.Window;}else{/* Reload IWDG counter with value defined in the reload register */__HAL_IWDG_RELOAD_COUNTER(hiwdg);}/* Return function status */return HAL_OK;
}
可以看出在初始化过程中,第6点有所不同(上述代码第50行)。HAL库在初始化时,先判断了下寄存器中的WINR值与句柄中Window的值,如果不同,那么会将句柄中的值赋值给寄存器。问题便出现在这里。
问题的根本原因:我们在定义iwdg句柄时一般为全局变量,导致hiwdg->Init.Window值为0,而寄存器中的值默认复位时为4065,由于两者不相等,所以寄存器中的值被赋值为0,再根据注释中所描述,写入window寄存器后会触发喂狗,而喂狗的时机一定是在窗口之外(窗口为0),进而导致单片机不断复位。
至此问题已彻底找到。
解决方案:在初始化有IWDG_WINR寄存器的单片机时应手动初始化hiwdg->Init.Window为4095
参考资料链接:IWDG部分在第33章节STM32L41xxx/42xxx/43xxx/44xxx/45xxx/46xxx advanced Arm®-based 32-bit MCUs - Reference manualhttps://www.st.com/resource/en/reference_manual/rm0394-stm32l41xxx42xxx43xxx44xxx45xxx46xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf