uCOS-II的移植步骤
*(--stk) = (INT32U)0x11111111uL;
*(--stk) = (INT32U)0x10101010uL;
*(--stk) = (INT32U)0x09090909uL;
*(--stk) = (INT32U)0x08080808uL;
*(--stk) = (INT32U)0x07070707uL;
*(--stk) = (INT32U)0x06060606uL;
*(--stk) = (INT32U)0x05050505uL;
*(--stk) = (INT32U)0x04040404uL;
return (stk); //返回任务的栈顶
第四步:是移植中最重要的部分,也就是汇编底层函数的编写。
主要有一下这几个函数
(一)开中断和关中断函数的实现。
OS_CPU_SR_Save ;用于实现关中断的汇编指令
MRS R0, PRIMASK ;读取PRIMASK到R0,R0是返回值
CPSID I ;PRIMASK=1,关中断(NMI和硬fault可以响应)
BX LR
OS_CPU_SR_Restore ;用于实现开中断的汇编指令
MSR PRIMASK, R0 ;读取R0到PRIMASK中,R0为参数
BX LR
(二)函数 void OSStartHighRdy(void)
OSStartHighRdy()由OSStart()调用,用来启动最高优先级任务,当然任务必须在OSStart()前已被创建
- PendSV中断的优先级应该为最低优先级,原因在<>的7.6节已有说明
- .PSP设置为0,是告诉具体的任务切换程序(OS_CPU_PendSVHandler()),这是第一次任务切换。做过切换后PSP就不会为0了,后面会看到。
- 往中断控制及状态寄存器ICSR(0xE000ED04)第28位写1即可产生PendSV中断。这个<>8.4.5 其它异常的配置寄存器有说明
OSStartHighRdy ;设置PendSV中断的优先级
LDR R0, =NVIC_SYSPRI14 ;Set the PendSV exception priority
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0] ;*(uint8_t *)NVIC_SYSPRI14 = NVIC_PENDSV_PRI
MOVS R0, #0 ;初始化进程堆栈指针 Set the PSP to 0 for initial context switch call
MSR PSP, R0 ;初始化PSP为0 初始化上下文切换调用
LDR R0, =OSRunning ; OSRunning = TRUE
MOVS R1, #1 ;设置OSRunning = TRUE
STRB R1, [R0]
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET ;触发PendSV中断
STR R1, [R0] ;*(uint32_t *)NVIC_INT_CTRL = NVIC_PENDSVSET
CPSIE I ; Enable interrupts at processor level开启中断
OSStartHang
B OSStartHang ; Should never get here 死循环 which(1);
(三)用户任务切换函数和中断任务的切换函数。
官方的移植代码里面,这两个函数的处理函数是一样的,而关于这个问题的讨论,网上也有很多,我查了下官方关于在Cortex-M3各个厂家处理器上的移植,都是一样的,就连现在最新推出的M4系列(飞思卡尔 K60),他们也是这么做,所以我决定也这么干吧。
这两个函数就做了一件事,就是触发PendSV中断。如果没有比PendSV优先级高的中断触发,那么用户的切换任务和中断的切换任务就会得到及时的执行。
OSIntCtxSw
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
OSCtxSw
LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0] ;*(uint32_t *)NVIC_INT_CTRL = NVIC_PENDSVSET
BX LR
(四)这个函数是真正实现任务切换的函数,理解这个函数很重要。
首先我们要明白一点,那就是这个函数说白了就是一个中断函数,而它不同于一般的中断函数,在KEIL里面我们写好C的程序之后,已经将中断的入栈和出栈的工作做好了,在这里我们要自己写入栈和出栈的汇编指令,而且这里的关键就在,中断函数出栈的时候恢复的堆栈指针是指向别的任务的,理解了这个,下面的函数就很好的理解了。
附上一幅任务出栈和入栈的图
// | .... |
;// |-----------------|
;// | .... |
;// |-----------------|
;// | .... |
;// |-----------------| |---- 任务切换时PSP
;// Low Memory | .... | |
;// |-----------------| | |---------------| |----------------|
;// ^ | R4 | <----|----|--OSTCBStkPtr |<-----| (OS_TCB *) |
;// ^ |-----------------| |---------------| |----------------|
;// ^ | R5 | | | OSTCBHighRdy
;// | |-----------------| |---------------|
;// | | R6 | | |
;// | |-----------------| |---------------|
;// | | R7 | | |
;// | |-----------------| |---------------|
;// | | R8 | Tasks
;// | |-----------------| OS_TCB
;// | | R9 |
;// | |-----------------|
;// | | R10 |
;// Stack |-----------------|
;// Growth | R11 |
;// = 1 |-----------------|
;// | | R0 = p_arg | <-------- 异常时的PSP (向上生长的满栈)
;// | |-----------------|
;// | | R1 |
;// | |-----------------|
;// | | R2 |
;// | |-----------------|
;// | | R3 |
;// | |-----------------|
;// | | R12 |
;// | |-----------------|
;// | | LR |
;// | |-----------------|
;// | | PC = task |
;// | |-----------------|
;// | | xPSR |
;// High Memory |-----------------|
uCOS-II移植步 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)