aboutsummaryrefslogtreecommitdiff
path: root/examples/mcxa/src/bin
diff options
context:
space:
mode:
Diffstat (limited to 'examples/mcxa/src/bin')
-rw-r--r--examples/mcxa/src/bin/adc_interrupt.rs65
-rw-r--r--examples/mcxa/src/bin/adc_polling.rs78
-rw-r--r--examples/mcxa/src/bin/blinky.rs36
-rw-r--r--examples/mcxa/src/bin/button.rs23
-rw-r--r--examples/mcxa/src/bin/button_async.rs29
-rw-r--r--examples/mcxa/src/bin/clkout.rs68
-rw-r--r--examples/mcxa/src/bin/crc.rs154
-rw-r--r--examples/mcxa/src/bin/dma_mem_to_mem.rs118
-rw-r--r--examples/mcxa/src/bin/dma_scatter_gather_builder.rs130
-rw-r--r--examples/mcxa/src/bin/dma_wrap_transfer.rs184
-rw-r--r--examples/mcxa/src/bin/hello.rs119
-rw-r--r--examples/mcxa/src/bin/i2c-async.rs39
-rw-r--r--examples/mcxa/src/bin/i2c-blocking.rs31
-rw-r--r--examples/mcxa/src/bin/i2c-scan-blocking.rs40
-rw-r--r--examples/mcxa/src/bin/lpuart_buffered.rs62
-rw-r--r--examples/mcxa/src/bin/lpuart_dma.rs68
-rw-r--r--examples/mcxa/src/bin/lpuart_polling.rs47
-rw-r--r--examples/mcxa/src/bin/lpuart_ring_buffer.rs115
-rw-r--r--examples/mcxa/src/bin/raw_dma_channel_link.rs278
-rw-r--r--examples/mcxa/src/bin/raw_dma_interleave_transfer.rs141
-rw-r--r--examples/mcxa/src/bin/raw_dma_memset.rs129
-rw-r--r--examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs244
-rw-r--r--examples/mcxa/src/bin/raw_dma_scatter_gather.rs165
-rw-r--r--examples/mcxa/src/bin/reset-reason.rs15
-rw-r--r--examples/mcxa/src/bin/rtc_alarm.rs47
-rw-r--r--examples/mcxa/src/bin/trng.rs106
26 files changed, 2531 insertions, 0 deletions
diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs
new file mode 100644
index 000000000..d2cda631c
--- /dev/null
+++ b/examples/mcxa/src/bin/adc_interrupt.rs
@@ -0,0 +1,65 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::{Duration, Ticker};
6use hal::adc::{Adc, InterruptHandler, LpadcConfig, TriggerPriorityPolicy};
7use hal::bind_interrupts;
8use hal::clocks::PoweredClock;
9use hal::clocks::config::Div8;
10use hal::clocks::periph_helpers::{AdcClockSel, Div4};
11use hal::config::Config;
12use hal::pac::adc1::cfg::{Pwrsel, Refsel};
13use hal::pac::adc1::cmdl1::Mode;
14use hal::pac::adc1::ctrl::CalAvgs;
15use hal::peripherals::ADC1;
16use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 ADC1 => InterruptHandler<ADC1>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let mut config = Config::default();
25 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
26
27 let p = hal::init(config);
28
29 defmt::info!("ADC interrupt Example");
30
31 let adc_config = LpadcConfig {
32 enable_in_doze_mode: true,
33 conversion_average_mode: CalAvgs::Average128,
34 enable_analog_preliminary: true,
35 power_up_delay: 0x80,
36 reference_voltage_source: Refsel::Option3,
37 power_level_mode: Pwrsel::Lowest,
38 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
39 enable_conv_pause: false,
40 conv_pause_delay: 0,
41 power: PoweredClock::NormalEnabledDeepSleepDisabled,
42 source: AdcClockSel::FroLfDiv,
43 div: Div4::no_div(),
44 };
45 let mut adc = Adc::new_async(p.ADC1, p.P1_10, Irqs, adc_config).unwrap();
46
47 adc.do_offset_calibration();
48 adc.do_auto_calibration();
49 adc.set_resolution(Mode::Data16Bits);
50
51 defmt::info!("ADC configuration done...");
52 let mut ticker = Ticker::every(Duration::from_millis(100));
53
54 loop {
55 ticker.next().await;
56 match adc.read().await {
57 Ok(value) => {
58 defmt::info!("ADC value: {}", value);
59 }
60 Err(e) => {
61 defmt::error!("ADC read error: {:?}", e);
62 }
63 }
64 }
65}
diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs
new file mode 100644
index 000000000..5c4d5524c
--- /dev/null
+++ b/examples/mcxa/src/bin/adc_polling.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::adc::{ConvCommandConfig, ConvTriggerConfig};
6use embassy_time::{Duration, Ticker};
7use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy};
8use hal::clocks::PoweredClock;
9use hal::clocks::config::Div8;
10use hal::clocks::periph_helpers::{AdcClockSel, Div4};
11use hal::config::Config;
12use hal::pac::adc1::cfg::{Pwrsel, Refsel};
13use hal::pac::adc1::cmdl1::Mode;
14use hal::pac::adc1::ctrl::CalAvgs;
15use hal::pac::adc1::tctrl::Tcmd;
16use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
17
18const G_LPADC_RESULT_SHIFT: u32 = 0;
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let mut config = Config::default();
23 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
24
25 let p = hal::init(config);
26
27 defmt::info!("=== ADC polling Example ===");
28
29 let adc_config = LpadcConfig {
30 enable_in_doze_mode: true,
31 conversion_average_mode: CalAvgs::Average128,
32 enable_analog_preliminary: true,
33 power_up_delay: 0x80,
34 reference_voltage_source: Refsel::Option3,
35 power_level_mode: Pwrsel::Lowest,
36 trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed,
37 enable_conv_pause: false,
38 conv_pause_delay: 0,
39 power: PoweredClock::NormalEnabledDeepSleepDisabled,
40 source: AdcClockSel::FroLfDiv,
41 div: Div4::no_div(),
42 };
43 let adc = Adc::new_blocking(p.ADC1, p.P1_10, adc_config).unwrap();
44
45 adc.do_offset_calibration();
46 adc.do_auto_calibration();
47
48 let conv_command_config = ConvCommandConfig {
49 conversion_resolution_mode: Mode::Data16Bits,
50 ..ConvCommandConfig::default()
51 };
52 adc.set_conv_command_config(1, &conv_command_config).unwrap();
53
54 let conv_trigger_config = ConvTriggerConfig {
55 target_command_id: Tcmd::ExecuteCmd1,
56 enable_hardware_trigger: false,
57 ..Default::default()
58 };
59 adc.set_conv_trigger_config(0, &conv_trigger_config).unwrap();
60
61 defmt::info!("=== ADC configuration done... ===");
62 let mut tick = Ticker::every(Duration::from_millis(100));
63
64 loop {
65 tick.next().await;
66 adc.do_software_trigger(1).unwrap();
67 let result = loop {
68 match adc.get_conv_result() {
69 Ok(res) => break res,
70 Err(_) => {
71 // Conversion not ready, continue polling
72 }
73 }
74 };
75 let value = result.conv_value >> G_LPADC_RESULT_SHIFT;
76 defmt::info!("ADC value: {=u16}", value);
77 }
78}
diff --git a/examples/mcxa/src/bin/blinky.rs b/examples/mcxa/src/bin/blinky.rs
new file mode 100644
index 000000000..dd08ec0d9
--- /dev/null
+++ b/examples/mcxa/src/bin/blinky.rs
@@ -0,0 +1,36 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::gpio::{DriveStrength, Level, Output, SlewRate};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = hal::init(hal::config::Config::default());
12
13 defmt::info!("Blink example");
14
15 let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast);
16 let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast);
17 let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast);
18
19 loop {
20 defmt::info!("Toggle LEDs");
21
22 red.toggle();
23 Timer::after_millis(250).await;
24
25 red.toggle();
26 green.toggle();
27 Timer::after_millis(250).await;
28
29 green.toggle();
30 blue.toggle();
31 Timer::after_millis(250).await;
32 blue.toggle();
33
34 Timer::after_millis(250).await;
35 }
36}
diff --git a/examples/mcxa/src/bin/button.rs b/examples/mcxa/src/bin/button.rs
new file mode 100644
index 000000000..943edbb15
--- /dev/null
+++ b/examples/mcxa/src/bin/button.rs
@@ -0,0 +1,23 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::gpio::{Input, Pull};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = hal::init(hal::config::Config::default());
12
13 defmt::info!("Button example");
14
15 // This button is labeled "WAKEUP" on the FRDM-MCXA276
16 // The board already has a 10K pullup
17 let monitor = Input::new(p.P1_7, Pull::Disabled);
18
19 loop {
20 defmt::info!("Pin level is {:?}", monitor.get_level());
21 Timer::after_millis(1000).await;
22 }
23}
diff --git a/examples/mcxa/src/bin/button_async.rs b/examples/mcxa/src/bin/button_async.rs
new file mode 100644
index 000000000..6cc7b62cd
--- /dev/null
+++ b/examples/mcxa/src/bin/button_async.rs
@@ -0,0 +1,29 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::gpio::{Input, Pull};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let p = hal::init(hal::config::Config::default());
12
13 defmt::info!("GPIO interrupt example");
14
15 // This button is labeled "WAKEUP" on the FRDM-MCXA276
16 // The board already has a 10K pullup
17 let mut pin = Input::new(p.P1_7, Pull::Disabled);
18
19 let mut press_count = 0u32;
20
21 loop {
22 pin.wait_for_falling_edge().await;
23
24 press_count += 1;
25
26 defmt::info!("Button pressed! Count: {}", press_count);
27 Timer::after_millis(50).await;
28 }
29}
diff --git a/examples/mcxa/src/bin/clkout.rs b/examples/mcxa/src/bin/clkout.rs
new file mode 100644
index 000000000..1e52912d3
--- /dev/null
+++ b/examples/mcxa/src/bin/clkout.rs
@@ -0,0 +1,68 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4};
6use embassy_mcxa::clocks::PoweredClock;
7use embassy_mcxa::gpio::{DriveStrength, Level, Output, SlewRate};
8use embassy_time::Timer;
9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
10
11/// Demonstrate CLKOUT, using Pin P4.2
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = hal::init(hal::config::Config::default());
15 let mut pin = p.P4_2;
16 let mut clkout = p.CLKOUT;
17
18 loop {
19 defmt::info!("Set Low...");
20 let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow);
21 Timer::after_millis(500).await;
22
23 defmt::info!("Set High...");
24 output.set_high();
25 Timer::after_millis(400).await;
26
27 defmt::info!("Set Low...");
28 output.set_low();
29 Timer::after_millis(500).await;
30
31 defmt::info!("16k...");
32 // Run Clock Out with the 16K clock
33 let _clock_out = ClockOut::new(
34 clkout.reborrow(),
35 pin.reborrow(),
36 Config {
37 sel: ClockOutSel::Clk16K,
38 div: Div4::no_div(),
39 level: PoweredClock::NormalEnabledDeepSleepDisabled,
40 },
41 )
42 .unwrap();
43
44 Timer::after_millis(3000).await;
45
46 defmt::info!("Set Low...");
47 drop(_clock_out);
48
49 let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow);
50 Timer::after_millis(500).await;
51
52 // Run Clock Out with the 12M clock, divided by 3
53 defmt::info!("4M...");
54 let _clock_out = ClockOut::new(
55 clkout.reborrow(),
56 pin.reborrow(),
57 Config {
58 sel: ClockOutSel::Fro12M,
59 div: const { Div4::from_divisor(3).unwrap() },
60 level: PoweredClock::NormalEnabledDeepSleepDisabled,
61 },
62 )
63 .unwrap();
64
65 // Let it run for 3 seconds...
66 Timer::after_millis(3000).await;
67 }
68}
diff --git a/examples/mcxa/src/bin/crc.rs b/examples/mcxa/src/bin/crc.rs
new file mode 100644
index 000000000..0125e625c
--- /dev/null
+++ b/examples/mcxa/src/bin/crc.rs
@@ -0,0 +1,154 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use hal::config::Config;
6use hal::crc::Crc;
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9const CCITT_FALSE: crc::Algorithm<u16> = crc::Algorithm {
10 width: 16,
11 poly: 0x1021,
12 init: 0xffff,
13 refin: false,
14 refout: false,
15 xorout: 0,
16 check: 0x29b1,
17 residue: 0x0000,
18};
19
20const POSIX: crc::Algorithm<u32> = crc::Algorithm {
21 width: 32,
22 poly: 0x04c1_1db7,
23 init: 0,
24 refin: false,
25 refout: false,
26 xorout: 0xffff_ffff,
27 check: 0x765e_7680,
28 residue: 0x0000,
29};
30
31#[embassy_executor::main]
32async fn main(_spawner: Spawner) {
33 let config = Config::default();
34 let mut p = hal::init(config);
35
36 defmt::info!("CRC example");
37
38 let buf_u8 = [0x00u8, 0x11, 0x22, 0x33];
39 let buf_u16 = [0x0000u16, 0x1111, 0x2222, 0x3333];
40 let buf_u32 = [0x0000_0000u32, 0x1111_1111, 0x2222_2222, 0x3333_3333];
41
42 // CCITT False
43
44 let sw_crc = crc::Crc::<u16>::new(&CCITT_FALSE);
45 let mut digest = sw_crc.digest();
46 digest.update(&buf_u8);
47 let sw_sum = digest.finalize();
48
49 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow());
50 crc.feed(&buf_u8);
51 let sum = crc.finalize();
52 assert_eq!(sum, sw_sum);
53
54 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow());
55 crc.feed(&buf_u16);
56 let sum = crc.finalize();
57 assert_eq!(sum, 0xa467);
58
59 let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow());
60 crc.feed(&buf_u32);
61 let sum = crc.finalize();
62 assert_eq!(sum, 0xe5c7);
63
64 // Maxim
65
66 let sw_crc = crc::Crc::<u16>::new(&crc::CRC_16_MAXIM_DOW);
67 let mut digest = sw_crc.digest();
68 digest.update(&buf_u8);
69 let sw_sum = digest.finalize();
70
71 let mut crc = Crc::new_maxim(p.CRC0.reborrow());
72 crc.feed(&buf_u8);
73 let sum = crc.finalize();
74 assert_eq!(sum, sw_sum);
75
76 let mut crc = Crc::new_maxim(p.CRC0.reborrow());
77 crc.feed(&buf_u16);
78 let sum = crc.finalize();
79 assert_eq!(sum, 0x2afe);
80
81 let mut crc = Crc::new_maxim(p.CRC0.reborrow());
82 crc.feed(&buf_u32);
83 let sum = crc.finalize();
84 assert_eq!(sum, 0x17d7);
85
86 // Kermit
87
88 let sw_crc = crc::Crc::<u16>::new(&crc::CRC_16_KERMIT);
89 let mut digest = sw_crc.digest();
90 digest.update(&buf_u8);
91 let sw_sum = digest.finalize();
92
93 let mut crc = Crc::new_kermit(p.CRC0.reborrow());
94 crc.feed(&buf_u8);
95 let sum = crc.finalize();
96 assert_eq!(sum, sw_sum);
97
98 let mut crc = Crc::new_kermit(p.CRC0.reborrow());
99 crc.feed(&buf_u16);
100 let sum = crc.finalize();
101 assert_eq!(sum, 0x66eb);
102
103 let mut crc = Crc::new_kermit(p.CRC0.reborrow());
104 crc.feed(&buf_u32);
105 let sum = crc.finalize();
106 assert_eq!(sum, 0x75ea);
107
108 // ISO HDLC
109
110 let sw_crc = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);
111 let mut digest = sw_crc.digest();
112 digest.update(&buf_u8);
113 let sw_sum = digest.finalize();
114
115 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow());
116 crc.feed(&buf_u8);
117 let sum = crc.finalize();
118 assert_eq!(sum, sw_sum);
119
120 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow());
121 crc.feed(&buf_u16);
122 let sum = crc.finalize();
123 assert_eq!(sum, 0x8a61_4178);
124
125 let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow());
126 crc.feed(&buf_u32);
127 let sum = crc.finalize();
128 assert_eq!(sum, 0xfab5_d04e);
129
130 // POSIX
131
132 let sw_crc = crc::Crc::<u32>::new(&POSIX);
133 let mut digest = sw_crc.digest();
134 digest.update(&buf_u8);
135 let sw_sum = digest.finalize();
136
137 let mut crc = Crc::new_posix(p.CRC0.reborrow());
138 crc.feed(&buf_u8);
139 let sum = crc.finalize();
140
141 assert_eq!(sum, sw_sum);
142
143 let mut crc = Crc::new_posix(p.CRC0.reborrow());
144 crc.feed(&buf_u16);
145 let sum = crc.finalize();
146 assert_eq!(sum, 0x6d76_4f58);
147
148 let mut crc = Crc::new_posix(p.CRC0.reborrow());
149 crc.feed(&buf_u32);
150 let sum = crc.finalize();
151 assert_eq!(sum, 0x2a5b_cb90);
152
153 defmt::info!("CRC successful");
154}
diff --git a/examples/mcxa/src/bin/dma_mem_to_mem.rs b/examples/mcxa/src/bin/dma_mem_to_mem.rs
new file mode 100644
index 000000000..b38baccb5
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_mem_to_mem.rs
@@ -0,0 +1,118 @@
1//! DMA memory-to-memory transfer example for MCXA276.
2//!
3//! This example demonstrates using DMA to copy data between memory buffers
4//! using the Embassy-style async API with type-safe transfers.
5//!
6//! # Embassy-style features demonstrated:
7//! - `TransferOptions` for configuration
8//! - Type-safe `mem_to_mem<u32>()` method with async `.await`
9//! - `Transfer` Future that can be `.await`ed
10//! - `Word` trait for automatic transfer width detection
11//! - `memset()` method for filling memory with a pattern
12
13#![no_std]
14#![no_main]
15
16use embassy_executor::Spawner;
17use embassy_mcxa::clocks::config::Div8;
18use embassy_mcxa::dma::{DmaChannel, TransferOptions};
19use static_cell::ConstStaticCell;
20use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
21
22const BUFFER_LENGTH: usize = 4;
23
24// Buffers in RAM (static mut is automatically placed in .bss/.data)
25static SRC_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([1, 2, 3, 4]);
26static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]);
27static MEMSET_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]);
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 // Small delay to allow probe-rs to attach after reset
32 for _ in 0..100_000 {
33 cortex_m::asm::nop();
34 }
35
36 let mut cfg = hal::config::Config::default();
37 cfg.clock_cfg.sirc.fro_12m_enabled = true;
38 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
39 let p = hal::init(cfg);
40
41 defmt::info!("DMA memory-to-memory example starting...");
42
43 defmt::info!("EDMA memory to memory example begin.");
44
45 let src = SRC_BUFFER.take();
46 let dst = DEST_BUFFER.take();
47 let mst = MEMSET_BUFFER.take();
48
49 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
50 defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());
51 defmt::info!("Configuring DMA with Embassy-style API...");
52
53 // Create DMA channel
54 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
55
56 // Configure transfer options (Embassy-style)
57 // TransferOptions defaults to: complete_transfer_interrupt = true
58 let options = TransferOptions::default();
59
60 // =========================================================================
61 // Part 1: Embassy-style async API demonstration (mem_to_mem)
62 // =========================================================================
63 //
64 // Use the new type-safe `mem_to_mem<u32>()` method:
65 // - Automatically determines transfer width from buffer element type (u32)
66 // - Returns a `Transfer` future that can be `.await`ed
67 // - Uses TransferOptions for consistent configuration
68 //
69 // Using async `.await` - the executor can run other tasks while waiting!
70
71 // Perform type-safe memory-to-memory transfer using Embassy-style async API
72 // Using async `.await` - the executor can run other tasks while waiting!
73 let transfer = dma_ch0.mem_to_mem(src, dst, options).unwrap();
74 transfer.await.unwrap();
75
76 defmt::info!("DMA mem-to-mem transfer complete!");
77 defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());
78
79 // Verify data
80 if src != dst {
81 defmt::error!("FAIL: mem_to_mem mismatch!");
82 } else {
83 defmt::info!("PASS: mem_to_mem verified.");
84 }
85
86 // =========================================================================
87 // Part 2: memset() demonstration
88 // =========================================================================
89 //
90 // The `memset()` method fills a buffer with a pattern value:
91 // - Fixed source address (pattern is read repeatedly)
92 // - Incrementing destination address
93 // - Uses the same Transfer future pattern
94
95 defmt::info!("--- Demonstrating memset() feature ---");
96
97 defmt::info!("Memset Buffer (before): {=[?]}", mst.as_slice());
98
99 // Fill buffer with a pattern value using DMA memset
100 let pattern: u32 = 0xDEADBEEF;
101 defmt::info!("Filling with pattern 0xDEADBEEF...");
102
103 // Using blocking_wait() for demonstration - also shows non-async usage
104 let transfer = dma_ch0.memset(&pattern, mst, options);
105 transfer.blocking_wait();
106
107 defmt::info!("DMA memset complete!");
108 defmt::info!("Memset Buffer (after): {=[?]}", mst.as_slice());
109
110 // Verify memset result
111 if !mst.iter().all(|&v| v == pattern) {
112 defmt::error!("FAIL: memset mismatch!");
113 } else {
114 defmt::info!("PASS: memset verified.");
115 }
116
117 defmt::info!("=== All DMA tests complete ===");
118}
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
23use embassy_executor::Spawner;
24use embassy_mcxa::clocks::config::Div8;
25use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder};
26use static_cell::ConstStaticCell;
27use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
28
29// Source buffers (multiple segments)
30static SRC1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0x11111111, 0x22222222, 0x33333333, 0x44444444]);
31static SRC2: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD]);
32static SRC3: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]);
33
34// Destination buffers (one per segment)
35static DST1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
36static DST2: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
37static DST3: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
38
39#[embassy_executor::main]
40async 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}
diff --git a/examples/mcxa/src/bin/dma_wrap_transfer.rs b/examples/mcxa/src/bin/dma_wrap_transfer.rs
new file mode 100644
index 000000000..acfd29f08
--- /dev/null
+++ b/examples/mcxa/src/bin/dma_wrap_transfer.rs
@@ -0,0 +1,184 @@
1//! DMA wrap transfer example for MCXA276.
2//!
3//! This example demonstrates using DMA with modulo addressing to wrap around
4//! a source buffer, effectively repeating the source data in the destination.
5//!
6//! # Embassy-style features demonstrated:
7//! - `DmaChannel::is_done()` and `clear_done()` helper methods
8//! - No need to pass register block around
9
10#![no_std]
11#![no_main]
12
13use core::fmt::Write as _;
14
15use embassy_executor::Spawner;
16use embassy_mcxa::clocks::config::Div8;
17use embassy_mcxa::dma::DmaChannel;
18use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx};
19use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
20
21// Source buffer: 4 words (16 bytes), aligned to 16 bytes for modulo
22#[repr(align(16))]
23struct AlignedSrc([u32; 4]);
24
25static mut SRC: AlignedSrc = AlignedSrc([0; 4]);
26static mut DST: [u32; 8] = [0; 8];
27
28/// Helper to print a buffer to UART
29fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) {
30 write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok();
31}
32
33#[embassy_executor::main]
34async fn main(_spawner: Spawner) {
35 // Small delay to allow probe-rs to attach after reset
36 for _ in 0..100_000 {
37 cortex_m::asm::nop();
38 }
39
40 let mut cfg = hal::config::Config::default();
41 cfg.clock_cfg.sirc.fro_12m_enabled = true;
42 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
43 let p = hal::init(cfg);
44
45 defmt::info!("DMA wrap transfer example starting...");
46
47 let config = Config {
48 baudrate_bps: 115_200,
49 ..Default::default()
50 };
51
52 let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap();
53 let (mut tx, _rx) = lpuart.split();
54
55 tx.blocking_write(b"EDMA wrap transfer example begin.\r\n\r\n").unwrap();
56
57 // Initialize buffers
58 unsafe {
59 SRC.0 = [1, 2, 3, 4];
60 DST = [0; 8];
61 }
62
63 tx.blocking_write(b"Source Buffer: ").unwrap();
64 print_buffer(&mut tx, unsafe { core::ptr::addr_of!(SRC.0) } as *const u32, 4);
65 tx.blocking_write(b"\r\n").unwrap();
66
67 tx.blocking_write(b"Destination Buffer (before): ").unwrap();
68 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
69 tx.blocking_write(b"\r\n").unwrap();
70
71 tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n")
72 .unwrap();
73
74 // Create DMA channel using Embassy-style API
75 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
76
77 // Configure wrap transfer using direct TCD access:
78 // SRC is 16 bytes (4 * u32). We want to transfer 32 bytes (8 * u32).
79 // SRC modulo is 16 bytes (2^4 = 16) - wraps source address.
80 // DST modulo is 0 (disabled).
81 // This causes the source address to wrap around after 16 bytes,
82 // effectively repeating the source data.
83 unsafe {
84 let t = dma_ch0.tcd();
85
86 // Reset channel state
87 t.ch_csr().write(|w| {
88 w.erq()
89 .disable()
90 .earq()
91 .disable()
92 .eei()
93 .no_error()
94 .ebw()
95 .disable()
96 .done()
97 .clear_bit_by_one()
98 });
99 t.ch_es().write(|w| w.bits(0));
100 t.ch_int().write(|w| w.int().clear_bit_by_one());
101
102 // Source/destination addresses
103 t.tcd_saddr()
104 .write(|w| w.saddr().bits(core::ptr::addr_of!(SRC.0) as u32));
105 t.tcd_daddr()
106 .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DST) as u32));
107
108 // Offsets: both increment by 4 bytes
109 t.tcd_soff().write(|w| w.soff().bits(4));
110 t.tcd_doff().write(|w| w.doff().bits(4));
111
112 // Attributes: 32-bit transfers (size = 2)
113 // SMOD = 4 (2^4 = 16 byte modulo for source), DMOD = 0 (disabled)
114 t.tcd_attr().write(|w| {
115 w.ssize()
116 .bits(2)
117 .dsize()
118 .bits(2)
119 .smod()
120 .bits(4) // Source modulo: 2^4 = 16 bytes
121 .dmod()
122 .bits(0) // Dest modulo: disabled
123 });
124
125 // Transfer 32 bytes total in one minor loop
126 let nbytes = 32u32;
127 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
128
129 // Source wraps via modulo, no adjustment needed
130 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0));
131 // Reset dest address after major loop
132 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32));
133
134 // Major loop count = 1
135 t.tcd_biter_elinkno().write(|w| w.biter().bits(1));
136 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
137
138 // Enable interrupt on major loop completion
139 t.tcd_csr().write(|w| w.intmajor().set_bit());
140
141 cortex_m::asm::dsb();
142
143 tx.blocking_write(b"Triggering transfer...\r\n").unwrap();
144 dma_ch0.trigger_start();
145 }
146
147 // Wait for completion using channel helper method
148 while !dma_ch0.is_done() {
149 cortex_m::asm::nop();
150 }
151 unsafe {
152 dma_ch0.clear_done();
153 }
154
155 tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n")
156 .unwrap();
157 tx.blocking_write(b"Destination Buffer (after): ").unwrap();
158 print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8);
159 tx.blocking_write(b"\r\n\r\n").unwrap();
160
161 // Verify: DST should be [1, 2, 3, 4, 1, 2, 3, 4]
162 let expected = [1u32, 2, 3, 4, 1, 2, 3, 4];
163 let mut mismatch = false;
164 unsafe {
165 for i in 0..8 {
166 if DST[i] != expected[i] {
167 mismatch = true;
168 break;
169 }
170 }
171 }
172
173 if mismatch {
174 tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap();
175 defmt::error!("FAIL: Mismatch detected!");
176 } else {
177 tx.blocking_write(b"PASS: Data verified.\r\n").unwrap();
178 defmt::info!("PASS: Data verified.");
179 }
180
181 loop {
182 cortex_m::asm::wfe();
183 }
184}
diff --git a/examples/mcxa/src/bin/hello.rs b/examples/mcxa/src/bin/hello.rs
new file mode 100644
index 000000000..e371d9413
--- /dev/null
+++ b/examples/mcxa/src/bin/hello.rs
@@ -0,0 +1,119 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::clocks::config::Div8;
6use hal::lpuart::{Blocking, Config, Lpuart};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9/// Simple helper to write a byte as hex to UART
10fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) {
11 const HEX_DIGITS: &[u8] = b"0123456789ABCDEF";
12 let _ = uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]);
13 let _ = uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]);
14}
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut cfg = hal::config::Config::default();
19 cfg.clock_cfg.sirc.fro_12m_enabled = true;
20 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
21 let p = hal::init(cfg);
22
23 defmt::info!("boot");
24
25 // Create UART configuration
26 let config = Config {
27 baudrate_bps: 115_200,
28 ..Default::default()
29 };
30
31 // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX
32 let mut uart = Lpuart::new_blocking(
33 p.LPUART2, // Peripheral
34 p.P2_2, // TX pin
35 p.P2_3, // RX pin
36 config,
37 )
38 .unwrap();
39
40 // Print welcome message before any async delays to guarantee early console output
41 uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n");
42 uart.write_str_blocking("Available commands:\r\n");
43 uart.write_str_blocking(" help - Show this help\r\n");
44 uart.write_str_blocking(" echo <text> - Echo back the text\r\n");
45 uart.write_str_blocking(" hex <byte> - Display byte in hex (0-255)\r\n");
46 uart.write_str_blocking("Type a command: ");
47
48 let mut buffer = [0u8; 64];
49 let mut buf_idx = 0;
50
51 loop {
52 // Read a byte from UART
53 let byte = uart.read_byte_blocking();
54
55 // Echo the character back
56 if byte == b'\r' || byte == b'\n' {
57 // Enter pressed - process command
58 uart.write_str_blocking("\r\n");
59
60 if buf_idx > 0 {
61 let command = &buffer[0..buf_idx];
62
63 if command == b"help" {
64 uart.write_str_blocking("Available commands:\r\n");
65 uart.write_str_blocking(" help - Show this help\r\n");
66 uart.write_str_blocking(" echo <text> - Echo back the text\r\n");
67 uart.write_str_blocking(" hex <byte> - Display byte in hex (0-255)\r\n");
68 } else if command.starts_with(b"echo ") && command.len() > 5 {
69 uart.write_str_blocking("Echo: ");
70 uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or(""));
71 uart.write_str_blocking("\r\n");
72 } else if command.starts_with(b"hex ") && command.len() > 4 {
73 // Parse the byte value
74 let num_str = &command[4..];
75 if let Ok(num) = parse_u8(num_str) {
76 uart.write_str_blocking("Hex: 0x");
77 write_hex_byte(&mut uart, num);
78 uart.write_str_blocking("\r\n");
79 } else {
80 uart.write_str_blocking("Invalid number for hex command\r\n");
81 }
82 } else if !command.is_empty() {
83 uart.write_str_blocking("Unknown command: ");
84 uart.write_str_blocking(core::str::from_utf8(command).unwrap_or(""));
85 uart.write_str_blocking("\r\n");
86 }
87 }
88
89 // Reset buffer and prompt
90 buf_idx = 0;
91 uart.write_str_blocking("Type a command: ");
92 } else if byte == 8 || byte == 127 {
93 // Backspace
94 if buf_idx > 0 {
95 buf_idx -= 1;
96 uart.write_str_blocking("\x08 \x08"); // Erase character
97 }
98 } else if buf_idx < buffer.len() - 1 {
99 // Regular character
100 buffer[buf_idx] = byte;
101 buf_idx += 1;
102 let _ = uart.write_byte(byte);
103 }
104 }
105}
106
107/// Simple parser for u8 from ASCII bytes
108fn parse_u8(bytes: &[u8]) -> Result<u8, ()> {
109 let mut result = 0u8;
110 for &b in bytes {
111 if b.is_ascii_digit() {
112 result = result.checked_mul(10).ok_or(())?;
113 result = result.checked_add(b - b'0').ok_or(())?;
114 } else {
115 return Err(());
116 }
117 }
118 Ok(result)
119}
diff --git a/examples/mcxa/src/bin/i2c-async.rs b/examples/mcxa/src/bin/i2c-async.rs
new file mode 100644
index 000000000..edcfd5f22
--- /dev/null
+++ b/examples/mcxa/src/bin/i2c-async.rs
@@ -0,0 +1,39 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::bind_interrupts;
7use hal::clocks::config::Div8;
8use hal::config::Config;
9use hal::i2c::InterruptHandler;
10use hal::i2c::controller::{self, I2c, Speed};
11use hal::peripherals::LPI2C3;
12use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
13
14bind_interrupts!(
15 struct Irqs {
16 LPI2C3 => InterruptHandler<LPI2C3>;
17 }
18);
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let mut config = Config::default();
23 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
24
25 let p = hal::init(config);
26
27 defmt::info!("I2C example");
28
29 let mut config = controller::Config::default();
30 config.speed = Speed::Standard;
31 let mut i2c = I2c::new_async(p.LPI2C3, p.P3_27, p.P3_28, Irqs, config).unwrap();
32 let mut buf = [0u8; 2];
33
34 loop {
35 i2c.async_write_read(0x48, &[0x00], &mut buf).await.unwrap();
36 defmt::info!("Buffer: {:02x}", buf);
37 Timer::after_secs(1).await;
38 }
39}
diff --git a/examples/mcxa/src/bin/i2c-blocking.rs b/examples/mcxa/src/bin/i2c-blocking.rs
new file mode 100644
index 000000000..0f6c8cbae
--- /dev/null
+++ b/examples/mcxa/src/bin/i2c-blocking.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::clocks::config::Div8;
7use hal::config::Config;
8use hal::i2c::controller::{self, I2c, Speed};
9use tmp108::Tmp108;
10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
16
17 let p = hal::init(config);
18
19 defmt::info!("I2C example");
20
21 let mut config = controller::Config::default();
22 config.speed = Speed::Standard;
23 let i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap();
24 let mut tmp = Tmp108::new_with_a0_gnd(i2c);
25
26 loop {
27 let temperature = tmp.temperature().unwrap();
28 defmt::info!("Temperature: {}C", temperature);
29 Timer::after_secs(1).await;
30 }
31}
diff --git a/examples/mcxa/src/bin/i2c-scan-blocking.rs b/examples/mcxa/src/bin/i2c-scan-blocking.rs
new file mode 100644
index 000000000..bd706d712
--- /dev/null
+++ b/examples/mcxa/src/bin/i2c-scan-blocking.rs
@@ -0,0 +1,40 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::gpio::{Input, Pull};
6use embassy_time::Timer;
7use hal::clocks::config::Div8;
8use hal::config::Config;
9use hal::i2c::controller::{self, I2c, Speed};
10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let mut config = Config::default();
15 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
16
17 let p = hal::init(config);
18
19 defmt::info!("I2C example");
20
21 let mut config = controller::Config::default();
22 config.speed = Speed::Standard;
23
24 // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and
25 // defaults to SWO on the debug peripheral. Explicitly make it a high-z
26 // input.
27 let _pin = Input::new(p.P0_2, Pull::Disabled);
28 let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap();
29
30 for addr in 0x01..=0x7f {
31 let result = i2c.blocking_write(addr, &[]);
32 if result.is_ok() {
33 defmt::info!("Device found at addr {:02x}", addr);
34 }
35 }
36
37 loop {
38 Timer::after_secs(10).await;
39 }
40}
diff --git a/examples/mcxa/src/bin/lpuart_buffered.rs b/examples/mcxa/src/bin/lpuart_buffered.rs
new file mode 100644
index 000000000..47b56b7c7
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_buffered.rs
@@ -0,0 +1,62 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::clocks::config::Div8;
6use embassy_mcxa::lpuart::Config;
7use embassy_mcxa::lpuart::buffered::BufferedLpuart;
8use embassy_mcxa::{bind_interrupts, lpuart};
9use embedded_io_async::Write;
10use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
11
12// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver
13bind_interrupts!(struct Irqs {
14 LPUART2 => lpuart::buffered::BufferedInterruptHandler::<hal::peripherals::LPUART2>;
15});
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let mut cfg = hal::config::Config::default();
20 cfg.clock_cfg.sirc.fro_12m_enabled = true;
21 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
22 let p = hal::init(cfg);
23
24 // Configure NVIC for LPUART2
25 hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3);
26
27 // UART configuration (enable both TX and RX)
28 let config = Config {
29 baudrate_bps: 115_200,
30 rx_fifo_watermark: 0,
31 tx_fifo_watermark: 0,
32 ..Default::default()
33 };
34
35 let mut tx_buf = [0u8; 256];
36 let mut rx_buf = [0u8; 256];
37
38 // Create a buffered LPUART2 instance with both TX and RX
39 let mut uart = BufferedLpuart::new(
40 p.LPUART2,
41 p.P2_2, // TX pin
42 p.P2_3, // RX pin
43 Irqs,
44 &mut tx_buf,
45 &mut rx_buf,
46 config,
47 )
48 .unwrap();
49
50 // Split into TX and RX parts
51 let (tx, rx) = uart.split_ref();
52
53 tx.write(b"Hello buffered LPUART.\r\n").await.unwrap();
54 tx.write(b"Type characters to echo them back.\r\n").await.unwrap();
55
56 // Echo loop
57 let mut buf = [0u8; 4];
58 loop {
59 let used = rx.read(&mut buf).await.unwrap();
60 tx.write_all(&buf[..used]).await.unwrap();
61 }
62}
diff --git a/examples/mcxa/src/bin/lpuart_dma.rs b/examples/mcxa/src/bin/lpuart_dma.rs
new file mode 100644
index 000000000..cc86f6a40
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_dma.rs
@@ -0,0 +1,68 @@
1//! LPUART DMA example for MCXA276.
2//!
3//! This example demonstrates using DMA for UART TX and RX operations.
4//! It sends a message using DMA, then waits for 16 characters to be received
5//! via DMA and echoes them back.
6//!
7//! The DMA request sources are automatically derived from the LPUART instance type.
8//! DMA clock/reset/init is handled automatically by the HAL.
9
10#![no_std]
11#![no_main]
12
13use embassy_executor::Spawner;
14use embassy_mcxa::clocks::config::Div8;
15use embassy_mcxa::lpuart::{Config, LpuartDma};
16use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let mut cfg = hal::config::Config::default();
21 cfg.clock_cfg.sirc.fro_12m_enabled = true;
22 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
23 let p = hal::init(cfg);
24
25 defmt::info!("LPUART DMA example starting...");
26
27 // Create UART configuration
28 let config = Config {
29 baudrate_bps: 115_200,
30 ..Default::default()
31 };
32
33 // Create UART instance with DMA channels
34 let mut lpuart = LpuartDma::new(
35 p.LPUART2, // Instance
36 p.P2_2, // TX pin
37 p.P2_3, // RX pin
38 p.DMA_CH0, // TX DMA channel
39 p.DMA_CH1, // RX DMA channel
40 config,
41 )
42 .unwrap();
43
44 // Send a message using DMA (DMA request source is automatically derived from LPUART2)
45 let tx_msg = b"Hello from LPUART2 DMA TX!\r\n";
46 lpuart.write_dma(tx_msg).await.unwrap();
47
48 defmt::info!("TX DMA complete");
49
50 // Send prompt
51 let prompt = b"Type 16 characters to echo via DMA:\r\n";
52 lpuart.write_dma(prompt).await.unwrap();
53
54 // Receive 16 characters using DMA
55 let mut rx_buf = [0u8; 16];
56 lpuart.read_dma(&mut rx_buf).await.unwrap();
57
58 defmt::info!("RX DMA complete");
59
60 // Echo back the received data
61 let echo_prefix = b"\r\nReceived: ";
62 lpuart.write_dma(echo_prefix).await.unwrap();
63 lpuart.write_dma(&rx_buf).await.unwrap();
64 let done_msg = b"\r\nDone!\r\n";
65 lpuart.write_dma(done_msg).await.unwrap();
66
67 defmt::info!("Example complete");
68}
diff --git a/examples/mcxa/src/bin/lpuart_polling.rs b/examples/mcxa/src/bin/lpuart_polling.rs
new file mode 100644
index 000000000..b80668834
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_polling.rs
@@ -0,0 +1,47 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::clocks::config::Div8;
6use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
7
8use crate::hal::lpuart::{Config, Lpuart};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let mut cfg = hal::config::Config::default();
13 cfg.clock_cfg.sirc.fro_12m_enabled = true;
14 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
15 let p = hal::init(cfg);
16
17 defmt::info!("boot");
18
19 // Create UART configuration
20 let config = Config {
21 baudrate_bps: 115_200,
22 ..Default::default()
23 };
24
25 // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX
26 let lpuart = Lpuart::new_blocking(
27 p.LPUART2, // Peripheral
28 p.P2_2, // TX pin
29 p.P2_3, // RX pin
30 config,
31 )
32 .unwrap();
33
34 // Split into separate TX and RX parts
35 let (mut tx, mut rx) = lpuart.split();
36
37 // Write hello messages
38 tx.blocking_write(b"Hello world.\r\n").unwrap();
39 tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap();
40
41 // Echo loop
42 loop {
43 let mut buf = [0u8; 1];
44 rx.blocking_read(&mut buf).unwrap();
45 tx.blocking_write(&buf).unwrap();
46 }
47}
diff --git a/examples/mcxa/src/bin/lpuart_ring_buffer.rs b/examples/mcxa/src/bin/lpuart_ring_buffer.rs
new file mode 100644
index 000000000..be7fd4534
--- /dev/null
+++ b/examples/mcxa/src/bin/lpuart_ring_buffer.rs
@@ -0,0 +1,115 @@
1//! LPUART Ring Buffer DMA example for MCXA276.
2//!
3//! This example demonstrates using the high-level `LpuartRxDma::setup_ring_buffer()`
4//! API for continuous circular DMA reception from a UART peripheral.
5//!
6//! # Features demonstrated:
7//! - `LpuartRxDma::setup_ring_buffer()` for continuous peripheral-to-memory DMA
8//! - `RingBuffer` for async reading of received data
9//! - Handling of potential overrun conditions
10//! - Half-transfer and complete-transfer interrupts for timely wakeups
11//!
12//! # How it works:
13//! 1. Create an `LpuartRxDma` driver with a DMA channel
14//! 2. Call `setup_ring_buffer()` which handles all low-level DMA configuration
15//! 3. Application asynchronously reads data as it arrives via `ring_buf.read()`
16//! 4. Both half-transfer and complete-transfer interrupts wake the reader
17
18#![no_std]
19#![no_main]
20
21use embassy_executor::Spawner;
22use embassy_mcxa::clocks::config::Div8;
23use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma};
24use static_cell::ConstStaticCell;
25use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
26
27// Ring buffer for RX - power of 2 is ideal for modulo efficiency
28static RX_RING_BUFFER: ConstStaticCell<[u8; 64]> = ConstStaticCell::new([0; 64]);
29
30/// Helper to write a byte as hex to UART
31fn write_hex<T: embassy_mcxa::lpuart::Instance, C: embassy_mcxa::dma::Channel>(
32 tx: &mut LpuartTxDma<'_, T, C>,
33 byte: u8,
34) {
35 const HEX: &[u8; 16] = b"0123456789ABCDEF";
36 let buf = [HEX[(byte >> 4) as usize], HEX[(byte & 0x0F) as usize]];
37 tx.blocking_write(&buf).ok();
38}
39
40#[embassy_executor::main]
41async fn main(_spawner: Spawner) {
42 // Small delay to allow probe-rs to attach after reset
43 for _ in 0..100_000 {
44 cortex_m::asm::nop();
45 }
46
47 let mut cfg = hal::config::Config::default();
48 cfg.clock_cfg.sirc.fro_12m_enabled = true;
49 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
50 let p = hal::init(cfg);
51
52 defmt::info!("LPUART Ring Buffer DMA example starting...");
53
54 // Create UART configuration
55 let config = Config {
56 baudrate_bps: 115_200,
57 ..Default::default()
58 };
59
60 // Create LPUART with DMA support for both TX and RX, then split
61 // This is the proper Embassy pattern - create once, split into TX and RX
62 let lpuart = LpuartDma::new(p.LPUART2, p.P2_2, p.P2_3, p.DMA_CH1, p.DMA_CH0, config).unwrap();
63 let (mut tx, rx) = lpuart.split();
64
65 tx.blocking_write(b"LPUART Ring Buffer DMA Example\r\n").unwrap();
66 tx.blocking_write(b"==============================\r\n\r\n").unwrap();
67
68 tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n")
69 .unwrap();
70
71 let buf = RX_RING_BUFFER.take();
72 // Set up the ring buffer with circular DMA
73 let mut ring_buf = rx.into_ring_dma_rx(buf);
74
75 tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n")
76 .unwrap();
77 tx.blocking_write(b"The DMA continuously receives in the background.\r\n\r\n")
78 .unwrap();
79
80 // Main loop: read from ring buffer and echo back
81 let mut read_buf = [0u8; 16];
82 let mut total_received: usize = 0;
83
84 loop {
85 // Async read - waits until data is available
86 match ring_buf.read(&mut read_buf).await {
87 Ok(n) if n > 0 => {
88 total_received += n;
89
90 // Echo back what we received
91 tx.blocking_write(b"RX[").unwrap();
92 for (i, &byte) in read_buf.iter().enumerate().take(n) {
93 write_hex(&mut tx, byte);
94 if i < n - 1 {
95 tx.blocking_write(b" ").unwrap();
96 }
97 }
98 tx.blocking_write(b"]: ").unwrap();
99 tx.blocking_write(&read_buf[..n]).unwrap();
100 tx.blocking_write(b"\r\n").unwrap();
101
102 defmt::info!("Received {} bytes, total: {}", n, total_received);
103 }
104 Ok(_) => {
105 // No data, shouldn't happen with async read
106 }
107 Err(_) => {
108 // Overrun detected
109 tx.blocking_write(b"ERROR: Ring buffer overrun!\r\n").unwrap();
110 defmt::error!("Ring buffer overrun!");
111 ring_buf.clear();
112 }
113 }
114 }
115}
diff --git a/examples/mcxa/src/bin/raw_dma_channel_link.rs b/examples/mcxa/src/bin/raw_dma_channel_link.rs
new file mode 100644
index 000000000..74785e4f3
--- /dev/null
+++ b/examples/mcxa/src/bin/raw_dma_channel_link.rs
@@ -0,0 +1,278 @@
1//! DMA channel linking example for MCXA276.
2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
7//! This example demonstrates DMA channel linking (minor and major loop linking):
8//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with:
9//! - Minor Link to Channel 1 (triggers CH1 after each minor loop)
10//! - Major Link to Channel 2 (triggers CH2 after major loop completes)
11//! - Channel 1: Transfers SRC_BUFFER to DEST_BUFFER1 (triggered by CH0 minor link)
12//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link)
13//!
14//! # Embassy-style features demonstrated:
15//! - `DmaChannel::new()` for channel creation
16//! - `DmaChannel::is_done()` and `clear_done()` helper methods
17//! - Channel linking with `set_minor_link()` and `set_major_link()`
18
19#![no_std]
20#![no_main]
21
22use embassy_executor::Spawner;
23use embassy_mcxa::clocks::config::Div8;
24use embassy_mcxa::dma::DmaChannel;
25use embassy_mcxa::pac;
26use static_cell::ConstStaticCell;
27use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
28
29// Buffers
30static SRC_BUFFER: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([1, 2, 3, 4]);
31static DEST_BUFFER0: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
32static DEST_BUFFER1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
33static DEST_BUFFER2: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]);
34
35#[embassy_executor::main]
36async fn main(_spawner: Spawner) {
37 // Small delay to allow probe-rs to attach after reset
38 for _ in 0..100_000 {
39 cortex_m::asm::nop();
40 }
41
42 let mut cfg = hal::config::Config::default();
43 cfg.clock_cfg.sirc.fro_12m_enabled = true;
44 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
45 let p = hal::init(cfg);
46
47 defmt::info!("DMA channel link example starting...");
48
49 // DMA is initialized during hal::init() - no need to call ensure_init()
50
51 let pac_periphs = unsafe { pac::Peripherals::steal() };
52 let dma0 = &pac_periphs.dma0;
53 let edma = unsafe { &*pac::Edma0Tcd0::ptr() };
54
55 // Clear any residual state
56 for i in 0..3 {
57 let t = edma.tcd(i);
58 t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one());
59 t.ch_int().write(|w| w.int().clear_bit_by_one());
60 t.ch_es().write(|w| w.err().clear_bit_by_one());
61 t.ch_mux().write(|w| unsafe { w.bits(0) });
62 }
63
64 // Clear Global Halt/Error state
65 dma0.mp_csr().modify(|_, w| {
66 w.halt()
67 .normal_operation()
68 .hae()
69 .normal_operation()
70 .ecx()
71 .normal_operation()
72 .cx()
73 .normal_operation()
74 });
75
76 defmt::info!("EDMA channel link example begin.");
77
78 // Initialize buffers
79 let src = SRC_BUFFER.take();
80 let dst0 = DEST_BUFFER0.take();
81 let dst1 = DEST_BUFFER1.take();
82 let dst2 = DEST_BUFFER2.take();
83
84 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
85 defmt::info!("DEST0 (before): {=[?]}", dst0.as_slice());
86 defmt::info!("DEST1 (before): {=[?]}", dst1.as_slice());
87 defmt::info!("DEST2 (before): {=[?]}", dst2.as_slice());
88
89 defmt::info!("Configuring DMA channels with Embassy-style API...");
90
91 let ch0 = DmaChannel::new(p.DMA_CH0);
92 let ch1 = DmaChannel::new(p.DMA_CH1);
93 let ch2 = DmaChannel::new(p.DMA_CH2);
94
95 // Configure channels using direct TCD access (advanced feature demo)
96 // This example demonstrates channel linking which requires direct TCD manipulation
97
98 // Helper to configure TCD for memory-to-memory transfer
99 // Parameters: channel, src, dst, width, nbytes (minor loop), count (major loop), interrupt
100 #[allow(clippy::too_many_arguments)]
101 unsafe fn configure_tcd(
102 edma: &embassy_mcxa::pac::edma_0_tcd0::RegisterBlock,
103 ch: usize,
104 src: u32,
105 dst: u32,
106 width: u8,
107 nbytes: u32,
108 count: u16,
109 enable_int: bool,
110 ) {
111 let t = edma.tcd(ch);
112
113 // Reset channel state
114 t.ch_csr().write(|w| {
115 w.erq()
116 .disable()
117 .earq()
118 .disable()
119 .eei()
120 .no_error()
121 .ebw()
122 .disable()
123 .done()
124 .clear_bit_by_one()
125 });
126 t.ch_es().write(|w| w.bits(0));
127 t.ch_int().write(|w| w.int().clear_bit_by_one());
128
129 // Source/destination addresses
130 t.tcd_saddr().write(|w| w.saddr().bits(src));
131 t.tcd_daddr().write(|w| w.daddr().bits(dst));
132
133 // Offsets: increment by width
134 t.tcd_soff().write(|w| w.soff().bits(width as u16));
135 t.tcd_doff().write(|w| w.doff().bits(width as u16));
136
137 // Attributes: size = log2(width)
138 let size = match width {
139 1 => 0,
140 2 => 1,
141 4 => 2,
142 _ => 0,
143 };
144 t.tcd_attr().write(|w| w.ssize().bits(size).dsize().bits(size));
145
146 // Number of bytes per minor loop
147 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
148
149 // Major loop: reset source address after major loop
150 let total_bytes = nbytes * count as u32;
151 t.tcd_slast_sda()
152 .write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32));
153 t.tcd_dlast_sga()
154 .write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32));
155
156 // Major loop count
157 t.tcd_biter_elinkno().write(|w| w.biter().bits(count));
158 t.tcd_citer_elinkno().write(|w| w.citer().bits(count));
159
160 // Control/status: enable interrupt if requested
161 if enable_int {
162 t.tcd_csr().write(|w| w.intmajor().set_bit());
163 } else {
164 t.tcd_csr().write(|w| w.intmajor().clear_bit());
165 }
166
167 cortex_m::asm::dsb();
168 }
169
170 unsafe {
171 // Channel 0: Transfer 16 bytes total (8 bytes per minor loop, 2 major iterations)
172 // Minor Link -> Channel 1
173 // Major Link -> Channel 2
174 configure_tcd(
175 edma,
176 0,
177 src.as_ptr() as u32,
178 dst0.as_mut_ptr() as u32,
179 4, // src width
180 8, // nbytes (minor loop = 2 words)
181 2, // count (major loop = 2 iterations)
182 false, // no interrupt
183 );
184 ch0.set_minor_link(1); // Link to CH1 after each minor loop
185 ch0.set_major_link(2); // Link to CH2 after major loop
186
187 // Channel 1: Transfer 16 bytes (triggered by CH0 minor link)
188 configure_tcd(
189 edma,
190 1,
191 src.as_ptr() as u32,
192 dst1.as_mut_ptr() as u32,
193 4,
194 16, // full buffer in one minor loop
195 1, // 1 major iteration
196 false,
197 );
198
199 // Channel 2: Transfer 16 bytes (triggered by CH0 major link)
200 configure_tcd(
201 edma,
202 2,
203 src.as_ptr() as u32,
204 dst2.as_mut_ptr() as u32,
205 4,
206 16, // full buffer in one minor loop
207 1, // 1 major iteration
208 true, // enable interrupt
209 );
210 }
211
212 defmt::info!("Triggering Channel 0 (1st minor loop)...");
213
214 // Trigger first minor loop of CH0
215 unsafe {
216 ch0.trigger_start();
217 }
218
219 // Wait for CH1 to complete (triggered by CH0 minor link)
220 while !ch1.is_done() {
221 cortex_m::asm::nop();
222 }
223 unsafe {
224 ch1.clear_done();
225 }
226
227 defmt::info!("CH1 done (via minor link).");
228 defmt::info!("Triggering Channel 0 (2nd minor loop)...");
229
230 // Trigger second minor loop of CH0
231 unsafe {
232 ch0.trigger_start();
233 }
234
235 // Wait for CH0 major loop to complete
236 while !ch0.is_done() {
237 cortex_m::asm::nop();
238 }
239 unsafe {
240 ch0.clear_done();
241 }
242
243 defmt::info!("CH0 major loop done.");
244
245 // Wait for CH2 to complete (triggered by CH0 major link)
246 // Using is_done() instead of AtomicBool - the standard interrupt handler
247 // clears the interrupt flag and wakes wakers, but DONE bit remains set
248 while !ch2.is_done() {
249 cortex_m::asm::nop();
250 }
251 unsafe {
252 ch2.clear_done();
253 }
254
255 defmt::info!("CH2 done (via major link).");
256
257 defmt::info!("EDMA channel link example finish.");
258
259 defmt::info!("DEST0 (after): {=[?]}", dst0.as_slice());
260 defmt::info!("DEST1 (after): {=[?]}", dst1.as_slice());
261 defmt::info!("DEST2 (after): {=[?]}", dst2.as_slice());
262
263 // Verify all buffers match source
264 let mut success = true;
265 for sli in [dst0, dst1, dst2] {
266 success &= sli == src;
267 }
268
269 if success {
270 defmt::info!("PASS: Data verified.");
271 } else {
272 defmt::error!("FAIL: Mismatch detected!");
273 }
274
275 loop {
276 cortex_m::asm::wfe();
277 }
278}
diff --git a/examples/mcxa/src/bin/raw_dma_interleave_transfer.rs b/examples/mcxa/src/bin/raw_dma_interleave_transfer.rs
new file mode 100644
index 000000000..a383b6cf4
--- /dev/null
+++ b/examples/mcxa/src/bin/raw_dma_interleave_transfer.rs
@@ -0,0 +1,141 @@
1//! DMA interleaved transfer example for MCXA276.
2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
7//! This example demonstrates using DMA with custom source/destination offsets
8//! to interleave data during transfer.
9//!
10//! # Embassy-style features demonstrated:
11//! - `TransferOptions::default()` for configuration (used internally)
12//! - DMA channel with `DmaChannel::new()`
13
14#![no_std]
15#![no_main]
16
17use embassy_executor::Spawner;
18use embassy_mcxa::clocks::config::Div8;
19use embassy_mcxa::dma::DmaChannel;
20use static_cell::ConstStaticCell;
21use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
22
23const BUFFER_LENGTH: usize = 16;
24const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2;
25
26// Buffers in RAM
27static SRC_BUFFER: ConstStaticCell<[u32; HALF_BUFF_LENGTH]> = ConstStaticCell::new([0; HALF_BUFF_LENGTH]);
28static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]);
29
30#[embassy_executor::main]
31async fn main(_spawner: Spawner) {
32 // Small delay to allow probe-rs to attach after reset
33 for _ in 0..100_000 {
34 cortex_m::asm::nop();
35 }
36
37 let mut cfg = hal::config::Config::default();
38 cfg.clock_cfg.sirc.fro_12m_enabled = true;
39 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
40 let p = hal::init(cfg);
41
42 defmt::info!("DMA interleave transfer example starting...");
43
44 defmt::info!("EDMA interleave transfer example begin.");
45
46 // Initialize buffers
47 let src = SRC_BUFFER.take();
48 *src = [1, 2, 3, 4, 5, 6, 7, 8];
49 let dst = DEST_BUFFER.take();
50
51 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
52 defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());
53
54 defmt::info!("Configuring DMA with Embassy-style API...");
55
56 // Create DMA channel using Embassy-style API
57 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
58
59 // Configure interleaved transfer using direct TCD access:
60 // - src_offset = 4: advance source by 4 bytes after each read
61 // - dst_offset = 8: advance dest by 8 bytes after each write
62 // This spreads source data across every other word in destination
63 unsafe {
64 let t = dma_ch0.tcd();
65
66 // Reset channel state
67 t.ch_csr().write(|w| {
68 w.erq()
69 .disable()
70 .earq()
71 .disable()
72 .eei()
73 .no_error()
74 .ebw()
75 .disable()
76 .done()
77 .clear_bit_by_one()
78 });
79 t.ch_es().write(|w| w.bits(0));
80 t.ch_int().write(|w| w.int().clear_bit_by_one());
81
82 // Source/destination addresses
83 t.tcd_saddr().write(|w| w.saddr().bits(src.as_ptr() as u32));
84 t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32));
85
86 // Custom offsets for interleaving
87 t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read
88 t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write
89
90 // Attributes: 32-bit transfers (size = 2)
91 t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2));
92
93 // Transfer entire source buffer in one minor loop
94 let nbytes = (HALF_BUFF_LENGTH * 4) as u32;
95 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
96
97 // Reset source address after major loop
98 t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32));
99 // Destination uses 2x offset, so adjust accordingly
100 let dst_total = (HALF_BUFF_LENGTH * 8) as u32;
101 t.tcd_dlast_sga()
102 .write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32));
103
104 // Major loop count = 1
105 t.tcd_biter_elinkno().write(|w| w.biter().bits(1));
106 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
107
108 // Enable interrupt on major loop completion
109 t.tcd_csr().write(|w| w.intmajor().set_bit());
110
111 cortex_m::asm::dsb();
112
113 defmt::info!("Triggering transfer...");
114 dma_ch0.trigger_start();
115 }
116
117 // Wait for completion using channel helper method
118 while !dma_ch0.is_done() {
119 cortex_m::asm::nop();
120 }
121 unsafe {
122 dma_ch0.clear_done();
123 }
124
125 defmt::info!("EDMA interleave transfer example finish.");
126 defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());
127
128 // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0
129 let mut mismatch = false;
130 let diter = dst.chunks_exact(2);
131 let siter = src.iter();
132 for (ch, src) in diter.zip(siter) {
133 mismatch |= !matches!(ch, [a, 0] if a == src);
134 }
135
136 if mismatch {
137 defmt::error!("FAIL: Mismatch detected!");
138 } else {
139 defmt::info!("PASS: Data verified.");
140 }
141}
diff --git a/examples/mcxa/src/bin/raw_dma_memset.rs b/examples/mcxa/src/bin/raw_dma_memset.rs
new file mode 100644
index 000000000..7b3c06ffa
--- /dev/null
+++ b/examples/mcxa/src/bin/raw_dma_memset.rs
@@ -0,0 +1,129 @@
1//! DMA memset example for MCXA276.
2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
7//! This example demonstrates using DMA to fill a buffer with a repeated pattern.
8//! The source address stays fixed while the destination increments.
9//!
10//! # Embassy-style features demonstrated:
11//! - `DmaChannel::is_done()` and `clear_done()` helper methods
12//! - No need to pass register block around
13
14#![no_std]
15#![no_main]
16
17use embassy_executor::Spawner;
18use embassy_mcxa::clocks::config::Div8;
19use embassy_mcxa::dma::DmaChannel;
20use static_cell::ConstStaticCell;
21use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
22
23const BUFFER_LENGTH: usize = 4;
24
25// Buffers in RAM
26static PATTERN: u32 = 0xDEADBEEF;
27static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]);
28
29#[embassy_executor::main]
30async fn main(_spawner: Spawner) {
31 // Small delay to allow probe-rs to attach after reset
32 for _ in 0..100_000 {
33 cortex_m::asm::nop();
34 }
35
36 let mut cfg = hal::config::Config::default();
37 cfg.clock_cfg.sirc.fro_12m_enabled = true;
38 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
39 let p = hal::init(cfg);
40
41 defmt::info!("DMA memset example starting...");
42 defmt::info!("EDMA memset example begin.");
43
44 // Initialize buffers
45 let pat = &PATTERN;
46 let dst = DEST_BUFFER.take();
47 defmt::info!("Pattern Value: {=u32}", pat);
48 defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());
49 defmt::info!("Configuring DMA with Embassy-style API...");
50
51 // Create DMA channel using Embassy-style API
52 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
53
54 // Configure memset transfer using direct TCD access:
55 // Source stays fixed (soff = 0, reads same pattern repeatedly)
56 // Destination increments (doff = 4)
57 unsafe {
58 let t = dma_ch0.tcd();
59
60 // Reset channel state
61 t.ch_csr().write(|w| {
62 w.erq()
63 .disable()
64 .earq()
65 .disable()
66 .eei()
67 .no_error()
68 .ebw()
69 .disable()
70 .done()
71 .clear_bit_by_one()
72 });
73 t.ch_es().write(|w| w.bits(0));
74 t.ch_int().write(|w| w.int().clear_bit_by_one());
75
76 // Source address (pattern) - fixed
77 t.tcd_saddr().write(|w| w.saddr().bits(pat as *const _ as u32));
78 // Destination address - increments
79 t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32));
80
81 // Source offset = 0 (stays fixed), Dest offset = 4 (increments)
82 t.tcd_soff().write(|w| w.soff().bits(0));
83 t.tcd_doff().write(|w| w.doff().bits(4));
84
85 // Attributes: 32-bit transfers (size = 2)
86 t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2));
87
88 // Transfer entire buffer in one minor loop
89 let nbytes = (BUFFER_LENGTH * 4) as u32;
90 t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes));
91
92 // Source doesn't need adjustment (stays fixed)
93 t.tcd_slast_sda().write(|w| w.slast_sda().bits(0));
94 // Reset dest address after major loop
95 t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32));
96
97 // Major loop count = 1
98 t.tcd_biter_elinkno().write(|w| w.biter().bits(1));
99 t.tcd_citer_elinkno().write(|w| w.citer().bits(1));
100
101 // Enable interrupt on major loop completion
102 t.tcd_csr().write(|w| w.intmajor().set_bit());
103
104 cortex_m::asm::dsb();
105
106 defmt::info!("Triggering transfer...");
107 dma_ch0.trigger_start();
108 }
109
110 // Wait for completion using channel helper method
111 while !dma_ch0.is_done() {
112 cortex_m::asm::nop();
113 }
114 unsafe {
115 dma_ch0.clear_done();
116 }
117
118 defmt::info!("EDMA memset example finish.");
119 defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());
120
121 // Verify: All elements should equal PATTERN
122 let mismatch = dst.iter().any(|i| *i != *pat);
123
124 if mismatch {
125 defmt::error!("FAIL: Mismatch detected!");
126 } else {
127 defmt::info!("PASS: Data verified.");
128 }
129}
diff --git a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs
new file mode 100644
index 000000000..80df40449
--- /dev/null
+++ b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs
@@ -0,0 +1,244 @@
1//! DMA ping-pong/double-buffer transfer example for MCXA276.
2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
7//! This example demonstrates two approaches for ping-pong/double-buffering:
8//!
9//! ## Approach 1: Scatter/Gather with linked TCDs (manual)
10//! - Two TCDs link to each other for alternating transfers
11//! - Uses custom handler that delegates to on_interrupt() then signals completion
12//! - Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads,
13//! so we need an AtomicBool to track completion
14//!
15//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!)
16//! - Single continuous transfer over entire buffer
17//! - Uses half-transfer interrupt to know when first half is ready
18//! - Application can process first half while second half is being filled
19//!
20//! # Embassy-style features demonstrated:
21//! - `DmaChannel::new()` for channel creation
22//! - Scatter/gather with linked TCDs
23//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice)
24//! - Standard `DmaCh1InterruptHandler` with `bind_interrupts!` macro
25//! - NEW: `wait_half()` for half-transfer interrupt handling
26
27#![no_std]
28#![no_main]
29
30use embassy_executor::Spawner;
31use embassy_mcxa::clocks::config::Div8;
32use embassy_mcxa::dma::{DmaChannel, Tcd, TransferOptions};
33use embassy_mcxa::pac;
34use static_cell::ConstStaticCell;
35use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
36
37// Source and destination buffers for Approach 1 (scatter/gather)
38static SRC: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([1, 2, 3, 4, 5, 6, 7, 8]);
39static DST: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]);
40
41// Source and destination buffers for Approach 2 (wait_half)
42static SRC2: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]);
43static DST2: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]);
44
45// TCD pool for scatter/gather - must be 32-byte aligned
46#[repr(C, align(32))]
47struct TcdPool([Tcd; 2]);
48
49static TCD_POOL: ConstStaticCell<TcdPool> = ConstStaticCell::new(TcdPool(
50 [Tcd {
51 saddr: 0,
52 soff: 0,
53 attr: 0,
54 nbytes: 0,
55 slast: 0,
56 daddr: 0,
57 doff: 0,
58 citer: 0,
59 dlast_sga: 0,
60 csr: 0,
61 biter: 0,
62 }; 2],
63));
64
65#[embassy_executor::main]
66async fn main(_spawner: Spawner) {
67 // Small delay to allow probe-rs to attach after reset
68 for _ in 0..100_000 {
69 cortex_m::asm::nop();
70 }
71
72 let mut cfg = hal::config::Config::default();
73 cfg.clock_cfg.sirc.fro_12m_enabled = true;
74 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
75 let p = hal::init(cfg);
76
77 defmt::info!("DMA ping-pong transfer example starting...");
78
79 defmt::info!("EDMA ping-pong transfer example begin.");
80
81 // Initialize buffers
82 let src = SRC.take();
83 let dst = DST.take();
84
85 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
86 defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());
87
88 defmt::info!("Configuring ping-pong DMA with Embassy-style API...");
89
90 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
91
92 // Configure ping-pong transfer using direct TCD access:
93 // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel.
94 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1.
95 // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0.
96 let tcds = &mut TCD_POOL.take().0;
97
98 let half_len = 4usize;
99 let half_bytes = (half_len * 4) as u32;
100
101 unsafe {
102 let tcd0_addr = &tcds[0] as *const _ as u32;
103 let tcd1_addr = &tcds[1] as *const _ as u32;
104
105 // TCD0: First half -> Links to TCD1
106 tcds[0] = Tcd {
107 saddr: src.as_ptr() as u32,
108 soff: 4,
109 attr: 0x0202, // 32-bit src/dst
110 nbytes: half_bytes,
111 slast: 0,
112 daddr: dst.as_mut_ptr() as u32,
113 doff: 4,
114 citer: 1,
115 dlast_sga: tcd1_addr as i32,
116 csr: 0x0012, // ESG | INTMAJOR
117 biter: 1,
118 };
119
120 // TCD1: Second half -> Links to TCD0
121 tcds[1] = Tcd {
122 saddr: src.as_ptr().add(half_len) as u32,
123 soff: 4,
124 attr: 0x0202,
125 nbytes: half_bytes,
126 slast: 0,
127 daddr: dst.as_mut_ptr().add(half_len) as u32,
128 doff: 4,
129 citer: 1,
130 dlast_sga: tcd0_addr as i32,
131 csr: 0x0012,
132 biter: 1,
133 };
134
135 // Load TCD0 into hardware registers
136 dma_ch0.load_tcd(&tcds[0]);
137 }
138
139 defmt::info!("Triggering first half transfer...");
140
141 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4])
142 unsafe {
143 dma_ch0.trigger_start();
144 }
145
146 let tcd = dma_ch0.tcd();
147 // Wait for first half
148 loop {
149 if tcd.tcd_saddr().read().bits() != src.as_ptr() as u32 {
150 break;
151 }
152 }
153
154 defmt::info!("First half transferred.");
155 defmt::info!("Triggering second half transfer...");
156
157 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8])
158 unsafe {
159 dma_ch0.trigger_start();
160 }
161
162 // Wait for second half
163 loop {
164 if tcd.tcd_saddr().read().bits() != unsafe { src.as_ptr().add(half_len) } as u32 {
165 break;
166 }
167 }
168
169 defmt::info!("Second half transferred.");
170
171 defmt::info!("EDMA ping-pong transfer example finish.");
172 defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());
173
174 // Verify: DST should match SRC
175 let mismatch = src != dst;
176
177 if mismatch {
178 defmt::error!("FAIL: Approach 1 mismatch detected!");
179 } else {
180 defmt::info!("PASS: Approach 1 data verified.");
181 }
182
183 // =========================================================================
184 // Approach 2: Half-Transfer Interrupt with wait_half() (NEW!)
185 // =========================================================================
186 //
187 // This approach uses a single continuous DMA transfer with half-transfer
188 // interrupt enabled. The wait_half() method allows you to be notified
189 // when the first half of the buffer is complete, so you can process it
190 // while the second half is still being filled.
191 //
192 // Benefits:
193 // - Simpler setup (no TCD pool needed)
194 // - True async/await support
195 // - Good for streaming data processing
196
197 defmt::info!("--- Approach 2: wait_half() demo ---");
198
199 // Enable DMA CH1 interrupt
200 unsafe {
201 cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1);
202 }
203
204 // Initialize approach 2 buffers
205 let src2 = SRC2.take();
206 let dst2 = DST2.take();
207
208 defmt::info!("SRC2: {=[?]}", src2.as_slice());
209
210 let dma_ch1 = DmaChannel::new(p.DMA_CH1);
211
212 // Configure transfer with half-transfer interrupt enabled
213 let mut options = TransferOptions::default();
214 options.half_transfer_interrupt = true; // Enable half-transfer interrupt
215 options.complete_transfer_interrupt = true;
216
217 defmt::info!("Starting transfer with half_transfer_interrupt...");
218
219 // Create the transfer
220 let mut transfer = dma_ch1.mem_to_mem(src2, dst2, options).unwrap();
221
222 // Wait for half-transfer (first 4 elements)
223 defmt::info!("Waiting for first half...");
224 let _ok = transfer.wait_half().await.unwrap();
225
226 defmt::info!("Half-transfer complete!");
227
228 // Wait for complete transfer
229 defmt::info!("Waiting for second half...");
230 transfer.await.unwrap();
231
232 defmt::info!("Transfer complete! Full DST2: {=[?]}", dst2.as_slice());
233
234 // Verify approach 2
235 let mismatch2 = src2 != dst2;
236
237 if mismatch2 {
238 defmt::error!("FAIL: Approach 2 mismatch!");
239 } else {
240 defmt::info!("PASS: Approach 2 verified.");
241 }
242
243 defmt::info!("=== All ping-pong demos complete ===");
244}
diff --git a/examples/mcxa/src/bin/raw_dma_scatter_gather.rs b/examples/mcxa/src/bin/raw_dma_scatter_gather.rs
new file mode 100644
index 000000000..eb9960764
--- /dev/null
+++ b/examples/mcxa/src/bin/raw_dma_scatter_gather.rs
@@ -0,0 +1,165 @@
1//! DMA scatter-gather transfer example for MCXA276.
2//!
3//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have
4//! a high-level and safe API for. It should not be taken as typical, recommended, or
5//! stable usage!
6//!
7//! This example demonstrates using DMA with scatter/gather to chain multiple
8//! transfer descriptors. The first TCD transfers the first half of the buffer,
9//! then automatically loads the second TCD to transfer the second half.
10//!
11//! # Embassy-style features demonstrated:
12//! - `DmaChannel::new()` for channel creation
13//! - Scatter/gather with chained TCDs
14//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice)
15
16#![no_std]
17#![no_main]
18
19use embassy_executor::Spawner;
20use embassy_mcxa::clocks::config::Div8;
21use embassy_mcxa::dma::{DmaChannel, Tcd};
22use static_cell::ConstStaticCell;
23use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
24
25// Source and destination buffers
26static SRC: ConstStaticCell<[u32; 12]> = ConstStaticCell::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
27static DST: ConstStaticCell<[u32; 12]> = ConstStaticCell::new([0; 12]);
28
29// TCD pool for scatter/gather - must be 32-byte aligned
30#[repr(C, align(32))]
31struct TcdPool([Tcd; 2]);
32
33static TCD_POOL: ConstStaticCell<TcdPool> = ConstStaticCell::new(TcdPool(
34 [Tcd {
35 saddr: 0,
36 soff: 0,
37 attr: 0,
38 nbytes: 0,
39 slast: 0,
40 daddr: 0,
41 doff: 0,
42 citer: 0,
43 dlast_sga: 0,
44 csr: 0,
45 biter: 0,
46 }; 2],
47));
48
49#[embassy_executor::main]
50async fn main(_spawner: Spawner) {
51 // Small delay to allow probe-rs to attach after reset
52 for _ in 0..100_000 {
53 cortex_m::asm::nop();
54 }
55
56 let mut cfg = hal::config::Config::default();
57 cfg.clock_cfg.sirc.fro_12m_enabled = true;
58 cfg.clock_cfg.sirc.fro_lf_div = Some(Div8::no_div());
59 let p = hal::init(cfg);
60
61 defmt::info!("DMA scatter-gather transfer example starting...");
62
63 defmt::info!("EDMA scatter-gather transfer example begin.");
64
65 // Initialize buffers
66 let src = SRC.take();
67 let dst = DST.take();
68
69 defmt::info!("Source Buffer: {=[?]}", src.as_slice());
70 defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice());
71 defmt::info!("Configuring scatter-gather DMA with Embassy-style API...");
72
73 let dma_ch0 = DmaChannel::new(p.DMA_CH0);
74 let src_ptr = src.as_ptr();
75 let dst_ptr = dst.as_mut_ptr();
76
77 // Configure scatter-gather transfer using direct TCD access:
78 // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel.
79 // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1.
80 // TCD1 transfers second half (SRC[4..12] -> DST[4..12]), last TCD.
81 unsafe {
82 let tcds = &mut TCD_POOL.take().0;
83
84 // In the first transfer, copy
85 tcds[0] = Tcd {
86 saddr: src_ptr as u32,
87 soff: 4,
88 attr: 0x0202, // 32-bit src/dst
89 nbytes: 4 * 4,
90 slast: 0,
91 daddr: dst_ptr as u32,
92 doff: 4,
93 citer: 1,
94 dlast_sga: tcds.as_ptr().add(1) as i32,
95 // ESG (scatter/gather) for non-last, INTMAJOR for all
96 csr: 0x0012,
97 biter: 1,
98 };
99
100 tcds[1] = Tcd {
101 saddr: src_ptr.add(4) as u32,
102 soff: 4,
103 attr: 0x0202, // 32-bit src/dst
104 nbytes: 8 * 4,
105 slast: 0,
106 daddr: dst_ptr.add(4) as u32,
107 doff: 4,
108 citer: 1,
109 dlast_sga: 0,
110 // ESG (scatter/gather) for non-last, INTMAJOR for all
111 csr: 0x0002,
112 biter: 1,
113 };
114
115 // Load TCD0 into hardware registers
116 dma_ch0.load_tcd(&tcds[0]);
117 }
118
119 defmt::info!("Triggering first half transfer...");
120
121 let tcd = dma_ch0.tcd();
122
123 // Trigger first transfer (first half: SRC[0..4] -> DST[0..4])
124 // TCD0 is currently loaded.
125 unsafe {
126 dma_ch0.trigger_start();
127 }
128
129 // Wait for first half
130 loop {
131 if tcd.tcd_saddr().read().bits() != src_ptr as u32 {
132 defmt::info!("saddr: {=u32}", tcd.tcd_saddr().read().bits());
133 defmt::info!("srptr: {=u32}", src_ptr as u32);
134 break;
135 }
136 }
137
138 defmt::info!("First half transferred.");
139 defmt::info!("Triggering second half transfer...");
140
141 // Trigger second transfer (second half: SRC[4..8] -> DST[4..8])
142 // TCD1 should have been loaded by the scatter/gather engine.
143 unsafe {
144 dma_ch0.trigger_start();
145 }
146
147 // Wait for second half
148 while !dma_ch0.is_done() {
149 cortex_m::asm::nop();
150 }
151
152 defmt::info!("Second half transferred.");
153
154 defmt::info!("EDMA scatter-gather transfer example finish.");
155 defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice());
156
157 // Verify: DST should match SRC
158 let mismatch = src != dst;
159
160 if mismatch {
161 defmt::error!("FAIL: Mismatch detected!");
162 } else {
163 defmt::info!("PASS: Data verified.");
164 }
165}
diff --git a/examples/mcxa/src/bin/reset-reason.rs b/examples/mcxa/src/bin/reset-reason.rs
new file mode 100644
index 000000000..c244fbe04
--- /dev/null
+++ b/examples/mcxa/src/bin/reset-reason.rs
@@ -0,0 +1,15 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use hal::config::Config;
6use hal::reset_reason::reset_reason;
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9#[embassy_executor::main]
10async fn main(_spawner: Spawner) {
11 let config = Config::default();
12 let _p = hal::init(config);
13
14 defmt::info!("Reset Reason: '{}'", reset_reason());
15}
diff --git a/examples/mcxa/src/bin/rtc_alarm.rs b/examples/mcxa/src/bin/rtc_alarm.rs
new file mode 100644
index 000000000..fe355888b
--- /dev/null
+++ b/examples/mcxa/src/bin/rtc_alarm.rs
@@ -0,0 +1,47 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_mcxa::bind_interrupts;
6use hal::rtc::{InterruptHandler, Rtc, RtcDateTime};
7use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
8
9bind_interrupts!(struct Irqs {
10 RTC => InterruptHandler<hal::rtc::Rtc0>;
11});
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = hal::init(hal::config::Config::default());
16
17 defmt::info!("=== RTC Alarm Example ===");
18
19 let rtc_config = hal::rtc::get_default_config();
20
21 let mut rtc = Rtc::new(p.RTC0, Irqs, rtc_config);
22
23 let now = RtcDateTime {
24 year: 2025,
25 month: 10,
26 day: 15,
27 hour: 14,
28 minute: 30,
29 second: 0,
30 };
31
32 rtc.stop();
33
34 defmt::info!("Time set to: 2025-10-15 14:30:00");
35 rtc.set_datetime(now);
36
37 let mut alarm = now;
38 alarm.second += 10;
39
40 defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)");
41 defmt::info!("RTC started, waiting for alarm...");
42
43 rtc.wait_for_alarm(alarm).await;
44 defmt::info!("*** ALARM TRIGGERED! ***");
45
46 defmt::info!("Example complete - Test PASSED!");
47}
diff --git a/examples/mcxa/src/bin/trng.rs b/examples/mcxa/src/bin/trng.rs
new file mode 100644
index 000000000..5f6e2408c
--- /dev/null
+++ b/examples/mcxa/src/bin/trng.rs
@@ -0,0 +1,106 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use hal::bind_interrupts;
6use hal::config::Config;
7use hal::trng::{self, InterruptHandler, Trng};
8use rand_core::RngCore;
9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
10
11bind_interrupts!(
12 struct Irqs {
13 TRNG0 => InterruptHandler;
14 }
15);
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let config = Config::default();
20 let mut p = hal::init(config);
21
22 defmt::info!("TRNG example");
23
24 let mut trng = Trng::new_blocking_128(p.TRNG0.reborrow());
25 let rand = trng.blocking_next_u32();
26 defmt::info!("128-bit {}", rand);
27
28 drop(trng);
29
30 let mut trng = Trng::new_blocking_256(p.TRNG0.reborrow());
31 let rand = trng.blocking_next_u32();
32 defmt::info!("256-bit {}", rand);
33
34 drop(trng);
35
36 let mut trng = Trng::new_blocking_512(p.TRNG0.reborrow());
37 let rand = trng.blocking_next_u32();
38 defmt::info!("512-bit {}", rand);
39
40 drop(trng);
41
42 let config = trng::Config::default();
43 let mut trng = Trng::new_blocking_with_custom_config(p.TRNG0.reborrow(), config);
44
45 defmt::info!("========== BLOCKING ==========");
46
47 defmt::info!("Generate 10 u32");
48 for _ in 0..10 {
49 let rand = trng.blocking_next_u32();
50 defmt::info!("{}", rand);
51 }
52
53 defmt::info!("Generate 10 u64");
54 for _ in 0..10 {
55 let rand = trng.blocking_next_u64();
56 defmt::info!("{}", rand);
57 }
58
59 let mut buf = [0_u8; 256];
60
61 defmt::info!("Generate 10 256-byte buffers");
62 for _ in 0..10 {
63 trng.blocking_fill_bytes(&mut buf);
64 defmt::info!("{:02x}", buf);
65 }
66
67 defmt::info!("RngCore");
68
69 for _ in 0..10 {
70 defmt::info!("u32: {}", trng.next_u32());
71 defmt::info!("u64: {}", trng.next_u64());
72 }
73
74 drop(trng);
75
76 defmt::info!("========== ASYNC ==========");
77
78 let mut trng = Trng::new_with_custom_config(p.TRNG0.reborrow(), Irqs, config);
79
80 defmt::info!("Generate 10 u32");
81 for _ in 0..10 {
82 let rand = trng.async_next_u32().await.unwrap();
83 defmt::info!("{}", rand);
84 }
85
86 defmt::info!("Generate 10 u64");
87 for _ in 0..10 {
88 let rand = trng.async_next_u64().await.unwrap();
89 defmt::info!("{}", rand);
90 }
91
92 let mut buf = [0_u8; 256];
93
94 defmt::info!("Generate 10 256-byte buffers");
95 for _ in 0..10 {
96 trng.async_fill_bytes(&mut buf).await.unwrap();
97 defmt::info!("{:02x}", buf);
98 }
99
100 defmt::info!("RngCore");
101
102 for _ in 0..10 {
103 defmt::info!("u32: {}", trng.next_u32());
104 defmt::info!("u64: {}", trng.next_u64());
105 }
106}