UART Operations

Relevant source files

This document covers the core UART operations provided by the Pl011Uart implementation, including initialization, character transmission and reception, status monitoring, and interrupt handling. These operations form the fundamental interface for communicating with PL011 UART hardware controllers.

For details about the underlying register structure and memory layout, see Register Definitions. For complete API documentation and method signatures, see Pl011Uart Methods.

Operation Categories

The Pl011Uart struct provides five main categories of operations implemented through distinct methods that directly manipulate hardware registers:

Operation CategoryMethodsPurpose
Initializationinit()Configure UART for operation
Character Outputputchar()Transmit single characters
Character Inputgetchar()Receive single characters
Interrupt Detectionis_receive_interrupt()Check for receive interrupts
Interrupt Handlingack_interrupts()Clear pending interrupts

Initialization Process

init() Method Operation Flow

flowchart TD
subgraph subGraph0["Register Operations"]
    ICR["icr: Interrupt Clear Register"]
    IFLS["ifls: FIFO Level Select"]
    IMSC["imsc: Interrupt Mask"]
    CR["cr: Control Register"]
end
Start["init() called"]
ClearIRQ["Clear all interruptsicr.set(0x7ff)"]
SetFIFO["Set FIFO trigger levelsifls.set(0)"]
EnableRxInt["Enable RX interruptimsc.set(1 << 4)"]
EnableUART["Enable UART componentscr.set(tx|rx|uart enable)"]
Complete["UART ready for operation"]

ClearIRQ --> SetFIFO
EnableRxInt --> EnableUART
EnableUART --> Complete
SetFIFO --> EnableRxInt
Start --> ClearIRQ

The init() method src/pl011.rs(L64 - L76)  performs a four-step hardware configuration sequence:

  1. Interrupt Clearing: Sets icr register to 0x7ff to clear all pending interrupts
  2. FIFO Configuration: Sets ifls register to 0 for 1/8 RX FIFO and 1/8 TX FIFO trigger levels
  3. Interrupt Enabling: Sets imsc register bit 4 to enable receive interrupts (rxim)
  4. UART Activation: Sets cr register bits 0, 8, and 9 to enable transmission, reception, and overall UART operation

Sources: src/pl011.rs(L61 - L76) 

Character Transmission

putchar() Operation Flow

flowchart TD
subgraph subGraph0["Register Access"]
    FR["fr: Flag Register (Read-Only)"]
    DR["dr: Data Register (Read-Write)"]
end
PutChar["putchar(c: u8) called"]
CheckTXFull["Poll fr registerCheck bit 5 (TXFF)"]
IsTXFull["TX FIFO Full?"]
Wait["Wait - continue polling"]
WriteDR["Write character to dr registerdr.set(c as u32)"]
Complete["Character transmitted"]

CheckTXFull --> IsTXFull
IsTXFull --> Wait
IsTXFull --> WriteDR
PutChar --> CheckTXFull
Wait --> CheckTXFull
WriteDR --> Complete

The putchar() method src/pl011.rs(L79 - L82)  implements blocking character transmission:

  1. Status Polling: Continuously reads the fr (Flag Register) and checks bit 5 (TXFF - Transmit FIFO Full)
  2. Busy Waiting: If bit 5 is set, the transmit FIFO is full and the method continues polling
  3. Character Writing: When bit 5 is clear, writes the character to the dr (Data Register) as a 32-bit value

Sources: src/pl011.rs(L78 - L82) 

Character Reception

getchar() Operation Flow

flowchart TD
subgraph subGraph0["Register Access"]
    FR["fr: Flag Register (Read-Only)"]
    DR["dr: Data Register (Read-Write)"]
end
GetChar["getchar() called"]
CheckRXEmpty["Read fr registerCheck bit 4 (RXFE)"]
IsRXEmpty["RX FIFO Empty?"]
ReturnNone["Return None"]
ReadDR["Read character from dr registerdr.get() as u8"]
ReturnSome["Return Some(character)"]

CheckRXEmpty --> IsRXEmpty
GetChar --> CheckRXEmpty
IsRXEmpty --> ReadDR
IsRXEmpty --> ReturnNone
ReadDR --> ReturnSome

The getchar() method src/pl011.rs(L85 - L91)  provides non-blocking character reception:

  1. Status Check: Reads the fr (Flag Register) and examines bit 4 (RXFE - Receive FIFO Empty)
  2. Conditional Read: If bit 4 is clear (FIFO not empty), reads from the dr (Data Register)
  3. Return Logic: Returns Some(u8) if data is available, None if FIFO is empty

Sources: src/pl011.rs(L84 - L91) 

Interrupt Handling

Interrupt Detection and Acknowledgment

flowchart TD
subgraph subGraph2["Register Types"]
    MIS["mis: Masked Interrupt Status (Read-Only)"]
    ICR["icr: Interrupt Clear Register (Write-Only)"]
    AckInt["ack_interrupts() called"]
    CheckInt["is_receive_interrupt() called"]
end
subgraph subGraph0["Interrupt Detection"]
    ReturnBool["Return boolean result"]
    subgraph subGraph1["Interrupt Acknowledgment"]
        MIS["mis: Masked Interrupt Status (Read-Only)"]
        AckInt["ack_interrupts() called"]
        ClearICR["Write 0x7ff to icr register(clears all interrupt types)"]
        IntCleared["All interrupts cleared"]
        CheckInt["is_receive_interrupt() called"]
        ReadMIS["Read mis register(Masked Interrupt Status)"]
        CheckBit4["Check bit 4 (receive interrupt)"]
    end
end

AckInt --> ClearICR
CheckBit4 --> ReturnBool
CheckInt --> ReadMIS
ClearICR --> IntCleared
ReadMIS --> CheckBit4

The interrupt handling operations src/pl011.rs(L94 - L102)  provide status checking and clearing functionality:

Interrupt Detection (is_receive_interrupt()):

  • Reads the mis (Masked Interrupt Status) register
  • Checks bit 4 to determine if a receive interrupt is pending
  • Returns boolean indicating interrupt status

Interrupt Acknowledgment (ack_interrupts()):

  • Writes 0x7ff to the icr (Interrupt Clear Register)
  • Clears all interrupt types simultaneously
  • Used after handling interrupts to reset hardware state

Sources: src/pl011.rs(L93 - L102) 

FIFO Management

The PL011 UART controller includes internal FIFOs for both transmission and reception. The implementation configures and interacts with these FIFOs through specific register operations:

FIFO AspectRegisterConfigurationPurpose
Trigger LevelsiflsSet to01/8 depth triggers for both TX/RX
TX Statusfrbit 5Read-onlyIndicates TX FIFO full condition
RX Statusfrbit 4Read-onlyIndicates RX FIFO empty condition
Data TransferdrRead/WriteSingle entry point for FIFO access

The FIFO configuration ensures efficient interrupt-driven operation while preventing data loss during high-throughput scenarios.

Sources: src/pl011.rs(L68 - L69)  src/pl011.rs(L80)  src/pl011.rs(L86) 

Register Access Patterns

All UART operations follow consistent patterns for hardware register access through the regs() method src/pl011.rs(L57 - L59) :

flowchart TD
subgraph subGraph0["Access Types"]
    ReadOnly["ReadOnly (fr, ris, mis)"]
    WriteOnly["WriteOnly (icr)"]
    ReadWrite["ReadWrite (dr, cr, ifls, imsc)"]
end
Method["UART Method"]
RegsCall["self.regs()"]
UnsafeDeref["unsafe { self.base.as_ref() }"]
RegisterStruct["&Pl011UartRegs"]
SpecificReg["Specific Register Access"]

Method --> RegsCall
RegisterStruct --> SpecificReg
RegsCall --> UnsafeDeref
UnsafeDeref --> RegisterStruct

The regs() method provides type-safe access to memory-mapped registers through the tock-registers crate, ensuring that register access constraints are enforced at compile time.

Sources: src/pl011.rs(L57 - L59)  src/pl011.rs(L9 - L32)