FreeRTOS按照教程移植好之后就可以使用了。 需要注意的是从官网下载的针对keil环境下STM32F103的FreeRTOS文件,使用systick时钟作为rtos的时钟,而这个systick的时钟源会被默认选择为STM32的内核时钟,而不能选择外部时钟。原因就是当rtos启动时(vTaskStartScheduler();这个函数开始被调用的时候),systick就会被按默认的参数配置好,而不是需要用户自己去配置,这些参数在FreeRTOSconfig.h文件里面
如图,第 88,89,90行,这几行的宏定义决定了systick的初始化参数,其中 configCPU_CLOCK_HZ是cpu时钟频率,也是systic的时钟源,如果不打算自己从头到尾来配置systick,一定不要修改这个参数。configTICK_RATE_HZ 是systick中断的频率,上图里面是1000HZ。而第 88行是我自己加的,它的原型隐藏在port.c文件里面
如果你不去额外定义它一下,它就会被定义成 0,这个参数在什么地方用到了呢?
同样是 port.c文件,有上面这么一段代码,如果configOVERRIDE_DEFAULT_TICK_CONFIGURATION 被定义成0,就去定义一个名为vPortSetupTimerInterrupt() 的函数,这个函数的作用是初始化systick定时器。注意这个函数里面的最后 2行,首先它的 reload值是直接根据stm32的内核时钟去计算的。另外,在这个函数里面的最后一行, portNVIC_SYSTICK_CTRL_REG与stm32库里面的SysTick->CTRL是一个意思,表示的systick的CTRL控制寄存器。CM3 参考手册里面,描述里这个CTRL寄存器的各个位的作用
可以看出,最后一行的目的有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 )
|