__asm void xPortPendSVHandler( void )
{
extern uxCriticalNesting;
extern pxCurrentTCB;
extern vTaskSwitchContext;
PRESERVE8
mrs r0, psp
isb//指令同步命令,
ldr r3, =pxCurrentTCB /* Get the location of the current TCB. */
ldr r2, [r3]//r2保存pxCurrentTCB的值,也是结构体topofstack的值,即栈顶的地址,
stmdb r0!, {r4-r11} /* Save the remaining registers. */进入中断会自动保存部分寄存器到//PSP
str r0, [r2] /* Save the new top of stack into the first member of the TCB. */
更新topofstack的值。
stmdb sp!, {r3, r14}//接下来会用到r3和r14.
mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
msr basepri, r0//禁止部分中断优先级低的中断
dsb
isb
bl vTaskSwitchContext//进行跳转的任务切换函数,见解析一
mov r0, #0
msr basepri, r0//运行所有中断
ldmia sp!, {r3, r14}
ldr r1, [r3]//因为r3保存的是xCurrentTCB的地址。在任务切换函数中,xCurrentTCB的值变成了要切换任务的TCB。所以下面的栈就是要运行的任务栈
ldr r0, [r1] /* The first item in pxCurrentTCB is the task top of stack. */
ldmia r0!, {r4-r11} /* Pop the registers and the critical nesting count. */
msr psp, r0//将top of stack赋给PSP
isb
bx r14//跳转到另一个任务。因为中断的硬件保存机制,所以即使另一个任务是被中断的,也可以继续保持运行。
nop
}
解析一:
void vTaskSwitchContext( void )
{
假设调度器正常运行。(精简后)
xYieldPending = pdFALSE;//允许礼让。
/* Select a new task to run using either the generic C or port
optimised asm code. */
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 );
根据找到的就绪列表中的其它任务,并将该任务的TCB赋值给pxCurrentTCB
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );
}