微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > uCOS-II的移植步骤

uCOS-II的移植步骤

时间:11-27 来源:互联网 点击:

*(--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 |-----------------|

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top