diff options
Diffstat (limited to 'examples/mcxa/src/bin/dma_scatter_gather_builder.rs')
| -rw-r--r-- | examples/mcxa/src/bin/dma_scatter_gather_builder.rs | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs new file mode 100644 index 000000000..30ce20c96 --- /dev/null +++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | //! DMA Scatter-Gather Builder example for MCXA276. | ||
| 2 | //! | ||
| 3 | //! This example demonstrates using the new `ScatterGatherBuilder` API for | ||
| 4 | //! chaining multiple DMA transfers with a type-safe builder pattern. | ||
| 5 | //! | ||
| 6 | //! # Features demonstrated: | ||
| 7 | //! - `ScatterGatherBuilder::new()` for creating a builder | ||
| 8 | //! - `add_transfer()` for adding memory-to-memory segments | ||
| 9 | //! - `build()` to start the chained transfer | ||
| 10 | //! - Automatic TCD linking and ESG bit management | ||
| 11 | //! | ||
| 12 | //! # Comparison with manual scatter-gather: | ||
| 13 | //! The manual approach (see `dma_scatter_gather.rs`) requires: | ||
| 14 | //! - Manual TCD pool allocation and alignment | ||
| 15 | //! - Manual CSR/ESG/INTMAJOR bit manipulation | ||
| 16 | //! - Manual dlast_sga address calculations | ||
| 17 | //! | ||
| 18 | //! The builder approach handles all of this automatically! | ||
| 19 | |||
| 20 | #![no_std] | ||
| 21 | #![no_main] | ||
| 22 | |||
| 23 | use embassy_executor::Spawner; | ||
| 24 | use embassy_mcxa::clocks::config::Div8; | ||
| 25 | use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder}; | ||
| 26 | use static_cell::ConstStaticCell; | ||
| 27 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | ||
| 28 | |||
| 29 | // Source buffers (multiple segments) | ||
| 30 | static SRC1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0x11111111, 0x22222222, 0x33333333, 0x44444444]); | ||
| 31 | static SRC2: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD]); | ||
| 32 | static SRC3: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]); | ||
| 33 | |||
| 34 | // Destination buffers (one per segment) | ||
| 35 | static DST1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]); | ||
| 36 | static DST2: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]); | ||
| 37 | static DST3: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]); | ||
| 38 | |||
| 39 | #[embassy_executor::main] | ||
| 40 | async fn main(_spawner: Spawner) { | ||
| 41 | // Small delay to allow probe-rs to attach after reset | ||
| 42 | for _ in 0..100_000 { | ||
| 43 | cortex_m::asm::nop(); | ||
| 44 | } | ||
| 45 | |||
| 46 | let mut cfg = hal::config::Config::default(); | ||
| 47 | cfg.clock_cfg.sirc.fro_12m_enabled = true; | ||
| 48 | cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div()); | ||
| 49 | let p = hal::init(cfg); | ||
| 50 | |||
| 51 | defmt::info!("DMA Scatter-Gather Builder example starting..."); | ||
| 52 | |||
| 53 | defmt::info!("DMA Scatter-Gather Builder Example"); | ||
| 54 | defmt::info!("==================================="); | ||
| 55 | let src1 = SRC1.take(); | ||
| 56 | let src2 = SRC2.take(); | ||
| 57 | let src3 = SRC3.take(); | ||
| 58 | let dst1 = DST1.take(); | ||
| 59 | let dst2 = DST2.take(); | ||
| 60 | let dst3 = DST3.take(); | ||
| 61 | |||
| 62 | // Show source buffers | ||
| 63 | defmt::info!("Source buffers:"); | ||
| 64 | defmt::info!(" SRC1: {=[?]}", src1.as_slice()); | ||
| 65 | defmt::info!(" SRC2: {=[?]}", src2.as_slice()); | ||
| 66 | defmt::info!(" SRC3: {=[?]}", src3.as_slice()); | ||
| 67 | |||
| 68 | defmt::info!("Destination buffers (before):"); | ||
| 69 | defmt::info!(" DST1: {=[?]}", dst1.as_slice()); | ||
| 70 | defmt::info!(" DST2: {=[?]}", dst2.as_slice()); | ||
| 71 | defmt::info!(" DST3: {=[?]}", dst3.as_slice()); | ||
| 72 | |||
| 73 | // Create DMA channel | ||
| 74 | let dma_ch0 = DmaChannel::new(p.DMA_CH0); | ||
| 75 | |||
| 76 | defmt::info!("Building scatter-gather chain with builder API..."); | ||
| 77 | |||
| 78 | // ========================================================================= | ||
| 79 | // ScatterGatherBuilder API demonstration | ||
| 80 | // ========================================================================= | ||
| 81 | // | ||
| 82 | // The builder pattern makes scatter-gather transfers much easier: | ||
| 83 | // 1. Create a builder | ||
| 84 | // 2. Add transfer segments with add_transfer() | ||
| 85 | // 3. Call build() to start the entire chain | ||
| 86 | // No manual TCD manipulation required! | ||
| 87 | |||
| 88 | let mut builder = ScatterGatherBuilder::<u32>::new(); | ||
| 89 | |||
| 90 | // Add three transfer segments - the builder handles TCD linking automatically | ||
| 91 | builder.add_transfer(src1, dst1); | ||
| 92 | builder.add_transfer(src2, dst2); | ||
| 93 | builder.add_transfer(src3, dst3); | ||
| 94 | |||
| 95 | defmt::info!("Added 3 transfer segments to chain."); | ||
| 96 | defmt::info!("Starting scatter-gather transfer with .await..."); | ||
| 97 | |||
| 98 | // Build and execute the scatter-gather chain | ||
| 99 | // The build() method: | ||
| 100 | // - Links all TCDs together with ESG bit | ||
| 101 | // - Sets INTMAJOR on all TCDs | ||
| 102 | // - Loads the first TCD into hardware | ||
| 103 | // - Returns a Transfer future | ||
| 104 | let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather"); | ||
| 105 | transfer.blocking_wait(); | ||
| 106 | |||
| 107 | defmt::info!("Scatter-gather transfer complete!"); | ||
| 108 | |||
| 109 | // Show results | ||
| 110 | defmt::info!("Destination buffers (after):"); | ||
| 111 | defmt::info!(" DST1: {=[?]}", dst1.as_slice()); | ||
| 112 | defmt::info!(" DST2: {=[?]}", dst2.as_slice()); | ||
| 113 | defmt::info!(" DST3: {=[?]}", dst3.as_slice()); | ||
| 114 | |||
| 115 | let comps = [(src1, dst1), (src2, dst2), (src3, dst3)]; | ||
| 116 | |||
| 117 | // Verify all three segments | ||
| 118 | let mut all_ok = true; | ||
| 119 | for (src, dst) in comps { | ||
| 120 | all_ok &= src == dst; | ||
| 121 | } | ||
| 122 | |||
| 123 | if all_ok { | ||
| 124 | defmt::info!("PASS: All segments verified!"); | ||
| 125 | } else { | ||
| 126 | defmt::error!("FAIL: Mismatch detected!"); | ||
| 127 | } | ||
| 128 | |||
| 129 | defmt::info!("=== Scatter-Gather Builder example complete ==="); | ||
| 130 | } | ||
