Timer

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.

DeviceTimer
Configuration6 32-bit mapped registers (only lower 16 bits used)
Input/OutputBoth
Address BaseTiner 1: 0xFF202000 and Timer2: 0xxFF202020
Address Map
AddressR/WDescription
baseR/WStatus Register bits:
1 - Run (1 if timer is running)
0 - Timeout (1 if timer has timed out - write 0 to this address to clear)
base+4R/WControl Register bits:
3 - stop (write 1 to stop timer)
2 - start (write 1 to start timer)
1 - cont (if this bit is 1, timer will restart and continue when it times out,
otherwise it will just reload the timeout period, but not start)
0 - interrupt enable for timeouts
base+8R/WPeriodl - lower 16 bits of Timeout period
base+12R/WPeriodh - upper 16 bits of Timeout period
base+16R/WCounter Snapshot (lower 16 bits)
base+20R/WCounter Snapshot (upper 16 bits)
InitializationNone (though a period must be written before running the timer, or it will immediately timeout)
Interrupts
TriggeredOn timeout
IRQ LineTimer1 use IRQ line 0 ; Timer2 use IRQ Line 2
EnableBit 0 of Control Register
AcknowledgeWrite 0 to status register to clear timeout bit (see address map above)
Hardware SetupNone
ReferenceFull documentation from Altera

Notes

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.

Assembly Example 1: Setting the timer to run for 1000 clock cycles, and stop when it times out

   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 

Assembly Example 2: Reading the current value of the timer into R4

   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 

C Example: Reading the Timer value

#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;
   }
}