📄 timer.c
字号:
// Function: OALTimerIntrHandler
//
// This function implement timer interrupt handler. It is called from common
// ARM interrupt handler.
//
UINT32 OALTimerIntrHandler()
{
volatile S3C2440X_INTR_REG *pIntr = (S3C2440X_INTR_REG*)OALPAtoVA(S3C2440X_BASE_REG_PA_INTR, FALSE);
UINT32 sysIntr = SYSINTR_NOP;
// Update high resolution counter
g_oalTimer.curCounts += g_oalTimer.countsPerSysTick*g_idleMSec;
// Update the millisecond counter
CurMSec += g_idleMSec;
// RETAILMSG(1,(TEXT("(%x)"), g_idleMSec));
OALTimerUpdate(g_oalTimer.countsPerSysTick, g_oalTimer.countsMargin);
g_idleMSec = 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
#if (DVS_METHOD == 3)
ChangeSystemStateDVS();
#endif
#endif
return sysIntr;
}
//------------------------------------------------------------------------------
//
// Function: OALTimerCountsSinceSysTick
//
// This function return count of hi res ticks since system tick.
//
// Timer 4 counts down, so we should substract actual value from
// system tick period.
//
INT32 OALTimerCountsSinceSysTick()
{
// return (g_oalTimer.countsPerSysTick - INREG32(&g_pPWMRegs->TCNTB4));
// Must be TCNTO4, TCNTB4 represents the written data, not counted data.
return (INREG32(&g_pPWMRegs->TCNTB4) - INREG32(&g_pPWMRegs->TCNTO4));
}
//------------------------------------------------------------------------------
//
// 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 tcon, ret;
ret = OALTimerCountsSinceSysTick()/g_oalTimer.countsPerSysTick;
OUTREG32(&g_pPWMRegs->TCNTB4, period);
tcon = INREG32(&g_pPWMRegs->TCON) & ~(0x0F << 20);
OUTREG32(&g_pPWMRegs->TCON, tcon | (0x2 << 20) );
OUTREG32(&g_pPWMRegs->TCON, tcon | (0x1 << 20) );
return (ret);
/*
UINT32 rc, count, offset, edge;
count = OALTimerGetCount();
edge = count + margin;
if (period == 0) {
// Period is zero, let interrupt occurs asap
rc = 0;
g_timer.compare = edge;
OALTimerSetCount(g_timer.compare);
} else if ((INT32)(g_timer.compare - edge) > 0) {
// We are more than margin before actual compare, update period
offset = count - g_timer.base;
// Avoid divide/multiply for most cases
if ((INT32)(offset - period) <= 0) {
rc = 0;
} else {
rc = offset/period;
g_timer.base += rc * period;
}
// New compare value is base plus period
g_timer.compare = g_timer.base + period;
// Are we more than margin before new compare?
if ((INT32)(g_timer.compare - edge) > 0) {
// Yes, then use calculated value
OALTimerSetCompare(g_timer.compare);
} else {
// No, shift real compare value
OALTimerSetCompare(edge);
}
} else {
// No, stay with original period
rc = (g_timer.compare - g_timer.base)/period - 1;
}
return rc;
*/
}
//------------------------------------------------------------------------------
//
// 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, idleMSec, idleSysTicks;
INT32 usedCounts, idleCounts;
ULARGE_INTEGER idle;
// Get current system timer counter
baseMSec = CurMSec;
// Compute the remaining idle time
idleMSec = dwReschedTime - baseMSec;
// RETAILMSG(1,(TEXT("(%d)"), idleMSec));
// Idle time has expired - we need to return
if ((INT32)idleMSec <= 0) 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;
// Find how many hi-res ticks was already used
usedCounts = OALTimerCountsSinceSysTick();
// RETAILMSG(1,(TEXT("(%x, %x)"), idleCounts, usedCounts));
if (idleCounts == usedCounts)
{
RETAILMSG(1,(TEXT("(%x, %x)"), idleCounts, usedCounts));
return;
}
// 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-usedCounts, g_oalTimer.countsMargin);
// Update value for timer interrupt which wakeup from idle
g_oalTimer.actualMSecPerSysTick = idleMSec;
g_oalTimer.actualCountsPerSysTick = idleCounts;
}
g_idleMSec = idleMSec;
// Move SoC/CPU to idle mode
OALCPUIdle();
INTERRUPTS_OFF();
// Return system tick period back to original. Don't call when idle
// time was one system tick. See comment above.
if (idleSysTicks > 1) {
// If there wasn't timer interrupt we have to update CurMSec&curCounts
if (CurMSec == baseMSec) {
// Return system tick period back to original
idleSysTicks = OALTimerUpdate(g_oalTimer.countsPerSysTick, g_oalTimer.countsMargin);
g_idleMSec = g_oalTimer.msecPerSysTick;
// RETAILMSG(1,(TEXT("(%x)"), idleSysTicks));
// Restore original values
g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;
// Fix system tick counters & idle counter
CurMSec += idleSysTicks * g_oalTimer.actualMSecPerSysTick;
idleCounts = idleSysTicks * g_oalTimer.actualCountsPerSysTick;
g_oalTimer.curCounts += idleCounts;
idleCounts += OALTimerCountsSinceSysTick();
}
} else {
if (CurMSec == baseMSec) {
// Update actual idle counts, if there wasn't timer interrupt
idleCounts = OALTimerCountsSinceSysTick();
// RETAILMSG(1,(TEXT("(%x)"), idleCounts));
}
}
// Get real idle value. If result is negative we didn't idle at all.
idleCounts -= usedCounts;
if (idleCounts < 0) idleCounts = 0;
// RETAILMSG(1,(TEXT("(%x, %x)"), idleCounts, (CurMSec - baseMSec)*g_oalTimer.countsPerSysTick));
// Update idle counters
idle.LowPart = curridlelow;
idle.HighPart = curridlehigh;
idle.QuadPart += idleCounts;
curridlelow = idle.LowPart;
curridlehigh = idle.HighPart;
#ifdef DVS_EN
dwCurrentidle = (idle.QuadPart/idleconv);
#endif
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -