aboutsummaryrefslogtreecommitdiff
path: root/examples/mcxa/src/bin/dma_scatter_gather_builder.rs
blob: 30ce20c9686154b71ae021f6f2374b88dffaf794 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! DMA Scatter-Gather Builder example for MCXA276.
//!
//! This example demonstrates using the new `ScatterGatherBuilder` API for
//! chaining multiple DMA transfers with a type-safe builder pattern.
//!
//! # Features demonstrated:
//! - `ScatterGatherBuilder::new()` for creating a builder
//! - `add_transfer()` for adding memory-to-memory segments
//! - `build()` to start the chained transfer
//! - Automatic TCD linking and ESG bit management
//!
//! # Comparison with manual scatter-gather:
//! The manual approach (see `dma_scatter_gather.rs`) requires:
//! - Manual TCD pool allocation and alignment
//! - Manual CSR/ESG/INTMAJOR bit manipulation
//! - Manual dlast_sga address calculations
//!
//! The builder approach handles all of this automatically!

#![no_std]
#![no_main]

use embassy_executor::Spawner;
use embassy_mcxa::clocks::config::Div8;
use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder};
use static_cell::ConstStaticCell;
use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};

// Source buffers (multiple segments)
static SRC1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0x11111111, 0x22222222, 0x33333333, 0x44444444]);
static SRC2: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD]);
static SRC3: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]);

// Destination buffers (one per segment)
static DST1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
static DST2: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
static DST3: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    // Small delay to allow probe-rs to attach after reset
    for _ in 0..100_000 {
        cortex_m::asm::nop();
    }

    let mut cfg = hal::config::Config::default();
    cfg.clock_cfg.sirc.fro_12m_enabled = true;
    cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
    let p = hal::init(cfg);

    defmt::info!("DMA Scatter-Gather Builder example starting...");

    defmt::info!("DMA Scatter-Gather Builder Example");
    defmt::info!("===================================");
    let src1 = SRC1.take();
    let src2 = SRC2.take();
    let src3 = SRC3.take();
    let dst1 = DST1.take();
    let dst2 = DST2.take();
    let dst3 = DST3.take();

    // Show source buffers
    defmt::info!("Source buffers:");
    defmt::info!("  SRC1: {=[?]}", src1.as_slice());
    defmt::info!("  SRC2: {=[?]}", src2.as_slice());
    defmt::info!("  SRC3: {=[?]}", src3.as_slice());

    defmt::info!("Destination buffers (before):");
    defmt::info!("  DST1: {=[?]}", dst1.as_slice());
    defmt::info!("  DST2: {=[?]}", dst2.as_slice());
    defmt::info!("  DST3: {=[?]}", dst3.as_slice());

    // Create DMA channel
    let dma_ch0 = DmaChannel::new(p.DMA_CH0);

    defmt::info!("Building scatter-gather chain with builder API...");

    // =========================================================================
    // ScatterGatherBuilder API demonstration
    // =========================================================================
    //
    // The builder pattern makes scatter-gather transfers much easier:
    // 1. Create a builder
    // 2. Add transfer segments with add_transfer()
    // 3. Call build() to start the entire chain
    // No manual TCD manipulation required!

    let mut builder = ScatterGatherBuilder::<u32>::new();

    // Add three transfer segments - the builder handles TCD linking automatically
    builder.add_transfer(src1, dst1);
    builder.add_transfer(src2, dst2);
    builder.add_transfer(src3, dst3);

    defmt::info!("Added 3 transfer segments to chain.");
    defmt::info!("Starting scatter-gather transfer with .await...");

    // Build and execute the scatter-gather chain
    // The build() method:
    // - Links all TCDs together with ESG bit
    // - Sets INTMAJOR on all TCDs
    // - Loads the first TCD into hardware
    // - Returns a Transfer future
    let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather");
    transfer.blocking_wait();

    defmt::info!("Scatter-gather transfer complete!");

    // Show results
    defmt::info!("Destination buffers (after):");
    defmt::info!("  DST1: {=[?]}", dst1.as_slice());
    defmt::info!("  DST2: {=[?]}", dst2.as_slice());
    defmt::info!("  DST3: {=[?]}", dst3.as_slice());

    let comps = [(src1, dst1), (src2, dst2), (src3, dst3)];

    // Verify all three segments
    let mut all_ok = true;
    for (src, dst) in comps {
        all_ok &= src == dst;
    }

    if all_ok {
        defmt::info!("PASS: All segments verified!");
    } else {
        defmt::error!("FAIL: Mismatch detected!");
    }

    defmt::info!("=== Scatter-Gather Builder example complete ===");
}