stm32l4系列启用看门狗后,调用HAL_IWDG_Refreh()就复位

发布于:2025-07-06 ⋅ 阅读:(17) ⋅ 点赞:(0)

问题描述:在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. 向下计数器在窗口外被重置计数值(在窗口外喂狗)

图1 数据手册所描述IWDG的主要特点

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

图2 IWDG之Window功能效果图

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

图3 窗口选项说明

在我手动初始化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 writing
  0x5555 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 window
  register */
  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 writing
    windows 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


网站公告

今日签到

点亮在社区的每一天
去签到