WINCE5.0的中断深入了解

本文详细解析了WinCE操作系统中的中断处理流程,包括中断服务例程(ISR)和中断服务线程(IST)的工作原理,以及如何在系统启动时注册中断服务程序。同时介绍了物理中断与逻辑中断之间的映射关系及其实现机制。

转至: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.
增加一个采用中断的设备驱动,这个函数不用修改。

源码来自:https://pan.quark.cn/s/fdd21a41d74f 正方教务管理系统成绩推送 简介 使用本项目前: 早晨睡醒看一遍教务系统、上厕所看一遍教务系统、刷牙看一遍教务系统、洗脸看一遍教务系统、吃早餐看一遍教务系统、吃午饭看一遍教务系统、睡午觉前看一遍教务系统、午觉醒来看一遍教务系统、出门前看一遍教务系统、吃晚饭看一遍教务系统、洗澡看一遍教务系统、睡觉之前看一遍教务系统 使用本项目后: 成绩更新后自动发通知到微信 以节省您宝贵的时间 测试环境 正方教务管理系统 版本 V8.0、V9.0 如果你的教务系统页面与下图所示的页面完全一致或几乎一致,则代表你可以使用本项目。 目前支持的功能 主要功能 每隔 30 分钟自动检测一次成绩是否有更新,若有更新,将通过微信推送及时通知用户。 相较于教务系统增加了哪些功能? 显示成绩提交时间,即成绩何时被录入教务系统。 显示成绩提交人姓名,即成绩由谁录入进教务系统。 成绩信息按时间降序排序,确保最新的成绩始终在最上方,提升用户查阅效率。 计算 计算百分制 对于没有分数仅有级别的成绩,例如”及格、良好、优秀“,可以强制显示数字分数。 显示未公布成绩的课程,即已选课但尚未出成绩的课程。 使用方法 Fork 本仓库 → 开启 工作流读写权限 → → → → → 添加 Secrets → → → → → → Name = Name,Secret = 例子 程序会自动填充 尾部的 ,因此你无需重复添加 对于部分教务系统,可能需要在 中添加 路径,如: 开启 Actions → → → 运行 程序 → → 若你的程序正常运行且未报错,那么在此之后,程序将会每隔 30 分钟自动检测一次成绩是否有更新 若你看不懂上述使用...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值