新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > uCOS-II的移植步骤

uCOS-II的移植步骤

作者:时间:2016-11-27来源:网络收藏

(二)函数 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 |-----------------|

这个里面有个PSP进程堆栈指针,关于这个指针和主堆栈指针的区别需要好好的看看权威指南

OS_CPU_PendSVHandler ;xPSR, PC, LR, R12, R0-R3已自动保存
CPSID I ;任务切换期间需要关中断 Prevent interruption during context switch
MRS R0, PSP ;R0 = PSP PSP is process stack pointer 线程堆栈指针
CBZ R0, OS_CPU_PendSVHandler_nosave ;如果PSP==0跳转到OS_CPU_PendSVHandler_nosave去执行 在多任务的初始化时PSP被初始化为0 Skip register save the first time
;若果PSP如果是0,标示任务没有运行过,那么不需要压栈

SUBS R0, R0, #0x20 ;R0 -= 0x20 保存R4-R11到任务堆栈 共32个字节

STM R0, {R4-R11} ;压栈R4-R11, 其他8个寄存器是在异常时自动压栈的
LDR R1, =OSTCBCur ;获取OSTCBCur->OSTCBStkPtr

LDR R1, [R1] ;R1 = *R1 (R1 = OSTCBCur)
STR R0, [R1] ;*R1 = R0 (*OSTCBCur = SP) R0 is SP of process being switched out
;将当前任务的堆栈保存到自己的任务控制块
;OSTCBCur->OSTCBStkPtr = PSP
;程序运行此位置,已经保存了当前任务的context了

; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH {R14} ; Save LR exc_return value 保存R14,因为后面要调用函数
LDR R0, =OSTaskSwHook ; OSTaskSwHook(); R0 = &OSTaskSwHook
BLX R0 ; 调用OSTaskSwHook()
POP {R14} ; 恢复R14

LDR R0, =OSPrioCur ; OSPrioCur = OSPrioHighRdy; R0 = &OSPrioCur
LDR R1, =OSPrioHighRdy ; R1 = &OSPrioHighRdy
LDRB R2, [R1] ; R2 = *R1 (R2 = OSPrioHighRdy)
STRB R2, [R0] ; *R0 = R2 (OSPrioCur = OSPrioHighRdy)

LDR R0, =OSTCBCur ; OSTCBCur = OSTCBHighRdy;;R0 = &OSTCBCur
LDR R1, =OSTCBHighRdy ; R1 = &OSTCBHighRdy
LDR R2, [R1] ; R2 = *R1 (R2 = OSTCBHighRdy)
STR R2, [R0] ; *R0 = R2 (OSTCBCur = OSTCBHighRdy) 此时 [R2] = 新任务的PSP

LDR R0, [R2] ;R0 = *R2 (R0 = OSTCBHighRdy), 此时R0是新任务的SP R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
LDM R0, {R4-R11} ; 从任务堆栈SP恢复R4-R11 Restore r4-11 from new process stack
ADDS R0, R0, #0x20 ; 调整PSP R0 += 0x20
MSR PSP, R0 ; Load PSP with new process SP PSP = R0, 用新任务的SP加载PSP
ORR LR, LR, #0x04 ; Ensure exception return uses process stack 确保LR位2为1,返回后使用进程堆栈PSP
CPSIE I ;开中断
BX LR ; Exception return will restore remaining context 中断返回

END

由于是第一次的学习关于操作系统的知识,里面的理解估计有很多不对的地方。随着自己的理解就会有所修正。


上一页 1 2 下一页

关键词: uCOS-II移植步

评论


相关推荐

技术专区

关闭