管理员
最后登录1970-1-1
在线时间 小时
注册时间2013-3-25
|
1:开始多任务函数 void OSStartHighRdy(void)
在OSInit()初始化完毕之后,会调用OSStart(),在OS开始函数里面会调用void OSStartHighRdy(void)函数,这是一个纯汇编编写的函数,在os_cpu_a.s这个汇编文件里面实现,具体的如下,我已经给每一句代码都添加了注释。
;********************************************************************************************************
; 开始多任务
; void OSStartHighRdy(void)
;
; 注意 : 1) 这个函数触发了一个PendSV异常,导致第一个任务开始运行.
;
; 2) OSStartHighRdy() 必须:
; a) 设置PendSV的优先级为最低;
; b) 初始化进程堆栈指针PSP等于0, 表明这是第一次上下文切换;
; c) 设置主堆栈指针等于OS_CPU_ExceptStkBase
; d) 触发PendSV异常;
; e) 使能中断,任务开始运行.
;********************************************************************************************************
- ;********************************************************************************************************
- ; 开始多任务
- ; void OSStartHighRdy(void)
- ;
- ; 注意 : 1) 这个函数触发了一个PendSV异常,导致第一个任务开始运行.
- ;
- ; 2) OSStartHighRdy() 必须:
- ; a) 设置PendSV的优先级为最低;
- ; b) 初始化进程堆栈指针PSP等于0, 表明这是第一次上下文切换;
- ; c) 设置主堆栈指针等于OS_CPU_ExceptStkBase
- ; d) 触发PendSV异常;
- ; e) 使能中断,任务开始运行.
- ;********************************************************************************************************
- OSStartHighRdy
- ; 设置PendSV中断优先级
- LDR R0, =NVIC_SYSPRI14
- LDR R1, =NVIC_PENDSV_PRI
- STRB R1, [R0] ;*R0=R1(低字节),因为表达优先级只需要8bit
- ; 初始化PSP=0
- MOVS R0, #0 ; 把0加载到R0
- MSR PSP, R0 ; 把R0的值加载到特殊寄存器PSP
- ; 初始化MSP地址
- LDR R0, =OS_CPU_ExceptStkBase ; 把OS_CPU_ExceptStkBase这个指针变量的地址加载到R0
- LDR R1, [R0] ; *R0 = R1,实际上就是把OS_CPU_ExceptStkBase的值加载到R1
- MSR MSP, R1 ; 把R1的值加载到MSP,此时MSP=OS_CPU_ExceptStkBase
-
- ; 触发PendSV异常 (进入上下文切换)
- LDR R0, =NVIC_INT_CTRL
- LDR R1, =NVIC_PENDSVSET
- STR R1, [R0] ; *R0 = R1
-
- ; 打开中断
- CPSIE I
- ; 正常情况下,永远不会运行到这,因为这是一个死循环
- OSStartHang
- B OSStartHang
复制代码
1:PendSV 异常服务函数 void OS_CPU_PendSVHandler(void)
- OS_CPU_PendSVHandler
- CPSID I ; 关中断,执行上下文切换的时候不能被中断,属于临界段
- MRS R0, PSP ; 加载PSP(即R13)的值到R0
- CBZ R0, OS_CPU_PendSVHandler_nosave ; R0的值为0则跳转到OS_CPU_PendSVHandler_nosave; CBZ:比较,如果结果为0就跳转
- ; 第一次进行上下文切换的时候PSP等于0,所以要进行跳转
-
- SUBS R0, R0, #0x20 ; 压栈之前先调整堆栈指针,要压栈的寄存器R4-R11有8个,所以偏移为8*0x04=0x20
- STM R0, {R4-R11} ; 手动将R4-R11压栈
- ; 实现 OSTCBCurPtr->OSTCBStkPtr = SP;
- LDR R1, =OSTCBCurPtr ; R1=&OSTCBCurPtr,这个时候R1里面存的是OSTCBCurPtr这个指针变量的地址
- LDR R1, [R1] ; R1=*R1=OSTCBCurPtr,这个时候,R1等于OSTCBCurPtr这个指针变量
- STR R0, [R1] ; *R1=R0,这个时候OSTCBCurPtr指向的TCB的第一个成员(即OSTCBCurPtr->OSTCBStkPtr)等于R0
- ; R0又是一开始进行压栈的PSP,所以OSTCBCurPtr->OSTCBStkPtr = SP
- ; 程序运行到这个点上,进入上下文切换的过程已经保存好了
- OS_CPU_PendSVHandler_nosave
- PUSH {R14} ; 保存 LR exc_return 的值
- LDR R0, =OSTaskSwHook ; 调用OSTaskSwHook()
- BLX R0
- POP {R14}
- ; 实现 OSPrioCur = OSPrioHighRdy;
- LDR R0, =OSPrioCur ; R0=&OSPrioCur
- LDR R1, =OSPrioHighRdy ; R1=&OSPrioHighRdy
- LDRB R2, [R1] ; R2=*R1(低字节),因为优先级是8bit的,所以是低字节
- STRB R2, [R0] ; R0=*R2(低字节),因为优先级是8bit的,所以是低字节
- ; 实现 OSTCBCurPtr = OSTCBHighRdyPtr;
- LDR R0, =OSTCBCurPtr ; R0=&OSTCBCurPtr
- LDR R1, =OSTCBHighRdyPtr ; R1=&OSTCBHighRdyPtr
- LDR R2, [R1] ; R2=*R1
- STR R2, [R0] ; R0=*R2
- LDR R0, [R2] ; R0等于新的进程的SP; SP = OSTCBHighRdyPtr->StkPtr
- ; R2=OSTCBHighRdyPtr,则[R2]=*R2=OSTCBHighRdyPtr=StkPtr,因为TCB的第一个成员就是StkPtr
- LDM R0, {R4-R11} ; 从新的堆栈中弹出R4-R11
- ADDS R0, R0, #0x20 ; 重新调整堆栈指针,R4-R11为8个寄存器,每个寄存器为四个字节,8*4=32=0X20
- MSR PSP, R0 ; 更新PSP的值
- ORR LR, LR, #0x04 ; 判断LR寄存器的位4是否为1,确保异常返回用用的是PSP
- CPSIE I ; 打开中断,上下文切换结束
- BX LR ; 异常返回
- END ; 汇编程序结束
复制代码
|
|