//------------------------------------------------------------------------------ // // 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. // // This implementation doesn't change system tick. It is intend to be used // with variable tick implementation. However it should work with fixed // variable tick implementation also (with lower efficiency because maximal // idle time is 1 ms). // VOID OEMIdle(DWORD idleParam) { UINT32 baseMSec; INT32 usedCounts, idleCounts; ULARGE_INTEGER idle; // Get current system timer counter baseMSec = CurMSec; // Find how many hi-res ticks was already used usedCounts = OALTimerCountsSinceSysTick(); // We should wait this time idleCounts = g_oalTimer.actualCountsPerSysTick; // Move SoC/CPU to idle mode OALCPUIdle(); // When there wasn't timer interrupt modify idle time if (CurMSec == baseMSec) { idleCounts = OALTimerCountsSinceSysTick(); } // Get real idle value. If result is negative we didn't idle at all. idleCounts -= usedCounts; if (idleCounts < 0) idleCounts = 0; // Update idle counters idle.LowPart = curridlelow; idle.HighPart = curridlehigh; idle.QuadPart += idleCounts; curridlelow = idle.LowPart; curridlehigh = idle.HighPart; }
//------------------------------------------------------------------------------ // // 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) { #if (BSP_TYPE == BSP_SMDK2443) UINT32 tcon, ret; ret = OALTimerCountsSinceSysTick(); OUTREG32(&g_pPWMRegs->TCNTB4, period); tcon = INREG32(&g_pPWMRegs->TCON) & ~(0x0F << 20); OUTREG32(&g_pPWMRegs->TCON, tcon | (0x2 << 20) ); OUTREG32(&g_pPWMRegs->TCON, tcon | (0x5 << 20) ); return (ret); #elif (BSP_TYPE == BSP_SMDK2450) #if 0 // Fixed Tick do not Update TImer UINT32 tcon, ret; ret = OALTimerCountsSinceSysTick(); OUTREG32(&g_pPWMRegs->TCNTB4, period); tcon = INREG32(&g_pPWMRegs->TCON) & ~(0x0F << 20); OUTREG32(&g_pPWMRegs->TCON, tcon | (0x2 << 20) ); OUTREG32(&g_pPWMRegs->TCON, tcon | (0x5 << 20) ); return (ret); #else return 0; #endif #endif }
//------------------------------------------------------------------------------ // // Function: OALTimerIntrHandler // // This function implement timer interrupt handler. It is called from common // ARM interrupt handler. // UINT32 OALTimerIntrHandler() { UINT32 sysIntr = SYSINTR_NOP; LastTimerMatch = g_XllpOSTHandle.pOSTRegs->osmr0; #ifdef OAL_ILTIMING if (g_oalILT.active) { g_oalILT.isrTime1 = OALTimerCountsSinceSysTick(); } #endif // g_LastPartialCounts represents fractional milliseconds which will // be added to CurMSec once they add up to one MSec. g_TotalPartialCounts += g_LastPartialCounts; g_LastPartialCounts = 0; if ((g_TotalPartialCounts > g_oalTimer.countsPerMSec)) { CurMSec++; g_TotalPartialCounts -= g_oalTimer.countsPerMSec; } // Update the millisecond and high resolution counters CurMSec += g_oalTimer.actualMSecPerSysTick; g_oalTimer.curCounts += g_oalTimer.actualCountsPerSysTick; //Re-schedule? if ((INT32)(CurMSec - dwReschedTime) >= 0) { sysIntr = SYSINTR_RESCHED; // Recharge timer with the maximum period possible from now. Kernel will call // OALTimerUpdateRescheduleTime to set it to the correct value it wants. RechargeTimer(CurMSec + g_oalTimer.maxPeriodMSec); } else { RechargeTimer(dwReschedTime); } // Update LEDs. // (Right shift by 10 instead of expensive division by 1000. This will // cause the LEDs to update every 1.024 seconds instead every 1 second, // which is okay as this is just a notification and not a measurement of any sort) OEMWriteDebugLED(0, CurMSec >> 10); #ifdef OAL_ILTIMING if (g_oalILT.active) { g_oalILT.counter--; if (g_oalILT.counter == 0) { sysIntr = SYSINTR_TIMING; g_oalILT.counter = g_oalILT.counterSet; g_oalILT.isrTime2 = OALTimerCountsSinceSysTick(); } } #endif return (sysIntr); }
//------------------------------------------------------------------------------ // // Function: OALTimerUpdateRescheduleTime // // This function is called by kernel to set next reschedule time. // VOID OALTimerUpdateRescheduleTime(DWORD time) { UINT32 baseMSec; INT32 counts; // Get current system timer counter baseMSec = CurMSec; // Return if we are already setup correctly if (time == (baseMSec + g_oalTimer.actualMSecPerSysTick)) goto cleanUp; // How far we are from next tick counts = g_oalTimer.actualCountsPerSysTick - OALTimerCountsSinceSysTick(); // If timer interrupts occurs, or we are within 1 ms of the scheduled // interrupt, just return - timer ISR will take care of it. if (baseMSec != CurMSec || counts < (INT32)g_oalTimer.countsPerMSec) { goto cleanUp; } //Note: We are going to assume that RechargeTimer will not take more than 1 ms and since we have already // checked above that there is at least 1 ms before the next timer interrupt, no timer interrupts // can occur during RechargeTimer execution (thus we satisfy the condition imposed by RechargeTimer) RechargeTimer(time); cleanUp: return; }
//------------------------------------------------------------------------------ // // Function: OALTimerIntrHandler // // This function implement timer interrupt handler. It is called from common // ARM interrupt handler. // UINT32 OALTimerIntrHandler() { UINT32 sysIntr = SYSINTR_NOP; #if (BSP_TYPE == BSP_SMDK2443) #if 1// for WFI OUTREG32(&g_pIntrRegs->SRCPND, 1 << IRQ_TIMER4); OUTREG32(&g_pIntrRegs->INTPND, 1 << IRQ_TIMER4); #endif #elif (BSP_TYPE == BSP_SMDK2450) static DWORD HeartBeatCnt, HeartBeatStat; //LED4 is used for heart beat // Clear the interrupt OUTREG32(&g_pIntrRegs->SRCPND1, 1 << IRQFORTIMER); OUTREG32(&g_pIntrRegs->INTPND1, 1 << IRQFORTIMER); #ifndef DVS_EN //[david.modify] 2008-09-09 17:30 // GPF4在4.3INCH项目上用做MENU_KEY #if 0 if (++HeartBeatCnt > 100) { HeartBeatCnt = 0; HeartBeatStat ^= 1; g_pPortRegs->GPCCON = (g_pPortRegs->GPCCON & ~(3<<14)) | (1<<14); if (HeartBeatStat) { g_pPortRegs->GPCDAT &= ~(1<<7); // LED 4 Off } else { g_pPortRegs->GPCDAT |= (1<<7); // LED 4 On } } #endif #endif #endif // Update high resolution counter g_oalTimer.curCounts += g_oalTimer.countsPerSysTick; // Update the millisecond counter CurMSec += g_oalTimer.msecPerSysTick; // 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 #ifdef DVS_EN ChangeSystemStateDVS(); #endif return sysIntr; }