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 Category | Methods | Purpose |
---|---|---|
Initialization | init() | Configure UART for operation |
Character Output | putchar() | Transmit single characters |
Character Input | getchar() | Receive single characters |
Interrupt Detection | is_receive_interrupt() | Check for receive interrupts |
Interrupt Handling | ack_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:
- Interrupt Clearing: Sets
icr
register to0x7ff
to clear all pending interrupts - FIFO Configuration: Sets
ifls
register to0
for 1/8 RX FIFO and 1/8 TX FIFO trigger levels - Interrupt Enabling: Sets
imsc
register bit 4 to enable receive interrupts (rxim
) - 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:
- Status Polling: Continuously reads the
fr
(Flag Register) and checks bit 5 (TXFF
- Transmit FIFO Full) - Busy Waiting: If bit 5 is set, the transmit FIFO is full and the method continues polling
- 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:
- Status Check: Reads the
fr
(Flag Register) and examines bit 4 (RXFE
- Receive FIFO Empty) - Conditional Read: If bit 4 is clear (FIFO not empty), reads from the
dr
(Data Register) - 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 theicr
(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 Aspect | Register | Configuration | Purpose |
---|---|---|---|
Trigger Levels | ifls | Set to0 | 1/8 depth triggers for both TX/RX |
TX Status | frbit 5 | Read-only | Indicates TX FIFO full condition |
RX Status | frbit 4 | Read-only | Indicates RX FIFO empty condition |
Data Transfer | dr | Read/Write | Single 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.