中断系统
- 格式:doc
- 大小:68.50 KB
- 文档页数:13
Windows Embedded CE 中断结构分析关键字:WinCE,中断,体系,结构摘要:本文主要以WinCE .NET 5.0 为操作系统平台,ARM为硬件平台,分析了WinCE 下中断的结构与实现方式作者:ETDrawer@ARMCE前言在嵌入式系统当中,对于中断的处理是非常重要的一部分内容。
许多外围设备都需要通过中断来实现自己的功能或者与系统内核交互,系统时钟本身也是由时钟中断产生的。
所以本文旨在分析WinCE下的中断的结构,以及常用的几种实现方式,来帮助读者了解WinCE 中断体系及实现自己的中断处理结构。
下面的介绍如非特殊说明,均以ARM 架构为硬件基础,操作系统代码使用Windows embedded CE 5.0。
一WinCE中断体系结构先看图1:图1 WinCE中断体系结构这张是经典的说明中断体系的图,我们可以通过分析这张图来了解WinCE的中断体系。
从结构上看,WinCE中断涉及4 层,即:硬件层、内核层、OAL层、IST处理层。
了解这4层之间的交互传递将对我们了解WinCE中断处理很有帮助。
1 硬件层:硬件层就是实际触发中断的硬件,这里主要有两方面作用,一个是触发中断,第二个是enable/disable硬件中断。
2 内核层:这一层由内核来处理,包括中断异常产生后跳转到相应的ISR,以及根据SYSINTR 来触发相应的Event。
关于SYSINTR 和IRQ 的概念后面会说明。
3 OAL层这一层主要就是我们需要实现的代码了,来识别硬件IRQ,对应到SYSINTR。
4 IST处理层一般使用IST 来做实际的中断处理,这样不会占用很多的锁定系统时间来处理中断,但是对中断的实时性大打折扣二IRQ,ISR,IST和SYSINTR说到这里先解释下IRQ,ISR,IST及SYSINTR 的概念、意义及相互关系。
IRQ:IRQ (Interrupt request),中断请求。
这里就是外设或其它请求服务的设备发出来的中断。
属于硬件中断,可能是一个电平触发的GPIO 中断,也可能是内部DMA的一个中断。
ISR:ISR (Interrupt service routine), 中断处理程序。
WinCE实际上使用ISR来处理中断,即默认的中断入口函数,在ARM体系中,系统默认的ISR就是OEMInterruptHandlerIST:IST (Interrupt service thread), 中断服务线程。
在ARM 的结构中,ISR 一般不会用来进行任何实际的操作,而只是返回一个SYSINTR,实际的操作全部在IST中完成,IST一般是在Device Manager 的一个线程中运行的一段高优先级的应用程序代码,用来服务实际的中断请求。
SYSINTR:在WinCE中,SYSINTR 就是system interrupt,就是一个操作系统的逻辑中断。
一般对于中断的处理方式都是将一个IRQ映射为一个或者多个(中断共享)SYSINTR,而后,在实际的ISR中根据IRQ返回一个对应的SYSINTR用来告诉操作系统需要服务的逻辑对象。
使用逻辑中断的好处当然就是可以实现虚拟的中断(一个SYSINTR 就被OS 认为是一个独立中断)和中断共享(单IRQ对应多SYSINTR)。
逻辑中断是WinCE需要处理的实际对象,至于这个对象是一个共享的IRQ,还是一个虚拟的中断,还是独立的物理中断,系统并不过问,从而隔离了硬件与逻辑,我们的ISR 需要做的也正是这种物理中断到逻辑中断的映射。
三WinCE中断处理原理下面基于ARM 体系,来介绍WinCE 中断处理的流程与原理。
对于一个硬件IRQ中断,系统内核在捕获之后,会交给OEMInterruptHandler 处理,这个函数就是我们实现中断处理的中心函数,首先我们从CPU 的寄存器里获得中断的信息,这些信息告诉我们到底是哪个IRQ 源触发了中断。
一般实现中断服务的方式有以下几种:1. 简单中断处理——ISR模型最简单的中断处理办法就是在ISR中直接处理,这里就是指在OEMInterruptHandler中直接对中断源进行判断,然后调用服务程序。
这种方式的优点和缺点一样明显。
优点:快速的响应了中断处理,使系统的实时性能增加不少缺点:由于进入OEMInterruptHandler的时候关闭了系统中断(当然你可以在ISR中自己打开中断,不过处理起来较麻烦),所以如果处理时间过长,其他中断很可能被忽略,造成中断丢失。
并且系统被锁定,使得系统任务的响应变慢。
2. 中断处理的一般流程——IST模型前面看到了ISR 模型的优缺点。
作为WinCE,主要定位还是民用的消费类电子产品,所以,对于中断响应的实时性不是特别高,所以系统的运行响应速度就显得更加重要。
而且目前的嵌入式设备的处理速度越来越高,已经几乎达到了当时奔 3 的水平。
所以ISR 的模型并不适用于WinCE。
如果把中断服务程序当作一个系统进程或者线程来处理,这样就不会造成系统被锁定,中断被屏蔽等问题,使得中断服务程序和其它进程、线程一样被系统管理调度。
于是就有了IST的概念IST 模型的想法是,在ISR 中判断到具体的中断源IRQ,就返回一个标志,用来标记需要哪个程序来服务中断,然后重新打开中断,恢复系统调度,系统根据这个标志来激活相应的程序来服务中断。
这个就是最常用的中断处理模型。
使得中断被关闭,系统被锁定的时间最短。
在WinCE中,经常使用的就是建立中断服务线程(IST),然后以IRQ 来申请一个系统逻辑中断号(SYSINTR),创建一个事件(Event),将Event 与SYSINTR 绑定,随后IST 阻塞在等待Event上面。
ISR 中只给系统返回一个SYSINTR,系统根据绑定关系激活相应的Event,使得随后的IST得以运行。
这就是IST的一般服务流程IST模型的缺点就是中断服务的延迟较大,从ISR 返回,到IST开始运行,中间需要花费一定的时间,相比ISR 模型的中断实时性较差,但是这种代价对于我们的应用是值得的。
四IST模型的实现下面我们来看IST模型具体在我们的驱动中是如何实现的。
上面已经介绍了IST 模型的一般服务流程,下面我们针对驱动程序实例,来分析具体的实现步骤。
1 驱动程序中IST的构建与中断初始化上面介绍的IST流程中,很多步骤都是WinCE的内置支持,也就是说你只要调用相应的API就可以实现功能了,不需要自己编写太多的代码。
只需要实现一些流程代码。
首先是驱动程序端的中断初始化。
假设现在有一个驱动程序,需要服务中断源,IRQ 为0x12。
a) 以IRQ 为参数,申请SYSINTR,方法为调用KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &(dwIrq),sizeof(UINT32), &dwSysIntr,sizeof(UINT32), NULL)其中dwIrq为IRQ号,即0x12dwSysIntr 为系统中断号,也就是调用返回的结果存放的位置/* ARMCE深入实际这个IOControl调用的是函数OALIoCtlHalRequestSysIntr,该函数的位置在WINCE500\PLATFORM\COMMON\SRC\COMMON\INTR\COMMON\Ioctl.c最终调用OALIntrRequestSysIntr,这个由OEM 自己实现,一般就是维护了2张表,一张是从SYSINTR 到IRQ 号码的映射表,另一张是IRQ 到SYSINTR 的映射表,两者是对应的关系。
这里注意一点,一个IRQ 映射为多个SYSINTR 是支持的,也就是共享中断,但是系统默认的实现并没有支持一个SYSINTR 映射为多个IRQ,你可以自己实现。
这两张表对于后面在OEMInterruptHandler中由IRQ查找SYSINTR提供了方便*/b) 创建与SYSINTR 绑定的Event由于我们的IST是需要Event激活的,所以这里申请一个Event。
申请Event的步骤比较简单和标准hISTEvent = CreateEvent(0,FALSE,FALSE,NULL);c) 将SYSINTR 与Event绑定调用InterruptInitialize(dwSysIntr,hISTEvent,0,0)将SYSINTR 与Event 绑定,用来在OEMInterruptHandler 中返回SYSINTR 时激活相对应的Event/* ARMCE深入InterruptInitialize 的代码参考SC_InterruptInitialize ,在E:\WINCE500\PRIVATE\WINCEOS\COREOS\NK\KERNEL\Intrapi.c中主要做两件事情:#1 将Event 的Ptr 填入一个数组,这个数组是记录每个SYSINTR 对应激活的Event#2 调用OEMInterruptEnable,使能SYSINTR所对应的IRQ,并且将标志IRQ被引用次数的变量加1(WinCE6 的代码中未见这一变量)*/d) 创建一个IST,并且等待hISTEvent到了这一步,中断关于系统方面的初始化基本结束,剩下的就是创建一个IST,然后等待Event来运行中断服务代码,例如:while(TRUE) {WaitForSingleObject(hISTEvent,INFINITE) ==WAIT_OBJECT_0)…}这里需要注意的是IST什么时候创建都可以,但是在InterruptInitialize之前不要运行IST 以等待这个Event,也就是说在InterruptInitialize 之前不要使用这个Event,否则会导致InterruptInitialize失败。
还有就是不要使用WaitForMultipleObjects来等待Event。
在中断处理完成之后需要调用InterruptDone,参数为该中断的SYSINTR。
来通知系统,中断处理完成,系统重新使能该中断到了这里,驱动的中断初始化工作就全部完成了。
2 OEM层需要做的工作OEM 层主要是控制IRQ 的enable (BSPIntrEnableIrq) 与disable (BSPIntrDisableIrq), 当然要初始化IRQ 的配置,使其在正确的触发状态,比如上升延触发至此一个中断处理的IST模型就实现了,系统在IRQ 触发时调用映射函数,获得相应IRQ 的SYSINTR,然后返回合法的SYSINTR给系统,系统查表激活相应的Event,对应的IST进行中断服务,然后再次等待Event。
3 中断资源的释放当不需要当前中断继续服务的时候可以通过调用KernelIoControl 来释放申请到的SYSINTR,具体格式为:KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, dwSysIntr, sizeof(DWORD), NULL, 0, NULL);其中dwSysIntr 就是需要释放的SYSINTR 号码。