1. 任务切换相关API函数
函数 | 描述 |
---|---|
xPortPendSVHandler() | PendSV中断服务函数,其实函数原型为PendSV_Handler() |
vTaskSwitchContext() | 检查任务堆栈使用是否溢出,和查找下一个优先级高的任务,如果使能运行时间统计功能,会计算任务运行时间 |
2. 任务切换的基本知识
在FreeRTOS任务管理中,最主要的目的就是找到就绪态优先级最高的任务,然后执行任务切换,从而能保持优先级最高的任务一直占用CPU资源。为了达到最优性能,任务切换部分程序使用汇编代码编写。
FreeRTOS有两种方法触发任务切换:
- 系统节拍时钟中断(SysTick定时器)。切换过程参考《FreeRTOS原理剖析:系统节拍时钟分析》
- 执行系统调用代码。普通任务使用taskYIELD()强制任务切换;中断服务程序使用portYIELD_FROM_ISR()强制任务切换;在应用程序里也可以通过设置xYieldPending的值来通知调度器进行任务切换。
其中:
// 对于普通任务时
#define taskYIELD() portYIELD()
#define portYIELD_WITHIN_API portYIELD
// 对于中断服务程序时
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
可以看出,最终执行的代码段为:
#define portYIELD() \
{ \
/* \
* 通过向中断控制及状态寄存器ICSR的第28位写入1,触发PendSV中断 \
* 地址为0xE000 ED04 \
*/ \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
\
/* dsb和isb 完成数据同步隔离和指令同步隔离 \
* 保证之前存储器访问操作和指令都执行完 \
*/ \
__dsb( portSY_FULL_READ_WRITE ); \
__isb( portSY_FULL_READ_WRITE ); \
}
通过向中断控制及状态寄存器ICSR(地址:0xE000 ED04)的第28位写入1,触发PendSV中断,从而执行任务切换