all
Chapter 8 of 20

Timers in Tiva C — Tiva C

Eslam El Hefny Apr 8, 2025 6 min read
40% done

Timers in Tiva C — Tiva C

Overview

The TM4C123GH6PM provides six General-Purpose Timer (GPTM) blocks (TIMER0 through TIMER5). Each block contains two 16-bit sub-timers (Timer A and Timer B) that can be used independently or concatenated to form a single 32-bit timer. Two additional wide timer blocks provide 32-bit sub-timers concatenatable into 64-bit mode.


Beginner Level — What & Why

What is a Timer?

A timer is a hardware counter that counts up or down at the system clock frequency. When it reaches a target value, it fires an event: either triggering an interrupt, toggling a pin, or capturing a timestamp. Think of a stopwatch that can not only time events but also ring an alarm at a precise moment.

Real-World Analogy

A kitchen oven timer counts down from a set time and beeps when done. The GPTM is like having six of these timers simultaneously, some measuring time, some watching for events, and some generating precise output signals.

What Problem Does It Solve?

  • Generate precise periodic interrupts (every 10 ms for a control loop)
  • Measure pulse widths (RC servo, ultrasonic sensor echo)
  • Generate output signals at exact frequencies (tone generation)
  • Trigger ADC conversions at precise intervals

Key Terms

Term Meaning
GPTM General-Purpose Timer Module
One-shot Counts once and stops
Periodic Auto-reloads and counts forever
Capture Timestamps an external GPIO edge
Edge-count Counts external GPIO edges
Concatenate Combine Timer A + B into a single 32-bit timer

Intermediate Level — How It Works

Timer Modes

Mode GPTMCFG GPTMTAMR Description
32-bit one-shot 0x0 0x1 Counts once, stops at 0
32-bit periodic 0x0 0x2 Auto-reloads, runs forever
16-bit one-shot 0x4 0x1 Timer A or B independently
16-bit periodic 0x4 0x2 Timer A or B independently
Input capture edge-time 0x4 0x3 Captures timestamp on GPIO edge
Input capture edge-count 0x4 0x3+TACMR Counts GPIO edges

Key Registers

Register Offset Description
GPTMCFG 0x000 0=32-bit, 4=16-bit, 1=RTC
GPTMTAMR 0x004 Timer A Mode: 1=one-shot, 2=periodic, 3=capture
GPTMTBMR 0x008 Timer B Mode
GPTMCTL 0x00C Enable bits, trigger, stall, output mode
GPTMIMR 0x018 Interrupt mask
GPTMRIS 0x01C Raw interrupt status
GPTMMIS 0x020 Masked interrupt status
GPTMICR 0x024 Interrupt clear
GPTMTAILR 0x028 Timer A Interval Load (reload value)
GPTMTBILR 0x02C Timer B Interval Load
GPTMTAPR 0x038 Timer A Prescaler (16-bit mode only)
GPTMTBPR 0x03C Timer B Prescaler
GPTMTAV 0x050 Timer A current value

TivaWare DriverLib API

#include "driverlib/timer.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"

/* Enable TIMER0 clock */
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0));

/* Configure TIMER0 as 32-bit periodic timer */
TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

/* Set period for 100 ms at 80 MHz
 * Period = clock * time = 80,000,000 * 0.1 = 8,000,000 ticks */
TimerLoadSet(TIMER0_BASE, TIMER_A, 8000000 - 1);

/* Enable Timer A timeout interrupt */
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

/* Enable Timer0A interrupt in NVIC */
IntEnable(INT_TIMER0A);
IntMasterEnable();

/* Start the timer */
TimerEnable(TIMER0_BASE, TIMER_A);

ISR Template

void TIMER0A_Handler(void)
{
    /* Clear the timer interrupt flag */
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    /* User code here — toggle LED, update counter, etc. */
}

Advanced Level — Deep Dive

Bare-Metal Periodic Timer

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_timer.h"
#include "inc/hw_ints.h"

void Timer0A_InitPeriodic_100ms(void)
{
    /* Enable Timer0 clock */
    HWREG(SYSCTL_RCGCTIMER) |= (1U << 0);
    while (!(HWREG(SYSCTL_PRTIMER) & (1U << 0)));

    /* Disable timer before configuration */
    HWREG(TIMER0_BASE + TIMER_O_CTL) &= ~TIMER_CTL_TAEN;

    /* 32-bit mode: GPTMCFG = 0 */
    HWREG(TIMER0_BASE + TIMER_O_CFG) = 0;

    /* Periodic mode: GPTMTAMR = 0x2, count down */
    HWREG(TIMER0_BASE + TIMER_O_TAMR) = TIMER_TAMR_TAMR_PERIOD;

    /* Load value for 100 ms: 80,000,000 * 0.1 - 1 = 7,999,999 */
    HWREG(TIMER0_BASE + TIMER_O_TAILR) = 7999999;

    /* Clear any pending interrupt */
    HWREG(TIMER0_BASE + TIMER_O_ICR) = TIMER_ICR_TATOCINT;

    /* Enable timeout interrupt */
    HWREG(TIMER0_BASE + TIMER_O_IMR) = TIMER_IMR_TATOIM;

    /* Enable NVIC interrupt for Timer0A (IRQ 19) */
    HWREG(NVIC_EN0) = (1U << (INT_TIMER0A - 16));

    /* Enable the timer */
    HWREG(TIMER0_BASE + TIMER_O_CTL) |= TIMER_CTL_TAEN;
}

Input Capture Mode (Measure Pulse Width)

Used for ultrasonic sensors, RC receiver PWM reading, or encoder timing:

/* Configure Timer0 16-bit edge-time capture on PB6 (T0CCP0) */
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0));
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOB));

/* Configure PB6 as Timer0 Capture pin */
GPIOPinConfigure(GPIO_PB6_T0CCP0);
GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);

/* 16-bit edge-time capture, count up */
TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR |
                             TIMER_CFG_A_CAP_TIME_UP);

/* Capture on both edges to measure pulse width */
TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_BOTH_EDGES);

/* Set prescaler for longer range (16-bit + 8-bit prescaler = 24-bit) */
TimerPrescaleSet(TIMER0_BASE, TIMER_A, 0xFF);  // max prescale

/* Load maximum value */
TimerLoadSet(TIMER0_BASE, TIMER_A, 0xFFFF);

TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);
IntEnable(INT_TIMER0A);
IntMasterEnable();
TimerEnable(TIMER0_BASE, TIMER_A);

Wide Timers (32-bit sub-timers, 64-bit concatenated)

The TM4C123 also has Wide Timer blocks (WTIMER0-WTIMER5). Each wide sub-timer is 32 bits:

SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
TimerConfigure(WTIMER0_BASE, TIMER_CFG_PERIODIC);
/* Load 32-bit value for ~53 second period at 80 MHz */
TimerLoadSet(WTIMER0_BASE, TIMER_A, 0xFFFFFFFF);
TimerEnable(WTIMER0_BASE, TIMER_A);

Gotchas

  • TIMER_A and TIMER_B are separate when GPTMCFG = 4. Loading TIMER_A does not affect TIMER_B.
  • In 32-bit mode (GPTMCFG = 0), always use TIMER_A as the argument — TIMER_B is ignored.
  • Prescaler only works in 16-bit split mode — it has no effect in 32-bit mode.
  • Counter direction is down by default. To count up, set GPTMTAMR.TACDIR bit.
  • Timer ISRs share the same vector as other Timer A events — check GPTMMIS to determine which event fired.

Step-by-Step Example

/*
 * timer_blink.c
 * Timer0A periodic interrupt blinks Red LED at exactly 2 Hz
 * Board  : TM4C123GXL EK LaunchPad
 * SDK    : TivaWare_C_Series-2.2.x
 */

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"

static volatile uint8_t g_ui8LedState = 0;

void TIMER0A_Handler(void)
{
    /* Clear the interrupt */
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    /* Toggle Red LED */
    g_ui8LedState ^= 1;
    GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_1,
                 g_ui8LedState ? GPIO_PIN_1 : 0);
}

int main(void)
{
    /* Step 1: 80 MHz clock */
    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL |
                   SYSCTL_OSC_MAIN   | SYSCTL_XTAL_16MHZ);

    /* Step 2: Enable Port F for Red LED */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOF));
    GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_1);

    /* Step 3: Enable Timer0 */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    while (!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0));

    /* Step 4: Configure as 32-bit periodic timer */
    TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);

    /* Step 5: Load for 2 Hz (toggle = 2× per second = 500 ms)
     * Ticks = 80,000,000 * 0.5 = 40,000,000 */
    TimerLoadSet(TIMER0_BASE, TIMER_A, 40000000 - 1);

    /* Step 6: Enable timeout interrupt */
    TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);

    /* Step 7: Enable Timer0A in NVIC */
    IntEnable(INT_TIMER0A);
    IntMasterEnable();

    /* Step 8: Start the timer */
    TimerEnable(TIMER0_BASE, TIMER_A);

    while (1)
    {
        /* CPU free for other work while timer fires in background */
    }
}

Summary

Key Point Details
Timer blocks TIMER0-5 (16-bit pairs) + WTIMER0-5 (32-bit pairs)
32-bit mode Concatenate A+B with GPTMCFG=0
Max 32-bit period ~53.7 seconds at 80 MHz
Load register GPTMTAILR (Timer A), GPTMTBILR (Timer B)
Interrupt clear GPTMICR — must clear in ISR
Prescaler 8-bit, 16-bit mode only
Capture mode Edge-time or edge-count on CCP pins
DriverLib TimerConfigure, TimerLoadSet, TimerEnable, TimerIntEnable

Next Chapter

USART in Tiva C

Share: