Getting Started

Relevant source files

This page provides a practical guide for integrating and using the arm_pl011 crate in your embedded systems project. It covers adding the crate as a dependency, basic initialization, and fundamental UART operations.

For detailed hardware register specifications, see Hardware Reference. For comprehensive API documentation, see API Reference.

Prerequisites

The arm_pl011 crate is designed for embedded systems development with the following requirements:

RequirementDetails
Rust Edition2021 or later
Target Environmentno_stdcompatible
HardwareARM-based system with PL011 UART controller
Memory ManagementAccess to memory-mapped I/O addresses
Dependenciestock-registersfor type-safe register access

Target Architecture Support:

  • aarch64-unknown-none-softfloat (primary target)
  • x86_64-unknown-linux-gnu (development/testing)
  • riscv64gc-unknown-none-elf (cross-platform compatibility)

Sources: Cargo.toml(L1 - L16) 

Adding the Crate to Your Project

Add arm_pl011 to your Cargo.toml dependencies:

[dependencies]
arm_pl011 = "0.1.0"

The crate automatically includes the tock-registers dependency for register manipulation safety.

Sources: Cargo.toml(L14 - L15) 

Basic Usage Flow

Initialization and Operation Sequence

flowchart TD
Start["Start"]
GetBase["Obtain UART Base Address"]
NewUart["Pl011Uart::new(base_ptr)"]
InitUart["uart.init()"]
Ready["UART Ready for Operations"]
TxPath["Transmit Path"]
RxPath["Receive Path"]
IntPath["Interrupt Path"]
Putchar["uart.putchar(byte)"]
TxDone["Character Transmitted"]
Getchar["uart.getchar()"]
CheckRx["Data Available?"]
RxSuccess["Character Received"]
RxEmpty["No Data"]
CheckInt["uart.is_receive_interrupt()"]
AckInt["uart.ack_interrupts()"]
IntHandled["Interrupt Processed"]

AckInt --> IntHandled
CheckInt --> AckInt
CheckRx --> RxEmpty
CheckRx --> RxSuccess
GetBase --> NewUart
Getchar --> CheckRx
InitUart --> Ready
IntPath --> CheckInt
NewUart --> InitUart
Putchar --> TxDone
Ready --> IntPath
Ready --> RxPath
Ready --> TxPath
RxPath --> Getchar
Start --> GetBase
TxPath --> Putchar

Sources: src/pl011.rs(L51 - L103) 

Code Entity Mapping

flowchart TD
Hardware["PL011 Hardware Controller"]
BaseAddr["Memory-mapped Base Address"]
NewMethod["Pl011Uart::new(base: *mut u8)"]
UartStruct["Pl011Uart struct"]
RegStruct["Pl011UartRegs"]
InitMethod["init()"]
PutcharMethod["putchar(c: u8)"]
GetcharMethod["getchar() -> Option"]
IntCheckMethod["is_receive_interrupt()"]
AckMethod["ack_interrupts()"]
DataReg["dr: ReadWrite"]
FlagReg["fr: ReadOnly"]
ControlReg["cr: ReadWrite"]
IntMaskReg["imsc: ReadWrite"]
IntClearReg["icr: WriteOnly"]

BaseAddr --> NewMethod
Hardware --> BaseAddr
NewMethod --> UartStruct
RegStruct --> ControlReg
RegStruct --> DataReg
RegStruct --> FlagReg
RegStruct --> IntClearReg
RegStruct --> IntMaskReg
UartStruct --> AckMethod
UartStruct --> GetcharMethod
UartStruct --> InitMethod
UartStruct --> IntCheckMethod
UartStruct --> PutcharMethod
UartStruct --> RegStruct

Sources: src/pl011.rs(L42 - L44)  src/pl011.rs(L11 - L32)  src/pl011.rs(L49 - L103) 

Simple Usage Examples

Basic UART Setup

use arm_pl011::Pl011Uart;

// Obtain the base address for your PL011 UART
// This is platform-specific and typically provided by your BSP
let uart_base = 0x0900_0000 as *mut u8;

// Create UART instance
let mut uart = Pl011Uart::new(uart_base);

// Initialize the UART with default settings
uart.init();

Character Transmission

The putchar method blocks until the transmit FIFO has space:

// Send a single character
uart.putchar(b'H');

// Send a string
for byte in b"Hello, World!\n" {
    uart.putchar(*byte);
}

Character Reception

The getchar method returns immediately with an Option:

// Check for received data
match uart.getchar() {
    Some(byte) => {
        // Process received byte
        uart.putchar(byte); // Echo back
    }
    None => {
        // No data available
    }
}

Interrupt Handling

// Check if receive interrupt occurred
if uart.is_receive_interrupt() {
    // Handle the interrupt
    if let Some(byte) = uart.getchar() {
        // Process received data
    }
    
    // Clear interrupts
    uart.ack_interrupts();
}

Sources: src/pl011.rs(L51 - L55)  src/pl011.rs(L64 - L76)  src/pl011.rs(L79 - L82)  src/pl011.rs(L85 - L91)  src/pl011.rs(L94 - L102) 

Memory Safety Considerations

The Pl011Uart struct implements Send and Sync traits, enabling safe usage across thread boundaries:

Safety FeatureImplementation
Memory SafetyUsesNonNullfor guaranteed non-null pointers
Thread SafetyManualSend + Syncimplementation for multi-threaded environments
Register Safetytock-registersprovides compile-time type safety for register access

Sources: src/pl011.rs(L46 - L47)  src/pl011.rs(L43) 

Configuration Details

The init() method configures the UART with these default settings:

SettingValueRegisterPurpose
FIFO Trigger1/8 leveliflsInterrupt timing
RX InterruptEnabledimscReceive notifications
UART EnableYescrOverall operation
TX EnableYescrTransmission capability
RX EnableYescrReception capability

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

Next Steps

After completing basic setup:

  1. Advanced Configuration: See UART Operations for FIFO management and custom interrupt handling
  2. Register Details: See Register Definitions for low-level register manipulation
  3. Thread Safety: See Thread Safety and Memory Safety for multi-threaded usage patterns
  4. Hardware Integration: See Hardware Reference for platform-specific considerations

For comprehensive method documentation, proceed to Pl011Uart Methods.

Sources: src/pl011.rs(L1 - L104)  Cargo.toml(L1 - L16)