Free RTOS task switch#

1. 调度器#

任务调度器总是使就绪态的最高优先级的任务得到CPU运行权。

当有多个任务的优先级相同且是最高的优先级时,进行时间片轮转调度。

2. 任务切换的方式#

FreeRTOS的任务切换是在 PendSV 中断中完成的,为什么要在 PendSV 中完成呢?

因为PendSV中断不是精确的,可以在高优先的中断中设置PendSV中断,并且PendSV中断不会立即执行,PendSV中断会等到高优先级的中断执行完之后再执行。

具体内容请参阅:《The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors》第10.3节

  • 通过调用API函数触发 PendSV 中断

/* Scheduler utilities. */
#define portYIELD()                                                             \
{                                                                               \
    /* Set a PendSV to request a context switch. */                             \
    portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;                             \
                                                                                \
    /* Barriers are normally not required but do ensure the code is completely  \
    within the specified behaviour for the architecture. */                     \
    __asm volatile( "dsb" ::: "memory" );                                       \
    __asm volatile( "isb" );                                                    \
}

#define portYIELD_WITHIN_API portYIELD

#define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()

#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )

3. 任务切换的时机#

  • Systick中断

  • 间接或者直接调用portYIELD()触发PendSV中断

会调用portYIELD()的函数:

osDelay();
osSingalSet();
...