中断在系统设计中的应用非常广泛,可以说,硬件中断、软件中断无处不在,在WINCE下驱动开发更是如此,比如:按键中断、触摸屏中断、AUDIO中断、DMA中断.....等等,几乎含概每个模块。因此,了解中断的处理过程对驱动开发极其重要,下面对WINCE下的中断处理过程做一个简单介绍。
中断处理可以分为两部分:中断服务例程-ISR、中断服务线程-IST。系统在处理中断异常的时候,应该要尽可能快的完成,因此,我们应该ISR中做简短的处理,把中断标识返回给中断处理器,越快越好。那么就要把大部分的处理留给IST来处理。我们可以简单的认为,ISR的任务就是完成把硬件中断也就是物理中断转为系统中断并返回。
下面再来了解一下IST,IST就是一个线程,在驱动初始化的时候创建并等待一个事件,当然,在这之前要先创建一个事件,并与中断相关联起来,当中断产生以后该事件触发IST,IST里通常是用户的处理程序。IST的实现必须先实现两个过程:IST的中断必须和一个事件相关联,IST必须通过WaitForSingleObject来等待这个事件的唤醒,IST的最后要调用INTERRUPTDONE来对注销中断,否则该中断只能用一次,一般我们在驱动的XXX_INIT函数中实现。
IST在BSP/COMMON/INTR/intr.c中,这里面的内容包括init、enable、disable、oeminterrupthandler等函数,主要是对中断的初始化、使能、处理等,其中最关键的是oeminterrupthandler。以下是我在该函数中对EINT的简单处理部分代码:
if (irq == IRQ_EINT4_7 || irq == IRQ_EINT8_23) { // 4 or 5
// Find external interrupt number
mask = INREG32(&g_pPortRegs->EINTPEND);
mask &= ~INREG32(&g_pPortRegs->EINTMASK);
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);
// Clear primary interrupt
mask = 1 << irq;
OUTREG32(&g_pIntrRegs->SRCPND, mask);
OUTREG32(&g_pIntrRegs->INTPND, mask);
// From now we care about this irq
irq = irq2;
else {
// Mask and clear interrupt
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);
}
而IST的具体实现过程可以参照下面的步骤:
1、创建一个事件。用createEvent 来实现
2、定义一个中断DWORD key_intr=SYSINTR_NOP;
3、得到ISR返回的中断号,并通过KernelIoControl将其与上面定义的中断相关联。
4、将创建的事件与中断相关联即通知系统注册中断,可以通过InterruptInitialize函数来实现。
5、创建一个中断处理IST,通过CreateThread来实现。
6、IST通过WaitForSingleObject来等待事件的唤醒,并处理中断。
7、IST调用InterruptDone来注销中断,循环等待下一次唤醒。
如果是一个按键对应一个IO,且作为外部中断的话,只需要对IO积存器、中断积存器进行设置就可以实现,下面贴出一个我自己的测试代码供大家参考:
#include
#include
#include
#include
#include "s3c2440a_base_regs.h"
#include "s3c2440a_intr.h"
#include "s3c2440a_ioport.h"
#define FUSQ_DEBUG 1
volatile S3C2440A_IOPORT_REG *p2440a_ioport_reg = NULL;
volatile S3C2440A_INTR_REG *p2440a_intr_reg = NULL;
DWORD Key_Interrupt = SYSINTR_NOP;
DWORD Key_Interrupt1 = SYSINTR_NOP;
HANDLE abc_KeyIntr_Event;
HANDLE abc_KeyIntr_Event1;
HANDLE abc_Key_Thread;
HANDLE abc_Key_Thread1;
void abc_KeyThread_Fun();
void abc_KeyThread_Fun1();
int i1=0;
int i2=0;
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD dwReason,
LPVOID lpvReserved)
{
RETAILMSG(FUSQ_DEBUG, (TEXT("--------------abc_DllMain /r/n") ) );
return TRUE;
}
DWORD abc_Init(LPCTSTR pContext,LPVOID lpvBusContext)
{
UINT32 Irq;
RETAILMSG(FUSQ_DEBUG, (TEXT("-----------------abc_Init /r/n") ) );
//initialize io port
p2440a_ioport_reg = (volatile S3C2440A_IOPORT_REG*)VirtualAlloc(0, sizeof(S3C2440A_IOPORT_REG), MEM_RESERVE, PAGE_NOACCESS);
if (!p2440a_ioport_reg)
{
RETAILMSG(FUSQ_DEBUG, (TEXT("p2440a_ioport_reg: VirtualAlloc failed!/r/n")));
return(FALSE);
}
else
RETAILMSG(FUSQ_DEBUG, (TEXT("p2440a_ioport_reg: VirtualAlloc ok----------!/r/n")));
if (!VirtualCopy((PVOID)p2440a_ioport_reg, (PVOID)(S3C2440A_BASE_REG_PA_IOPORT >> 8), sizeof(S3C2440A_IOPORT_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
{
RETAILMSG(FUSQ_DEBUG, (TEXT("p2440a_ioport_reg: VirtualCopy failed!/r/n")));
return(FALSE);
}
else
RETAILMSG(FUSQ_DEBUG, (TEXT("p2440a_ioport_reg: VirtualCopy ok-----------!/r/n")));
/*
p2440a_ioport_reg->GPFCON &=0xFFFFEBFF;//GPF5 、GPF6 For External interrupt
p2440a_ioport_reg->GPFCON |=(1<<11)|(1<<13);
*/
// p2440a_ioport_reg->EXTINT0 &=0xFF8FFFFF;// EINT5 Low Level Triggered
//p2440a_ioport_reg->GPFCON=0xAAAAAAAA; //all initialize int intr.c of OALIntrInit()
p2440a_ioport_reg->EXTINT0=0xf33fffff;
//initialize interrupt
p2440a_intr_reg = (volatile S3C2440A_INTR_REG*)VirtualAlloc(0, sizeof(S3C2440A_INTR_REG), MEM_RESERVE, PAGE_NOACCESS);
if (!p2440a_intr_reg)
{
RETAILMSG(FUSQ_DEBUG, (TEXT("p2440a_intr_reg: VirtualAlloc failed!/r/n")));
return(FALSE);
}
else
RETAILMSG(FUSQ_DEBUG, (TEXT("p2440a_intr_reg: VirtualAlloc ok------------!/r/n")));
if (!VirtualCopy((PVOID)p2440a_intr_reg, (PVOID)(S3C2440A_BASE_REG_PA_INTR >> 8), sizeof(S3C2440A_INTR_REG), PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE))
{
RETAILMSG(FUSQ_DEBUG, (TEXT("p2440a_intr_reg: VirtualCopy failed!/r/n")));
return(FALSE);
}
else
RETAILMSG(FUSQ_DEBUG, (TEXT("p2440a_intr_reg: VirtualCopy ok-----!/r/n")));
//relating the INTR to SystemIntr
Irq=IRQ_EINT5;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(Irq), &Key_Interrupt, sizeof(UINT32), NULL))
{
RETAILMSG(FUSQ_DEBUG, (TEXT("ERROR: KernelIoControl For Key_Interrupt failed./r/n")));
Key_Interrupt = SYSINTR_UNDEFINED;
return(FALSE);
}
else
RETAILMSG(FUSQ_DEBUG, (TEXT("KernelIoControl For Key_Interrupt ok---./r/n")));
Irq=IRQ_EINT6;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(Irq), &Key_Interrupt1, sizeof(UINT32), NULL))
{
RETAILMSG(FUSQ_DEBUG, (TEXT("ERROR: KernelIoControl For Key_Interrupt1 failed./r/n")));
Key_Interrupt1 = SYSINTR_UNDEFINED;
return(FALSE);
}
//create Intr Event and relating Intr to Event
abc_KeyIntr_Event=CreateEvent(NULL,false,false,NULL);
if(!abc_KeyIntr_Event)
{
RETAILMSG(FUSQ_DEBUG,(TEXT("CreateEvent--faile---/r/n")));
return false;
}
else
RETAILMSG(FUSQ_DEBUG,(TEXT("CreateEvent---OK--/r/n")));
abc_KeyIntr_Event1=CreateEvent(NULL,false,false,NULL);
if(!abc_KeyIntr_Event1)
{
RETAILMSG(FUSQ_DEBUG,(TEXT("CreateEvent1--faile---/r/n")));
return false;
}
if(! InterruptInitialize(Key_Interrupt, abc_KeyIntr_Event, NULL, 0))
{
RETAILMSG(FUSQ_DEBUG,(TEXT("InterruptInitialize--Key_Interrupt to abc_KeyIntr_Event failed ./r/n")));
return FALSE;
}
else
RETAILMSG(FUSQ_DEBUG,(TEXT("InterruptInitialize--Key_Interrupt to abc_KeyIntr_Event ok----- ./r/n")));
if(! InterruptInitialize(Key_Interrupt1, abc_KeyIntr_Event1, NULL, 0))
{
RETAILMSG(FUSQ_DEBUG,(TEXT("InterruptInitialize--Key_Interrupt to abc_KeyIntr_Event failed ./r/n")));
return FALSE;
}
abc_Key_Thread=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)abc_KeyThread_Fun,
0,
0,
NULL
);
if(!abc_Key_Thread)
{
RETAILMSG(FUSQ_DEBUG,(TEXT("CreateThread----faile--/r/n")));
return false;
}
else
RETAILMSG(FUSQ_DEBUG,(TEXT("CreateThread----OK--/r/n")));
abc_Key_Thread1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)abc_KeyThread_Fun1,
0,
0,
NULL
);
if(!abc_Key_Thread1)
{
RETAILMSG(FUSQ_DEBUG,(TEXT("CreateThread1----faile--/r/n")));
return false;
}
return true;
}
BOOL abc_Deinit(DWORD hDeviceContext)
{
RETAILMSG(FUSQ_DEBUG,(TEXT("--------abc_Deinit--/r/n")));
return true;
}
DWORD abc_Open(DWORD hDeviceContext,DWORD AccessCode,DWORD ShareMode)
{
RETAILMSG(FUSQ_DEBUG,(TEXT("--------abc_Open--/r/n")));
return true;
}
BOOL abc_Close(DWORD hOpenContext)
{
RETAILMSG(FUSQ_DEBUG,(TEXT("--------abc_Close--/r/n")));
return true;
}
bool abc_IOControl(DWORD hOpenContext,DWORD dwCode,char pBufIn[],DWORD dwLenIn,char pBufOut[],DWORD dwLenOut,PDWORD pdwActualOut)
{
//PBYTE pBufOut PBYTE pBufIn
RETAILMSG(FUSQ_DEBUG,(TEXT("--------abc_IOControl----------------/r/n")));
return true;
}
void abc_KeyThread_Fun()
{
while(1)
{
WaitForSingleObject(abc_KeyIntr_Event,INFINITE);
RETAILMSG(FUSQ_DEBUG,(TEXT("Thread is running:times==%d/r/n"),i1));
i1++;
InterruptDone(Key_Interrupt);
//OEMInterruptDone(Key_Interrupt);
}
}
void abc_KeyThread_Fun1()
{
while(1)
{
WaitForSingleObject(abc_KeyIntr_Event1,INFINITE);
RETAILMSG(FUSQ_DEBUG,(TEXT("Thread is running:times1==%d/r/n"),i2));
i2++;
InterruptDone(Key_Interrupt1);
//OEMInterruptDone(Key_Interrupt);
}
}