The timer is a peripheral that allows the user to measure real-time as a number of clock cycles. A user loads the timer with the number of clock cycles they'd like to wait, and then polls the "Timeout" bit or optionally enables an interrupt to indicate to the processor that the period has elapsed.
Device | Timer | |||||||||||||||||||||
Configuration | 6 32-bit mapped registers (only lower 16 bits used) | |||||||||||||||||||||
Input/Output | Both | |||||||||||||||||||||
Address Base | Tiner 1: 0xFF202000 and Timer2: 0xxFF202020 | |||||||||||||||||||||
Address Map |
| |||||||||||||||||||||
Initialization | None (though a period must be written before running the timer, or it will immediately timeout) | |||||||||||||||||||||
Interrupts |
| |||||||||||||||||||||
Hardware Setup | None | |||||||||||||||||||||
Reference | Full documentation from Altera |
The timer counts downwards on a 100MHz clock, and runs in terms of clock cycles (a period of 100000000 will cause the timer to timeout in 1 second).
The full 32-bit period of the timer is given by the combination of "Periodh" and "Periodl". Both those registers are only 16-bits, even though they take up 32-bits of the address space.
When a timeout occurs, the Timeout bit in the Control Register will stay as 1 until the user writes 0 to the status register.
When a timeout occurs, the timer's counter is reset to the period, regardless of the "continue" bit. The continue bit determines whether the timer will then wait until 1 is written to the start bit again, or continue running immediately.
Reading the time remaining in the timer can not be done by reading the Periodh/l registers. Instead, the Counter Snapshot is used to copy the current time remaining, which can then be safely read by the user. By writing to either one of the snapshot registers (the written value is ignored), the current value of Periodh and Periodl, will be copied into the corresponding snapshot registers, which can then be read as in example 2 below.
WARNING: Do not try to read the Periodh/l registers directly.
movia r7, 0xFF202000 # r7 contains the base address for the timer movui r2, 1000 stwio r2, 8(r7) # Set the period to be 1000 clock cycles stwio r0, 12(r7) movui r2, 4 stwio r2, 4(r7) # Start the timer without continuing or interrupts
movia r7, 0xFF202000 # r7 contains the base address for the timer stwio r0,16(r7) # Tell Timer to take a snapshot of the timer ldwio r3,16(r7) # Read snapshot bits 0..15 ldwio r4,20(r7) # Read snapshot bits 16...31 slli r4,r4,16 # Shift left logically or r4,r4,r3 # Combine bits 0..15 and 16...31 into one register
#define Timer 0xFF202000 #define TimerStatus ((volatile short*) (Timer)) #define TimerControl ((volatile short*) (Timer+4)) #define TimerTimeoutL ((volatile short*) (Timer+8)) #define TimerTimeoutH ((volatile short*) (Timer+12)) #define TimerSnapshotL ((volatile short*) (Timer+16)) #define TimerSnapshotH ((volatile short*) (Timer+20)) #define ADDR_LEDR ((volatile long *) 0xFF200000) long numclks,numchigh,numclow; int main() { int i; // Configure the timeout period to maximum *(TimerTimeoutL)=0xffff; *(TimerTimeoutH)=0xffff; // Configure timer to start counting and to always continue *(TimerControl)=6; while (1) { *(TimerSnapshotL)=0; //write to timer to get snapshot numclow = *(TimerSnapshotL); //get low part numchigh = *(TimerSnapshotH); //get high part numclks = numclow | (numchigh << 16); //assemble full number *ADDR_LEDR = numclks; } }