Windows CE 中断管理

 Windows CE 中断管理

    操作系统对外设的请求都是通过中断来处理的。大多数情况,操作系统都不主动去查看外围设备的请求,只有当中断发生的情况下,操作系统才会通过中断来向外围设备提供服务。首先需要解释几个概念:

       IRQ(Interrupt Request):物理中断请求,这是外部设备通过CPU的中断引脚向CPU发送的中断信号。

       SYSINTR:逻辑中断,这是操作系统或者驱动程序直接调用的中断号,它是通过OAL把物理中断信号映射成为了OEM定义的逻辑中断号。

       ISR(Interrupt Service Routine):中断服务例程,处于内核模式,ISR的主要职责就是判断输入的物理中断号,转化为相应的逻辑中断号。

       IST(Interrupt Service Thread):中断服务线程,处于用户模式,IST是真正的中断处理程序,处理相关的中断请求就是在IST中实现的。

       Windows CE     的中断处理模型如下图所示。简单来说,外围设备向内核发出了一个物理中断,ISR捕捉到这个物理中断,并且转化为相应的逻辑中断,将逻辑事件与一个事件关联,IST通过事件响应,进入中断处理程序,一次中断结束。

Windows CE 中断管理_第1张图片

一.  中断处理过程

当一个中断发生时,处理器将控制内核中的一个异常操作,然后调用ISR注册到当前的中断。ISR负责把当前的物理中断转化为一个逻辑中断,同时给内核返回一个逻辑中断号。内核将设置一个事件与该逻辑中断相关联。IST将等到这个事件,直到该事件触发,IST处理中断请求。

下图是一个中断处理内部结构图:

Windows CE 中断管理_第2张图片

 

 

上图的整个流程为:

 

       (1). 如果内核的捕捉异常代码接收到一个硬件中断,那么内核接着就会识别一个异常,并且提交相应的硬件中断。

(2). 内核的中断管理器通知ISR禁用当前中断,直到中断处理完成,才能再重新启动当前中断。这个阶段过程中,允许中断嵌套,也就是允许高优先级的中断触发。

(3). 异常管理器调用ISR来响应这个中断。

       (4). 内核接收到ISR的返回值后,依据该返回值来决定如何处理中断。

       (5). 内核触发中断支持处理器来唤醒IST并激活该线程。

       (6). IST响应相应的中断,如果有需要,IST调用个中I/O函数来访问响应的硬件来完成操作。

       (7). IST完成中断处理工作后,调用InterruptDone()函数来通知内核。

       (8). 内核调用OAL中的函数OEMInterruptDone()函数来宣告所有中断处理工作已经完成。OAL通知硬件重新打开该中断。至此,一次中断处理结束。

 

二.  中断服务例程ISR

ISR是运行在内核当中的一段代码,通常通过OEM实现。ISR主要是用于相应物理中断,并决定如何处理该中断。如果中断需要被内核和IST进一步处理,那么ISR会返回一个逻辑中断号SYSINTR_XXX;如果该中断不需要被进一步的处理,那么ISR只需要返回SYSINTR_NOP给内核。一个ISR程序必须非常的高效,从而避免对硬件中断相应的延迟。如果一个ISR响应太慢,从用户来看,就会认为这个设备死机了。

从上面看来,我们也可以在ISR中直接完成对中断的请求,并且完成相应的操作。但是这不是很好的办法,我们应该让IST来完成大多数的工作。

下面以一个SMDK2410的例子,该函数位于%WINCEROOT% /PLATFORM/COMMON/SRC/ARM/SAMSUNG/S3C2410X/INTR下,在SMDK2410种,OEMInterruptHandler()函数充当了ISR的角色:

ULONG OEMInterruptHandler(ULONG ra)

{

    //得到正在处理的物理中断号

    irq = INREG32(&g_pIntrRegs->INTOFFSET);

 

    //系统时钟处理

if (irq == IRQ_TIMER4) {

 

        // Clear the interrupt

        OUTREG32(&g_pIntrRegs->SRCPND, 1 << IRQ_TIMER4);

        OUTREG32(&g_pIntrRegs->INTPND, 1 << IRQ_TIMER4);

 

        // Rest is on timer interrupt handler

        sysIntr = OALTimerIntrHandler();

       

    }

    else {

 

            //禁止同类的中断

            mask = 1 << irq;

            SETREG32(&g_pIntrRegs->INTMSK, mask);

 

        }

 

        //清空中断寄存器

        OUTREG32(&g_pIntrRegs->SRCPND, mask);

        OUTREG32(&g_pIntrRegs->INTPND, mask);

 

        //可挂载ISR

        sysIntr = NKCallIntChain((UCHAR)irq);

        if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) {

            // IRQ wasn't claimed, use static mapping

            sysIntr = OALIntrTranslateIrq(irq);

        }

 

        // unmask interrupts in case it's NOP or invalid

        if (SYSINTR_NOP == sysIntr) {

            if (OAL_INTR_IRQ_UNDEFINED == irq2) {

                // Unmask the primary interrupt

                CLRREG32(&g_pIntrRegs->INTMSK, mask);

            } else {

                // Unmask the external interrupt

                mask = 1 << (irq2 - IRQ_EINT4 + 4);

                CLRREG32(&g_pPortRegs->EINTMASK, mask);

            }

        }

 

    }

    //返回逻辑中断号

    return sysIntr;

}

 

三.   中断服务线程IST

IST其实就是一个普通的用户态线程,它负责处理相应中断的大多数操作。前面的内容中,我们提到过IST线程是在等待到相应事件才会进行处理的,所以在大多数情况下,IST都是空闲的。实现IST的常见函数如下:

InterruputInitialize():该函数负责把某个逻辑中断与一个Event内核对象关联起来。

WaitForSingleObject():该函数阻塞当前进程,等待某个EVENT内核对象事件发生。

InterruptDone():该函数用来告诉操作系统,对该中断已经处理完成,操作系统可以重新开启该中断。

实现IST必须的步骤:

(1).创建一个结构体用来保存中断处理的相关数据。

(2).IST触发时使用CreateEvent()函数。

(3).通过注册表读取物理中断号和逻辑中断号,在驱动加载前允许OAL把物理中断号映射成逻辑中断号。

(4).保存创建线程句柄。

            具体例子就不在这里列举出来了。

 

参考书籍:

Windows CE 嵌入式操作系统。

Windows CE 设备驱动及BSP开发指南。

 

你可能感兴趣的:(Windows CE 中断管理)