嵌入式系统(embedded system)是嵌入式计算机系统的简称。它是一类典型的面向消息响应的计算机系统,只对特定消息进行响应(处理)。在计算机与外界实时交互的过程中,中断技术是一项关键的技术,当外部事件发生时,CPU必须及时响应中断,以实现对相应事件的处理。因此中断响应能力是影响嵌入式系统性能的主要因素。
在嵌入式系统开发方面,最核心的技术是嵌入式处理器芯片和嵌入式操作系统。“ARM+μC/OSII”是当前嵌入式系统中被广泛研究和应用的一款平台。ARM具有体积小、功耗低、速度快等特点,是非常适合于嵌入式应用的MCU。μC/OSII是一个基于优先级的抢占式实时内核,支持多任务,移植性好,代码可读性强,可固化,可裁剪,应用非常灵活。但随着应用的不断深化,ARM+μC/OSII嵌入式系统平台暴露出一些问题,如硬实时特性如何保障?中断响应能力如何?这类问题需要在实践中认真考虑并加以解决。
1 ARM的中断和异常体系结构
ARM 系统结构支持7种处理器模式:用户模式(USR)、快中断模式(FIQ)、中断模式(IRQ)、管理模式(SVC)、终止模式(ABT)、未定义模式(UND)和系统模式(SYS)。当异常发生时,CPU自动切换运行模式,并跳转至异常向量处执行,不同模式对应的堆栈空间也不相同。本文主要讨论IRQ/FIQ中断异常的响应机制。当中断请求(IRQ)到来使CPU进入中断响应时,CPU将会自动完成下列操作(FIQ与此类似): 将PC的当前值存入中断态的LR;将CPSR的值存入中断态的SPSR;改变CPSR中的运行状态位,使CPU进入中断态并关闭中断;然后将PC的值改成0x18,从而使CPU的执行转入0x18。如前所述,中断态也是一种特权状态,但是有自己的LR、SP和SPSR,所以并不等同于管理模式(即常说的“系统模式”)。
如果系统中需要实现可重入中断,必须注意SYS模式的正确使用方式,其主要用途是嵌套中断。可重入中断处理流程如图1所示。
图1 可重入中断处理流程
2 μC/OSII中断机制的实现
μC/OSII与其他嵌入式内核相比,最大差距是没有构造一个完整的设备驱动体系。例如Linux中编写驱动只须写少许的几个固定函数,且每个函数的功能都有详细的定义,VxWorks也有类似的框架体系。完整的驱动体系中最重要的部分是如何实现设备的管理。设备与CPU的通信是设备管理的重要方面,一般通过中断实现,因而构造完整的设备驱动体系的关键部分是如何实现中断机制。
μC/OSII中断实现机制可以分为两大类:第一类将μC/OSII与ISR作为两个并列的部分,可采用“_irq”关键字进行编译优化。其特点是结构简单,中断延时小,容易实现但功能简单。第二类将ISR纳入μC/OSII的管理之下,在进入具体ISR之前先进入操作系统统一的中断入口。特点是结构复杂,能实现较强的功能,并使μC/OSII体现出完整的结构。而在同一系统中往往同时存在这两类结构,将FIQ设计为第一类,使其具有快速的反应能力;将IRQ设计为第二类,使其具有强大的功能。由于第一类实现较为简单,因而下文主要针对IRQ的实现进行分析和研究。
在μC/OSII原书中是以DOS和BIOS一起,加上PC机中实际的CPU和相关硬件作为底层的框架,构成μC/OSII的一个硬件抽象层(HAL)。这个硬件抽象层相当复杂,在一般嵌入式系统中不可能也没有必要用这么复杂的HAL,但无论大小HAL都肯定是存在的。同时为保证了应用程序的移植性,需要保持上层μC/OSII相同,而主要移植HAL,这样凸显了系统的体系结构。ARM公司针对ARM处理器为操作系统的开发提供了一个HAL,称为“μHAL”。从结构上看,μHAL是一组库程序。“μHAL+μC/OSII”的实现方式能弥补μC/OSII结构上的不足,简化了μC/OSII的移植并提高了性能。
在μHAL中,为系统中的每个中断(请求)通道(即中断请求线)都配备了一个数据结构μHALis_IRQ,定义为:
structuHALis_IRQ {
PrHandler hand ;
/*routine for specific interrupt*/
unsignedintflags ;
unsignedintmask ;
constU8*name ;
/*Debug , owner id*/
structuHALis_IRQ*next ;
/*Handy for shared interrupts*/
};
中断服务本身没有上下文, uHALis_IRQ结构与μC/OSII中的OS_TCB相类似,因此ISR也可以看作一个特殊的进程。在非嵌套中断方式下,当前中断可看成是优先级最高的进程;在嵌套中断方式下,中断可看成是一个先进后出的运行队列,有其特殊的运行方式。因此uHALis_IRQ不必像OS_TCB那样复杂。在上述结构中,指针handler用来指向一个具体的中断服务程序(为0则表示空闲),通过这种数据结构可以把一个ISR与一个中断通道挂上钩。如果有多个中断源连接在同一个中断请求线上,则可以将多个uHALis_IRQ结构通过其指针next链接成一个队列。
为便于根据中断通道号找到相应的uHALis_IRQ结构,系统配备了一个以中断通道号为下标的“中断向量”结构数组:
struct uHALis_IRQ uHALv_IRQVector [NR_IRQS + 1];
有了uHALv_IRQVector[] 结构数组后,只需要为每通道写一个ISR,并通过uHALr_RequestInterupt()函数把ISR的地址赋值给uHALv_IRQVector[]中的指针handle,这样该中断处理程序便与中断响应程序挂上了钩。如:
uHALr_RequestInterupt(USB,(PFVI)usb_ISR,"USB");
其中,参数USB是中断通道的序号或中断号,也就是用于这个数组的下标;usb_ISR是函数指针;"USB"为设备名。
根据ARM的特点,μC/OSII采用一种两层的中断响应机制,其特点是当中断发生时需要分两步才能确定中断源。开中断后,当中断请求到来时,CPU自动完成一系列动作并转移到地址0x18处执行,在地址0x18处读取中断转移向量、跳转至中断分发服务程序uHALir_TrapIRQ()内执行,在uHALir_TrapIRQ()中读取相应设备寄存器的值后判断具体中断源,再进入由uHALr_RequestInterupt()注册的具体ISR。
3 μC/OSII中断机制存在的问题及其改进
为了保证μC/OSII的硬实时特性,需要对影响中断响应速度的因素加以考查。影响中断响应速度的因素包括硬件因素和软件因素两类。在特定硬件平台确定后,其性能就只由软件决定。在μC/OSII原书中,中断响应性能的估算公式回避了临界区保护机制对中断的干扰。在μC/OSII中存在大量开、关中断的代码,不考虑临界区保护是不妥当的。所以应该把开、关中断保护限制在最小的范围内(仅在内核代码中),避免应用程序使用开、关中断的手段,这样估算才有意义。μC/OSII原书第63页的公式如下:
中断响应时间=中断延时+
保存CPU内部寄存器延时+
内核进入中断服务函数的执行时间
中断延时相当小,对于50 MHz的ARM7来说,最多是28个时钟,即0.56 μs。在ISR中,仅对第二个时间(保存CPU内部寄存器延时)进行估计是不够的,还涉及保存任务、准备中断嵌套环境等这些时间,准确的描述应该称为“准备ISR环境时间”。第三个时间是最模糊的,由于在μC/OSII中对开、关中断的使用并不规范,导致这个时间很难估算,并且开、关中断保护造成的中断响应延时是必须考虑的。因此,这个时间值只有通过对开、关中断保护的严格规划后才能得到可信值。
中断可分为非嵌套中断方式、半嵌套中断方式和完全嵌套方式。其中,非嵌套方式最为简单,但延时时间长,只有当一个ISR完全结束并退出后才重新接受中断,这样显然损害了系统的实时特性。完全嵌套方式是指当CPU响应中断并进行相应环境准备后,重新开放中断,当下一个中断到来时,CPU保存当前中断的上下文后再响应新到来的中断。显然,完全嵌套没有考虑中断的优先级,不符合实时系统根据进程(ISR是一种特殊的进程)优先级进行调度的原则,使中断响应时间不可预知。半嵌套中断方式是指根据中断的优先级进行响应,通过CPU对中断向量控制器(VIC)的优先级设置,屏蔽比当前优先级低(包括当前优先级)的中断,响应比当前优先级高的中断,这样就能准确地估计中断响应时间。
半嵌套中断方式中断延时最坏情况:
{
T0=中断延时+准备ISR环境时间;
T1= T0*中断设备数;
T2=内核中不可剥夺窗口最长时间;
中断响应=(T2> T1)? T2 : T1;
/* T2和T1中较大的一个*/
}
需要注意的是,μC/OSII的特点是开、关中断的手段是开放给应用程序的,而开、关中断的手段应只能在内核中,所以为了使系统保证硬实时要求,在应用程序中应杜绝使用该手段。否则,若需将开、关中断的手段暴露给应用程序以完成应用逻辑设计,就会存在开、关中断隐性泛滥的危险,这样T2的值很可能在运行时发生改变,无法准确地估算和测试。
4 其他性能优化措施
① μC/OSII继承了分时系统的一些特性,影响了系统的硬实时特性,其中最典型的是进程间通信(ITC)机制中的信号量(semaphore)机制。信号量是最常用的进程间通信手段之一,μC/OSII中的信号量机制并未解决优先级倒转的问题。而只要对共享资源的互斥共享访问就可能会有优先级倒转,并且与信号量联系的优先级倒转是最常见的,因此引起的问题也最严重。在μC/OSII中,互斥量(mutex)是信号量的一种特殊形式,互斥量较好地解决了信号量引起的优先级倒转问题。当系统复杂到一定程度时,优先级倒转是开发者需要认真加以考虑的问题。
② 为了提高系统的硬实时特性,应该使ISR尽可能的精简。但当ISR不可避免复杂时,可以借鉴Linux中采用的bottom half机制。在μC/OSII中根据中断的优先级排列相应bh函数(进程),使所有bh函数的优先级均高于应用进程的优先级,并采用同步机制来进行调用。特别值得注意的是时钟中断服务程序的bh函数应是系统中优先级最高的进程。
③ 许多ARM芯片允许代码在Flash或ROM中运行,而Flash速度远慢于RAM或SDRAM,所以应尽可能将内核代码和ISR配置到内部RAM或SDRAM中运行,这样处理后能大大提高中断处理速度。
结语
μC/OSII是一种基于优先级的抢占式实时操作系统,适合于复杂度不是很高的中小型嵌入式系统。本文在深入分析μC/OSII中断机制的基础上,对中断响应机进行了改进,提出了优化方案,在实际工程应用中得到了很好的验证,具有一定的实用性。由于μC/OSII本身系统结构存在一些问题(如ITC机制中存在许多直接控制开关中断的代码),容易造成隐性开关中断泛滥、硬实时不确定等情况,还需要在实际工程中认真加以分析和考虑。