HAL库中 systick 的前世和今生

hal hal库 systick
robe_zhang
发布时间: 2018-10-17
阅读: 7814

现在Hal 库越来越稳定成熟,加上配套软件cobemx 的成熟,hal 库使用频率越来越高,hal 库的用户也越来越多,有一部分新手用户发现systick 出现问题。

最近借用周末时间,分析了hal库代码,看看 systick HAL 库中是个什么角色。

 

也许你会问:systick RTOS 使用的心跳时钟,我不使用 RTOS,是不是就和 systick 没关系了?

答:不是。不使用 RTOS,只使用 HAL 库,HAL 库中照样会启用 systick,也就是说使用HAL库的同时,也在默默的使用 systick

 

这也就能理解为啥最近有小伙伴使用 hal 库时候,把 systick 当作普通定时器使用,用完后发现时间怎么错了,和时间有关的东西,不准了,原因就在这里,用的时候把systick修改,时间基准都变了,整个时间全都乱了。

 

上代码,看个仔细:本文使用的正点原子探索者开发板,芯片是stm32f407,使用官方最新的 stm32cobemx 软件生成工程代码,基于最新的版本的 HAL

源码中main函数之前和systick 没有关系,直接从 main 函数开始看:

1.png


重点也是这两个函数告诉你一切,首先看HAL_init():

(本文主要分析这两个函数,所以用12来标记这两个函数,如果是把函数展开,分析子函数,就标记1.1,或者 2.1,再有子函数就标志1.1.12.1.2,这样标记一看就知道分析的代码是整体代码的第几层,第几个函数的第几个子函数,对于读者来说更好从整体的角度看源码分析,不然看着看着绕迷了,不知道说的哪里,除了作者自己知道,读者迷茫,这就不好了。)

2.png



以上是函数1,其中和systick 相关的代码在子函数HAL_inittick 中,从名字和注释来看,这个函数是初始化systick时钟,心跳是 1ms,对这个函数展开如下:

3.png



以上是函数1.1,其中框框标识的函数是配置systick 的,有个参数 systemcore clock,看下图:

4.png



Systemcoreclock 参数初始化是个常数,为什么是16000000不是其他?换种写法,16百万,还不认识,再换种写法,16M,熟悉了点,再想想片上内部高速时钟也正好是16M,对了,也就是系统开机默认使用片上/内部高速时钟当作芯片的时钟源。

5.png



从时钟树来看,就是这样过来的,直接是16Mhz,因为此时PLL还么有启用。

现在知道芯片启动时候systick 时钟频率了,回过去分析:

6.png



继续看1.1函数,框框标识函数的参数systemcoreclock知道了,为啥是1000不是其他呢?

因为要1ms心跳,看注释1ms,所以除以100016k 心跳一次,1秒正好心跳1000次,1000就是这么来的,这个心跳在 RTOS 中是可以自己配置的宏,这里写死了,1000。这个函数参数分析完了,把 HAL_SYSTICK_config 函数展开:

7.png



以上是1.1.1函数,继续展开框框标识的函数

8.png



Systick  LOADVALCTRL 很熟悉了把,寄存器操作,给systick 初始化开终端,启用systick 的。所以到现在为止,知道了HAL库中其实是使用了 systick 时钟的,自己使用 hal 库的时候,不要再使用 systick 当作定时器自己又配置又启动又关闭,都会给 hal 库的时间基准破坏掉。


9.png


现在分析第二个函数 systemclcok_config(),把他展开:


10.png


以上是2.1函数的一部分,这个函数比较长,无关的不看,只看有关的,

HAL_RCC_Clockconfig 看名字是RCC 时钟配置,对这个感兴趣,展开:


11.png

12.png

13.png

14.png


以上是2.1.1函数,这个函数很长,基本是就是配置时钟,PLL等,看重点,框框标识的代码,systemcoreclock这个参数刚才是 16M 呀,现在对他赋值了,要发生变化了,变成什么呢?对赋值的函数展开:


15.png


以上是2.1.1.1函数,赋的值是HSE_VALUE 经过PLL 变换之后的值,从上面的公式算出来的,从 cobemx 时钟树角度看看:


16.png


以上是cobemx时钟树配置,这是笔者按照 stm32f407最大工作频率配置的时钟:

红色线条是时钟路径,数字是时钟在每个节点的频率。这个值更新之后是168M

代码返回去继续看


17.png


以上是2.1.1函数,刚刚systemcoreclock 更新完了,又一次调用HAL_inittick 函数,如上图框框标识的函数,这个函数前面看过了,再浏览一遍:继续展开:


18.png


以上是2.1.1.2函数,如上图框框标识的函数,配置systick时钟,此时配置的时钟频率还是同样的systemcoreclock参数,因为值刚刚更新过,所以此时systick 时钟已经不是开机时候的 16Mhz了,而是更新之后的 168Mhz

但是心跳呢,照样是 1000,因为分母是1000,并且是写死的,永远是1000,不管选择什么规格的晶振,怎么配置PLL,经过他设置之后的systick 心跳总是1000


总结:

1, 使用hal库的时候,systick 的使用问题:

hal 库使用了systick,用户自己的代码需要用时钟的话,最好选择其他的timer,如果一定要systick,可以短时间用,但是的时候要考虑和处理时间基准的问题,其实是个全局变量如下图框框标识,还有,用完了要恢复systick 装载值。


19.png


2, systick前世今生:

系统上电,先用片上/内部高速时钟运行,初始化 HAL 库,在HAL库中初始化 systick,并开启systick,然后重新配置 RCC,配置完更新时钟源并更新时钟源频率参数,然后使用新的频率再次初始化 systick

3, 系统使用的时钟顺序是:上电启动使用内部高速时钟16Mhz,初始化时候开启外部高速时钟启用外部高速时钟。之后一直使用外部高速时钟

4, Systick 使用时钟顺序:和系统使用的时钟顺序一样,虽然时钟源和频率有切换的动作,但是系统心跳都是1000,系统心跳没有变化。切换前后系统心跳一直保持1000

5, Hal 库使用的时间基准是uwTick 变量,这个变量基于systick 心跳,心跳一直是1000,所以hal库的时间一直是准确的,不受前后时钟源切换的影响。

6,其实进入低功耗时候,systick 需要suspend,工作的话,一进中断就立即唤醒了,保持不了低功耗模式。







原创作品,未经权利人授权禁止转载。详情见转载须知 举报文章

点赞 (2)
robe_zhang
评论(0)

登录后可评论,请 登录注册

相关文章推荐
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回

我要举报该内容理由

×
请输入您举报的理由(50字以内)