Day 3:任务调度
PendSV异常:
PendSV异常全称为可挂起的系统调用,其优先级可通过编程设置,在FreeRTOS中,一般将其设置为最低优先级。FreeRTOS系统的任务切换都是在PendSV中断服务函数中完成的。
SVC:
全称系统服务调用,用于产生系统函数的调用请求。
任务切换场合:
认识这两个概念以后熟悉一下,FreeRTOS在什么情况下会进行任务的切换:
- 执行系统调用 SVC;
- 系统嘀嗒定时器中断;
执行系统调用 就是FreeRTOS系统提供的相关 API函数,比如 函数,比如 任务切换函数 taskYIELD(), FreeRTOS有些 API函数 也会调用taskYIELD(),这些 ,这些 API函数都会导致任务切换,统称为系统调用;
#define taskYIELD() portYIELD()
#define portYIELD()
{
//通过向中断控制和壮态寄存器ICSR的bit28写入1挂起PendSV来启动PendSV中断,进行任务切换
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
__dsb( portSY_FULL_READ_WRITE );
__isb( portSY_FULL_READ_WRITE );
}
#define portEND_SWITCHING_ISR( xSwitchRequired )\
if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
系统嘀嗒定时器中断 也会进行任务切换:
void SysTick_Handler(void)
{
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED) //系统已经运行
{
xPortSysTickHandler();
}
HAL_IncTick();
}
void xPortSysTickHandler( void )
{
vPortRaiseBASEPRI(); //关闭中断
if( xTaskIncrementTick() != pdFALSE ) //进入PendSV中断
{
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
vPortClearBASEPRIFromISR(); //打开中断
}
PendSV解析
FreeRTOS在PendSV中完成任务切换,具体不具体展开,因为是汇编语言,核心信息是利用vTaskSwitchContext() 来获取下一个要运行的任务,并将pxCurrentTCB更新为这个要运行的任务:
void vTaskSwitchContext( void )
{
if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE ) //挂起状态不能进行任务切换
{
xYieldPending = pdTRUE;
}
else
{
xYieldPending = pdFALSE;
traceTASK_SWITCHED_OUT();
taskCHECK_FOR_STACK_OVERFLOW();
taskSELECT_HIGHEST_PRIORITY_TASK(); //切换至就绪状态下的优先级最高的任务
traceTASK_SWITCHED_IN();
}
}
#define taskSELECT_HIGHEST_PRIORITY_TASK()
{
UBaseType_t uxTopPriority = uxTopReadyPriority;
//pxReadyTasksLists[]为就绪任务列表数组,一个优先级一个列表,同优先级都挂到相对应的列表
while( listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxTopPriority ] ) ) )
{
configASSERT( uxTopPriority );
--uxTopPriority;
}
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB,&( pxReadyTasksLists[ uxTopPriority ] ) );
uxTopReadyPriority = uxTopPriority;
}
时间片调度方式:
- 任务3 正在运行;
- 嘀嗒器中断,任务时间片用完(时间片的长度用configTICK_RATE_HZ来确定),切换任务至任务1(就绪的下一个任务);
- 不断切换至任务3运行完成,调用portYIELD强行进行任务切换,并放弃剩余的时间片;
- 其余任务不断切换;
内核控制函数概览:
这些函数应用层是不使用的,请注意!!!