ZLG7290(wince下)驱动之不停执行同一动作的解决办法(作者:wogoyixikexie@gliet)
//-----------------------------------------------------------------------------------------------------------
// 日期:2009年3月23日 8:31:19
// 作者:wogoyixikexie@gliet
// 版权:桂林电子科技大学一系科协wogoyixikexie@gliet
// 平台:wince5.0 2440 5.0 BSP
// 最后修改:2009年3月23日 8:31:30
//-----------------------------------------------------------------------------------------------------------
今天,把原来4.2BSP的ZLG7290驱动搬到2440 5.0BSP下,只是简单修改一下中断的获得方式就成功了,哈哈,看到按键控制菜单真是爽呆了。可是出现了非常郁闷的事情,那就是按一下就会不停的执行按下的相应动作。这明显是中断不停的产生了,真是不知道如何搞的。现在的机子是成品不给拆卸,示波器用不上了,真是奇了,刚才我认为是是BSP没有处理好中断。OEMInterruptHandler函数有禁止中断的功能,在处理完相应的线程以后,我们必须调用InterruptDone函数来重新使能中断,我看了一下代码,发现这个OEMInterruptHandler并没有问题,并且即使没有禁止,也只会在按下的时候多次中断发生,而不会没有按的时候不停的中断。我觉得还是这个ZLG7290的问题,极有可能他不停的产生了中断信号,明天使用示波器之后就会知道了。
现在不妨看看这个键盘驱动是怎么回事。在命令行窗口输入 dumpbin /exports 键盘驱动DLL
--明天继续吧,下班打篮球了。
继续.........
先来看看这个DLL到处了什么函数。
LIBRARY LAYOUTMANAGER——哈哈,这个名字可以改动的吗?以前没有注意这个问题。
EXPORTS
KeybdDriverInitializeEx
KeybdDriverPowerHandler
KeybdDriverGetInfo
KeybdDriverSetMode
KeybdDriverInitStates
KeybdDriverVKeyToUnicode
KeybdDriverMapVirtualKey
LayoutMgrGetKeyboardType
LayoutMgrGetKeyboardLayout
LayoutMgrGetKeyboardLayoutName
LayoutMgrGetKeyboardLayoutList
LayoutMgrLoadKeyboardLayout
LayoutMgrActivateKeyboardLayout
IL_00000409
Matrix
PS2_AT_00000409
从这些函数找突破口很容易找到问题所在。
根据现象,我觉得产生这种原因有两种可能:一个是中断不停的产生,一个是没有检测按键弹起出了问题。我设置接ZLG7290的中断引脚的EINT11为双边沿触发的?难道上升沿触发无效(即检测按键弹起)?好用sunrain_hjb的工具修改一下中断方式看看到底是怎么回事。
0x22224242是把EINT11设置成上升沿触发(检测键盘弹起中断),这样之后按键按下弹起不会做任何动作了,难道真的是没有检测到上升沿中断?我把把EINT11设置成下降沿触发(检测键盘按下中断),按键又能工作了,效果和双边触发一样。上面的猜测不一定成功,要把键盘的IST移到BSP中加入打印信息就知道是否产生了上升沿触发中断了。
郁闷,当设置成上升沿触发的时候果然什么反映都没有啊,怎么搞的?难道上升沿是什么事情都不做?
我在keyboard IST里面加了打印信息,来看看按一次是否能产生两次中断。
BOOL
KeybdIstLoop(
PKEYBD_IST pKeybdIst
)
{
SETFNAME(_T("KeybdIstLoop"));
UINT32 rguiScanCode[16];
BOOL rgfKeyUp[16];
UINT cEvents;
// add by wogo at 2009-03-12
RETAILMSG(1, (TEXT("In KeybdIstLoop Funtion:\r\n")));
DEBUGCHK(pKeybdIst->hevInterrupt != NULL);
DEBUGCHK(pKeybdIst->pfnGetKeybdEvent != NULL);
DEBUGCHK(pKeybdIst->pfnKeybdEvent != NULL);
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
wait_for_keybd_interrupt:
if (WaitForSingleObject(pKeybdIst->hevInterrupt, INFINITE) == WAIT_OBJECT_0)
{
// add by wogo at 2009-03-12
RETAILMSG(1, (TEXT("Deal with hevInterrupt@@@!!! :\r\n")));
cEvents = (*pKeybdIst->pfnGetKeybdEvent)
(pKeybdIst->uiPddId, rguiScanCode, rgfKeyUp);
for (UINT iEvent = 0; iEvent < cEvents; ++iEvent) {
(*pKeybdIst->pfnKeybdEvent)(pKeybdIst->uiPddId,
rguiScanCode[iEvent], rgfKeyUp[iEvent]);
}
// cEvents could be 0 if this was a partial scan code, like 0xE0
InterruptDone(pKeybdIst->dwSysIntr_Keybd);
// add by wogo at 2009-03-12
RETAILMSG(1, (TEXT("InterruptDone(pKeybdIst->dwSysIntr_Keybd)@@@!!! :\r\n")));
}
goto wait_for_keybd_interrupt;
ERRORMSG(1, (TEXT("KeybdIstLoop: Keyboard driver thread terminating.\r\n")));
RETAILMSG(1, (TEXT("KeybdIstLoop: Keyboard driver thread terminating!!! :\r\n")));
return TRUE;
}
找到问题了,果然按下一次按键只打印了如下信息
Deal with hevInterrupt@@@!!! :
InterruptDone(pKeybdIst->dwSysIntr_Keybd)@@@!!! :
按照常理,使用双边触发,按一次应该打印如下。
Deal with hevInterrupt@@@!!! :
InterruptDone(pKeybdIst->dwSysIntr_Keybd)@@@!!! :
Deal with hevInterrupt@@@!!! :
InterruptDone(pKeybdIst->dwSysIntr_Keybd)@@@!!! :
现在难搞了,使用应用程序去读中断寄存器的设置,读出是0x22226242,这个和要求完全吻合,怎么就不产生双边沿触发呢?难道是干扰?我的天啊,真是越来越神奇了。神啊,救救我吧!
后来我根据CSDN的shuiyan牛人的建议做了如下事情:
一、在按下之后禁止下降沿中断,使能上升沿中断——》结果:当按下键盘太久的时候,可以产生弹起中断,快点只能产生按下中断;配置成双边触发却不行,这个说明双边触发的反映速度比单片触发要慢。
二、把中断线程里面的代码全部删除——》结果:可以产生按下、弹起中断。这个足以证明是中断处理线程调用的ZLG7290的键盘扫描函数花掉了大量时间,后来我把里面的for循环延时全部删除,但是还是无济于事,后来逼急了想了个绝招——在按下之后设置一个标志告诉系统,已经按下,这样系统就不会不停的做同一件事情啊。结果成功解决问题。
现在把结果公布,造福后人——把微软的键盘IST移植到BSP下添加的。
键盘功能通过偏方实现了功能,但是不能扑捉到键盘弹起中断的问题依然没有解决。
我在按下线程里面加了一个键盘弹起的标志,告诉系统,就这样,这个键盘就搞定了。哈哈
哎,就是加了两行东西。
wait_for_keybd_interrupt:
if (WaitForSingleObject(pKeybdIst->hevInterrupt, INFINITE) == WAIT_OBJECT_0)
{
// add by wogo at 2009-03-12
//RETAILMSG(1, (TEXT("Deal with hevInterrupt@@@!!! :\r\n")));
//#if 0
cEvents = (*pKeybdIst->pfnGetKeybdEvent)
(pKeybdIst->uiPddId, rguiScanCode, rgfKeyUp);
//
//RETAILMSG(1, (TEXT("cEvents=%d\r\n"), cEvents));
for (UINT iEvent = 0; iEvent < cEvents; ++iEvent) {
//UINT iEvent = 0
(*pKeybdIst->pfnKeybdEvent)(pKeybdIst->uiPddId, rguiScanCode[iEvent], rgfKeyUp[iEvent]);
rgfKeyUp[iEvent]=TRUE;——我原来太执着于本身了,不过键盘功能是实现了,但是本质没有解决。
(*pKeybdIst->pfnKeybdEvent)(pKeybdIst->uiPddId, rguiScanCode[iEvent], rgfKeyUp[iEvent]);
}
// cEvents could be 0 if this was a partial scan code, like 0xE0
//#endif
InterruptDone(pKeybdIst->dwSysIntr_Keybd);
// add by wogo at 2009-03-12
//RETAILMSG(1, (TEXT("InterruptDone.Keybd)\r\n")));
}
感谢各位关照,尤其是shuiyan前辈,他自己忙着加班,还要回我的问题。
现在来对键盘驱动做个总结吧。
MDD太复杂了,这里就不谈了,现在就来谈PDD和IST
C:\WINCE500\PLATFORM\SMDK2440A\Src\Drivers\Keybd\Kbdcommon里面的东西构成了PDD
初始化(中断,IO等)——》申请中断——》调用键盘IST——》等待中断(MDD IST)
下面代码相当重要,用来绑定IST,使MDD和PDD紧密结合起来。
KEYBD_IST keybdIst;
keybdIst.hevInterrupt = m_hevInterrupt;
keybdIst.dwSysIntr_Keybd = dwSysIntr_Keybd;
keybdIst.uiPddId = v_uiPddId;
keybdIst.pfnGetKeybdEvent = KeybdPdd_GetEventEx2;
keybdIst.pfnKeybdEvent = v_pfnKeybdEvent;
KeybdIstLoop(&keybdIst);
论坛同步帖子http://topic.csdn.net/u/20090312/14/51c097e2-11a8-49eb-b5f0-38bf15d84107.html