📄 timer.c
字号:
// 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 (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 rc, count, offset, edge;
count = OALTimerGetCount();
edge = count + margin;
if (period == 0) {
// Period is zero, let interrupt occurs asap
rc = 0;
g_timer.compare = g_timer.base;
OALTimerSetCompare(edge);
} 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;
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: OALCPUIdle
//
// This Idle function implements a busy idle. It is intend to be used only
// in development (when CPU doesn't support idle mode it is better to stub
// OEMIdle function instead use this busy loop). The busy wait is cleared by
// an interrupt from interrupt handler setting the g_oalLastSysIntr.
//
VOID OALCPUIdle()
{
volatile S3C2440A_CLKPWR_REG *p2440CLKPWR = (S3C2440A_CLKPWR_REG *)OALPAtoVA(S3C2440A_BASE_REG_PA_CLOCK_POWER, FALSE);
volatile S3C2440A_INTR_REG *p2440INTR = (S3C2440A_INTR_REG *)OALPAtoVA(S3C2440A_BASE_REG_PA_INTR, FALSE);
volatile S3C2440A_IOPORT_REG *p2440IOP = (S3C2440A_IOPORT_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
volatile S3C2440A_LCD_REG *p2440LCD = (S3C2440A_LCD_REG*)OALPAtoVA(S3C2440A_BASE_REG_PA_LCD, FALSE);
#ifdef DVS_EN
#if(DVS_METHOD == 1)
if ( p2440LCD->LCDSRCPND & 2 ) p2440LCD->LCDSRCPND = 2;
if ( p2440LCD->LCDINTPND & 2 ) p2440LCD->LCDINTPND = 2;
if ( p2440INTR->SRCPND & (1 << IRQ_LCD )) p2440INTR->SRCPND = 1 << IRQ_LCD;
if ( p2440INTR->INTPND & (1 << IRQ_LCD )) p2440INTR->INTPND = 1 << IRQ_LCD;
p2440INTR->INTMSK &= ~(1 << IRQ_LCD); // enable LCD interrupt
if ( CurrStateIdle == TRUE )
p2440INTR->INTMSK |= (1 << IRQ_LCD); // disable LCD interrupt
b_oalInterruptFlag = FALSE;
IDLEflag = TRUE;
INTERRUPTS_ON();
p2440CLKPWR->CLKCON |= (1 << 2); /* Enter IDLE Mode */
while (!b_oalInterruptFlag) {}
p2440CLKPWR->CLKCON &= ~(1 << 2); /* turn-off IDLE bit. */
INTERRUPTS_OFF();
IDLEflag = FALSE;
if ( p2440LCD->LCDSRCPND & 2 ) p2440LCD->LCDSRCPND = 2;
if ( p2440LCD->LCDINTPND & 2 ) p2440LCD->LCDINTPND = 2;
if ( p2440INTR->SRCPND & (1 << IRQ_LCD) ) p2440INTR->SRCPND = ( 1 << IRQ_LCD );
if ( p2440INTR->INTPND & (1 << IRQ_LCD) ) p2440INTR->INTPND = ( 1 << IRQ_LCD );
p2440INTR->INTMSK &= ~(1 << IRQ_LCD); // enable LCD interrupt
if ( CurrStateIdle == FALSE )
p2440INTR->INTMSK |= (1 << IRQ_LCD); // disable LCD interrupt
#elif (DVS_METHOD == 2)
// 2.3 DVS_ON = 1 (3:3:6)
DVS_ON();
// 2.4 Drop Voltage
ChangeVoltage(LOWVOLTAGE);
b_oalInterruptFlag = FALSE;
INTERRUPTS_ON();
p2440CLKPWR->CLKCON |= (1 << 2); /* Enter IDLE Mode */
while (!b_oalInterruptFlag) {}
p2440CLKPWR->CLKCON &= ~(1 << 2); /* turn-off IDLE bit. */
INTERRUPTS_OFF();
#elif (DVS_METHOD == 3)
if ( CurrentState == LazyActive ) // Lazy Active -> Deep Idle
{
b_oalInterruptFlag = FALSE;
IDLEflag = TRUE;
INTERRUPTS_ON();
p2440CLKPWR->CLKCON |= (1 << 2); /* Enter IDLE Mode */
while (!b_oalInterruptFlag) {}
p2440CLKPWR->CLKCON &= ~(1 << 2);
INTERRUPTS_OFF();
IDLEflag = FALSE;
}
else if ( CurrentState == SlowActive ) // Slow Active -> Deep Idle
{
if( p2440LCD->LCDSRCPND & 2 ) p2440LCD->LCDSRCPND = 2;
if( p2440LCD->LCDINTPND & 2 ) p2440LCD->LCDINTPND = 2;
if( p2440INTR->SRCPND & (1 << IRQ_LCD) ) p2440INTR->SRCPND = ( 1 << IRQ_LCD );
if( p2440INTR->INTPND & (1 << IRQ_LCD) ) p2440INTR->INTPND = ( 1 << IRQ_LCD );
p2440INTR->INTMSK &= ~(1 << IRQ_LCD); // enable LCD interrupt
if ( CurrStateIdle == TRUE )
p2440INTR->INTMSK |= (1 << IRQ_LCD); // disable LCD interrupt
NextState = DeepIdle;
b_oalInterruptFlag = FALSE;
IDLEflag = TRUE;
INTERRUPTS_ON();
p2440CLKPWR->CLKCON |= (1 << 2); /* Enter IDLE Mode */
while (!b_oalInterruptFlag) {}
p2440CLKPWR->CLKCON &= ~(1 << 2);
INTERRUPTS_OFF();
IDLEflag = FALSE;
if( p2440LCD->LCDSRCPND & 2 ) p2440LCD->LCDSRCPND = 2;
if( p2440LCD->LCDINTPND & 2 ) p2440LCD->LCDINTPND = 2;
if( p2440INTR->SRCPND & (1 << IRQ_LCD) ) p2440INTR->SRCPND = ( 1 << IRQ_LCD );
if( p2440INTR->INTPND & (1 << IRQ_LCD) ) p2440INTR->INTPND = ( 1 << IRQ_LCD );
p2440INTR->INTMSK &= ~(1 << IRQ_LCD); // enable LCD interrupt
if ( CurrStateIdle == TRUE )
p2440INTR->INTMSK |= (1 << IRQ_LCD); // disable LCD interrupt
NextState = SlowActive;
}
else if ( CurrentState == Active ) // Active -> Idle
{
DVS_ON();
ChangeVoltage(LOWVOLTAGE);
b_oalInterruptFlag = FALSE;
IDLEflag = TRUE;
INTERRUPTS_ON();
p2440CLKPWR->CLKCON |= (1 << 2); /* Enter IDLE Mode */
while (!b_oalInterruptFlag) {}
p2440CLKPWR->CLKCON &= ~(1 << 2);
INTERRUPTS_OFF();
IDLEflag = FALSE;
}
#endif //DVS_METHOD
#else
b_oalInterruptFlag = FALSE;
INTERRUPTS_ON();
p2440CLKPWR->CLKCON |= (1 << 2);
// Wait until interrupt handler set interrupt flag
while (!b_oalInterruptFlag) {}
p2440CLKPWR->CLKCON &= ~(1 << 2);
INTERRUPTS_OFF();
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -