目 录
摘要 ................................................................ 1 关键词 .............................................................. 1 1 引言 .............................................................. 1 2 μC/OS-II简介 ..................................................... 2 2.1 μC/OS-II的特点 ................................................. 2 2.2 μC/OS-II的体系结构 ............................................. 3 3 移植规划 .......................................................... 3 3.1 移植条件 ........................................................ 3 3.1.1 可重入代码与非可重入代码 ...................................... 4 3.1.2 OS_ENTER_CRITICAL( )与OS_EXIT_CRITICAL( ) ..................... 4 3.2 移植要求 ........................................................ 4 3.3 移植需要编写的文件 .............................................. 4 3.4 移植代码包括的主要内容 .......................................... 5 3.5 编译器的选择 .................................................... 5 4 移植的实现 ........................................................ 6 4.1 OS_CPU.H的移植 .................................................. 6 4.1.1数据类型的定义 ................................................. 6 4.1.2堆栈的定义 ..................................................... 6 4.1.3中断与临界区代码 ............................................... 7 4.1.4使用软中断SWI作底层接口 ....................................... 8 4.2 OS_CPU_C.C的移植 ................................................ 9 4.2.1 OSTaskStkInit( ) .............................................. 9 4.2.2 Hook( )函数 .................................................. 10 4.3 OS_CPU_A.ASM的移植 ............................................. 11 4.3.1 OSStartHighRdy()函数 ......................................... 11 4.3.2 OSCtxSw( )函数 ............................................... 12 4.3.3 OSIntCtxSw()函数 ............................................. 13 4.3.4 OSTickISR()函数 .............................................. 14 5 嵌入式系统的初始化 ............................................... 16 5.1初始化程序的下载执行 ............................................ 16 5.2嵌入式系统的初始化过程 .......................................... 17 5.2.1硬件初始化阶段 ................................................ 17
I
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
5.2.2 RTOS初始化阶段 ............................................... 18 5.3 ARM920T系统初始化的一般过程 .................................... 19 5.3.1设置程序入口指针 .............................................. 19 5.3.2设置中断向量 .................................................. 19 5.4初始化存储器系统 ................................................ 20 5.4.1存储器地址分布 ................................................ 20 5.4.2 ROM地址重映射的实现 .......................................... 20 5.5初始化堆栈 ...................................................... 215.6初始化应用程序执行环境 .......................................... 225.6.1初始化C环境 .................................................. 225.6.2改变处理器模式 ................................................ 235.6.3调用C程序 .................................................... 235.7 uC/OS系统的初始化 .............................................. 235.7.1 ARM的硬件抽象层——uHALuC/OS ................................. 245.7.2 ARMTargetInit()函数结构 ...................................... 245.7.3 uHAL的功能 ................................................... 256 移植测试 ......................................................... 256.1测试移植代码 .................................................... 256.1.1确保C编译器、汇编编译器及链接器正常工作 ...................... 256.1.2验证OSTskStkInit() 和OSStartHighRdy()函数 .................... 256.1.3验证OSCtxSw() 函数 ........................................... 266.1.4验证OSIntCtxSw()和OSTickISR()函数 ............................ 266.2在S3C2440上测试移植结果 ........................................ 266.2.1编译uCOS2 .................................................... 266.2.2把uCOS2下载到内存中运行 ...................................... 287 结论 ............................................................. 30 致 谢 ........................................................... 31参考文献 ........................................................... 31英文翻译 ........................................................... 32
II
2010届电子信息工程专业毕业设计(论文)
实时操作系统μC/OS-II在ARM上的移植研究
陈利顺
重庆三峡学院物理与电子工程学院电子信息工程专业06级 重庆万州 404000
摘要 本设计采用三星公司生产的一款基于ARM920T核的高性能低功耗soc芯片S3C2440作为移
植的硬件平台。对实时操作系统μC/OS-II的特点、体系结构、移植所需要的条件、移植所需要编写的文件,移植所需要的编译器作了深入的了解,通过编写移植代码,对移植的测试,实现了μC/OS-II在S3C2440的移植。
关键词 嵌入式系统 μC/OS-II 移植
1. 引言
随着信息化技术的发展和数字化产品的普及,以计算机技术、芯片技术和软件技术为核心的嵌入式系统再度成为当前研究和应用的热点。对功能、可靠性、成本、体积和功耗严格要求的嵌入式系统一般由嵌入式微处理器、外围硬件设备、嵌入式操作系统以及用户的应用程序等四个部分组成,其中嵌入式微处理器和嵌入式操作系统分别是其硬件和软件的核心。
自从嵌入式系统开发以来, 很长时间都采用前后台系统软件设计模式: 主程序为一个无限循环, 单任务顺序执行。通过设置一个或多个中断来处理异步事件。这种系统对于简单的应用是可以的, 但对于实时性要求比较高的处理任务较多的应用, 就会暴露出实时性差、系统可靠性低、稳定性差等缺点。μC/OS-II是一种给予优先级的抢占式多任务实时操作系统, 包含了实时内核、任务管理、时间管理、任务间通信同步(信号量, 邮箱, 消息队列)和内存管理等功能。它可以使各个任务独立工作, 互不干涉, 很容易实现准时而且无误执行, 使得实时应用程序的设计和扩展变得容易, 使得应用程序的设计过程大为减化。而且它内核源代码公开,移植性强, 为编程人员提供了很好的一个软件平台。
ARM(Advanced RISC Machines)公司是全球领先的16/32位RISC微处理器知识产权设计供应商。ARM公司通过转让高性能、低成本、低功耗的RISC微处理器、外围和系统芯片设计技术给合作伙伴,是他们能使用这些技术来生产各具特色的芯片。ARM已成为移动通信、手持设备、多媒体数字消费嵌入式解决方案的RISC标准。ARM处理器有三大特点:小体积、低功耗、低成本而高性能;16/32位双指令集;全球众多的合作伙伴。
三星公司推出的16/32位RISC微处理器S3C2440,为手持设备和一般类型应用提供了低价格、低功耗、搞性能小型微控制器的解决方案。S3C2440的杰出的特点是其核心处理器(CPU),是一个由Advanced RISC Machines有限公司设计的16/32位ARM920T的RISC处理器,实现了MMU,AMBA,BUS和Harvard高速缓冲体系结构。这一结构具有独立的16KB指令Cache和16KB数据Cache。每个都是由具有8字长的行组成,通过提供一套完整的通用系统外设,S3C2440减少整体系统成本和无需配置额外的组件,因此本文选定三星公司生产的一款基于ARM920T核的高性能低功耗SOC
1
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
芯片S3C2440作为移植方案的硬件平台。
2. μC/OS-II简介
μC/OS-Ⅱ是由Jean J . Labrosse 先生编写的完整的可移植、固化、裁剪的占先式实时多任务内核。是用ANSI的C语言编写的,包含小部分汇编语言代码,使之可供不同架构的微处理器使用。至今。从8位到64位,μC/OS-Ⅱ已在超过40种不同架构的微处理器上运行。
μC/OS-Ⅱ功能强大,支持56个用户任务,支持信号量、邮箱、消息队列等多种常用的进程间通信机制,现已成功应用到众多商业嵌入式系统中,是一个成熟稳定的实时内核。
2.1μC/OS-II特点
1) 提供源代码:购买作者撰写的《嵌入式实时操作系统μC/OS-II》一书即可获得μC/OS-II
V2.52版本的所有源代码,购买此书的其它版本可以获得相应版本的全部源代码。 2) 可移植性:μC/OS-II的源代码绝大部分是使用移植性很强的ANSI C写的,将与微处理
器硬件相关的汇编语言使用量压缩到最低的限度,以使μC/OS-II便于移植到其它微处理器上。目前,μC/OS-II已经被移植到多种不同架构的微处理器上。
3) 可固化:只要具备合适的软硬件工具,就可以将μC/OS-II嵌入到产品中成为产品的一部
分。
4) 可剪裁:μC/OS-II使用条件编译实现可剪裁,用户程序可以只编译自己需要的(μ
C/OS-II的)功能,而不编译不要需要的功能,以减少μC/OS-II对代码空间和数据空间的占用。
5) 可剥夺:μC/OS-II是完全可剥夺型的实时内核,μC/OS-II总是运行就绪条件下优先级
最高的任务。
6) 多任务:μC/OS-II可以管理64个任务,然而,μC/OS-II的作者建议用户保留8个给
μC/OS-II。这样,留给用户的应用程序最多可有56个任务。
7) 可确定性:绝大多数μC/OS-II的函数调用和服务的执行时间具有确定性,也就是说,用
户总是能知道μC/OS-II的函数调用与服务执行了多长时间。
8) 任务栈:μC/OS-II的每个任务都有自己单独的栈,使用μC/OS-II的占空间校验函数,
可确定每个任务到底需要多少栈空间。
9) 系统服务:μC/OS-II提供很多系统服务,例如信号量、互斥信号量、时间标志、消息邮
箱、消息队列、块大小固定的内存的申请与释放及时间管理函数等。
10) 中断管理:中断可以使正在执行的任务暂时挂起,如果优先级更高的任务被中断唤醒,
则高优先级的任务在中断嵌套全部退出后立即执行,中断嵌套层数可达255层。 11) 稳定性与可靠性:μC/OS-II是μC/OS的升级版,μC/OS自1992年以来已经有数百个商
业应用。μC/OS-II与μC/OS的内核是一样的,只是提供了更多的功能。2000年7月,μC/OS-II在一个航空项目中得到了美国联邦航空管理局对商用飞机的、符合RTCA DO – 178B标准的认证。这表明,该操作系统的质量得到了认证,可以在任何应用中使用。
2
2010届电子信息工程专业毕业设计(论文)
2.2μC /OSⅡ的体系结构
应用程序软件uC/OS-II(与处理器无关的代码)OS_CORE.C OS_FLAG.COS_MBOX.C OS_MEM.COS_MUTEX.C OS_Q.COS_SEM.C OS_TASK.COS_TIME.C uCOS_II.CuCOS_II.HuCOS-II配置文件(与应用程序有关)OS_CFG.HINCLUDEES.H移植uCOS-II(与处理器类型有关的代码)OS_CPU.HOS_CPU_A.ASMOS_CPU_C.C软件硬件CPU定时器
图1 μC /OS-Ⅱ的硬件/软件体系结构
上图给出了μC/OS-Ⅱ的软件体系结构,它包括如下结构:
1) 应用程序软件是用户根据实际需求编写的代码,用户根据自己的应用系统,通过编写与应
用相关的代码定制合适的内核服务功能,由此来实现对μC /OS-Ⅱ的裁剪。
2) 与处理器无关的代码就是通常所说的操作系统内核,它为μC/OS-Ⅱ提供所有的系统服务,
并将应用系统和底层硬件有机地结合成一个实时系统。这部分源代码是完全公开的。 3) 要使同一个内核能适用于不同的硬件体系,就需要在内核和硬件之间添加一个中间层,这
就是与处理器相关的代码。所谓移植,就是编写与处理器相关的这部分代码。
3. 移植规划
3.1移植条件
一般来说,能移植μC /OS-Ⅱ的微处理器必须满足以下条件: 1) 处理器的C编译器能产生可重入型代码。 2) 处理器支持中断,并且能产生定时中断。
3
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
3) 用C语言就可以开/关中断。
4) 处理器能支持一定数量的数据存储硬件堆栈。
5) 处理器有将堆栈指针及其他CPU寄存器的内容读出、并存储到堆栈或内存中去的指令。
3.1.1可重入代码与非可重入代码
可重入的代码指的是一段代码(比如:一个函数)可以被多个任务同时调用,而不必担心会破坏数据。也就是说,可重入型函数在任何时候都可以被中断执行,过一段时间以后又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用,影响函数中的数据。
3.1.2 OS_ENTER_CRITICAL( )与OS_EXIT_CRITICAL( )
同其他内核一样,μC/OS-Ⅱ 为了处理临界段(critical sections)代码,须关中断,处理完毕后,再开中断。关中断使得μC/OS-Ⅱ 能够避免同时有其他任务或中断服务进入临界代码段。
在μC/OS-Ⅱ中,可以通过:OS_ENTER_CRITICAL( )和OS_EXIT_CRITICAL( )宏来控制系统关闭或者打开中断。这需要处理器的支持。在S3C2440的处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。
OS_ENTER_CRITICAL( )和OS_EXIT_CRITICAL( )总是成对使用的,把临界段代码封包起来。 μC/OS-Ⅱ是通过处理器产生的定时器的中断来实现多任务之间的调度的。在S3C2440的处理器上可以产生定时器中断
3.2移植要求
要移植一个操作系统到一个特定的CPU体系结构并不是一件很容易的事情,它对移植者有以下要求:
(1).对目标体系结构要有很深了解; (2).对OS原理要有较深入的了解; (3).对所使用的编译器要有较深入的了解; (4).对需要移植的操作系统要有相当的了解; (5).对具体使用的芯片也要一定的了解
3.3移植需要编写的文件
µC/OS-II的代码被分成3个部分:与处理无关的代码;与应用相关的代码;与处理器相关的代码。移植时只要考虑与处理器相关的代码。与处理器相关的代码由3个文件组成:OS_CPU.H文件;OS_CPU_C.C文件;OS_CPU_A.S文件。
根据μC/OS-II的要求,移植μC/OS-II到一个新的体系结构上需要提供2个或3个文件: OS_CPU.H(C语言头文件) OS_CPU_C.C(C程序源文件) OS_CPU_A.ASM(汇编程序源文件)
其中OS_CPU_A.ASM在某些情况下不需要,但极其罕见。不需要OS_CPU_A.ASM的必须满足以下苛刻条件:
(1)可以直接使用C语言开关中断;
4
2010届电子信息工程专业毕业设计(论文)
(2)可以直接使用C语言编写中断服务程序; (3)可以直接使用C语言操作堆栈指针; (4)可以直接使用C语言保存CPU的所有寄存器。
OS_CPU.H文件;OS_CPU_C.C文件;OS_CPU_A.S文件代码的正确配置与编写,只能确保基于S3C2440的µC/OS-II微内核代码形成,并不能立即烧入目标板运行,要在目标板上运行,必须还要编写目标板初始化引导程序,初始化引导程序主要实现硬件初始化、内存映射、中断向量初始化、系统堆栈空间的分配等功能,以引导µC/OS-II的正确运行。
3.4移植代码包括的主要内容 移植内容 BOOLEAN INT8U INT8S OS_STK OS_ENTER_CRITICAL() OS_EXIT_CRITICAL() OS_STK_GROWTH S_TASK_SW 常量 函数 OS_CPU.H OS_CPU.H 定义堆栈的增长方向 任务切换时执行的代码 OSTaskStkInit() OSInitHookBegin() OSInitHookEnd() 函数 函数 OS_CPU_C.C OS_CPU_C.C 任务堆栈初始化函数 uCOS-II在执行某些操作时调用的用户函数,一般为空 OSStartHighRdy() 函数 OS_CPU_A,ASM 进入多任务环境时运行优先级最高的任务 OSInitCtxSw() 函数 OS_CPU_A,ASM 中断退出时的任务切换函数 OSTickISR() 中断服务程序 OS_CPU_A,ASM 时钟节拍中断服务程序 数据类型 宏 OS_CPU.H OS_CPU.H 类型 数据类型 所属文件 OS_CPU.H 描述 与编译器无关的数据类型 堆栈的数据类型 开关中断的代码 图2移植代码包括的主要内容
实际上,还有一个文件很重要,它就是IRQ.INC,它定义了一个汇编宏,它是μC/OS-II 对ARM9通用的中断服务程序的汇编与C函数接口代码。时钟节拍中断服务程序也没有移植,因为其与芯片和应用都强烈相关,需要用户自己编写,不过可以通过IRQ.INC简化用户代码的编写。
3.5编译器的选择
1) 针对ARM处理器核的C语言编译器有很多,如SDT、ADS、IAR、TASKING和GCC等 2) 目前在国内最流行的是ADS、SDT和GCC
3) SDT和ADS均为ARM公司自己开发,ADS为SDT的升级版,以后ARM公司不再支持SDT,
故不选择SDT。GCC虽然支持广泛,很多开发套件使用它作为编译器,但是与ADS比较其
5
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
编译效率较低,这对充分发挥芯片性能不利
故本次设计考虑使用ADS编译程序和调试程序。
4.μC/OS-II 移植的实现
实际上,μC /OS-Ⅱ可以简单地看作是一个多任务调度器,在这个任务调度器上添加了与多任务操作系统相关的一些系统服务,如信号量、邮箱等,其90 %的代码是用C语言写的。
移植工作主要集中在多任务切换的实现上,因为这部分代码用来保存和恢复CPU现场(即写/读相关寄存器) ,不能用C语言实现,而只能用汇编语言完成。
μC /OS-Ⅱ 的全部源代码量大约是6 000~7 000行,将其移植到ARM处理器上,需要修改3个与ARM 体系结构相关的文件: OS_CPU.H, OS_CPU_C.C, OS_CPU_A. ASM,代码量大约是500行。下面分别介绍这3个文件的移植工作。
4.1 OS_CPU.H的移植
在这个文件中主要定义了与编译器和处理器相关的代码,这部分代码包括数据类型定义、堆栈单位定义、堆栈增长方向定义、关中断和开中断的宏定义以及进行任务切换的宏定义等。
4.1.1数据类型的定义
这部分的修改是和所用的编译器相关的,不同的编译器会使用不同的字节长度来表示同一数据类型。μC/OS-II不使用C语言中的short、int、long等数据类型的定义,因为它们与处理器类型有关,隐含着不可移植性。代之以移植性强的整数数据类型,这样既直观又可移植,不过这就成了必须移植的代码。根据ADS编译器的特性,这些代码如下程序清单所示(与编译有关)。具体定义代码如下: typedef typedef typedef typedef typedef typedef typedef typedef typedef typedef
4.1.2堆栈的定义
寄存器在任务切换时将会保存在当前运行任务的堆栈中,所以堆栈单位(即数据类型 OS_STK)应该是和处理器的寄存器长度一致的。
堆栈也是和编译器有关的,当进行函数调用时,入口参数和返回地址都会保存在当前任务的
unsigned char unsigned char signed char unsigned short signed short unsigned int signed int float double int32u
图3数据类型的定义代码
BOOLEAN INT8U INT8S INT16U INT16S INT32U INT32S FP32 FP64 OS_STK
6
2010届电子信息工程专业毕业设计(论文)
堆栈中,编译器的编译选项和由此生成的堆栈指令决定堆栈的增长方向。
在μC/OS-Ⅱ中, 用OS_STK_GROWTH 来设置堆栈的增长方向, 其宏定义为: #define OS_STK_GROWTH 1; /* 堆栈从高地址向低地址增长*/ #define OS_STK_GROWTH 0; /* 堆栈从低地址向高地址增长*/ 4.1.3中断与临界区代码
μC/OS-Ⅱ和其它所有的实时内核一样,在访问操作系统的临界区之前必须关闭中断,访问之后开中断。这可以保证μC/OS-Ⅱ的临界区代码不会被多个任务或中断服务程序同时访问,避免造成共享数据(μC/OS-Ⅱ的全局变量)的不一致性。
对于不同的处理器和编译器,实现开、关中断的方法可能不一样。所以为了方便移植,μC/OS-Ⅱ提供了两个宏定义:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(),用这两个宏定义屏蔽开, 关中断的不同实现。 相关宏定义如下:
#define OS_TASK_SW() OSCtxSw() /*任务切换*/ #define OS_EXIT_CRITICAL() ARMDisabIeInt() /*关闭中断*/ #define OS_ENTER_CRITICAL() ARMEnableInt() /*开启中断*/
OS_TASK_SW()函数用来实现任务切换。μC/OS-Ⅱ会调用 OSCtxSw()函数实现任务切换。OSCtxSw()需要对寄存器进行操作,加上考虑到效率的因素,OSCtxSw()用 ARM 汇编来实现。具体实现过程将在OS_CPU_A. ASM中详细讲述。
OS_ENTER_CRITICAL()和 OS_EXIT_CRITICAL() 采用汇编来实现禁止和允许中断,具体实现为 ARMDisableInt()和 ARMEnableInt()。
在μC/OS-Ⅱ移植过程中很关键的一个问题就是OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL ()这一对宏定义如何实现的问题。最简单的方法是仅用关中断指令实现宏OS_ENTER_CRITICAL() ,仅用开中断指令实现宏OS_EXIT_CRITICAL()。用以下的汇编子程序完成ARMDisableInt()函数来实现关中断:
STMFD SP!,{R0,LR} //R0,LR入栈
MRS R0,CPSR //CPSR->R0需要修改R0
ORR R0,R0,#0XC0 //修改CPSR的运行IRQ位和FIQ位 SWI UpdateCPSR //使修改生效 LDMFD SP!,{RO,PC}
Condition Code FlagsReservedControl Bits31N30Z 29282726252423876543210CV.......OverflowCarry/Borrow/ExtendZeroNegative/Less ThanIFTM4M3M2M1M0Mode bitsState bitFIQ disableIRQ disable
图4程序状态寄存器组成图
7
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
注意子程序中改变中断状态的方法,这里用了一条软件中断指令。因为,当程序运行在用户模式时,不能用MSR指令来改变CPSR的内容,所以,必须用一条软件中断指令进入管理模式来改变中断状态。
软件中断服务程序如下:
UpdateCPSR
MSR SPSR_cxsf,R0 MOVS PC,LR
其中,寄存器R0用于传递参数,包含新的CPSR。这里是利用在管理模式下改变其SPSR(软件中断前用户模式下的CPSR)的值达到改变用户模式下CPSR的目的。指令MOVS PC,R14在将返回地址赋给PC时, 同时也将管理模式下的SPSR值赋给用户模式的CPSR。
用类似的方法可以实现开中断,而且中断状态的改变也必须用软件中断实现。
这种方法可以减少中断延迟时间,但它可能存在一点小问题,就是如果程序在调用OS_ENTER_CRITICAL() 之前,中断已经被禁止,那么在调用OS_EXIT_CRITICAL () 之后,中断被允许,这可能不是程序所期望的。因此这种简单的实现方法对某些情况不适用。
OS_ENTER_CRITICAL() 和OS_EXIT_CRITICAL ()的具体实现要根据原来的中断禁止/允许的状态来决定的。对原方案的改进是在退出临界区的时候会恢复进入之前的状态,使用堆栈保存状态和恢复状态。
具体的方法是在实现宏OS_ENTER_CRITICAL() 的时候,先将当前程序的中断状态保存到堆栈, 然后关中断,而宏OS_EXIT_CRITICAL ()的实现只需将堆栈中的中断状态恢复。这样,就不会破坏程序原来的中断状态,但是这种实现会增加中断的延迟时间。
4.1.4使用软中断SWI作底层接口
μC/OS-II运行时,处理器可能处于的模式如下图所示:
ARM指令ARM指令集Thumb指令集用户模式Thumb指令用户任务使用的处理器模式系统模式ARM指令Thumb指令
图5处理器可能处于的模式
8
2010届电子信息工程专业毕业设计(论文)
为了使底层接口函数与处理器状态无关,同时在任务调用相应的函数不需要知道函数位置,在移植中使用软中断指令SWI作为底层接口,使用不同的功能号区分不同的函数。软中断功能号分配如下表所示,未列出的为保留功能。
功能号 0x00 0x01 0x02 0x03 0x80 0x81 0x82 0x83
接口函数
void OS_TASK_SW(void) void OSStartHighRdy(void) void OS_ENTER_CRITICAL(void) void OS_EXIT_CRITICAL(void) void ChangeToSYSMode(void) void ChangeToUSRMode(void) void TaskIsARM(INT8U prio) void TaskIsTHUMB(INT8U prio)
图6软中断功能号分配
简介
任务级任务切换函数 运行优先级最高的任务,由OSStartHighRdy产生 关中断 开中断
任务切换到系统模式 任务切换到用户模式 任务代码是ARM代码 任务代码是THUMB代码
用软中断作为操作系统的底层接口就需要在C语言中使用SWI(SoftWare Interrupt)指令。在ADS中,有一个关键字__swi,用它声明一个不存在的函数,则调用这个函数就在调用这个函数的地方插入一条SWI指令,并且可以指定功能号。同时,这个函数也可以有参数和返回值,其传递规则与一般函数相同。
4.2 OS_CPU_C.C的移植
在此文件中, 要求我们必须编写10 个简单的C 函数。 OStaskStkInit(); /*任务堆栈初始化函数*/ OStaskCreateHook (); /*任务建立接口函数 */ OStaskDelHook (); /*任务删除接口函数*/ OStaskSwHook (); /*任务切换接口函数*/ OStaskIdleHook (); /*空闲任务接口函数*/ OStaskStatHook (); /*统计任务接口函数*/ OSTimeTickHook (); /*时钟节拍接口函数*/ OStaskHookBegin (); /*系统初始化开始接口函数*/ OStaskHookEnd (); /*系统初始化结束接口函数*/ OSTCBInitHook (); /*控制块初始化接口函数*/
唯一必要的函数是OsTaskStkInt()函数。其他9 个函数必须声明, 但可以不包含任何代码。
4.2.1 OSTaskStkInit( )
该函数用于初始化任务堆栈,使任务的堆栈看起来就像刚发生中断一样。即任务被执行时,就像从中断返回一样。
在编写此函数之前,必须先确定任务的堆栈结构。而任务的堆栈结构是与CPU的体系结构、编译器有密切的关联。本移植的堆栈结构如下图所示。
9
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
任务入栈的其他数据 PC LR R12 R11 R10 R9 R8 ... R2 R1 R0 OSEnterSum 空闲空间 图7 移植的堆栈结构
其示意代码为:
OS_STK * OSTaskStkInit(void (*task)(void *pd ), void *pdata,OS_STK *ptos,INT16U opt); {
模拟带参数(pdata)的函数调用; 模拟ISR向量;
按照预先设计的寄存器值初始化堆栈结构; 返回栈顶指针给调用该函数的函数; }
执行OSTaskCreate ( )时,会调用OSTaskStkInit ( )的初始化过程,然后通过OSTCBInit ( )函数调用,将返回的SP指针保存到该任务的TCB 块中。初始状态的堆栈是模拟了一次中断后的堆栈结构,使建立好的进入就绪任务的堆栈与系统发生中断、并且将环境变量保存完毕时的设置与堆栈结构一致。因为任务创建后并不是直接就获得执行,而是通过OSSched ( )函数进行调度分配,当满足执行条件后才能获得执行。为了使调度简单一致,就预先将该任务的PC指针和返回地址LR都指向函数入口,以便被调度时从堆栈中恢复到刚开始运行时的CPU现场。
4.2.2 Hook( )函数
在Os_cpu_c.c文件中还有许多Hook()函数,它们在某个特定的系统动作时被调用,允许执行函数中的用户代码。这些函数默认是空函数,用户根据实际情况添加相关代码。它们分别如下表所示:
栈底 任务环境开始 SP 10
2010届电子信息工程专业毕业设计(论文)
函数名 OSInitHookBehin() OSInitHookEnd() OSTaskCreateHook() OSTaskDelHook() OSTaskSwHook() OSTaskStatHook() OSTCBInitHook() OSTimeTickHook() OSTaskIdleHook()
被执行条件 在开始执行OSInit()函数时被执行 在OSInit()函数结束时被执行 在任务建立时被调用 在任务删除时被调用 在进行任务切换时被调用 被统计任务调用,每秒执行一次 在建立所有的TCB后,由OSTCBInit函数调用 每个时钟节拍产生后被调用 由空闲任务调用 图8 Hook()函数的调用
OSTaskCreateHook()在µC/OS中没有,在由µC/OS 向µC/OS-II升级时,定义一个空函数就可以了。注意其中的赋值语句,如果不把Ptcb赋给Ptcb,有些编译器会产生一个警告错误,说定义的Ptcb变量没有用到。
OSTaskCreateHook() #if OS_CPU_HOOKS_EN
OSTaskCreateHook(OS_TCB *ptcb) {
ptcb = ptcb; //防止编译时出现警告 } #endif
用户还应该使用条件编译管理指令来处理这个函数。只有在OS_CFG.H文件中将OS_CPU_HOOKS _EN设为1时,OSTaskCreateHook()的代码才会生成。这样做的好处是允许用户移植时可在不同文件中定义钩子函数。void OSTaskDelHook ()与void OSTaskCreateHook ()的定义类似。
4.3 OS_CPU_A.ASM的移植
为了方便移植,大部分的 μC/OS-Ⅱ代码是用 C 语言写的,但仍需要用 C 和汇编语言写一些与处理器相关的代码,这是因为μC/OS-Ⅱ在读写处理器寄存器时只能通过汇编语言来实现。这部分代码都放在了OS_CPU_A.ASM文件中。在此文件中需改写4 个简单汇编语言函数。
(1)OSStartHighRdy()函数 (2)OSCtxSw( )函数 (3)OSIntCtxSw()函数 (4)OSTickISR()函数
4.3.1 OSStartHighRdy()函数
操作系统初始化后,开始执行系统内第一个最高优先级的任务。对于第一个执行的任务,不
11
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
需要进行上下文保存,只需恢复任务上下文即可。第一个任务的执行是通过调用汇编子程序OSStartHighRdy 实现的。此子程序首先调用钩子函数OSTaskSwHook(),完成用户扩展的操作系统功能,然后将OSRunnig 的值置为真,表示开始任务的执行,从而保证任务切换操作的正确执行。紧接着从具有最高优先级的任务控制块中取得任务的堆栈指针,初始化堆栈指针寄存器SP 。然后恢复CPSR,恢复其它的寄存器,开始执行最高的优先级的任务。
注意,这里CPRS的恢复也必须用前面所述的软件中断来实现,以保证有效性。 具体代码如下:、
LDR r4,addr_OSTCBCur; /*得到当前任务的 TCB 地址*/ LDR r5,addr_OSTCBHighRdy; /*得到高优先级任务的 TCB 地址*/ LDR r5,[r5]; /*得到堆栈指针*/ LDR sp,[r5]; /*切换到新的堆栈*/
STR r5,[r4]; /*设置新的当前任务的 TCB 地址*/ LDMFD sp!,{r4}; MSR CPSR_cxsf,r4;
LDMFD sp!, {r4} ; /*从栈顶得到新的声明 */ MSR CPSR_cxsf, r4
LDMFD sp!,{r0-r12,lr,pc}; /*开始新的任务*/ END
4.3.2 OSCtxSw( )函数
任务级的上下文切换,当任务因为被阻塞而主动请求CPU调度时被执行,由于此时的任务切换在非异常模式下进行,因此区别于中断级别的任务切换。它的工作是先将当前任务的CPU现场保存到该任务堆栈中,然后获得最高优先级任务的堆栈指针,从该堆栈中恢复此任务的CPU现场,使之继续执行。这样就完成了一次任务切换
任务级上下文切换是由汇编子程序OSCtxSw()实现。它是由操作系统的任务调度函数OSSched()调用,所有的操作都在用户模式下完成(除了使用软件中断进入管理模式改变CPSR)在整个过程中中断是关闭的,因为在上下文切换过程中要访问操作系统的全局变量。
OSCtxSw()函数是一个任务级的任务切换函数。软中断向量指向此函数。在μC/OS-Ⅱ中, 如果任务调用了某个函数, 而该函数的执行结果可能造成系统任务的重新调度, 则在函数的末尾会调用OSSched(),OSSched()查找当前就绪最高优先级的任务, 如果不是当前任务, 则找该任务的TCB 地址, 并复制到变量OSTcbHighRdy()中, 然后通过宏OS_TASK_SW( ) 执行软中断调用OSCtxSw()进行任务切换。变量OSTCBCur 始终包含指向当前运行任务TCB的指针。
具体代码如下:
STMFD sp!, {lr} ; 保存PC 指针 STMFD sp!, {lr} ; 保存lr 指针
STMFD sp!, {r0-r12} ;保存寄存器文件和ret 地址
12
2010届电子信息工程专业毕业设计(论文)
MRS r4, CPSR
STMFD sp!, {r4} ; 保存当前PSR MRS r4, SPSR STMFD sp!, {r4} LDR r4, addr_OSPrioCur LDR r5, addr_OSPrioHighRdy LDRB r6, [r5]
STRB r6, [r4] ; 得到当前任务的TCB 地址 LDR r4, addr_OSTCBCur LDR r5, [r4]
STR sp, [r5] ; 保存栈指针在占先任务的TCB 上 ,取得高优先级任务的TCB 地址 LDR r6, addr_OSTCBHighRdy LDR r6, [r6]
LDR sp, [r6] ;得到新任务的堆栈指针 OSTCBCur = OSTCBHighRdy
STR r6, [r4] ; 设置当前新任务的TCB 地址 LDMFD sp!, {r4} MSR SPSR_cxsf, r4 LDMFD sp!, {r4} MSR CPSR_cxsf, r4
LDMFD sp!, {r0-r12, lr, pc}
4.3.3 OSIntCtxSw()函数
ARM处理器在跳到中断服务程序时,自动关闭IRQ中断。为保证IRQ中断的可重入性,即一个IRQ中断程序能被另一个IRQ中断,需要使用ARM提供的系统模式。因此中断服务程序需要运行在系统模式下。
为了能够跟踪中断服务程序,操作系统提供了两个函数,一个是OSIntEnter(),在开始运行实际的中断服务之前调用;另一个是OSIntExit(),在退出中断服务时调用。由于中断服务程序可能会激活一个更高优先级的任务,所以,OSIntExit()对就绪任务队列进行检查,如果有更高优先级的任务且任务调度允许,则调用中断级的上下文切换例程,保存被中断的任务,运行高优先级的任务。
OSIntCtxSw()过程用于实现中断级的上下文切换,它由OSIntExit()调用。OSIntCtxSw()的主要功能是将被中断的任务的执行环境保存到其堆栈中,而被中断的任务堆栈指针的保存、高优先级任务执行环境的恢复与执行,由例程CmnCtxSw()完成。
因此,实现OSIntCtxSw()的关键在于如何收集被中断任务的上下文。首先必须清楚,从中断发生到中断级上下文切换的过程中,例程的调用关系和处理器模式的变化情况。如图所示:
13
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
任务USR时钟中断时钟中断服务程序TickISRIRQSYSIRQ例程调用SYSOSIntExit例程调用SYSOSIntCtxsw 图9 调用关系和处理器模式的变化情况
从上图可知,被中断任务的返回地址PC、通用寄存器R0-R12以及程序状态寄存器CPSR被保存在IRQ堆栈中,而连接寄存器LR_usr被保存在系统模式的堆栈中(实际上就是被中断任务的堆栈中)。由于中断级的任务切换发生在系统模式,为了访问IRQ堆栈,必须把处理器状态改变到IRQ模式并禁止中断,获取IRQ堆栈指针,将其保存到通用寄存器,然后回到系统模式并禁止中断。
这样,在系统模式下可以访问到被中断任务的返回地址、R0-R12的值以及CPRS的值,而且LR_usr的值也已被保存在系统模式的堆栈中。从而,在系统模式下完成了被中断任务执行环境的保存。 具体代码如下:
STMFD sp! ,{lr}; /* 保存PC 指针*/
STMFD sp! ,{r0- r12}; /* 保存寄存器文件和RET 地址*/ STMFD sp! ,{r4}; /* 保存当前PSR*/
LDR r4,addr_OSTCBCur; /* 得到当前任务的TCB 地址*/ STR sp,[r5]; /* 保存栈指针在占先任务的TCB 上*/ LDR r6,addr_OSTCBHighRdy;/* 取得高优先级任务 的TCB 地址*/ LDR sp,[r6]; /* 得到新任务的堆栈指针*/ LDMFD sp,{r
4.3.4 OSTickISR()函数
当时钟中断(IRQ)到来时,处理器跳转到时钟中断服务程序,时钟中断服务程序主要调用函数OSTimeTick(),这个函数处理与系统时钟相关的工作,如将每个任务的等待时间减1、更新系统时间等等。
时钟中断服务程序由汇编子程序OSTickISR()实现。因为OSTickISR()的具体实现与中断级上下文切换的实现有很大的关系,所以对其具体的实现步骤进行较详细的分析:
1)它首先保存被中断程序的上下文环境。将被中断程序的返回地址、通用寄存器以及程序状态寄存器保存到IRQ堆栈中,此时,IRQ堆栈中的内容如图所示(堆栈指针寄存器指向内容为CPSR的堆栈单元)。IRQ堆栈中保存的寄存器内容非常重要,因为它影响中断级上下文切换的实现。在保存被中断任务执行环境的时候,中断级上下文切换必须从IRQ堆栈中读取相关的寄存器内容。 IRQ 堆栈的内容如下图:
/* 设置当前新任务的TCB 地址*/
14
2010届电子信息工程专业毕业设计(论文)
栈底(高地址)...PC (LR_irq)R12R11...R0CPSR(SPSR_irq)...栈顶(底地址)
图10 IRQ堆栈的内容
2)执行标识中断结束的指令。这是通过向AIC(高级中断控制器)的中断结束命令寄存器写一个任意数实现的。
3)切换到系统模式并允许IRQ和FIQ中断。为了允许中断的嵌套,在开始中断服务以前,必须进入系统模式。因为如果在IRQ模式下允许中断嵌套,那么,当下一个IRQ中断发生的时候,就会破坏当前中断的执行环境。
4)保存系统模式下相关的寄存器。主要是连接寄存器LR_usr(),因为系统模式和用户模式共用寄存器组,该操作实际上是把LR_usr()保存到了用户模式的堆栈中(被中断任务的堆栈中),这个寄存器的内容在中断级任务切换的时候要用到,所以必须保存。
5)在调用OSTimeTick()函数之前,先调用操作系统提供的OSIntEnter()函数,以使操作系统对中断程序进行跟踪。调用OSTimeTick()之后,再调用函数OSIntExit(),通知操作系统中断完成。如果就绪队列中有更高优先级的任务且允许任务调度,OSIntExit()则进行中断级任务切换(在后面论述)。如果没有更高优先级的任务,则恢复系统模式下保存的寄存器,并切换到IRQ模式且禁止中断,恢复被中断任务的上下文环境,重新执行被中断的任务 具体代码如下:
STMDB SP!,{r0-r11,lr} MRS R0, CPSR
ORR R0, R0, #0x80 ; 设置中断禁止标 MRS CPSR_cxsf, r0 ;中断结束 LDR R0, =I_ISPC LDR R1, =BIT_TIMER0 STR R1, [R0] BL IrqStart BL OSTimeTick BL IrqFinish
LDR R0, =need_to_swap_context LDR R2, [R0]
15
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
CMP R2, #1 LDREQ PC, =_CON_SW
通过前面的分析,我们可以画出下面这张结构图:
流程图保存当前任务的寄存器组中断嵌套数加1切换到系统模式执行中断服务程序中断服务程序ISR关中断执行OSInitExit()切换到IRQ模式判断是否需要进行任务切换在ISR中可以打开中断实现中断嵌套切换任务或返回
图11 中断服务程序流程图
完成上述工作后, μC/OS-Ⅱ的就移植代码编写完毕,但是否可以正常运行还需要进行系统初始化、移植测试,以保证其在S3C2440板上可以正常运行。
5.嵌入式系统的初始化
5.1初始化程序的下载执行
1)通过编程器将可执行目标文件烧写到BootROM(ROM、EPROM、FLASH)等;
2)通过串行口和网口下载执行目标文件,要求宿主机系统上有数据传输工具程序、目标机装载器、嵌入式监视器或目标机系统上的调试代理。 3)通过JTAG或BDM接口下载;
16
2010届电子信息工程专业毕业设计(论文)
5.2嵌入式系统的初始化过程
最 1复位向量小 启 动 硬件2最小硬件代初始化初始化码BSP
3其余硬件 初始化 4RTOS初始化 RTOSRTOS 初始化5部件初始化RTOS 6启动RTOS
软件应用初始化7启动应用程序程序 图12 嵌入式系统初始化过程
5.2.1硬件初始化阶段
1复位向量最小启动2最小硬件 代
初始化码BSP 其余硬件
3初始化 图13 硬件初始化阶段
1、复位向量
ENTRY
b ResetHandler ;for debug b HandlerUndef ;handlerUndef b HandlerSWI ;SWI interrupt handler b HandlerPabort ;handlerPAbort
17
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
b HandlerDabort ;handlerDAbort b .
;handlerReserved
b HandlerIRQ
b HandlerFIQ 2、最小硬件初始化
1)设置适当的寄存器,使嵌入式处理器处于一个已知的状态: 获得CPU的类型;
获得或设置CPU的时钟频率。 2)禁止中断和高速缓存
3)初始化内存控制器、内存芯片和高速缓存单元,包括: 得到内存的开始地址; 得到内存的大小;
如果有要求,则还需要进行主存测试; 3、其余硬件初始化
1)引导代码调用合适的函数对目标机系统上的全部硬件部件进行初始化,包括:建立执行处理程序 初始化中断处理程序 初始化总线接口
初始化板级外设得到内存的开始地址;
5.2.2 RTOS初始化阶段
4RTOS 初始化 RTOSRTOS 初始化5部件初始化RTOS 6启动RTOS
图14 RTOS初始化阶段
18
2010届电子信息工程专业毕业设计(论文)
5.3 ARM920T系统初始化的一般过程
启动(系统上电/复位) 从程序入口点 关闭中断 初始化时钟等硬件相关寄存器 初始化存储器系统 初始化C所需要的存储器空间 调用C入口函数
图15 ARM920T系统初始化的一般过程
5.3.1设置程序入口指针
1) 上电复位后直接到程序入口点执行,入口点一般为一个跳转表,跳转到复位处理程序处
开始执行ARM9TDMI系统的初始化;
2) 启动程序首先必须定义入中指针,而且整个应用程序只有一个入口指针 AREA Boot,CODE,READONLY ENTRY /*设置程序入口指针*/
5.3.2 设置中断向量
1) ARM要求中断向量必须设置在从OX00000000地址开始,连续8*4字节的地址空间; 2) 向量表包含一系列跳转指令,跳转到相应的中断服务程序;
3) 对各未用中断,使其指向一个含返回指令的哑函数,以防止错误中断引起系统的混乱;
19
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
中断向量表的程序 AREA Boot,CODE,READONLY ENTRY
B Reset_handler B Undef_Handler B SWI_Handler B PreAbort_Handler
B . ;预定中断,停止 B IRQ_handler B FIQ_handler
5.4初始化存储器系统
存储器类型和时序配置(参考芯片手册,设置与内存映射相关的寄存器)
1) 一个复杂的系统可能存在多种存储器类型的接口,需要根据实际的系统设计对此加以正
确配置。对同一种存储器类型来说,也因为访问速度的差异,需要不同的时序设置。 2) 通常Flash 和SRAM 同属于静态存储器类型,可以合用同一个存储器端口; 3) 而DRAM 因为动态刷新和地址线复用等特性,通常配有专用的存储器端口。
4) 存储器端口的接口时序优化是非常重要的,影响到整个系统的性能。因为一般系统运行
的速度瓶颈都存在于存储器访问,所以存储器访问时序应尽可能地快;但同时又要考虑由此带来的稳定性问题。只有根据具体选定的芯片,进行多次的测试之后,才能确定最佳的时序配置。
5.4.1存储器地址分布
1) 有些系统具有非常灵活的存储器地址分配特性,进行存储器初始化设计的时候一定要根
据应用程序的具体要求来完成地址分配。
2) 一种典型的情况是启动ROM 的地址重映射(remap)。当一个系统上电后程序将自动从0
地址处开始执行,因此在系统的初始状态,必须保证在0地址处存在正确的代码,即要求0地址开始处的存储器是非易性的ROM 或Flash 等。但是因为ROM 或Flash 的访问速度相对较慢,每次中断发生后都要从读取ROM 或Flash 上面的向量表开始,影响了中断响应速度。因此有的系统便提供一种灵活的地址重映射方法,可以把0地址重新指向到RAM 中去。在这种地址映射的变化过程当中,程序员需要仔细考虑的是程序的执行流程不能被这种变化所打断。
5.4.2 ROM地址重映射的实现
20
2010届电子信息工程专业毕业设计(论文)
Flash 0x0200
(remap) 0x0204 0x0200 RAM (boot code) (remap) 0x0100
(Reset_handler)
(boot code) …… (Reset_handler
0x0000 B Reset_Handler
0x0000
B Reset_Handler 图16 ROM地址重映射的实现
为保证重映射之后提供正确的中断入口地址,在重映射之前就必须把中断和异常向量表拷贝
到内部RAM中。其程序实现如下:
mov r8, #RAM_BASE_BOOT
//RAM_BASE_BOOT是重映射前内部RAM区地址
add r9, pc,#-(8+.-VectorTable) //VectorTale是异常向量表入口 ldmia r9!, {r0-r7} //读8个异常向量 stmia r8!, {r0-r7} //保存8个异常向量到RAM区 ldmia r9!, {r0-r4} //读5个异常处理程序绝对地址
stmia r8!, {r0-r4} //保存5个异常处理程序绝对地址到RAM区
5.5初始化堆栈
1) ARM处理器有好几种运行状态(模式),各种状态都需要有自己的堆栈,所以需要分别为
这些堆栈分配空间并设置好各自的堆栈指针
2) 每一种状态的堆栈指针寄存器(SP)都是独立的(System 和User 模式使用相同的SP 寄
存器)。因此对程序中需要用到的每一种模式都要给SP寄存器定义一个堆栈地址。方法是改变状态寄存器CPSR内的状态位,使处理器切换到不同的状态,然后给SP赋值。(意不要切换到User模式进行User 模式的堆栈设置,因为进入User 模式后就不能再操作CPSR回到别的模式了。可能会对接下去的程序执行造成影响。
3) 一般堆栈的大小要根据需要而定,但是要尽可能给堆栈分配快速和高带宽的存储器。堆
栈性能的提高对系统整体性能的影响是非常明显的。
堆栈初始化代码示例:
MRS R0, CPSR ; CPSR -> R0
BIC R0, R0, #MODEMASK ; 安全起见,屏蔽模式位以外的其它位
21
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
ORR R1, R0, #IRQMODE ; 把设置模式位设置成需要的模式(IRQ) MSR CPSR_cxsf, R1 ; 转到IRQ 模式 LDR SP, =UndefStack ; 设置SP_irq
ORR R1,R0,#FIQMODE
MSR CPSR_cxsf, R1 ; FIQMode LDR SP, =FIQStack
ORR R1, R0, #SVCMODE
MSR CPSR_cxsf, R1 ; SVCMode LDR SP, =SVCStack
5.6初始化应用程序执行环境
只定义了变量名的全局变量ZI(Zero initialzed R/W Data)定义时带初始值的全局变量RW(R/W Data)RO(Code + RO Data)
图17 应用执行环境初始化
映像一开始总是存储在ROM/Flash 里面的,其RO 部分既可以在ROM/Flash里面执行,也可以转移到速度更快的RAM 中去;而RW 和ZI 这两部分必须是需要转移到可写的RAM 里去的。所谓应用程序执行环境的初始化,就是完成必要的从ROM 到RAM 的数据传输和内容清零。
5.6.1初始化C环境
1) 在目标文件中,代码、数据放在不同的段中。源文件编译链接生成含.data、.text段的目
标文件,且链接器生成的.data段是以系统RAM为参考地址
2) 故在系统启动时需要拷贝ROM或FLASH中的.data段到RAM,以完成对RAM的初始
化。在初始化期间应将系统需要读写的数据和变量从ROM拷贝到RAM里运行
链接器产生的符号表
1) 符号由链接器自动产生,只读段(read-only RO)就是代码段,读写段(read-write RW)
是已经初始化的全局变量,而零初始化段(zero-initialized section ZI)中存放未初始化的全局变量;
编译结果 22
2010届电子信息工程专业毕业设计(论文)
符号表示 Image$$RO$$ Base Image$$RO$$ Limit Image$$RW$$ Base Image$$RW$$ Limit Image$$ZI$$ Base Image$$ZI$$ Limit 图18 C环境初始化 2) C环境初始化,就是利用上述符号初始化RW和ZI段以使后面使用的全局变量的C程序正常运行;
3) 这里有两个循环,第一个循环把预初始化的数据段RW(位于代码段的后面)复制到RAM
中,另一个循环把未初始化的数据段ZI初始化为0,也就是实现把从ROM中的.data段拷贝到RAM,对ZI段内的数据初始化为0,以完成对C环境的实始化;
5.6.2改变处理器模式
除用户模式以外,其他6种模式都是特权模式。因为在初始化过程中许多操作需要在特权模式下才能进行(比如CPSR 的修改),所以要特别注意不能过早地进入用户模式。一般地,在初始化过程中会经历以下一些模式变化:
(堆栈初始化阶段)超级模式(Supervisor)意义 只读段的起始地址 只读段结束的后首地址 读写段的起始地址 读写段结束的后首地址 零初始化段的起始地址 零初始化结束的后首地址 多种特权模式变化设置成用户程序运行模式复位后的缺省模式注意不要进入用户模式用户选择 图19 处理器运行模式 5.6.3调用C程序
对main函数的调用进入uc/OS的入口,通过这个入口就进入uC/OS的主函数,启动对uC/OS的初始化
例
IMPORT Main
b Main ;C 入口
5.7 uC/OS系统的初始化
完成了前面的硬件初始化和运行环境的相关设置后,进入Main(), Main()是uC/OS的入口函数,启动对uC/OS的初始化
23
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
5.7.1 ARM的硬件抽象层——uHALuC/OS
1) ARM公司为操作系统的开发提供了一个硬件抽象层HAL,称为uHAL;
2) 从结构上看,uHAL是一组库程序,需要说明的是,uHAL并不是专门为uC/OS准备的,
甚至也不是专为操作系统内核准备的; 3) uHAL只是个针对ARM核的函数库; 4) uC/OS是建立在uHAL的基础之上的; Void main(viod) {
…………..
ARMTargetInit(); /*初始化系统的硬件;*/
OSInit(); /*任务的建立,消息机制的建立;*/ ……………… ARMTargetStart(); OSStart(); }
5.7.2 ARMTargetInit()函数结构
ARMTargetInit() 调uHAL打印接口打印系统信息 调用uHAL函数禁止所有中断 调用uHAL函数对中断初始化 uHAL函数对ARM计数器初始化 结束
图20 ARMTargetInit()函数结构
24
2010届电子信息工程专业毕业设计(论文)
5.7.3 uHAL的功能
1) uHAL的作用之一是在操作系统本身进入正常运行之前,为系统提供基本的输入输出手段,
例如uHALr_printf()等;
2) uHAL还要为操作系统的运行准备一个基本的运行环境,具体包括下列各种初始化: 通过uHAL_ResetMMU(),将MMU设置在一个确定的初始状态; 通过ARMDisable()关闭中断;
通过uHAL_InitInterrupts()设置中断向量处理程序; 通过uHAL_InitTimer()对系统使用的计数器进行初始化
6.移植测试
6.1测试移植代码
当用户为自己的处理器做完μC/OS-Ⅱ的移植后,紧接着的工作就是验证移植的μC/OS-Ⅱ能否正常的工作,而这可能是移植中最复杂的一步。应该首先不加任何应用代码来测试移植好的μC/OS-Ⅱ,也就是说,应该首先测试内核自身的运行状况。这样做的原因是:
(1)尽量避免将事情复杂化;
(2)如果有些部分没有正常工作,可以明白是移植本身的问题,而不是应用代码产生的问题。 如果已经将2个基本的任务和节拍中断运行起来,那么接下来添加应用任务是很简单的事情。
可以使用各种不同的技术测试自己的移植工作,这取决于用户个人在嵌入式系统方面的经验和对处理器的理解。一般情况下通过四个步骤测试移植代码:
1)确保C编译器、汇编编译器及链接器正常工作 2)验证OSTskStkInit() 和OSStartHighRdy()函数 3)验证OSCtxSw() 函数
4)验证OSIntCtxSw()和OSTickISR()函数
6.1.1确保C编译器、汇编编译器及链接器正常工作
当修改完需要根据CPU更改的文件后,紧接着要把这些文件和μC/OS-Ⅱ中与处理器无关的文件一同编译和链接。显然这个步骤取决于使用的编译器,在这期间是无代码的测试。最小的测试程序如下:
#include “includes.h” Void main(void) {
osinit(); Osstart(); }
6.1.2验证OSTskStkInit() 和OSStartHighRdy()函数
如果上一步的测试完成了,就可以测试移植好的μC/OS-Ⅱ代码,真正的测试工作就可以开始了。在OS_CFG.H文件中设置OS_TASK_STAT_EN为0,只让一个空闲任务OS_TaskIdle()运行,检查是否出错.如果调试器在OS_TaskIdle()的循环中运行,且在无限循环中已经执行几次,那
25
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
么就已经验证了OSTskStkInit() 和OSStartHighRdy()函数是成功的。
6.1.3验证OSCtxSw() 函数
如果上一步测试成功,这一步代码验证就比较容易了。已经因为知道由OSTskStkInit() 初始化的堆栈结构是正确的。在这步测试中,添加一个应用程序,并不断切换到空闲任务。在此之前,应该保证已经正确设置了软中断向量或指令陷阱TRAP向量,使它指向OSCtxSw() 。测试程序如下:
#include “includes.h” Void main(void) {
osinit();
ostaskcreate(testtask,(void*)0,&testtask[99],0); Osstart(); }
void testtask(void *pdata) {pdata= pdata;
While(1) {
ostimedly(1);
} }
现在单步执行进入OSTimeDly()。 OSTimeDly()调用OS_Sched()函数,而OS_Sched()调用汇编语言编写的OSCtxSw() 函数。当进入OSCtxSw() 的代码,看到TestTask()任务的寄存器已经保存到它的任务堆栈,而OS_TaskIdle()的寄存器被调入CPU.
如果OSCtxSw()并没有将用户带入OS_TaskIdle(),则应检查原因,纠正OSCtxSw()中的错误。
6.1.4验证OSIntCtxSw()和OSTickISR()函数
OSIntCtxSw()很像OSCtxSw() ,且比OSCtxSw()简单。实际上,OSIntCtxSw()中的多数代码可从OSCtxSw()中得到。在此测试之前,应该保证时钟中断向量指向了时钟节拍中断服务子程序,然后,初始化时钟节拍并中断。
6.2在S3C2440上测试移植结果
6.2.1编译uCOS2
本次移植所用开发板为友善之臂的Mini2440,在移植时写了液晶显示和LED显示。用ADS1.2打开所编写的程序,如下图所示:
26
2010届电子信息工程专业毕业设计(论文)
图21 移植代码 这时点击project→Make或者直接按F7键,开始编译uCOS2项目,编译完成后,生成2440ucos2.Bin可执行文件,如图:
图22 生成2440ucos2.Bin可执行文件
27
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
6.2.2把uCOS2下载到内存中运行
(1)连接好开发板电源,串口线,USB线,并设置开发板为Nor Flash启动系统,为别打开超级终端和DNW,上电启动开发板。
(2)保证USB驱动已经安装好,这时可以看到DNW的标题栏显示[USB:OK],如图所示:
图23 DNW的运行界面
(3)点DNW菜单Configuration,设置USB下载运行地址0x30000000
图24 DNW的配置
28
2010届电子信息工程专业毕业设计(论文)
(4)这时在超级终端的BIOS的功能菜单中选择功能号[d],出现USB下载等待提示信息:
图25 超级终端连接开发板后的界面
(5)点击DNW程序的”USB” →”Transmit’,选择刚刚编译出的镜像文件,就开始下载了。 (6)下载结束后,会自动运行,串口出现如下信息:
图26 下载成功后超级终端的界面
29
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
最终在开发板上可以看到移植后运行的结果,在LCD上显示一幅图片,同时LED在闪烁。如下图所示:
由上图可知,本次移植成功!
7.结论
本文介绍了将μC/OS-II这种稳定可靠的实时嵌入式内核移植到S3C2440上,以友善之臂的Mini2440开发板为对象,通过驱动LCD显示图像和LED闪烁来判断是否成功移植了μC/OS-II。经测试,移植好的μC/OS-II代码能正常的在S3C2440处理器中稳定运行。
μC/OS-II是开源的实时嵌入式操作系统,在工业控制与机器人控制具有广泛的应用前景,已经被移植到各种结构的微处理器上。RTOS是当今嵌入式应用的热点,应用RTOS可以使产品更可靠、功能更强大而开发周期更短。 将μC/OS-II这种稳定可靠的实时嵌入式内核移植到S3C2440上,取代传统的前后台系统的设计方法,可以更好更大限度的发挥S3C2440的优异性能。
采用基于ARM9的S3C2440嵌入式微处理器,可以使系统具备高性能的运算能力的同时便于与各种外设连接扩展,简化了硬件设计,维持小型化的同时降低了系统成本。μC/OS-II作为一
30
2010届电子信息工程专业毕业设计(论文)
个源代码公开的操作系统,在具体应用中稳定可靠,并且支持uIP TCP/IP协议栈、ucGUI等,可扩展性强,功能强大。本系统采ARM9+uC/OS II开发设计,具有精度高、运行稳定、实时性好、抗干扰能力强、性价比高的特点,可以在各种工业场合中广泛应用,达到了设计的初衷。
μC /OS-Ⅱ提供的仅仅是一个任务调度的内核,将其移植到S3C2440开发板上以后,要想实现一个相对完整、实用的RTOS,还需要进行相当多的扩展性工作。这部分工作主要包括:建立文件系统、为外部设备建立驱动程序并规范相应的API函数、创建图形用户接口( GUI)函数、建立其他实用的应用程序接口(API)函数等。鉴于毕业设计的时间有限,对于移植后,RTOS体系结构的扩展,触摸屏的驱动还没有完成,在以后的学习与工作中,还有待进一步的深入研究。
致谢
衷心地感谢我的指导老师谢小维副教授的悉心指导帮助!从开题一直到定稿,谢老师每次对我的指导都令我受益匪浅,如沐春风。他严肃的科学态度、精益求精的工作作风深深地感染和激励着我。在此谨向谢老师致以最诚挚的谢意和最崇高的敬意!
其次,还要感谢我的父母,他们给了我在大学校园学习的机会,而且在成长过程中他们给予我无微不至的关怀和教我如何做人。
最后,我还要衷心感谢大学期间教育、关心我的老师们,互相帮助的同学们。
参考文献
[1]Jean J.Labrosse.嵌入式实时操作系统μC/OS-II.第2版.邵贝贝等译[M].北京:北京航空航天大学出版社,2003
[2] 马忠梅. 徐英慧. ARM嵌入式处理器结构与应用处理[M]. 北京:北京航空航天大学出版社,2002
[3] 周立功. ARM嵌入式系统基础教程[M]。 北京:北京航空航天大学出版社,2005 [4] 陈是知. μC/OS-II内核分析、移植与驱动程序开发[M].北京:人民邮电出版社,2007 [5] μC/OS-II官方网站.http://www.ucos-ii.com
[6] ARMArchitectureReferenceManual.http://www.arm.com [7] 三星官网. http://www.samsung.com
[8] 杨宗德,张兵. μC/OS-II标准教程[M]. 北京:人民邮电出版社,2009 [9] 王田苗. 基于ARM微处理器与μC/OS-II实时操作系[M].第二版. 北京:清华大学出版社,2003
[10] 张勇,方勤,蔡鹏. μC/OS-II原理与ARM应用程序设计[M]. 西安电子科技大学出版社,2010 [11] 吴勇忠. 嵌入式实时操作系统μC/OS-II教程[M]. 西安电子科技大学出版社,2007
31
陈利顺 实时操作系统μCOS-II在ARM上的移植研究
[12] 杜春雷. ARM体系结构与编程[M]. 清华大学出版社,2003
[13] 斯洛斯. ARM嵌入式系统开发:软件设计与优化[M]. 北京:北京航空航天大学出版社,2005 [14] W. Richard Stevens, Stephen A. Rago. Advanced Programming in the UNIX® Environment: Second Edition[M]. Addison Wesley Professional,2005
[15] 吴倚龙, 郝卫东, 赵瑞芳.uCGUI和uC/OS II在S3C2410 上的整合移植实现[J]. 桂林电子工业学院学报,2006,4
Embedded real time operating system MicroC / OS-II on the ARM transplantation
CHEN Li-shun Grade 2006
Major in electronic and information engineering Physical and electronic technology department
Chongqing Three Gorges University Wanzhou Chongqing 404000
Abstract: This design uses Samsung's production of a nuclear-based high-performance
low-power ARM920T soc S3C2440 chip hardware platform as a transplant. Real-time operating system μC / OS-II features, architecture, the conditions required for transplantation, transplant need to prepare the documents needed for transplant depth understanding of the compiler, by writing portable code, on the transplantation test achieve the μC / OS-II in the S3C2440 transplant.
Key words:The embedded system μC/OS-II Transplantation
32
因篇幅问题不能全部显示,请点此查看更多更全内容