wwmbt 发表于 2020-2-1 00:25:00

STM32F1 HAL / LL Driver HAL_Delay() 的Bug

刚开始学习STM32,在使用STM32CubeIDE,以STM32F103为基础开学。安装了STM32Cube_FW_F1_V1.8.0,这两天把STM32F1 HAL的基础部分看完了,对于HAL_Delay()这个功能有一些疑虑:
该函数是基于Systick计数器实现的,把Systick计数器组态为每1ms自动重载一次,同时启动中断程序,给32位无符号全局参数uwTick累加1,也就是说uwTick相当于每1ms会自动+1,在HAL_Delay()函数中等待从调用它开始到目前uwTick增加的数,来实现以ms位单位的延时,具体函数如下:
__weak void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
    wait += (uint32_t)(uwTickFreq);
}
while ((HAL_GetTick() - tickstart) < wait)
{
}
}


但是程序里没有对uwTick做上溢回零后的处理和保护,那么当在上溢发生前启动延时,而且上溢前延时还没有达到,而发生了上溢则uwTick又从零来时累计了,那么该延时就不会完成,就可能会触发看门狗而其他重启了。
举例来说:无符号32位数最大值位4,294,967,296(不到一点50天),当uwTick累计到接近最大值的时候,比如说差1ms时启动了延时5ms,那么按照上面的函数就永远都无法跳出while循环了。
而一般来说,在功能测试期间,很少会让系统连续跑超过50天进行测试,而即使有超过50天的连续测试,如果没有在上面的极端情况发生,也很少有机会发现这个bug,但是这种可能性还是存在的,如果使用的延时功能够多,那么在系统投入实际运行后,这种问题一定会发生。
建议在delay函数里做一点修正:只要判断uwTick是否有上溢,在做相应的保护就可以了。
由于我是做工业控制系统的,所以对于系统连续运行性能要求比较高,所以在此提出一点疑虑和建议。当然了对于民用或者一些对于连续运行要求不高的场合,这种问题就无所谓了。

wwmbt 发表于 2020-2-11 04:48:08

今天特意测试了一下HAL_Delay,当uwTick发生上溢后从0开始计数后,由于是使用的无符号数,所以小数字-大数字,会变成一个更大的数,所以结果肯定大于等待值,系统不至于重启,只是延时时间会变得不准确而已。

sxying 发表于 2020-3-3 12:58:56

其实应该理解为符号数,这样完全不用考虑溢出问题,1-0xffffffff=1-(-1)=2;

zlfxia 发表于 2020-3-20 21:45:09

复习一下计算机组成原理就明白了
页: [1]
查看完整版本: STM32F1 HAL / LL Driver HAL_Delay() 的Bug