Tiva-C Launchpad Using Timers to generate precise Time Delay

Keywords: Embedded systems, ARM, TM4C123GXL, Timers, Counters

Code Link: Source Code Github Keil MDK5 – ARM Assembly


In the world of embedded systems the most important parameter is time. It’s the time that qualifies a systems from simple blinky led to complex inter-systems communication. Its time which defines how fast/slow a job can be done on target processor. Obviously what’s the purpose of time if you can’t count it? This where timers comes into action. Timers provide the facility to measure time relatively from one reference point to another. This relative time measure enables us to generate an event or a specific time interval (like signal) or conversely measure an event time. This makes timers one of the crucial part of Embedded Systems.

The basic idea behind timers is that its logic is provided with some clock and upon each clock it increments/ decrements a counter register value. At the end the counted number of cycles is multiplied with input clock Time period to get the total time elapsed.

Total Time: Counter Value * 1/Frequency

Figure-1: Timer General Operation

A term that usually confuses newbies is the difference between a Timer and a Counter. As a matter of fact there is no such thing as Timers…!!! We only have counters in embedded systems. The source of confusion is that both these terms are NOT so often used INTERFACHANGABLY. The basic functions of both is to count time based events. A minor difference that is usually considered to differentiate timers and counters is frequency source. While in case of timers the input events (clock pulses) have same frequency i.e. clock to timers is fixed; and when the timer is feed from some external events which may or may not of fixed time intervals, the timer is known be as Counter (Counting events). But the basic idea behind both of them is same – They just count events. That’s it.

Tiva-C LaunchPad Timers:

The TM4C123GH6PM General-Purpose Timer Module (GPTM) contains six 16/32-bit GPTM blocks and six 32/64-bit Wide GPTM blocks. Each 16/32-bit GPTM block provides two 16-bit timers/counters (referred to as Timer A and Timer B) that can be configured to operate independently as timers or event counters, or concatenated to operate as one 32-bit timer or one 32-bit Real-Time Clock (RTC). Each 32/64-bit Wide GPTM block provides 32-bit timers for Timer A and Timer B that can be concatenated to operate as a 64-bit timer.

Timer A and Timer B can be used individually, in which case they have a 16-bit counting range for the 16/32-bit GPTM (General-Purpose Timer Module) blocks and a 32-bit counting range for 32/64-bit Wide GPTM blocks. In addition, Timer A and Timer B can be concatenated to provide a 32-bit counting range for the 16/32-bit GPTM blocks and a 64-bit counting range for the 32/64-bit Wide GPTM blocks.

Timers on TM4C123GH6PM can operate in one of the following modes.

  • One-Shot/Periodic Timer Mode
  • Real-Time Clock Timer Mode
  • Input Edge-Count Mode
  • Input Edge-Time Mode
  • PWM Mode

Of all the above given modes the simplest one is “One-Shot/Periodic Timer Mode”. In this mode the timer simple counts pre-defined number of cycles once/repeatedly. We will use this mode to continuously measure number of cycles equivalent to 1-sec as stated by the following tutorial scenario.

Tutorial Scenario:

In this tutorial we will use Timer-0 in concatenated mode (Timer-A and Timer-B are concatenated to form one 32-bits Timer) to generate blink on-board RED LED at the rate of 1-second i.e. After each 1-second, Time-0 generate an interrupt which toggles the on-board RED LED.

Let’s get started. Following are tutorial steps.

Tutorial Steps:

1. Before we can configure Timer-0, clock must be enabled to it. Clock to Timer-0 can be enabled by setting General-Purpose Timer Run Mode Clock Gating Control (RCGCTIMER) Register bit-0 to 1- Figure-2.

Figure-2: General-Purpose Timer Run Mode Clock Gating Control (RCGCTIMER) Register

  • Rx = 0: 16/32-bit general-purpose timer x is disabled. (x= 0-5)
  • Rx = 1: Enable and provide a clock to 16/32-bit general-purpose timer x in Run mode. (x= 0-5)
RCGCTIMER_REG	EQU	0x400FE604

;enable clock to Timer-0
LDR		R1,		=RCGCTIMER_REG
LDR		R0,		[R1]
ORR		R0,		R0,		#0x1 ; set bit-0
STR		R0,		[R1]

2. Once we have enabled clock to Timer-0, let’s move to further configurations. Timer-0 is 16/32-bit timer module which means it can be run in 32-bits as a single timer or two 16-bits timers (Timer A, Timer B). In 16-bits each timer i.e. Timer-A, Timer-B can count upto 65535 (2^16) which is not sufficient to generate 1-sec delay as will be clear in subsequent steps. So we will operate Timer-0 in concatenated mode.

The concatenated mode can be selected via GPTM Configuration (GPTMCFG) Register – Figure-3.

Figure-3: GPTM Configuration (GPTMCFG) Register

  • GPTMCFG[0-2] = 0x0 : concatenated mode
  • GPTMCFG[0-2] = 0x1 : RTC mode
  • GPTMCFG[0-2] = 0x4 : Timer-A and Timer-B operates in isolation

Let’s configure Timer-0 in concatenated mode.

TIMER0CFG_REG   EQU   0x40030000

; configure timer-A,B in concatenated mode for Timer-0
LDR		R1,		=TIMER0CFG_REG
MOV		R0,		#0
STR		R0,		[R1]

3. Next step is to select a mode for Timer-0. Each timer is capable of operating in one of specific modes mentioned here. As we want to continuously toggle LED after each 1-sec, so Timer-0 needs to be configured in periodic mode.

In concatenated configuration, Timer mode can be selected via GPTM Timer A Mode (GPTMTAMR) Register TAMR bits – Figure-4.

  • TAMR = 0x1 : One-Shot Timer mode
  • TAMR = 0x2 : Periodic Timer mode
  • TAMR = 0x3 : Capture mode

Figure-4: GPTM Timer A Mode (GPTMTAMR) Register

As we need period mode, so TAMR bits need to be set to 0x2.

TIMER0AMR_REG    EQU   0x40030004

; periodic mode -> 1000ms continuous delay
LDR	R1,     =TIMER0AMR_REG
LDR     R0,     [R1]
BIC     R0,     R0,     #0x3    ; clear the lower two bits
ORR     R0,     R0,     #0x2    ; set bit-1
STR	R0,	[R1]

4. Next step is to set number of cycles to be counted by timer that will result in 1-sec (1000ms) delay. The cycles count can be set via UGPTM Timer A Interval Load (GPTMTAILR) Register – Figure-5.

Figure-5: GPTM Timer A Interval Load (GPTMTAILR) Register

When the timer is counting down, this register is used to load the starting count value into the timer. When the timer is counting up, this register sets the upper bound for the timeout event. When a 16/32-bit GPTM is configured to one of the 32-bit modes, GPTMTAILR appears as a 32-bit register (the upper 16-bits correspond to the contents of the GPTM Timer B Interval Load (GPTMTBILR) register). In a 16-bit mode, the upper 16 bits of this register read as 0s and have no effect on the state of GPTMTBILR.

The number of cycles count can be calculated via the following formula.

Counts = (Time Required in Seconds) x (Timer Frequency) – 1

In our case as we want to 1-second delay so the calculation is:
Note: By default timer-0 receives 16Mhz clock.

Counts = 1 x 16000000 – 1 Counts = 15999999

TIMER0AIL_REG     EQU    0x40030028
TIMER_DELAY_VAL   EQU    16000000

; value to count for 1000ms delay @16Mhz clock
LDR	R1,	=TIMER0AIL_REG
LDR     R0,     =TIMER_DELAY_VAL
STR	R0,	[R1]

5. Now that we have configured Timer-0 for desired delay value, its time to enable interrupt which will be called every time timer counts our desired value configured in previous step. Various interrupt for Timers can be enabled/disabled via GPTM Interrupt Mask (GPTMIMR) Register – Figure-6. In this case we want the interrupt to be triggered once the timer reaches its configured count value i.e. Time-out. So we will set TATOIM field of GPTM Interrupt Mask (GPTMIMR) Register.

Figure-6: UART Control (UARTCTL) Register

  • TATOIM = 0 : Interrupt is disabled.
  • TATOIM = 1 : Interrupt is enabled.
TIMER0IMR_REG   EQU   0x40030018

; enable Interrupt for Timer-A 
LDR		R1,		=TIMER0IMR_REG
LDR		R0,		[R1]
ORR		R0,		R0,		#0x1 ; set bit-0
STR		R0,		[R1]


6. 
Now that we have successfully configured Timer-0 to generate an interrupt upon Time-out but the interrupt will only reach ARM Cortex-M core once it is also enabled on NVIC side. If you don’t know about ARM NVIC, refer to the following tutorial.

Interrupt in NVIC can be enabled/disabled via ENx (where x=0-4) Registers – Figure-7. Each of ENx register is capable of enabling/disabling 32 interrupts (1-bit for each interrupt). Each Interrupt is assigned a number – see Table 2-9 (Pg#105) in TM4C123GH6PM datasheet [2]. In order to enable an interrupt, respective bit in one of the ENx register needs to be set as per the following interrupts distribution.

  • EN0 = Interrupt 0-31.
  • EN1 = Interrupt 32-63.
  • EN2 = Interrupt 64-95.
  • EN3 = Interrupt 96-127.
  • EN4 = Interrupt 128-138.
Figure-7: Set Enable (ENx) Register

  • 0: Interrupt is disabled.
  • 1: Interrupt is enabled.

From Table 2-9 (Pg#105) in TM4C123GH6PM datasheet [2], the interrupt No for Timer-0 port is 19 – Figure-8, which is covered by EN0 (Interrupt 0-31). Let’s enable Timer-0 interrupt on NVIC side by setting bit-19.

Figure-8: Timer-0 Interrupt Entry in Vector Table

;NVIC Registers
NVIC_EN0_REG    EQU   0xE000E100

; 16/32-Bit Timer 0A at NVIC side
; assuming the core in privileged mode
LDR	    R1,	    =NVIC_EN0_REG
MOV     R2,     #0x1
LSLS    R2,     R2,     #19
STR     R2,	    [R1]  

7. That’s every thing we need to configure Timer for period mode. Let’s finally enable Timer-0 to start counting. To enable timer set TAEN field of GPTM Control (GPTMCTL) Register – Figure-9.

Figure-9: GPTM Control (GPTMCTL) Register

  • TAEN = 0 : Timer is disabled.
  • TAEN = 1 : Timer is enabled.
TIMER0CTL_REG    EQU   0x4003000C

; enable  Timer-0 
LDR		R1,		=TIMER0CTL_REG
LDR		R0,		[R1]
ORR     R0,     R0,     #0x1    ; set bit-0    
STR		R0,		[R1]

8. That’s pretty much everything we needed to configure. Now we need an ISR which will be called once interrupt is triggered by Timer-0. From TM4C123GH6PM startup file in Keil, the ISR name for Timer-0 is TIMER0A_Handler.

Within TIMER0A_Handler ISR two thing are done.

1) Interrupt is cleared so that next interrupt can call the ISR.

2) Red LED (PF.1) is toggled.

The following code snippet shows TIMER0A_Handler ISR which will be called each time Time-0 counts the pre-configured value.

TIMER0A_Handler PROC
                
                EXPORT TIMER0A_Handler

                ; clear the interrupt
                LDR	    R1,	    =TIMER0ICR_REG
		LDR	    R0,	    [R1]
		ORR	    R0,     R0,     #0x1 ; set bit-0
		STR	    R0,	    [R1]  

		; Toggle PF.1
                LDR		R1,	=GPIOFDATA_APB_REG                
		LDR		R0, 	[R1]				
		EOR		R0, 	R0,		#0x2				
		STR		R0, 	[R1]
                
                BX  LR
                ENDP
                
                ALIGN
		END

Note: For PF.1 to be toggled, the pin needs to be configured as a Digital Output. This tutorial doesn’t cover GPIO configuration as a Digital input (required for PF.0) or as a Digital output (required for PF.1). These are covered in the tutorials here  and  here.

Congratulation we have successfully configured Timer-0 for precise 1-second delay.

For complete source code refer to the Github links given at the start of this tutorial.

Video Demonstration:

Click the full screen button to have more clear view.

References:



87 thoughts on “Tiva-C Launchpad Using Timers to generate precise Time Delay”

Leave a Reply

Your email address will not be published. Required fields are marked *