freertos任务调度关键函数理解
void xPortPendSVHandler( void )
{
/* This is a naked function. */
__asm volatile
(
//保存当前任务上下文
" mrs r0, psp \n" //读取进程栈指针(PSP)到r0
" isb \n" //指令同步屏障,确保前面的指令执行完毕
" \n"
" ldr r3, pxCurrentTCBConst \n" /* Get the location of the current TCB. */
" ldr r2, [r3] \n" //保存r4-r11寄存器到当前任务栈(STMDB指令)
" \n" //只保存/恢复r4-r11是因为ARM架构下中断自动保存r0-r3,r12,lr,pc,xPSR
" stmdb r0!, {r4-r11} \n" /* Save the remaining registers. */
" str r0, [r2] \n" /* Save the new top of stack into the first member of the TCB. */
" \n" //更新TCB中的栈顶指针
" stmdb sp!, {r3, r14} \n" //临时保存r3和r14寄存器
" mov r0, %0 \n"
" msr basepri, r0 \n" //提升中断优先级(basepri)保护临界区
" bl vTaskSwitchContext \n" //调用vTaskSwitchContext选择新任务
" mov r0, #0 \n"
" msr basepri, r0 \n" //恢复中断优先级 解除所有中断屏蔽 (BASEPRI=0 时允许所有优先级中断)
" ldmia sp!, {r3, r14} \n"
" \n" /* Restore the context, including the critical nesting count. */
" ldr r1, [r3] \n" //从新任务的TCB获取栈指针 临界区嵌套计数可能是前面版本的注释,此处不适合.
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. */
" ldmia r0!, {r4-r11} \n" // Pop the registers. 恢复r4-r11寄存器(LDMIA指令)
" msr psp, r0 \n" //更新PSP为新任务的栈指针
" isb \n" //指令同步屏障,确保前面的指令执行完毕
" bx r14 \n" //通过BX指令返回到新任务的执行点
" \n" //会触发处理器的异常返回机制
//处理器会自动从栈中恢复xPSR、PC、LR、R12、R3-R0(这是异常进入时自动压栈的寄存器) 从R0开始...到PC结束
//根据EXC_RETURN值切换回线程模式并使用PSP
" .align 4 \n"
"pxCurrentTCBConst: .word pxCurrentTCB \n"
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
中断时使用的是msp,任务x使用的是psp
对比linux来理解:
中断模式属于内核态,任务x属于用户态。
systick中断会触发xPortPendSVHandler,内核态使用msp,即使被其他高级别的中断再中断,也是使用msp,不会影响用户态的psp指针.