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

📄 timer.c

📁 Windows CE 6.0 BSP for the Beagle Board.
💻 C
字号:
//
// Copyright (c) Special Computing.  All rights reserved. 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//------------------------------------------------------------------------------
//
//  File:  timer.c
//
#include <bsp.h>

//------------------------------------------------------------------------------
//
//  External: g_oalTimerIrq
//
//  This variable is defined in interrupt module and it is used in interrupt
//  handler to distinguish system timer interrupt.
//
extern UINT32 g_oalTimerIrq;   

//------------------------------------------------------------------------------
//
//  Global: g_oalTimer    
//
//  This is global instance of timer control block.
//
OAL_TIMER_STATE g_oalTimer;

//------------------------------------------------------------------------------
//
//  Local: g_pTimerRegs;
//
static OMAP3_GPTIMER_REGS *g_pTimerRegs;
static OMAP3_CM_WKUP_REGS *g_pCMRegs;
static OMAP3_TIMER32K_REGS *g_p32KTimerRegs;

//------------------------------------------------------------------------------
//
//  Function: OALTimerInit
//
//  This function is typically called from the OEMInit to initialize Windows CE
//  system timer. The tickMSec parameter determine timer period in milliseconds.
//  On most platform timer period will be 1 ms, but it can be usefull to use
//  higher value for some specific devices.
//
//  For OMAP3 32kHz timer is used to implement system timer. Because of
//  fixed timer frequency countsPerMSec and countsMargin parameters are
//  ignored.
//
BOOL OALTimerInit(
    UINT32 msecPerSysTick, UINT32 countsPerMSec, UINT32 countsMargin
) {
    BOOL rc = FALSE;
    UINT32 sysIntr;

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

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

    // Ignore two last passed arguments 
    countsPerMSec = OMAP3_GPTIMER_COUNTS_PER_1MS;
    countsMargin = 2;
    
    // 32 bit counter
    g_oalTimer.maxPeriodMSec = 0xFFFFFFFF/countsPerMSec;

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

    // Initialize timer state structure
    g_oalTimer.countsPerMSec = countsPerMSec;
    g_oalTimer.countsMargin = countsMargin;
    g_oalTimer.msecPerSysTick = msecPerSysTick;
    g_oalTimer.countsPerSysTick = g_oalTimer.countsPerMSec * msecPerSysTick;
    g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
    g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;

    // Set kernel exported globals to initial values
    idleconv = 2;
    curridlelow = 0;
    curridlehigh = 0;
    CurMSec = 0;

	// Set global variable to tell interrupt module about timer used
//    g_oalTimerIrq = IRQ_GPT1; 
g_oalTimerIrq = IRQ_GPT12; 

    // Request SYSINTR for timer IRQ, it is done to reserve it...
    sysIntr = OALIntrRequestSysIntr(1, &g_oalTimerIrq, OAL_INTR_FORCE_STATIC);
    
    // Hardware Setup
    g_pCMRegs  = OALPAtoUA(OMAP3_CM_WKUP_REGS_PA);
//    g_pTimerRegs = OALPAtoUA(OMAP3_GPTIMER1_REGS_PA);
g_pTimerRegs = OALPAtoUA(OMAP3_GPTIMER12_REGS_PA);
    g_p32KTimerRegs = OALPAtoUA(OMAP3_TIMER32K_REGS_PA);
    
	// stop
    OUTREG32(&g_pTimerRegs->ulTCLR, 0);

    // Soft reset timer module
    OUTREG32(&g_pTimerRegs->ulTIOCP, TIOCP_RESET);

    // wait
    while ((INREG32(&g_pTimerRegs->ulTISTAT) & TISTAT_RESETDONE) == 0);

	// Enable global wakeup feature and smart idle 
    //  Set clock activity - FCLK can be  switched off, L4 interface clock is maintained during wkup.
    OUTREG32(&g_pTimerRegs->ulTIOCP, 0x00000214);
    
    // Enable overflow wakeup
    OUTREG32(&g_pTimerRegs->ulTWER, TWER_OVERFLOW);
    
    // Clear Interrupt
    SETREG32(&g_pTimerRegs->ulTISR, TISR_OVERFLOW);

    // Enabled overflow interrupt
    SETREG32(&g_pTimerRegs->ulTIER, TIER_OVERFLOW);
    
	OALMSG(OAL_TIMER, (L"Timer Load Value is %x\r\n",g_oalTimer.countsPerSysTick));
    //  Set the load register value.
    OUTREG32(&g_pTimerRegs->ulTLDR, (0xFFFFFFFF - g_oalTimer.countsPerSysTick+1));
    
    //  Trigger a counter reload by writing    
    OUTREG32(&g_pTimerRegs->ulTTGR, 0xFFFFFFFF);
   
    //  Start the timer.  Also set for auto reload
    SETREG32(&g_pTimerRegs->ulTCLR, TLCR_AR | TLCR_ST);

    // Enable the functional and interface clocks
SETREG32(&g_pCMRegs->ulICLKEN, CM_WKUP_ICLKEN_EN_GPT12);
//    SETREG32(&g_pCMRegs->ulICLKEN, CM_WKUP_ICLKEN_EN_GPT1);
//    SETREG32(&g_pCMRegs->ulFCLKEN, CM_WKUP_FCLKEN_EN_GPT1);

//OALMSG(OAL_TIMER, (L"1\r\n"));
//OALMSG(OAL_TIMER, (L"SYNC      %08X\r\n",INREG32(&g_p32KTimerRegs->ulCR)));
//OALMSG(OAL_TIMER, (L"TCRR      %08X\r\n",INREG32(&g_pTimerRegs->ulTCRR)));
//OALMSG(OAL_TIMER, (L"TLDR      %08X\r\n",INREG32(&g_pTimerRegs->ulTLDR)));
//OALMSG(OAL_TIMER, (L"TISR      %08X\r\n",INREG32(&g_pTimerRegs->ulTISR)));
//OALMSG(OAL_TIMER, (L"TIER      %08X\r\n",INREG32(&g_pTimerRegs->ulTIER)));
//OALMSG(OAL_TIMER, (L"\r\n"));

	// Enable System Tick interrupt
    if (!OEMInterruptEnable(sysIntr, NULL, 0)) {
        OALMSG(OAL_ERROR, (
            L"ERROR: OALTimerInit: Interrupt enable for system timer failed"
        ));
        goto cleanUp;
    }

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

//------------------------------------------------------------------------------
//
//  Function: OALTimerIntrHandler
//
//  This function implement timer interrupt handler. It is called from common
//  ARM interrupt handler.
//
UINT32 OALTimerIntrHandler()
{
    UINT32 sysIntr = SYSINTR_NOP;

#ifdef OAL_ILTIMING
    if (g_oalILT.active) {
            g_oalILT.isrTime1 = OALTimerCountsSinceSysTick();
    }        
#endif

	OALLED(0,DEBUG_LED_TOGGLE);

    //Acknowledge the current timer interrupt and 
    //clear the status for next timer interrupt
    SETREG32(&g_pTimerRegs->ulTISR, TISR_OVERFLOW);

    // Update the millisecond and high resolution counters
    g_oalTimer.curCounts += g_oalTimer.actualCountsPerSysTick;
    CurMSec = (UINT32)((g_oalTimer.curCounts*1000)>>15);

    // Reschedule?
    if ((int)(CurMSec - dwReschedTime) >= 0) sysIntr = SYSINTR_RESCHED;

#ifdef OAL_ILTIMING
    if (g_oalILT.active) {
        if (--g_oalILT.counter == 0) {
            sysIntr = SYSINTR_TIMING;
            g_oalILT.counter = g_oalILT.counterSet;
            g_oalILT.isrTime2 = OALTimerCountsSinceSysTick();
        }
    }
#endif
    // Done    
    return sysIntr;
}

//------------------------------------------------------------------------------
//
//  Function: OALTimerCountsSinceSysTick
//
//  This function return count of hi res ticks since system tick.
//
INT32 OALTimerCountsSinceSysTick()
{
    // Calc value.
    return (INREG32(&g_pTimerRegs->ulTCRR) - INREG32(&g_pTimerRegs->ulTLDR));
}

//------------------------------------------------------------------------------
//
//  Function:  OEMIdle
//
//  This is 1ms fixed tick implementation. No need to implement the OEMIdle function.
//
void OEMIdle(DWORD idleParam)
{
}

#ifdef OAL_FAKE_IDLE

volatile UINT32 g_oalLastSysIntr;
//------------------------------------------------------------------------------
//
//  Function:   OALCPUIdle
//
//  This Idle function implements a busy idle. It is intend to be used only
//  in development (when CPU doesn't support idle mode it is better to stub
//  OEMIdle function instead use this busy loop). The busy wait is cleared by
//  an interrupt from interrupt handler setting the g_oalLastSysIntr.
//

VOID OALCPUIdle()
{
    // Clear last SYSINTR global value
    g_oalLastSysIntr = SYSINTR_NOP;

    INTERRUPTS_ON();
    // Wait until interrupt handler set interrupt flag
    while (g_oalLastSysIntr == SYSINTR_NOP);
    INTERRUPTS_OFF();
}
#endif

//------------------------------------------------------------------------------
//
//  Function: OEMGetTickCount
//
//  This returns the number of milliseconds that have elapsed since Windows 
//  CE was started. If the system timer period is 1ms the function simply 
//  returns the value of CurMSec. If the system timer period is greater then
//  1 ms, the HiRes offset is added to the value of CurMSec.
//
UINT32 OEMGetTickCount()
{
    UINT32 count;
    INT32 offset;

    if (g_oalTimer.actualMSecPerSysTick == 1) {
        // Return CurMSec if the system tick is 1 ms.
        count = CurMSec;
    }  else {
        // System timer tick period exceeds 1 ms. 
        //
        // This code adjusts the accuracy of the returned value to the nearest
        // MSec when the system tick exceeds 1 ms. The following code checks if 
        // a system timer interrupt occurred between reading the CurMSec value 
        // and the call to fetch the HiResTicksSinceSysTick. If so, the value of
        // CurMSec and Offset is re-read, with the certainty that a system timer
        // interrupt will not occur again.
        do {
            count = CurMSec;
            offset = OALTimerCountsSinceSysTick();
        } 
        while (count != CurMSec);

        // Adjust the MSec value with the contribution from HiRes counter.
        count += offset/g_oalTimer.countsPerMSec;
    }

    return count;
}


//------------------------------------------------------------------------------
//
//  Function: OALQueryPerformanceFrequency
//
//  This function returns the frequency of the high-resolution 
//  performance counter.
//
BOOL OALTimerQueryPerformanceFrequency(LARGE_INTEGER *pFrequency)
{
    if (!pFrequency) return FALSE;

    pFrequency->HighPart = 0;
    pFrequency->LowPart = 32768; // 32k timer frequency
    return TRUE;
}

//------------------------------------------------------------------------------
//
//  Function: OALQueryPerformanceCounter
//
//  This function returns the current value of the high-resolution 
//  performance counter.
//  
BOOL OALTimerQueryPerformanceCounter(LARGE_INTEGER *pCounter)
{
    UINT64 base;
    INT32 offset;

    if (!pCounter) return FALSE;
 
    // Make sure CurTicks is the same before and after read of counter
    // to avoid for possible rollover. Note that this is probably not necessary
    // because TimerTicksSinceBeat will return negative value when it happen.
    // We must be careful about signed/unsigned arithmetic.
    
    do {
       base = g_oalTimer.curCounts;
       offset = OALTimerCountsSinceSysTick();
    } while (base != g_oalTimer.curCounts);

    // Update the counter
    pCounter->QuadPart = (ULONGLONG)((INT64)base + offset);

    return TRUE;
}

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

⌨️ 快捷键说明

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