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

📄 m8260timer.c

📁 Embedded Planet公司的ep8260单板计算机的BSP包(VxWorks)
💻 C
📖 第 1 页 / 共 2 页
字号:
/* sbcm8260Timer.c - PowerPC/8260 timer library */

/* Copyright 1984-1999 Wind River Systems, Inc. */
#include "copyright_wrs.h"

/*
modification history
--------------------
01a,22apr99,elk  adapted from ppc860Timer.c (ver 01a).  Also updated to
                 include SPR #10000 from ppcDecTimer.c (ver 01o).
*/

/*
DESCRIPTION

This library provides PowerPC/8260 system clock, auxiliary clock, and
timestamp support.

The PowerPC decrementer timer, is used to implement a system clock, and CPM
TIMER2 for a 16-bit auxiliary clock. CPM timers TIMER3, and TIMER4
are cascaded into a free-running 32-bit timer for timestamp support.

The macro, DEC_CLOCK_FREQ, the frequency of the decrementer input clock, must
be defined before using this module. The macro, DEC_CLK_TO_INC, the ratio
between the number of decrementer input clock cycles and one counter
increment, may be redefined prior to including this file in sysLib.c.

The macros SYS_CLK_RATE_MIN, SYS_CLK_RATE_MAX, AUX_CLK_RATE_MIN, and
AUX_CLK_RATE_MAX must be defined to provide parameter checking for
sysClkRateSet(), and sysAuxClkRateSet() routines.

To include the timestamp timer facility, the macro INCLUDE_TIMESTAMP must be
defined.

To enable dynamic bus clock rates, the BSP should set the macro,
PPC_TMR_RATE_SET_ADJUST, to call an apropriate routine. This call, will be
made each time sysClkRateSet() is called. E.g. To use sysClkRateAdjust to
compute a correct value for sysDecClkFrequency.

  #define PPC_TMR_RATE_SET_ADJUST sysClkRateAdjust (&sysDecClkFrequency)

The macro, PPC_TMR_RATE_SET_ADJUST, is by default not defined.

INCLUDE FILES: timerDev.h, vxPpcLib.h

SEE ALSO:
.pG "Configuration"
*/

/* includes */

#include "arch/ppc/vxPpcLib.h"
#include "drv/timer/timerDev.h"
#include "drv/timer/m8260Clock.h"
#include "drv/timer/m8260Timer.h"
#include "m8260IntrCtl.h"

/* local defines */

#define SYS_CLK_LED             0x40
#define SYS_AUX_LED             0x20
#define SYS_TIMESTAMP_LED       0x10

#ifndef	DEC_CLK_TO_INC
#define	DEC_CLK_TO_INC		4		/* # bus clks per increment */
#endif

#define DEFAULT_DEC_CLK_FREQ	33333333	/* 33.33 Mhz default */

#ifndef CPU_INT_UNLOCK
#    define  CPU_INT_UNLOCK(x)  (intUnlock(x))
#endif

#ifndef CPU_INT_LOCK
#    define  CPU_INT_LOCK(x)  (*x = intlock())
#endif

/* extern declarations */

IMPORT STATUS	excIntConnect (VOIDFUNCPTR *, VOIDFUNCPTR);

IMPORT void sysLedOn(UINT8 led);
IMPORT void sysLedOff(UINT8 led);

#ifdef PPC_TMR_RATE_SET_ADJUST
IMPORT void  sysClkRateAdjust (int *);
#endif /* PPC_TMR_RATE_SET_ADJUST */

/* locals */

LOCAL int 	sysClkTicksPerSecond 	= 60;	  /* default 60 ticks/second */
LOCAL FUNCPTR	sysClkRoutine		= NULL;
LOCAL int	sysClkArg		= NULL;
LOCAL BOOL	sysClkConnectFirstTime	= TRUE;
LOCAL int       decCountVal		= 10000000;	/* default dec value */
LOCAL BOOL	sysClkRunning 		= FALSE;
LOCAL int 	sysDecClkFrequency	= DEFAULT_DEC_CLK_FREQ/DEC_CLK_TO_INC;
#ifdef INCLUDE_SYSCLK_LED
LOCAL int       sysClkCount             = 0;
#endif  /* INCLUDE_SYSCLK_LED */


#ifdef INCLUDE_AUX_CLK
LOCAL FUNCPTR	sysAuxClkRoutine	= NULL;
LOCAL int	sysAuxClkArg		= NULL;
LOCAL BOOL	sysAuxClkRunning	= FALSE;
LOCAL BOOL	sysAuxClkIntConnected	= FALSE;
LOCAL int	sysAuxClkTicksPerSecond	= 60;
#ifdef INCLUDE_AUXCLK_LED
LOCAL int       sysAuxClkCount          = 0;
#endif  /* INCLUDE_AUXCLK_LED */
#endif  /* INCLUDE_AUX_CLK */

#ifdef	INCLUDE_TIMESTAMP
LOCAL BOOL	sysTimestampRunning  	= FALSE;   /* timestamp running flag */
LOCAL FUNCPTR	sysTimestampRoutine	= NULL;
LOCAL int	sysTimestampArg		= NULL;
LOCAL BOOL	sysTimestampIntConnected = FALSE;
#endif	/* INCLUDE_TIMESTAMP */

/*******************************************************************************
*
* sysClkInt - clock interrupt handler
*
* This routine handles the clock interrupt on the PowerPC architecture. It is
* attached to the decrementer vector by the routine sysClkConnect().
*
* RETURNS : N/A
*/

#ifdef __DCC__
asm void ClkIntMacro(int count)
{
% lab sysClkIntLoop; reg count
! "r4"

	mfdec 	r4
sysClkIntLoop:
	add. 	r4, count, r4
	ble 	sysClkIntLoop
	mtdec 	r4
}
#endif

LOCAL void sysClkInt (void)
    {
    /*
     * The PowerPC decrementer doesn't reload the value by itself. The reload
     * need to be performed in this handler. The reload value should be
     * adjusted each time because the time spent between the exception
     * generation and the moment the register is reloaded changes.
     * By reading the decrementer we obtain the time spent between the
     * two events and can adjust the value to reload. This is done in assembly
     * language in order to minimize time spent between reading and writing
     * to the decrementer register in order to maximize system clock accuracy.
     */
#ifdef __DCC__
	ClkIntMacro(decCountVal);
#else
__asm__ ("
    mfdec   	3
sysClkIntLoop:
    add. 	3, %0, 3
    ble		sysClkIntLoop		/* check if we missed tick(s) */
    mtdec	3"
    :					/* no output operands  */
    : "r" (decCountVal)			/* input operand, %0 = decCountVal */
    : "3", "cc"/* side-effects: r3 clobbered, 'condition code' is clobbered */
    );
#endif

    /* Unlock interrupts during decrementer processing */

    CPU_INT_UNLOCK (_PPC_MSR_EE);

#ifdef INCLUDE_SYSCLK_LED
    sysClkCount++;
    if (sysClkCount > sysClkTicksPerSecond)
       { sysClkCount = 0;
         sysLedOff(SYS_CLK_LED);
       }
    else if (sysClkCount == (sysClkTicksPerSecond/2))
       sysLedOn(SYS_CLK_LED);
#endif /* INCLUDE_SYSCLK_LED */

    /* execute the system clock routine */

    if (sysClkRunning && (sysClkRoutine != NULL))
	(*(FUNCPTR) sysClkRoutine) (sysClkArg);

    }

/*******************************************************************************
*
* sysClkConnect - connect a routine to the system clock interrupt
*
* This routine specifies the interrupt service routine to be called at each
* clock interrupt.  Normally, it is called from usrRoot() in usrConfig.c to
* connect usrClock() to the system clock interrupt.
*
* RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.
*
* SEE ALSO: intConnect(), usrClock(), sysClkEnable()
*/

STATUS sysClkConnect
    (
    FUNCPTR 	routine,	/* routine to connect */
    int 	arg		/* argument for the routine */
    )
    {

    if (sysClkConnectFirstTime)
      {
      sysHwInit2();
      sysClkConnectFirstTime = FALSE;
      }

#ifdef  DEC_CLOCK_FREQ
    sysDecClkFrequency = DEC_CLOCK_FREQ / DEC_CLK_TO_INC;
#endif  /* DEC_CLOCK_FREQ */

    /* connect the routine to the decrementer exception */

    excIntConnect ((VOIDFUNCPTR *) _EXC_OFF_DECR, (VOIDFUNCPTR) sysClkInt);

    sysClkRoutine	= routine;
    sysClkArg		= arg;

    return (OK);
    }

/******************************************************************************
*
* sysClkEnable - turn on system clock interrupts
*
* This routine enables system clock interrupts.
*
* RETURNS: N/A
*
* SEE ALSO: sysClkConnect(), sysClkDisable(), sysClkRateSet()
*/

void sysClkEnable (void)
    {
    if (!sysClkRunning)
	{
	sysClkRunning = TRUE;
	vxDecSet (decCountVal);
	}
    }

/******************************************************************************
*
* sysClkDisable - turn off system clock interrupts
*
* This routine disables system clock interrupts.
*
* RETURNS: N/A
*
* SEE ALSO: sysClkEnable()
*/

void sysClkDisable (void)
    {
    if (sysClkRunning)
	sysClkRunning = FALSE;
    }

/******************************************************************************
*
* sysClkRateGet - get the system clock rate
*
* This routine returns the system clock rate.
*
* RETURNS: The number of ticks per second of the system clock.
*
* SEE ALSO: sysClkEnable(), sysClkRateSet()
*/

int sysClkRateGet (void)
    {
    return (sysClkTicksPerSecond);
    }

/******************************************************************************
*
* sysClkRateSet - set the system clock rate
*
* This routine sets the interrupt rate of the system clock.  It is called
* by usrRoot() in usrConfig.c.
*
* RETURNS: OK, or ERROR if the tick rate is invalid or the timer cannot be set.
*
* SEE ALSO: sysClkEnable(), sysClkRateGet()
*/

STATUS sysClkRateSet
    (
    int 	ticksPerSecond  /* number of clock interrupts per second */
    )
    {
    if (ticksPerSecond < SYS_CLK_RATE_MIN || ticksPerSecond > SYS_CLK_RATE_MAX)
        return (ERROR);

    /* save the clock speed */

    sysClkTicksPerSecond = ticksPerSecond;

    /* Calibrate the clock, if needed. */

#ifdef PPC_TMR_RATE_SET_ADJUST
    PPC_TMR_RATE_SET_ADJUST;
#endif

    /*
     * compute the value to load in the decrementer. The new value will be
     * load in the decrementer after the end of the current period
     */

    decCountVal = sysDecClkFrequency / ticksPerSecond;

    return (OK);
    }


#ifdef INCLUDE_AUX_CLK

/*******************************************************************************
*
* sysAuxClkInt - auxiliary clock interrupt handler
*
* This routine handles the auxiliary clock interrupt.  It calls a user routine
* if one was specified by the routine sysAuxClkConnect().
*/

LOCAL void sysAuxClkInt (void)
    {
    UINT32 immrVal = vxImmrGet();

    *M8260_TER2(immrVal) |= M8260_TER_REF;     /* clear event register */

    *M8260_SIPNR_L(immrVal) = 0x00000008;  /* clear in-service bit */

#ifdef INCLUDE_AUXCLK_LED
    sysAuxClkCount++;
    if (sysAuxClkCount > sysAuxClkTicksPerSecond)
       { sysAuxClkCount = 0;
         sysLedOff(SYS_AUX_LED);
       }
    else if (sysAuxClkCount == (sysAuxClkTicksPerSecond/2))
       sysLedOn(SYS_AUX_LED);
#endif /* INCLUDE_AUXCLK_LED */

    if (sysAuxClkRoutine != NULL)
        (*sysAuxClkRoutine) (sysAuxClkArg);
    }

/*******************************************************************************
*
* sysAuxClkConnect - connect a routine to the auxiliary clock interrupt
*
* This routine specifies the interrupt service routine to be called at each
* auxiliary clock interrupt.  It does not enable auxiliary clock
* interrupts.
*
* RETURNS: OK, or ERROR if the routine cannot be connected to the interrupt.
*
* SEE ALSO: intConnect(), sysAuxClkEnable()
*/

STATUS sysAuxClkConnect
    (
    FUNCPTR routine,	/* routine called at each aux. clock interrupt */
    int     arg		/* argument to auxiliary clock interrupt routine */
    )

⌨️ 快捷键说明

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