FreeRTOS分析三 — 任务的切换
我们带着三个问题开始了对 FreeRTOS 代码的探究。
1. FreeRTOS 是如何建立任务的呢?
2. FreeRTOS 是调度和切换任务的呢?
3. FreeRTOS 是如何保证实时性呢?
前两篇文章分别从代码的层面分析了 FreeRTOS 是如何建立任务以及建立的任务是怎么样被调用,“跑”起来的。
FreeRTOS从代码层面进行原理分析(1 任务的建立)
FreeRTOS从代码层面进行原理分析(2 任务的启动)
本篇继续上个博文中的提到的有官任务的切换问题,继续从代码的逻辑上来分析,FreeRTOS 是如何做到的。
FreeRTOS 中任务切换的细粒度
在 FreeRTOS 中称其为时间片(Time Slicing),如果两个 FreeRTOS 的任务具有相同的优先级那么实际执行起来的样子就像下面的图片一样,两个任务各自交替运行,每次每个任务可以一个时间片。
这个时间片的能力实际上就是来自 Systick 产生的中断。再上一篇博文中,咱们提到了使用 vPortSetupTimerInterrupt
函数配置 SysTick的过程。
这细粒度的具体时间就是由一行代码来控制的。
portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
每次时钟脉冲都会使得 reload 里面的值减 1,这样通过对时钟的设置和 reload 寄存器的初始值设置,就可以对 FreeRTOS 的时间片进行设置了。
这里没有很详细的讲解 Systick,因为那不是这篇博文的重点,而且有大把介绍 Systick 的文章有呢~
任务切换的触发
根据 STM32F10x_Startup.s 文件中对中断向量表的配置来看,当发生 SysTick 中断时 xPortSysTickHandler
函数将会被调用。
自己盗自己个图~ hhhh
在 xPortSysTickHandler
函数中的逻辑其实很简单。就是通过增加时间的形式,看看是不是真的有任务需要进行切换,如果切换的话就再触发另一个 PendSV(可挂起的系统服务) 中断 。
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
void xPortSysTickHandler( void )
{
portDISABLE_INTERRUPTS();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* A context switch is required. Context switching is performed in
* the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG &