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

📄 timer.c

📁 Windows CE 6.0 BSP for VOIPAC Board (PXA270) Version 2b.
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// 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.
//
// Portions Copyright (c) Texas Instruments.  All rights reserved. 
//
//------------------------------------------------------------------------------
//
//  File:  timer.c
//
//  The 32KHz timer (32768Hz) requires special procedure for update.
//  After writting new value to TVR and setting TRB bit in CR register
//  code should wait for counter harware to clear TRB bit. Then code has
//  to wait until value readed from TCR register is new value minus one.
//  The reason is that counter will ignore any new value set in this period
//  (when TCR value is equal to value set to TVR). This is true even in case
//  of autoload, so in our situation it means we can't update timer when
//  OEMIdle is entered until counter value is smaller than set/autoload one.
//  Another issue is related to interrupt. There is latency half or one clock
//  before interrupt is seen in interrupt controller. However TCR value can
//  already has been set to recharged value. This is reason why code has to
//  check for pending interrupt two times.
//
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <oal.h>
#include <omap730.h>
#include <omap730_led.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_pOALEMIFRegs    
//
//  This global variable contains EMIF module virtual address. It is used
//  in OALCPUIdle to move DRAM to self-refresh mode.
//
OMAP730_EMIF_REGS *g_pOALEMIFRegs;

//------------------------------------------------------------------------------
//
//  Define: TIMER_PERIOD/TIMER_MARGIN/SET_COMPENSTATION
//
//  This definition are used in code when timer period, timer margin (if count
//  value is higher we can update timer period) or timer set compensation is
//  used. However some code was optimalized for timer period 32 tick and
//  it will require code modification when different period is used.
//
#define TIMER_PERIOD                32
#define TIMER_MARGIN                3
#define SET_COMPENSATION            5
#define DEEP_SLEEP_COMPENSATION     0

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

typedef struct {
    UINT32 maxIdleMSec;                     // maximal idle in MSec
    volatile UINT64 curCounts;              // counts at last system tick
    OMAP730_TIMER32K_REGS *pTimerRegs;      // 32K timer address
    OMAP730_ULPD_REGS *pULPDRegs;           // ULPD address
    OMAP730_CLKM_REGS *pCLKMRegs;           // CLKM address
    BOOL updatePeriod;                      // change timer period
    BOOL deepSleep;                         // is DEEP_SLEEP enabled?
    UINT32 deepSleepSetup;                  // delay after deep sleep...
    UINT32 deepSleepTreshold;               // idle treshold for deep sleep
} OMAP730_TIMER_STATE;

//------------------------------------------------------------------------------
//
//  Global: g_timer
//
//  This is global instance of timer control block.
//
OMAP730_TIMER_STATE g_timer;

//------------------------------------------------------------------------------
// External functions

BOOL OALIntrIsIrqPending(UINT32 irq);

//------------------------------------------------------------------------------
//
//  Function: OALTimerInit
//
//  For OMAP730 32kHz timer is used to implement system timer. The code is
//  optimized for this timer with period 32 timer clocks per system tick. We
//  ignore all parameters.
//
BOOL OALTimerInit(
    UINT32 sysTickMSec, UINT32 countsPerMSec, UINT32 countsMargin
) {
    BOOL rc = FALSE;
    UINT32 sysIntr;


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

    // 32K timer has 24 bits
    g_timer.maxIdleMSec = 0x3FFFFF >> 5;
    g_timer.updatePeriod = FALSE;

    // Set idle conversion constant and counters
    idleconv = 32768;
    curridlehigh = curridlelow = 0;
    g_timer.curCounts = 0;

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

    // Request SYSINTR for timer IRQ, it is done to reserve it...
    sysIntr = OALIntrRequestSysIntr(1, &g_oalTimerIrq, OAL_INTR_FORCE_STATIC);

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

    // Get virtual addresses for hardware
    g_timer.pTimerRegs = OALPAtoUA(OMAP730_TIMER32K_REGS_PA);
    g_timer.pULPDRegs = OALPAtoUA(OMAP730_ULPD_REGS_PA);
    g_timer.pCLKMRegs = OALPAtoUA(OMAP730_CLKM_REGS_PA);
    g_pOALEMIFRegs = OALPAtoUA(OMAP730_EMIF_REGS_PA);

    // Get deep sleep setup delay
    g_timer.deepSleepSetup  = INREG16(&g_timer.pULPDRegs->SLICER_SETUP);
    g_timer.deepSleepSetup += INREG16(&g_timer.pULPDRegs->VTCXO_SETUP);   
    g_timer.deepSleepSetup += INREG16(&g_timer.pULPDRegs->RF_SETUP);   
    g_timer.deepSleepSetup += DEEP_SLEEP_COMPENSATION;

    // Enable deep sleep by default
    g_timer.deepSleep = TRUE;
    // Set treshold to 2 * deep sleep setup delay
    g_timer.deepSleepTreshold = g_timer.deepSleepSetup << 1;
    
    // Start timer    
    OUTREG32(&g_timer.pTimerRegs->TVR, TIMER_PERIOD - 1);
    SETREG32(&g_timer.pTimerRegs->CR, CR_TRB);
    while ((INREG32(&g_timer.pTimerRegs->CR) & CR_TRB) != 0);
    SETREG32(&g_timer.pTimerRegs->CR, CR_TSS|CR_INT_EN|CR_ARL);

    // Done
    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;
    UINT32 delta;


    // Update the millisecond and high resolution counters
    g_timer.curCounts += TIMER_PERIOD;
    CurMSec = (UINT32)((g_timer.curCounts * 1000) >> 15);
    
    // Update LED display (bits 0&1)
    OALLED(LED_IDX_TIMERSPIN, CurMSec >> 10);

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

    // Should we update timer period?
    if (g_timer.updatePeriod) {

        // Set new value
        OUTREG32(&g_timer.pTimerRegs->TVR, TIMER_PERIOD - 1);
        SETREG32(&g_timer.pTimerRegs->CR, CR_TRB);
        // Wait while it is set
        while ((INREG32(&g_timer.pTimerRegs->CR) & CR_TRB) != 0);
        // Wait until one tick (any timer set in this time is ignored)
        while (INREG32(&g_timer.pTimerRegs->TCR) != (TIMER_PERIOD - 2));
        // We are done with period update
        g_timer.updatePeriod = FALSE;
    }

    // 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 possible and halted.
//  It is important to be able to resume execution quickly upon receiving an
//  interrupt.
//
//  Interrupts are disabled when OEMIdle is called and when it returns.
//
//  Note that system timer must be running when CPU/SoC is moved to reduced
//  power mode.
//
void OEMIdle(DWORD idleParam)
{
    UINT32 baseMSec, idleSysTicks;
    INT32 usedCounts, idleCounts;
    ULARGE_INTEGER idle;
    UINT32 cnt, set, counts;
    BOOL deepSleep;
    OMAP730_TIMER32K_REGS *pTimerRegs = g_timer.pTimerRegs;
    OMAP730_ULPD_REGS *pULPDRegs = g_timer.pULPDRegs;
    OMAP730_CLKM_REGS *pCLKMRegs = g_timer.pCLKMRegs;


    // Get current system timer counter
    baseMSec = CurMSec;

    // Compute the remaining idle time
    idleSysTicks = dwReschedTime - baseMSec;

    // Idle time has expired - we need to return
    if ((INT32)idleSysTicks <= 0) return;

⌨️ 快捷键说明

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