一种实时操作系统μC/OS-II在LPC2114上移植的实现

时间:2011-07-20

  传统的嵌入式系统设计大多采用单任务顺序机制,应用程序是一个无限的大循环,所有的事件都按顺序执行,与时间相关性较强的事件靠定时中断来保证,由此带来系统的稳定性、实时性较差;尤其当系统功能较复杂,且对实时性要求较严格时,这种单任务机制的弱点暴露无遗。本文引入的嵌入式操作系统μC/OS-II是一个多任务的实时内核,主要提供任务管理功能。在实时系统中的多个任务,必须决定这些任务的优先级顺序,任务调度算法需要动态为就绪任务的优先级排序。为了满足对实时性要求越来越高的需要,同时避免频繁改变就绪任务的优先级,在分析μC/OS-II源代码的基础上,对其调度算法进行改进。

  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系统结构

  μC/OS-II是一个完整的,可移植、可固化、可裁剪的占先式实时多任务内核;支持56个用户任务,支持信号量、邮箱、消息队列等常用的进程间通信机制;适用于各种微控制器微处理器;所有代码用ANSI C语言编写,程序的可读性强,具有良好的可移植性,已被移植到多种处理器架构中,在某些实时性要求严格的领域中得到广泛应用。

  图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是板级支持包,是介于主板硬件和操作系统之间的一层,应该说是属于操作系统的一部分,主要目的是为了支持操作系统,使之能够更好的运行于硬件主板。BSP是相对于操作系统而言的,不同的操作系统对应于不同定义形式的BSP,例如VxWorks的BSP和Linux的BSP相对于某一CPU来说尽管实现的功能一样,可是写法和接口定义是完全不同的,所以写BSP一定要按照该系统BSP的定义形式来写(BSP的编程过程大多数是在某一个成型的BSP模板上进行修改)。这样才能与上层OS保持正确的接口,良好的支持上层OS.

  为μ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正常运转,不断调度任务,响应中断。
  

上一篇:浅谈家庭网络视频监控技术及前景应用
下一篇:一种数据采集及解码器的设计与实现

免责声明: 凡注明来源本网的所有作品,均为本网合法拥有版权或有权使用的作品,欢迎转载,注明出处。非本网作品均来自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

相关技术资料