6190|11

59

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

系统时钟不准确,久了会死机的疑问? [复制链接]

大家好:
遇到了一个问题,向各位请教:
   我在APP中用SetTimer(1,1000,NULL),然后在Ontimer做响应处理,目的是一秒钟一次操作,但我的系统Timer设置有问题: Timer时快时慢,而且过一段时间后,就会死机。不知道这是什么原因。-
---------------------
我google了一下:
http://www.cnemb.com/forum/read.php?tid=23044   这个帖子和我的问题一样,

我的BSP中是把Timer4预留给系统的,
这个是我的代码:
  1. static DWORD dwPartialCurMSec = 0;                // Keep CPU-specific sub-millisecond leftover.
  2. void
  3. OEMIdle( DWORD dwIdleParam )
  4. {
  5.         DWORD dwIdleMSec;
  6.         DWORD dwPrevMSec = *pCurMSec;
  7.        
  8.         // Use for 64-bit math
  9.         ULARGE_INTEGER currIdle = { curridlelow, curridlehigh };

  10.         if ((int) (dwIdleMSec = dwReschedTime - dwPrevMSec) <= 0)
  11.         {
  12.                 return;                                // already time to wakeup
  13.         }

  14.         // just idle till tick if profiling or running iltiming
  15.         if (bProfileTimerRunning || fIntrTime)        // fIntrTime : Interrupt Latency timeing.
  16.         {
  17.                 // idle till end of 'tick'
  18.                 CPUEnterIdle(dwIdleParam);

  19.                 // Update global idle time and return
  20.                 currIdle.QuadPart += RESCHED_PERIOD;
  21.                 curridlelow = currIdle.LowPart;
  22.                 curridlehigh = currIdle.HighPart;
  23.         
  24.                 return;
  25.         }
  26.         RETAILMSG(1,(TEXT("OEMIdle ->RESCHED_PERIOD=%d \r\n"),RESCHED_PERIOD));  
  27.         //
  28.         // Since OEMIdle( ) is being called in the middle of a normal reschedule
  29.         // period, CurMSec, dwPartialCurMSec, and CurTicks need to be updated accordingly.
  30.         // Once we reach this point, we must re-program the timer (if we ever did)
  31.         // because dwPartialCurMSec will be modified in the next function call.
  32.         //
  33.         CPUGetSysTimerCountElapsed(RESCHED_PERIOD, pCurMSec, &dwPartialCurMSec, pCurTicks);

  34.         if ((int) (dwIdleMSec -= *pCurMSec - dwPrevMSec) > 0)
  35.         {
  36.                 dwPrevMSec = *pCurMSec;

  37.                 //
  38.                 // The system timer may not be capable of arbitrary timeouts. Get the
  39.                 // CPU-specific highest possible timeout available.
  40.                 //
  41.                 dwIdleMSec = CPUGetSysTimerCountMax(dwIdleMSec);

  42.                 //
  43.                 // Set the timer to wake up much later than usual, if needed.
  44.                 //
  45.                 CPUSetSysTimerCount(dwIdleMSec);
  46.                 CPUClearSysTimerIRQ( );

  47.                 //
  48.                 // Enable wakeup on any interrupt, then go to sleep.
  49.                 //
  50. //                DEBUGMSG(1, (TEXT("OEMIDle  \r\n")));
  51.                 CPUEnterIdle(dwIdleParam);
  52.                 INTERRUPTS_OFF( );
  53.         
  54.                 //
  55.                 // We're awake! The wake-up ISR (or any other ISR) has already run.
  56.                 //
  57.                 if (dwPrevMSec != *pCurMSec)
  58.                 {
  59.                         //
  60.                         // We completed the full period we asked to sleep.  Update the counters.
  61.                         //
  62.                         *pCurMSec  += (dwIdleMSec - RESCHED_PERIOD); // Subtract resched period, because ISR also incremented.
  63.                         CurTicks.QuadPart += (dwIdleMSec - RESCHED_PERIOD) * dwReschedIncrement;

  64.                         currIdle.QuadPart += dwIdleMSec;
  65.                 } else {
  66.                         //
  67.                         // Some other interrupt woke us up before the full idle period was
  68.                         // complete.  Determine how much time has elapsed.
  69.                         //
  70.                         currIdle.QuadPart += CPUGetSysTimerCountElapsed(dwIdleMSec, pCurMSec, &dwPartialCurMSec, pCurTicks);
  71.                 }
  72.         }

  73.         // Re-arm counters
  74.         CPUSetSysTimerCount(RESCHED_PERIOD);
  75.         CPUClearSysTimerIRQ( );

  76.         // Update global idle time
  77.         curridlelow = currIdle.LowPart;
  78.         curridlehigh = currIdle.HighPart;

  79.         return;
  80. }

  81. ------------------------------------------------------------------------------------------------------
  82. void
  83. InitClock(void)
  84. {
  85.     volatile PWMreg *s2440PWM =(PWMreg *)PWM_BASE;
  86.     volatile INTreg *s2440INT = (INTreg *)INT_BASE;  
  87.     DWORD ttmp;  


  88.         // Timer4 as OS tick and disable it first.
  89.     s2440INT->rINTMSK |= BIT_TIMER4;                // Mask timer4 interrupt.
  90.     s2440INT->rSRCPND = BIT_TIMER4;                        // Clear pending bit
  91.     s2440INT->rINTPND = BIT_TIMER4;

  92.         // Operating clock : PCLK=101500000 (101.5 Mhz)   
  93.         // IMPORTANT : MUST CHECK S2440.H DEFINITIONS !!!!
  94.         s2440PWM->rTCFG1  = 0x8080;        //;;; SHL
  95.         s2440PWM->rTCFG0 &= ~(0xff << 8);                /* Prescaler 1's Value                        */
  96.         s2440PWM->rTCFG0 |= (PRESCALER << 8);        // prescaler value=15       

  97.         RETAILMSG(1, (_T("InitClock_PRESCALER=%d\r\n"),PRESCALER));
  98.         /* Timer4 Divider field clear */
  99.         s2440PWM->rTCFG1 = 0x11111;        // ;;; SHL
  100.         s2440PWM->rTCFG1 &= ~(0xf << 16);
  101.        
  102. #if( SYS_TIMER_DIVIDER == D2 )
  103.                   s2440PWM->rTCFG1  |=  (D1_2   << 16);                /* 1/2                                                        */
  104. #elif ( SYS_TIMER_DIVIDER == D4 )
  105.                 s2440PWM->rTCFG1  |=  (D1_4   << 16);                /* 1/4                                                        */
  106. #elif ( SYS_TIMER_DIVIDER == D8 )
  107.                   s2440PWM->rTCFG1  |=  (D1_8   << 16);                /* 1/8                                                        */
  108. #elif ( SYS_TIMER_DIVIDER == D16 )
  109.                   s2440PWM->rTCFG1  |=  (D1_16   << 16);                /* 1/16                                                        */
  110. #endif
  111.         s2440PWM->rTCNTB4 = RESCHED_INCREMENT;        //((RESCHED_PERIOD * OEM_CLOCK_FREQ) / 1000)         
  112.         ttmp = s2440PWM->rTCON & (~(0xf << 20));

  113.         s2440PWM->rTCON = ttmp | (2 << 20);                /* update TCVNTB4, stop                                        */
  114.         s2440PWM->rTCON = ttmp | (1 << 20);                /* one-shot mode,  start                                */

  115.     // Number of timer counts for reschedule interval
  116.     dwReschedIncrement = RESCHED_INCREMENT;

  117.         // Set OEM timer count for 1 ms
  118.     OEMCount1ms = OEM_COUNT_1MS;
  119.    
  120.     // Set OEM clock frequency
  121.     OEMClockFreq = OEM_CLOCK_FREQ;

  122.     s2440INT->rINTMSK &= ~BIT_TIMER4;               

  123.     return;
  124. }

复制代码


最新回复

我想stubs 的意思应该是,将暂时不实现的function , 直接做return TRUE或return FALSE 处理,居然是这个意思! 汗, //------------------------------------------------------------------------------ BOOL OEMGetExtensionDRAM(     LPDWORD lpMemStart,     LPDWORD lpMemLen     ) {     return FALSE; // no extension DRAM } ------------   详情 回复 发表于 2009-10-15 13:46
点赞 关注

回复
举报

74

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
帮顶,up
 
 

回复

77

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
忘了说我的平台是:S3C2440+WINCE5.0
 
 
 

回复

76

帖子

0

TA的资源

一粒金砂(初级)

4
 
顶一下
 
 
 

回复

62

帖子

0

TA的资源

一粒金砂(初级)

5
 
1. 系统时钟(system tick)概念
  
  系统时钟是内核需要的唯一中断(IRQ0),系统时钟每毫秒产生一个中断,当发生中断时内核在ISR中累计,到1000的倍数就是过了一秒钟。在处理系统时钟的ISR中不仅要累计计数,还要决定是否通知内核开始重新调度当前所有的线程。要实现一个OAL,系统时钟是第一个必须做的事。
  
  2. X86平台系统时钟中断的处理工作 系统时钟由InitClock函数负责初始化工作,一般是在OEMInit函数中调用。当发生中断时,ISR首先用下列语句累计计数:
  
  CurMSec += SYSTEM_TICK_MS; /////SYSTEM_TICK_MS = 1
  
  然后根据下列语句判断应该返回什么值:
  
  if ((int) (dwReschedTime – CurMSec) >= 0)
  return SYSINTR_RESCHED; ///重新调度
  else
  return SYSINTR_NOP; ///不再执行任何操作
  
  上述代码中全局变量dwReschedTime在schedule.c中定义,也就是由内核的调度模块决定在何时开始重新调度线程。CurMSec累计了从WindowsCE启动到当前总共产生了多少个system tick。实现系统时钟后还要实现OEMIdle函数,当没有线程准备运行时OEMIdle被调用,OEMIdle函数将CPU置于空闲模式,但在空闲模式下仍然要累计系统时钟。
-------以上资料来源--[/url]-----

在[url=http://www.cnemb.com/forum/read.php?tid=23044]
该贴LZ说是OEMIdle函数的影响,导致时钟时快时慢,但现在不知道究竟是什么影响了, 继续研究
 
 
 

回复

85

帖子

0

TA的资源

一粒金砂(初级)

6
 
引用 4 楼 trueman_onlyme 的回复:
1. 系统时钟(system tick)概念
  
  系统时钟是内核需要的唯一中断(IRQ0),系统时钟每毫秒产生一个中断,当发生中断时内核在ISR中累计,到1000的倍数就是过了一秒钟。在处理系统时钟的ISR中不仅要累计计数,还要决定是否通知内核开始重新调度当前所有的线程。要实现一个OAL,系统时钟是第一个必须做的事。
  
  2. X86平台系统时钟中断的处理工作 系统时钟由InitClock函数负责初始化工作,一般是在OEMInit函数中调用。当发生中断时,ISR首先用下列语句累计计数:
  
  CurMSec += SYSTEM_TICK_MS; /////SYSTEM_TICK_MS = 1
  
  然后根据下列语句判断应该返回什么值:
  
  if ((int) (dwReschedTime – CurMSec) >= 0)
  return SYSINTR_RESCHED; ///重新调度
  else
  return SYSINTR_NOP; ///不再执行任何操作
  
  上述代码中全局变量dwReschedTime在schedule.c中定义,也就是由内核的调度模块决定在何时开始重新调度线程。CurMSec累计了从WindowsCE启动到当前总共产生了多少个system tick。实现系统时钟后还要实现OEMIdle函数,当没有线程准备运行时OEMIdle被调用,OEMIdle函数将CPU置于空闲模式,但在空闲模式下仍然要累计系统时钟。
-------以上资料来源--http://motion.chinaitlab.com/WINCE/30568.html-----

在http://www.cnemb.com/forum/read.php?tid=23044 该贴LZ说是OEMIdle函数的影响,导致时钟时快时慢,但现在不知道究竟是什么影响了, 继续研究

采用动态tick的情况下,如果OEMIdle函数没有处理好,会影响到系统的tick
但是lz采用了动态tick么?
 
 
 

回复

70

帖子

0

TA的资源

一粒金砂(初级)

7
 
1.同意楼上的,是不是采用的vartick?可以用fixedtick试试
2.注意2440的Timer2、3、4的设置clock第一次分频是共用一个TCFG,会不会你在其他地方修改了这个TCFG?造成timer4不准??
 
 
 

回复

92

帖子

0

TA的资源

纯净的硅(中级)

8
 
引用 6 楼 skynet000 的回复:
1.同意楼上的,是不是采用的vartick?可以用fixedtick试试
2.注意2440的Timer2、3、4的设置clock第一次分频是共用一个TCFG,会不会你在其他地方修改了这个TCFG?造成timer4不准??


vartick  and fixedticK?
      这个没有研究过,请问可否在详细说下,  明天来看看
----
其他的设置,触摸屏用的是Timer1,  其他的Timer不知道哪里在用?   
----
     
 
 
 

回复

73

帖子

0

TA的资源

一粒金砂(初级)

9
 
如果上层有线程在runing,oem_idle不会使用到,可以不用理会var tick
 
 
 

回复

86

帖子

0

TA的资源

一粒金砂(初级)

10
 
主要是APP中用到SetTimer了,  从InitClock(void)
中的
// Set OEM timer count for 1 ms
    OEMCount1ms = OEM_COUNT_1MS;
可以看出  是1ms  !

但真的好像是Tick 在变,
 
 
 

回复

74

帖子

0

TA的资源

一粒金砂(初级)

11
 
什么是stubs?
Stubs are routines that do not contain executable code. They act as placeholders for functions that need to be fully implemented later.
   When implementing stubs, you can leave comments that describe what you eventually need to do to add functionality to your function. By scanning existing sample OAL code, you can easily obtain the function header, such as return type and arguments, for each of these functions.
   You can either create the stub functions from scratch or copy an existing boot loader or OAL that is of similar CPU type and board design, and then use #if 0 and #endif tags for the function contents.
To create a stub function
1、Obtain the function header definition for the function to be stubbed by referring to a sample OAL that supports similar hardware. The function header includes a return type and a series of function arguments.
2、From the function header definition, create an empty function implementation.
3、If the function header specifies a return type, add a placeholder return value to satisfy the compiler.
For example, if the function returns a Boolean value, add either return (TRUE); or return (FALSE); to satisfy the compiler. A successful function call is usually signaled by a TRUE or non-zero value, while failure is usually signaled by a FALSE or 0 value. However, this depends on the function and the data being returned.
The following code example shows the stub for the OEMReadData function:
BOOL OEMReadData (DWORD cbData, LPBYTE pbData) { return(TRUE); }
这个链接
[url=http://www.cnemb.com/forum/read.php?tid=23044][/url]
上的解决办法是
“找到了问题出在哪里了,OEMIdle函数中的处理应该是有问题,用Stub代替之后正常了。 ”
stub 具体是什么,怎么用,  怎么用它来代替OEMIdle?
看文档的介绍有点费解,  
 
 
 

回复

87

帖子

0

TA的资源

一粒金砂(初级)

12
 
我想stubs 的意思应该是,将暂时不实现的function , 直接做return TRUE或return FALSE 处理,居然是这个意思! 汗,
//------------------------------------------------------------------------------
BOOL
OEMGetExtensionDRAM(
    LPDWORD lpMemStart,
    LPDWORD lpMemLen
    )
{
    return FALSE; // no extension DRAM
}
------------
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表