Wince外部中断控制LED详解---动态申请

本实例是基于S3C2440,WINCE5.0

1.中断分两大类:内部中断和外部中断。

          外部中断:由外部设备所引发的中断,这些外部中断都是通过GPIO中的中断引脚产生的。S3C2440有24个外部中断,相关的寄存器如下:

                EXTINT0-EXTINT2:三个寄存器设定EINT0-EINT23的触发方式。

                EINTFLT0-EINTFLT3:控制滤波时钟和滤波宽度。

                EINTPEND:中断挂起寄存器

                EINTMASK:中断屏蔽寄存器

         内部中断:内部中断是有CPU内部器件产生的中断,如定时器中断,USB中断,UART中断等。相关的寄存器如下:

                 SUBSRCPND:次级中断挂起寄存器。

                 INTSUBMSK:次级中断屏蔽寄存器。

                 INTMOD:中断方式寄存器

                 PRIORITY :优先级寄存器

                 SRCPND :中断挂起寄存器

                 INTMSK :中断屏蔽寄存器。

                 INTPND :中断发生后,SRCPND中会有位置1,可能好几个,这些中断会由优先级仲裁器选出一个优先级最高的,然后INTPND中相应位置1,同一时间只有一位是1。

                这里要注意一级中断和次级中断的区别,次级中断的设置要比一级中断复杂一些。
2.WINCE中断机制:ISR和IST

                WINCE中断从大的方面分为ISR和IST两部分,具体ISR,IST是什么这里就不详说了,网上一搜一大把。简单的说是ISR负责把IRQ转化为逻辑中断并返回给内核;IST则负责中断的逻辑处理。

3.WINCE中断实例:外部按键中断控制LED灯

              (1)创建一个简单的流驱动模板,这一步可以手动创建,也可以通过"Windows CE Developer Samples" -> "Windows CE 5.0 Embedded Development Labs" -> "DrvWiz.exe" 框架产生。建议采用后者,简单快捷,不易出错。这里工程命名为LED,即生产的DLL为LED_DLL。

              (2)填充函数体。这里主要介绍与中断相关的两个函数:

                              DWORD LED_Init( LPCTSTR pContext)//驱动初始化函数,主要做内存的分配和调用中断初始化函数。 

                               DWORD WINAPI  LED_IST( LPVOID lpvParam ) //中断处理线程,即IST,在这里进行中断处理.

                               DWORD InitInterrupt( void ) //中断初始化函数,包括中断寄存器的设置,事件和线程的创建,初始化等。

                   首先介绍DWORD InitInterrupt( void ),代码如下:

DWORD InitInterrupt( void )
{
 HANDLE g_htIST;  //线程返回句柄
 BOOL fRetVal;
 DWORD dwThreadID;
 printfmsg((TEXT("**************come into the setup interrupt!!!********************/r/n")));

//初始化外部中断8
      s2440IO->rGPGCON &= ~(0X3);
      s2440IO->rGPGCON  |= 0X2;//设置为中断模式
      s2440IO->rEXTINT1 &= ~(0X0f);
      s2440IO->rEXTINT1  |= 0XA;  //下降沿触发,使能滤波器
      s2440IO->rEINTMASK &= ~(1<<8);//打开中断 8
      s2440IO->rEINTPEND |= (1<<8);//清除中断
      //GPIO 设置-LED
      s2440IO->rGPBCON  = (s2440IO->rGPBCON  &~(3 << 14)) | (1<< 14); // GPB7 == OUTPUT.
      s2440IO->rGPBCON  = (s2440IO->rGPBCON  &~(3 << 16)) | (1<< 16);       // GPB8 == OUTPUT.


   s2440INTR->rINTMSK &= ~(0x20); //取消外部中断8的屏蔽
   s2440INTR->rSRCPND |= (0x20);  //清除外部中断8
   s2440INTR->rINTPND  |=0X20;    //清除外部中断,即初始化
 // Create an event
 // 创建一个事件
 g_hevInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);
 if(!g_hevInterrupt) return -10;

 // Have the OAL Translate the IRQ to a system irq
 //将物理中断IRQ转换为逻辑中断
 fRetVal = KernelIoControl( IOCTL_HAL_TRANSLATE_IRQ,
        &dwIrq,
        sizeof( dwIrq ),
        &g_dwSysInt,
        sizeof( g_dwSysInt ),
        NULL );

  
 if( !fRetVal )
 { return -1 }
  
 // Create a thread that waits for signaling
 // 创建中断服务线程IST
 g_htIST = CreateThread(NULL,// CE Has No Security
       0, // No Stack Size
       ThreadIST,// Interrupt Thread
       NULL,// No Parameters
       CREATE_SUSPENDED,// Create Suspended until we are done
       &dwThreadID // Thread Id
       );
 if( !g_htIST )
 {return -1 }
 // Set the thread priority to real time
 // 设置线程的优先级
 int m_nISTPriority = 7;
 if(!CeSetThreadPriority( g_htIST, m_nISTPriority))
 { return -1 }
 // Initialize the interrupt
 // 初始化中断,将逻辑中断号与事件关联,即中断产生时触发该事件
 //在中断服务线程IST中会等该事件的发生,即WaitForSingleObject(g_hevInterrupt, INFINITE);
 //从而中断发生就导致IST运行,处理中断任务
 if ( !InterruptInitialize(g_dwSysInt, g_hevInterrupt, NULL, 0) )
 {return -1; }
 ResumeThread( g_htIST );
      printfmsg((TEXT("*************leave the setup interrupt!!!********************/r/n")));

 return 1;
}

      简单说一下初始化中断的流程,首先是初始化相关的中断寄存器,我这里采用的是外部中断8。接下来是创建一个事件,用于关联外部中断8和IST线程。在IST中会通过dwStatus = WaitForSingleObject(g_hevInterrupt, INFINITE)来等待中断的发生。然后利用KernelIoControl( IOCTL_HAL_TRANSLATE_IRQ,
        &dwIrq, sizeof( dwIrq ), &g_dwSysInt, sizeof( g_dwSysInt ), NULL ); 将物理中断IRQ转换为逻辑中断。这是给内核用的。接着就要创建中断服务线程了:g_htIST = CreateThread(NULL,// CE Has No Security
       0, // No Stack Size
       ThreadIST,// Interrupt Thread
       NULL,// No Parameters
       CREATE_SUSPENDED,// Create Suspended until we are done
       &dwThreadID // Thread Id
       );

      这些都做好以后就可以初始化中断了.

     // Initialize the interrupt 
     // 初始化中断,将逻辑中断号与事件关联,即中断产生时触发该事件
     //在中断服务线程IST中会等该事件的发生,即WaitForSingleObject(g_hevInterrupt, INFINITE);
     //从而中断发生就导致IST运行,处理中断任务
   InterruptInitialize(g_dwSysInt, g_hevInterrupt, NULL, 0) 该函数就将物理中断对应的逻辑中断号和事件关联起来了。

    到这里整个初始化就做好了,这其中的函数调用顺序不是唯一的,但只要理清各个函数的调用顺序就行了。

    DWORD TST_Init( LPCTSTR pContext)
{
  printfmsg((TEXT("**************come into the init!!!********************/r/n")));


          // GPIO Virtual alloc
 s2440IO = (volatile IOPreg *) VirtualAlloc(0,sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS);
 if(s2440IO == NULL) {
   printfmsg((TEXT("For s2440IO: VirtualAlloc faiLED!/r/n")));
 }
 else {
  if(!VirtualCopy((PVOID)s2440IO,(PVOID)(IOP_BASE),sizeof(IOPreg),PAGE_READWRITE | PAGE_NOCACHE )) {
   printfmsg((TEXT("For s2440IO: Virtualcopy faiLED!/r/n")));
  }
 }

  s2440INTR = (volatile INTreg *) VirtualAlloc(0,sizeof(INTreg ),MEM_RESERVE, PAGE_NOACCESS);
 if(s2440INTR == NULL) {
  printfmsg((TEXT("For s2440INTR: VirtualAlloc faiLED!/r/n!/r/n")));
 }
 else {
  if(!VirtualCopy((PVOID)s2440INTR,(PVOID)(INT_BASE),sizeof(INTreg),PAGE_READWRITE | PAGE_NOCACHE )) {
   printfmsg((TEXT("For s2440INTR: Virtualcopy faiLED!/r/n!/r/n")));
  }

   InitInterrupt();
   return 0x1234;

}
    这个函数是在驱动被加载的时候调用的,所以要把初始化的任务放在这里。

     与中断相关的部分就这么多,这是动态申请中断的方法,比较复杂。其实完全可以不用动态申请的方法,而且不推荐采用此方法。静态申请是一种很好的方法,比较简单。在后面的文章会进一步讲解。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值