FreeRTOS任务的切换最终都是在PendSV中断服务函数(汇编代码实现的)中完成的,发生任务切换的场合有两种情况:
1) 执行一个系统调用
2) 系统滴答定时器(sysTick)中断
所谓的执行系统调用就是执行了taskYIELD()函数或者调用了taskYIELD的其他API函数;taskYIELD()函数定义在task.h中:
#define taskYIELD() portYIELD()
函数portELD定义在portmacro.h中:
#define portYIELD()
{
portNVIC_INT_CTRL_REG=portNVIC_PENDSVSET_BIT;//步骤1
__dsb(portSY_FULL_READ_WRITE);
__isb(portSY_FULL_READ_WRITE);
}
步骤1表示通过向中断控制和状态寄存器ICSR的bit28写入1挂起PendSV来启动PendSV中断。这样就可以在PendSV中断服务函数中进行任务切换了。
中断级的任务切换函数为portYIELD_FROM_ISR()也是通过调用portYIELD来完成任务切换的。
第二个能产生任务切换的就是滴答定时器(SysTick)中断服务函数:
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
{
xPortSysTickHandler();
}
}
xPortSysTickHandler()的主要功能是向中断控制和状态寄存器ICSR的bit28写入1挂起PendSV来启动PendSV中断。这样就可以在PendSV中断服务函数中进行任务切换了。