摘 要:嵌入式实时操作系统在目标处理器平台上的移植是嵌入式软件开发的基础和前提。论文实现了源码公开的嵌入式实时操作系统μC/OS-II在ARM7微控制器LPC2210上的成功移植,并研究了在移植过程中的关键问题。构成了一个功能强大的嵌入式开发基础平台。
关键词:实时操作系统;μC/OS-II;LPC2210微控制器;移植
Abstract: The porting embedded RTOS to target processor is the foundation and precondition of the software development in embedded system. In the paper the open source RTOS μC/OS-II is successfully ported to LPC2210 which is one of ARM7 microcontrollers. It also researches the key points in the course of porting. A powerful embedded foundational development platform is founded.
Key words: RTOS μC/OS-II LPC2210 Microcontroller Porting
1 引言
嵌入式系统是以嵌入式计算机技术为核心,面向用户、面向产品、面向应用,软硬件可裁减,适用于对功能、可靠性、成本、体积、功耗等综合性能有严格要求的专用计算机系统[1]。今天随着科技的飞速发展,嵌入式系统已经在科学研究、工程设计、军事技术、各类产业及日常生活的各个方面得到了广泛的应用。嵌入式实时操作系统在嵌入式系统中有着极为重要的作用,特别是在功能复杂结构庞大的应用系统中,嵌入式实时操作系统可以提高应用系统的可靠性,充分发挥32位CPU的多任务处理能力。研究嵌入式系统的基础性工作就是实现嵌入式实时操作系统在目标处理器平台上的移植。嵌入式实时操作系统是嵌入式软件运行的基础平台,由其内核负责管理各任务的创建、删除、调度及任务之间的通信和控制。本文研究了将源代码公开的嵌入式实时操作系统μC/OS-II移植到PHILIPS公司的ARM微控制器LPC2210上,构成软硬件功能强大的嵌入式开发基础平台的方法及实现技术。
2 实时操作系统μC/OS-II和微控制器LPC2210
2.1 实时操作系统μC/OS-II
μC/OS-II是一款源码开放的实时操作系统内核,具有良好的可移植性,大部分源代码都是用ANSI C编写。μC/OS-II是一个完全抢占式内核,它总是运行最高优先级的就绪任务,但不支持时间片轮转法任务调度。μC/OS-II提供了许多系统服务,如邮箱,信号量,消息队列,内存管理及时间管理等。μC/OS-II可以移植到很多的处理器上,它能运行在大部分的8位-64位的微处理器和数字信号处理器DSP上。

μC/OS-II的软件体系结构如图1所示。应用程序软件是用户根据需求编写与应用相关的代码定制合适的内核服务功能,实现对μC/OS-II的裁剪。与处理器无关的代码就是操作系统的内核,μC/OS-II内核提供所有的系统服务。这部分代码完全公开,本文采用μC/OS-II(v2.52)版本。内核将应用程序与底层硬件有机的结合成一个实时系统。与处理器相关的代码可以看作是内核与硬件之间的中间层,它实现了同一内核应用于不同硬件体系的目标。处理器不同,这部分代码也不同,由用户自行编写。所谓移植就是编写与处理器相关的代码和进行一些μC/OS-II的设置。
2.2 微控制器LPC2210
LPC2210是PHILIPS公司的一款16∕32位ARM7TDMI-S™CPU微控制器。它是基于ARM通用体系结构的RISC微处理器,具有低成本、低功耗、高性能等优点。LPC2210CPU支持实时仿真和嵌入式跟踪;具有标准32位ARM指令集和16位THUMB指令集;144管脚封装结构,16K字节的片内静态RAM,2个32位定时器,8路10位ADC,PWM输出以及多达9个外部中断,通过配置总线可提供76个GPIO;与片内存储器控制器接口为ARM7局部总线,与中断控制器接口为AMBA高性能总线,连接片内外设为VLSI外设总线。
3 μC/OS-II在LPC2210上的移植
3.1 移植概要
移植工作主要集中在与处理器相关的3个文件,OS_CPU.H,OS_CPU_C.C,OS_CPU_A.S。其中OS_CPU.H文件中主要包含与编译器相关的数据类型定义、堆栈类型定义、两个宏定义和几个函数说明。由于ADSv1.2的C语言编译器只支持满递减堆栈,这里定义堆栈的增长方向为从上往下。OS_CPU_C.C中包含与移植有关的6个C函数,它们为OSTaskStkInit(), OSTaskCreateHook(),OSTaskDelHook(),OSTaskSwHook(),TaskStatHook(),OSTimeTickHook()。除第一个任务堆栈初始化函数外的5个函数为钩子函数,它们需要声明,没有实际内容。由系统函数调用,以便用户能在操作系统中加入自己需要的功能。OS_CPU_A.S中包含与移植有关的4个汇编语言函数,它们是OSStartHighRdy(),OSCtxSw(),OSIntCtxSw(),OSTickISR()。
3.2 μC/OS-II在LPC2210上移植的关键问题分析
3.2.1 开∕关中断的实现
在μC/OS-II中开∕关中断的实现是通过OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()两个宏来实现的。μC/OS-II与其他实时内核一样,在访问临界区代码之前必须关中断,访问之后开中断。而这两个宏保证了μC/OS-II的临界区代码不会被多个任务或中断服务程序同时访问,避免造成μC/OS-II全局变量的不一致。有两种实现方法:
方法1:在OS_ENTER_CRITICAL()中调用处理器的中断禁止指令禁止中断,在OS_EXIT_CRITICAL()中调用中断允许指令开中断。该方法可以减少中断延迟时间,但如果用户在禁止中断的情况下调用μC/OS-II功能函数,从μC/OS-II返回的时候,中断可能会变成允许,这不是用户所期望的。
方法2:执行OS_ENTER_CRITICAL()时先将中断禁止状态保存到堆栈中,然后禁止中断,执行OS_EXIT_CRITICAL()时再从堆栈中恢复原来的中断状态。可以解决方法1的问题,但延长了中断响应时间。
本文使用了软件中断功能。利用软中断进入处理器的管理模式,然后修改程序状态保存寄存器SPSR中的相应控制位,软中断退出时会将SPSR恢复到程序状态寄存器CPSR。这样就改变了CPSR中的相应控制位从而实现了中断的开∕关。实现开∕关中断的嵌入汇编代码如下。

3.2.2 任务堆栈的初始化
任务堆栈初始化函数OSTaskStkInit()是在用户建立任务时由任务建立函数OSTaskCreate()调用。该函数基于任务的堆栈结构。LPC2210微控制器基于ARM7TDMI架构,本文的任务堆栈结构设计如图2。堆栈空间从高到低依次存放着PC,LR,R12,R11,……R1,R0,CPSR,OsEnterSum。每个任务都有独立的OsEnterSum,在任务切换时保存和恢复各自的OsEnterSum值。各个任务开关中断的状态可以不同,这样实现了开关中断的嵌套。

当堆栈任务初始化完成后,OSTaskStkInit()返回新的堆栈指针。在任务建立函数OSTaskCreate()执行时会调用OSTaskStkInit()的初始化过程,然后将返回的堆栈指针保存到任务控制块OS_TCB中。
3.2.3 OSStartHighRdy()函数的实现
μC/OS-II的启动多任务环境的函数是OSStart(),用户在调用该函数之前,必须建立一个或更多任务。OSStart()最终调用函数OSStartHighRdy()运行优先级最高的任务。OSStartHighRdy()函数的汇编代码如下。
MSR CPSR_c, #(NoInt|SYS32Mode) ;进入系统模式
LDR R4, =OSRunning ;设置OSRunning为真,标识程序开始运行
MOV R5, #1
STRB R5, [R4]
BL OSTaskSwHook ;调用钩子函数
LDR R6, =OSTCBHighRdy ;加载OS_TCB中最高优先级任务的地址
LDR R6, [R6]
B OSIntCtxSw_1 ;程序跳转,获取新任务堆栈指针
3.2.4 OSCtxSw()函数的实现
OSCtxSw()函数是由任务级任务切换函数OS_TASK_SW()调用,实现从低优先级向高优先级的切换。本文任务级切换是通过SWI软中断(软中断号为0x00)来实现。该中断完成的功能是:保存任务的环境变量;将当前任务的堆栈指针SP存入任务控制块OS_TCB中;载入就绪最高优先级任务的堆栈指针SP;恢复就绪最高优先级任务的环境变量;中断返回。软中断的异常处理程序挂接到CPU内核,通过修改启动代码里的异常向量表来实现。中断服务程序与CPU芯片相关中断源的挂接通过以下两种方式来实现。
(1) 增加汇编接口的支持
在文件IRQ.S的适当位置添加如下的程序代码,其中Xxx替换为所需要的字符串。
Xxx_Handler HANDLER Xxx_Exception
(2) 初始化向量中断控制器
代码如下,其中M为分配给中断的优先级,N为中断的通道号。该代码位于文件target.c中。
Extern void Xxx_Handler (void);
VICVectAddrM = (uint32) Xxx_Handler;
VICVectCntlM = (0x20|N);
VICIntEnable = 1<<N;
3.2.5 OSIntCtxSw()函数的实现
OSIntCtxSw()是一个中断级的任务切换函数,在中断退出时由函数OSIntExit()调用。在中断服务程序中,当发现有高优先级任务等待的时钟信号到来时,在中断退出后并不返回被中断任务,而是直接调度就绪的最高优先级任务执行,从而尽快响应高优先级的任务,保证了系统的实时性。OSIntCtxSw()函数的基本原理与任务级的切换相同,只是由于进入中断时已经保存了被中断任务的环境变量,就不进行类似操作,只需要对堆栈指针进行调整。在中断执行过程中堆栈的内容以及堆栈指针的调整如图3所示。
|
|
|
|
|
|
3.2.6 OSTickISR()函数的实现
系统时钟节拍中断函数OSTickISR()是一个周期性中断,为内核提供时钟节拍。其周期决定了内核所能给应用系统提供的最小时间间隔服务。OSTickISR()函数的功能通过在中断服务程序中调用OSTimeTick()函数来实现。也就是在中断处理程序代码段的用户代码中调用OSTimeTick()。

3.2.7 内核编译与下载
以上完成了μC/OS-II在LPC2210上的移植工作。为了测试移植代码的运行情况,编写了一个2任务的简单测试程序。一个任务用于检测按键输入,另一个任务用于控制蜂鸣器蜂鸣。程序中设置蜂鸣器控制任务的优先级高于按键检测任务的优先级。蜂鸣器控制任务平时处于等待状态,当按键检测任务检测到有效按键输入时,立即执行蜂鸣器控制任务。LPC2210没有片内FLASH,但外扩了16MB的FLASH用来存储数据和程序。在ADSv1.2中选择生成目标为RelOutChip,同时配置存储器组为Bank0-FLASH和Bank1-RAM,然后编译连接工程。最后选择Project→Debug,启动AXD进行JTAG仿真调试。程序脱机运行稳定,测试结果正确,表明本移植成功。接下来根据μC/OS-II的编程规范和现有的硬件基础制定API规范及应用程序编写规范,构建一个嵌入式的软件开发平台。
4 结论
μC/OS-II作为一个优秀的嵌入式实时操作系统已经被移植到各种体系结构的微处理器上。在嵌入式系统领域基于ARM体系架构的微处理器获得了绝对优势的应用和支持,所以研究μC/OS-II在ARM微处理器上的移植和应用,能够使我们更深刻的了解实时操作系统的内核原理和工作机制,加快基于ARM微处理器的应用和开发,更好的服务于国民经济的发展。论文成功实现了μC/OS-II在LPC2210上的移植,并通过简单的多任务例程得到验证。下一步的工作是构造一个基于μC/OS-II内核的RTOS软件开发平台,研究其在精细农业中的应用。
参考文献
[1] 周立功等.ARM与嵌入式系统基础教程[M]. 广州周立功单片机发展有限公司, 2004.
[2] Jean J.Labrosse著,邵贝贝译.μC/OS-II—源码公开的实时嵌入式操作系统[M]. 北京:中国电力出版社,2001.
[3] PHILIPS公司. LPC2200 User Manual. PHILIPS公司, 2004.
[4] 张静,张凯. 实时操作系统μC/OS-II在ARM7上的移植研究与实现[J].计算机工程与应用,2004,(4):100-102,153.
[5] 赵宁,陈明. 嵌入式操作系统μC/OS-II在ARM上的移植与应用[J].计算机技术与应用,2004,(4):29-31,34.
本文介绍了嵌入式实时操作系统μC/OS-II在ARM7微控制器LPC2210上的移植过程及关键技术。通过对μC/OS-II核心文件的修改与配置,实现了中断管理、任务堆栈初始化等功能。测试结果表明移植成功。
3880

被折叠的 条评论
为什么被折叠?



