⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 timer.c

📁 Windows CE 6.0 BSP for VOIPAC Board (PXA270) Version 2b.
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  File: timer.c
//  
//  This file contains timer module functions implementation. The code is
//  using coprocessor 0 count/compare counter. It can be used for most
//  MIPS based CPU/SoC. Note that some hardware implementation doesn't update
//  CP0 counter when it is moved to idle mode. If this is a case this 
//  implementation can't be used for such hardware.
//
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <oal.h>
#include <oal_intr_mips.h>

//------------------------------------------------------------------------------
//
//  External:  g_oalLastSysIntr
//
//  This global variable should be set by interrupt handler to last SYSINTR
//  when interrupt occurs. It is used by fake (busy loop) idle/power off OAL 
//  implementations.
//
#ifdef OAL_FAKE_IDLE
extern volatile UINT32 g_oalLastSysIntr;
#endif

//------------------------------------------------------------------------------
//
//  External:  g_oalRTCTicks/g_oalRTCAlarm
//
//  This global variables are used when RTC is implemented by timer interrupt.
//  The g_oalRTCTicks is incremented in each timer interrupt (RTC implementation
//  doesn't uses CurMSec to avoid rollover in approx 47 days). If g_aolRTCAlarm
//  is nonzero it is decremented on each timer interrupt. When it reaches zero 
//  SYSINTR_RTC_ALARM is returned (instead SYSINTR_RESCHED, but reschedule
//  is done in all cases when timer interrupt returns value different from
//  SYSINTR_NOP).
//
#ifdef OAL_TIMER_RTC
extern UINT64 *g_pOALRTCTicks;
extern UINT64 g_oalRTCTicks;
extern UINT64 g_oalRTCAlarm;
#endif

//------------------------------------------------------------------------------
//
//  Function:  OALTimerInit
//
//  Initialize timer oriented constants and start system timer. Usually system
//  timer triggers each 1 ms but it can be changed if required to optimize
//  platform and set beat period to multiple of ms.
//
BOOL OALTimerInit(
    UINT32 sysTickMSec, UINT32 countsPerMSec, UINT32 countsMargin
) {
    BOOL rc = FALSE;

    OALMSG(OAL_TIMER&&OAL_FUNC, (
        L"+OALTimerInit(%d, %d, %d)\r\n", sysTickMSec, countsPerMSec,
        countsMargin
    ));

    // MIPS counter has 32 bits, but we need to avoid too long periods
    g_oalTimer.maxPeriodMSec = 0x3FFFFFFF/countsPerMSec;

    // System tick period must be smaller than counter maximal period.
    // This reduction will be usual when variable tick is used.
    if (sysTickMSec > g_oalTimer.maxPeriodMSec) {
        sysTickMSec = g_oalTimer.maxPeriodMSec;
    }

    // Initialize timer state structure
    g_oalTimer.countsPerMSec = countsPerMSec;
    g_oalTimer.countsMargin = countsMargin;
    g_oalTimer.msecPerSysTick = sysTickMSec;
    g_oalTimer.countsPerSysTick = g_oalTimer.countsPerMSec * sysTickMSec;
    g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
    g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;
    
    // Set idle conversion constant and counters
    idleconv = countsPerMSec;
    curridlehigh = curridlelow = 0;
    g_oalTimer.curCounts = 0;

    // Initialize high resolution timer function pointers
    pQueryPerformanceFrequency = OALTimerQueryPerformanceFrequency;
    pQueryPerformanceCounter = OALTimerQueryPerformanceCounter;

#ifdef OAL_TIMER_RTC
    // Get counter from arguments (depends on platform)
    g_pOALRTCTicks = OALArgsQuery(OAL_ARGS_QUERY_RTC);
    // If platform hasn't such location use internal one
    if (g_pOALRTCTicks == NULL) g_pOALRTCTicks = &g_oalRTCTicks;
    // Clear alarm
    g_oalRTCAlarm = 0;
#endif

    // Hook timer ISR
    if (!HookInterrupt(5, OALTimerIntrHandler)) {
        OALMSG(OAL_ERROR, (
            L"ERROR: OALTimerInit: HookInterrupt for MIPS interrupt 5 failed\r\n"
        ));
        goto cleanUp;
    }        
        
    // Initialize counter/compare registers
    OALTimerInitCount(g_oalTimer.countsPerSysTick);

    // We are ok
    rc = TRUE;

cleanUp:
    OALMSG(OAL_TIMER&&OAL_FUNC, (L"-OALTimerInit(rc = %d)\r\n", rc));
    return rc;
}

//------------------------------------------------------------------------------
//
//  Function: OALTimerIntrHandler
//
//  This function implements timer interrupt handler. The implementation
//  can be compiled to support interrupt latency timing, real time clock 
//  based on system interrupt and fake idle wakeup.
//
UINT32 OALTimerIntrHandler()
{
    UINT32 sysIntr;
    UINT32 delta, msecPeriod, countsPeriod;

#ifdef OAL_ILTIMING
    if (g_oalILT.active) {
        g_oalILT.counter--;
        if (g_oalILT.counter == 0) {
            g_oalILT.interrupts = 0;
            g_oalILT.isrTime1 = OALTimerCountsSinceSysTick();
            g_oalILT.isrTime1 -= g_oalTimer.actualCountsPerSysTick;
        }            
    }        
#endif

    // Update the millisecond and high resolution counters
    CurMSec += g_oalTimer.actualMSecPerSysTick;
    g_oalTimer.curCounts += g_oalTimer.actualCountsPerSysTick;

    // Reschedule?
    delta = dwReschedTime - CurMSec;
    if ((INT32)delta <= 0) {
        // We have to reschedule
        sysIntr = SYSINTR_RESCHED;
        msecPeriod = g_oalTimer.msecPerSysTick;
        countsPeriod = g_oalTimer.countsPerSysTick;
    } else {
        // No reschedule
        sysIntr = SYSINTR_NOP;
        // Is next tick longer than maximal tick period?
        if (delta >= g_oalTimer.msecPerSysTick) {
            // Yes, do maximal tick
            msecPeriod = g_oalTimer.msecPerSysTick;
            countsPeriod = g_oalTimer.countsPerSysTick;
        } else {
            // No, next tick must be shorter to catch planned reschedule
            msecPeriod = delta;
            countsPeriod = delta * g_oalTimer.countsPerMSec;
        }
    }        

#ifdef OAL_TIMER_RTC
    // Update RTC global variable
    *g_pOALRTCTicks += g_oalTimer.actualMSecPerSysTick;
    // When RTC alarm is active check if it has to be fired
    if (g_oalRTCAlarm > 0) {
        if (g_oalRTCAlarm > g_oalTimer.actualMSecPerSysTick) {
            g_oalRTCAlarm -= g_oalTimer.actualMSecPerSysTick;
        } else {
            g_oalRTCAlarm = 0;
            sysIntr = SYSINTR_RTC_ALARM;
        }            
    }
#endif
                                 
    // Reload actual period values and recharge timer to start new period
    g_oalTimer.actualMSecPerSysTick = msecPeriod;
    g_oalTimer.actualCountsPerSysTick = countsPeriod;
    OALTimerRecharge(countsPeriod, g_oalTimer.countsMargin);

#ifdef OAL_FAKE_IDLE
    // Set flag for fake wake/idle
    if (sysIntr != SYSINTR_NOP) g_oalLastSysIntr = sysIntr;
#endif

#ifdef OAL_ILTIMING
#ifdef OAL_FAKE_IDLE
    // When ILT is active we must set g_oalLastSysIntr to non - SYSINTR_NOP
    if (g_oalILT.active && sysIntr == SYSINTR_NOP) {
        g_oalLastSysIntr = SYSINTR_TIMING;
    }        
#endif
    if (g_oalILT.active && g_oalILT.counter == 0) {
        sysIntr = SYSINTR_TIMING;
        g_oalILT.counter = g_oalILT.counterSet;
        g_oalILT.isrTime2 = OALTimerCountsSinceSysTick();
    }        
#endif

    // Return
    return sysIntr;
}

//------------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -