先看下stm32时钟树
虽然SYSCLK有多种时钟源,但一般不用我们管,ST提供的标准库函数已经配置了,选择的时钟源是外部8MHZ晶振经过PLL锁相环9倍频,即SYSCLK默认是72MHZ,然后过AHB分频器,对应寄存器默认为0,即1分频(不分频),即AHB默认也是72MHZ。
其余分支不管,看Cortex系统时钟(SYSTICK)和FCLK自由运行时钟(内核时钟SystemCoreClock)
Cortex系统时钟就是SysTick,即系统嘀嗒定时器,时钟源有两个,外部时钟源STCLK和内核时钟源FCLK。FreeRTOS默认是内核时钟源,就不用除以8,而FCLK又和HCLK同步,所以一般为72MHZ。如果选择外部时钟源,就要除以8,所以一般为72/8=9MHZ。
Fclk为供给CPU内核的时钟信号,我们所说的cpu主频为XXXXMHz,就是指的这个时钟信号,相应的,1/Fclk即为cpu时钟周期;
FCLK 为处理器的自由振荡的处理器时钟,用来采样中断和为调试模块计时。在处理器休眠时,通过FCLK 保证可以采样到中断和跟踪休眠事件。 Cortex-M3内核的“自由运行时钟(free running clock)”FCLK。“自由”表现在它不来自系统时钟HCLK,因此在系统时钟停止时FCLK 也继续运行。FCLK和HCLK 互相同步。FCLK 是一个自由振荡的HCLK。FCLK 和HCLK 应该互相平衡,保证进入Cortex-M3 时的延迟相同。
好了,看一下FreeRTOS里的配置
在FreeRTOSConfig.h里 ,configCPU_CLOCK_HZ是CPU主频,即FCLK,72MHZ。configTICK_RATE_HZ,是 抵达定时器的中断频率。
查看configCPU_CLOCK_HZ的引用,跳转到port.c如下,第一个是配置嘀嗒定时器的LOAD寄存器,第二个是配置CTRL寄存器。1UL 表示 无符号长整型 1。,在keil编译器里long是4字节,即32位。还有一个清除当前数字寄存器
下面是对应宏定义,刚好对应嘀嗒定时器寄存器地址,一个重装寄存器,一个配置寄存器。还有一个当前数字寄存器。这些地址宏定义在port.c里定义的。
先看第一个LOAD寄存器,转到configSYSTICK_CLOCK_HZ定义,发现configSYSTICK_CLOCK_HZ是configCPU_CLOCK_HZ的宏定义,即72MHZ。(72M/1000)-1UL=72K-1UL
再看CTRL寄存器,跳转到对应参数的定义,CLK_BIT对应CTRL的第2位,即时钟源选择,1UL<<2UL就是选择内核时钟FCLK作为嘀嗒定时器的时钟源,
INT_BIT和ENABLE_BIT分别对应寄存器第1位和第0位,这里都设为了0,分别表示SYSTICK计数器数到0产生异常请求、使能嘀嗒定时器。
再看当前数值寄存器,读取就会返回当前计数器的值,写它就清零,这个可能与获取当前嘀嗒数有关。
xTaskGetTickCount() :用于查询任务调度器从启动到现在时间计数器xTickCount的值。xTickCount是系统的时钟节拍值,并不是真实的时间值。每个滴答定时器中断xTickCount就会加一,中断周期取决于系统时钟节拍数
关于xTaskDelay和Delay,我还没研究,猜想xTaskDelay是当前任务进入阻塞状态,其他任务可以运行,Delay是延时,所有任务都无法执行。
xTaskDelay和xTaskDelayUtil
任务只能一次执行一个tick,说的是没有调用vTaskDelay或其他中断的时候,当下一个tick中断发生,就会发生一次调度,当然,调度后可以依旧是那个任务运行,调度其实就是对任务状态的链表进行操作。
下面是xTaskDelay函数,先将所有任务放入SusPend链表,然后将需要阻塞的任务放入Delay链表,再恢复任务。然后触发一次任务调度。
portYIELD触发一次任务调度,这个函数在空闲任务里也调用了,用于礼让