从前面的介绍,我们知道了裸机中断处理的流程、WINCE驱动的中断处理,但是,WINCE底层是怎么处理中断的呢?这里就是介绍WinCE系统的OAL层的中断处理。它和裸机的处理总体一样,只是实现细节方面有点区别,具体流程如下:

一、在OAL层的初始化函数,在系统启动的过程中被调用,如下所示:

BOOL OALIntrInit()
{
BOOL rc = FALSE;
// Initialize interrupt mapping
OALIntrMapInit();
// First get uncached virtual addresses
g_pIntrRegs = (S3C2410X_INTR_REG*)OALPAtoVA(
S3C2410X_BASE_REG_PA_INTR, FALSE
);
g_pPortRegs = (S3C2410X_IOPORT_REG*)OALPAtoVA(
S3C2410X_BASE_REG_PA_IOPORT, FALSE
);
// Mask and clear external interrupts
OUTREG32(&g_pPortRegs->EINTMASK, 0xFFFFFFFF);
OUTREG32(&g_pPortRegs->EINTPEND, 0xFFFFFFFF);
// Mask and clear internal interrupts
OUTREG32(&g_pIntrRegs->INTMSK, 0xFFFFFFFF);
OUTREG32(&g_pIntrRegs->SRCPND, 0xFFFFFFFF);
// S3C2410X developer notice (page 4) warns against writing a 1 to any
// 0 bit field in the INTPND register. Instead we'll write the INTPND
// value itself.
OUTREG32(&g_pIntrRegs->INTPND, INREG32(&g_pIntrRegs->INTPND));
// Unmask the system tick timer interrupt
CLRREG32(&g_pIntrRegs->INTMSK, 1 << IRQ_TIMER4);
// Give BSP change to initialize subordinate controller
rc = BSPIntrInit(); // 配置某些外设的中断配置,比如以太网,但这不是必须的,也可以在以太网驱动内实现。
return rc;
}

实际上,上面这部份的初始化是超简单的,总结为完成的事情如下:
1、外设引脚功能的配置及中断触发方式,图中所示是:GPFCON、EXTINT0
2、中断mask码、优先级、模式的设定,包括子级掩码、主级掩码,图中所示是:EINTMASK、MASK、MODE、Priority。

二、中断服务程序,它会在硬件IRQ产生时被调用
中断服务程序是IRQ中断的入口点,代码如下所示:
ULONG OEMInterruptHandler(ULONG ra)
{
UINT32 sysIntr = SYSINTR_NOP;
UINT32 irq, irq2 = OAL_INTR_IRQ_UNDEFINED, mask;
fInterruptFlag = TRUE; // Signal OemIdle to come out of idle.
// Get pending interrupt(s)
irq = INREG32(&g_pIntrRegs->INTOFFSET);
// System timer interrupt? 系统时间中断?
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();
}
// Profiling timer interrupt?
else if (irq == IRQ_TIMER2)
{
// Mask and clear the interrupt.
mask = 1 << irq;
SETREG32(&g_pIntrRegs->INTMSK, mask);
OUTREG32(&g_pIntrRegs->SRCPND, mask);
OUTREG32(&g_pIntrRegs->INTPND, mask);
// The rest is up to the profiling interrupt handler (if profiling
// is enabled).
//
if (g_pProfilerISR)
{
sysIntr = g_pProfilerISR(ra);
}
}
else
{
if (irq == IRQ_EINT4_7 || irq == IRQ_EINT8_23) {
// Find external interrupt number
mask = INREG32(&g_pPortRegs->EINTPEND);
mask &= ~INREG32(&g_pPortRegs->EINTMASK); // Find the effect interrupt number
/*
// g_i[i], g_i[i] ^(g_i[i]-1), g_i[i]^(g_i[i]-1)) >> 5
1: 1 : 0
2: 3 : 0
4: 7 : 0
8: 15 : 0
16: 31 : 0
32: 63 : 1
64: 127 : 3
128: 255 : 7
256: 511 : 15
512: 1023 : 31
1024: 2047 : 63
*/
mask = (mask ^ (mask - 1)) >> 5;
irq2 = IRQ_EINT4;
while (mask != 0) {
mask >>= 1;
irq2++;
}
// Mask and clear interrupt
mask = 1 << (irq2 - IRQ_EINT4 + 4);
SETREG32(&g_pPortRegs->EINTMASK, mask);
OUTREG32(&g_pPortRegs->EINTPEND, mask);
// calculate mask for primary interrupt
mask = 1 << irq;
// update irq
irq = irq2;
} else {
// Mask the interrupt
mask = 1 << irq;
SETREG32(&g_pIntrRegs->INTMSK, mask);
}
// clear primary interrupt
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);
}
// 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;
}
从上面代码总结出,中断服务程序主要做的事情是:
1、从INTPND得知主级中断中的中断号。
2、从EINTPEND得知次级中断中的中断号。
3、置位或者清零中断控制器的寄存器
·置位次级的mask
·置位主级的mask
·清理次级中断PND,图中所示为:EINTPEND
·清理主级中断PND,图中所示为:SRCPND
4、最后返回一个中断号sysIntr,这个是逻辑上面的中断号,和WINCE驱动的逻辑中断号相对应。

三、OALIntrDoneIrqs函数
WinCE驱动在处理中断完毕后,会调用InterruptDone函数,此函数会调用OALIntrDoneIrqs函数,OALIntrDoneIrqs函数内容如下:
VOID OALIntrDoneIrqs(UINT32 count, const UINT32 *pIrqs)
{
UINT32 i, mask, irq;
for (i = 0; i < count; i++) {
// Depending on IRQ number use internal or external mask register
if (irq <= IRQ_ADC) {
// Use internal interrupt mask register
mask = 1 << irq;
CLRREG32(&g_pIntrRegs->INTMSK, mask);
} else if (irq <= IRQ_EINT23) {
// Use external mask register
mask = 1 << (irq - IRQ_EINT4 + 4);
CLRREG32(&g_pPortRegs->EINTMASK, mask);
}
}
}
从上面的代码可知,OALIntrDoneIrqs所做的事情是在中断处理完毕之后的清零主级的mask或者清零次级的mask。

现在回顾一下整理,在OEMInterruptHandler函数内清零PND,这样做是有好处的。不然,在驱动内实现的话,就要严格按照步骤来清零,即:先清零PND,然后再清零外设PND。为什么要先清零PND,然后再清零外设PND,可以参考我写的另一篇文章“应该怎么样清理中断的PND位?”。

结论是,WinCE在默认情况下,适合边缘触发的中断,如果需要处理电平触发的话,需要同时修改OEMInterruptHandler函数和OALIntrDoneIrqs函数,在OEMInterruptHandler函数内不要清零PND而在OALIntrDoneIrqs内清零PND,这样才能避免重复处理同一个中断。

总之,WINCE的OAL层和中断相关的函数是:
ULONG OEMInterruptHandler(ULONG ra); //中断服务函数

void OEMInterruptDone( DWORD idInt ); //中断处理完毕的函数
void OEMInterruptDisable( DWORD idInt ); //禁用中断的函数
BOOL OEMInterruptEnable( DWORD idInt, LPVOID pvData, DWORD cbData ); //启用中断的函数
当然,还有中断初始化函数,但那是非OEM函数,即自己定义。以上几个函数的源码,可以参考相应的BSP包。

仅管OEMInterruptDone和OEMInterruptEnable,在功能上都是把指定IRQ的MASK给清零,但是OEMInterruptEnable需要多做一件事情,它需要把前一级的相应的PND寄存器给清零,意思是:清除以前发生的中断,现在开始处理新的中断。

OEMInterruptDone会调用OALIntrDoneIrqs,OALIntrDoneIrqs调用BSPIntrDoneIrq,主要的功能处理都在OALIntrDoneIrqs函数内实现。

ARM中断分析之四:WinCE的OAL层的中断分析相关推荐

  1. S3C2440中断解析和基于WINCE操作系统的中断分析(整理于网络,用于按键中断使用)

    在调试CAN总线的时候,遇到了操作系统的中断,为了彻底的弄清楚中断是怎么回事?我先从底层的中断开始研究,在这里我们只讨论外部中断,下面就结合S3C2440TEST测试程序来分析一下中断是怎么执行的:我 ...

  2. Linux中断(interrupt)子系统之四:驱动程序接口层 中断通用逻辑层

    在本系列文章的第一篇:Linux中断(interrupt)子系统之一:中断系统基本原理,我把通用中断子系统分为了4个层次,其中的驱动程序接口层和中断通用逻辑层的界限实际上不是很明确,因为中断通用逻辑层 ...

  3. 【Android 事件分发】事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 )

    Android 事件分发 系列文章目录 [Android 事件分发]事件分发源码分析 ( 驱动层通过中断传递事件 | WindowManagerService 向 View 层传递事件 ) 文章目录 ...

  4. arm b bl 地址无关码_ARM_异常和中断

    ARM_异常和中断 问题1.中断向量表为于存储器的什么位置? ARM7系列,除ARM720T可以放高端地址,ARM9或更高都放高端地址上. 2.FIQ或IRQ异常返回指令是什么? 答案见下面.... ...

  5. Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

    本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7497260 更多请看专栏,地址 ...

  6. 1.8.ARM裸机第八部分-按键和CPU的中断系统

    1.8.1.什么是按键 1.8.1.1.按键的物理特性 (1).平时没人按的时候,弹簧把按键按钮弹开.此时内部断开的. (2).有人按下的时候,手的力量克服弹簧的弹力,将按钮按下,此时内部保持接通(闭 ...

  7. 安卓逆向学习笔记:native层开发、分析和调试基础

    安卓逆向学习笔记:native层开发.分析和调试基础 本笔记主要是自己看,所以如果有看不懂的地方也请多多包涵,这一篇的笔记主要是<Android应用安全防护和逆向分析>的部分内容. 一 A ...

  8. 【Binder 机制】Native 层 Binder 机制分析 ( binder_loop | svcmgr_handler | binder.c | binder_parse )

    文章目录 前言 一.binder_loop 方法调用 二.binder_loop 方法参数 svcmgr_handler 三.binder_loop 方法 四.binder_parse 方法 前言 在 ...

  9. AT解析层的思路分析及代码实现

    文章目录 1 AT解析层的思路分析 1.1 AT解析层的接口API分析 1.2 AT解析层代码流程 2 AT解析层代码实现 2.1 代码实现 1 AT解析层的思路分析 1.1 AT解析层的接口API分 ...

最新文章

  1. 使用Python,OpenCV进行涂鸦(绘制文字、线、圆、矩形、椭圆、多边形轮廓、多边形填充、箭头~)
  2. 利用脑记录产生的合成语音
  3. 数值优化(Numerical Optimization)学习系列-文件夹
  4. PhoneGap工作原理及需改进的地方(转)
  5. 【mysql】配置 选项文件
  6. spring-security权限控制详解
  7. java 注入 循环_spring依赖注入——循环依赖
  8. observable_Java Observable clearChanged()方法与示例
  9. 用VC写Assembly代码(6)--附录2[windows进程中的内存结构]
  10. 基于JAVA+Servlet+JSP+MYSQL的物流管理系统
  11. 什么叫做微内核?与安卓系统有什么区别?
  12. Bailian2946 玩游戏【模拟】
  13. display none 隐藏后怎么显示_第12天:打破常规之 display
  14. 网络工程师应该掌握的知识要点 (共45个)
  15. JAVA系列-设计模式-中介者模式
  16. Excel 2016: 录制宏入门
  17. 塞规公差带图_塞规和卡规公差表
  18. Jmeter使用及压测
  19. JSP页面的初步编写
  20. 基于SSM实现的人力资源管理系统【附源码】(毕设)

热门文章

  1. oracle代码实例,oracle存储过程代码实例
  2. .NET Framework学习笔记(十)
  3. python执行gradle脚本
  4. Loj #6307. 「雅礼国庆 2017 Day1」Clique
  5. 表现与数据分离;前台MVC
  6. jenkins Auth fail验证失败
  7. 一个分布式服务器集群架构方案
  8. 易宝支付碰到 交易签名无效问题 (2)
  9. [密码学基础][每个信息安全博士生应该知道的52件事][Bristol Cryptography][第36篇]Index Calculus算法
  10. [Linux][Ubuntu]Linux实习常用操作/Debug总结