硬汉嵌入式论坛

 找回密码
 立即注册
查看: 653|回复: 23
收起左侧

[emWin] 发现个systick_delay时间不准的问题

  [复制链接]

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
发表于 2023-10-16 09:00:42 | 显示全部楼层 |阅读模式
在STM32F103上,使用systick进行us/ms的精准延时,发现不准了!!!

systick_delay_ms(200)的情况下,有时候是1s,有时候是600ms。这是怎么回事啊。
如果是晶振的问题的话,串口打印那些都是正常的呢。
最奇怪的是,我如果一直周期调用systick_delay_ms(200)的话,这个函数的延时时间还是不固定的,有时候是1000ms,有时候是600ms,还有800ms的。
这代码原来一直用着的呀,怎么突然就有问题了

void systick_delay_init(void)
{
        static u32 dword_20000000 = 72000000;
       
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
  f_clk_us = dword_20000000 / 8000000;
  f_clk_ms = 1000 * f_clk_us;
}
void systick_delay_ms(s32 ms)
{
  SysTick->LOAD = f_clk_ms * ms;
  SysTick->VAL = 0;
  SysTick->CTRL |= 1;
  while(SysTick->CTRL & 1 && !(SysTick->CTRL & 0x10000));
  SysTick->CTRL &= 0xFFFFFFFE;
  SysTick->VAL = 0;
}


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
发表于 2023-10-16 09:06:00 | 显示全部楼层
推荐用DWT.

DWT实现一个精确微秒延迟的参考例程
https://www.armbbs.cn/forum.php? ... 9128&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

5

主题

61

回帖

76

积分

初级会员

积分
76
发表于 2023-10-16 09:14:21 | 显示全部楼层
跑的裸机还是实时系统?实时系统的话可能函数被重入了吧。
回复

使用道具 举报

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
 楼主| 发表于 2023-10-16 09:43:29 | 显示全部楼层
Blake 发表于 2023-10-16 09:14
跑的裸机还是实时系统?实时系统的话可能函数被重入了吧。

裸机了,中断都全关了
回复

使用道具 举报

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
 楼主| 发表于 2023-10-16 09:49:11 | 显示全部楼层
eric2013 发表于 2023-10-16 09:06
推荐用DWT.

DWT实现一个精确微秒延迟的参考例程

不是精度的问题吧,是软件哪里有Bug吧
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
发表于 2023-10-16 09:56:51 | 显示全部楼层
jplzl10000 发表于 2023-10-16 09:49
不是精度的问题吧,是软件哪里有Bug吧

是的,我没有针对你的问题回复,我是推荐换个方案,简单易用好使。
回复

使用道具 举报

19

主题

234

回帖

291

积分

高级会员

积分
291
发表于 2023-10-16 10:05:59 | 显示全部楼层
测时间这么测的,通过串口助手的时间戳吗,可能不准。
应该表现在LED或者引脚的状态翻转上,用示波器打一下
回复

使用道具 举报

22

主题

66

回帖

132

积分

初级会员

积分
132
发表于 2023-10-16 11:19:22 | 显示全部楼层
你这明显数据溢出了  滴答定时器是24位,计算范围是0-的 2 的24次方
回复

使用道具 举报

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
 楼主| 发表于 2023-10-16 14:08:44 | 显示全部楼层
tovinz 发表于 2023-10-16 10:05
测时间这么测的,通过串口助手的时间戳吗,可能不准。
应该表现在LED或者引脚的状态翻转上,用示波器打一 ...

就是有个蜂史鸣器,上电会响一下,开始听的时间很长,然后测了下IO的电平才知道这个时间长度不对了。
systick使用的是HCLK的8分频了,LOAD值200*9000=0x1B7740 怎么可能会超
回复

使用道具 举报

19

主题

371

回帖

428

积分

高级会员

积分
428
发表于 2023-10-16 15:19:32 | 显示全部楼层
一般使用毫秒级延迟:
1. systick设置为1毫秒
2. 应用层:HAL_Delay毫秒级别延时
3. 或者应用层:用HAL_GetTick自定义延时
回复

使用道具 举报

3

主题

49

回帖

58

积分

初级会员

积分
58
发表于 2023-10-16 15:38:48 | 显示全部楼层
tovinz 发表于 2023-10-16 10:05
测时间这么测的,通过串口助手的时间戳吗,可能不准。
应该表现在LED或者引脚的状态翻转上,用示波器打一 ...

我在使用ESP32输出时,sscom串口助手的时间戳还是挺准的!
回复

使用道具 举报

3

主题

120

回帖

129

积分

初级会员

积分
129
发表于 2023-10-16 15:43:21 | 显示全部楼层
确定没开其他中断吗,看了代码滴答定时器中断确实没开,如果开了中断,看是不是中断里用了比较耗时的函数。还有一种可能是重启了,hardfault或者看门狗咬死了,时间不定可能是重启了好几次,代码初始化亮灯,进主循环把灯关掉,排除一下是不是重启的原因。
回复

使用道具 举报

19

主题

234

回帖

291

积分

高级会员

积分
291
发表于 2023-10-16 15:58:11 | 显示全部楼层
跟着硬汉学 发表于 2023-10-16 15:38
我在使用ESP32输出时,sscom串口助手的时间戳还是挺准的!

我用的 UartAssist,不过这种情况也不是经常出现。
回复

使用道具 举报

19

主题

371

回帖

428

积分

高级会员

积分
428
发表于 2023-10-16 16:17:41 | 显示全部楼层
不会吧systick中断也关了吧
回复

使用道具 举报

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
 楼主| 发表于 2023-10-17 13:54:14 | 显示全部楼层
h_007 发表于 2023-10-16 16:17
不会吧systick中断也关了吧

这个是死循环判断sysytick计数结束的,不是sysytick中断哦
回复

使用道具 举报

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
 楼主| 发表于 2023-10-17 14:52:15 | 显示全部楼层
eric2013 发表于 2023-10-16 09:56
是的,我没有针对你的问题回复,我是推荐换个方案,简单易用好使。

把这个延时时间到的判断换一下就正常了
while(!(SysTick->CTRL & 0x10000) && (SysTick->CTRL & 1));//while((SysTick->CTRL & 1) && !(SysTick->CTRL & 0x10000));
这是啥原因?
(SysTick->CTRL & 1) 这个判断不要也是行的。感觉上是触发了某种芯片硬件上问题
回复

使用道具 举报

3

主题

120

回帖

129

积分

初级会员

积分
129
发表于 2023-10-17 15:20:43 | 显示全部楼层
SysTick->CTRL & 1这个是开启systick,拿来判断不是一直为真吗。可能重复开启就出问题了,改成只开一次就行。之前可能把这个优化掉了所以没有触发bug
在arm官网上找到systick寄存器说明

https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/system-timer--systick/systick-control-and-status-register
When ENABLE is set to 1, the counter loads the RELOAD value from the SYST_RVR register and then counts down. On reaching 0, it sets the COUNTFLAG to 1 and optionally asserts the SysTick depending on the value of TICKINT. It then loads the RELOAD value again, and begins counting.




回复

使用道具 举报

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
 楼主| 发表于 2023-10-17 17:32:43 | 显示全部楼层
skyshine 发表于 2023-10-17 15:20
SysTick->CTRL & 1这个是开启systick,拿来判断不是一直为真吗。可能重复开启就出问题了,改成只开一次就行 ...

这个不是重复开启,是读取这个使能位的状态。可能当初写这个代码的时候只是为了保险起见。
很多情况下也没啥问题。最近用在103,105的几个芯片上都有这样的问题。时间就是几倍的变长了
回复

使用道具 举报

19

主题

371

回帖

428

积分

高级会员

积分
428
发表于 2023-10-17 17:57:37 | 显示全部楼层
会不会是优化的问题?
回复

使用道具 举报

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
 楼主| 发表于 2023-10-18 08:33:24 | 显示全部楼层
h_007 发表于 2023-10-17 17:57
会不会是优化的问题?

都没开优化。如果有优化的话,那应该一直死循环了。
调换一下判断的顺序就可以了。
很是奇怪
回复

使用道具 举报

75

主题

684

回帖

909

积分

金牌会员

积分
909
发表于 2023-10-18 09:34:14 | 显示全部楼层
jplzl10000 发表于 2023-10-18 08:33
都没开优化。如果有优化的话,那应该一直死循环了。
调换一下判断的顺序就可以了。
很是奇怪

顺序应该没关系的,你试试用一个变量读取寄存器数据再判断,不要两次读取寄存器数据来做判断试试。可能存在同时读写冲突了。
[C] 纯文本查看 复制代码
while(1)
{
    uint32_t ctrl_reg = SysTick->CTRL;
    if ((ctrl_reg & 1) && (!(ctrl_reg & 0x10000)))
    {
        break;
    }
}
回复

使用道具 举报

262

主题

578

回帖

1364

积分

至尊会员

积分
1364
 楼主| 发表于 2023-10-19 08:53:14 | 显示全部楼层
庄永 发表于 2023-10-18 09:34
顺序应该没关系的,你试试用一个变量读取寄存器数据再判断,不要两次读取寄存器数据来做判断试试。可能存 ...

应该是这个原因。看汇编代码,是 读了2次 SysTick.CTRL 这个寄存器。
改成读一次的话就没问题了。
回复

使用道具 举报

19

主题

371

回帖

428

积分

高级会员

积分
428
发表于 2023-10-19 10:39:21 | 显示全部楼层
学习了
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106678
QQ
发表于 2023-10-19 12:03:32 | 显示全部楼层
庄永 发表于 2023-10-18 09:34
顺序应该没关系的,你试试用一个变量读取寄存器数据再判断,不要两次读取寄存器数据来做判断试试。可能存 ...

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-29 09:58 , Processed in 0.372462 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表