如何在wince 5.0 增加自定义系统中断 是ARM平台

xushangjin   2008-10-28 15:09 楼主
还有个问题 就是wince5.0中的系统中断在哪里定义的啊,比如键盘的SYSINTR_KEYBOARD 一直没有找到 请高手指点

回复评论 (8)

在Windows CE增加自定义中断处理



ISQ --> Interrupt ID(逻辑中断号)  --> Event对象。

当中断发生时,ISR(中断服务例程)返回该中断号对应的逻辑中断号,然后尽可能快地返回;随后CE就set该逻辑中断号对应的Event对象(如果有的话),以唤醒在该Event等待的IST(中断服务线程),大部分工作都是由IST来完成。一般来说IST是存在驱动程序里,单其实放在普通的应用程序里也可以,尤其是对应只有一个应用程序使用的特殊硬件更方便。因为对应CE来说其实驱动程序也只是一个普通的DLL,也是运行在用户空间。

为了简单起见我们就直接修改BSP包的ISR部分,IST也直接在应用程序里实现,步骤如下:

1、在BSP的oalintr.h里定义自定义中断的逻辑中断值,如:

            #define SYSINTR_MYINTR  (SYSINTR_FIRMWARE + 10)

2、修改KERNEL\HAL\cfw.c中的以下三个函数,增加对自定义中断的启用禁用代码:

           OEMInterruptEnable(), OEMInterruptDisable(), OEMInterruptDone()

3、修改KERNEL\HAL\ARM\armint.c中的OEMInterruptHandler(),对irq返回逻辑中断号,如:

else if (IntPendVal == INTSRC_EINT2) // EINT2

    return(SYSINTR_MYINTR);

4、在PlatformBuilder中重新生成nk.bin,下载运行。

现在,内核已经支持我们的自定义中断SYSINTR_MYINT了,我们在应用程序中就可以把这个SYSINTR_MYINT与一个Event对象关联起来,然后在一个线程里等待这个Event就ok了,这个线程就是IST。

5、在IST里用InterruptInitialize()将自定义中断和Event关联起来,并WaitForSingleObject()。注意下面的代码是在一个线程里(即IST):

hEvent = CreateEvent(NULL, FALSE, FALSE, NULL));

InterruptInitialize(SYSINTR_MYINTR, hEvent, NULL, 0));     //若没有修改OEMInterruptEnable(),这个调用就会失败

while ( TRUE )

{

    WaitForSingleObject(hEvent, INFINITE);

    // do some process...

}
这个帖子你也可以参考一下。网卡驱动开发。这是标准5.0BSP的一些方法,我上面是4.2升级到5.0的BSP方法


点赞  2008-10-28 15:23
那wince5.0中的系统中断在哪里定义的啊,比如键盘的SYSINTR_KEYBOARD ?  SYSINTR_KEYBOARD 应该是本来就有的吧 4.2在oalintr.h中定义了很多系统中断号 5.0就没找到啊!
点赞  2008-10-28 23:53
引用: 引用 2 楼 panxirun 的回复:
那wince5.0中的系统中断在哪里定义的啊,比如键盘的SYSINTR_KEYBOARD ?  SYSINTR_KEYBOARD 应该是本来就有的吧 4.2在oalintr.h中定义了很多系统中断号 5.0就没找到啊!

我上面不是给出了5.0的 链接地址吗?
http://topic.eeworld.net/u/20081027/19/3f0a9112-a377-4f31-9184-3bdea075a65c.html----------这个
点赞  2008-10-29 08:29
引用: 引用 2 楼 panxirun 的回复:
那wince5.0中的系统中断在哪里定义的啊,比如键盘的SYSINTR_KEYBOARD ?  SYSINTR_KEYBOARD 应该是本来就有的吧 4.2在oalintr.h中定义了很多系统中断号 5.0就没找到啊!

你所谓的SYSINTR_KEYBOARD逻辑中段可能在5.0中对应的是另一个名字呢?找到定义逻辑中断的文件,找找看,如果实在没有,那么,就在这个文件中自己添加一个,这样肯定是可以的,当然,要符合逻辑中断定义范围
(我是在6.0下做的开发,可能不怎么相同,应该有相通之处吧,我已经把问题的处理过程记录在博客上了,如果有兴趣,你可以看看)
点赞  2008-10-29 09:28
SYSINTR_KEYBOARD不一定需要定义,完全可以通过IOCTL_HAL_REQUEST_SYSINTR动态申请
所以有可能5.0下面改成了动态申请,所以你找不到相关的定义了
点赞  2008-10-29 09:35
建议你看看下面这篇文章,我的博客你也去看看,我原创了一些。也转载了不少。

//=============================================================
Windows CE5.0内核启动分析

移植或者创建一个BSP,也许需要先熟悉Windows CE的内核启动过程.

目录

基于ARM的Windows CE内核启动分析1

1.startup.s2

2.KernelStart2

2.1 ARMInit()3

2.1.1 OALIntrInit3

2.1.2 OALTimerInit4

2.1.2.1 Variable Tick Scheduler4

2.2 KernelInit()4

2.3 FirstSchedule5



1.startup.s

内核入口点startup.S,内核从这里启动.因为内核经过bootloader加载,内核运行时候,已经由bootloader完成了硬件的基本初始化(关闭watchdog, pll设置等等)所以,startup.S的任务比较简单,只是将oemaddrtab_cfg.inc里面的g_oalAddressTable数组地址作为参数,传递给KernelStart,这个数组用来描述和实现物理地址到虚拟地址的映射.

(. + 8)是流水线处理.KernelStart()位于

PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\armtrap.s

2.KernelStart

ARMInit()位于本目录的mdram.c文件.

KernelInit()位于PRIVATE\WINCEOS\COREOS\NK\KERNEL\kwin32.c中.

FirstSchedule()位于armtrap.s的一个label.

主要关注ARMInit()和KernelInit(),前一个进行目标板的初始化,后一个负责内核的初始化.FirstSchdule()开始调度第一个程序.

2.1 ARMInit()

先看看ARMInit()它的几个关键性动作如下:

KernelRelocate()是进行重定位.KernelFindMemory()是查找系统可用内存,并分成应用内存和object store两部分.这2个函数都已由MS自己实现.我们需要添加的函数是名字以OEM开头的函数.

OEMInitDebugSerial()初始化一个调试口,我们一般使用一个串口来作为调试口,这个函数需要自己实现,在 PLATFORM\SMDK2440A\Src\Kernel\Oal\debug.c中定义这个函数.比如可以将串口0设置为调试口,在这个函数中对串口0进行初始化.

OEMInit()是一个比较重要的函数,

OALCacheGlobalsInit()在PLATFORM\COMMON\SRC\ARM\COMMON\CACHE\init.s中实现,这部分代码以PQOAL的形式提供.

OALIntrInit()初始化中断.

OALTimerInit()初始化定时器TIMER4,作为系统时钟(tick),

configGPIO()初始化gpio口,设置相关寄存器.

InitDisplay()初始化LCD.有时候,我们希望在oal启动和内核加载期间显示一副等待图片或者显示LOGO,为达到这个目的,需要先初始化LCD.

OALKitlStart()准备启动KITL.

此外,在ARMInit还会通过调试口打印一些基本信息,开始时候打印”Windows CE Kernel for ARM….”字样, 中间打印处理器类型等等信息.结束时候打印” ARMInit done.”

2.1.1 OALIntrInit

调用OALIntrMapInit()初始化2个数组g_oalSysIntr2Irq,g_oalIrq2SysIntr,这2个数组表征irq和逻辑中断SysIntr的映射关系.

然后初始化中断寄存器,

最后,留一个接口给oem: BSPIntrInit(),如果oem需要在这个阶段初始化一些中断,可以定义这个函数并实现.

2.1.2 OALTimerInit

这个函数比较重要. 都知道所有WinCE系统都需要一个定时器来提供一个heartbeat,



g_oalTimer包含各种系统时钟相关的变量.

curridlehigh, curridlelow,这2个32位的DWORD变量合起来实现一个64位的计数器,反映了系统处于空闲模式(Idle mode)的时间。一般在OEMIdle()函数内更新。用户程序通过调用GetIdleTime()函数可以得到这个值。

初始化内核函数指针:pQueryPerformanceFrequency, pQueryPerformanceCounter.通过这两个函数实现高精度的计时器. 这两个函数的原型也已经由PQOAL实现.

初始化TIMER4作为系统时钟.TIMER4是一个16bit的定时器.此函数将TIMER4设置成为自动转载模式.

2.1.2.1 Variable Tick Scheduler

可变的系统时钟节拍,这个是WinCE5.0中增加的新的性能.

每一次定时器中断时候,内核分析所有线程后决定切换到哪个线程运行.假如所有线程都在等待状态,系统将进入idle状态.在这个状态的时候,任何中断都会唤醒系统重新开始调度.一般系统大部分时间是处于idle状态的,内核会调用OEMIdle()进入idle状态,我们已经知道这个状态会被任何中断唤醒. 在以前的版本中,系统中断(即上面的TIMER4中断)每毫秒产生一次,查看系统是否需要重新调度. 为了节电,不希望中断那么频繁.于是WinCE5.0中,在调用OEMIdle()之前会先调用pOEMUpdateRescheduleTime().通过这个函数重新设置侠义次系统时钟中断的时间.

2.2 KernelInit()

再看看KernelInit()函数

不过多关注KernelInit().

2.3 FirstSchedule

位于armtrap.s的一个label.开始第一个线程调度.整个内核开始运行.

点赞  2008-10-29 10:18
说得非常对呀!
点赞  2008-11-1 19:46
顶gooogleman --good man!
点赞  2008-11-3 15:33
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复