Skip to main content

Command Palette

Search for a command to run...

What Really Happens When You Send Data Through UART?

Updated
5 min read
What Really Happens When You Send Data Through UART?

Most engineers learn UART as one of the first communication protocols in embedded systems. We often see diagrams showing TX connected to RX, configure a baud rate, call a transmit API, and data magically appears on the other side.

But what actually happens between calling a UART transmit function and seeing bytes arrive at the receiver?

This article explores the complete transmission path from software to hardware and back again.

Why UART Still Matters

UART (Universal Asynchronous Receiver Transmitter) remains one of the most widely used communication interfaces in embedded systems.

You'll find it in:

  • Debug consoles, Sensor communication, Bootloaders, Wireless modules, GPS receivers, Production testing interfaces, Firmware update mechanisms

Even modern SoCs still include multiple UART peripherals.

Understanding UART deeply helps engineers understand how software interacts with hardware.

The Simple Application View

Most applications use UART through an API.

uart_write("Hello");

From the application's perspective, this looks simple.

The assumption is:

Application calls API -> UART sends data -> Receiver gets data.

However, several layers operate underneath. Let's focus on each layer one-by-one.

Layer 1: Application Layer

The application decides:

  • What data to send, When to send it, Which UART instance to use

Example:

char msg[] = "Hello";
uart_write(msg, sizeof(msg));

At this stage, data exists only in system memory. Nothing has reached the UART peripheral yet.

Layer 2: UART Driver

The UART driver acts as the bridge between software and hardware.

Its responsibilities include:

  • Parameter validation, Buffer management, Register programming, Interrupt handling, DMA setup (if enabled), Error handling

The driver converts a software request into hardware actions.

Layer 3: UART Hardware FIFO

Most UART peripherals include transmit FIFOs.

FIFO stands for First-In First-Out.

Instead of sending directly to the UART shift register, the driver typically fills the FIFO.

Example:

FIFO
+-----+
| H   |
| e   |
| l   |
| l   |
| o   |
+-----+

This allows software and hardware to operate independently.

The CPU can continue executing while UART hardware transmits bytes.

Layer 4: Shift Register

The UART hardware moves bytes from FIFO into a shift register.

The shift register is responsible for serializing parallel data.

Example:

Byte: 0x41

Binary:
01000001

The shift register sends one bit at a time over the TX line.

This is where parallel-to-serial conversion occurs.

Layer 5: UART Frame Creation

UART doesn't simply send raw bytes.

Each byte is wrapped into a frame.

Example configuration:

  • Baud Rate: 115200

  • Data Bits: 8

  • Parity: None

  • Stop Bits: 1

Frame format:

Idle | Start | Data Bits | Stop
  1      0      8 bits      1

For character 'A' (0x41):

Start
 0

Data
10000010 (LSB first)

Stop
1

The receiver uses the start bit to synchronize.

What Determines Transmission Speed?

Transmission speed depends on baud rate.

Example:

115200 baud

One bit duration:

1 / 115200
≈ 8.68 µs

10-bit frame:

8.68 × 10
≈ 86.8 µs

Approximately 11,520 bytes per second.

This explains why UART becomes a bottleneck for image transfer and high-speed data applications.

What Happens on the Receiving Side?

The receiver continuously monitors the RX line.

When a falling edge appears:

1 -> 0

the UART detects a start bit.

The receiver then samples incoming bits at predefined intervals.

The reconstructed byte is stored into a receive FIFO.

Software later reads the data through:

uart_read(...)

or through an interrupt service routine.

Interrupt Driven Transmission

Polling works for simple applications.

Production systems often use interrupts.

Flow:

Application
     |
Driver
     |
FIFO Empty Interrupt
     |
ISR
     |
Load More Data

Advantages:

  • Better CPU utilization

  • Lower latency

  • Higher scalability

Most modern embedded firmware uses interrupt-driven UART communication.

DMA-Based UART

For large transfers, DMA is often preferred.

Flow:

Application
     |
DMA Setup
     |
DMA Engine
     |
UART FIFO
     |
TX Line

Advantages:

  • Minimal CPU involvement

  • High throughput

  • Lower power consumption

DMA becomes essential for image streaming, logging systems, and large data transfers.

Common UART Errors

Real systems encounter several UART errors:

  • Framing Error - Incorrect stop bit detected.

  • Parity Error - Parity validation fails.

  • Overrun Error - Receiver cannot process incoming data fast enough.

  • Buffer Overflow - Software buffers become full.

A robust UART driver must detect and recover from these situations.

Putting It All Together

The next time you call:

uart_write("Hello");

remember the actual flow:

Application
    ↓
UART Driver
    ↓
TX FIFO
    ↓
Shift Register
    ↓
UART Frame Generation
    ↓
TX Pin
    ↓
RX Pin
    ↓
RX FIFO
    ↓
UART Driver
    ↓
Application

What appears to be a simple API call is actually a carefully coordinated interaction between software, hardware, interrupts, buffers, and timing logic.

Understanding this flow is the foundation for designing reliable embedded communication systems.


What's Next?

In the next article we'll explore:

"SPI Explained Beyond MOSI and MISO"

We'll examine what really happens inside the controller, peripheral, FIFOs, interrupts, DMA engines, and clock generation hardware when an SPI transfer begins.