您的位置:首页 > 其它

WinCE中断结构分析

2013-12-30 11:07 260 查看
以前写的原创博文,这里放一份

前一段时间研究了一下WinCE下的中断结构,整理了一下,希望与大家讨论。

最下面有PDF版本下载,便于保存

Windows Embedded CE 

 中断结构分析

关键字:WinCE,中断,体系,结构

摘要:本文主要以WinCE  .NET 5.0为操作系统平台,ARM为硬件平台,分析了WinCE下

中断的结构与实现方式

前言

  在嵌入式系统当中,对于中断的处理是非常重要的一部分内容。许多外围设备都需要通

过中断来实现自己的功能或者与系统内核交互,系统时钟本身也是由时钟中断产生的。所以

本文旨在分析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 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中断处理原理

  下面基于 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号,即0x12

dwSysIntr 为系统中断号,也就是调用返回的结果存放的位置

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

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号码。

五 可安装的 ISR

  1   为什么要使用可安装 ISR(以下简称 IISR)

    需要 IISR 的目的有两种:

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。

  所以 IISR 的实现就是动态的向某一个IRQ服务程序链表添加结点的过程。

2 IISR的实现

下面我们来看看IISR 的具体实现步骤:

  首先我们需要了解IISR服务中断的实现原理,如上面描述的,根据IRQ,来顺序调用

链表中的中断处理程序。所以我们可以有两个选择,一个就是类似 ISR 模型,直接在链表

中的中断处理程序中判断是不是自己的中断,并且做处理。还有一种方式就是类似 IST 模

型,如果判断是自己的中断,则返回一个SYSINTR,以此SYSINTR 来激活IST。

  无论哪种方法,关于注册中断和查询中断的方式是一样的,下面我们来看下如何将中断

程序添加到链表,又如何在中断来的时候去搜索链表。

  Microsoft提供了一个通用的IISR的处理模型,叫做GIISR,这是一个以 IST模型处

理 IISR 的模块,源程序可以在WINCE500\PUBLIC\COMMON\OAK\DRIVERS\GIISR

找到。熟悉了 GIISR,想实现自己的 IISR 处理程序或者基于 ISR 模型的处理,都比较简

单了。

  下面我们就分析这种比较通用的处理 IISR的模型。

a)  首先我们需要以 IRQ 来申请 SYSINTR,并且将SYSINTR 与 Event 绑定,这些

步骤与IST模型中介绍的一样,这里就不重复叙述了,IISR 在这里与 IST模型并

没有任何的不同。其与 IST 模型的唯一不同点就是如何根据 IRQ 来判断相应的

SYSINTR。

在 IST 模型中是 OEM写死的一个判断程序,而 IISR 可以动态来注册一个判断程

序给系统调用,这是唯一的实现区别。

b)  下面我们需要注册可安装中断程序的 dll,和dll中的中断处理函数,并且将他们与

某一个特定的IRQ相关联

这个过程是通过调用LoadIntChainHandler函数来实现的。

这里我们的中断服务dll叫做”giisr.dll”,处理函数名叫做”ISRHandler”,对应IRQ

为0x20,则函数调用形式如下:

HANDLE  hIsrHandler  =  LoadIntChainHandler(TEXT(“giisr.dll”),

TEXT(“ISRHandler”), 0x20);

c)  上一步在GIISR中通过CreateInstance把这个新的中断处理程序加入GIISR自

己的管理。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 {

      DWORD SysIntr;                    // SYSINTRfor ISR handler to return

(if associated device is asserting IRQ)

      BOOL CheckPort;                  // If true,check port to see if device is

asserting IRQ

      BOOL PortIsIO;                    // Port isIO port (possibly true only for

x86)

      BOOL UseMaskReg;                //  If  true,  read  fromMaskAddr  to

obtain mask

      DWORD PortAddr;      
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: