UART
micro/uart provides serial communication. UART is the most common way to get debug output off an MCU.
Basic Usage
use board/pico as board
use core/fmt
use std/time
fn main() -> never {
let port = board.default_uart().init()
loop {
fmt.write(port, "hello from Flint\r\n")
time.sleep_ms(1000)
}
}
Initialization
Current executable surface:
use micro/uart
let port = uart.port(0).init()
For board-default debug output, prefer:
use board/pico as board
let port = board.default_uart().init()
Writing
port.write_byte(0x0A)
port.write_char('A')
// Formatted output through core/fmt
use core/fmt
fmt.write(port, "temp={}\r\n", temp_c)
fmt.write(port, "x={} y={}\r\n", x, y)
uart.Port participates in core/io.Writer, and core/fmt.write(...) uses that concrete writer implementation on the current executable path. General runtime dispatch through a trait-typed io.Writer parameter is still separate backend work.
Reading
let has_data = port.has_data()
let byte = port.read_byte()
Board Package Convenience
The board package provides a pre-configured default UART:
use board/pico
fn main() -> never {
let console = pico.default_uart().init()
loop {
fmt.write(console, "tick\r\n")
time.sleep_ms(1000)
}
}
Example: Temperature Over UART
From examples/rp2040/temp_sensor:
use board/pico
use core/fmt
use std/time
fn main() -> never {
let port = pico.default_uart().init()
loop {
let temp_c: f32 = pico.temp_sensor().read_c()
fmt.write(port, "temp={}C\r\n", temp_c)
time.sleep_ms(1000)
}
}
Do and Don’t
// Do: use core/fmt for checked no-heap formatting
fmt.write(port, "value={}\r\n", n)
// Do: use the board-default UART when you want the standard debug port
let port = pico.default_uart().init()
// Avoid: writing docs or examples against unimplemented builder APIs
let port = uart.port(0).init()
// Avoid: using UART for timing-critical code; UART TX has variable latency