www.pudn.com > vXworksBSPfors3c44b0.rar > sngks32cTimer.c
/* sngks32cTimer.c - Samsung S3C44B0X timer library */ /* Copyright 1984-2001 Wind River Systems, Inc. */ #include "copyright_wrs.h" /* modification history -------------------- 01o,27jul04,a_m BSP定制 for 多刃剑开发板 01e,19apr02,m_h sysAuxClkConnect for THUMB 01d,27sep01,m_h sysClkRateSet() doesn't change the clock rate 01c,18jul01,m_h Fix timestamp timer 01b,26apr01,m_h convert tabs to spaces for readability 01a,12apr01,m_h created from snds100 template. */ /* DESCRIPTION This is a timer driver for Samsung's KS32C50100 microprocessor which is an ARM based processor with several integrated peripherals. It has an interrupt controller, two 32-bit timers, one Ethernet controller, two HDLC controllers, one IIC controller, general purpose I/O ports, and a 2-channel DMA controller. The 32-bit timers can be programmed in interval mode or toggle mode. In interval mode, an output pulse is generated when the countdown value in the count register reaches zero. This will generate a frequency of (SYSCLK/count). On the other hand, in the toggle mode, the output toggles its state for each time the countdown value reaches zero. In this case, the output frequency will be (SYSCLK/(2*count)). The Timer Data register is used to load the countdown value. When the timer is enabled using the Timer Mode register, the Timer Count register is loaded with the count in Timer Data register. The count value is decremented for every internal clock edge. Once the count becomes zero, an interrupt is generated (if enabled in the interrupt controller) and the Timer Count register is reloaded automatically. The internal timer registers are accessed in a straight-forward fashion. They are accessible as 32-bit integers from the internal system register offsets, as given in sngks32cTimer.h file. The macros SNGKS32C_TIMER_REG_WRITE and SNGKS32C_TIMER_REG_READ does nothing but reading and writing 32-bit integers from and to the given addresses. This driver provides 3 main functions, system clock support, auxiliary clock support, and timestamp timer support. If necessary, each function may be conditioned by a separate INCLUDE_ macro. The timestamp function is always conditional upon the INCLUDE_TIMESTAMP macro. The SNGKS32C ARM7 timer register definitions are given in sngks32cTimer.h file. The macros SYS_CLK_RATE_MIN, SYS_CLK_RATE_MAX, AUX_CLK_RATE_MIN, and AUX_CLK_RATE_MAX must be defined in sngks32carm7.h to provide parameter checking for the sys[Aux]ClkRateSet() routines. INCLUDES: sngks32cTimer.h timestampDev.h SEE ALSO:*/ /* includes */ #include "vxWorks.h" #include "config.h" #include "drv/timer/timerDev.h" #include "drv/timer/timestampDev.h" #include "sngks32cTimer.h" /* defines */ /* The default is to assume memory mapped I/O */ #ifndef SNGKS32C_TIMER_REG_READ #define SNGKS32C_TIMER_REG_READ(reg, result) \ ((result) = *(volatile UINT32 *)(reg)) #endif /*SNGKS32C_TIMER_READ*/ #ifndef SNGKS32C_TIMER_REG_WRITE #define SNGKS32C_TIMER_REG_WRITE(reg, data) \ (*((volatile UINT32 *)(reg)) = (data)) #endif /*SNGKS32C_TIMER_WRITE*/ #ifndef SNGKS32C_TIMER_INT_ENABLE #define SNGKS32C_TIMER_INT_ENABLE(level) intEnable(level) #endif #ifndef SNGKS32C_TIMER_INT_DISABLE #define SNGKS32C_TIMER_INT_DISABLE(level) intDisable(level) #endif /* locals */ LOCAL FUNCPTR sysClkRoutine = NULL; /* routine to call on clock tick */ LOCAL int sysClkArg = (int)NULL; /* its argument */ LOCAL int sysClkRunning = FALSE; LOCAL int sysClkConnected = FALSE; LOCAL int sysClkTicksPerSecond = 60; LOCAL FUNCPTR sysAuxClkRoutine = NULL; LOCAL int sysAuxClkArg = (int)NULL; LOCAL int sysAuxClkRunning = FALSE; LOCAL int sysAuxClkTicksPerSecond = 100; LOCAL int sysAuxClkTicks; #ifdef INCLUDE_TIMESTAMP LOCAL BOOL sysTimestampRunning = FALSE; /* running flag */ LOCAL FUNCPTR sysTimestampRoutine = NULL; /* routine to call on intr */ LOCAL int sysTimestampArg = 0; /* arg for routine */ void sysTimestampInt (void); /* forward declaration */ #endif /* INCLUDE_TIMESTAMP */ /******************************************************************************* * * sysClkInt - interrupt level processing for system clock * * This routine handles a system clock interrupt. It acknowledges the * interrupt and calls the routine installed by sysClkConnect(). */ void sysClkInt (void) { /* call system clock service routine */ if (sysClkRoutine != NULL) (* 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. * * RETURN: OK, or ERROR if the routine cannot be connected to the interrupt. * * SEE ALSO: intConnect(), usrClock(), sysClkEnable() */ STATUS sysClkConnect ( FUNCPTR routine, /* routine to be called at each clock interrupt */ int arg /* argument with which to call routine */ ) { if (sysClkConnected == FALSE) { /*SNGKS32C_TIMER_REG_WRITE (SNGKS32C_TIMER_TMOD, SNGKS32C_TIMER_INITIALIZE);*/ /* : deleted and added */ /*dead zone=0, pre0=100*/ SNGKS32C_TIMER_REG_WRITE (S3C44B0X_TCFG0, 0x00000064); /*all interrupt, mux0=1/4*/ SNGKS32C_TIMER_REG_WRITE (S3C44B0X_TCFG1, 0x00000001); SNGKS32C_TIMER_REG_WRITE (S3C44B0X_TCON, 0x00000000); sysHwInit2 (); sysClkConnected = TRUE; } sysClkRoutine = NULL; sysClkArg = arg; #if ((CPU_FAMILY == ARM) && ARM_THUMB) /* set b0 so that sysClkConnect() can be used from shell */ sysClkRoutine = (FUNCPTR)((UINT32)routine | 1); #else sysClkRoutine = routine; #endif /* CPU_FAMILY == ARM */ return (OK); } /******************************************************************************* * * sysClkDisable - turn off system clock interrupts * * This routine disables system clock interrupts. * * RETURNS: N/A * * SEE ALSO: sysClkEnable() */ void sysClkDisable (void) { /*int oier;*/ /* : deleted */ if (sysClkRunning) { /* : deleted */ /*SNGKS32C_TIMER_REG_READ (SNGKS32C_TIMER_TMOD, oier);*/ /*SNGKS32C_TIMER_REG_WRITE (SNGKS32C_TIMER_TMOD, oier & ~(1));*/ /* : added */ SNGKS32C_TIMER_REG_WRITE (S3C44B0X_TCON, 0x00000000); /* disable timer interrupt in the interrupt controller */ SNGKS32C_TIMER_INT_DISABLE (SYS_TIMER_INT_LVL); sysClkRunning = FALSE; } } /******************************************************************************* * * sysClkEnable - turn on system clock interrupts * * This routine enables system clock interrupts. * * RETURNS: N/A * * SEE ALSO: sysClkConnect(), sysClkDisable(), sysClkRateSet() */ void sysClkEnable (void) { /*UINT32 oier;*/ /* : deleted */ if (!sysClkRunning) { /* * Load the match register with a new value calculated by * adding the ticks per interrupt to the current value of the * counter register. Note that this may wraparound to a value * less than the current counter value but thats OK. */ /* : deleted */ /*SNGKS32C_TIMER_REG_WRITE (SNGKS32C_TIMER_TDATA_0, SYS_TIMER_CLK / sysClkTicksPerSecond);*/ /*SNGKS32C_TIMER_REG_READ (SNGKS32C_TIMER_TMOD,oier);*/ /*SNGKS32C_TIMER_REG_WRITE (SNGKS32C_TIMER_TMOD, oier|1);*/ /* : added */ /*set T0 count*/ SNGKS32C_TIMER_REG_WRITE (S3C44B0X_TCNTB0, (165*(1000/sysClkTicksPerSecond))); /*update T0*/ SNGKS32C_TIMER_REG_WRITE (S3C44B0X_TCON, 0x00000002); /*auto reload and start T0*/ SNGKS32C_TIMER_REG_WRITE (S3C44B0X_TCON, 0x00000009); /* enable clock interrupt in interrupt controller */ SNGKS32C_TIMER_INT_ENABLE (SYS_TIMER_INT_LVL); sysClkRunning = TRUE; } } /******************************************************************************* * * 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); sysClkTicksPerSecond = ticksPerSecond; if (sysClkRunning) { sysClkDisable (); sysClkEnable (); } return (OK); } /******************************************************************************* * * sysAuxClkInt - handle an auxiliary clock interrupt * * This routine handles an auxiliary clock interrupt. It acknowledges the * interrupt and calls the routine installed by sysAuxClkConnect(). * * RETURNS: N/A */ void sysAuxClkInt (void) { /* call auxiliary clock service routine */ 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 */ ) { sysAuxClkRoutine = NULL; sysAuxClkArg = arg; #if ((CPU_FAMILY == ARM) && ARM_THUMB) /* set b0 so that sysClkConnect() can be used from shell */ sysAuxClkRoutine = (FUNCPTR)((UINT32)routine | 1); #else sysAuxClkRoutine = routine; #endif /* CPU_FAMILY == ARM */ return (OK); } /******************************************************************************* * * sysAuxClkDisable - turn off auxiliary clock interrupts * * This routine disables auxiliary clock interrupts. * * RETURNS: N/A * * SEE ALSO: sysAuxClkEnable() */ void sysAuxClkDisable (void) { /*UINT32 oier;*/ /* : deleted */ if (sysAuxClkRunning) { /* disable timer interrupt in the timer */ /* : deleted */ /*SNGKS32C_TIMER_REG_READ (SNGKS32C_TIMER_TMOD, oier);*/ /*SNGKS32C_TIMER_REG_WRITE (SNGKS32C_TIMER_TMOD, oier & ~(1 << 3));*/ /* disable timer interrupt in the interrupt controller */ SNGKS32C_TIMER_INT_DISABLE (AUX_TIMER_INT_LVL); sysAuxClkRunning = FALSE; } } /******************************************************************************* * * sysAuxClkEnable - turn on auxiliary clock interrupts * * This routine enables auxiliary clock interrupts. * * RETURNS: N/A * * SEE ALSO: sysAuxClkConnect(), sysAuxClkDisable(), sysAuxClkRateSet() */ void sysAuxClkEnable (void) { /*UINT32 oier;*/ /* : deleted */ static BOOL connected = FALSE; if (!connected) { intConnect (INUM_TO_IVEC (INT_LVL_TIMER1), sysAuxClkInt, 0); connected = TRUE; } if (!sysAuxClkRunning) { /* * Calculate the number of ticks of the timer clock that this * period requires. Do this once, here, so that the timer interrupt * routine does not need to perform a division. */ sysAuxClkTicks = (AUX_TIMER_CLK / sysAuxClkTicksPerSecond); /* * Load the match register with a new value calculated by * adding the ticks per interrupt to the current value of the * counter register. Note that this may wraparound to a value * less than the current counter value but that's OK. */ /* : deleted */ /*SNGKS32C_TIMER_REG_WRITE (SNGKS32C_TIMER_TDATA_1, sysAuxClkTicks);*/ /* enable timer 1 */ /* : deleted */ /*SNGKS32C_TIMER_REG_READ (SNGKS32C_TIMER_TMOD, oier);*/ /*SNGKS32C_TIMER_REG_WRITE (SNGKS32C_TIMER_TMOD, oier | 8);*/ /* enable clock interrupt in interrupt controller */ SNGKS32C_TIMER_INT_ENABLE (AUX_TIMER_INT_LVL); sysAuxClkRunning = TRUE; } } /******************************************************************************* * * sysAuxClkRateGet - get the auxiliary clock rate * * This routine returns the interrupt rate of the auxiliary clock. * * RETURNS: The number of ticks per second of the auxiliary clock. * * SEE ALSO: sysAuxClkEnable(), sysAuxClkRateSet() */ int sysAuxClkRateGet (void) { return (sysAuxClkTicksPerSecond); } /******************************************************************************* * * sysAuxClkRateSet - set the auxiliary clock rate * * This routine sets the interrupt rate of the auxiliary clock. It does not * enable auxiliary clock interrupts. * * RETURNS: OK, or ERROR if the tick rate is invalid or the timer cannot be set. * * SEE ALSO: sysAuxClkEnable(), sysAuxClkRateGet() */ STATUS sysAuxClkRateSet ( int ticksPerSecond /* number of clock interrupts per second */ ) { if (ticksPerSecond < AUX_CLK_RATE_MIN || ticksPerSecond > AUX_CLK_RATE_MAX) return (ERROR); sysAuxClkTicksPerSecond = ticksPerSecond; if (sysAuxClkRunning) { sysAuxClkDisable (); sysAuxClkEnable (); } return (OK); } #ifdef INCLUDE_TIMESTAMP /******************************************************************************* * * sysTimestampInt - timestamp timer interrupt handler * * This routine handles the timestamp timer interrupt. A user routine is * called, if one was connected by sysTimestampConnect(). * * RETURNS: N/A * * SEE ALSO: sysTimestampConnect() */ void sysTimestampInt (void) { if (sysTimestampRunning && sysTimestampRoutine != NULL) (*sysTimestampRoutine)(sysTimestampArg); } /******************************************************************************* * * sysTimestampConnect - connect a user routine to the timestamp timer interrupt * * This routine specifies the user interrupt routine to be called at each * timestamp timer interrupt. It does not enable the timestamp timer itself. * * RETURNS: OK, or ERROR if sysTimestampInt() interrupt handler is not used. */ STATUS sysTimestampConnect ( FUNCPTR routine, /* routine called at each timestamp timer interrupt */ int arg /* argument with which to call routine */ ) { return ERROR; /* System clock tick specifies a rollover event */ } /******************************************************************************* * * sysTimestampEnable - initialize and enable the timestamp timer * * This routine connects the timestamp timer interrupt and initializes the * counter registers. If the timestamp timer is already running, this routine * merely resets the timer counter. * * The rate of the timestamp timer should be set explicitly within the BSP, * in the sysHwInit() routine. This routine does not initialize the timer * rate. * * RETURNS: OK, or ERROR if hardware cannot be enabled. */ STATUS sysTimestampEnable (void) { if (!sysTimestampRunning) { sysTimestampRunning = TRUE; } sysClkEnable(); /* make sure that system clock is running */ return (OK); } /******************************************************************************* * * sysTimestampDisable - disable the timestamp timer * * This routine disables the timestamp timer. Interrupts are not disabled, * although the tick counter will not increment after the timestamp timer * is disabled, thus interrupts will no longer be generated. * * RETURNS: OK, or ERROR if timer cannot be disabled. */ STATUS sysTimestampDisable (void) { if (sysTimestampRunning) sysTimestampRunning = FALSE; return (OK); } /******************************************************************************* * * sysTimestampPeriod - get the timestamp timer period * * This routine returns the period of the timestamp timer in ticks. * The period, or terminal count, is the number of ticks to which the timestamp * timer will count before rolling over and restarting the counting process. * * RETURNS: The period of the timestamp timer in counter ticks. */ UINT32 sysTimestampPeriod (void) { return (SYS_TIMER_CLK / sysClkTicksPerSecond); } /******************************************************************************* * * sysTimestampFreq - get the timestamp timer clock frequency * * This routine returns the frequency of the timer clock, in ticks per second. * * RETURNS: The timestamp timer clock frequency, in ticks per second. */ UINT32 sysTimestampFreq (void) { return (SYS_TIMER_CLK); } /******************************************************************************* * * sysTimestamp - get the timestamp timer tick count * * This routine returns the current value of the timestamp timer tick counter. * The tick count can be converted to seconds by dividing by the return of * sysTimestampFreq(). * * This routine should be called with interrupts locked. If interrupts are * not already locked, sysTimestampLock() should be used instead. * * RETURNS: The current timestamp timer tick count. * * SEE ALSO: sysTimestampLock() */ UINT32 sysTimestamp (void) { UINT32 count; /*SNGKS32C_TIMER_REG_READ (SNGKS32C_TIMER_TCNT_0, count);*/ /* : deleted and added */ SNGKS32C_TIMER_REG_READ (S3C44B0X_TCNTO0, count); /* timer counts down to 0 from sysClkTicks load value */ return (sysTimestampPeriod() - count); } /******************************************************************************* * * sysTimestampLock - get the timestamp timer tick count * * This routine returns the current value of the timestamp timer tick counter. * The tick count can be converted to seconds by dividing by the return of * sysTimestampFreq(). * * This routine locks interrupts for cases where it is necessary to stop the * tick counter in order to read it, or when two independent counters must * be read. If interrupts are already locked, sysTimestamp() should be * used instead. * * RETURNS: The current timestamp timer tick count. * * SEE ALSO: sysTimestamp() */ UINT32 sysTimestampLock (void) { UINT32 result; result = sysTimestamp (); return (result); } #endif /* INCLUDE_TIMESTAMP */