(1) ucos版本查看 OS_VERSION
(2) ARM一般是小端模式,堆栈指针一般位于高地址,向下生长
OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt)
{
OS_STK *stk;
opt = opt; /* 'opt' is not used, prevent warning */
stk = ptos; /* Load stack pointer (堆栈栈顶处) */
*(stk) = (OS_STK)task; /* Entry Point (实际就是函数名) */
*(--stk) = (INT32U)0x14141414L; /* R14 (LR) */
*(--stk) = (INT32U)0x12121212L; /* R12 */
*(--stk) = (INT32U)0x11111111L; /* R11 */
*(--stk) = (INT32U)0x10101010L; /* R10 */
*(--stk) = (INT32U)0x09090909L; /* R9 */
*(--stk) = (INT32U)0x08080808L; /* R8 */
*(--stk) = (INT32U)0x07070707L; /* R7 */
*(--stk) = (INT32U)0x06060606L; /* R6 */
*(--stk) = (INT32U)0x05050505L; /* R5 */
*(--stk) = (INT32U)0x04040404L; /* R4 */
*(--stk) = (INT32U)0x03030303L; /* R3 */
*(--stk) = (INT32U)0x02020202L; /* R2 */
*(--stk) = (INT32U)0x01010101L; /* R1 */
*(--stk) = (INT32U)p_arg; /* R0 : argument */
*(--stk) = (INT32U)ARM_SVC_MODE; /* CPSR (Enable both IRQ and FIQ interrupts) */
return (stk);
}
INT8U OS_TCBInit (INT8U prio, OS_STK *ptos, OS_STK *pbos, INT16U id, INT32U stk_size, void *pext, INT16U opt)
{
...................
ptcb->OSTCBStkPtr = ptos; //即上面返回的指针保存在任务块中,作为以后SP指针的地址,存取CPU寄存器
....................
}
假设定义固定长度堆栈 OS_STK Stack1[STKSIZE] (OS_STK 32位长度)
实际任务(task)堆栈结构
Stack1[STKSIZE-1] = Entry Point (实际上是任务运行到某处的PC值)
Stack1[STKSIZE-2] = LR
...........................................
Stack1[STKSIZE-16] = CPSR
Stack1[STKSIZE-17] = DATA1 //作为任务其他需要用到的堆栈空间
............................................
Stack1[STKSIZE-N] = DATAN //例如任务中的局部变量等
void OS_Sched (void)
{
INT8U y;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
cpu_sr = 0; /* Prevent compiler warning */
#endif
OS_ENTER_CRITICAL();
if (OSIntNesting == 0) { /* Schedule only if all ISRs done and ... */
if (OSLockNesting == 0) { /* ... scheduler is not locked */
y = OSUnMapTbl[OSRdyGrp]; /* Get pointer to HPT ready to run */
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
if (OSPrioHighRdy != OSPrioCur) { /* 获得最高优先级OSPrioHighRdy*/
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
OSTCBHighRdy->OSTCBCtxSwCtr++; /* Inc. # of context switches to this task */
#endif
OSCtxSwCtr++; /* Increment context switch counter */
OS_TASK_SW(); /* Perform a context switch */
}
}
}
OS_EXIT_CRITICAL();
}
OSCtxSw ;任务切换
; SAVE CURRENT TASK'S CONTEXT
STMFD SP!, {LR} ; 将当前任务下一条PC指令的值推入该任务堆栈中
STMFD SP!, {LR}
STMFD SP!, {R0-R12} ; 将其他寄存器依次推入该任务堆栈中
MRS R4, CPSR ; Push current CPSR
TST LR, #1 ; See if called from Thumb mode
ORRNE R4, R4, #0x20 ; If yes, Set the T-bit
STMFD SP!, {R4}
LDR R4, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP;(将该任务的SP指针保存起来,以备以后存取)
LDR R5, [R4]
STR SP, [R5]
LDR R0, =OSTaskSwHook ; OSTaskSwHook();
MOV LR, PC
BX R0
LDR R4, =OSPrioCur ; OSPrioCur = OSPrioHighRdy (将最高优先级的任务作为当前任务)
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]
LDR R4, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
STR R6, [R4]
LDR SP, [R6] ; SP = OSTCBHighRdy->OSTCBStkPtr;(将SP指向新任务的堆栈处)
; RESTORE NEW TASK'S CONTEXT
LDMFD SP!, {R4} ; Pop new task's CPSR
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC}^ ; Pop new task's context (跳转到新任务上一次被中断的PC处)