首先:介绍一下wince中断处理过程,
1、当一个中断发生后,发送到内核异常处理器(ExceptionHandler)
2、内核的中断支持处理器调用OAL层函数OEMInterruptDisable 屏蔽中断(..\hal\Cfw.c)
屏蔽掉所有优先级等于或是小于当前优先级的中断
3、内核调用ISR,ISR 返回中断号(逻辑中断标识符)给内核。
内核的处理程序打开除当前外的所有中断,然后内核根据此中断号绑(InterruptInitialize函数 绑定中断号核事件)的事件(Event)唤醒事件的等待线程(IST),IST 在用户态完成中断处理。
4、IST 调用InterruptDone 来告诉操作系统中断处理完毕,操作系统再次调用OAL 中
OEMInterruptDone函数完 成中断的处理。
5、IST调用InterruptDone函数来通知系统已经完成中断的处理。
这个函数会调用OAL层的OEMinterruptDone函数,它会重新开启当前中断
WinCE的中断处理模型
二、WinCE中断体系结构
从结构上看,WinCE中断涉及4 层,即:硬件层、内核层、OAL层、IST处理层。了解这 4层之间的交互传递将对我们了解WinCE中断处理很有帮助。
1、硬件层:
硬件层就是实际触发中断的硬件,这里主要有两方面作用,一个是触发中断,第二个是enable/disable硬件中断。 1、层即上述模型中的第一部分 中断相应 产生物理IRQ
2、OAL层
这一层主要就是我们需要实现的代码了,来识别硬件IRQ,对应到SYSINTR。 上述模型中的内核
3、内核层:
这一层由内核来处理,包括中断异常产生后跳转到相应的ISR,以及根据SYSINTR 来触发相应的Event。关于SYSINTR 和 IRQ 的概念后面会说明。
4、IST处理层
一般使用 IST 来做实际的中断处理,这样不会占用很多的锁定系统时间来处理中断,但是对中断的实时性大打折扣
三、WinCE中断处理实例(按键控制LED)
详细代码下载地址:http://download.csdn.net/detail/lyx123/4525808
大致步骤如下:
1. 初始化GPIO口
2、 创建事件
3、 获取IRQ的系统中断号
4、 创建挂起的中断服务线程IST
5、 调用InterruptInitialize以创建IRQ与事件之间的关联。(创建未挂起的中断服务线程有可能导致InterruptInitialize函数调用失败,因为该事件已经处于等待状态)
6、 调用CeSetThreadPriority函数设置IST的优先级
7、 启动IST线程
采用流驱动编写
1.初始化GPIO口
//声明的一些变量
HANDLE m_interruptTestEvent = NULL;
HANDLE m_interrupTestThread = NULL;
DWORD m_interruptTestSysId = SYSINTR_UNDEFINED;
DWORD m_interruptTestPhyId = 0;
LPDWORD lpThreadId = NULL;
DWORD threadpriority = 6;
BOOL m_ExitThread = FALSE ;
void InitInterruptTestGPIO(void)
{
RETAILMSG(1,(TEXT("***test InitInterruptTestGPIO \r\n")));
// interrupt led test 中断控制的led灯
v_pIOPregs->GPMCON &= 0xfffffff0; //set pin out
v_pIOPregs->GPMCON |= 0x1;
v_pIOPregs->GPMPUD &= 0xfffffffc ; //enable up
v_pIOPregs->GPMPUD |= 0x2;
//interrup sourse gpn0 设置gpn0脚为中断源
v_pIOPregs->GPNCON &= 0xfffffffc;
v_pIOPregs->GPNCON |= (0x2<<0);
//pull up enable
v_pIOPregs->GPNPUD &= 0xfffffffc;
v_pIOPregs->GPNPUD |= (0x2<<0);
//filter enable
v_pIOPregs->EINT0FLTCON0 = (v_pIOPregs->EINT0FLTCON0 & ~(0x1<<6)) |(0x1<<7);
//Configurate the EINT0 Trigger of Flowing Type 01x 配置EINT0为下降沿触发
v_pIOPregs->EINT0CON0 &= 0xfffffff8;
v_pIOPregs->EINT0CON0 |= (0x2<<0);
}
2.使能中断
BOOL Enble_Test_Interrupt(void)
{
//clear interrupt eint 0
v_pIOPregs->EINT0PEND = (0x1<<0);
//网上有说v_pIOPregs->EINT0PEND = (0x1<<0) 与v_pIOPregs->EINT0PEND |=(0x1<<0);
//有差,前者是清除位元,后者是全部位清除,我试了都可以,还得好好研究
//ENable Interrupt MASK EINT0
v_pIOPregs->EINT0MASK =v_pIOPregs->EINT0MASK & ~(0x1<<0);
return true;
}
3.物理中断映射成系统中断号,创建中断事件及中断处理线程
BOOL InitInterruptTest(void)
{
RETAILMSG(1,(TEXT("******testInitInterruptTest\r\n")));
m_interruptTestPhyId = IRQ_EINT0;//物理中断号
//物理中断映射成系统中断号
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,&m_interruptTestPhyId,sizeof(DWORD),&m_interruptTestSysId,sizeof(DWORD),NULL))
{
RETAILMSG(1,(TEXT("******test KernelIoControlt fail\r\n")));
m_interruptTestSysId = SYSINTR_UNDEFINED;
return FALSE;
}
//create an event
m_interruptTestEvent = CreateEvent(NULL, FALSE, FALSE,NULL);
if (NULL == m_interruptTestEvent)
{
RETAILMSG(1,(TEXT("******test create event fail\r\n")));
return FALSE;
}
// 创建一个挂起的线程
m_interrupTestThread = CreateThread(NULL, // Security
0, // No Stack Size
(LPTHREAD_START_ROUTINE)Threadproc,//Interrupt Thread /*参数必须与中断处理函数名称一样*/
NULL, // No Parameters
CREATE_SUSPENDED, // Create Suspended
lpThreadId ); // Thread Id );
// set the thread priority
threadpriority = 6;
if( !CeSetThreadPriority( m_interrupTestThread, threadpriority))
{
RETAILMSG(1,(TEXT("test: Failed setting Thread Priority.\r\n")));
return FALSE;
}
//initialize interrupt event
if (!InterruptInitialize(m_interruptTestSysId,m_interruptTestEvent,NULL,0))
{
ERRORMSG( 1, (TEXT("test interrupt is not initialized\n\r")));
return(FALSE);
}
//启动线程
ResumeThread( m_interrupTestThread );
return TRUE;
}
4.中断线程处理函数
DWORD WINAPIThreadproc(LPVOID lpvParam)
{
DWORD dwStatus;
BOOL fState = TRUE;
static BOOL count = TRUE;
RETAILMSG(1,(TEXT("entry test thread \r\n")));
while (!m_ExitThread)
{
dwStatus = WaitForSingleObject(m_interruptTestEvent,INFINITE);
if (m_ExitThread)
{
break;
}
if (dwStatus == WAIT_OBJECT_0)
{
RETAILMSG(1,(TEXT("test thread happend \r\n")));
}
count = ~count;
if(count&0x1)
v_pIOPregs->GPMDAT |= 0x1; //灯灭
else
v_pIOPregs->GPMDAT &= 0xfffffffe;//灯亮
InterruptDone(m_interruptTestSysId);
Enble_Test_Interrupt();
}
return FALSE;
}