原创 UCOS-II中OSCtxSw函数移植

2010-9-20 10:51 3081 10 10 分类: MCU/ 嵌入式

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_TASK_SW();                                    


                      }


        }


    }


    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、从堆栈中得到待运行任务的断点值,从断点处开始继续运行。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
10
关闭 站长推荐上一条 /3 下一条