WinCE中断结构分析
来源:互联网 发布:java compare 返回值 编辑:程序博客网 时间:2024/06/03 16:00
以前写的原创博文,这里放一份
前一段时间研究了一下WinCE下的中断结构,整理了一下,希望与大家讨论。
最下面有PDF版本下载,便于保存
Windows Embedded CE
关键字:WinCE,中断,体系,结构
摘要:本文主要以WinCE
中断的结构与实现方式
前言
过中断来实现自己的功能或者与系统内核交互,系统时钟本身也是由时钟中断产生的。所以
本文旨在分析WinCE下的中断的结构,以及常用的几种实现方式,来帮助读者了解WinCE
中断体系及实现自己的中断处理结构。
embedded CE 5.0。
一 WinCE中断体系结构
图 1 WinCE中断体系结构
解这 4层之间的交互传递将对我们了解WinCE中断处理很有帮助。
1 硬件层:
enable/disable硬件中断。
2 内核层:
触发相应的Event。关于SYSINTR 和 IRQ 的概念后面会说明。
3 OAL层
4 IST处理层
但是对中断的实时性大打折扣
二
说到这里先解释下IRQ,ISR,IST及 SYSINTR 的概念、意义及相互关系。
IRQ:
IRQ (Interrupt request),中断请求。
这里就是外设或其它请求服务的设备发出来的中断。属于硬件中断,可能是一个电平触发的
GPIO 中断,也可能是内部DMA的一个中断。
ISR:
ISR (Interrupt serviceroutine),
WinCE实际上使用 ISR来处理中断,即默认的中断入口函数,在 ARM体系中,系统默认的
ISR就是 OEMInterruptHandler
IST:
IST (Interrupt servicethread),
在 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中断处理原理
这个函数就是我们实现中断处理的中心函数,首先我们从CPU 的寄存器里获得中断的信息,
这些信息告诉我们到底是哪个 IRQ 源触发了中断。
一般实现中断服务的方式有以下几种:
1. 简单中断处理——ISR模型
中直接对中断源进行判断,然后调用服务程序。
自己打开中断,不过处理起来较麻烦),所以如果处理时间过长,其他中断很可能被忽略,
造成中断丢失。并且系统被锁定,使得系统任务的响应变慢。
2. 中断处理的一般流程——IST模型
所以,对于中断响应的实时性不是特别高,所以系统的运行响应速度就显得更加重要。而且
目前的嵌入式设备的处理速度越来越高,已经几乎达到了当时奔 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 模型的中断实时性较差,但是这种代价对于我们的应用是值得
的。
四
的实现步骤。
1 驱动程序中 IST的构建与中断初始化
上面介绍的 IST流程中,很多步骤都是WinCE的内置支持,也就是说你只要调用相应
的 API就可以实现功能了,不需要自己编写太多的代码。只需要实现一些流程代码。
首先是驱动程序端的中断初始化。假设现在有一个驱动程序,需要服务中断源,IRQ
为 0x12。
a)
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,&(dwIrq),
其中 dwIrq为IRQ号,即0x12
dwSysIntr 为系统中断号,也就是调用返回的结果存放的位置
b)
由于我们的IST是需要Event激活的,所以这里申请一个 Event。
申请 Event的步骤比较简单和标准
hISTEvent = CreateEvent(0,FALSE,FALSE,NULL);
c)
调用 InterruptInitialize(dwSysIntr,hISTEvent,0,0)将 SYSINTR 与 Event绑
定,用来在OEMInterruptHandler 中返回SYSINTR 时激活相对应的 Event
d)
到了这一步,中断关于系统方面的初始化基本结束,剩下的就是创建一个 IST,然
后等待 Event来运行中断服务代码,例如:
while(TRUE) {
WaitForSingleObject(hISTEvent,INFINITE) ==
WAIT_OBJECT_0)
…
}
这里需要注意的是IST什么时候创建都可以,但是在InterruptInitialize之前不要
运行 IST 以等待这个 Event,也就是说在 InterruptInitialize 之前不要使用这个
Event,否则会导致InterruptInitialize失败。
还有就是不要使用WaitForMultipleObjects来等待Event。
在中断处理完成之后需要调用 InterruptDone,参数为该中断的SYSINTR。来通
知系统,中断处理完成,系统重新使能该中断
2
OEM 层 主 要 是 控 制 IRQ 的enable
(BSPIntrDisableIrq), 当然要初始化 IRQ 的配置,使其在正确的触发状态,比如上升延
触发
IRQ 的 SYSINTR,然后返回合法的SYSINTR给系统,系统查表激活相应的Event,对应
的 IST进行中断服务,然后再次等待 Event。
SYSINTR,具体格式为:
NULL, 0, NULL);
五 可安装的 ISR
I. 动态的安装中断程序
在系统运行的过程中注册中断,这种中断一般是不可预知设备的中断,常用在总线设备
中,比如PCI设备
II. 中断共享
当多个中断源使用同一个中断号(IRQ)时,就需要使用 IISR 来实现了
当然如果是需要动态安装的共享中断就最适合了。
因为我们的 IST模型中,中断服务程序就是驱动中的IST,IRQ与 IST是一对一的关
系。所以在需要动态添加一个中断服务程序的时候就没有办法处理了。
同样由于 IRQ 与 IST 的一一对应关系对于一个 IRQ 对应多个需要服务的 IST 就同样
没有办法处理。
基于上面的情况才会有IISR 的出现,IISR 从本质上是在ISR 中提供了一个接口,当
ISR 调用 NKCallIntChain时,以此IRQ为参数,在链表中依次查找是哪一个服务程序来
服务这次 IRQ,然后返回相应的 SYSINTR,此后的动作与 IST 模型就基本一样,通过
SYSINTR 来激活Event,从而启动相应的 IST。
2 IISR的实现
下面我们来看看IISR 的具体实现步骤:
链表中的中断处理程序。所以我们可以有两个选择,一个就是类似 ISR 模型,直接在链表
中的中断处理程序中判断是不是自己的中断,并且做处理。还有一种方式就是类似 IST 模
型,如果判断是自己的中断,则返回一个SYSINTR,以此SYSINTR 来激活IST。
程序添加到链表,又如何在中断来的时候去搜索链表。
理 IISR 的模块,源程序可以在WINCE500\PUBLIC\COMMON\OAK\DRIVERS\GIISR
找到。熟悉了 GIISR,想实现自己的 IISR 处理程序或者基于 ISR 模型的处理,都比较简
单了。
a)
步骤与IST模型中介绍的一样,这里就不重复叙述了,IISR 在这里与 IST模型并
没有任何的不同。其与 IST 模型的唯一不同点就是如何根据 IRQ 来判断相应的
SYSINTR。
在 IST 模型中是 OEM写死的一个判断程序,而 IISR 可以动态来注册一个判断程
序给系统调用,这是唯一的实现区别。
b)
某一个特定的IRQ相关联
这个过程是通过调用LoadIntChainHandler函数来实现的。
这里我们的中断服务dll叫做”giisr.dll”,处理函数名叫做”ISRHandler”,对应IRQ
为0x20,则函数调用形式如下:
HANDLE
TEXT(“ISRHandler”), 0x20);
c)
己的管理。GIISR 的主要作用就是判断当中断来的时候,是不是其内部数组中的某
个成员需要服务中断。所以需要更多的信息用来判断中断是否匹配当前的中断服务
程序,所以我们需要把信息传递进去,这里就是调用KernelLibIoControl。
具体的方法为:
KernelLibIoControl(hIsrHandler,IOCTL_GIISR_INFO,&giisr_info,
sizeof(GIISR_INFO), NULL, 0, NULL);
这里就是把 giisr_info 的内容传递给刚才注册的中断,giisr_info 是一个
GIISR_INFO的结构体,其内容如下:
typedef struct _GIISR_INFO {
(if associated device is asserting IRQ)
asserting IRQ
x86)
obtain mask