微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > μC/OS-II在ARM平台上移植的研究

μC/OS-II在ARM平台上移植的研究

时间:01-04 来源:互联网 点击:

μC/OS-II的内核分成2个部分,与处理器无关的代码和与处理器有关的代码。移植过程中需要根据S3C2410处理器和ADSV1.2开发平台(这里特地强调编译平台的因素,主要考虑到各个编译平台对数据格式的理解略有差别)的特点来重新编写3个文件,用C语言编写的OS_CPU.H、OS_CPU_C.C和用汇编语言编写的OS_CPU_A.ASM,此外,要将S3C2410开发板引导程序和μC/OS-II内核程序融合在一起,还必须将各自main()函数融为一体。

3.1 OS_CPU.H的移植

μC/OS-II内核中OS_CPU.H代码是根据X86内核而写的,其中的数据格式定义与ARM9内核以及ADSv1.2开发平台不完全相符。OS_CPU.H的移植分为以下4个部分:

(1)数据类型定义:在调试时发现,虽然定义8 bit或16 bit数据类型时,在编译过程中不会报错,但这些变量并不会按要求被正确初始化或赋值,运行过程常常出错。所以,在改写OS_CPU.H代码时,将所有变量都定义成32 bit或64 bit;

(2)堆栈生长方向定义:ARM的堆栈是从上往下生长的,OS_STK_GROWTH定义为1;

(3)开关中断的宏定义:用开关中断的汇编函数实现,放在OS_CPU_A.ASM文件中。

(4)宏定义OS_TASK_SW():这个宏定义是在ARM中断处理之外时,μC/OS-II从低优先级切换到高优先级任务时所调用的代码,它总是在任务级代码中被调用。在有些资料中[1],将OS_TASK_SW()和OSIntCtxSw()等同起来,这在ARM内核中是不行的,因为后者是ARM内核在中断模式下的任务切换函数,而不同模式下处理器的寄存器组是不同的,所要保护的寄存器内容也不相同,经过调试,发现以下代码可达到目的。

OS_TASK_SW

stmfd sp!, {lr} ; PC入栈,lr其实是任务的返回地址,

stmfd sp!, {r0-r12, lr}

mrs r4, cpsr

stmfd sp!, {r4} ;最后保存CPSR ldr r4, =OSTCBCur

ldr r5, [r4]

str sp, [r5] ;将SP保存在当前任务的控制块中 ldr r5, =OSTCBHighRdy

ldr r5, [r5]

str r5, [r4] ;OSTCBCur = OSTCBHighRdy ldr r6, =OSPrioHighRdy

ldr r6, [r6]

ldr r4, =OSPrioCur

str r6, [r4] ;OSPrioCur = OSPrioHighRdy

ldr sp, [r5] ;得到新任务的堆栈指针

ldr r4, [sp], #4

msr cpsr_cxsf, r4 ;先恢复CPSR

ldmfd sp!, {r0-r12, lr, pc}

3.2 OS_CPU_C.C.H的移植

在OS_CPU_C.C中,最主要的函数是OSTaskStkInit(),它在任务建立时,用来初始化任务堆栈结构,其余钩子函数可以不用动,这个函数的代码比较简单[2]。需要说明的是,由于本文所述系统,用户任务运行在SVC模式下,没有保存SPSR寄存器。

3.3 OS_CPU_A.ASM的移植

OS_CPU_A.ASM文件的汇编程序是μC/OS-II移植工程的重点和难点。它通常包括OSStartHighRdy()、OSIntCtxSw()、OSTickISR()和开关中断代码等。其中,OSStartHighRdy()的主要工作是将优先级最高任务对应的所有寄存器按顺序从任务堆栈中恢复出来,其代码简单[2]。对于开关中断函数,在调试时所用代码如下:

EnterCritical

mrs r1, cpsr

str r1, [r0]

orr r1, r1, #NOINT

msr cpsr_cxsf, r1

mov pc, lr

ExitCritical

ldr r1, [r0]

msr cpsr_cxsf, r1

mov pc, lr

需要指出的是,在每次成对调用这两个函数时,需要提前声明变量r,代码如下所示:

INT32U r;

EnterCritical(r);

ExitCritical(r);

需要慎重对待的是OSIntCtxSw()、OSTickISR()函数。在调试时发现,用一般参考资料所介绍的代码都无法实现多任务的正常运行,其主要原因是,对ARM9内核而言,其每种特定的中断返回,都有特定的返回指令,在中断处理过程中,强制使用模式切换指令,使处理器的中断处理机制发生混乱,程序无法正常执行。例如在ISR模式中使用指令:

MSR CPSR_c, #(NO_INT | SVC32_MODE)

其目的是返回ISR发生之前的模式,然后保存一些寄存器。但调试时发现,在上述指令执行之后,处理器重新响应ISR中断,并没有顺序执行,而是立即回到ISR模式下。

还有,对于S3C2410的ARM920T内核而言,其ISR模式的返回指令是:

ldmfd sp!, {r0-r12, lr}

subs pc, lr, #04

其他任何形式的指令都无法使处理器正确返回。有些资料用下述指令:

Ldmfd sp!, {r0-r12, lr,pc}; 执行之前堆栈中相应存储单元的内容为(lr-4)。

看起来与前面的两行代码意义相同,但后面的代码仅仅让处理器实现PC指针的跳转,而无法实现处理器的模式转换,即从ISR模式回到中断发生之前的模式。

但在中断发生时,无法在中断处理过程中保存所有的处理器寄存器。例如,在ISR模式下,无法保存SVC模式的LR寄存器等。为了解决这个问题,本文采取了如图1所示的框图结构来编写中断处理代码和OSIntCtxSw()函数。

因为S

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

网站地图

Top