摘 要:介绍了实时操作系统μC/OS-II的特点和内核结构,并实现了μC/OS-II在Philips嵌入式处理器LPC2114上的移植。
关键词:μC/OS-II LPC2114 移植
作为一个实时内核,μC/OS从1992年开始为人们熟悉,到现在已经发展为μC/OS-II。μC/OS-II最多支持56个任务,其内核为占先式,即总是执行就绪态的优先级最高的任务,并支持Semaphore(信号量)、Mailbox(邮箱)、Message Queue(消息队列)等多种常用的进程间通信机制。与大多数商用RTOS不同的是,μC/OS-II公开其全部源代码,并可以免费获得,对商业应用只收取少量的License费用。
LPC2114是Philips公司开发的一款支持实时仿真和跟踪的ARM7TDMI-S CPU,并嵌入了128KB的高速Flash存储器。其内部集成了与片内存储器控制器接口的ARM7局部总线、与中断控制器接口的AMBA高性能总线(AHB)和连接片内外设功能的VLSI外设总线(VPB,ARM AMBA总线的兼容超集)。LPC2114将ARM7TDMI-S配置为小端(little-endian)字节顺序。128位宽度的存储器接口和独特的加速结构使32位代码能够在最大时钟频率下运行。
将μC/OS-II移植在LPC2119上不仅有益于ARM和μC/OS-II在车用控制器上的应用,其成果还可以用于其他嵌入式工业控制领域。本次移植中,使用CodeWarrior For ARM Developer Suite v1.2编译调试环境。
1 μC/OS-II系统结构
图1为μC/OS-II的软硬件体系结构。应用程序处于整个系统的顶层,每个任务都可以认为自己独占了CPU,因而可以设计成为一个无限循环。μC/OS-II处理器无关的代码提供了μC/OS-II的系统服务,应用程序可以使用这些API函数进行内存管理、任务间通信以及创建、删除任务等。
大部分μC/OS-II代码是使用ANSI C语言编写的,因此μC/OS-II的可移植性较好。尽管如此,仍然需要使用C和汇编语言写一些处理器相关的代码。μC/OS-II的移植需要满足下列要求:(1)处理器的C编译器可以产生可重入代码。(2)可以使用C调用进入和退出Critical Code(临界区代码)。(3)处理器必须支持硬件中断,并且需要一个定时中断源。(4)处理器需要能够容纳一定数据的硬件堆栈。(5)处理器需要有能够在CPU寄存器与内存和堆栈交换数据的指令。
移植μC/OS-II的主要工作涉及处理器及编译器相关代码以及BSP的编写。
2 μC/OS-II BSP的编写
BSP(板级支持包)是介于底层硬件和操作系统之间的软件层次,它完成系统上电后最初的硬件和软件初始化,并对底层硬件进行封装,使得操作系统不再面对具体的硬件。
为μC/OS-II编写一个简单的BSP的方法是:首先设置CPU内部寄存器和系统堆栈,并初始化堆栈指针,建立程序的运行和调用环境;然后使用C语言设置LPC2114向量中断控制器、GPIO以及SRAM控制器,初始化串口(UART0)作为默认打印口,并向操作系统提供一些硬件相关例程和函数(如dprintf( )),以方便调试;在CPU、板级和程序自身初始化完成后,就可以把CPU的控制权交给操作系统了。
LPC2114处理器支持七种类型的异常。异常出现后,CPU强制从异常类型对应的固定存储地址开始执行程序,因此需要在程序头建立起异常向量表,例如:
向量从上到下依次为复位、未定义指令异常、软件中断、预取指令中止、预取数据中止、保留的异常、IRQ和FIQ。保留的异常向量位置所填的数据0xb9205f80是为了使向量表中所有的数据32位累加和为0。这个向量在ARM文件中标识为保留,该位置被Boot装载程序用作有效的用户程序关键字。当向量表中所有的数据累加为0(且外部硬件禁止进入ISP程序)时,Boot装载程序将执行用户程序。
从异常向量表可知:芯片复位时程序会跳转到标号Reset处。程序首先调用InitStack初始化各种模式的堆栈,然后调用TargetResetInit对系统进行基本的初始化,最后跳转到ADS提供的启动代码__main。例如:
Reset
BL InitStack
BL TargetResetInit
B__main
同时在每个硬件时钟到来后,μC/OS-II会在中断服务例程中调用OSIntCtxSw( )进行任务调度。另外,当某个任务因等待资源而被挂起时,它可以自己主动放弃CPU,而没有必要等到自己的时间片全都用完。这可以通过调用一个任务级的任务调度函数OSCtxSw( )来实现,其中相对复杂的是OSIntCtxSw( )。由于OSLickISR( )调用了 OSIntExit( ),OSIntExit( )又再次调用了OSIntCtxSw( ),如果进行任务切换,则二次调用都不会返回,而不同的C编译器、不同的编译选项处理C调用时对堆栈的使用也不尽相同。因此OSIntCtxSw( )是与编译器相关的。在ADS编译环境下,OSIntCtxSw的软件流程如图2所示。
3 μC/OS-II 任务堆栈初始化
μC/OS-II中每个任务都有自己的任务堆栈。在任务创建初期由OSTaskStkInit( )初始化。初始化堆栈的目的就是模拟一次中断。任务堆栈中保存了任务代码的起始地址和一些CPU寄存器(初值是无关紧要的),这样一旦条件满足,就可以执行任务了。LPC2114在中断发生时,会自动保存程序指针PC、状态寄存器SR以及其他一些信息。图3为针对LPC2114编程结构设计的堆栈结构。
本次移植的函数OSTaskStkInt( )代码为:
4 μC/OS-II系统时钟管理
μC/OS-II需要在系统初始化时开始一个系统时钟节拍,它是OS系统的时间基准。该时钟节拍一般由时间中断产生。LPC2114中可产生时钟节拍的模块很多,本次移植采用定时器0异常。因为它与外部中断使用不同的异常向量,便于对异常事件的管理,有利于提高OS的稳定性。32位定时器TC的计数频率由plck经过PR分频控制得到,而定时器的启动/停止、计数复位由TCR控制。当有捕获事件或比较匹配事件发生时,IR会设置相关的中断标志,若已打开中断允许,则会产生中断。
本次移植设置系统时钟频率为11.0592MHz,代码在时钟初始化和每次进入定时器0异常时,将定时器0的计数器PWMTC设置为11.0592M/OS_TICKS_PER_SEC,这样可使OS每秒钟产生OS_TICKS_PER_SEC的时钟节拍。
5 应用方法
在使用移植后的OS时,用户需要编写自己的主程序main( ),其流程图如图4。在适当的初始化后即可启动OS。
另外,用户需在TaskStart任务中启动时钟节拍,调用OS_StartInit( )函数初始化统计任务,创建所需的其他任务,最后调用OSTaskDel( )函数删除TaskStart任务。OS在该函数调用结束后,会自动允许异常和中断,OS正常运转,不断调度任务,响应中断。
参考文献
1 LABROSSE J J.μC/OS-II:the Real Time Kernel.RS:R&D
Books,1999
2 周立功.ARM微控制器基础与实战.北京:北京航空航天大学出版社,2003
3 Labrosse J著,邵贝贝译.嵌入式实时操作系统μC/OS-II(第二版).北京:北京航空航天大学出版社,2003