aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-12-09 14:41:19 +0100
committerJames Munns <[email protected]>2025-12-09 14:41:19 +0100
commit4386b39e2516c453966d894b4fd265fae9d82c1a (patch)
tree455eec4232f060ee1906b479cc3ba3567f02c773
parentf7d5abfe946e71d426c9d0e96231e48faf27f6cd (diff)
Enforce scatter gather API statically
-rw-r--r--embassy-mcxa/src/dma.rs19
-rw-r--r--examples/mcxa/src/bin/dma_scatter_gather_builder.rs20
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
2239impl<W: Word> ScatterGatherBuilder<'_, W> { 2239impl<'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
2380impl<W: Word> Default for ScatterGatherBuilder<W> { 2377impl<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
23use core::fmt::Write as _;
24
25use embassy_executor::Spawner; 23use embassy_executor::Spawner;
26use embassy_mcxa::clocks::config::Div8; 24use embassy_mcxa::clocks::config::Div8;
27use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder}; 25use 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