zoukankan      html  css  js  c++  java
  • Windows Embedded CE 中断结构分析

    一 WinCE中断体系结构
    中断涉及4层,即:硬件层、内核层、OAL层、IST处理层;

    1 硬件层:
    硬件层就是实际触发中断的硬件,这里主要有两方面作用,一个是触发中断,第二个是enable/disable硬件中断。

    2 内核层:
    这一层由内核来处理,包括中断异常产生后跳转到相应的ISR,以及根据SYSINTR来触发相应的Event。

    3 OAL层
    这一层主要就是我们需要实现的代码了,来识别硬件IRQ,对应到SYSINTR。

    4 IST处理层
    一般使用IST来做实际的中断处理,这样不会占用很多的锁定系统时间来处理中断,但是对中断的实时性大打折扣。

    二 IRQ,ISR,IST和SYSINTR

    IRQ:IRQ (Interrupt request),中断请求。
    这里就是外设或其它请求服务的设备发出来的中断。属于硬件中断,可能是一个电平触发的GPIO中断,也可能是内部DMA的一个中断。

    ISR:ISR (Interrupt service routine), 中断处理程序。
    WinCE实际上使用ISR来处理中断,即默认的中断入口函数,在ARM体系中,系统默认的ISR就是OEMInterruptHandler。

    IST: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号,即0x12
    dwSysIntr为系统中断号,也就是调用返回的结果存放的位置
    /* 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,具体格式为:其中dwSysIntr就是需要释放的SYSINTR号码。
    KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, dwSysIntr, sizeof(DWORD), NULL, 0, NULL);

    /* ARMCE深入

    这里实际调用的是OALIntrReleaseSysIntr这个函数,由OEM自己实现。所做的动作也很简单,就是从SYSINTR到IRQ和IRQ到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);

    /* ARMCE深入
    LoadIntChainHandler的源代码可以在WINCE500\PRIVATE\WINCEOS\
    COREOS\NK\KERNEL\Loader.c中找到,就是函数SC_LoadIntChainHandler
    WinCE6在KDriver.c中的NKLoadIntChainHandler,两者功能大致相同,只是在一些结构体定义上略有不同
    其主要功能就是加载dll到NK,并且获得三个函数的指针,一个是CreateInstance,一个是你刚才传进来的处理函数,这里就是ISRHandler,还一个就是IOControl,后面会用到。
    首先调用CreateInstance来获得一个实例的数据,这个数据就是一个index,用来标示其中的一个中断处理程序的索引。
    这里可能需要解释下GIISR的处理原理。我们所有的可安装中断都通过giisr.dll里面的ISRHandler来处理,在NKCallIntChain被调用的时候,会遍历所有注册到这个IRQ的中断处理函数,这里全部都是同一个函数ISRHandler。那么就需要可以区分每一次调用,所以就在giisr模块里面维护一个数组,每一个中断服务程序占用一个数组成员,这些数组成员的Index就是他们在giisr里面的唯一标识。所以CreateInstance的任务就是查找数组,找到第一个空闲位置,将Index返回。在ISRHandler被调用到的时候,会将这个Index传递进去,根据这个Index,ISRHandler就能够知道是数组中哪个成员正在被查询,进而确定是不是这个成员需要处理中断请求,进而确定该返回的SYSINTR。详细的步骤下面会一一说明,大家先有一个概念在从CreateInstance返回了可用的数组Index之后,调用HookIntChain,此函数在Kdriver.c中。这个函数的功能比较简单,我们先了解下共享中断在系统中的处理。
    前面有所提到,在调用NKCallIntChain时会遍历一个链表,每个链表头就是系统维护的一个数组中的一个成员,每一个IRQ号码都对应数组中的一个成员,这个数组就是pIntChainTable。IRQ按照其号码在数组中对应相应的数组成员,注意pIntChainTable是一个256个成员的数组,这也就意味着你的IRQ号码数字不能超过255,当然这是指你传递进来的IRQ号码,如果你的IRQ号码都是大于255的,可以对实际IRQ号码做处理,保证其数字值在0-255,比如对256取模,这样当然就可以传递进来了。pIntChainTable中的每个元素都是一个链表的头,当你向一个IRQ添加中断处理的时候,实际是建立了一个新的PINTCHAIN元素,然后向pIntChainTable中的IRQ索引位置去添加,如果该位置不为空,则查找这个元素指向的下一个元素,在这个单向链表的操作下,将新的中断处理程序加入。
    这个加入工作就是HookIntChain做的*/

    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; // SYSINTR for 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 is IO port (possibly true only for x86)
    BOOL UseMaskReg; // If true, read from MaskAddr to obtain mask
    DWORD PortAddr; // Port Address
    DWORD PortSize; // Port data width in bytes

    DWORD Mask; // Mask to use on data port to determine if device is asserting IRQ
    DWORD MaskAddr; // Address of register to use as mask
    } GIISR_INFO, *PGIISR_INFO;

    这些成员都是需要设置的,具体含义如下
    SysIntr:这个中断所对应的系统中断号,即第一步申请到的SYSINTR,系统在确定是当前的设备出发的IRQ之后会返回这个SysIntr
    CheckPort:一般为TRUE,如果为FALSE则直接返回SysIntr,而不是判断是不是当前设备触发的中断
    PortIsIO:是不是IO端口,这个可能只是在x86下使用,我们置为FALSE
    UseMaskReg:是否使用地址来获得Mask,如果为TRUE,则Mask字段无意义
    PortAddr:实际上是可以判断中断是哪个设备出发的那个寄存器的地址
    PortSize:PortAddr的位宽,标志PortAddr是1字节(BYTE),2字节(WORD),还是4字节(DWORD)的寄存器,其他不支持
    Mask:一个掩码位,在UseMaskReg为FALSE的情况下与PortAddr的值进行位或运算,如果不为0,则确定为当前设备触发的中断
    MaskAddr:当UseMaskReg为TRUE的时候,使用这个地址来获得掩码的值,给动态的判断中断提供了接口

    仔细看了上面各个成员的介绍,大家就应该可以了解GIISR是如何判断中断是不是当前设备产生的。
    所有的判断依据就是这个结构体。一般我们会将CheckPort置为TRUE,然后让系统去读取PortAddr地址处的值,这个值可以标志是否为当前设备触发的中断。获得这个值以后,与一个mask值进行或运算(&),如果值不为0,则认为是当前设备触发的中断。这个mask值在UseMaskReg为FALSE时是成员Mask,反之是从MaskAddr地址处获得。

    /* ARMCE深入
    KernelLibIoControl的源代码可以在Kdriver.c中找到,就是SC_KernelLibIoControl。SC_KernelLibIoControl直接调用的NKKernelLibIoControl,这个函数同样在kdriver.c中。分析源码可知,就是调用了giisr.dll中的IOControl,参数为IOCTL_GIISR_INFO,就是传递进去了一个GIISR_INFO结构体,用来给Index标示的数组元素赋值,这个Index就是前面CreateInstance返回的那个数值,通过hIsrHandler传递进去。
    */

    d) 下面就是启动IST,等待Event,这里和IST模型没有任何区别。
    到这里全部的初始化就完成了,可以看出,和IST模型相比就是多了两步b)和c),这两步决定了中断判断的方式,这也是IISR的根本所在。

    3 中断的判断
    下面详细介绍下可安装中断在ISR中被判断的过程。
    同样,中断到来时进入的函数是OEMInterruptHandler,在OEMInterruptHandler中会调用NKCallIntChain来遍历该IRQ对应注册的IISR。这是一个链表结构,所以对中断判断程序是一个顺序调用的过程,即先注册的设备先判断,如果判断到正确的结果,则返回合法的SYSINTR,OEMInterruptHandler也同样返回这个值。所以即使后面的设备也符合条件,也不会被执行。如果整个链表中都没找到正确的设备,则返回SYSINTR_CHAIN。OEMInterruptHandler在判断到返回结果为SYSINTR_CHAIN时,即表示请求中断的设备不在链表中。
    /* ARMCE深入
    NKCallIntChain的代码在KDriver.c中,是个非常简单的函数,以传递进来的IRQ为Index找到链表的头,然后去调用各链表节点的hIsrHandler,并且以CreateInstance的返回值为参数。当有返回的值不是SYSINTR_CHAIN时,就返回这个值,反之继续查找,直到链表尾部,如果还没有找到,就返回SYSINTR_CHAIN。
    */

    4 自定义的IISR
    我们可以不使用GIISR,而自己实现IISR功能,只要知道了IISR的原理。
    当以某一个寄存器或者地址的值,不足以判断到底是系统中哪个设备触发的中断的时候,GIISR就不是这么好用了。比如多个不同的外设,使用同一个GPIO来触发中断。外设需要读取多个寄存器或者需要一个复杂些的计算(不只是简单的一个&操作)才能判定中断是否是其产生的。这时候我们需要使用自己的一套IISR的处理方式。
    当然我们不希望去改动整个微软对于IISR的处理结构,所以我们就要区分开来上面介绍的GIISR的模型里,哪些是微软的架构,哪些是GIISR自己的实现。

    微软的IISR架构:
    a) 首先需要使用LoadIntChainHandler去注册这个IISR的处理判断程序的dll,在这个dll中除了需要一个判断处理程序(也就是通过
    LoadIntChainHandler传递进去的那个参数),还需要一个CreateInstance的函数,这个是必须的。在你不改动微软内核的情况下,名字也是固定的,详细地函数定义,可以参考GIISR的CreateInstance。至于IOControl,最好也参考GIISR的定义一个,如果不需要去调用KernelLibIoControl的话,应该是可以不实现的。
    b) 在OEMInterruptHandler中调用NKCallIntChain去遍历链表,在调用处理函数时将CreateInstance的返回值作为参数传递进去,如果处理函数在判断到不是自己触发的中断,应该返回SYSINTR_CHAIN,否则返回一个有意义的SYSINTR值
    c) 在需要注销这个IISR的时候,调用FreeIntChainHandler,需要在dll中实现DestroyInstance这个函数,被系统调用,这个是可选的。

    GIISR自己的实现:
    使用同一套代码管理这些中断处理程序,每个中断处理程序在内部的数组中占用一项,这些项目记录着中断处理程序激活使用的SYSINTR以及判定其触发中断的标准。这个标准就是读取某个寄存器或地址来用掩码来判断。同时这个数组项目对应的结构体数据就是通过KernelLibIoControl传递进去的。
    所以对于需要使用自己的特殊方式判断中断触发的程序,可以使用自己的中断判别程序。
    我们可以为每一个中断外设都实现自己的处理dll。在调用LoadIntChainHandler时传递进自定义的一个dll与处理函数,CreateInstance一定要实现,不过返回值可以忽略。
    在处理函数中,我们直接根据自己的外设来判断中断条件,然后返回相应的SYSINTR。
    其实使用CreateInstance的含义就是想把同一判断类型的设备使用一套统一的处理函数来判断。CreateInstance的返回值就是区别不同设备的这个Index。

    5 IISR资源的释放
    当我们需要注销这个IISR的时候,需要调用FreeIntChainHandler,来将该中断服务从链表中删除。
    FreeIntChainHandler(hIsrHandler);

    hIsrHandler就是LoadIntChainHandler的返回值。
    /*ARMCE深入
    FreeIntChainHandler函数实现同样在loader.c中的SC_FreeIntChainHandler。所做的动作就是,如果有DestroyInstance函数,则调用DestroyInstance。然后调用UnhookIntChain。UnhookIntChain的函数实现在kdriver.c中,是一个标准的单向链表删除其中一个元素的操作,这里不再详细解释。
    */

    6 使用IISR的注意事项
    由于IISR是动态的被加载的,也就是说注册的dll会被加载到内核空间。所以不能调用任何非内核的函数。并且,如果将IISR的dll放在bib文件的MODULES section里面,需要设置”K”属性,如
    giisr.dll $(_FLATRELEASEDIR)\giisr.dll NK SHK
    如果放在FILES section里面,需要保证没有fixup类型的变量。

    六 WinCE中断的延迟

    重新看图1。这里画出了从硬件中断发生,到IST运行的全部过程,中间就是我们要研究的延时部分。
    图中的”IST延迟”标志,实际上就是我们所说的中断延时。但是将IST延时细分,可以分为如下几部分延时:
    a) ISR延时
    这部分延时是指从硬件触发中断到进入OEM的ISR程序的时间,在ARM体系下,就是进入OEMInterruptHandler的时间。
    b) ISR执行时间在OEMInterruptHandler中判断IRQ,并且返回相应的SYSINTR的时间,也是OEM最主要把握的时间。
    c) 从ISR返回到IST运行的时间
    主要就是系统根据ISR返回的SYSINTR激活相应的Event,系统调度运行,到IST执行的这段时间,2 如何降低中断延时上面的中断延时原因中,a)是我们一般不去过问的部分,这段代码是微软实现的,原则上是可以改的,但是收效不大,而且可能引入bug,建议不要去动。c)是我们可以部分控制的,关键就是IST的优先级,其他部分我们也使用微软默认的实现。
    b)这一部分就是我们着重需要管理的了,因为这一块就是OEMInterruptHandler函数的实现,是OEM自己实现的代码。也就是说,判断中断源,返回SYSINTR的过程是我们唯一较可行的控制中断延时的地方。关于这部分的优化,首先就是尽量用较简单的逻辑判断IRQ,来返回相应的SYSINTR,而且OEMInterruptHandler会调用NKCallIntChain,所以IISR的链表长度与IISR处理函数的效率也是影响中断延时的重要因素。一般在判断IRQ的过程中,我们会把最可能出现、最频繁出现的IRQ放在最前面判断,比如系统时钟。这样在刚进入OEMInterruptHandler就可以判断到IRQ,并返回,节省了时间,提高了效率。同样这种方法也适用于IISR,将最可能出现,最频繁出现的设备放在链表的前面,可以提高遍历的效率。

    七 总结
    WinCE下提供了较灵活的中断处理方式,包括ISR,IST,IISR三种主要方式。
    对于ARM架构下的系统开发,我们常用的就是IST与IISR两种方式。两种方式从本质上都是通过返回正确的SYSINTR来激活相应的IST来服务中断。不同点只是对IRQ判断的方式,IST是内置的OEM写死的判断程序,而IISR是通过一个预留的接口,来动态注册判断程序,从而给了系统一个注册新中断的机会。同时IISR可以实现中断共享,在一个IRQ上通过链表的方式不断添加判断程序,从而让多个设备共享同一个IRQ,同时又可以有自己独立的中断判断程序。
    在最后,我们分析了中断延时的一些因素,这里并没有详细的进行分析,只是提出了一些降低中断延时的方法。


     

  • 相关阅读:
    差分约束系统
    拓扑排序
    算法题笔记
    Pytorch学习笔记
    caffe增加新的layer
    跑实验技巧
    cmake & make入门
    CVPR2017_Learning Detailed Face Reconstruction from a Single Image
    Arxiv1801_PointCNN
    ICCV2015_Multi-view Convolutional Neural Networks for 3D Shape Recognition
  • 原文地址:https://www.cnblogs.com/zym0805/p/2136902.html
Copyright © 2011-2022 走看看