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

TermMeaning
GPTMGeneral-Purpose Timer Module
One-shotCounts once and stops
PeriodicAuto-reloads and counts forever
CaptureTimestamps an external GPIO edge
Edge-countCounts external GPIO edges
ConcatenateCombine Timer A + B into a single 32-bit timer

Intermediate Level — How It Works

Timer Modes

ModeGPTMCFGGPTMTAMRDescription
32-bit one-shot0x00x1Counts once, stops at 0
32-bit periodic0x00x2Auto-reloads, runs forever
16-bit one-shot0x40x1Timer A or B independently
16-bit periodic0x40x2Timer A or B independently
Input capture edge-time0x40x3Captures timestamp on GPIO edge
Input capture edge-count0x40x3+TACMRCounts GPIO edges

Key Registers

RegisterOffsetDescription
GPTMCFG0x0000=32-bit, 4=16-bit, 1=RTC
GPTMTAMR0x004Timer A Mode: 1=one-shot, 2=periodic, 3=capture
GPTMTBMR0x008Timer B Mode
GPTMCTL0x00CEnable bits, trigger, stall, output mode
GPTMIMR0x018Interrupt mask
GPTMRIS0x01CRaw interrupt status
GPTMMIS0x020Masked interrupt status
GPTMICR0x024Interrupt clear
GPTMTAILR0x028Timer A Interval Load (reload value)
GPTMTBILR0x02CTimer B Interval Load
GPTMTAPR0x038Timer A Prescaler (16-bit mode only)
GPTMTBPR0x03CTimer B Prescaler
GPTMTAV0x050Timer 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 PointDetails
Timer blocksTIMER0-5 (16-bit pairs) + WTIMER0-5 (32-bit pairs)
32-bit modeConcatenate A+B with GPTMCFG=0
Max 32-bit period~53.7 seconds at 80 MHz
Load registerGPTMTAILR (Timer A), GPTMTBILR (Timer B)
Interrupt clearGPTMICR — must clear in ISR
Prescaler8-bit, 16-bit mode only
Capture modeEdge-time or edge-count on CCP pins
DriverLibTimerConfigure, TimerLoadSet, TimerEnable, TimerIntEnable

Next Chapter

USART in Tiva C

Share: