OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 14083|回复: 5

使用FreeRTOS时Systick时钟的配置

[复制链接]

15

主题

184

帖子

0

精华

高级会员

Rank: 4

积分
647
金钱
647
注册时间
2014-4-29
在线时间
299 小时
发表于 2016-6-20 15:53:40 | 显示全部楼层 |阅读模式
FreeRTOS按照教程移植好之后就可以使用了。
需要注意的是从官网下载的针对keil环境下STM32F103FreeRTOS文件,使用systick时钟作为rtos的时钟,而这个systick的时钟源会被默认选择为STM32的内核时钟,而不能选择外部时钟。原因就是当rtos启动时(vTaskStartScheduler();这个函数开始被调用的时候),systick就会被按默认的参数配置好,而不是需要用户自己去配置,这些参数在FreeRTOSconfig.h文件里面

图片1.png
如图,第88,89,90行,这几行的宏定义决定了systick的初始化参数,其中configCPU_CLOCK_HZcpu时钟频率,也是systic的时钟源,如果不打算自己从头到尾来配置systick,一定不要修改这个参数。configTICK_RATE_HZsystick中断的频率,上图里面是1000HZ而第88行是我自己加的,它的原型隐藏在port.c文件里面 图片2.png
如果你不去额外定义它一下,它就会被定义成0,这个参数在什么地方用到了呢?
图片3.png

同样是port.c文件,有上面这么一段代码,如果configOVERRIDE_DEFAULT_TICK_CONFIGURATION 被定义成0,就去定义一个名为vPortSetupTimerInterrupt()的函数,这个函数的作用是初始化systick定时器。注意这个函数里面的最后2行,首先它的reload值是直接根据stm32的内核时钟去计算的。另外,在这个函数里面的最后一行,portNVIC_SYSTICK_CTRL_REGstm32库里面的SysTick->CTRL是一个意思,表示的systickCTRL控制寄存器。CM3参考手册里面,描述里这个CTRL寄存器的各个位的作用 图片4.png

可以看出,最后一行的目的有3个:选择时钟源为内核时钟;选择计数值到达0时会引起中断;开启计数器的连拍模式(使能计数器) 现在终于可以看出来configOVERRIDE_DEFAULT_TICK_CONFIGURATION到底是干什么的了:如果用户没有把这个东西定义成一个非0的量,它就会被默认定义为0,这样的结果就是默认把systick的时钟源设置为stm32的内核时钟。 一种很可能的误会就是用户在启动RTOS之前已经配置好了systick,时钟源设置为系统时钟的1/8,并把它用于软件延时。结果并没有发现FreeRTOS启动的时候把systick又重新配置了一遍,导致延时不准了。然后用户去freeRTOS留给用户的配置文件里去找,发现了这里有个东西还没改呢#define configCPU_CLOCK_HZ                        ( ( unsigned long ) 72000000 )就自作聪明的改成这样(我自己开始就是这么干的)#define configCPU_CLOCK_HZ                        ( ( unsigned long ) 72000000/8 )那就踩到坑了。如果用户使用不依赖中断的查询式的软件延时,还是会出现延时不准的后果。因为FreeRTOS启动的时候还是帮你把systick的时钟源改成了内核时钟(72M),而不是预期的9M,所以计数器的频率是72M,但是计算reload值是用的9M时钟源,导致中断的周期却是正确的。 正确的配置并使用systick的方案有2个:一.就使用内核时钟作为时钟源。延时什么的也都按照这个计算。二.如果确实想使用1/8的时钟源,就要这样配置1.FreeRTOSconfig.h文件里面加上这个宏定义,定义成非0的数#define configOVERRIDE_DEFAULT_TICK_CONFIGURATION    1 [size=10.5000pt]2.自己在需要的地方定义好systick的初始化函数,并把它命名为   void vPortSetupTimerInterrupt( void )这样会带来一个问题就是tickless idle的功能不能用了,也希望有前辈指点一下这个问题怎么解决 3.至于这个宏定义就不需要改动了因为它已经不会被使用了#define configCPU_CLOCK_HZ                        ( ( unsigned long ) 72000000 )
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
111
金钱
111
注册时间
2013-5-30
在线时间
21 小时
发表于 2020-6-3 19:53:42 | 显示全部楼层
原子的例程 delay_init函数会先初始并配置滴答时钟,但系统运行后被重置了,貌似delay_init中滴答配置是多余的,不过在系统未运行前,如果应用有us级的延时,反而delay函数中还必须配滴答时钟。
所以,如果系统运行前无us级delay,delay_init函数只初始化fac_us ,fac_ms 即可,反之则按原子例程一开始就在delay_init函数中先配置一次滴答定时器,然后系统运行开始(之前的即使有延时也早已执行完毕了),系统自动重置一下滴答定时器后开始执行第一个任务了,这样也没啥影响。
当然楼主说的时基的问题也要注意一下,如果要分频的话,就修改vPortSetupTimerInterrupt函数,把时钟源配置0,就是8分频,此外为了计算LOAD_REG的值时正确的将configSYSTICK_CLOCK_HZ/8,这样时钟源是系统8分频,重载值时按照分频后计算的数值,那应该就没问题了。多补充一点:如果用HAL库还得用两套时基才行,不然HAL库自带延时也会出问题,再次不细说了,论坛里有帖子讲过这个。
回复 支持 1 反对 0

使用道具 举报

2

主题

14

帖子

0

精华

初级会员

Rank: 2

积分
170
金钱
170
注册时间
2013-11-28
在线时间
31 小时
发表于 2016-6-21 13:44:40 | 显示全部楼层
不错!
回复 支持 反对

使用道具 举报

12

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
281
金钱
281
注册时间
2013-1-5
在线时间
22 小时
发表于 2016-9-7 21:57:53 | 显示全部楼层
多谢楼主整理分享
天道酬勤
回复 支持 反对

使用道具 举报

1

主题

5

帖子

0

精华

新手入门

积分
16
金钱
16
注册时间
2019-6-16
在线时间
4 小时
发表于 2019-7-3 00:03:42 | 显示全部楼层
将configOVERRIDE_DEFAULT_TICK_CONFIGURATION define 成1 会编译出错的, 如果想另其失效,在port.c中将vPortSetupTimerInterrupt(); 执行的地方注释掉就好了
回复 支持 反对

使用道具 举报

1

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
101
金钱
101
注册时间
2019-7-25
在线时间
33 小时
发表于 2019-11-9 14:07:37 | 显示全部楼层
好帖子
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 21:58

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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