zoukankan      html  css  js  c++  java
  • 实时操作系统μC/OSII在MCF5272上的移植

    关键词:μC/OS-II MCF5272 移植 GNU工具链

     作为一个实时内核,μ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(宿主机)环境为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 DSP编写

    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.1 #_vectors,%d0

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

    move.1 #0x10000001,%d0

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

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

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

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

    ……

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

    jsr ucos_start //启动μC/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,#<d0>开始。这两条指令都会影响堆栈指针。为了实现任务切换,必须重新调整堆栈指针以补偿调用的影响。一个完整过程如下:

    OSIntCtxSw:

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

    move.1 (OSTCBCur),%a1

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

    jsr OSTaskSwHook //调和Hook钩子函数

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

    move.1 (OSTCBHighRdy),%a1

    move.1 %a1,(OSTCBCur)

    move.b (OSPrioHighRdy),%d0

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

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

    movem.1 (%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×164×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具有很强的实用前景。

    推荐文章:

    《uClinux下中断驱动的I/O方式》 

    关于驱动程序中的ioctl

  • 相关阅读:
    Java.io.outputstream.PrintStream:打印流
    Codeforces 732F. Tourist Reform (Tarjan缩点)
    退役了
    POJ 3281 Dining (最大流)
    Light oj 1233
    Light oj 1125
    HDU 5521 Meeting (最短路)
    Light oj 1095
    Light oj 1044
    HDU 3549 Flow Problem (dinic模版 && isap模版)
  • 原文地址:https://www.cnblogs.com/fengyv/p/2423905.html
Copyright © 2011-2022 走看看