Expand description
§Asynchronous HAL APIs
This HAL provides a comprehensive and efficient way to interact with
the underlying peripherals in an asynchronous fashion, enabling concurrent
and non-blocking programming through the use of async
/await
APIs.
This module provides the basis for interacting with peripherals through
async
APIs. Notably, in order to function correctly and wake an await
ing
Future
, peripherals must be able to signal when
their respective interrupts fire. Traditionally, the user manually writes
their own interrupt handlers. When using async
APIs, the peripherals
effectively take control of their own interrupt handlers in order to wake
tasks at the appropriate time.
§Using the async
APIs
To use the asynchronous APIs provided by the HAL, enable the async
Cargo
feature. Note that this uses a certain amount of static RAM in order to
initialize wakers for each peripheral.
§Supported peripherals
Note: The asynchronous APIs for the individual peripherals are provided
in their respective modules. This module only deals with the generalities of
using async
constructs throughout the HAL.
§Declaring interrupt bindings
In order for the peripherals to wake their respective tasks, the interrupt
sources must be bound to their handler at compile time. A struct that
implements Binding
must be passed to an async
peripheral in order to prove to the compiler that the correct interrupt
handlers have been bound.
This module provides convenient macros that generate the interrupt bindings.
Use bind_interrupts
to bind single interrupt
sources to handlers. See also Declaring multiple interrupt source
bindings.
§Declaring multiple interrupt source bindings
For some thumbv7em
peripherals, there are multiple interrupt sources used
by a single peripheral. In these cases, we must provide a binding to an
interrupt handler for each of these interrupt sources in order for the
peripheral driver to function properly. The HAL defines only one interrupt
“source” per peripheral. Your job is to tell it where to find all the
relevant interrupts it must use to operate the peripheral properly. Use
bind_multiple_interrupts
to bind
multiple interrupts to a single handler.
Currently, the supported peripherals which have multiple interrupts per peripheral (thumbv7em targets only):
SERCOMx: [SERCOMx_0, SERCOMx_1, SERCOMx_2, SERCOMx_OTHER]
DMAC: [DMAC_0, DMAC_1, DMAC_2, DMAC_OTHER]
§Complete example using the feather_m0
BSP and the Embassy executor
#![no_std]
#![no_main]
use defmt_rtt as _;
use panic_probe as _;
use bsp::hal;
use bsp::pac;
use feather_m0 as bsp;
use fugit::MillisDuration;
use hal::{
clock::GenericClockController,
dmac::{DmaController, PriorityLevel},
prelude::*,
sercom::Sercom4,
};
use rtic_monotonics::systick::Systick;
atsamd_hal::bind_interrupts!(struct Irqs {
SERCOM4 => atsamd_hal::sercom::spi::InterruptHandler<Sercom4>;
DMAC => atsamd_hal::dmac::InterruptHandler;
});
#[embassy_executor::main]
async fn main(_s: embassy_executor::Spawner) {
let mut peripherals = pac::Peripherals::take().unwrap();
let _core = pac::CorePeripherals::take().unwrap();
let mut clocks = GenericClockController::with_external_32kosc(
peripherals.gclk,
&mut peripherals.pm,
&mut peripherals.sysctrl,
&mut peripherals.nvmctrl,
);
let pins = bsp::Pins::new(peripherals.port);
// Take SPI pins
let (miso, mosi, sclk) = (pins.miso, pins.mosi, pins.sclk);
// Initialize DMA Controller
let dmac = DmaController::init(peripherals.dmac, &mut peripherals.pm);
// Turn dmac into an async controller
let mut dmac = dmac.into_future(Irqs);
// Get individual handles to DMA channels
let channels = dmac.split();
// Initialize DMA Channels 0 and 1
let channel0 = channels.0.init(PriorityLevel::Lvl0);
let channel1 = channels.1.init(PriorityLevel::Lvl0);
let mut spi = bsp::spi_master(
&mut clocks,
100.kHz(),
peripherals.sercom4,
&mut peripherals.pm,
sclk,
mosi,
miso,
)
.into_future(Irqs)
.with_dma_channels(channel0, channel1);
loop {
defmt::info!("Sending 0x00 to SPI device...");
spi.write(&[0x00]).await.unwrap();
defmt::info!("Sent 0x00.");
let mut buffer = [0xff; 4];
spi.read(&mut buffer).await.unwrap();
defmt::info!("Read buffer: {:#x}", buffer);
Systick::delay(MillisDuration::<u32>::from_ticks(500).convert()).await;
}
}
Modules§
- Async interrupts