|
摘要 随着嵌入式计算技术的飞速发展,多种功能强大的微处理器和相应嵌入式操作系统也相继问世。选择合适的嵌入式操作系统和处理器平台进行移植成为嵌入式开发的重要技术环节。本文介绍了开源嵌入式实时操作系统Real Time Operating System(RTOS) T-Kernel和 Blackfin(BF)533处理器及其开发环境VisualDSP++4.5 Environment,给出了中断管理,任务切换和系统调用入口三个模块的移植方法,并讨论了相应的系统稳定性和实时性测试方法。 日本T-Engine组织推出的T-Kernel RTOS拥有高实时性,小体积的内核,并强调对底层处理器全面封装;ADI Blackfin 系列微处理器同时具有DSP和MCU的特点,非常适合于移植RTOS。所以T-Kernel在BF533上的移植是一个典型的开发应用实例,其移植分析方法对于其他嵌入式RTOS移植也具有参考价值。 关键字 T-Kernel BF533 T-Engine 嵌入式RTOS移植 嵌入式微处理器
1 概述 随着嵌入式技术的蓬勃发展,嵌入式RTOS已逐渐成为软件系统中一个重要部分,选用优秀的开源免费RTOS(如RT-linux等),既可以免去购买商用操作系统的高额License费用,又节省了自主开发的研发成本和时间,对于目前国内的嵌入式开发是一个较好的选择。 T-Kernel源自于日本东京大学坂村健博士于1984年提出的计算机操作系统规范TRON(The Real-time Operating SystemNucleus)。凭借其强实时性,小体积,和开源免费等特点,RTON占据了全球微处理器市场60%份额。 T-Engine组织在IRON优越的实时性内核基础上推出的T-Kernel规范,进一步强调了统一的上层接口规范、对象数据格式以及标准的中间件结构,使上层应用软件能从底层硬件结构中独立出来,可以不依赖于硬件处理器而移植,大大加快嵌入式软件的开发速度[1]。 Analog Device Inc.Blackfin系列处理器在嵌入式控制和数字信号处理领域应用非常广泛,其最大的特点就是同时结合了Microcontroller(MCU)和DSP特点,即能100%运行在MCU状态,也能100%运行在DSP状态,非常适合于运行RTOS[2]。 本文分析和归纳了T-Kernel在Blackfin533(BF533)处理器上移植过程中的三个主要问题:中断管理,任务切换和系统调用入口三个模块的移植,并讨论了系统稳定性和实时性的测试方法。上述T-Kernel和Blackfin的特点,使移植和测试过程非常具有代表性,本文所讨论的方法,对于其他RTOS的移植也具有参考价值。 在以下第2节和第3节分别对T-Kernel和Blackfin处理器对于移植相关的部分进行简要的分析;第4节具体讨论了移植的主要问题;第5章介绍了对于移植以后的稳定性和实时性的测试方法,最后进行总结。
2 T-Kernel概述 2.1 T-Kernel的系统结构
T-Kernel的系统结构如图2.1所示,各功能模块是以子系统(subsystem)的形式存在的,如设备管理模块。 T-Kernel的内核是系统默认的子系统,它为应用层提供系统服务(SVC)接口,同时管理着其他子系统。子系统为应用层提供扩展服务(Extended SVC)调用接口。系统中各子系统运行在相互独立的地址空间中,保证了系统的模块化,易于扩充和裁减。
2.2 T-Kernel的系统状态和任务调度 T-Kernel规范[3]中对系统状态做了明确的划分和定义,这里主要分析如下两种状态: (1) 任务态 (TaskPortion) 运行在应用层最高优先级的就绪任务中为任务态。 (2)任务无关态 (Task Independent Portion) 任务无关态指系统的中断和异常处理过程。 在所有状态中,优先级最高的是任务无关态。操作系统(OS)定义的中断和软中断异常可以抢先临界区之外的任何状态;与OS不相关的不可屏蔽中断NMI可以中断临界区,但NMI处理程序中不能调用OS的服务。除了任务无关态,任务态具有被执行的优先权。 T-Kernel内核采用了基于优先级的可抢先调度策略,优先级相同的任务采用先进先出的时间片轮转调度,允许任务动态更改优先级。 T-Kernel的任务调度和切换是分离的过程。内核中维护着按照优先级排列的就绪任务TCB(TaskControl Block)指针链表队列,任务调度的过程就是将新的就绪任务TCB指针按照优先级放到表中相应的位置。比当前运行任务(其TCB指针存放在ctxtsk变量中)优先级更高的任务就绪时,就更新schedtsk(存放需要调度的任务的TCB指针)变量。可以看到,调度过程是一个查表的操作,其复杂度独立于就绪任务数目,从而保证了T-Kernel内核的实时性。 任务调度发生后,在进行任务切换的条件(任务无关态结束,并且系统允许任务调度)达到时,系统触发软中断异常进行任务切换,将ctxtsk更新为schedtsk,程序转入新任务运行。
3 VisualDSP++4.5开发环境和BF533处理器 移植使用的开发环境是ADI VisualDSP++4.5 Environment,程序运行在bf533的Simulator环境。图形化程序调试环境VisualDSP++4.5,提供了项目管理,程序调试,编译连接,下载模拟等软件开发的全部功能。其针对Blackfin 处理器的Built-in Functions library,可以很方便的读取和配置处理器的硬件相关的寄存器,请参考 [2]。
BF533的处理器内核包含了两个16-bit乘法器,两个40-bit累加器,两个40-bit算术运算单元(ALUs),四个8-bit video ALUs和一个40位移位器,如图3.1[2]所示: 在上下文切换过程中,需要保存的寄存器主要有: (1)堆栈和返回地址寄存器:SP(Stack Pointer),FP(FramePointer),RETS(SubroutineReturn Address Register),RETI(Interrupt Return Address Register); (2)通用数据寄存器R0~R7,通用地址寄存器P0~P7. 其它寄存器:L0~L3,LB0~LB1,LC0~LC1,LT0~LT1,ASTAT,A0~A1,I0~I3, B0~B3,M0~M3, 其中在进入新的上下文之前,L0~L3需要清零。 Blackifn处理器内核支持15个优先级的中断。在中断处理过程中,ILAT寄存器中为1的位表示当前触发的中断,查询这个寄存器,可以得到当前需要执行的最高的优先级中断号;IMASK寄存器的每一位的状态则代表相应优先级中断的使能和禁止,在移植中,IMASK寄存器作为系统的全局中断状态寄存器;IPEND寄存器的第4位IPEND[4]是全局中断的使能和禁止位,其余的位是相对应优先级的中断响应标志位。 T-Kernel系统运行在BF533的第15号(最低优先级)软中断处理程序中,这样可以获得对处理器内核的supervisor权限,请参考[4] Blackfin编译器提供两种禁止全局中断的方式,一是通过关闭IMASK寄存器中的所有标志位;另一种是通过对RETI寄存器的压栈和弹栈更改IPEND[4]状态。前者易于用C语言操作,主要用在进出临界区的操作,后者不会改变IMASK寄存器的状态,在中断前后处理和任务切换中的汇编程序使用。 从汇编函数调用C函数时,R0~R2保存前三个参数,大于三个的参数保存在堆栈中,从[ SP + 0xC ]开始,返回时R0存放返回值。P3~P5,R4~R7可以用于存放调用C语言函数前后的不变量如(SP等),实际的情况还与编译器的设置有关。
4 T-Kernel在BF533上的移植 4.1 系统中断的管理 T-Kernel对于处理器的中断资源采取动态管理的方法,在运行中任务(task)可以动态的更改中断向量表,注册和取消中断,通过系统调用tk_def_int(Define Interrupt Handler) 来实现这个功能。在中断管理模块的移植中,主要解决两个问题: (1)保证全局中断状态寄存器IMASK 在动态管理中断向量表的过程中,需要保证全局中断状态IMASK寄存器为全局变量,如果每个任务都各自拥有一个局部的IMASK值,则会出现一个任务等待的中断在另一个任务运行时被禁止的情况,造成系统对中断无法实时响应处理。 (2)延迟任务切换 在T-Kernel系统中,中断处理属于task independent portion,比task portion的优先级要高,所以在中断处理程序中发生的任务调度,并不能得到及时的切换,需要延迟到中断结束才能进行。所以在中断后理中需要判断是否进行从中断到任务的上下文切换,如果是则调用T-Kernel系统服务tk_ret_int(Return from Interrupt Handler)。 下面将讨论在BF533处理器上实现T-Kernel对中断的动态管理的方法以及中断前后处理的流程。
4.1.1临界区和全局IMASK问题 保证IMASK寄存器为全局变量的一个关键部分是如何设计进出临界区的操作。在临界区中通过关闭IMASK寄存器中所有中断使能位禁止所有OS定义的任何中断。在临界区中一旦发生了任务调度,那么在出临界区之后需要进行任务切换,这样临界区的设计需要实现下面两个功能: (1) 进入临界区之前取出当前的IMASK寄存器进行保存,关闭所有的中断使能标志,在出临界区之前把保存的IMASK值重新设置,打开中断。 (2) 出临界区之后判断,如果有任务调度发生,而且当前系统状态允许任务切换,则调用dispatch()函数触发软中断,开始任务切换。 这样,只要在任务切换过程和中断的响应过程中,不保存和更改IMASK寄存器,那么IMASK寄存器在所有task中为一个全局变量。 同时,tk_def_int(UINTdintno, T_DINT *pk_dint)函数要保证三点:只有在intno号中断处于空闲的状态下可以定义;只有定义intno号中断的task才能取消intno号中断的定义;在tk_def_int函数中进行了定义中断或取消中断操作的同时,对IMASK寄存器进行操作,打开或关闭相应的中断使能位,这一步骤是在临界区中进行的。 通过上述方法,可以有效地管理全局中断状态标志寄存器IMASK,安全稳定实时地实现了T-Kernel动态重构中断向量表的功能,对处理器中断资源进行最大限度的利用。
4.1.2中断前后处理 在T-Kernel系统中,中断是独立且优先于任务被执行的模块,需要被快速的响应和执行,在中断前后处理中主要进行以下四项操作: (1)保存和恢复上下文; (2)设置标志变量表示进出和嵌套Task Independent Portion; (3)更改堆栈指针使中断子程序运行在位于处理器内部RAM的中断堆栈; (4)取得当前触发的最高优先级中断号对应的子程序地址进行调用; (5)在中断后处理判断是否任务切换。 系统为中断程序分配了独立的堆栈,位于处理器内部,这可以使中断程序运行的地址空间独立于任务和虚拟存储地址,也可以加快中断程序的处理速度,更重要的是,在系统进入省电模式停止了外部存储器时,并不影响对中断唤醒的响应。 中断结束时进行任务切换的条件是:系统任务无关态的运行已经结束,系统处于任务可切换状态,ctxtsk不等于schedtsk. 一旦条件满足,则调用tk_ret_int()进行任务切换。 第(2)(3)(5)步操作不能被中断,必须禁止全局中断后执行。第(4)步在调用中断子程序前后需要执行LINK n 和UNLINK n为C语言子程序设置堆栈,请参考[4]。
4.2 任务切换模块的移植 任务切换的发生有两种情况:从一个任务的上下文切换到另一个任务的上下文,在临界区结束时触发软中断进入dispatch_entry();从中断的上下文切换到最高优先级的就绪任务,在中断后处理中调用tk_ret_int()。 dispatch_entry()和tk_ret_int()都是保存ctxtsk任务的上下文,替换ctxtsk为schedtsk,恢复其上下文,执行流程统一如图4.2.1所示。

图4.2.1任务切换流程图
从图中可以看到,在切换的进行过程中有允许中断的过程,如果在其中发生了任务调度,返回时可以得到最新的最高优先级就绪任务schedtsk,从而减小了系统对中断响应的延迟。如果ctxtsk = NULL,即系统中没有就绪的任务,系统转入内部RAM运行,可停止外设进行低功耗处理。 tk_ret_int()在中断后处理中被调用,仍处于中断过程,其优先级由中断处理程序的优先级决定;dispatch_entry()软中断的优先级设为系统中最低的优先级,可能出现被tk_ret_int()嵌套的情况,所以在从tk_ret_int()切入新任务或低功耗状态之前需要判断是否需要清除IPEND寄存器中断嵌套的标志。 在新建任务时,任务堆栈中必须预先设置上下文寄存器内容,任务初始化参数可以置于堆栈中R0,R1,R2的位置,在第一次切入任务时作为参数传入。每个任务可以定义一个异常处理函数,一般进行判断是否需要结束或删除任务。
4.3系统调用入口移植 在T-Kernel的公开源码中对应用层调用系统服务和扩展服务进行了限制,应用层所调用的系统服务和扩展服务只是用汇编实现的接口(API)(以tk_***_***()命名),在接口函数中取得相应服务函数唯一的标识码fncd(FunctionCode)并触发软中断进入Call_entry()函数。在Call_entry()函数中通过fncd进行判断,取得实际服务函数(以_tk_***_***()命名)的入口地址执行[6]。 T-Kernel每个系统调用可能发生在中断过程中,所以Call_entry()软中断异常的优先级需要设为用户中断的最高优先级,处理流程如下图4.3.1所示。从fncd可以判断出被调用的函数是T-Kernel的系统服务还是子系统的扩展系统服务,是T-Kernel的系统服务,从预先设置好的函数地址列表中取出相应的入口地址进行调用;否则调用svc_ientry()函数进入子系统自身的扩展调用入口函数取得入口地址。
图4.3.1 call_entry()处理流程
5 移植测试 移植测试工作主要分为稳定性测试和实时性测试两部分。测试的目的是保证移植工作的正确性。 通过新建15个不同优先级的任务进行休眠暂停请求异常处理和请求信号量等操作,同时定义计时器中断唤醒任务,可以测试系统的稳定性。确认下面五个功能,能遍历所有的移植程序,使移植后系统的实时性得到保证。 (1) 任务能自身进行休眠(Sleep)、暂停(suspend)和唤醒(wake up); (2) 任务之间进程间通讯能正常进行,任务等待信号量暂停之后,能被另一个任务和中断子程序释放信号量唤醒; (3) 在任务切换过程中,IMASK寄存器能正常地关闭打开中断,维持全局的中断使能状态; (4) 任务能安全有效地定义和取消中断; (5) 任务的异常处理请求能得到正常的响应。 移植系统的实时性可以通过任务的建立时间,结束时间,任务的切换时间,抢占时间,中断延迟时间,信号量混洗时间等指标来确定。 任务切换时间为系统在两个独立的,处于就绪态并具有相同优先级任务之间切换所需的时间。抢占时间定义为系统控制从低优先级任务转移到高优先级任务所花费的时间。中断延迟时间指从中断响应到中断子程序语句得到执行的时间间隔。信号量混洗时间指一个信号被释放到等待该信号量的任务被激活的时间延迟[7]。 部分的测试结果如表5.1所示。移植代码编译器的优化选项为速度优化100%,时间单位是Blackfin处理器cycles寄存器所记录的运行时钟周期。可以看到,系统运行在600MHz时的性能指标都在微秒级,移植系统的实时性可以得到确认。
|
任务切换时间 |
抢占时间
(中断触发) |
中断延迟时间 |
信号量混洗时间 |
|
处理器时钟周期 |
1716 |
1662 |
424 |
1584 |
|
运行时间(600MHz) |
2.9us |
2.7us |
0.7 us |
2.6us |
表5.1 部分适时性测试时间结果
6 总结 本文针对BF533处理器平台上移植T-Kernel工程应用,分析和归纳了移植的主要过程,没有过多涉及工程细节,而是总结了其中中断管理、任务切换和系统调用接口三部分的移植方法,而这是在其他RTOS移植过程中也可以参考的。对系统的稳定性和实时性进行相应的测试可以保证移植工作的正确性,当然,还需要在实际应用中更完全的测试系统。 文中所讨论的移植方法,没有包括对于MMU(Memory Management Unit)管理模块的移植,因为在绝大多数嵌入式实时性应用中,由于对速度和资源的限制,并不开启处理器的MMU功能,如果在数据和信息处理的应用中有需求,可以针对特定处理器的MMU模块进行相关代码的移植。 (特别感谢上海易律电子 刘湘毅的技术支持)
参考文献 [1] 坂村健梁 青 构筑无所不在计算的基础—TRON技术体系结构 《计算机世界报》 第47期 B3 2004年12月6日 [2] ADI ADSP-BF533 Blackfin ProcessorHardware Reference [3] T-Engine Forum T-Kernel SpecificationVersion 1.00.00 2005 [4][ADI]Deep B. uC/OS-II and The Blackfin Processor (ADSP-BF53x)Application Note Nov 2006 [5]T-Engine Forum T-Kernel Implementationguide to New Hardware Rev.1.00.01 2006.06.2 [6] Mohit Sindhwani, Anatomy of a T-EngineSystem Call, page:www.onghu.com/te 2006 [7] 嵌入式实时操作系统性能测试方法研究 http://www.avrw.com/article/art_104_1218.htm
本文作者创新点:本文分析并提出了开源嵌入式RTOS T-Kernel在ADI Blackfin处理器上的移植方法,同时给出了测试结果保证系统的稳定性和实时性,移植系统已经在实际工程中得到了应用。 T-Kernel是开源免费的强实时性操作系统,其前身ITRON成功占据了全球微处理市场60%的份额,研究和使用T-Kernel可以节省license费用和研发成本,本文在移植的同时也揭示其内核任务调度的技术细节,对于其它RTOS开发和移植也具有相当的参考价值。
项目经济效益:有待评估。数据来源:T-Engine Forum, EPSON 研究方法:参考相关说明文档和文献,参考EPSON公司ITRON4.0的代码,并结合实际需求。
|