Chapter 9 of 20

USART in Tiva C — Tiva C

Eslam El Hefny Apr 9, 2025 6 min read
45% done

USART in Tiva C — Tiva C

Overview

The TM4C123GH6PM integrates eight UART modules (UART0–UART7), each capable of standard asynchronous serial communication with programmable baud rates up to 5 Mbps. UART0 is particularly important as it is connected to the on-board ICDI debug chip, enabling easy terminal communication without external hardware.


Beginner Level — What & Why

What is UART?

UART (Universal Asynchronous Receiver-Transmitter) is one of the simplest serial communication protocols. It sends data as a stream of bits at an agreed-upon speed (baud rate), framed with start and stop bits. No shared clock signal is needed between devices — only two wires: TX (transmit) and RX (receive).

Real-World Analogy

UART is like two people exchanging morse code over walkie-talkies. Both agree on the speed beforehand (baud rate). One talks, the other listens. Start and stop beeps frame each letter (character frame). No wristwatch synchronisation is needed — only matching speeds.

What Problem Does It Solve?

  • Debug output from microcontroller to PC terminal (the “printf of embedded systems”)
  • Communication with GPS modules, Bluetooth adapters, sensors with UART interfaces
  • PC-to-MCU command interface

Key Terms

TermMeaning
Baud rateBits per second (typically 9600, 115200)
FIFO16-byte hardware buffer that holds received/transmitted data
8N18 data bits, No parity, 1 stop bit — the most common frame format
BRDBaud Rate Divisor — integer + fractional parts
UARTFRFlag register: TX/RX FIFO status

Intermediate Level — How It Works

Baud Rate Calculation

The UART clock on TM4C123 is the system clock (80 MHz by default).

BRD = f_clk / (16 × baud_rate)

For 115200 baud at 80 MHz:
BRD = 80,000,000 / (16 × 115200) = 43.4028

Integer part  (UARTIBRD) = 43
Fractional part (UARTFBRD) = round(0.4028 × 64) = round(25.78) = 26

Key Registers

RegisterOffsetDescription
UARTDR0x000Data Register (TX write / RX read)
UARTRSR0x004Receive Status / Error Clear
UARTFR0x018Flag: TXFF, RXFE, BUSY, TXFE, RXFF
UARTIBRD0x024Integer Baud Rate Divisor
UARTFBRD0x028Fractional Baud Rate Divisor
UARTLCRH0x02CLine Control (word length, FIFO, parity, stop)
UARTCTL0x030Control (UARTEN, TXE, RXE, LBE)
UARTIFLS0x034FIFO Level Select (interrupt thresholds)
UARTIM0x038Interrupt Mask
UARTRIS0x03CRaw Interrupt Status
UARTMIS0x040Masked Interrupt Status
UARTICR0x044Interrupt Clear

UARTFR flag bits:

BitNameMeaning
3BUSYUART is transmitting
4RXFERX FIFO empty (no data to read)
5TXFFTX FIFO full (cannot write)
6RXFFRX FIFO full
7TXFETX FIFO empty

TivaWare DriverLib API

#include "driverlib/uart.h"
#include "driverlib/pin_map.h"

/* Enable UART0 and Port A */
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0));
while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA));

/* Assign PA0=RX, PA1=TX alternate functions */
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

/* Configure 115200, 8N1 */
UARTConfigSetExpClk(UART0_BASE,
                    SysCtlClockGet(),  // 80 MHz
                    115200,
                    UART_CONFIG_WLEN_8 |
                    UART_CONFIG_STOP_ONE |
                    UART_CONFIG_PAR_NONE);

/* Send a character */
UARTCharPut(UART0_BASE, 'A');

/* Receive a character (blocking) */
int32_t c = UARTCharGet(UART0_BASE);

/* Non-blocking receive */
if (UARTCharsAvail(UART0_BASE))
    int32_t c = UARTCharGetNonBlocking(UART0_BASE);

UARTprintf via uartstdio

#include "utils/uartstdio.h"

/* Initialize UARTStdio on UART0 at 115200 baud */
UARTStdioConfig(0, 115200, SysCtlClockGet());

/* printf-style output over UART */
UARTprintf("Hello from TM4C123! Tick = %d\r\n", tick);

Advanced Level — Deep Dive

Bare-Metal UART Configuration

#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_uart.h"
#include "inc/hw_gpio.h"

void UART0_Init(uint32_t ui32SysClock, uint32_t ui32Baud)
{
    /* Enable UART0 and GPIO Port A clocks */
    HWREG(SYSCTL_RCGCUART)  |= (1U << 0);  // UART0
    HWREG(SYSCTL_RCGCGPIO)  |= (1U << 0);  // Port A
    while (!(HWREG(SYSCTL_PRUART)  & (1U << 0)));
    while (!(HWREG(SYSCTL_PRGPIO)  & (1U << 0)));

    /* Disable UART while configuring */
    HWREG(UART0_BASE + UART_O_CTL) &= ~UART_CTL_UARTEN;

    /* Calculate baud rate divisor
     * BRD_integer  = SysClock / (16 * baud)
     * BRD_fraction = round((BRD - int) * 64) */
    uint32_t ui32IBrd = ui32SysClock / (16 * ui32Baud);
    uint32_t ui32FBrd = (((ui32SysClock * 8) / ui32Baud) + 1) / 2 & 0x3F;

    HWREG(UART0_BASE + UART_O_IBRD) = ui32IBrd;
    HWREG(UART0_BASE + UART_O_FBRD) = ui32FBrd;

    /* 8-bit, 1 stop bit, no parity, FIFO enabled */
    HWREG(UART0_BASE + UART_O_LCRH) = UART_LCRH_WLEN_8 | UART_LCRH_FEN;

    /* Configure PA0/PA1 for UART alternate function */
    HWREG(GPIO_PORTA_BASE + GPIO_O_AFSEL) |= 0x03;   // PA0, PA1
    HWREG(GPIO_PORTA_BASE + GPIO_O_PCTL)  =
        (HWREG(GPIO_PORTA_BASE + GPIO_O_PCTL) & ~0xFF) | 0x11;  // PMC=1 (UART)
    HWREG(GPIO_PORTA_BASE + GPIO_O_DEN)   |= 0x03;

    /* Enable UART: TX and RX enabled */
    HWREG(UART0_BASE + UART_O_CTL) =
        UART_CTL_UARTEN | UART_CTL_TXE | UART_CTL_RXE;
}

void UART0_SendChar(char c)
{
    /* Wait while TX FIFO is full */
    while (HWREG(UART0_BASE + UART_O_FR) & UART_FR_TXFF);
    HWREG(UART0_BASE + UART_O_DR) = (uint32_t)c;
}

char UART0_RecvChar(void)
{
    /* Wait while RX FIFO is empty */
    while (HWREG(UART0_BASE + UART_O_FR) & UART_FR_RXFE);
    return (char)(HWREG(UART0_BASE + UART_O_DR) & 0xFF);
}

Interrupt-Driven UART

/* Enable RX interrupt when FIFO reaches 1/2 full */
UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);
IntEnable(INT_UART0);
IntMasterEnable();

void UART0_Handler(void)
{
    uint32_t ui32Status = UARTIntStatus(UART0_BASE, true);
    UARTIntClear(UART0_BASE, ui32Status);

    while (UARTCharsAvail(UART0_BASE))
    {
        char c = (char)UARTCharGetNonBlocking(UART0_BASE);
        /* Echo back */
        UARTCharPut(UART0_BASE, c);
    }
}

FIFO and Flow Control

The UART has a 16-byte deep TX FIFO and a 16-byte deep RX FIFO. FIFO interrupt thresholds (UARTIFLS) can be set to 1/8, 1/4, 1/2, 3/4, or 7/8 full. Hardware flow control (RTS/CTS) is available on UART1.

Gotchas

  • UARTLCRH must be written after UARTIBRD/UARTFBRD — writing LCRH latches the baud rate registers.
  • FIFO enabled by default (FEN bit) — if you disable it, each write/read goes directly to a single buffer register.
  • UART0 is the debug UART on LaunchPad — it routes through the ICDI chip to the PC’s USB virtual COM port.
  • Blocking UARTCharGet hangs the CPU if no data arrives — always use timeout or interrupt-based reception in production code.

Step-by-Step Example

/*
 * uart_echo.c
 * UART0 echo: receives characters from PC terminal, sends them back
 * Board  : TM4C123GXL EK LaunchPad (UART0 via USB Virtual COM Port)
 * SDK    : TivaWare_C_Series-2.2.x
 * Terminal: 115200 baud, 8N1
 */

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_memmap.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/uart.h"
#include "driverlib/pin_map.h"
#include "utils/uartstdio.h"

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 peripherals */
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    while (!SysCtlPeripheralReady(SYSCTL_PERIPH_UART0));
    while (!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA));

    /* Step 3: Configure PA0 (RX) and PA1 (TX) */
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    /* Step 4: Configure UARTStdio (wraps UART0 with printf) */
    UARTStdioConfig(0, 115200, SysCtlClockGet());

    /* Step 5: Print banner */
    UARTprintf("\r\n=== TM4C123 UART Echo Demo ===\r\n");
    UARTprintf("Type characters and press Enter:\r\n");

    /* Step 6: Echo loop */
    while (1)
    {
        /* UARTCharGet blocks until a character arrives */
        int32_t c = UARTCharGet(UART0_BASE);

        /* Echo the character back */
        UARTCharPut(UART0_BASE, (uint8_t)c);

        /* Add newline after carriage return for readability */
        if (c == '\r')
            UARTCharPut(UART0_BASE, '\n');
    }
}

Summary

Key PointDetails
UART modulesUART0–UART7
UART0 locationPA0 (RX), PA1 (TX)
Debug UARTUART0 via USB ICDI on LaunchPad
Max baud rate5 Mbps
Baud registerUARTIBRD (integer) + UARTFBRD (fractional)
Frame formatConfigurable via UARTLCRH
FIFO depth16 bytes TX, 16 bytes RX
printfUARTStdioConfig + UARTprintf from utils/uartstdio.h
RX interruptUART_INT_RX, UART_INT_RT (receive timeout)

Next Chapter

I2C Interface

Share: