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

📄 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
//
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <oal.h>
#include <oal_intr_mips.h>
#include <au1.h>


//------------------------------------------------------------------------------
//
//  Globals:  g_pIC0Regs/g_pSysRegs
//
//  The global variables are storing virual address for IC0 and SYS units
//  for use in interrupt handling to avoid possible time consumig call to
//  OALPAtoVA function.
//
static AU1_IC_REGS *g_pIC0Regs;
static AU1_SYS_REGS *g_pSysRegs;

//------------------------------------------------------------------------------
//
//  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.
//
//  Implementation bellow uses TOY timer with input frequency 32768 Hz and
//  it ignores countsPerMSec and countsMargin parameters. The timer uses
//  high priority interrupt assignment for TOY interrupt. It changes
//  assignment on interrupt controller and unhook default interrupt handler
//  from MIPS interrupt 1.
//
BOOL OALTimerInit(
    UINT32 sysTickMSec, UINT32 countsPerMSec, UINT32 countsMargin
) {
    BOOL rc = FALSE;
    UINT32 irq;
    
    OALMSG(OAL_TIMER&&OAL_FUNC, (
        L"+OALTimerInit(%d, %d, %d)\r\n", sysTickMSec, countsPerMSec,
        countsMargin
    ));

    // We can change period
    g_oalTimer.maxPeriodMSec = 1;
    g_oalTimer.countsPerMSec = 1;
    g_oalTimer.countsMargin = 0;
    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 = 2;
    curridlehigh = curridlelow = 0;
    g_oalTimer.curCounts = 0;

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

    // Map IC0 & SYS registers
    g_pSysRegs = (AU1_SYS_REGS*)OALPAtoUA(AU1_SYS_REGS_PA);
    g_pIC0Regs = (AU1_IC_REGS*)OALPAtoUA(AU1_IC0_REGS_PA);
    
    // Start 32.768kHz Oscillator
    if ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_32S) == 0) {
       SETREG32(&g_pSysRegs->CNTRCTRL, SYS_CNTRCTRL_EO);
       while ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_32S) == 0);
    }

    // Disable TOY if it is set
    if ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_TEN) != 0) {
       // Wait until TOY can be disabled/enabled
       while ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_ETS) != 0); 
       // Disable it
       CLRREG32(&g_pSysRegs->CNTRCTRL, SYS_CNTRCTRL_TEN);
       while ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_ETS) != 0); 
    }
    while ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_TS) != 0);

    // Set initial value to zero and -1
    OUTREG32(&g_pSysRegs->TOYWRITE, 0);
    OUTREG32(&g_pSysRegs->TOYMATCH0, -1);
    OUTREG32(&g_pSysRegs->TOYMATCH1, -1);
    OUTREG32(&g_pSysRegs->TOYMATCH2, -1);

    // Use prescale it should results in approximatelly sysTickMSec ms tick
    // NOTE: The TOYTRIM register will prescale the clock by its value + 1.
    //       Please account for the +1 when setting this register.
    while ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_TTS) != 0);
    OUTREG32(&g_pSysRegs->TOYTRIM, (33 * sysTickMSec) - 1);

    // Enable TOY
    while ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_ETS) != 0); 
    SETREG32(&g_pSysRegs->CNTRCTRL, SYS_CNTRCTRL_TEN);
    while ((INREG32(&g_pSysRegs->CNTRCTRL) & SYS_CNTRCTRL_ETS) != 0); 

    // Assign it to request 1
    OUTREG32(&g_pIC0Regs->ASSIGNCLR, 1 << IRQ_TOY);

    // Unhook default interrupt handler
    if (!UnhookInterrupt(1, OALIntr1Handler)) {
        OALMSG(OAL_ERROR, (
            L"ERROR: OALTimerInit: UnhookInterrupt for interrupt 1 failed\r\n"
        ));
        goto cleanUp;
    }

    // Hook timer interrupt handler
    if (!HookInterrupt(1, OALTimerIntrHandler)) {
        OALMSG(OAL_ERROR, (
            L"ERROR: OALTimerInit: HookInterrupt for interrupt 1 failed\r\n"
        ));
        goto cleanUp;
    }        

    // Enable TOY interrupt
    irq = IRQ_TOY;
    OALIntrEnableIrqs(1, &irq);

    // 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.
//
UINT32 OALTimerIntrHandler()
{
    UINT32 sysIntr = SYSINTR_NOP;

    // Clear TOY rising edges
    OUTREG32(&g_pIC0Regs->RISINGCLR, 1 << IRQ_TOY);

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

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

    // Reload actual period values to start new period
    g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
    g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;

#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

    // Return 
    return sysIntr;
}

//------------------------------------------------------------------------------
//
//  Function:  OEMIdle
//
//  This function is called by the kernel when there are no threads ready
//  to run. The CPU should be put into a reduced power mode if exists and
//  halted. It is important to be able to resume execution quickly upon
//  receiving an interrupt.
//
//  Actual implementaion on Au1 SoC uses IDLE0 mode. TOY timer hardware 
//  doesn't allow extend/change actual period. So there isn't way how to idle
//  for longer than system tick period without possibility of CurMSec shift.
//
void OEMIdle(DWORD idleParam)
{
    ULONG idlelow;
   
    // If we should reschedule do it now
    if (CurMSec >= dwReschedTime) return;

    // Go to idle
    OALCPUIdle();

    // Add idle (we have 1 ms resolution, so do some estimate)
    idlelow = curridlelow;
    curridlelow += 1;
    if (curridlelow < idlelow) curridlehigh++;
}

//------------------------------------------------------------------------------
//
//  Function:  OALTimerCountsSinceSysTick
//
//  With TOY timer there isn't way how to get more accurate info about time.
//
INT32 OALTimerCountsSinceSysTick()
{
    return 0;    
}

//------------------------------------------------------------------------------
//
//  Function:  OALTimerGetCount
//
//  Implementation is simple becuase TOY timer ticks in system tick period.
//
UINT32 OALGetTickCount()
{
    return INREG32(&g_pSysRegs->TOYREAD) * g_oalTimer.msecPerSysTick;
}

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

⌨️ 快捷键说明

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