📄 at91timer.c
字号:
/* at91Timer.c - Atmel AT91 timer library */
/* Copyright 1999 ARM Limited */
/* Copyright 2002-2004 Wind River Systems, Inc. */
/*
modification history
--------------------
01b,13jul99,jpd minor documentation updates.
01a,25jun99,jpd written.
*/
/*
DESCRIPTION
This library contains routines to manipulate the timer functions on a
AT91M9200 chip with a mostly board-independent interface. This driver
provides 3 main functions, system clock support, auxiliary clock
support, and timestamp timer support. The timestamp function is always
conditional upon the INCLUDE_TIMESTAMP macro.
The Atmel AT92RM9200 microcontroller is a highly integrated
microcontroller. It contains 2xthree counter/timers,
clocked from possibly different sources to provide
software programmable interval timers via interrupt generation.
The timers are 16-bit incrementers which have associated match
registers and comparators between them. In Waveform mode, in the mode
used by this driver, they increment continuously until the timer value
matches the value in register C, at which time they flag an interrupt,
reset to zero and then continue incrementing.
The timer registers are described below under the symbolic names used
herein.
At any time, the current timer values may be read from the counter value
registers.
REGISTERS:
BLOCK MODE: (read/write) controls the external clocks connected to each
channel of the block of timers.
CHANNEL CONTROL: (write only) allows enabling, disabling and triggering
of the timer channel.
CHANNEL MODE: (read/write) allows the selection of clocks to the timer
channel, the enabling of different types of triggering, and the actions
on comparison of the counter value with the different registers.
COUNTER VALUE: (read/write) contains the actual 16-bit value of the
counter for the timer channel.
REGISTER A and B: (16-bit comparison registers not used by this driver).
REGISTER C: (read/write) 16-bit comparison register containing the value
against which to match the incrementing counter value.
STATUS: (read only) contains status information for the timer channel,
e.g. on whether comparisons and triggers have occurred, overflows
etc.
INTERRUPT ENABLE: (write only)
INTERRUPT DISABLE: (write only) registers to enable and disable the
various interrupts that can be generated by each timer channel.
INTERRUPT MASK: (read only) contains information of which interrupts
are enabled.
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 the
sys[Aux]ClkRateSet() routines. The following macros must also be defined:
SYS_TIMER_CLK /@ frequency of clock feeding SYS_CLK timer @/
AUX_TIMER_CLK /@ frequency of clock feeding AUX_CLK @/
SYS_TIMER_INT_LVL /@ interrupt level for sys Clk @/
AUX_TIMER_INT_LVL /@ interrupt level for aux Clk @/
The following may also be defined, if required:
AT91_TIMER_READ (reg, result) /@ read a timer register @/
AT91_TIMER_WRITE (reg, data) /@ write ... @/
AT91_TIMER_INT_ENABLE (level) /@ enable an interrupt @/
AT91_TIMER_INT_DISABLE (level) /@ disable an interrpt @/
BSP
Apart from defining such macros described above as are needed, the BSP
will need to connect the interrupt handlers (typically in sysHwInit2()).
e.g.
.CS
/@ connect sys clock interrupt and auxiliary clock interrupt @/
intConnect (INUM_TO_IVEC (INT_VEC...), sysClkInt, 0);
intConnect (INUM_TO_IVEC (INT_VEC...), sysAuxClkInt, 0);
.CE
INCLUDES:
at91Timer.h
timestampDev.h
SEE ALSO:
"Atmel AT92M9200 ARM920T based microcontroller, Data Sheet,"
*/
/* includes */
#include "at91Timer.h"
#include "drv/timer/timestampDev.h"
/* defines */
#ifndef AT91_TIMER_READ
#define AT91_TIMER_READ(reg, result) \
((result) = *((volatile UINT32 *)(reg)))
#endif /* AT91_TIMER_READ */
#ifndef AT91_TIMER_WRITE
#define AT91_TIMER_WRITE(reg, data) \
(*((volatile UINT32 *)(reg)) = (data))
#endif /* AT91_TIMER_WRITE */
#ifndef AT91_TIMER_INT_ENABLE
#define AT91_TIMER_INT_ENABLE(level) intEnable (level)
#endif
#ifndef AT91_TIMER_INT_DISABLE
#define AT91_TIMER_INT_DISABLE(level) intDisable (level)
#endif
/* locals */
LOCAL FUNCPTR sysClkRoutine = NULL; /* routine to call on clock interrupt */
LOCAL int sysClkArg = 0; /* its argument */
LOCAL int sysClkRunning = FALSE;
LOCAL int sysClkConnected = FALSE;
LOCAL int sysClkTicksPerSecond = 60;
LOCAL FUNCPTR sysAuxClkRoutine = NULL;
LOCAL int sysAuxClkArg = 0;
LOCAL int sysAuxClkRunning = FALSE;
LOCAL int sysAuxClkTicksPerSecond = 100;
#ifdef INCLUDE_TIMESTAMP
LOCAL BOOL sysTimestampRunning = FALSE; /* timestamp running flag */
#endif /* INCLUDE_TIMESTAMP */
/*******************************************************************************
*
* sysClkInt - interrupt level processing for system clock
*
* This routine handles the system clock interrupt. It is attached to the
* clock interrupt vector by the routine sysClkConnect().
*
* RETURNS: N/A.
*/
LOCAL void sysClkInt (void)
{
UINT32 dummy;
/* acknowledge interrupt: a read of the Status Register clears interrupt */
AT91_TIMER_READ (SYS_TIMER_STATUS, dummy);
/* If any routine is attached via sysClkConnect(), call it */
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. It does not enable system clock interrupts.
* 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 be called at each clock interrupt */
int arg /* argument with which to call routine */
)
{
if (sysClkConnected == FALSE)
{
sysHwInit2 (); /* XXX for now -- needs to be in usrConfig.c */
sysClkConnected = TRUE;
}
sysClkRoutine = NULL; /* ensure routine not called with wrong arg */
sysClkArg = arg;
sysClkRoutine = routine;
return OK;
}
/*******************************************************************************
*
* sysClkDisable - turn off system clock interrupts
*
* This routine disables system clock interrupts.
*
* RETURNS: N/A
*
* SEE ALSO: sysClkEnable()
*/
void sysClkDisable (void)
{
if (sysClkRunning)
{
/* Disable timer in Channel Control Register */
AT91_TIMER_WRITE (SYS_TIMER_CCR, AT91_TIMER_CCR_CLKDIS);
/* Disable Register C Compare Interrupt in the timer */
AT91_TIMER_WRITE (SYS_TIMER_IDR, AT91_TIMER_IER_CPCS);
/* Disable the timer interrupt in the Interrupt Controller */
AT91_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 tm;
if (!sysClkRunning)
{
/*
* Calculate the timer match value:
* counter match value = (clock rate / sysClkTicksPerSecond)
*/
tm = (SYS_TIMER_CLK / sysClkTicksPerSecond);
/* Load match value into Timer Register C */
AT91_TIMER_WRITE (SYS_TIMER_REG_C, tm);
/*
* Set up Channel Mode Register: waveform mode, divide MCKI by 128,
* Register C compare trigger (reset counter and start counter).
*/
AT91_TIMER_WRITE (SYS_TIMER_CMR, (AT91_TIMER_CMR_MCKI_128 | \
AT91_TIMER_CMR_CPCTRG | \
AT91_TIMER_CMR_WAVE));
/* Clear Interrupt Status */
AT91_TIMER_READ (SYS_TIMER_STATUS, tm);
/* Enable Register C Compare Interrupt in the timer */
AT91_TIMER_WRITE (SYS_TIMER_IER, AT91_TIMER_IER_CPCS);
/* Enable the timer */
AT91_TIMER_WRITE (SYS_TIMER_CCR, AT91_TIMER_CCR_CLKEN);
/* Trigger the timer */
AT91_TIMER_WRITE (SYS_TIMER_CCR, AT91_TIMER_CCR_SWTRG);
/* enable clock interrupt in interrupt controller */
AT91_TIMER_INT_ENABLE (SYS_TIMER_INT_LVL);
sysClkRunning = TRUE;
}
}
/*******************************************************************************
*
* sysClkRateGet - get the system clock rate
*
* This routine returns the interrupt rate of the system clock.
*
* RETURNS: The number of ticks per second of the system clock.
*
* SEE ALSO: sysClkRateSet(), sysClkEnable()
*/
int sysClkRateGet (void)
{
return sysClkTicksPerSecond;
}
/*******************************************************************************
*
* sysClkRateSet - set the system clock rate
*
* This routine sets the interrupt rate of the system clock. It does
* not enable system clock interrupts unilaterally, but if the system
* clock is currently enabled, the clock is disabled and then enabled with
* the new rate. Normally 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: sysClkRateGet(), sysClkEnable()
*/
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
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -