三、移植OS_CPU_A.ASM
1、移植OS_CPU_SR_Save() OS_CPU_SR_Restore()
OS_CPU_SR_Save()保存当前的开关中断状态到R0,使用R0是因为编译器一般用R0传递参数。然后关中断。
Bx LR
从被OS_CPU_SR_Save()函数中断的程序处继续执行。进入临界段。
OS_CPU_SR_Restore()恢复R0中保存的开关状态,
Bx LR
从被OS_CPU_SR_Restore()函数中断的程序处继续执行。退出临界段。
这里使用的是PRIMASK,PRIMASK用于除能在 NMI和硬 fault之外的所有异常。
FAULTMASK能关闭所有异常和硬fault。
这里使用PRIMASK而不是FAULTMASK,是因为出现硬fault,必须要去处理,硬fault不能被关掉。
2、移植OSStartHighRdy()
OSStart()调用OSStartHighRdy()来使就绪态任务中优先级最高的任务开始运行。
这个函数里首先设置PENDSV中断优先级最低。
把PSP进程堆栈寄存器的值设为0.
设置MSP主堆栈寄存器的值为OS_CPU_ExceptStkBase。OS_CPU_ExceptStkBase在OS_CPU.H中定义,指向一个堆栈类型数组。
把OSRunning置1,表示OS内核开始运行。
悬起PendSV,开总中断。
3、移植任务切换函数OSCtxSw()
这个函数也是悬起PendSV中断,在PendSV中断程序中进行上下文切换。
OSCtxSw()在OS_Sched()函数中被调用。
4、移植中断切换函数OSIntCtxSw()
悬起PendSV中断,在PendSV中断程序中进行上下文切换。
OSIntCtxSw()在OSIntExit()函数中被调用。
5、移植PendSV_Handler()
PendSV用于上下文切换,这是CM3推荐的做法。因为CM3对任何异常自动保存和恢复xPSR,PC,LR,r12,r3,r4,r1,r0,所以只有R4-R11需要手动保存到任务堆栈。
1、 关闭中断
2、 判断PSP是否为0,因为在开始执行第一个任务时,在函数OSStartHighRdy()中把PSP置0,所以如果PSP为0,那么表示当前执行的是第一个任务,没有上文需要保存,直接跳转到OS_CPU_PendSVHandler_nosave。
如果PSP不为0,需要保存R4-R11的值到当前任务的堆栈。因为CM3自动保存了8个字节寄存器,每个寄存器32位,4个字节,4*8=32=0x20.所以R0-0x20,得到当前的堆栈指针,然后把R4-R11压入堆栈。最后把当前的堆栈值送给当前任务的任务控制块OSTCBCur->OSTCBStkPtr。
3、 LR压栈,调用钩子函数OSTaskSwHook(),LR出栈。如果不使用钩子函数,这一段可以屏蔽。
4、 OSPrioCur = OSPrioHighRdy; OSPrioHighRdy是一个8位数,指待运行的优先级最高的任务的优先级号。OSPrioCur是当前任务的优先级号。
5、 改变OSTCBCur的值,使OSTCBCur指向待运行任务的控制块OSTCBHighRdy。
6、 把待运行任务的堆栈指针放到R0
7、 从待运行任务的堆栈中取出R4-R11的值送给R4-R11
8、 因为已经出栈8个寄存器的值,每个寄存器占4字节,调整待运行任务的堆栈指针,R0+0X20。
9、 把待运行任务的当前堆栈值送到CM3的进程堆栈PSP。
10、 ORR LR, LR, #0x04,确保异常返回后使用PSP
11、 开中断
12、 退出异常,从PSP弹出xPSR,PC,LR,r12,r3,r4,r1,r0(这几个寄存器的值也是保存在待运行任务的栈中),开始执行新任务。
注意中断函数名是PendSV_Handler,要和要和startup_LPC17xx.s中的中断向量表定义的PendSV中断函数名称对应起来。在startup_LPC17xx.s中定义了
这是默认的PendSV_Handler中断函数,是一个死循环。后面[WEAK]的意思是告诉编译器,如果程序其它地方定义了PendSV_Handler(),就不用这里定义的PendSV_Handler()。如果在OS_CPU_A.ASM中没有声明PendSV_Handler()可以被外部引用
就是这段代码没有EXPORT PendSV_Handler,即使OS_CPU_A.ASM中定义了PendSV_Handler()函数,编译时也会用
这段代码,在发送PendSV中断时,程序一直在B.处死循环。
到这里,整个移植工作就完成了。
