CPUGetSysTimerCountElapsed Routine (Windows CE 5.0)
OEMIdle calls CPUGetSysTimerCountElapsed to determine how much time has elapsed since the last timer tick.
In some situations, CPUGetSysTimerCountElapsed is called with interrupts off, making it possible for a timer interrupt to be pending when it is called. This routine must compensate for the interrupt service routine (ISR), which will also update CurMSec when its interrupt is unmasked.
Systems that use a PIT should note the return value from CPUClearSysTimerIRQ as it indicates whether the PIT interrupt was serviced in time to avoid losing timer information.
This routine is prototyped as shown in the following code example.
DWORD CPUGetSysTimerCountElapsed(
DWORD dwTimerCountdownMSec,
volatile DWORD *pCurMSec,
DWORD *pPartialCurMSec,
volatile ULARGE_INTEGER *pCurTicks
)
The following table shows the parameters used in this routine:
Parameter | Description |
---|---|
dwCountdownMSec | The number of milliseconds that the system expected to sleep before the next timer interrupt. |
pCurMSec | Points to a millisecond counter, often but not always the global variable CurMSec. |
pPartialCurMSec | Some number of timer counts, not timer ticks, not accounted for in the current value of *pCurMSec. |
pCurTicks | Pointer to a 64-bit tick counter. |
CPUGetSysTimerCountElapsed determines the number of counter increments or decrements that have elapsed and adds it to *pPartialCurMSec. It then calculates the number of whole milliseconds the sum represents and updates *pCurMSec with that value. Finally, it updates *pPartialCurMSec with any counts left over from this calculation.
CPUGetSysTimerCountElapsed treats *pCurTicks as a running number of timer counts, reflecting the number of times the counter has been incremented or decremented, not the number of interrupts it has generated or the number of milliseconds elapsed.
The following code example shows an implementation of CPUGetSysTimerCountElapsed for an ARM-based hardware platform, using a PIT.
DWORD CPUGetSysTimerCountElapsed(
DWORD dwTimerCountdownMSec,
volatile DWORD *pCurMSec,
DWORD *pPartialCurMSec,
volatile ULARGE_INTEGER *pCurTicks
)
{
TimerStruct_t *pTimer = gSysTimers[OS_TIMER].pt;
DWORD dwTick = dwTimerCountdownMSec * OEMCount1ms;
DWORD dwCount;
// If timer IRQ is pending, a full rescheduled period elapsed.
if (CPUClearSysTimerIRQ( )) {
*pCurMSec += dwTimerCountdownMSec;
pCurTicks->QuadPart += dwTick;
return dwTimerCountdownMSec;
}
// If no timer IRQ is pending, calculate how much time has elapsed.
dwCount = pTimer->TimerValue;
if (dwCount > dwTick) {
// This is an error case. Recover gracefully.
dwCount = dwTick;
}
else {
dwCount = dwTick - dwCount;
}
pCurTicks->QuadPart += dwCount;
dwCount += *pPartialCurMSec;
*pPartialCurMSec = dwCount % OEMCount1ms;
*pCurMSec += (dwCount /= OEMCount1ms);
return dwCount;
}
The following code example shows an implementation for the DDB5476 hardware platform using a free-running timer with value and compare registers.
DWORD CPUGetSysTimerCountElapsed(
DWORD dwTimerCountdownMSec,
volatile DWORD *pCurMSec,
DWORD *pPartialCurMSec,
volatile ULARGE_INTEGER *pCurTicks
)
{
DWORD dwTick = dwTimerCountdownMSec * OEMCount1ms;
DWORD dwCount = R4000Compare( ) - R4000Count( );
// Note: If dwCount is negative, the counter went past the compare
// point. The math still works because it accounts
// for the dwTick time plus the time past the compare point.
dwCount = dwTick - dwCount;
pCurTicks->QuadPart += dwCount;
dwCount += *pPartialCurMSec;
*pPartialCurMSec = dwCount % OEMCount1ms;
dwCount /= OEMCount1ms;
*pCurMSec += dwCount;
return dwCount;
}
See Also
Boilerplate Interface Routines
Send Feedback on this topic to the authors