diff --git a/boards/feather_m0/examples/async_dmac.rs b/boards/feather_m0/examples/async_dmac.rs index 9cb8efa8fb95..d648ce8ec40d 100644 --- a/boards/feather_m0/examples/async_dmac.rs +++ b/boards/feather_m0/examples/async_dmac.rs @@ -32,7 +32,7 @@ async fn main(_s: embassy_executor::Spawner) { ); // Initialize DMA Controller - let dmac = DmaController::init(peripherals.dmac, &mut peripherals.pm); + let dmac = DmaController::new(peripherals.dmac, &mut peripherals.pm); // Turn dmac into an async controller let mut dmac = dmac.into_future(crate::Irqs); diff --git a/boards/feather_m0/examples/async_i2c.rs b/boards/feather_m0/examples/async_i2c.rs index 7c986c6b77f2..72a182f28730 100644 --- a/boards/feather_m0/examples/async_i2c.rs +++ b/boards/feather_m0/examples/async_i2c.rs @@ -41,7 +41,7 @@ async fn main(_s: embassy_executor::Spawner) { let i2c_sercom = bsp::periph_alias!(peripherals.i2c_sercom); // Initialize DMA Controller - let dmac = DmaController::init(peripherals.dmac, &mut peripherals.pm); + let dmac = DmaController::new(peripherals.dmac, &mut peripherals.pm); // Turn dmac into an async controller let mut dmac = dmac.into_future(Irqs); diff --git a/boards/feather_m0/examples/async_spi.rs b/boards/feather_m0/examples/async_spi.rs index ddcae321cf09..e10d72c4ee35 100644 --- a/boards/feather_m0/examples/async_spi.rs +++ b/boards/feather_m0/examples/async_spi.rs @@ -41,7 +41,7 @@ async fn main(_s: embassy_executor::Spawner) { let spi_sercom = bsp::periph_alias!(peripherals.spi_sercom); // Initialize DMA Controller - let dmac = DmaController::init(peripherals.dmac, &mut peripherals.pm); + let dmac = DmaController::new(peripherals.dmac, &mut peripherals.pm); // Turn dmac into an async controller let mut dmac = dmac.into_future(Irqs); diff --git a/boards/feather_m0/examples/async_uart.rs b/boards/feather_m0/examples/async_uart.rs index fb555ac6aaa0..4a103d9fd8df 100644 --- a/boards/feather_m0/examples/async_uart.rs +++ b/boards/feather_m0/examples/async_uart.rs @@ -41,7 +41,7 @@ async fn main(spawner: embassy_executor::Spawner) { let uart_sercom = periph_alias!(peripherals.uart_sercom); // Initialize DMA Controller - let dmac = DmaController::init(peripherals.dmac, &mut peripherals.pm); + let dmac = DmaController::new(peripherals.dmac, &mut peripherals.pm); // Turn dmac into an async controller let mut dmac = dmac.into_future(Irqs); // Get individual handles to DMA channels diff --git a/boards/feather_m0/examples/dmac.rs b/boards/feather_m0/examples/dmac.rs index eff3d6ce51e9..8af191dc7d35 100644 --- a/boards/feather_m0/examples/dmac.rs +++ b/boards/feather_m0/examples/dmac.rs @@ -41,7 +41,7 @@ fn main() -> ! { cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); // Initialize DMA Controller - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, &mut pm); // Get individual handles to DMA channels let mut channels = dmac.split(); diff --git a/boards/feather_m0/examples/i2c.rs b/boards/feather_m0/examples/i2c.rs index 02480426a84d..743b251d7657 100644 --- a/boards/feather_m0/examples/i2c.rs +++ b/boards/feather_m0/examples/i2c.rs @@ -46,7 +46,7 @@ fn main() -> ! { let (sda, scl) = (pins.sda, pins.scl); // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, &mut pm); let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); diff --git a/boards/feather_m0/examples/spi.rs b/boards/feather_m0/examples/spi.rs index 43f8f9e395da..d6be496a5481 100644 --- a/boards/feather_m0/examples/spi.rs +++ b/boards/feather_m0/examples/spi.rs @@ -40,7 +40,7 @@ fn main() -> ! { let (miso, mosi, sclk) = (pins.miso, pins.mosi, pins.sclk); // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, &mut pm); let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); let chan1 = channels.1.init(PriorityLevel::Lvl0); diff --git a/boards/feather_m0/examples/uart_dma_blocking.rs b/boards/feather_m0/examples/uart_dma_blocking.rs index 1c3c1a8d5d3f..fa15dab6633b 100644 --- a/boards/feather_m0/examples/uart_dma_blocking.rs +++ b/boards/feather_m0/examples/uart_dma_blocking.rs @@ -36,7 +36,7 @@ fn main() -> ! { let pins = bsp::Pins::new(peripherals.port); // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, &mut pm); let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); diff --git a/boards/feather_m0/examples/uart_dma_nonblocking.rs b/boards/feather_m0/examples/uart_dma_nonblocking.rs index dae57b611d7e..8f1238f6dc80 100644 --- a/boards/feather_m0/examples/uart_dma_nonblocking.rs +++ b/boards/feather_m0/examples/uart_dma_nonblocking.rs @@ -36,7 +36,7 @@ fn main() -> ! { let pins = bsp::Pins::new(peripherals.port); // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, &mut pm); let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); diff --git a/boards/feather_m4/examples/dmac.rs b/boards/feather_m4/examples/dmac.rs index 16fec8bb702f..d0b00987d02c 100644 --- a/boards/feather_m4/examples/dmac.rs +++ b/boards/feather_m4/examples/dmac.rs @@ -9,28 +9,21 @@ use cortex_m::asm; use feather_m4 as bsp; use panic_halt as _; -use hal::{ - clock::GenericClockController, - pac::{CorePeripherals, Peripherals}, -}; - use hal::dmac::{DmaController, PriorityLevel, Transfer, TriggerAction, TriggerSource}; +use hal::pac::Peripherals; #[bsp::entry] fn main() -> ! { let mut peripherals = Peripherals::take().unwrap(); - let core = CorePeripherals::take().unwrap(); - let _clocks = GenericClockController::with_external_32kosc( + let (mut _buses, clocks, _tokens) = hal::clock::v2::clock_system_at_reset( + peripherals.oscctrl, + peripherals.osc32kctrl, peripherals.gclk, - &mut peripherals.mclk, - &mut peripherals.osc32kctrl, - &mut peripherals.oscctrl, + peripherals.mclk, &mut peripherals.nvmctrl, ); - let mut pm = peripherals.pm; let dmac = peripherals.dmac; - let _nvic = core.NVIC; // Initialize buffers const LENGTH: usize = 50; @@ -40,7 +33,7 @@ fn main() -> ! { cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); // Initialize DMA Controller - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, clocks.ahbs.dmac); // Get individual handles to DMA channels let mut channels = dmac.split(); @@ -95,7 +88,7 @@ fn main() -> ! { // Move split channels back into the Channels struct channels.0 = chan0.into(); // Free the DmaController and return the PAC DMAC struct - let _dmac = dmac.free(channels, &mut pm); + let (_dmac, _ahb_clk) = dmac.free(channels); loop { asm::nop(); diff --git a/boards/metro_m0/examples/i2c.rs b/boards/metro_m0/examples/i2c.rs index bb6abbcea70f..451d9d77709d 100644 --- a/boards/metro_m0/examples/i2c.rs +++ b/boards/metro_m0/examples/i2c.rs @@ -46,7 +46,7 @@ fn main() -> ! { let (sda, scl) = (pins.sda, pins.scl); // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, &mut pm); let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); diff --git a/boards/metro_m0/examples/spi.rs b/boards/metro_m0/examples/spi.rs index 4ccbabb682c5..316586855c69 100644 --- a/boards/metro_m0/examples/spi.rs +++ b/boards/metro_m0/examples/spi.rs @@ -40,7 +40,7 @@ fn main() -> ! { let (miso, mosi, sclk) = (pins.miso, pins.mosi, pins.sck); // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, &mut pm); let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); let chan1 = channels.1.init(PriorityLevel::Lvl0); diff --git a/boards/metro_m4/examples/async_dmac.rs b/boards/metro_m4/examples/async_dmac.rs index 81a1a120bd30..71a396cde522 100644 --- a/boards/metro_m4/examples/async_dmac.rs +++ b/boards/metro_m4/examples/async_dmac.rs @@ -9,10 +9,7 @@ use panic_probe as _; use bsp::hal; use bsp::pac; -use hal::{ - clock::GenericClockController, - dmac::{DmaController, PriorityLevel, TriggerAction, TriggerSource}, -}; +use hal::dmac::{DmaController, PriorityLevel, TriggerAction, TriggerSource}; use metro_m4 as bsp; atsamd_hal::bind_multiple_interrupts!(struct Irqs { @@ -22,18 +19,16 @@ atsamd_hal::bind_multiple_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_s: embassy_executor::Spawner) { let mut peripherals = pac::Peripherals::take().unwrap(); - let _core = pac::CorePeripherals::take().unwrap(); - - let _clocks = GenericClockController::with_external_32kosc( + let (mut _buses, clocks, _tokens) = hal::clock::v2::clock_system_at_reset( + peripherals.oscctrl, + peripherals.osc32kctrl, peripherals.gclk, - &mut peripherals.mclk, - &mut peripherals.osc32kctrl, - &mut peripherals.oscctrl, + peripherals.mclk, &mut peripherals.nvmctrl, ); // Initialize DMA Controller - let dmac = DmaController::init(peripherals.dmac, &mut peripherals.pm); + let dmac = DmaController::new(peripherals.dmac, clocks.ahbs.dmac); // Turn dmac into an async controller let mut dmac = dmac.into_future(crate::Irqs); diff --git a/boards/samd11_bare/examples/i2c.rs b/boards/samd11_bare/examples/i2c.rs index be321a5c1173..3c9638650cba 100644 --- a/boards/samd11_bare/examples/i2c.rs +++ b/boards/samd11_bare/examples/i2c.rs @@ -46,7 +46,7 @@ fn main() -> ! { let (sda, scl) = (pins.d4, pins.d5); // Setup DMA channels for later use - let mut dmac = DmaController::init(dmac, &mut pm); + let mut dmac = DmaController::new(dmac, &mut pm); let channels = dmac.split(); let chan0 = channels.0.init(PriorityLevel::Lvl0); diff --git a/hal/src/dmac/dma_controller.rs b/hal/src/dmac/dma_controller.rs index 588488c4ce4e..f1cb79cdb768 100644 --- a/hal/src/dmac/dma_controller.rs +++ b/hal/src/dmac/dma_controller.rs @@ -3,7 +3,7 @@ //! # Initializing //! //! The DMAC should be initialized using the -//! [`DmaController::init`] method. It will consume the +//! [`DmaController::new`] method. It will consume the //! DMAC object generated by the PAC. By default, all four priority levels //! will be enabled, but can be selectively enabled/disabled through the //! [`DmaController::enable_levels`] ansd [`DmaController::disable_levels`] @@ -44,10 +44,12 @@ use super::{ channel::{Channel, Uninitialized}, sram, }; -use crate::{ - pac::{Dmac, Pm}, - typelevel::NoneT, -}; +#[hal_cfg(any("dmac-d11", "dmac-d21"))] +use crate::pac::Pm; +use crate::{pac::Dmac, typelevel::NoneT}; + +#[hal_cfg("dmac-d5x")] +type DmacAhbClk = crate::clock::v2::ahb::AhbClk; /// Trait representing a DMA channel ID pub trait ChId { @@ -150,28 +152,18 @@ macro_rules! define_channels_struct_future { with_num_channels!(define_channels_struct_future); /// Initialized DMA Controller +#[hal_macro_helper] pub struct DmaController { dmac: Dmac, + #[hal_cfg("dmac-d5x")] + ahb_clk: DmacAhbClk, _irqs: PhantomData, } impl DmaController { - /// Initialize the DMAC and return a DmaController object useable by - /// [`Transfer`](super::transfer::Transfer)'s. By default, all - /// priority levels are enabled unless subsequently disabled using the - /// `level_x_enabled` methods. - #[inline] - #[hal_macro_helper] - pub fn init(mut dmac: Dmac, _pm: &mut Pm) -> Self { - // ----- Initialize clocking ----- // - #[hal_cfg(any("dmac-d11", "dmac-d21"))] - { - // Enable clocking - _pm.ahbmask().modify(|_, w| w.dmac_().set_bit()); - _pm.apbbmask().modify(|_, w| w.dmac_().set_bit()); - } - - Self::swreset(&mut dmac); + /// Reset and enable the DMA controller. + fn init(dmac: &mut Dmac) { + Self::swreset(dmac); // SAFETY: // @@ -196,6 +188,21 @@ impl DmaController { // Enable DMA controller dmac.ctrl().modify(|_, w| w.dmaenable().set_bit()); + } + + #[hal_cfg(any("dmac-d11", "dmac-d21"))] + /// Initialize the DMAC and return a DmaController object useable by + /// [`Transfer`](super::transfer::Transfer)'s. By default, all + /// priority levels are enabled unless subsequently disabled using the + /// `level_x_enabled` methods. + #[inline] + pub fn new(mut dmac: Dmac, pm: &mut Pm) -> Self { + // ----- Initialize clocking ----- // + // Enable clocking + pm.ahbmask().modify(|_, w| w.dmac_().set_bit()); + pm.apbbmask().modify(|_, w| w.dmac_().set_bit()); + + Self::init(&mut dmac); Self { dmac, @@ -203,6 +210,23 @@ impl DmaController { } } + #[hal_cfg("dmac-d5x")] + /// Initialize the DMAC and return a DmaController object useable by + /// [`Transfer`](super::transfer::Transfer)'s. By default, all + /// priority levels are enabled unless subsequently disabled using the + /// `level_x_enabled` methods. + #[inline] + pub fn new(mut dmac: Dmac, ahb_clk: DmacAhbClk) -> Self { + Self::init(&mut dmac); + + Self { + dmac, + ahb_clk, + _irqs: PhantomData, + } + } + + #[hal_cfg(any("dmac-d11", "dmac-d21"))] /// Release the DMAC and return the register block. /// /// **Note**: The [`Channels`] struct is consumed by this method. This means @@ -210,22 +234,31 @@ impl DmaController { /// moved back into the [`Channels`] struct before being able to pass it /// into [`free`](DmaController::free). #[inline] - #[hal_macro_helper] - pub fn free(mut self, _channels: Channels, _pm: &mut Pm) -> Dmac { - self.dmac.ctrl().modify(|_, w| w.dmaenable().clear_bit()); - - Self::swreset(&mut self.dmac); + pub fn free(mut self, _channels: Channels, pm: &mut Pm) -> Dmac { + Self::disable_and_reset(&mut self.dmac); - #[hal_cfg(any("dmac-d11", "dmac-d21"))] - { - // Disable the DMAC clocking - _pm.apbbmask().modify(|_, w| w.dmac_().clear_bit()); - _pm.ahbmask().modify(|_, w| w.dmac_().clear_bit()); - } + // Disable the DMAC clocking + pm.apbbmask().modify(|_, w| w.dmac_().clear_bit()); + pm.ahbmask().modify(|_, w| w.dmac_().clear_bit()); // Release the DMAC self.dmac } + + #[hal_cfg("dmac-d5x")] + /// Release the DMAC and return the underlying resources. + /// + /// **Note**: The [`Channels`] struct is consumed by this method. This means + /// that any [`Channel`] obtained by [`split`](DmaController::split) must be + /// moved back into the [`Channels`] struct before being able to pass it + /// into [`free`](DmaController::free). + #[inline] + pub fn free(mut self, _channels: Channels) -> (Dmac, DmacAhbClk) { + Self::disable_and_reset(&mut self.dmac); + + // Release the DMAC and bus clock + (self.dmac, self.ahb_clk) + } } impl DmaController { @@ -290,6 +323,7 @@ impl DmaController { /// [`bind_interrupts`](crate::bind_interrupts). #[cfg(feature = "async")] #[inline] + #[hal_macro_helper] pub fn into_future(self, _interrupts: I) -> DmaController where I: crate::async_hal::interrupts::Binding< @@ -304,10 +338,20 @@ impl DmaController { DmaController { dmac: self.dmac, + #[hal_cfg("dmac-d5x")] + ahb_clk: self.ahb_clk, _irqs: PhantomData, } } + /// Disable and reset the DMAC + #[inline] + fn disable_and_reset(dmac: &mut Dmac) { + dmac.ctrl().modify(|_, w| w.dmaenable().clear_bit()); + + Self::swreset(dmac); + } + /// Issue a software reset to the DMAC and wait for reset to complete #[inline] fn swreset(dmac: &mut Dmac) { @@ -324,6 +368,7 @@ where super::async_api::InterruptHandler, >, { + #[hal_cfg(any("dmac-d11", "dmac-d21"))] /// Release the DMAC and return the register block. /// /// **Note**: The [`Channels`] struct is consumed by this method. This means @@ -331,22 +376,31 @@ where /// moved back into the [`Channels`] struct before being able to pass it /// into [`free`](DmaController::free). #[inline] - #[hal_macro_helper] - pub fn free(mut self, _channels: FutureChannels, _pm: &mut Pm) -> Dmac { - self.dmac.ctrl().modify(|_, w| w.dmaenable().clear_bit()); + pub fn free(mut self, _channels: FutureChannels, pm: &mut Pm) -> Dmac { + Self::disable_and_reset(&mut self.dmac); - Self::swreset(&mut self.dmac); - - #[hal_cfg(any("dmac-d11", "dmac-d21"))] - { - // Disable the DMAC clocking - _pm.apbbmask().modify(|_, w| w.dmac_().clear_bit()); - _pm.ahbmask().modify(|_, w| w.dmac_().clear_bit()); - } + // Disable the DMAC clocking + pm.apbbmask().modify(|_, w| w.dmac_().clear_bit()); + pm.ahbmask().modify(|_, w| w.dmac_().clear_bit()); // Release the DMAC self.dmac } + + #[hal_cfg("dmac-d5x")] + /// Release the DMAC and return the underlying resources. + /// + /// **Note**: The [`Channels`] struct is consumed by this method. This means + /// that any [`Channel`] obtained by [`split`](DmaController::split) must be + /// moved back into the [`Channels`] struct before being able to pass it + /// into [`free`](DmaController::free). + #[inline] + pub fn free(mut self, _channels: FutureChannels) -> (Dmac, DmacAhbClk) { + Self::disable_and_reset(&mut self.dmac); + + // Release the DMAC and bus clock + (self.dmac, self.ahb_clk) + } } macro_rules! define_split { diff --git a/hal/src/dmac/mod.rs b/hal/src/dmac/mod.rs index c1d4980a9daf..a65c458ca209 100644 --- a/hal/src/dmac/mod.rs +++ b/hal/src/dmac/mod.rs @@ -64,7 +64,7 @@ //! priority (in the default, ie static, arbitration scheme). //! //! By default, all priority levels are enabled when initializing the DMAC -//! (see [`DmaController::init`]). Levels +//! (see [`DmaController::new`]). Levels //! can be enabled or disabled through the //! [`DmaController::enable_levels`] and //! [`DmaController::disable_levels`] methods. These methods must be supplied a @@ -120,28 +120,41 @@ //! # Example //! ``` //! let mut peripherals = Peripherals::take().unwrap(); -//! let mut dmac = DmaController::init(peripherals.DMAC, &mut peripherals.PM); +//! let (mut _buses, clocks, _tokens) = hal::clock::v2::clock_system_at_reset( +//! peripherals.oscctrl, +//! peripherals.osc32kctrl, +//! peripherals.gclk, +//! peripherals.mclk, +//! &mut peripherals.nvmctrl, +//! ); +//! +//! let mut dmac = DmaController::new(peripherals.dmac, clocks.ahbs.dmac); //! // Get individual handles to DMA channels -//! let channels = dmac.split(); +//! let mut channels = dmac.split(); //! -//! // Initialize DMA Channel 0 -//! let chan0 = channels.0.init(PriorityLevel::LVL0, false, &mut dmac); +//! // Initialize DMA Channel 0 +//! let chan0 = channels.0.init(PriorityLevel::Lvl0); //! -//! // Setup a DMA transfer (memory-to-memory -> incrementing source, incrementing destination) +//! // Initialize buffers +//! const LENGTH: usize = 50; +//! let buf_src: &'static mut [u8; LENGTH] = +//! cortex_m::singleton!(: [u8; LENGTH] = [0xff; LENGTH]).unwrap(); +//! let buf_dest: &'static mut [u8; LENGTH] = +//! cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); +//! +//! // Setup a DMA transfer (memory-to-memory -> incrementing source, incrementing destination) //! // NOTE: buf_src and buf_dest should be either: //! // &'static mut T, &'static mut [T], or &'static mut [T; N] where T: BeatSize -//! let xfer = Transfer::new(chan0, buf_src, buf_dest, false).begin( -//! &mut dmac, -//! TriggerSource::DISABLE, -//! TriggerAction::BLOCK, -//! ); +//! let xfer = Transfer::new(chan0, buf_src, buf_dest, false) +//! .unwrap() +//! .begin(TriggerSource::Disable, TriggerAction::Block); //! -//! // Wait for transfer to complete and grab resulting buffers -//! let (chan0, buf_src, buf_dest, _) = xfer.wait(&mut dmac); +//! // Wait for transfer to complete and grab resulting buffers +//! let (chan0, _buf_src, _buf_dest) = xfer.wait(); //! -//! // (Optional) free the [`DmaController`] struct and return the underlying PAC struct +//! // (Optional) free the [`DmaController`] struct and return the underlying resources //! channels.0 = chan0.into(); -//! let dmac = dmac.free(channels, &mut peripherals.PM); +//! let (dmac, ahb_clk) = dmac.free(channels); //! ``` //! //! # [`Transfer`] recycling @@ -153,98 +166,112 @@ //! then call [`begin`](Transfer::begin), a [`Transfer::recycle`] method //! is provided. If the buffer lengths match and the previous transfer is //! completed, a new transfer will immediately be triggered using the provided -//! source and destination buffers. If the recycling operation is succesful, +//! source and destination buffers. If the recycling operation is successful, //! `Ok((source, destination))` containing the old source and destination //! buffers is returned. Otherwise, `Err(_)` is returned. //! //! ``` -//! let new_source = produce_source(); -//! let new_destination = produce_destination(); +//! const LENGTH: usize = 50; +//! let new_source: &'static mut [u8; LENGTH] = +//! cortex_m::singleton!(: [u8; LENGTH] = [0xff; LENGTH]).unwrap(); +//! let new_destination: &'static mut [u8; LENGTH] = +//! cortex_m::singleton!(: [u8; LENGTH] = [0x00; LENGTH]).unwrap(); //! //! // Assume xfer is a `Busy` `Transfer` -//! let (old_source, old_dest) = xfer.recycle(new_source, new_destination).unwrap(); +//! let (_old_source, _old_dest) = xfer.recycle( +//! new_source, +//! new_destination +//! ).unwrap(); //! ``` //! -//! # Waker operation +//! # Async transfers //! -//! A [`Transfer`] can also accept a function or closure that will be called on -//! completion of the transaction, acting like a waker. +//! By enabling the `async` feature, DMA transfers can be completed +//! asynchronously using [`Channel::transfer_future`]. The [`DmaController`] +//! must first be converted into async mode by calling +//! [`into_future`](DmaController::into_future) before splitting the channels. +//! The following example illustrates this using [RTIC](https://rtic.rs/) v2.x. //! //! ``` -//! fn wake_up() { -//! //... -//! } +//! use atsamd_hal::dmac::*; //! -//! fn use_waker(dmac: DmaController, -//! source: &'static mut [u8; N], -//! destination: &'static mut [u8; N] -//! ){ -//! let chan0 = dmac.split().0; -//! let xfer = Transfer::new_from_arrays(chan0, source, destination, false) -//! .with_waker(wake_up) -//! .begin(); -//! //... -//! } -//! ``` +//! atsamd_hal::bind_multiple_interrupts!(struct Irqs { +//! DMAC: [DMAC_0] => InterruptHandler; +//! }); //! -//! ## RTIC example +//! #[rtic::app(device = pac, dispatchers = [EVSYS_0])] +//! mod app { +//! use super::*; //! -//! The [RTIC] framework provides a convenient way to store a `static`ally -//! allocated [`Transfer`], so that it can be accessed by both the interrupt -//! handlers and user code. The following example shows how [`Transfer`]s might -//! be used for a series of transactions. It uses features from the latest -//! release of [RTIC], `v0.6-alpha.4`. +//! #[shared] +//! struct Shared {} //! -//! ``` -//! use atsamd_hal::dmac::*; +//! #[local] +//! struct Local { +//! other_stuff: OtherStuff, +//! channel: Channel, +//! } //! -//! const LENGTH: usize = 50; -//! type TransferBuffer = &'static mut [u8; LENGTH]; -//! type Xfer = Transfer, TransferBuffer, TransferBuffer>; -//! -//! #[resources] -//! struct Resources { -//! #[lock_free] -//! #[init(None)] -//! opt_xfer: Option, -//! -//! #[lock_free] -//! #[init(None)] -//! opt_channel: Option>, -//! } +//! #[init] +//! fn init(cx: init::Context) -> (Shared, Local) { +//! let mut peripherals = cx.device; +//! let (_buses, clocks, tokens) = atsamd_hal::clock::v2::clock_system_at_reset( +//! peripherals.oscctrl, +//! peripherals.osc32kctrl, +//! peripherals.gclk, +//! peripherals.mclk, +//! &mut peripherals.nvmctrl, +//! ); +//! +//! // Setup the DMA controller +//! let mut dmac = DmaController::new(peripherals.dmac, clocks.ahbs.dmac).into_future(Irqs); +//! +//! // Get individual handles to DMA channels +//! let channels = dmac.split(); +//! +//! // Initialize DMA Channel 0 +//! let channel = channels.0.init(PriorityLevel::Lvl0); +//! +//! task::spawn().ok().unwrap(); +//! +//! ( +//! Shared {}, +//! Local { +//! other_stuff: OtherStuff::new( +//! peripherals.rtc, +//! peripherals.port, +//! clocks.osculp32k_base, +//! tokens, +//! ), +//! channel, +//! }, +//! ) +//! } //! -//! // Note: Assume interrupts have already been enabled for the concerned channel -//! #[task(resources = [opt_xfer, opt_channel])] -//! fn task(ctx: task::Context) { -//! let task::Context { opt_xfer } = ctx; -//! match opt_xfer { -//! Some(xfer) => { -//! if xfer.complete() { -//! let (chan0, _source, dest, _payload) = xfer.take().unwrap().stop(); -//! *opt_channel = Some(chan0); -//! consume_data(buf); -//! } -//! } -//! None => { -//! if let Some(chan0) = opt_channel.take() { -//! let source: [u8; 50] = produce_source(); -//! let dest: [u8; 50] = produce_destination(); -//! let xfer = opt_xfer.get_or_insert( -//! Transfer::new_from_arrays(channel0, source, destination) -//! .with_waker(|| { task::spawn().ok(); }) -//! .begin() -//! ); -//! } +//! #[task(priority = 1, local=[other_stuff, channel])] +//! async fn task(cx: task::Context) { +//! const LENGTH: usize = 50; +//! let mut source = [0xff; LENGTH]; +//! let mut dest = [0x00; LENGTH]; +//! +//! // Just do a transfer repeatedly and then other stuff +//! loop { +//! cx.local +//! .channel +//! .transfer_future( +//! &mut source, +//! &mut dest, +//! TriggerSource::Disable, +//! TriggerAction::Block, +//! ) +//! .await +//! .unwrap(); +//! +//! cx.local.other_stuff.do_other_stuff().await; //! } //! } //! } -//! -//! #[task(binds = DMAC, resources = [opt_future])] -//! fn tcmpl(ctx: tcmpl::Context) { -//! ctx.resources.opt_xfer.as_mut().unwrap().callback(); -//! } //! ``` -//! [RTIC]: https://rtic.rs // This is necessary until modular_bitfield fixes all their identity_op warnings #![allow(clippy::identity_op)]