1、启动第一个任务
os_start
|--》OSInit
|--》OSTaskCreate
|--》OSTaskStkInit
|--》OSStart
|--》OSStartHighRdy
2、OSTaskStkInit,这个函数用于构造一个伪现场,用于调度中断的出栈处理
CPU_STK *OSTaskStkInit (OS_TASK_PTR p_task,
void *p_arg,
CPU_STK *p_stk_base,
CPU_STK *p_stk_limit,
CPU_STK_SIZE stk_size,
OS_OPT opt)
{
CPU_STK *p_stk;
(void)opt; /* Prevent compiler warning */
p_stk = &p_stk_base[stk_size]; /* Load stack pointer */
/* Registers stacked as if auto-saved on exception */
*--p_stk = (CPU_STK)0x01000000u; /* xPSR */
*--p_stk = (CPU_STK)p_task; /* Entry Point */
*--p_stk = (CPU_STK)OS_TaskReturn; /* R14 (LR) */
*--p_stk = (CPU_STK)0x12121212u; /* R12 */
*--p_stk = (CPU_STK)0x03030303u; /* R3 */
*--p_stk = (CPU_STK)0x02020202u; /* R2 */
*--p_stk = (CPU_STK)p_stk_limit; /* R1 */
*--p_stk = (CPU_STK)p_arg; /* R0 : argument */
/* Remaining registers saved on process stack */
*--p_stk = (CPU_STK)0x11111111u; /* R11 */
*--p_stk = (CPU_STK)0x10101010u; /* R10 */
*--p_stk = (CPU_STK)0x09090909u; /* R9 */
*--p_stk = (CPU_STK)0x08080808u; /* R8 */
*--p_stk = (CPU_STK)0x07070707u; /* R7 */
*--p_stk = (CPU_STK)0x06060606u; /* R6 */
*--p_stk = (CPU_STK)0x05050505u; /* R5 */
*--p_stk = (CPU_STK)0x04040404u; /* R4 */
return (p_stk);
}
3、OSStartHighRdy --》1、把psp置为0,2、MSP指向OS_CPU_ExceptStkBase,3,、触发PendSV exception
OSStartHighRdy
LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0]
MOVS R0, #0 ; Set the PSP to 0 for initial context switch call
MSR PSP, R0
LDR R0, =OS_CPU_ExceptStkBase ; Initialize the MSP to the OS_CPU_ExceptStkBase
LDR R1, [R0]
MSR MSP, R1
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
CPSIE I ; Enable interrupts at processor level
OSStartHang
B OSStartHang ; Should never get here
4、PendSV_Handler
1)因为psp为0,所以直接跳转到OS_CPU_PendSVHandler_nosave
2)调用OSTaskSwHook
3)OSPrioCur = OSPrioHighRdy;
4)OSTCBCurPtr = OSTCBHighRdyPtr;
5)SP = OSTCBHighRdyPtr->StkPtr;这个时候从堆栈依次弹出R4-R11,PSP指向R0+#0x20
6)ORR LR, LR, #0x04,确保中断返回后使用PSP。
7)从中断返回。BX LR表示从中断中返回。
PendSV_Handler
CPSID I ; Prevent interruption during context switch
MRS R0, PSP ; PSP is process stack pointer
CBZ R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time
SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack
STM R0, {R4-R11}
LDR R1, =OSTCBCurPtr ; OSTCBCurPtr->OSTCBStkPtr = SP;
LDR R1, [R1]
STR R0, [R1] ; R0 is SP of process being switched out
; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH {R14} ; Save LR exc_return value
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
BLX R0
POP {R14}
LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy;
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
LDR R0, =OSTCBCurPtr ; OSTCBCurPtr = OSTCBHighRdyPtr;
LDR R1, =OSTCBHighRdyPtr
LDR R2, [R1]
STR R2, [R0]
LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdyPtr->StkPtr;
LDM R0, {R4-R11} ; Restore r4-11 from new process stack
ADDS R0, R0, #0x20
MSR PSP, R0 ; Load PSP with new process SP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack
CPSIE I
BX LR ; Exception return will restore remaining context
END
5、STM发生中断需要做的事情:
z 入栈: 把8个寄存器的值压入栈
z 取向量:从向量表中找出对应的服务程序入口地址
z 选择堆栈指针MSP/PSP,更新堆栈指针SP(使用MSP),更新连接寄存器LR(一个特殊值),更新程序计数器PC(指向ISR)
从中断返回即弹出以上堆栈,可以看出,堆栈顺序和OSTaskStkInit是一致的。
6、普通任务切换:
OSTaskResume --》 OSSched --》OS_TASK_SW -》触发任务切换 --》回到函数PendSV_Handler
#define OS_TASK_SW() NVIC_INT_CTRL = NVIC_PENDSVSET
这是的任务切换中断处理多了两个步骤:
1)保存R4-R11
2)保存SP到原任务堆栈OSTCBCurPtr->OSTCBStkPtr = SP;