WINCE5.0的中断深入了解

转至:http://www.hzlitai.com.cn/bbs/viewthread.php?tid=11507&extra=page%3D2

When an interrupt is processed, a specific sequence of events takes place.
你需要为你的设备驱动写好中断处理请求(ISR)和中断服务线程(IST),并牢记这些事件的顺序:

1,当一个中断发生,处理器跳转到核心的中断处理程序(exception handler );
2,这个中断处理程序禁止所有同级或低优先级的其他中断,然后为当前的IRQ调用对应的ISR;
3,ISR中会按照中断标识的形式,返回一个逻辑中断号给中断处理程序,并会置位板级设备中断;
4,中断处理程序重新使能所有的中断,而目前的中断已经在上一步中置位了,然后就触发对应的IST事件;
5,IST就绪,服务于中断设备,然后完成对中断的处理;
6,IST调用InterruptDone函数,该函数将顺序调用OAL层的OEMInterruptDone函数,它将重新使能当前的中断。

原文:
When an interrupt occurs, the microprocessor jumps to the kernel exception handler.
The exception handler disables all interrupts of an equal and lower priority at the microprocessor, and then calls the appropriate ISR for the physical interrupt request (IRQ).
The ISR returns a logical interrupt, in the form of an interrupt identifier, to the interrupt handler and typically masks the board-level device interrupt.
The interrupt handler re-enables all interrupts at the microprocessor, with the exception of the current interrupt, which is left masked at the board, and then signals the appropriate IST event.
The IST is scheduled, services the hardware, and then finishes processing the interrupt.
The IST calls the InterruptDone function, which in turn calls the OEMInterruptDone function in the OAL.
OEMInterruptDone re-enables the current interrupt.

用电源按键pwrbutton驱动来对应这个序列。


1,物理中断和逻辑中断的对应关系如何建立?


这个函数用将物理中断号来获取逻辑中断号:


KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &g_PwrButtonIrq, sizeof(UINT32), &g_PwrButtonSysIntr, sizeof(UINT32), NULL))


其中:UINT32 g_PwrButtonIrq = IRQ_EINT0;
从help里面查出,KernelIoControl函数最终是调用OEMIoControl函数。
在WINCE500/PLATFORM/COMMON/SRC/COMMON/IOCTL/ioctl.c里找到它的定义了,关键代码:
// Execute the handler
    rc = g_oalIoCtlTable.pfnHandler(
        code, pInBuffer, inSize, pOutBuffer, outSize, pOutSize
    );

在SMDK2440/Src/Kernel/Oal/ioctl.c中可以找到:
const OAL_IOCTL_HANDLER g_oalIoCtlTable[] = {
#include "ioctl_tab.h"
};
在SMDK2440/Src/Inc/ioctl_tab.h文件中,找到这个表的定义。这个命令对应的函数是OALIoCtlHalRequestSysIntr。
PLATFORM/COMMON/SRC/COMMON/IOCTL/ioctl.c找到这个函数定义:
// Find if it is new or old call type
    if (inpSize > sizeof(UINT32) && pInpData[0] == -1) {
        // Second UINT32 contains flags, third and subsequents IRQs
        sysIntr = OALIntrRequestSysIntr(
            inpSize/sizeof(UINT32) - 2, &pInpData[2], pInpData[1]
        );
    } else {       
        // This is legacy call, first UINT32 contains IRQ
        sysIntr = OALIntrRequestSysIntr(1, pInpData, 0);
    }
在WINCE500/PLATFORM/COMMON/SRC/COMMON/INTR/BASE/map.c找到OALIntrRequestSysIntr定义:
irq = pIrqs[0];
sysIntr = g_oalIrq2SysIntr[irq];
在同一个文件中定义:
static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM];
对这个表格赋值仅有两个地方:
VOID OALIntrStaticTranslate(UINT32 sysIntr, UINT32 irq)
{
    OALMSG(OAL_FUNC&&OAL_INTR, (
        L"+OALIntrStaticTranslate(%d, %d)/r/n", sysIntr, irq
    ));
    if (irq < OAL_INTR_IRQ_MAXIMUM && sysIntr < SYSINTR_MAXIMUM) {
        g_oalSysIntr2Irq[sysIntr] = irq;
        g_oalIrq2SysIntr[irq] = sysIntr;
    }       
    OALMSG(OAL_FUNC&&OAL_INTR, (L"-OALIntrStaticTranslate/r/n"));
}


OALIntrStaticTranslate和OALIntrRequestSysIntr本身两个函数负责建立对应表。后者如果在现有的中断表中找不到已经建立的对应关系,就会分配一个未定义的Sysintr逻辑中断号给这个物理中断号。因此逻辑中断和物理中断的对应,可以说是随机的,只要保证两者是一一对应就好了,不必要硬性建立一个中断号表格(像WINCE4.2那样)。
代码中只找到OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH);是静态对应。
当中断处理程序获得了逻辑中断号,那么就会触发该中断号关联着的事件。

2,核心部分的中断处理程序如何获得物理中断号?(这个问题的目的是:如何添加一个原来系统中没有的物理中断)

Physical interrupts (IRQs) are hardware lines over which devices can send interrupt signals to the microprocessor. Logical interrupts (SYSINTRs) are a mapping of the IRQ, which the OAL specifies.

一般情况下将ISR与中断处理程序相关联的注册在系统启动的时候进行。在启动过程中,在OAL层kernel调用OEMInit函数。然后,OEMInit调用HookInterrupt 函数来通知中断处理程序,哪些ISR对应到某个物理中断。
原文:You generally register your ISRs with the exception handler at system boot time. During boot, the kernel calls the OEMInit function in the OEM Adaptation Layer (OAL). Next, OEMInit calls the HookInterrupt function to inform the exception handler of which ISRs correspond to individual physical interrupt lines. A few subroutines in the OAL, such as the OEMInterruptEnable, OEMInterruptDisable, and OEMInterruptDone functions, are also used in interrupt processing.


WINCE500/PUBLIC/COMMON/OAK/INC/nkintr.h,定义了某些逻辑中断号,声明了hookInterrupt等函数。除此之外,再没有hookInterrupt的定义。
看看WINCE500/PLATFORM/SMDK2440A/src/kernel/oal/init.c里面的OEMinit函数做了些什么:
// Initialize interrupts
    if (!OALIntrInit()) {
        OALMSG(OAL_ERROR, (
            L"ERROR: OEMInit: failed to initialize interrupts/r/n"
        ));
    }
OALIntrInit函数在WINCE500/PLATFORM/COMMON/SRC/ARM/SAMSUNG/S3C2440A/Intr/intr.c文件中定义:
调用OALIntrMapInit()函数;
初始化寄存器;
最后调用:
#ifdef OAL_BSP_CALLBACKS
    // Give BSP change to initialize subordinate controller
    rc = BSPIntrInit();
#else
    rc = TRUE;
#endif

OALIntrMapInit()函数里面对两个中断表做了初始化:
    for (i = 0; i < SYSINTR_MAXIMUM; i++) {
        g_oalSysIntr2Irq = OAL_INTR_IRQ_UNDEFINED;
    }
    for (i = 0; i < OAL_INTR_IRQ_MAXIMUM; i++) {
        g_oalIrq2SysIntr = SYSINTR_UNDEFINED;
    }

WINCE500/PLATFORM/COMMON/SRC/ARM/SAMSUNG/S3C2440A/Intr/sources:

TARGETNAME=oal_intr_s3c2440a
TARGETTYPE=LIBRARY
SYNCHRONIZE_DRAIN=1
NOMIPS16CODE=1

CDEFINES=$(CDEFINES) -DCEDDK_USEDDKMACRO -DOAL_BSP_CALLBACKS
----------------------------------------------------------------------------------
CDEFINES=-DSomeDef : This sets one or more preprocessor definitions. You must include the -D switch on each define you add. You can add new defines by using this syntax: "CDEFINES=$(CDEFINES) -DAnotherDef", or you can ignore existing settings with this syntax: "CDEFINES=-DOnlyDef".
----------------------------------------------------------------------------------
因此BSPIntrInit会被执行。
在WINCE500/PLATFORM/SMDK2440A/Src/Kernel/Oal/intr.c有这个函数的定义:
做了:
// Set GPG1 as EINT9
// Add static mapping for Built-In OHCI
OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH);
到这里,无法了解如何添加一个物理中断。

文章《wince5.0中断的详细解释》地址:http://www.hzlitai.com.cn/article/ARM9-article/system/wince_interrupt.html
其中说“在CPU接收到中断后,对中断的处理是在 OEMInterruptHandler()中,该函数的首先屏蔽该中断,最后得到实际中断IRQ所对应的sysintr的值”
OEMInterruptHandler函数在WINCE500/PLATFORM/COMMON/SRC/ARM/SAMSUNG/S3C2440A/Intr/intr.c文件中,感觉到它实际上就是上面中断序列中谈到的“中断处理程序”和ISR。就是说,中断发生之后,CPU并不知道到底是哪个中断发生了,实际上WINCE中也没有建立中断矢量表,而是直接跳转到OEMInterruptHandler函数,然后在其中查看g_pIntrRegs->INTOFFSET寄存器,来查看到底发生了什么中断。
在s3c2440a_intr.h文件里面有中断号宏定义:

#define IRQ_EINT0           0           // Arbiter 0
#define IRQ_EINT1           1
#define IRQ_EINT2           2
#define IRQ_EINT3           3

......
INTOFFSET寄存器的值与这个宏定义是完全一一对应。
这样,也就搞清楚了物理中断号如何获得,又如何对应到逻辑中断号,最后,触发了IST,整个中断处理就结束了。2440全部的中断源都已经被纳入了,添加一个采用某个中断源的设备驱动,只需要用kernelIOControl函数通过物理中断产生一个逻辑中断号就可以了!

这样的话,只要在0x18位置有一个跳转指令就可以了(但还没有找到这条跳转指令)。

3,其他中断相关函数了解

关注WINCE500/PLATFORM/COMMON/SRC/ARM/SAMSUNG/S3C2440A/Intr/intr.c中的其他函数:
OEMInterruptHandler包含了对以下中断的判断和处理:
IRQ_TIMER4,这个是系统节拍;
IRQ_TIMER2,作用未知(Profiling timer);
IRQ_EINT4_7,EINT8_23,外部中断;
任何一个中断发生后,先mask该中断(禁止中断),然后再清除中断请求:
mask = 1 << irq;
            SETREG32(&g_pIntrRegs->INTMSK, mask);
            OUTREG32(&g_pIntrRegs->SRCPND, mask);
            OUTREG32(&g_pIntrRegs->INTPND, mask);

其它中断获取逻辑中断号:
// First find if IRQ is claimed by chain
        sysIntr = NKCallIntChain((UCHAR)irq);
        if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) {
            // IRQ wasn't claimed, use static mapping
            sysIntr = OALIntrTranslateIrq(irq);
        }
关于NKCallIntChain的说明:
如果没有与ISR关联的IRQ事件,返回SYSINTR_CHAIN ;
除此之外,将返回IRQ对应的SYSINTR值。

If no ISR has handled the IRQ event, SYSINTR_CHAIN is returned.

Otherwise, a valid SYSINTR value is returned to the OEM. The OEM must then pass this value back to the kernel so the IST can be triggered.
增加一个采用中断的设备驱动,这个函数不用修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板中拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器中打开此项目。然后有一个 index.html 文件可供您修改。在命令提示符中运行该文件,或者您可以直接运行索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
项目:Javascript 中的钢琴块游戏(附源代码) 关于项目 钢琴块游戏是使用 HTML、CSS 和 JavaScript 开发的。谈到游戏玩法,它是最令人上瘾的游戏之一。该项目是原版钢琴块游戏的克隆版本,可在 Android 和 iOS 上使用。就像这里的原版一样,玩家必须点击黑色块。点击每个黑色块后,会产生钢琴音效。如果玩家点击空白处或块,他/她将输掉游戏并显示总分。背景有 4 行块。玩家必须在开始游戏前设置一定时间(以秒为单位),然后游戏将按照给定的时间进行。 说到这款游戏的 PC 控制,一切都很简单。您只需在键盘上输入数字键“1”、“2”、“3”和“4”。对于最左边的方块,按“1”,对于第二个方块,按“2”,对于第三个方块,按“3”,对于最右边的方块,按“4”。所有方块都是随机掉落的。玩家必须移动手指,同时点击每个方块。游戏速度和规则都相同。所有游戏功能均由 Javascript 设置,而布局则由 HTML 设置。 要运行此项目,我们建议您使用现代浏览器,例如 Google Chrome、  Mozilla Firefox。游戏可能不支持 Explorer/Microsoft Edge。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
项目:使用 JavaScript 编写的忍者对决滑板游戏(附源代码) 忍者对决滑板游戏是一款简单的 HTML5 和 Javascript 游戏。这款游戏使用 PhaserJS 框架制作。您必须滑动玩家来控制游戏。 关于游戏 首先,下载项目并解压。解压完文件夹后,您现在可以打开索引文件来玩游戏。运行游戏时,您将在屏幕上看到选项。您可以选择开始按钮来玩游戏。之后,您可以选择使用开始按钮开始游戏。鼠标是此游戏的控制器。您只需将鼠标拖到相邻的侧面即可切换侧面。这样您就可以防止自己击中其他物体。此外,您还可以实时查看您的分数。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器中打开此项目。然后有一个您可以修改的 index.html 文件。运行该索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。您必须安装 NodeJS 才能运行此游戏。使用命令提示符 shell 启动游戏。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你能添加一些具有不同颜色选项的级别,那么你肯定能用它的库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值