讨论:HAL库的HAL_Delay函数bug问题

2019-07-20 14:29发布

STM32的HAL库提供了一个HAL_Delay函数,使用Systick中断来实现,实现过程如下:

1.首先是一个Systick中断配置函数SysTick_Config,该函数实现的是Systick中断每隔ticks中断一次。。。。。
[mw_shl_code=c,true]__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);                                                     /* Function successful */
}[/mw_shl_code]

2.其次依次是:HAL_SYSTICK_Config函数和HAL_InitTick函数。。。。
HAL_InitTick函数调用之后,实际上就是配置每隔1ms中断一次,最终调用的是SysTick_Config函数进行配置。而这个函数是在HAL_Init函数中调用,在系统初始化之后会调用。


[mw_shl_code=c,true]uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
   return SysTick_Config(TicksNumb);
}

__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /*Configure the SysTick to have interrupt in 1ms time basis*/
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

  /*Configure the SysTick IRQ priority */
  HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority ,0);

  /* Return function status */
  return HAL_OK;
}[/mw_shl_code]

3.经过前面2步骤,开启了Systick定时器,每隔1ms中断一次。。。
而中断服务函数和相关逻辑函数是这样的:
[mw_shl_code=c,true]void SysTick_Handler(void)
{
  HAL_IncTick();
}

static __IO uint32_t uwTick;

__weak void HAL_IncTick(void)
{
  uwTick++;
}


__weak uint32_t HAL_GetTick(void)
{
  return uwTick;
}[/mw_shl_code]
定义了一个32位的全局变量uwTick,每次中断(1ms),变量uwTick增加1.。。。


4.最后HAL_Delay函数是这样的:
[mw_shl_code=c,true]__weak void HAL_Delay(__IO uint32_t Delay)
{
  uint32_t tickstart = 0;
  tickstart = HAL_GetTick();
  while((HAL_GetTick() - tickstart) < Delay)
  {
  }
}[/mw_shl_code]

通过HAL_GetTick();函数获取此时uwTick的值赋给tickstart,然后使用while循环不断调用HAL_GetTick() 函数获取当前uwTick值减掉tickstart,差值就是定时的ms数。。。


问题来了,如果32位的uwTick越界了怎么办? 32位uwTick的值,每1ms增加1,最大只有几十天就越界了。。。。
例如,如果还有1s就越界,如果此时此刻,我们调用HAL_Delay延时10s,那么肯定就乱套了。。。。
ST不应该会犯如此大的错误吧?不知道是我看少了,还是确实是一个Bug,大家讨论一下。。。。




友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
10条回答
xkwy
1楼-- · 2019-07-20 19:08
 精彩回答 2  元偷偷看……
openedvadmin
2楼-- · 2019-07-21 00:34
lvehe
3楼-- · 2019-07-21 01:16
本帖最后由 lvehe 于 2016-5-25 13:17 编辑

不是BUG,简单的写了个程序验证,模拟即将越界时的情况。打印情况如下:
0, 4294967291
1, 4294967292
2, 4294967293
3, 4294967294
4, 4294967295
5, 0
6, 1
7, 2
8, 3
9, 4
退出循环

[mw_shl_code=c,true]
uint32_t uwTick, tickstart, tmp;
void delay(uint32_t ms)
{
        tickstart = 4294967296 - 5;
        uwTick = tickstart;
        while ((tmp = (uwTick - tickstart)) < ms)
        {
                printf("%u, %u ", tmp, uwTick);
                uwTick++;
        }
}
int main(void)
{
        delay(10);
        getchar();
}[/mw_shl_code]



八度空间
4楼-- · 2019-07-21 05:50
 精彩回答 2  元偷偷看……
xkwy
5楼-- · 2019-07-21 06:07
 精彩回答 2  元偷偷看……
openedvadmin
6楼-- · 2019-07-21 09:28
xkwy 发表于 2016-5-25 05:51
这不是bug,程序没有问题

用减法是不会出错的,能回避这个问题。

YES,你回答得非常对。。。稍微深入研究一下代码就可以了。。。

没有问题。

一周热门 更多>