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

📄 timer_fixedtick.c

📁 SMDK2416_BSP
💻 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 <s3c2450.h>
#include <bsp_cfg.h>

#define IRQFORTIMER		IRQ_TIMER4

extern void MMU_WaitForInterrupt();

#ifdef DVS_EN
extern void DVS_ON(void);
extern void DVS_OFF(void);
extern void ChangeVoltage(int, int*);
extern int GetCurrentVoltage(int);
extern	void HCLK_DOWNTO_PCLK();
extern	void HCLK_RECOVERYUP();

volatile int CurrentState;
DWORD dwCurrentidle;

DWORD dwPrevTotalTick1000 = 0;
DWORD dwPrevTotalTick100 = 0;

DWORD dwPrevIdleTick1000 = 0;
DWORD dwPrevIdleTick100 = 0;

DWORD dwPercentIdle1000 = 0;
DWORD dwPercentIdle100 = 0;
#endif
//------------------------------------------------------------------------------
// Local Variables 

static S3C2450_PWM_REG *g_pPWMRegs = NULL;

#if (BSP_TYPE == BSP_SMDK2443)
extern volatile S3C2450_INTR_REG *g_pIntrRegs; 
#elif (BSP_TYPE == BSP_SMDK2450)
static S3C2450_IOPORT_REG *g_pPortRegs;
static S3C2450_CLKPWR_REG *g_pClkpwrRegs;
static S3C2450_INTR_REG *g_pIntrRegs; 
#endif

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; 

//------------------------------------------------------------------------------
//
//  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 s3c2450 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;
/*#undef	OAL_TIMER
#undef	OAL_FUNC
#define OAL_TIMER	1
#define	OAL_FUNC	1*/
    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;

	g_oalTimer.actualMSecPerSysTick = msecPerSysTick;
	g_oalTimer.actualCountsPerSysTick = countsPerSysTick;

    // 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 = IRQFORTIMER;
    sysIntr = OALIntrRequestSysIntr(1, &irq, OAL_INTR_FORCE_STATIC);

    // Hardware Setup
#if (BSP_TYPE == BSP_SMDK2443)
    g_pPWMRegs = (S3C2450_PWM_REG*)OALPAtoUA(S3C2450_BASE_REG_PA_PWM);
#elif (BSP_TYPE == BSP_SMDK2450)
    g_pPWMRegs = (S3C2450_PWM_REG*)OALPAtoUA(S3C2450_BASE_REG_PA_PWM);
    g_pClkpwrRegs = (S3C2450_CLKPWR_REG *)OALPAtoUA(S3C2450_BASE_REG_PA_CLOCK_POWER);
    g_pIntrRegs = (S3C2450_INTR_REG *)OALPAtoUA(S3C2450_BASE_REG_PA_INTR);
    g_pPortRegs = (S3C2450_IOPORT_REG *)OALPAtoUA(S3C2450_BASE_REG_PA_IOPORT);
#endif	
    // Set prescaler 1 to 1 
    OUTREG32(&g_pPWMRegs->TCFG0, INREG32(&g_pPWMRegs->TCFG0) & ~0x0000FF00);
	OUTREG32(&g_pPWMRegs->TCFG0, INREG32(&g_pPWMRegs->TCFG0) | (PRESCALER<<8));
    // Select MUX input 1/2
    OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) & ~(0xF << 16));
#if( SYS_TIMER_DIVIDER == DV2 )
    OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) | (D1_2 << 16));
#elif ( SYS_TIMER_DIVIDER == DV4 )
    OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) | (D1_4 << 16));
#elif ( SYS_TIMER_DIVIDER == DV8 )
    OUTREG32(&g_pPWMRegs->TCFG1, INREG32(&g_pPWMRegs->TCFG1) | (D1_8 << 16));
#elif ( SYS_TIMER_DIVIDER == DV16 )
    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 auto reload mode
    tcon = INREG32(&g_pPWMRegs->TCON) & ~(0x0F << 20);
    OUTREG32(&g_pPWMRegs->TCON, tcon | (0x2 << 20) );
    OUTREG32(&g_pPWMRegs->TCON, tcon | (0x5 << 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
VOID ChangeSystemStateDVS()
{
	unsigned int dwCurrentMSec, dwCurrentIdleSec;
	//unsigned int PercentIdle;
	static unsigned int SlowCount = 0;

	dwCurrentMSec = CurMSec;
	dwCurrentIdleSec = dwCurrentidle;
	
	if ( dwCurrentMSec - dwPrevTotalTick100 > 100 )
	{
		dwPercentIdle100 = ((100*(dwCurrentIdleSec - dwPrevIdleTick100)) / (dwCurrentMSec - dwPrevTotalTick100));
		dwPrevTotalTick100 = dwCurrentMSec;
		dwPrevIdleTick100 = dwCurrentIdleSec;
		if ( dwPercentIdle100 < 20 )
		{
			if ( CurrentState == SlowActive)
			{
				if ( GetCurrentVoltage(ARM_VDD) == 0 ){
					RETAILMSG(1,(TEXT("Cannot get current voltage. State Freezing\n")));
					return;
				}
				if ( GetCurrentVoltage(ARM_VDD) != HIGHVOLTAGE )
				{
					// DVS OFF...
					int voltage_set[2] = HIGH_V_SET;
					ChangeVoltage(ARM_INT_VDD, voltage_set);
//					RETAILMSG(1, (TEXT("H")));					
				}
				DVS_OFF();
				g_oalIoCtlClockSpeed = S3C2450_FCLK;

				CurrentState = Active;
				SlowCount = 0;
//				RETAILMSG(1, (TEXT("-A-")));
			}
			if( CurrentState == LazyActive)		// Change state from SlowActive to Active...
			{
				if ( GetCurrentVoltage(ARM_VDD) == 0 ){
					RETAILMSG(1,(TEXT("Cannot get current voltage. State Freezing\n")));
					return;
				}
				if ( GetCurrentVoltage(ARM_VDD) != HIGHVOLTAGE )
				{
					// DVS OFF...
					int voltage_set[2] = HIGH_V_SET;
					ChangeVoltage(ARM_INT_VDD, voltage_set);
//					RETAILMSG(1, (TEXT("H")));					
				}
				DVS_OFF();
				g_oalIoCtlClockSpeed = S3C2450_FCLK;
				
				HCLK_RECOVERYUP();

				CurrentState = Active;
				SlowCount = 0;

//				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)
			{
				int voltage_set[2] = MID_V_SET;

⌨️ 快捷键说明

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