技术开发 频道

Windows CE .NET平台上实现坚固的计时器

 所有硬件中断都被映射到该 ISR 并在该 ISR 中进行处理。线 018 得到当前的中断号。线 020 和 088 分别处理计时器 0 中断和 RTC(实时时钟)中断。如果该中断是其他某种中断,则线 096 会执行快速验证,调用任何链化的 ISR(参见 MSDN 中的函数 NKCallIntChain),将中断号转换为 SYSINTR_ 值,禁用该中断,并且最后在 ulRet 中返回 SYSINTR_ 值。如果找不到 SYSINTR_ 映射的 Irq,则用 SYSINTR_NOP 填充 ulRet。任何已注册的 IST(中断服务线程)事件都按照 ISR 的 SYSINTR_ 返回值进行设置。通过调用 InterruptInitialize 来注册 IST:

 InterruptInitialize(SYSINTR_SOFT1MS, hEvent, NULL, 0);

 在上述函数中,事件 hEvent 被映射到 ISR 返回值 SYSINTR_SOFT1MS。

 最后,ISR 通过向可编程中断控制器写 EOI(中断结束)值 (0x20),通知它中断已被处理。如果中断号大于 7,则必须首先通知第二个 PIC(两个 PIC 控制器通过中断线 2 级联)。

 因为我们调整了计时器频率,所以我们还必须调整上述 ISR,原因是现在 ISR 通常被调用两次,因此计划程序也工作两倍的次数(对于每个线程,计划次数被除以 2)。

 首先,我们必须声明一个静态布尔值,以便能够在 timer0 中断发生时切换 ISR 行为:

 001   ULONG PeRPISR(void)

 002   {

 003      ULONG ulRet = SYSINTR_NOP;

 004      UCHAR ucCurrentInterrupt;

 #define USE_SOFT_1MS

 #ifdef USE_SOFT_1MS

 static BOOL bToggle = FALSE;

 #endif

 005

 006      if (fIntrTime)

 007      {

 // Append rest of code here

 我们必须只为 timer0 中断切换该行为:

 020      if (ucCurrentInterrupt == INTR_TIMER0)

 021      {

 #ifdef USE_SOFT_1MS

 bToggle = !bToggle;      // Toggle value

 if (bToggle)

 {

 #endif

 022            if (PProfileInterrupt)

 023            {

 024               ulRet= PProfileInterrupt();

 025            }

 026            else

 027            {

 // Lines 028 to 077 are unchanged, and not showed here to save

 // the rainforest...

 078            }

 079

 080            //

 081            // Check if a reboot was requested.

 082            //

 083            if (dwRebootAddress)

 084            {

 085               RebootHandler();

 086            }

 #ifdef USE_SOFT_1MS

 }

 else

 {

 ulRet = SYSINTR_SOFT1MS;

 }

 #endif

 087      }

 088      else if (ucCurrentInterrupt == INTR_RTC)

 089      {

 // Append rest of code here

 现在,发生 timer0 中断时的行为在“运行正常的 CE ISR 代码”和“返回 SYSINTR_SOFT1MS”之间切换。我们现在可以通过 SYSINTR_SOFT1MS 值使用 InterruptInitialize,以便将某个事件绑定到 timer0 中断。然后,该事件将每 1 ms 产生一次。

 修改 oalintr.h

 Before we can use the SYSINTR_SOFT1MS value

 we have to define it in oalintr.h, which resides in

 \WINCE410\PUBLIC\COMMON\OAK\CSP\I486\INC, like this:

 #define USE_SOFT_1MS

 #ifdef USE_SOFT_1MS

 #define SYSINTR_SOFT1MS       (SYSINTR_FIRMWARE+6)

 #endif

 只要您按照下面的说明修改 OEMInterruptEnable 函数,就可以随便使用任何基于 SYSINTR_FIRMWARE 的值(就像 SYSINTR_FIRMWARE+20 一样)。

 修改 OEMInterruptEnable 函数

 我们还必须更改 cfwpc.c 内部的 OEMInterruptEnable 函数,以确保对于我们的 timer0 中断,该函数总是成功。如果我们不这样做,则对于 SYSINTR_SOFT1MS 中断,InterruptInitialize 函数将失败。将下面的代码行添加到该函数:

#define USE_SOFT_1MS

 #ifdef USE_SOFT_1MS

 if (idInt == SYSINTR_SOFT1MS)

 {

 DEBUGMSG (1, (TEXT("Accepting the soft 1ms interrupt enable request.\r\n")));

 return (TRUE);

 }

 #endif

  生成平台

 因为我们更改了一些内核代码,所以必须对内核进行完整的生成,包括重新生成依赖项树。首先,保存所有已更改的文件,然后在 Platform Builder 的“Tools”菜单中选择“Options”,并单击“Build”选项卡。现在,确保“Enable Deptree Build”被选中。此时,就可以通过单击“Build”菜单中的“Rebuild Platform”重新生成整个平台了。完成所有工作以后,请从“Tools”->“Options”菜单的“Build”选项卡中取消选中“Enable Deptree Build”。

查看原文地址

0
相关文章