📄 timer.c
字号:
//
// Copyright (c) Special Computing. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
//
// File: timer.c
//
#include <bsp.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_oalTimer
//
// This is global instance of timer control block.
//
OAL_TIMER_STATE g_oalTimer;
//------------------------------------------------------------------------------
//
// Local: g_pTimerRegs;
//
static OMAP3_GPTIMER_REGS *g_pTimerRegs;
static OMAP3_CM_WKUP_REGS *g_pCMRegs;
static OMAP3_TIMER32K_REGS *g_p32KTimerRegs;
//------------------------------------------------------------------------------
//
// Function: OALTimerInit
//
// This function is typically called from the OEMInit to initialize Windows CE
// system timer. The tickMSec parameter determine timer period in milliseconds.
// On most platform timer period will be 1 ms, but it can be usefull to use
// higher value for some specific devices.
//
// For OMAP3 32kHz timer is used to implement system timer. Because of
// fixed timer frequency countsPerMSec and countsMargin parameters are
// ignored.
//
BOOL OALTimerInit(
UINT32 msecPerSysTick, UINT32 countsPerMSec, UINT32 countsMargin
) {
BOOL rc = FALSE;
UINT32 sysIntr;
OALMSG(OAL_TIMER&&OAL_FUNC, (
L"+OALTimerInit(%d, %d, %d)\r\n", msecPerSysTick, countsPerMSec,
countsMargin
));
// Initialize high resolution timer function pointers
pQueryPerformanceFrequency = OALTimerQueryPerformanceFrequency;
pQueryPerformanceCounter = OALTimerQueryPerformanceCounter;
// Ignore two last passed arguments
countsPerMSec = OMAP3_GPTIMER_COUNTS_PER_1MS;
countsMargin = 2;
// 32 bit counter
g_oalTimer.maxPeriodMSec = 0xFFFFFFFF/countsPerMSec;
// System tick period must be smaller than counter maximal period.
// This reduction will be usual when variable tick is used.
if (msecPerSysTick > g_oalTimer.maxPeriodMSec) {
msecPerSysTick = g_oalTimer.maxPeriodMSec;
}
// Initialize timer state structure
g_oalTimer.countsPerMSec = countsPerMSec;
g_oalTimer.countsMargin = countsMargin;
g_oalTimer.msecPerSysTick = msecPerSysTick;
g_oalTimer.countsPerSysTick = g_oalTimer.countsPerMSec * msecPerSysTick;
g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;
// Set kernel exported globals to initial values
idleconv = 2;
curridlelow = 0;
curridlehigh = 0;
CurMSec = 0;
// Set global variable to tell interrupt module about timer used
// g_oalTimerIrq = IRQ_GPT1;
g_oalTimerIrq = IRQ_GPT12;
// Request SYSINTR for timer IRQ, it is done to reserve it...
sysIntr = OALIntrRequestSysIntr(1, &g_oalTimerIrq, OAL_INTR_FORCE_STATIC);
// Hardware Setup
g_pCMRegs = OALPAtoUA(OMAP3_CM_WKUP_REGS_PA);
// g_pTimerRegs = OALPAtoUA(OMAP3_GPTIMER1_REGS_PA);
g_pTimerRegs = OALPAtoUA(OMAP3_GPTIMER12_REGS_PA);
g_p32KTimerRegs = OALPAtoUA(OMAP3_TIMER32K_REGS_PA);
// stop
OUTREG32(&g_pTimerRegs->ulTCLR, 0);
// Soft reset timer module
OUTREG32(&g_pTimerRegs->ulTIOCP, TIOCP_RESET);
// wait
while ((INREG32(&g_pTimerRegs->ulTISTAT) & TISTAT_RESETDONE) == 0);
// Enable global wakeup feature and smart idle
// Set clock activity - FCLK can be switched off, L4 interface clock is maintained during wkup.
OUTREG32(&g_pTimerRegs->ulTIOCP, 0x00000214);
// Enable overflow wakeup
OUTREG32(&g_pTimerRegs->ulTWER, TWER_OVERFLOW);
// Clear Interrupt
SETREG32(&g_pTimerRegs->ulTISR, TISR_OVERFLOW);
// Enabled overflow interrupt
SETREG32(&g_pTimerRegs->ulTIER, TIER_OVERFLOW);
OALMSG(OAL_TIMER, (L"Timer Load Value is %x\r\n",g_oalTimer.countsPerSysTick));
// Set the load register value.
OUTREG32(&g_pTimerRegs->ulTLDR, (0xFFFFFFFF - g_oalTimer.countsPerSysTick+1));
// Trigger a counter reload by writing
OUTREG32(&g_pTimerRegs->ulTTGR, 0xFFFFFFFF);
// Start the timer. Also set for auto reload
SETREG32(&g_pTimerRegs->ulTCLR, TLCR_AR | TLCR_ST);
// Enable the functional and interface clocks
SETREG32(&g_pCMRegs->ulICLKEN, CM_WKUP_ICLKEN_EN_GPT12);
// SETREG32(&g_pCMRegs->ulICLKEN, CM_WKUP_ICLKEN_EN_GPT1);
// SETREG32(&g_pCMRegs->ulFCLKEN, CM_WKUP_FCLKEN_EN_GPT1);
//OALMSG(OAL_TIMER, (L"1\r\n"));
//OALMSG(OAL_TIMER, (L"SYNC %08X\r\n",INREG32(&g_p32KTimerRegs->ulCR)));
//OALMSG(OAL_TIMER, (L"TCRR %08X\r\n",INREG32(&g_pTimerRegs->ulTCRR)));
//OALMSG(OAL_TIMER, (L"TLDR %08X\r\n",INREG32(&g_pTimerRegs->ulTLDR)));
//OALMSG(OAL_TIMER, (L"TISR %08X\r\n",INREG32(&g_pTimerRegs->ulTISR)));
//OALMSG(OAL_TIMER, (L"TIER %08X\r\n",INREG32(&g_pTimerRegs->ulTIER)));
//OALMSG(OAL_TIMER, (L"\r\n"));
// Enable System Tick interrupt
if (!OEMInterruptEnable(sysIntr, NULL, 0)) {
OALMSG(OAL_ERROR, (
L"ERROR: OALTimerInit: Interrupt enable for system timer failed"
));
goto cleanUp;
}
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;
#ifdef OAL_ILTIMING
if (g_oalILT.active) {
g_oalILT.isrTime1 = OALTimerCountsSinceSysTick();
}
#endif
OALLED(0,DEBUG_LED_TOGGLE);
//Acknowledge the current timer interrupt and
//clear the status for next timer interrupt
SETREG32(&g_pTimerRegs->ulTISR, TISR_OVERFLOW);
// Update the millisecond and high resolution counters
g_oalTimer.curCounts += g_oalTimer.actualCountsPerSysTick;
CurMSec = (UINT32)((g_oalTimer.curCounts*1000)>>15);
// 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
// Done
return sysIntr;
}
//------------------------------------------------------------------------------
//
// Function: OALTimerCountsSinceSysTick
//
// This function return count of hi res ticks since system tick.
//
INT32 OALTimerCountsSinceSysTick()
{
// Calc value.
return (INREG32(&g_pTimerRegs->ulTCRR) - INREG32(&g_pTimerRegs->ulTLDR));
}
//------------------------------------------------------------------------------
//
// Function: OEMIdle
//
// This is 1ms fixed tick implementation. No need to implement the OEMIdle function.
//
void OEMIdle(DWORD idleParam)
{
}
#ifdef OAL_FAKE_IDLE
volatile UINT32 g_oalLastSysIntr;
//------------------------------------------------------------------------------
//
// 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()
{
// Clear last SYSINTR global value
g_oalLastSysIntr = SYSINTR_NOP;
INTERRUPTS_ON();
// Wait until interrupt handler set interrupt flag
while (g_oalLastSysIntr == SYSINTR_NOP);
INTERRUPTS_OFF();
}
#endif
//------------------------------------------------------------------------------
//
// Function: OEMGetTickCount
//
// This returns the number of milliseconds that have elapsed since Windows
// CE was started. If the system timer period is 1ms the function simply
// returns the value of CurMSec. If the system timer period is greater then
// 1 ms, the HiRes offset is added to the value of CurMSec.
//
UINT32 OEMGetTickCount()
{
UINT32 count;
INT32 offset;
if (g_oalTimer.actualMSecPerSysTick == 1) {
// Return CurMSec if the system tick is 1 ms.
count = CurMSec;
} else {
// System timer tick period exceeds 1 ms.
//
// This code adjusts the accuracy of the returned value to the nearest
// MSec when the system tick exceeds 1 ms. The following code checks if
// a system timer interrupt occurred between reading the CurMSec value
// and the call to fetch the HiResTicksSinceSysTick. If so, the value of
// CurMSec and Offset is re-read, with the certainty that a system timer
// interrupt will not occur again.
do {
count = CurMSec;
offset = OALTimerCountsSinceSysTick();
}
while (count != CurMSec);
// Adjust the MSec value with the contribution from HiRes counter.
count += offset/g_oalTimer.countsPerMSec;
}
return count;
}
//------------------------------------------------------------------------------
//
// Function: OALQueryPerformanceFrequency
//
// This function returns the frequency of the high-resolution
// performance counter.
//
BOOL OALTimerQueryPerformanceFrequency(LARGE_INTEGER *pFrequency)
{
if (!pFrequency) return FALSE;
pFrequency->HighPart = 0;
pFrequency->LowPart = 32768; // 32k timer frequency
return TRUE;
}
//------------------------------------------------------------------------------
//
// Function: OALQueryPerformanceCounter
//
// This function returns the current value of the high-resolution
// performance counter.
//
BOOL OALTimerQueryPerformanceCounter(LARGE_INTEGER *pCounter)
{
UINT64 base;
INT32 offset;
if (!pCounter) return FALSE;
// Make sure CurTicks is the same before and after read of counter
// to avoid for possible rollover. Note that this is probably not necessary
// because TimerTicksSinceBeat will return negative value when it happen.
// We must be careful about signed/unsigned arithmetic.
do {
base = g_oalTimer.curCounts;
offset = OALTimerCountsSinceSysTick();
} while (base != g_oalTimer.curCounts);
// Update the counter
pCounter->QuadPart = (ULONGLONG)((INT64)base + offset);
return TRUE;
}
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -