OSCtxSw()函数把被中止任务的断点指针和CPU的寄存器值保存到该任务的堆栈中,并从待运行任务的堆栈中得到其堆栈指针,把待运行任务堆栈中的存储的CPU通用寄存器的内容恢复到CPU的通用寄存器中,最后使CPU获得待运行任务的断点指针。
任务切换函数OSCtxSw()一般有2种方法实现。一种是软中断,周立功的LPC资料上都是这么用的。一种是用子程序调用,我现在做的这个项目就是这么实现的。
在OS_CPU.H中定义
#define OS_TASK_SW() OSCtxSw()
OSCtxSw()函数在OS_CPU_A.S中:
OSCtxSw
; SAVE CURRENT TASK'S CONTEXT
STR LR, [SP, #-4]! 1
STR LR, [SP, #-4]! 2
STR R12, [SP, #-4]! 3
STR R11, [SP, #-4]! 4
STR R10, [SP, #-4]! 5
STR R9, [SP, #-4]! 6
STR R8, [SP, #-4]! 7
STR R7, [SP, #-4]! 8
STR R6, [SP, #-4]! 9
STR R5, [SP, #-4]! 10
STR R4, [SP, #-4]! 11
STR R3, [SP, #-4]! 12
STR R2, [SP, #-4]! 13
STR R1, [SP, #-4]! 14
STR R0, [SP, #-4]! 15
MRS R4, CPSR 16 ; push current CPSR
STR R4, [SP, #-4]! 17
LDR R4, =OSTCBCur 18; OSTCBCur->OSTCBStkPtr = SP;
LDR R5, [R4] 19
STR SP, [R5] 20
BL OSTaskSwHook 21 ; OSTaskSwHook();
LDR R4, =OSPrioCur 22; OSPrioCur = OSPrioHighRdy
LDR R5, =OSPrioHighRdy 23
LDRB R6, [R5] 24
STRB R6, [R4] 25
LDR R4, =OSTCBCur 26; OSTCBCur = OSTCBHighRdy;
LDR R6, =OSTCBHighRdy 27
LDR R6, [R6] 28
STR R6, [R4] 29
LDR SP, [R6] 30; SP = OSTCBHighRdy->OSTCBStkPtr;
; RESTORE NEW TASK'S CONTEXT
LDR R4, [SP], #4 31; pop new task's CPSR
MSR CPSR_cxsf, R4 32
LDR R0, [SP], #4 33; pop new task's context
LDR R1, [SP], #4 34
LDR R2, [SP], #4 35
LDR R3, [SP], #4 36
LDR R4, [SP], #4 37
LDR R5, [SP], #4 38
LDR R6, [SP], #4 39
LDR R7, [SP], #4 40
LDR R8, [SP], #4 41
LDR R9, [SP], #4 42
LDR R10, [SP], #4 43
LDR R11, [SP], #4 44
LDR R12, [SP], #4 45
LDR LR, [SP], #4 46
LDR PC, [SP], #4 47
OS_Sched (void)函数在OS_CORE.C中:
void OS_Sched (void)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr = 0;
#endif
OS_ENTER_CRITICAL();
if (OSIntNesting == 0) {
if (OSLockNesting == 0) {
OS_SchedNew();
if(OSPrioHighRdy!=OSPrioCur) {
OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
OSTCBHighRdy->OSTCBCtxSwCtr++;
#endif
OSCtxSwCtr++;
}
}
}
OS_EXIT_CRITICAL();
}
在ADS中通过汇编语言可以看到,OS_TASK_SW();语句对应的汇编语句是 BL OSCtxSW
我的程序中BL OSCtxSW下条语句的地址是0x00000CB4,在执行完BL OSCtxSW这条语句后,程序跳到OSCtxSW函数处,同时R14(LR)的值变为0x00000CB4。
BL命令在执行时会自动把下一条指令的地址值拷贝到LR中,但是不会自动保存状态寄存器CPSR。
下面分析OSCtxSW函数:
1、 把LR的值保存到sp – 4后对应得地址中,同时sp = sp – 4。被中止任务再次调度执行时,会把这个值送到PC寄存器中,使被中止任务从断点处继续执行。
2、 把LR的值再次压入堆栈。这条语句和46语句是对应的。就是保存R14(LR)的值,便于恢复。LR的值再次保存我觉得没有什么必要。因为LR的值已经保存过一次,在任务恢复执行时,会把这个值送到PC寄存器。任务切换后,会从待运行任务的堆栈中恢复一个值到PC寄存器。
LR在调用OSCtxSW函数和其它子函数时的作用是不一样的。在调用OSCtxSW函数时,
LR的作用是保存当前任务的断点,并把断点值送到当前任务的堆栈。在执行完OSCtxSW函数后,程序执行的已经是另外的任务,和调用OSCtxSW函数时保存的LR值已经没关系了。
调用其它子函数时,LR保存当前任务断点,执行完子函数后,把LR的值送到PC寄存器,任务继续运行。
这个地方写的很罗嗦,因为这个地方我觉得不好理解,所以不厌其烦,希望已经说清楚了。
3-15、把R12-R0寄存器的值压入堆栈。
16-17、保存CPSR的值
18-20、把当前的SP值送到当前任务的任务控制块OSTCBCur->OSTCBStkPtr
21、调用OSTaskSwHook函数,这个函数用户自己添加内容,一般为空。
22-27、获得待运行任务的控制块地址。
28、把待运行任务的堆栈指针值送到SP寄存器。
31-32、从堆栈中得到CPSR的值。
33-46、从堆栈中得到cpu其它寄存器的值。
47、从堆栈中得到待运行任务的断点值,从断点处开始继续运行。
文章评论(0条评论)
登录后参与讨论