WinCE 6.0中断驱动程序分析

简介: Windows Embedded CE 6.0的中断处理过程主要分为两部分:  中断服务例程(ISR):处于内核中的低级处理程序,中断发生时首先被调用。中断服务线程(IST):处于驱动或者应用中的中断处理线程,由系统调度,完成大部分的中断处理工作。

Windows Embedded CE 6.0的中断处理过程主要分为两部分:

  •  中断服务例程(ISR):处于内核中的低级处理程序,中断发生时首先被调用。
  • 中断服务线程(IST):处于驱动或者应用中的中断处理线程,由系统调度,完成大部分的中断处理工作。

ISR的实现在OALOEM适配层)中,它只处理最低级的中断响应,通常是获取IRQSYSINTR并设置MCU内部的中断控制寄存器。中断处理的主要部分在驱动或者应用的中断处理线程中。中断处理线程与其他普通线程一样,使用同一个线程优先级管理系统。ISRIST之间通过事件对象进行同步。IST中创建一个事件对象,并使用函数WaitForSingleObject()等待该事件被触发。ISR中通知内核触发相应的事件对象。Windows Embedded CE 6.0的中断处理的过程如下图所示。

                       Windows Embedded CE 6.0 的中断处理过程

  在其他的一些嵌入式操作系统中,在介绍中断处理时经常会提到一个中断向量表的概念,如uC/OS。当中断发生时它会进入IRQ的处理程序,并根据IRQ的值跳转到事先分配好的中断向量表相应的中断处理函数中。但在WinCE中实际上并不存在中断向量表的概念,而只有一个异常向量表,对应于MCU的几种运行模式。WinCE的中断处理对应于两个异常IRQHandlerFIQHandler,通常我们使用的是IRQHandler。当外部中断产生时,系统执行IRQHandler(),IRQHandler()中调用OEMInterruptHandler()获取IRQ对应的SYSINTR,然后根据SYSINTR调用函数OEMNotifyIntrOccurs()触发与SYSINTR关联的事件,最后由IST完成主要的中断处理工作。这种中断处理机制在一定程度上影响了系统的实时性,但提高了IST的灵活性。有关WinCE系统实时性分析,将在另外一篇中描述。

     下面结合DEVICEEMULATORPWRBUTTON驱动进行分析。该驱动也是一个流驱动,所以可以用驱动调试助手进行动态加载和卸载,但需要对代码进行相应的修改,否则会出问题。

    首先看PBT_Init()函数,代码如下:

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif Code
DWORD
PBT_Init(DWORD dwContext)
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
{
    DWORD   IDPowerButtonThread;
    DWORD   IDResetButtonThread;
    HMODULE hmCore;

    
//
    
// 从CORE Library中获取电源管理器"SetSystemPowerState"的函数指针/
    pfnSetSystemPowerState = NULL;

    hmCore 
= (HMODULE) LoadLibrary(_T("coredll.dll"));

    
if(hmCore != NULL)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        pfnSetSystemPowerState 
= (PFN_SetSystemPowerState) GetProcAddress(hmCore, _T("SetSystemPowerState"));

        
if(pfnSetSystemPowerState == NULL)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
{
            FreeLibrary(hmCore);
        }

    }


    
//初始化相关的虚拟内存地址
    InitializeAddresses();

    
// 创建POWER Button的IST和RESET Button的IST
    ResetButtonIntrThreadHandle = CreateThread(00, (LPTHREAD_START_ROUTINE) ResetButtonIntrThread, 00&IDResetButtonThread);
    
if (ResetButtonIntrThreadHandle == 0)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        RETAILMSG(
1, (TEXT("PBT: CreateThread() Fail\r\n")));
    }

    PowerButtonIntrThreadHandle 
= CreateThread(00, (LPTHREAD_START_ROUTINE) PowerButtonIntrThread, 00&IDPowerButtonThread);
    
if (PowerButtonIntrThreadHandle == 0)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        RETAILMSG(
1, (TEXT("PBT: CreateThread() Fail\r\n")));
    }


    
return (dwContext);
}

      RESET ButtonISTPOWER ButtonIST基本一致,所以这里只分析POWER ButtonIST,代码如下。      

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif Code
static DWORD
PowerButtonIntrThread(PVOID pArg)
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
{
    
//初始化中断寄存器,使能相应的中断
    EnablePowerButtonInterrupt();

    
//创建一个事件
    PwrButtonIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    
//
    
// 根据IRQ获取一个SYSINTR
    
//
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &PwrButtonIrq, sizeof PwrButtonIrq, &PwrButtonSysIntr, sizeof PwrButtonSysIntr, NULL))
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        RETAILMSG(
1, (TEXT("PBT: Error! Failed to request sysintr value for power button interrupt.\r\n")));
        
return(0);
    }

    
    
//关联SYSINTR和之前创建的事件
    if (!(InterruptInitialize(PwrButtonSysIntr, PwrButtonIntrEvent, 00)))
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        RETAILMSG(
1, (TEXT("ERROR: PwrButton: Interrupt initialize failed.\r\n")));
    }


    
//POWER Button按下的处理程序
    for (;;)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        WaitForSingleObject(PwrButtonIntrEvent, INFINITE);
        
        
if (PowerButtonIsPushed()) //确认按键确实被按下,消除抖动
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
        {
            Sleep(
200);         //延迟200ms,排除长按的情况
            if (!PowerButtonIsPushed())    //按键被有效释放
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
            {
                
//
                
//关闭系统 
                
//
                if(pfnSetSystemPowerState != NULL)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                
{
                    RETAILMSG(
1,(TEXT("PBT: Signalling power manager to suspend\r\n")));
                    pfnSetSystemPowerState(NULL, POWER_STATE_SUSPEND, POWER_FORCE);
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                }
 else {
                    RETAILMSG(
1,(TEXT("PBT: Suspending by calling PowerOffSystem\r\n")));
                    PowerOffSystem();
                }

                
//
                
//结束当前线程的时间片
                Sleep(0);
            }

            
else
                RETAILMSG(
1,(TEXT("PBT: Button held too long (ignored)\r\n")));
        }

        
else
            RETAILMSG(
1,(TEXT("PBT: Feeble button press or noise triggered it (ignored)\r\n")));

        InterruptDone(PwrButtonSysIntr);
    }

}

    以上代码结构清晰,不再赘述。但这样编译出来的驱动是不能通过驱动调试助手动态加载的,必须进行相应的修改才行。主要原因是没有善始善终,分配的系统逻辑中断没有释放,系统逻辑中断与事件的关联也没有取消。实验现象是,能通过驱动调试助手加载卸载,但中断并不能正常工作了。下面介绍一下解决这个问题的办法。

  首先定义一个全局变量g_bThreadExit初始化为FALSE。IST修改后的代码如下:

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif Code
static DWORD
PowerButtonIntrThread(PVOID pArg)
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
{
//初始化中断寄存器,使能相应的中断
    EnablePowerButtonInterrupt();

    
//创建一个事件
    PwrButtonIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    
//
    
// 根据IRQ获取一个SYSINTR
    
//
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &PwrButtonIrq, sizeof PwrButtonIrq, &PwrButtonSysIntr, sizeof PwrButtonSysIntr, NULL))
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        RETAILMSG(
1, (TEXT("PBT: Error! Failed to request sysintr value for power button interrupt.\r\n")));
        
return(0);
    }

    
    
//关联SYSINTR和之前创建的事件
    if (!(InterruptInitialize(PwrButtonSysIntr, PwrButtonIntrEvent, 00)))
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        RETAILMSG(
1, (TEXT("ERROR: PwrButton: Interrupt initialize failed.\r\n")));
    }

    
    
// POWER Button按下的处理程序
    for (;;)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif    
{
        WaitForSingleObject(PwrButtonIntrEvent, INFINITE);
                
        
if(g_bThreadExit)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif        
{
            
break;    
        }


        
if (PowerButtonIsPushed())     //确认按键确实被按下,消除抖动
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
        {
            Sleep(
200);         //延迟ms,排除长按的情况
            if (!PowerButtonIsPushed())    //按键被有效释放
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif
            {
                
//
                
//关闭系统
                
//
                if(pfnSetSystemPowerState != NULL)
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                
{
                    RETAILMSG(
1,(TEXT("PBT: Signalling power manager to suspend\r\n")));
                    pfnSetSystemPowerState(NULL, POWER_STATE_SUSPEND, POWER_FORCE);
img_2887d91d0594ef8793c1db92b8a1d545.gifimg_7a2b9a960ee9a98bfd25d306d55009f8.gif                }
 else {
                    RETAILMSG(
1,(TEXT("PBT: Suspending by calling PowerOffSystem\r\n")));
                    PowerOffSystem();
                }

                
//
                
//结束当前线程的时间片
                
//
                Sleep(0);
            }

            
else
                RETAILMSG(
1,(TEXT("PBT: Button held too long (ignored)\r\n")));
        }

        
else
            RETAILMSG(
1,(TEXT("PBT: Feeble button press or noise triggered it (ignored)\r\n")));

        InterruptDone(PwrButtonSysIntr);
    }

    
    
//取消IRQ与SYSINTR之间的关联
    KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR,&PwrButtonSysIntr, sizeof(UINT32),NULL,0, NULL);
    
    
//取消Event与PwrButtonSysIntr之间的关联
    InterruptDisable(PwrButtonSysIntr);

    CloseHandle(PwrButtonIntrEvent);
    
    RETAILMSG(
1, (TEXT("PowerButtonIntrThread Exit.\r\n")));
    
return 0;
}

  PBT_Deinit()修改后的代码如下:

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif Code
BOOL
PBT_Deinit(DWORD dwContext)
img_405b18b4b6584ae338e0f6ecaf736533.gifimg_1c53668bcee393edac0d7b3b3daff1ae.gif
{
    RETAILMSG(
1, (TEXT("PBT: PBT_Deinit()\r\n")));
    
//设置退出线程的标志
g_bThreadExit = TRUE;
    
//模拟一个中断事件
SetInterruptEvent(PwrButtonSysIntr);
    
//延迟500ms,确保IST退出
Sleep(500);

    
return (TRUE);
}

  经过以上修改,该中断驱动程序就可以通过驱动调试助手动态加载和卸载,并能正常工作了。另外,在模拟器中由于没有外部中断按键,可以通过创建一个特定名称的事件与中断关联,并在另外一个应用或者驱动中设置该事件以模拟一个外部中断按键的触发,这种方法也可以在实际平台中根据需要使用。示例代码如下:

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif Code
//打开与中断关联的事件
gIntrEvent = CreateEvent(NULL, FALSE, FALSE, _T("PBTINTR"));
//设置该事件,模拟一个中断的触发
SetEvent(gIntrEvent);
IST中创建与中断关联的事件代码修改如下:
PwrButtonIntrEvent 
= CreateEvent(NULL, FALSE, FALSE, _T("PBTINTR"));

  总的来说,WinCE中断处理过程结构清晰,方便开发人员灵活设计IST。在使用驱动调试助手调试有关中断的驱动程序时,需要善始善终,否则会出现中断不能正常工作的情况。

目录
相关文章
|
1天前
|
编译器 C语言 C++
C语言,C++编程软件比较(推荐的编程软件)
C语言,C++编程软件比较(推荐的编程软件)
|
7月前
|
安全 Linux 数据安全/隐私保护
有什么事让你觉得在Linux上顺理成章,换到Windows上就令你费解?
有什么事让你觉得在Linux上顺理成章,换到Windows上就令你费解?
56 0
|
11月前
|
Windows
程序填空题
程序填空题
174 0
|
11月前
|
C++
C++ <windows.h>库函数探究初步续一:键鼠操作
C++ <windows.h>库函数探究初步续一:键鼠操作
184 0
|
编译器 C语言 C++
Win知识 - 程序是怎样跑起来的——通过编译器输出汇编语言的源代码
Win知识 - 程序是怎样跑起来的——通过编译器输出汇编语言的源代码
200 0
|
C语言 C++ 开发者
三子棋小游戏及如何让朋友也能玩自己写的游戏(程序)(exe如何附带动态链接库dll)C语言从入门到入土(入门特别篇)(二)
一:三子棋 1.游戏的基本开始流程() 2.三子棋的实现 2.1第一步写出基本流程 2.2第二步打印菜单 2.3游戏的实现 2.3.1初始化棋盘 2.3.2打印棋盘 2.3.3玩家下棋 2.3.4电脑下棋 2.3.5判断 2.4游戏的整个代码 game.c: 2.5三子棋的扩展 二:vs如何发布exe文件并附带动态链接库 第一步:vs->工具->命令行->开发者 PowerShell(P) 第二步:查看vs 是Debug还是Releas 是x86还是x64 第三步:找到exe所在位置 第四步:查询你exe文件所需要的的动态链接库(dll)
三子棋小游戏及如何让朋友也能玩自己写的游戏(程序)(exe如何附带动态链接库dll)C语言从入门到入土(入门特别篇)(二)
|
C语言 C++ 开发者
三子棋小游戏及如何让朋友也能玩自己写的游戏(程序)(exe如何附带动态链接库dll)C语言从入门到入土(入门特别篇)(三)
一:三子棋 1.游戏的基本开始流程() 2.三子棋的实现 2.1第一步写出基本流程 2.2第二步打印菜单 2.3游戏的实现 2.3.1初始化棋盘 2.3.2打印棋盘 2.3.3玩家下棋 2.3.4电脑下棋 2.3.5判断 2.4游戏的整个代码 game.c: 2.5三子棋的扩展 二:vs如何发布exe文件并附带动态链接库 第一步:vs->工具->命令行->开发者 PowerShell(P) 第二步:查看vs 是Debug还是Releas 是x86还是x64 第三步:找到exe所在位置 第四步:查询你exe文件所需要的的动态链接库(dll)
|
C语言 C++ 开发者
三子棋小游戏及如何让朋友也能玩自己写的游戏(程序)(exe如何附带动态链接库dll)C语言从入门到入土(入门特别篇)(一)
一:三子棋 1.游戏的基本开始流程() 2.三子棋的实现 2.1第一步写出基本流程 2.2第二步打印菜单 2.3游戏的实现 2.3.1初始化棋盘 2.3.2打印棋盘 2.3.3玩家下棋 2.3.4电脑下棋 2.3.5判断 2.4游戏的整个代码 game.c: 2.5三子棋的扩展 二:vs如何发布exe文件并附带动态链接库 第一步:vs->工具->命令行->开发者 PowerShell(P) 第二步:查看vs 是Debug还是Releas 是x86还是x64 第三步:找到exe所在位置 第四步:查询你exe文件所需要的的动态链接库(dll)
三子棋小游戏及如何让朋友也能玩自己写的游戏(程序)(exe如何附带动态链接库dll)C语言从入门到入土(入门特别篇)(一)
|
C语言 C++ 开发者
三子棋小游戏及如何让朋友也能玩自己写的游戏(程序)(exe如何附带动态链接库dll)C语言从入门到入土(入门特别篇)(四)
一:三子棋 1.游戏的基本开始流程() 2.三子棋的实现 2.1第一步写出基本流程 2.2第二步打印菜单 2.3游戏的实现 2.3.1初始化棋盘 2.3.2打印棋盘 2.3.3玩家下棋 2.3.4电脑下棋 2.3.5判断 2.4游戏的整个代码 game.c: 2.5三子棋的扩展 二:vs如何发布exe文件并附带动态链接库 第一步:vs->工具->命令行->开发者 PowerShell(P) 第二步:查看vs 是Debug还是Releas 是x86还是x64 第三步:找到exe所在位置 第四步:查询你exe文件所需要的的动态链接库(dll)
三子棋小游戏及如何让朋友也能玩自己写的游戏(程序)(exe如何附带动态链接库dll)C语言从入门到入土(入门特别篇)(四)
|
数据库 数据库管理