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

📄 timer.c

📁 freescale i.mx31 BSP CE5.0全部源码
💻 C
📖 第 1 页 / 共 2 页
字号:
}


//-----------------------------------------------------------------------------
//
//  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.
//
//  Parameters:
//      dwIdleParam
//          [in] Used by MIPS CPU only. Base value for program status 
//          register (PSR) to allow interrupts to be enabled.
//
//  Returns:
//      None.
//
//------------------------------------------------------------------------------
void OEMIdle(DWORD dwIdleParam)
{
    UINT32 idleMSec, idleSysTicks;
    INT32 countBeforeIdle, countAfterIdle, idleCounts;
    ULARGE_INTEGER idle;

    // Compute the remaining idle time
    idleMSec = dwReschedTime - CurMSec;
    
    // Idle time has expired - we need to return
    if ((INT32)idleMSec <= 0) return;

    // If we don't have enough margin to update the timer before the current
    // system tick expires, just return
    if ((OALTimerCountsSinceSysTick() + g_oalTimer.countsMargin) >= 
        g_oalTimer.countsPerSysTick) return;
    
    // Limit the maximum idle time to what is supported.  
    // Counter size is the limiting parameter.  When kernel 
    // profiler or interrupt latency timing is active, it is set
    // to one system tick.
    if (idleMSec > g_oalTimer.maxPeriodMSec) 
    {
        idleMSec = g_oalTimer.maxPeriodMSec;
    }
    
    // We can wait only full systick
    idleSysTicks = idleMSec / g_oalTimer.msecPerSysTick;
    
    // This is idle time in hi-res ticks
    idleCounts = idleSysTicks * g_oalTimer.countsPerSysTick;

    // Prolong beat period to idle time -- don't do it idle time isn't
    // longer than one system tick. Even if OALTimerExtendSysTick function
    // should accept this value it can cause problems if kernel profiler
    // or interrupt latency timing is active.
    if (idleSysTicks > 1) 
    {        
        // Extend timer period.
        OALTimerUpdate(idleCounts, g_oalTimer.countsMargin);
                
        // Update value for timer interrupt which wakeup from idle
        g_oalTimer.actualMSecPerSysTick = idleMSec;
        g_oalTimer.actualCountsPerSysTick = idleCounts;
    }

    // Find how many hi-res ticks were are consumed in the current system tick
    // before idle mode is entered
    countBeforeIdle = OALTimerCountsSinceSysTick();
    
    // Move SoC/CPU to idle mode
    OALCPUIdle();

    // Find how many hi-res ticks were are consumed in the current system tick
    // after idle mode is exited
    countAfterIdle = OALTimerCountsSinceSysTick();
            
    // Return system tick period back to original. Don't call when idle
    // time was one system tick. See comment above.
    if (idleSysTicks > 1) 
    {

        // Since interrupts were disabled upon entry to idle mode, this code
        // should assume the timer interrupt may be pending, but not yet
        // serviced.  Execution resumes within OEMIdle before the timer interrupt
        // is serviced.  We will clear any pending timer interrupt and prepare
        // for the next available system tick.

        // Restore original system tick and expired ticks
        idleSysTicks = OALTimerUpdate(g_oalTimer.countsPerSysTick, 
            g_oalTimer.countsMargin);

        // Restore original values used for advancing timer globals
        g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
        g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;
            
        // Adjust system timer OAL variables.  Note expired system ticks
        // returned by OALTimerUpdate is rounded down to nearest system tick.
        CurMSec += (idleSysTicks * g_oalTimer.msecPerSysTick);
        g_oalTimer.curCounts += (idleSysTicks * g_oalTimer.countsPerSysTick);

    } 

    // Get real idle value. If result is negative we didn't idle at all.
    idleCounts = countAfterIdle - countBeforeIdle;
    if (idleCounts < 0) idleCounts = 0;
    
    // Update idle counters
    idle.LowPart = curridlelow;
    idle.HighPart = curridlehigh;
    idle.QuadPart += idleCounts;
    curridlelow  = idle.LowPart;
    curridlehigh = idle.HighPart;
    
}


//------------------------------------------------------------------------------
//
//  Function:  OALTimerSetCompare
//
//  This function sets timer compare value. This function should be
//  implemented only for systems with count/compare timer type. It is used
//  for OALTimerRecharge/OALTimerCountsSinceSysTick/OALTimerReduceSysTick and
//  OALTimerExtendSysTick implementation for systems with count/compare timer.
//
VOID OALTimerSetCompare(UINT32 compare)
{
    // Clear timer compare interrupt flag (write-1-clear)
    OUTREG32(&g_pEPIT->SR, CSP_BITFMASK(EPIT_SR_OCIF));

    OUTREG32(&g_pEPIT->CMPR, compare);


#ifdef VPMX31
    // Keep advancing the compare value until we have a valid timer event.
    // On Virtio, the timer advances while the ARM simulator is inactive
    // resulting in invalid timer compare settings.
    while ((INT32) (INREG32(&g_pEPIT->CNT) - INREG32(&g_pEPIT->CMPR)) <= 0)
    {
        OUTREG32(&g_pEPIT->CMPR, INREG32(&g_pEPIT->CNT) - g_oalTimer.countsMargin);

        // Clear timer compare interrupt flag (write-1-clear)
        OUTREG32(&g_pEPIT->SR, CSP_BITFMASK(EPIT_SR_OCIF));
    }
#endif

}

//------------------------------------------------------------------------------
//
//  Function:  OALTimerRecharge
//
//  This function recharge count/compare timer. In case that we are late more
//  than margin value we will use count as new counter base. Under
//  normal conditions previous compare value stored in global variable is used.
//  Using global variable instead reading compare register allows compensate
//  offset when we reduce system tick to value which can cause hazard.
//
//  Parameters:
//      period
//          [in] System tick period in raw timer ticks.
////
//      margin
//          [in] Safe time range in raw timer ticks where the timer can be 
//          modified without errors.
//
//  Returns:
//      None.
//
//-----------------------------------------------------------------------------
VOID OALTimerRecharge(UINT32 period, UINT32 margin)
{
    UINT32 cnt, cmpr;
    
    // Grab current timer counter
    cnt = INREG32(&g_pEPIT->CNT);

    // Advance base for current system tick to beginning of next system tick
    g_BaseTimerCount -= period;

    // Set timer compare to end of next system tick
    cmpr = g_BaseTimerCount - period;

    // If requested timer compare value is invalid
    if ((INT32) (cnt - cmpr - margin) < 0)
    {
        // Allow the timer to catch up
        g_BaseTimerCount = cnt;
        
        // Set timer compare to end of next system tick
        cmpr = cnt - period;

    }

    OALTimerSetCompare(cmpr);

}


//------------------------------------------------------------------------------
//
//  Function: OALTimerUpdate
//
//  This function is called to change length of actual system timer period.
//  If end of actual period is closer than margin period isn't changed (so
//  original period elapse). Function returns time which already expires
//  in new period length units. If end of new period is closer to actual time
//  than margin period end is shifted by margin (but next period should fix
//  this shift - this is reason why OALTimerRecharge doesn't read back 
//  compare register and it uses saved value instead).
//
UINT32 OALTimerUpdate(UINT32 period, UINT32 margin)
{
    UINT32 rc = 0, cmpr, cnt, expired;

    // Grab current timer counter
    cnt = INREG32(&g_pEPIT->CNT);

    // If requested system tick is zero
    if (period == 0)
    {
        // Let interrupt occur ASAP
        cmpr = cnt - margin;

        OALTimerSetCompare(cmpr);
    }

    // Else, requested system tick is non-zero
    else
    {
        // Get number of expired high-res ticks in current system tick
        expired = g_BaseTimerCount - cnt;
        
        // If we want to reduce system tick (i.e. ticks expired in
        // current system tick meet or exceed requested period)
        if (expired >= period) 
        {
            // Calculate expired time in new period length units
            rc = expired / period;

            // Advance base for current system tick to beginning of next system tick
            g_BaseTimerCount -= (rc * period);

        }

        // New compare value can be determined by subtracting
        // requested period current system tick base
        cmpr = g_BaseTimerCount - period;

        // If we have enough margin to update timer compare value
        if ((INT32) (cnt - cmpr - margin) >= 0)
        {
            OALTimerSetCompare(cmpr);
        }
    }
    
    return rc;
}

⌨️ 快捷键说明

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