交流做病理切片的网站,如何做移动端网站,扬州百度推广公司,枣庄手机网站建设从前面的介绍#xff0c;我们知道了裸机中断处理的流程、WINCE驱动的中断处理#xff0c;但是#xff0c;WINCE底层是怎么处理中断的呢#xff1f;这里就是介绍WinCE系统的OAL层的中断处理。它和裸机的处理总体一样#xff0c;只是实现细节方面有点区别#xff0c;具体流…从前面的介绍我们知道了裸机中断处理的流程、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 well 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 wasnt claimed, use static mapping sysIntr OALIntrTranslateIrq(irq); } // unmask interrupts in case its 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会调用OALIntrDoneIrqsOALIntrDoneIrqs调用BSPIntrDoneIrq主要的功能处理都在OALIntrDoneIrqs函数内实现。