实时操作系统μC/OS-II在MCF5272上的移植

分享到:

 作为一个实时内核,μC/OS从1992年开始为人们熟悉,到现在已经发展为μC/OS-II。μC/OS-II最多支持56个任务,其内核为占先式,总是执行就绪态的优先级最高的任务,并支持Semaphore(信号量)、Mailbox(邮箱)、Message Queue(消息队列)等多种常用的进程间通信机制。与大多商用RTOS不同的是,μC/OS-II公开所有的源代码,并可以免费获得,对商业应用收取少量License费用。一般商用操作系统如VxWorks、pSOS、WinCE,购买费用动辄数万美元,而且每件产品都需要交纳运行费,开发、使用成本高昂。

  目前MCF5272是Motorola公司一款集成度最高的ColdFire处理器,采用ColdFire V2可变长RISC处理器核心和DigitalDNA技术,在66MHz时钟下能够达到63Dhrystone2.1MIPS。其内部SIM(System Integrated Module)单元集成了丰富的通用模块,如10/100MHz快速以太网控制器,USB1.1接口等,并且能够与常用的外围设备(如SDRAM、ISDN收发器)实现无缝连接,从而简化了外围电路设计,降低了产品成本、体积和功耗。

  使用GNU工具链(包括交叉编译器GCC、汇编器AS等)进行μC/OS-II内核的编译,Host(宿主机)环境为Linux RedHat 6.2,MCF5272目标板上有4MB FLASH、16MB SDRAM。在宿主机上编译出MCF5272处理器的可执行代码,通过MCF5272的BDM调试工具下载到目标板调试运行。

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语言设置MCF5272片选地址(CS0~CS7)、GPIO以及SDRAM控制器,初始化串口(UART0)作为默认打印口,并向操作系统提供一些硬件相关例程和函数如dprintf(),以方便调试;在CPU、板级和程序自身初始化完成后,就可以把CPU的控制权交给操作系统了。

  MCF5272处理器将系统上电作为2号异常,因此需要在异常矢量表中相应位置填写第一条指令的物理地址,这可以在编译时自动完成。该矢量表必须存放在CS0对应的FLASH中供CPU上电时自动读取。如:

_vectors: //矢量表起始地址

.long 0x0, _start, _fault, _fault, ... //初始化1K字节矢量表

......

_start: nop //第一条指令

move.w #0x2700, %sr //屏蔽所有中断

move.l #_vectors, %d0

move.c %d0, %VBR //#vectors->VBR

move.l #0x10000001,%d0

move.c %d0, %MBAR //SIM单元基地址0x10000000

move.l #0x20000001,%a0 //SRAM起始地址0x20000000

move.c %a0, %RAMBAR0 //初始化内部SRAM

move.l #0x20001001, %a7 //设置堆栈指针

......

jsr cpu_init //调用cpu_init初始化SIM单元

jsr ucos_start //启动uC/OS-II

......

其中cpu_init函数用于初始化CPU内部SIM单元、SDRAM控制器、UART串口。值得注意的是SDRAM初始化,不同生产商的SDRAM的初始化时序有一定差异。

  BSP在完成片级和板级初始化后,还负责初始化程序自身,如将.data段的内容从只读的ROM复制到SDRAM中,建立运行时环境。以下是建立程序数据段的代码:

memcpy(&_sdata,&_etext, (&_edata - &_sdata));//拷贝.data段

memset(&_sbss, 0, (&_ebss - &_sbss));//将.bss段清零

  还需要为μC/OS-II编写4个简单的汇编函数。在每个硬件时钟到来后,μC/OS-II会在中断服务例程中调用OSIntCtxSw()进行任务调度;另外,当某个任务因等待资源而被挂起时,没有必要等到自己的时间片全都用完,可以自己主动放弃CPU,这可以通过调用一个任务级的任务调度函数OSCtxSw()来实现。其中相对复杂的是OSIntCtxSw()。由于OSTickISR()调用了OSIntExit(),OSIntExit()又再次调用了OSIntCtxSw(),如果进行任务切换,那么两次调用都不会返回,而不同的C编译器、不同的编译选项处理C调用时对堆栈的使用也不尽相同。因此OSIntCtxSw()是编译器相关的。GCC在使用2~4级优化时,在主调函数中会是一个jsr跳转指令,而被调函数以linkw %fp, #开始。这两条指令都会影响堆栈指针。为了实现任务切换,必须重新调整堆栈指针以补偿调用的影响。一个完整过程如下:

OSIntCtxSw:

adda.l #16,%a7 //栈补偿,GCC-O2->-O4优化

move.l (OSTCBCur),%a1

move.l %a7,(%a1) //OSTCBCur->OSTCBStkPtr=SP

jsr OSTaskSwHook //调用Hook钩子函数

/*OSTCBCur->OSTCBStkPtr=OSTCBHighRdy->OSTCBStkPtr*/

move.l (OSTCBHighRdy), %a1

move.l %a1, (OSTCBCur)

move.b (OSPrioHighRdy), %d0

move.b %d0, (OSPrioCur) //OSPrioCur=OSPrioHighRdy

move.l (%a1),%a7 //SP=OSTCBCur->OSTCBStkPtr

movem.l (%a7),%d0-%d7/%a0-%a6 //恢复CPU寄存器,切换到新任务

lea 60(%a7),%a7

rte

篇幅所限,其它三个函数就不赘述了。

3 μC/OS-II任务堆栈初始化

  μC/OS-II中每个任务都有自己的任务堆栈,在任务创建初期由OSTaskStkInit()初始化。初始化堆栈的目的就是模拟一次中断。任务堆栈中保存了任务代码的起始地址和一些CPU寄存器(初值是无关紧要的),这样一旦条件满足,就可以执行该任务了。MCF5272在中断发生时,会自动保存程序指针PC、状态寄存器SR以及其它一些信息,为四字帧结构。除此以外,%d0-%d7、%a0-%a6也必须按一定顺序入栈。OSTaskStkInit()在完成堆栈初始化后,还要返回栈顶指针以用于该任务控制块TCB结构的初始化。该程序使用C语言编写。

4 μC/OS-II系统时钟

  MCF5272处理器内置了4个定时器,使用TIMER0产生周期10ms的定时中断作为系统时钟。当PIVR寄存器设置为0x40时,TIMER0为69号中断,在矢量表的相应位置需填入时钟服务程序OSTickISR()的入口地址,并初始化时钟:

volatile unsigned short*pTimer;

pTimer=(unsigned short*)(0x10000000+0x200);//指向TIMER0

/* 复位时钟 */

*pTimer &= 0xFFF9; //定时器处于STOP状态

*pTimer=(*pTimer & 0x00FF) | 0xFA00;//预分频=250

*pTimer |= 0x0018; //计数满自动清零,中断方式

pTimer[2] = 165; //Set TRR = 165

*pTimer=(*pTimer & 0xFFF9) | 0x0004;CLK=Master/16, 启动

上述程序段时钟节拍的周期为:(1/66MHz)×250×165×16=0.01秒。实时性要求高的场合可以使用更为精细的时钟。TIMER0一旦完成初始化,就开始工作,但是要让中断发生,还必须设置ICR寄存器相应字段给该中断分配IPL(Interrupt Priority Level,中断优先级),并保证该中断没有被状态寄存器SR屏蔽。

  该时钟初始化代码可以放在第一个μC/OS-II任务中,在OSStart()后执行。一旦内核可以进行正常的任务切换,移植工作也就基本完成了。

5 内核编译与下载

  所有的C和汇编源文件经过编译、链接,最终形成一个二进制映像文件。由于μC/OS-II使用了自定义的数据类型,因此必须将其转变成为GCC(GNU C Compiler)能识别的类型,如INT8U可以定义为unsigned char。另外,还必须编写一个LD(链接脚本)文件控制编译,将程序定位到实际的ROM和RAM资源中。为了调试方便,通常是通过BDM工具将内核下载到目标板SDRAM中运行,调试通过后再固化到FLASH中。

  RTOS是当前嵌入式应用的热点。应用RTOS,可以使产品更可靠、功能更强大而开发周期更短。μC/OS-II有着良好的实时性和很小的代码量,并被广泛移植到x86、68K、ColdFire、MPC 8xx、ARM、MIPS、C5409等许多处理器上。数百个成功的商业应用实例说明μC/OS-II是一个稳定可靠的内核,因此将μC/OS-II移植到MCF5272具有很强的实用前景。

继续阅读
方法μCOS-II在ATmega128单片机上的移植和开发

引 言 本文介绍μC/OS-Ⅱ移植到ATMEL公司的8位微控制器ATmega128上的过程。所谓移植,就是使一个实时内核可以在某个微处理器上运行,并在此基础上进行驱动程序开发,使之成为一个实用的嵌

缩短μC/OS-II实时内核中断关闭时间的方法设计

笔者将以μC/OS-II实时内核为例,通过对μC/OS-II的改进,向读者描述一种缩短实时操作系统中断关闭时间的方法。之所以选择μC/OS-II,一是因为读者容易获得相关代码,国内很多读者也对μC/OS-II有一定程度的了解;二是因为其自身结构简单,适合运用于低档嵌入式处理器,关中断时间的问题更加突出。低档嵌入式处理器的处理速度慢,在关中断时间里处理相同的软件代码,花费的时间更长,相对地延长了关中断时间,这时尽量从软件着手解决关中断时间的问题。

实时操作系统软件调度器/硬件调度器的设计与实现

实时操作系统(RTOS),在整个嵌入式系统中扮演着十分重要的角色,它就像人的大脑支配人的行为一样,控制着整个系统的工作与运转,一个RTOS性能的优劣将对整个系统的性能产生直接的影响.衡量一个RTOS的好坏有多种标准,实时性则为一个关键指标,并且随着实时操作系统实际运用的加深及拓广,对RTOS提出了更加严格的要求.在系统限定时间内响应处理外部事件已经成为了对RTOS的一个基本要求.

Linux实时化解决方案Xenomai的原理及应用

除了提供Linux硬实时,Xenomai的另一个目的是使基于Linux的实时操作系统能提供与传统的工业级实时操作系统(包括VxWorks、pSOS+、VRTX或者uITRON)功能相同的API.这样,可以让这些操作系统下的应用程序能够很容易地移植到GNU/Linux环境中,同时保持很好的实时性。

基于ARM的人体生理参数监护系统的设计

该监护系统采用了ARM7系列芯片中的LPC2292嵌入式微处理器,主要用来测量人体的生理参数,如:心电图、血压、血氧饱和度、体温等。

©2019 Microchip Corporation
facebook google plus twitter linkedin youku weibo rss