UART
Capabilities
Ariel OS provides portable UART drivers, which implement embedded_io_async::Read and embedded_io_async::Write.
They can be enabled using the uart Cargo feature1.
Ariel OS currently favors async interfaces, and the UART drivers do not implement embedded_io::Read or embedded_io::Write.
UART drivers are buffered drivers, which avoids missing data when a future from the UART driver is awaited in combination (e.g., with a select) with another future, at the cost of a few extra bytes of memory.
Non-buffered drivers are not currently provided.
Usage
Instantiating the Driver
The driver for a buffered UART can be instantiated as follows (the configuration is explained below):
#![allow(unused)]
fn main() {
// NOTE: The size of buffers may be adjusted.
let mut rx_buf = [0u8; 32];
let mut tx_buf = [0u8; 32];
let mut uart = TestUart::new(
peripherals.uart_rx,
peripherals.uart_tx,
&mut rx_buf,
&mut tx_buf,
uart_config,
)
.expect("UART configuration should be valid");
}
The UART driver determines which UART peripheral is used: they are available in ariel_os::hal::uart; their names match that of the Embassy-style HAL (in the example above, TestUart is a type alias for the driver selected).
Pin peripherals can be obtained through the usual mechanisms.
Some microcontrollers allow using (almost) any pair of pins, but most require specific pins for each peripheral: this is automatically enforced at compile time.
Note
Currently, pins for both RX and TX must always be provided.
The buffers should be sized depending on how long it may take for the application to yield to the async executor: the longer the larger buffers.
Leveraging the Structured Board Descriptions
Instead of relying on the UART pins being defined inside the application as presented above, it is also possible to leverage the SBD files, if the board is supported in-tree. In that case, the driver for the UART can be instantiated as follows:
ariel_os::hal::group_peripherals!(Peripherals {
uart: ariel_os_boards::pins::Uart0,
// or, to use the UART defined as host-facing in the SBD file:
uart: ariel_os_boards::pins::HOST_FACING_UART,
});
#[ariel_os::task(autostart, peripherals)]
async fn main(peripherals: Peripherals) {
let uart = peripherals.uart.build_with_config(&mut rx_buf, &mut tx_buf, uart_config)
.expect("UART configuration should be valid");
}
This uses the pins defined in the SBD file for the UART. The SBD file currently lists possible UART peripherals that can be used for the bus, and the first one is automatically selected. It is not currently possible to select another one.
The host-facing UART is the UART connected to a USB ⟷ UART adapter on the board (which may be part of an interface MCU), if present.
To make sure such a UART is available on the board the application is compiled for, the application should be made to depend on the has_host_facing_uart laze module.
There is currently no equivalent laze module for other UARTs.
Important
Here,
Uart0does not refer to theUART0microcontroller peripheral, but instead to the UART defined at index 0 in the SBD sequence of UARTs.
Configuration
UART configuration is HAL-specific, and a default configuration can be obtained this way:
#![allow(unused)]
fn main() {
let mut uart_config = ariel_os::hal::uart::Config::default();
}
The default configuration is the following:
- 8 data bits
- 1 stop bit
- No parity bit
Selecting the Baud Rate
Ariel OS provides a set of common baud rates with ariel_os::uart::Baudrate, up to 115,200 baud:
#![allow(unused)]
fn main() {
uart_config.baudrate = ariel_os::uart::Baudrate::_115200;
}
To use a baud rate outside of that set, especially a higher baud rate, HAL-specific types must be used instead:
#![allow(unused)]
fn main() {
uart_config.baudrate = ariel_os::uart::Baudrate::Hal(250_000.into())
// or, if the microcontroller or the HAL does not support arbitrary baud rates:
uart_config.baudrate = ariel_os::hal::uart::Baudrate::_1000000,
}
When providing an arbitrary baud rate, it is checked at runtime when the driver is instantiated.
Important
On the RP2040 and the RP235x MCUs, providing a baud rate too high instead uses the highest supported baud rate.
Tip
HAL-specific baud rate types should only be used when required, to keep the application as portable as possible.
Configuring Other Settings
The number of data and stop bits and whether a parity bit is used can also be configured when supported by the microcontroller and the HAL.
-
When the Cargo feature is not enabled (including indirectly as a dependency of another Cargo feature), the peripherals and their interrupts are not managed by Ariel OS and can be used separately, including through their Embassy-style HAL. ↩