目录
任务切换
任务切换的本质:就是CPU寄存器的切换。就是把任务块的TCB开头的寄存器加载到CPU的R寄存器里面。
假设当由任务A切换到任务B时,主要分为两步:
第一步:需暂停任务A的执行,并将此时任务A的寄存器(CUP的寄存器,因为正在运行的是任务A所以CUP的寄存器应该保存到任务A的任务推栈里面)保存到任务堆栈,这个过程叫做保存现场;
第二步:将任务B的各个寄存器值(被存于任务堆栈中)恢复到CPU寄存器中,这个过程叫做恢复现场;
对任务A保存现场,对任务B恢复现场,这个整体的过程称之为:上下文切换
注意:任务切换的过程在PendSV中断服务函数里面完成
PendSV中断的触发
1.滴答定时器中断调用
2.执行FreeRTOS提供的相关API函数:portYIELD()
本质:通过向中断控制和状态寄存器ICSR的bit28写入1挂起PendSV来启动PendSV 中断
xPortPendSVHandler中断服务函数
__asm void xPortPendSVHandler( void )
{
extern uxCriticalNesting;
extern pxCurrentTCB;
extern vTaskSwitchContext;
/*保存现场*/
/*8字节对齐*/
PRESERVE8
/*保存PSP进程指针到R0里面,中断里面执行的是MSP主推栈指针*/
mrs r0, psp
isb
/*获取任务控制块地址*/
ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */
/*通过R3任务控制块的地址,获取任务控制块的值(栈顶指针)*/
ldr r2, [r3]
/*压栈R4-R11*/
stmdb r0!, {r4-r11} /* Save the remaining registers. */
/*把栈顶指针赋值给R2里面,在恢复任务时直接从R0直接出栈*/
str r0, [r2] /* Save the new top of stack into the first member of the TCB. */
/*压栈R3R14 MSP指针,*/
stmdb sp!, {r3, r14}
/*获取FreeRTOS所管理的最高中断优先级*/
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
/*把r0的值写到中断屏蔽寄存器里面,实现关FreeRTOS所管理的中断*/
msr basepri, r0
dsb
isb
/*执行vTaskSwitchContext函数查找下一个要运行任务的任务块*/
bl vTaskSwitchContext
/*赋值r0为0 */
mov r0, #0
/*中断屏蔽寄存器写0,实现开中断*/
msr basepri, r0
/*出栈R0和R14*/
ldmia sp!, {r3, r14}
/*vTaskSwitchContext执行这个函数后,当前任务控制块指针内容会变成下一个要执行的任务控制块地址*/
/*获取要执行的任务控制块地址*/
ldr r1, [r3]
/*通过R3任务控制块的地址,获取任务控制块的值(栈顶指针)*/
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */
/*出栈R4-R11*/
ldmia r0!, {r4-r11} /* Pop the registers and the critical nesting count. */
/*把r0值写到PSP指针里面此时R0指针指向的是R11寄存器的地址,后硬件恢复其他寄存器*/
msr psp, r0
isb
/*返回r14链接寄存,然后去执行任务B的任务函数执行任务*/
bx r14
nop
}
查找最高优先级任务vTaskSwitchContext函数
taskSELECT_HIGHEST_PRIORITY_TASK() /* 通过这个函数完成*/
#define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority; \
\
/* Find the highest priority list that contains ready tasks. */ \
/**/
/*获取最高优先级,前导零指令*/
portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority ); \
configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
/*获取最高优先级就绪列表的任务块*/
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) ); \
} /* taskSELECT_HIGHEST_PRIORITY_TASK() */
FreeRTOS任务调度整个过程脑图