SPI
Capabilities
Ariel OS provides portable SPI drivers, which implement embedded_hal_async::spi:SpiBus and embedded_hal_async::spi::SpiDevice, so they can be used by higher-level drivers (e.g., sensor drivers).
They can be enabled using the spi Cargo feature1.
Only the main role is currently supported.
Ariel OS currently favors async interfaces, and the SPI drivers do not implement embedded_hal::spi::SpiBus, although the underlying driver may still block.
Usage
Bus Sharing
Like all buses, SPI allows connecting multiple devices (SPI subs) on a single bus. The driver for the SPI bus can be instantiated as follows (the configuration is explained below):
#![allow(unused)]
fn main() {
let spi_bus = SensorSpi::new(
peripherals.spi_sck,
peripherals.spi_miso,
peripherals.spi_mosi,
spi_config,
);
let spi_bus = Mutex::new(spi_bus);
}
The bus driver determines which SPI peripheral is used: they are available in ariel_os::hal::spi::main; their names match that of the Embassy-style HAL (in the example above, SensorSpi 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 MISO and MOSI must always be provided. Therefore, three-wire, half-duplex SPI is not supported at microcontroller level.
Then, a driver instance for each SPI sub can be created using the following:
#![allow(unused)]
fn main() {
let cs_output = ariel_os::gpio::Output::new(peripherals.spi_cs, gpio::Level::High);
let mut spi_device = ariel_os::spi::main::SpiDevice::new(&spi_bus, cs_output);
}
The output must be set to high initially, as the chip select (CS) is an active-low signal.
Methods provided by embedded_hal_async::spi::SpiDevice can then be used to communicate with the SPI sub.
Configuration is applied to the whole bus, and it is not currently possible to use different configurations for individual SPI subs.
Bus Configuration
SPI configuration is HAL-specific, and a default configuration can be obtained this way:
#![allow(unused)]
fn main() {
let mut spi_config = hal::spi::main::Config::default();
}
Selecting the Bus Frequency
Ariel OS provides a helper function highest_freq_in() that helps keep the application portable while allowing to use the bus at the highest frequency possible on the hardware:
#![allow(unused)]
fn main() {
spi_config.frequency = const { highest_freq_in(Kilohertz::kHz(1000)..=Kilohertz::kHz(2000)) };
}
Alternatively, if a specific frequency is required, enums are also available:
#![allow(unused)]
fn main() {
spi_config.frequency = ariel_os::spi::main::Frequency::_2M;
}
It it also possible to use a HAL-specific frequency setting:
#![allow(unused)]
fn main() {
spi_config.frequency = ariel_os::hal::spi::main::Frequency::F(Kilohertz::MHz(2)); // Selects 2 MHz.
// or, if the microcontroller or the HAL does not support arbitrary frequencies:
spi_config.frequency = ariel_os::hal::spi::main::Frequency::_2M; // Selects 2 MHz.
}
Tip
HAL-specific frequency settings should only be used when required, to keep the application as portable as possible.
The maximum available frequency depends on the microcontroller, and may be further limited by the Embassy-style HAL and by Ariel OS. In particular, Ariel OS currently limits it to that of the SPI peripheral supporting the lowest maximum frequency.
Selecting the SPI Mode
The SPI mode can be configured using Mode:
#![allow(unused)]
fn main() {
spi_config.mode = ariel_os::spi::Mode::Mode3;
}
-
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. ↩