diff options
| author | James Munns <[email protected]> | 2025-12-09 14:41:19 +0100 |
|---|---|---|
| committer | James Munns <[email protected]> | 2025-12-09 14:41:19 +0100 |
| commit | 4386b39e2516c453966d894b4fd265fae9d82c1a (patch) | |
| tree | 455eec4232f060ee1906b479cc3ba3567f02c773 | |
| parent | f7d5abfe946e71d426c9d0e96231e48faf27f6cd (diff) | |
Enforce scatter gather API statically
| -rw-r--r-- | embassy-mcxa/src/dma.rs | 19 | ||||
| -rw-r--r-- | examples/mcxa/src/bin/dma_scatter_gather_builder.rs | 20 |
2 files changed, 10 insertions, 29 deletions
diff --git a/embassy-mcxa/src/dma.rs b/embassy-mcxa/src/dma.rs index d076949b8..1f604a340 100644 --- a/embassy-mcxa/src/dma.rs +++ b/embassy-mcxa/src/dma.rs | |||
| @@ -2236,9 +2236,9 @@ pub struct ScatterGatherBuilder<'a, W: Word> { | |||
| 2236 | _plt: core::marker::PhantomData<&'a mut W>, | 2236 | _plt: core::marker::PhantomData<&'a mut W>, |
| 2237 | } | 2237 | } |
| 2238 | 2238 | ||
| 2239 | impl<W: Word> ScatterGatherBuilder<'_, W> { | 2239 | impl<'a, W: Word> ScatterGatherBuilder<'a, W> { |
| 2240 | /// Create a new scatter-gather builder. | 2240 | /// Create a new scatter-gather builder. |
| 2241 | pub fn new() -> ScatterGatherBuilder<'static, W> { | 2241 | pub fn new() -> Self { |
| 2242 | ScatterGatherBuilder { | 2242 | ScatterGatherBuilder { |
| 2243 | tcds: [Tcd::default(); MAX_SCATTER_GATHER_TCDS], | 2243 | tcds: [Tcd::default(); MAX_SCATTER_GATHER_TCDS], |
| 2244 | count: 0, | 2244 | count: 0, |
| @@ -2257,7 +2257,7 @@ impl<W: Word> ScatterGatherBuilder<'_, W> { | |||
| 2257 | /// # Panics | 2257 | /// # Panics |
| 2258 | /// | 2258 | /// |
| 2259 | /// Panics if the maximum number of segments (16) is exceeded. | 2259 | /// Panics if the maximum number of segments (16) is exceeded. |
| 2260 | pub fn add_transfer<'a>(mut self, src: &'a [W], dst: &'a mut [W]) -> &'a mut Self { | 2260 | pub fn add_transfer<'b: 'a>(&mut self, src: &'b [W], dst: &'b mut [W]) -> &mut Self { |
| 2261 | assert!(self.count < MAX_SCATTER_GATHER_TCDS, "Too many scatter-gather segments"); | 2261 | assert!(self.count < MAX_SCATTER_GATHER_TCDS, "Too many scatter-gather segments"); |
| 2262 | assert!(!src.is_empty()); | 2262 | assert!(!src.is_empty()); |
| 2263 | assert!(dst.len() >= src.len()); | 2263 | assert!(dst.len() >= src.len()); |
| @@ -2300,12 +2300,7 @@ impl<W: Word> ScatterGatherBuilder<'_, W> { | |||
| 2300 | /// # Returns | 2300 | /// # Returns |
| 2301 | /// | 2301 | /// |
| 2302 | /// A `Transfer` future that completes when the entire chain has executed. | 2302 | /// A `Transfer` future that completes when the entire chain has executed. |
| 2303 | /// | 2303 | pub fn build<C: Channel>(&mut self, channel: &DmaChannel<C>) -> Result<Transfer<'a>, Error> { |
| 2304 | /// # Safety | ||
| 2305 | /// | ||
| 2306 | /// All source and destination buffers passed to `add_transfer()` must | ||
| 2307 | /// remain valid for the duration of the transfer. | ||
| 2308 | pub unsafe fn build<C: Channel>(&mut self, channel: &DmaChannel<C>) -> Result<Transfer<'_>, Error> { | ||
| 2309 | if self.count == 0 { | 2304 | if self.count == 0 { |
| 2310 | return Err(Error::Configuration); | 2305 | return Err(Error::Configuration); |
| 2311 | } | 2306 | } |
| @@ -2360,7 +2355,9 @@ impl<W: Word> ScatterGatherBuilder<'_, W> { | |||
| 2360 | cortex_m::asm::dsb(); | 2355 | cortex_m::asm::dsb(); |
| 2361 | 2356 | ||
| 2362 | // Load first TCD into hardware | 2357 | // Load first TCD into hardware |
| 2363 | channel.load_tcd(&self.tcds[0]); | 2358 | unsafe { |
| 2359 | channel.load_tcd(&self.tcds[0]); | ||
| 2360 | } | ||
| 2364 | 2361 | ||
| 2365 | // Memory barrier before setting START | 2362 | // Memory barrier before setting START |
| 2366 | cortex_m::asm::dsb(); | 2363 | cortex_m::asm::dsb(); |
| @@ -2377,7 +2374,7 @@ impl<W: Word> ScatterGatherBuilder<'_, W> { | |||
| 2377 | } | 2374 | } |
| 2378 | } | 2375 | } |
| 2379 | 2376 | ||
| 2380 | impl<W: Word> Default for ScatterGatherBuilder<W> { | 2377 | impl<W: Word> Default for ScatterGatherBuilder<'_, W> { |
| 2381 | fn default() -> Self { | 2378 | fn default() -> Self { |
| 2382 | Self::new() | 2379 | Self::new() |
| 2383 | } | 2380 | } |
diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs index ba8682cee..1691129f6 100644 --- a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs +++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs | |||
| @@ -20,8 +20,6 @@ | |||
| 20 | #![no_std] | 20 | #![no_std] |
| 21 | #![no_main] | 21 | #![no_main] |
| 22 | 22 | ||
| 23 | use core::fmt::Write as _; | ||
| 24 | |||
| 25 | use embassy_executor::Spawner; | 23 | use embassy_executor::Spawner; |
| 26 | use embassy_mcxa::clocks::config::Div8; | 24 | use embassy_mcxa::clocks::config::Div8; |
| 27 | use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder}; | 25 | use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder}; |
| @@ -97,28 +95,14 @@ async fn main(_spawner: Spawner) { | |||
| 97 | defmt::info!("Added 3 transfer segments to chain."); | 95 | defmt::info!("Added 3 transfer segments to chain."); |
| 98 | defmt::info!("Starting scatter-gather transfer with .await..."); | 96 | defmt::info!("Starting scatter-gather transfer with .await..."); |
| 99 | 97 | ||
| 100 | // TODO START | ||
| 101 | defmt::info!("Destination buffers (after):"); | ||
| 102 | defmt::info!(" DST1: {=[?]}", dst1.as_slice()); | ||
| 103 | defmt::info!(" DST2: {=[?]}", dst2.as_slice()); | ||
| 104 | defmt::info!(" DST3: {=[?]}", dst3.as_slice()); | ||
| 105 | // TODO: If we want to make the `builder.build()` below safe, the above prints SHOULD NOT | ||
| 106 | // compile. We need to make sure that the lifetime of the builder reflects that it is | ||
| 107 | // "consuming" the slices until the builder is dropped, since we can access them to print here, | ||
| 108 | // that means that the borrow checker isn't enforcing that yet. | ||
| 109 | todo!("ABOVE CODE SHOULDN'T COMPILE"); | ||
| 110 | // TODO END | ||
| 111 | |||
| 112 | // Build and execute the scatter-gather chain | 98 | // Build and execute the scatter-gather chain |
| 113 | // The build() method: | 99 | // The build() method: |
| 114 | // - Links all TCDs together with ESG bit | 100 | // - Links all TCDs together with ESG bit |
| 115 | // - Sets INTMAJOR on all TCDs | 101 | // - Sets INTMAJOR on all TCDs |
| 116 | // - Loads the first TCD into hardware | 102 | // - Loads the first TCD into hardware |
| 117 | // - Returns a Transfer future | 103 | // - Returns a Transfer future |
| 118 | unsafe { | 104 | let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather"); |
| 119 | let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather"); | 105 | transfer.blocking_wait(); |
| 120 | transfer.blocking_wait(); | ||
| 121 | } | ||
| 122 | 106 | ||
| 123 | defmt::info!("Scatter-gather transfer complete!"); | 107 | defmt::info!("Scatter-gather transfer complete!"); |
| 124 | 108 | ||
