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

📄 timer.c

📁 支持三星原产的S3C2413开发板
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  Module: timer.c		   
//
//  Interface to OAL timer services.
//
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <oal.h>
#include <S3C2413.h>
#include <bsp_cfg.h>


//------------------------------------------------------------------------------
// Local Variables 

static S3C2413_PWM_REG *g_pPWMRegs = NULL;

UINT32	g_idleMSec;

//------------------------------------------------------------------------------
//
//  Global:  g_oalLastSysIntr
//
//  This global variable is set by fake version of interrupt/timer handler
//  to last SYSINTR value.
//
//volatile UINT32 g_oalLastSysIntr; 

#ifdef DVS_EN
volatile BOOL IDLEflag = FALSE;
extern BOOL	VSYNCINTR;
extern BOOL	CurrStateIdle;

extern void DVS_ON(void);
extern void DVS_OFF(void);
extern void ChangeVoltage(int);
int GetCurrentVoltage(void);

extern volatile int CurrentState;
DWORD dwCurrentidle;

DWORD dwPrevTotalTick1000 = 0;
DWORD dwPrevTotalTick100 = 0;

DWORD dwPrevIdleTick1000 = 0;
DWORD dwPrevIdleTick100 = 0;

DWORD dwPercentIdle1000 = 0;
DWORD dwPercentIdle100 = 0;

#endif

extern volatile S3C2413_INTR_REG *g_pIntrRegs;
//------------------------------------------------------------------------------
//
//  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 (low-power) devices.
//
//  Implementation for S3C2413 is using timer 4 as system timer.
//
BOOL OALTimerInit(
	UINT32 msecPerSysTick, UINT32 countsPerMSec, UINT32 countsMargin
) {
	BOOL rc = FALSE;
	UINT32 countsPerSysTick;
	UINT32 sysIntr, irq;
	UINT32 tcon;

	OALMSG(OAL_TIMER&&OAL_FUNC, (
		L"+OALTimerInit( %d, %d, %d )\r\n", 
		msecPerSysTick, countsPerMSec, countsMargin
	));

	// Validate Input parameters
	countsPerSysTick = countsPerMSec * msecPerSysTick;
	if (
		msecPerSysTick < 1 || msecPerSysTick > 1000 ||
		countsPerSysTick < 1 || countsPerSysTick > 65535
	) {
		OALMSG(OAL_ERROR, (
			L"ERROR: OALTimerInit: System tick period out of range..."
		));
		goto cleanUp;
	}

	// Initialize timer state global variable	
	g_oalTimer.msecPerSysTick = msecPerSysTick;
	g_oalTimer.countsPerMSec = countsPerMSec;
	g_oalTimer.countsMargin = countsMargin;
	g_oalTimer.countsPerSysTick = countsPerSysTick;
	g_oalTimer.curCounts = 0;
	g_oalTimer.maxPeriodMSec = 0xFFFF/g_oalTimer.countsPerMSec;

	// Set kernel exported globals to initial values
	idleconv = countsPerMSec;
	curridlehigh = 0;
	curridlelow = 0;

	// Initialize high resolution timer function pointers
	pQueryPerformanceFrequency = OALTimerQueryPerformanceFrequency;
	pQueryPerformanceCounter = OALTimerQueryPerformanceCounter;

	// Create SYSINTR for timer
	irq = IRQ_TIMER4;
	sysIntr = OALIntrRequestSysIntr(1, &irq, OAL_INTR_FORCE_STATIC);

	// Hardware Setup
	g_pPWMRegs = (S3C2413_PWM_REG*)OALPAtoUA(S3C2413_BASE_REG_PA_PWM);

	// Set prescaler 1 to 1 
	OUTREG32(&g_pPWMRegs->TCFG0, INREG32(&g_pPWMRegs->TCFG0) & ~0x0000FF00);
	OUTREG32(&g_pPWMRegs->TCFG0, INREG32(&g_pPWMRegs->TCFG0) | (PRESCALER<<8));
	OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) & ~(0xF << 16));
#if( SYS_TIMER_DIVIDER == D2 )
	OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) | (D1_2 << 16));
#elif ( SYS_TIMER_DIVIDER == D4 )
	OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) | (D1_4 << 16));
#elif ( SYS_TIMER_DIVIDER == D8 )
	OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) | (D1_8 << 16));
#elif ( SYS_TIMER_DIVIDER == D16 )
	OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) | (D1_16 << 16));
#endif
	// Set timer register
	OUTREG32(&g_pPWMRegs->TCNTB4, g_oalTimer.countsPerSysTick);

	// Start timer in one shot mode
	tcon = INREG32(&g_pPWMRegs->TCON) & ~(0x0F << 20);
	OUTREG32(&g_pPWMRegs->TCON, tcon | (0x2 << 20) );
	OUTREG32(&g_pPWMRegs->TCON, tcon | (0x1 << 20) );

	// Enable System Tick interrupt
	if (!OEMInterruptEnable(sysIntr, NULL, 0)) {
		OALMSG(OAL_ERROR, (
			L"ERROR: OALTimerInit: Interrupt enable for system timer failed"
		));
		goto cleanUp;

	}

//	
// Define ENABLE_WATCH_DOG to enable watchdog timer support.
// NOTE: When watchdog is enabled, the device will reset itself if watchdog timer is not refreshed within ~4.5 second.
//	   Therefore it should not be enabled when kernel debugger is connected, as the watchdog timer will not be refreshed.
//
#ifdef ENABLE_WATCH_DOG
	{
		extern void SMDKInitWatchDogTimer (void);
		SMDKInitWatchDogTimer ();
	}
#endif

	// Done		
	rc = TRUE;
	
cleanUp:
	OALMSG(OAL_TIMER && OAL_FUNC, (L"-OALTimerInit(rc = %d)\r\n", rc));
	return rc;
}

#ifdef DVS_EN
#if (DVS_METHOD == 3)
VOID ChangeSystemStateDVS()
{
	unsigned int dwCurrentMSec, dwCurrentIdleSec;
	//unsigned int PercentIdle;
	volatile S3C2413_LCD_REG *s2413LCD = (S3C2413_LCD_REG*)OALPAtoVA(S3C2413_BASE_REG_PA_LCD, FALSE);
	volatile S3C2413_INTR_REG *s2413INT = (S3C2413_INTR_REG*)OALPAtoVA(S3C2413_BASE_REG_PA_INTR, FALSE);
	volatile S3C2413_IOPORT_REG *s2413IOP = (S3C2413_IOPORT_REG*)OALPAtoVA(S3C2413_BASE_REG_PA_IOPORT, FALSE);
	unsigned int i;

	dwCurrentMSec = CurMSec;
	dwCurrentIdleSec = dwCurrentidle;
	
	if ( dwCurrentMSec - dwPrevTotalTick100 > 100 )
	{
		dwPercentIdle100 = ((100*(dwCurrentIdleSec - dwPrevIdleTick100)) / (dwCurrentMSec - dwPrevTotalTick100));
		dwPrevTotalTick100 = dwCurrentMSec;
		dwPrevIdleTick100 = dwCurrentIdleSec;
		if ( dwPercentIdle100 < 20 )
		{
			if ( CurrentState == SlowActive )		// Change state from SlowActive to Active...
			{
				CurrentState = Active;

				if ( GetCurrentVoltage() != HIGHVOLTAGE )		// State is HCLK is half and DVS is on...
				{
					// DVS OFF...
					ChangeVoltage(HIGHVOLTAGE);
					for(i=0;i<VOLTAGEDELAY;i++)
					{
						s2413IOP->GPFDAT; // for loop operation, just read.
					}
					DVS_OFF();
					g_oalIoCtlClockSpeed = S3C2413_FCLK;

					// LCD Interrupt Enable for HCLK recover...
					if  ( s2413LCD->LCDSRCPND & 2 ) s2413LCD->LCDSRCPND = 2;
					if  ( s2413LCD->LCDINTPND & 2 ) s2413LCD->LCDINTPND = 2;
					if  ( s2413INT->SRCPND & (1 << IRQ_LCD)) s2413INT->SRCPND = (1 << IRQ_LCD);
					if  ( s2413INT->INTPND & (1 << IRQ_LCD)) s2413INT->INTPND = (1 << IRQ_LCD);
					s2413INT->INTMSK &= ~(1 << IRQ_LCD);		// enable LCD interrupt
				}
				else		// State is same with Active... so just disable the LCD interrupt...
				{
					// LCD Interrupt Disable...
					if  ( s2413LCD->LCDSRCPND & 2 ) s2413LCD->LCDSRCPND = 2;
					if  ( s2413LCD->LCDINTPND & 2 ) s2413LCD->LCDINTPND = 2;
					if  ( s2413INT->SRCPND & (1 << IRQ_LCD)) s2413INT->SRCPND = (1 << IRQ_LCD);
					if  ( s2413INT->INTPND & (1 << IRQ_LCD)) s2413INT->INTPND = (1 << IRQ_LCD);
					s2413INT->INTMSK |= (1 << IRQ_LCD);		// disable LCD interrupt
				}
				RETAILMSG(1, (TEXT("-A-")));
			}
		}
	}
	if ( dwCurrentMSec - dwPrevTotalTick1000 > 1000 )
	{
		dwPercentIdle1000 = ((100*(dwCurrentIdleSec - dwPrevIdleTick1000)) / (dwCurrentMSec - dwPrevTotalTick1000));
		dwPrevTotalTick1000 = dwCurrentMSec;
		dwPrevIdleTick1000 = dwCurrentIdleSec;
//		RETAILMSG(1, (TEXT("%d,%d "), dwPercentIdle100, CurrentState));
		if ( dwPercentIdle1000 > 70 )
		{
			if ( CurrentState == Active )
			{
				volatile S3C2413_LCD_REG *s2413LCD = (S3C2413_LCD_REG*)OALPAtoVA(S3C2413_BASE_REG_PA_LCD, FALSE);
				volatile S3C2413_INTR_REG *s2413INT = (S3C2413_INTR_REG*)OALPAtoVA(S3C2413_BASE_REG_PA_INTR, FALSE);

				CurrentState = SlowActive;

				if  ( s2413LCD->LCDSRCPND & 2 ) s2413LCD->LCDSRCPND = 2;
				if  ( s2413LCD->LCDINTPND & 2 ) s2413LCD->LCDINTPND = 2;
				if  ( s2413INT->SRCPND & (1 << IRQ_LCD)) s2413INT->SRCPND = (1 << IRQ_LCD);
				if  ( s2413INT->INTPND & (1 << IRQ_LCD)) s2413INT->INTPND = (1 << IRQ_LCD);
				s2413INT->INTMSK &= ~(1 << IRQ_LCD);		// enable LCD interrupt

				RETAILMSG(1, (TEXT("-S-")));
			}
		}
	}
}
#endif
#endif
//------------------------------------------------------------------------------
//
//  Function: OALTimerIntrHandler
//
//  This function implement timer interrupt handler. It is called from common
//  ARM interrupt handler.
//
UINT32 OALTimerIntrHandler()
{
	volatile S3C2413_INTR_REG *s2413IOP = (S3C2413_INTR_REG*)OALPAtoVA(S3C2413_BASE_REG_PA_INTR, FALSE);
	UINT32 sysIntr = SYSINTR_NOP;

#if 1	// From 2413 mag.

        // Clear the interrupt
     OUTREG32(&g_pIntrRegs->SRCPND, 1 << IRQ_TIMER4);
     OUTREG32(&g_pIntrRegs->INTPND, 1 << IRQ_TIMER4);
	 
	// 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;
#else	// from 2410 ce timer...
  // 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;
#endif

#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()
{
// 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;

⌨️ 快捷键说明

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