From 0443134bc47918d2f8f0ede1b292b372629f8894 Mon Sep 17 00:00:00 2001 From: Bogdan Petru Chircu Mare Date: Fri, 31 Oct 2025 21:44:48 -0700 Subject: feat(mcxa276): initial HAL import --- examples/adc_interrupt.rs | 106 +++++++++++ examples/adc_polling.rs | 95 ++++++++++ examples/blink.rs | 93 ++++++++++ examples/common/mod.rs | 45 +++++ examples/hello.rs | 126 +++++++++++++ examples/lpuart_buffered.rs | 88 +++++++++ examples/lpuart_polling.rs | 67 +++++++ examples/ostimer_alarm.rs | 126 +++++++++++++ examples/ostimer_async.rs | 76 ++++++++ examples/ostimer_counter.rs | 142 +++++++++++++++ examples/ostimer_race_test.rs | 411 ++++++++++++++++++++++++++++++++++++++++++ examples/rtc_alarm.rs | 105 +++++++++++ examples/uart_interrupt.rs | 86 +++++++++ 13 files changed, 1566 insertions(+) create mode 100644 examples/adc_interrupt.rs create mode 100644 examples/adc_polling.rs create mode 100644 examples/blink.rs create mode 100644 examples/common/mod.rs create mode 100644 examples/hello.rs create mode 100644 examples/lpuart_buffered.rs create mode 100644 examples/lpuart_polling.rs create mode 100644 examples/ostimer_alarm.rs create mode 100644 examples/ostimer_async.rs create mode 100644 examples/ostimer_counter.rs create mode 100644 examples/ostimer_race_test.rs create mode 100644 examples/rtc_alarm.rs create mode 100644 examples/uart_interrupt.rs (limited to 'examples') diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs new file mode 100644 index 000000000..452eaae01 --- /dev/null +++ b/examples/adc_interrupt.rs @@ -0,0 +1,106 @@ +#![no_std] +#![no_main] + +use embassy_mcxa276 as hal; +use cortex_m; +use embassy_executor::Spawner; + +use hal::adc::{TriggerPriorityPolicy, LpadcConfig}; +use hal::pac::adc1::cfg::{Refsel, Pwrsel}; +use hal::pac::adc1::tctrl::{Tcmd}; +use hal::pac::adc1::cmdl1::{Adch, Mode}; +use hal::pac::adc1::ctrl::{CalAvgs}; + +use hal::uart; +mod common; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +use hal::bind_interrupts; +use hal::InterruptExt; + +bind_interrupts!(struct Irqs { + ADC1 => hal::adc::AdcHandler; +}); + +#[used] +#[no_mangle] +static KEEP_ADC: unsafe extern "C" fn() = ADC1; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + unsafe { + common::init_uart2(hal::pac()); + } + + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + + uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); + + unsafe { + common::init_adc(hal::pac()); + } + + + let adc_config = LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + }; + let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + + adc.do_offset_calibration(); + adc.do_auto_calibration(); + + let mut conv_command_config = adc.get_default_conv_command_config(); + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + adc.set_conv_command_config(1, &conv_command_config); + + let mut conv_trigger_config = adc.get_default_conv_trigger_config(); + conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; + conv_trigger_config.enable_hardware_trigger = false; + adc.set_conv_trigger_config(0, &conv_trigger_config); + + uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); + + adc.enable_interrupt(0x1); + + unsafe { + hal::interrupt::ADC1.enable(); + } + + unsafe { + cortex_m::interrupt::enable(); + } + + loop { + adc.do_software_trigger(1); + while !adc.is_interrupt_triggered() { + // Wait until the interrupt is triggered + } + uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); + //TBD need to print the value + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} \ No newline at end of file diff --git a/examples/adc_polling.rs b/examples/adc_polling.rs new file mode 100644 index 000000000..7cb728e91 --- /dev/null +++ b/examples/adc_polling.rs @@ -0,0 +1,95 @@ +#![no_std] +#![no_main] + +use embassy_mcxa276 as hal; + +use embassy_executor::Spawner; + +use hal::adc::{TriggerPriorityPolicy, LpadcConfig, ConvResult}; +use hal::pac::adc1::cfg::{Refsel, Pwrsel}; +use hal::pac::adc1::tctrl::{Tcmd}; +use hal::pac::adc1::cmdl1::{Adch, Mode}; +use hal::pac::adc1::ctrl::{CalAvgs}; + +use hal::uart; + +mod common; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +use core::fmt::Write; +use heapless::String; + + +const G_LPADC_RESULT_SHIFT: u32 = 0; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + unsafe { + common::init_uart2(hal::pac()); + } + + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + + uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); + + unsafe { + common::init_adc(hal::pac()); + } + + + let adc_config = LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + }; + let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + + adc.do_offset_calibration(); + adc.do_auto_calibration(); + + let mut conv_command_config = adc.get_default_conv_command_config(); + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + adc.set_conv_command_config(1, &conv_command_config); + + let mut conv_trigger_config = adc.get_default_conv_trigger_config(); + conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; + conv_trigger_config.enable_hardware_trigger = false; + adc.set_conv_trigger_config(0, &conv_trigger_config); + + uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); + + loop { + adc.do_software_trigger(1); + let mut result: Option = None; + while result.is_none() { + result = hal::adc::get_conv_result(); + } + let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; + let mut buf: String<16> = String::new(); // adjust size as needed + write!(buf, "\r\nvalue: {}\r\n", value).unwrap(); + uart.write_str_blocking(&buf); + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} \ No newline at end of file diff --git a/examples/blink.rs b/examples/blink.rs new file mode 100644 index 000000000..6289ac14e --- /dev/null +++ b/examples/blink.rs @@ -0,0 +1,93 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa276 as hal; +use embassy_time::{Duration, Timer}; +use hal::gpio::pins::PIO3_18; +use hal::gpio::{Level, Output}; + +mod common; + +use embassy_mcxa276::bind_interrupts; + +// Bind only OS_EVENT for timer interrupts +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + + // Board-style init: enable LED GPIO/PORT clocks used by blink + unsafe { + common::init_led(hal::pac()); + } + // Initialize OSTIMER for async timing + unsafe { + common::init_ostimer0(hal::pac()); + } + + // Initialize embassy-time global driver backed by OSTIMER0 + hal::ostimer::time_driver::init( + hal::config::Config::default().time_interrupt_priority, + 1_000_000, + ); + + // Configure LED pin for GPIO mode + PIO3_18::set_mux_gpio(); + + let mut led = Output::new(PIO3_18::degrade(), Level::High); + + // Complex blinking pattern: SOS in Morse code + // S: ... (3 short) + // O: --- (3 long) + // S: ... (3 short) + // With pauses between letters and words + + loop { + // S: three short blinks + for _ in 0..3 { + led.set_low(); + Timer::after(Duration::from_millis(150)).await; + led.set_high(); + Timer::after(Duration::from_millis(150)).await; + } + + // Pause between letters + Timer::after(Duration::from_millis(300)).await; + + // O: three long blinks + for _ in 0..3 { + led.set_low(); + Timer::after(Duration::from_millis(450)).await; + led.set_high(); + Timer::after(Duration::from_millis(150)).await; + } + + // Pause between letters + Timer::after(Duration::from_millis(300)).await; + + // S: three short blinks + for _ in 0..3 { + led.set_low(); + Timer::after(Duration::from_millis(150)).await; + led.set_high(); + Timer::after(Duration::from_millis(150)).await; + } + + // Long pause between words (SOS repeats) + Timer::after(Duration::from_millis(1000)).await; + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/common/mod.rs b/examples/common/mod.rs new file mode 100644 index 000000000..7ada4c456 --- /dev/null +++ b/examples/common/mod.rs @@ -0,0 +1,45 @@ +//! Shared board-specific helpers for the FRDM-MCXA276 examples. +//! These live with the examples so the HAL stays generic. + +use embassy_mcxa276 as hal; +use hal::{clocks, pins, reset}; + +/// Initialize clocks and pin muxing for UART2 debug console. +/// Safe to call multiple times; writes are idempotent for our use. +#[allow(dead_code)] +pub unsafe fn init_uart2(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_uart2_port2(p); + reset::release_reset_port2(p); + reset::release_reset_lpuart2(p); + pins::configure_uart2_pins_port2(); + clocks::select_uart2_clock(p); +} + +/// Initialize clocks for the LED GPIO/PORT used by the blink example. +#[allow(dead_code)] +pub unsafe fn init_led(p: &hal::pac::Peripherals) { + clocks::enable_led_port(p); + reset::release_reset_gpio3(p); + reset::release_reset_port3(p); +} + +/// Initialize clocks for OSTIMER0 (1 MHz source). +#[allow(dead_code)] +pub unsafe fn init_ostimer0(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_ostimer0(p); + reset::release_reset_ostimer0(p); + clocks::select_ostimer0_clock_1m(p); +} + +/// Initialize clocks and pin muxing for ADC. +#[allow(dead_code)] +pub unsafe fn init_adc(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_adc(p); + reset::release_reset_port1(p); + reset::release_reset_adc1(p); + pins::configure_adc_pins(); + clocks::select_adc_clock(p); +} diff --git a/examples/hello.rs b/examples/hello.rs new file mode 100644 index 000000000..591bf2460 --- /dev/null +++ b/examples/hello.rs @@ -0,0 +1,126 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa276 as hal; +use hal::uart; + +mod common; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +/// Simple helper to write a byte as hex to UART +fn write_hex_byte(uart: &hal::uart::Uart, byte: u8) { + const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; + uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); + uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + #[cfg(feature = "defmt")] + defmt::info!("boot"); + + // Board-level init for UART2 clocks and pins. + unsafe { + common::init_uart2(hal::pac()); + } + + // Get UART source frequency from clock configuration + // Using hardcoded frequency for now - dynamic detection may have issues + let src = 12_000_000; // FRO_LF_DIV at 12MHz with DIV=0 + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + + // Print welcome message before any async delays to guarantee early console output + uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); + uart.write_str_blocking("Available commands:\r\n"); + uart.write_str_blocking(" help - Show this help\r\n"); + uart.write_str_blocking(" echo - Echo back the text\r\n"); + uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); + uart.write_str_blocking("Type a command: "); + + let mut buffer = [0u8; 64]; + let mut buf_idx = 0; + + loop { + // Read a byte from UART + let byte = uart.read_byte_blocking(); + + // Echo the character back + if byte == b'\r' || byte == b'\n' { + // Enter pressed - process command + uart.write_str_blocking("\r\n"); + + if buf_idx > 0 { + let command = &buffer[0..buf_idx]; + + if command == b"help" { + uart.write_str_blocking("Available commands:\r\n"); + uart.write_str_blocking(" help - Show this help\r\n"); + uart.write_str_blocking(" echo - Echo back the text\r\n"); + uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); + } else if command.starts_with(b"echo ") && command.len() > 5 { + uart.write_str_blocking("Echo: "); + uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or("")); + uart.write_str_blocking("\r\n"); + } else if command.starts_with(b"hex ") && command.len() > 4 { + // Parse the byte value + let num_str = &command[4..]; + if let Ok(num) = parse_u8(num_str) { + uart.write_str_blocking("Hex: 0x"); + write_hex_byte(&uart, num); + uart.write_str_blocking("\r\n"); + } else { + uart.write_str_blocking("Invalid number for hex command\r\n"); + } + } else if command.len() > 0 { + uart.write_str_blocking("Unknown command: "); + uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); + uart.write_str_blocking("\r\n"); + } + } + + // Reset buffer and prompt + buf_idx = 0; + uart.write_str_blocking("Type a command: "); + } else if byte == 8 || byte == 127 { + // Backspace + if buf_idx > 0 { + buf_idx -= 1; + uart.write_str_blocking("\x08 \x08"); // Erase character + } + } else if buf_idx < buffer.len() - 1 { + // Regular character + buffer[buf_idx] = byte; + buf_idx += 1; + uart.write_byte(byte); + } + } +} + +/// Simple parser for u8 from ASCII bytes +fn parse_u8(bytes: &[u8]) -> Result { + let mut result = 0u8; + for &b in bytes { + if b >= b'0' && b <= b'9' { + result = result.checked_mul(10).ok_or(())?; + result = result.checked_add(b - b'0').ok_or(())?; + } else { + return Err(()); + } + } + Ok(result) +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs new file mode 100644 index 000000000..88f256096 --- /dev/null +++ b/examples/lpuart_buffered.rs @@ -0,0 +1,88 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa276 as hal; +use embassy_mcxa276::interrupt::typelevel::Handler; +use embassy_mcxa276::lpuart; +use embassy_mcxa276::lpuart::buffered::BufferedLpuart; + +use embedded_io_async::{Read, Write}; + +use embassy_mcxa276::bind_interrupts; + +mod common; + +// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver +bind_interrupts!(struct Irqs { + LPUART2 => lpuart::buffered::BufferedInterruptHandler::; +}); + +// Wrapper function for the interrupt handler +unsafe extern "C" fn lpuart2_handler() { + lpuart::buffered::BufferedInterruptHandler::::on_interrupt(); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + let p2 = lpuart::lib::init(); + + unsafe { + hal::interrupt::install_irq_handler(mcxa276_pac::Interrupt::LPUART2, lpuart2_handler); + } + + // Configure NVIC for LPUART2 + hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); + + unsafe { + common::init_uart2(hal::pac()); + common::init_ostimer0(hal::pac()); + } + + // UART configuration (enable both TX and RX) + let config = lpuart::Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + rx_fifo_watermark: 0, + tx_fifo_watermark: 0, + ..Default::default() + }; + + let mut tx_buf = [0u8; 256]; + let mut rx_buf = [0u8; 256]; + + // Create a buffered LPUART2 instance with both TX and RX + let mut uart = BufferedLpuart::new( + p2.LPUART2, + p2.PIO2_2, // TX pin + p2.PIO2_3, // RX pin + Irqs, + &mut tx_buf, + &mut rx_buf, + config, + ) + .unwrap(); + + // Split into TX and RX parts + let (tx, rx) = uart.split_ref(); + + tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); + tx.write(b"Type characters to echo them back.\r\n") + .await + .unwrap(); + + // Echo loop + let mut buf = [0u8; 4]; + loop { + rx.read_exact(&mut buf[..]).await.unwrap(); + tx.write_all(&buf[..]).await.unwrap(); + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/lpuart_polling.rs b/examples/lpuart_polling.rs new file mode 100644 index 000000000..c83c959e8 --- /dev/null +++ b/examples/lpuart_polling.rs @@ -0,0 +1,67 @@ +#![no_std] +#![no_main] + +use crate::hal::lpuart::{lib, Config, Lpuart}; +use embassy_executor::Spawner; +use embassy_mcxa276 as hal; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +mod common; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + let p2 = lib::init(); + + #[cfg(feature = "defmt")] + defmt::info!("boot"); + + // Board-level init for UART2 clocks and pins. + unsafe { + common::init_uart2(hal::pac()); + } + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + let lpuart = Lpuart::new_blocking( + p2.LPUART2, // Peripheral + p2.PIO2_2, // TX pin + p2.PIO2_3, // RX pin + config, + ) + .unwrap(); + + // Split into separate TX and RX parts + let (mut tx, mut rx) = lpuart.split(); + + // Write hello messages + tx.blocking_write(b"Hello world.\r\n").unwrap(); + tx.blocking_write(b"Echoing. Type characters...\r\n") + .unwrap(); + + // Echo loop + loop { + let mut buf = [0u8; 1]; + rx.blocking_read(&mut buf).unwrap(); + tx.blocking_write(&buf).unwrap(); + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/ostimer_alarm.rs b/examples/ostimer_alarm.rs new file mode 100644 index 000000000..823e37c15 --- /dev/null +++ b/examples/ostimer_alarm.rs @@ -0,0 +1,126 @@ +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; +use cortex_m; +use embassy_executor::Spawner; +use embassy_mcxa276 as hal; +use hal::uart; + +mod common; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +use embassy_mcxa276::bind_interrupts; + +// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +// Global flag for alarm callback +static ALARM_FLAG: AtomicBool = AtomicBool::new(false); + +// Alarm callback function +fn alarm_callback() { + ALARM_FLAG.store(true, Ordering::Release); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + // Enable/clock OSTIMER0 and UART2 before touching their registers + unsafe { + common::init_ostimer0(hal::pac()); + } + unsafe { + common::init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + uart.write_str_blocking("OSTIMER Alarm Example\n"); + + // Initialize embassy-time global driver backed by OSTIMER0 + hal::ostimer::time_driver::init( + hal::config::Config::default().time_interrupt_priority, + 1_000_000, + ); + + // Create OSTIMER instance + let config = hal::ostimer::Config { + init_match_max: true, + clock_frequency_hz: 1_000_000, // 1MHz + }; + let ostimer = hal::ostimer::Ostimer::::new(p.OSTIMER0, config, hal::pac()); + + // Create alarm with callback + let alarm = hal::ostimer::Alarm::new() + .with_callback(alarm_callback) + .with_flag(&ALARM_FLAG); + + uart.write_str_blocking("Scheduling alarm for 2 seconds...\n"); + + // Schedule alarm to expire in 2 seconds (2,000,000 microseconds) + let scheduled = ostimer.schedule_alarm_delay(&alarm, 2_000_000); + if scheduled { + uart.write_str_blocking("Alarm scheduled successfully\n"); + } else { + uart.write_str_blocking("Failed to schedule alarm (would exceed timer capacity)\n"); + return; + } + + // Wait for alarm to expire + loop { + // Check if alarm has expired + if ALARM_FLAG.load(Ordering::Acquire) { + uart.write_str_blocking("Alarm expired! Callback executed.\n"); + break; + } + + // Busy wait - don't use Timer::after_millis as it interferes with alarm MATCH + for _ in 0..100000 { + cortex_m::asm::nop(); + } + } + + // Demonstrate canceling an alarm + uart.write_str_blocking("Scheduling another alarm for 3 seconds...\n"); + ALARM_FLAG.store(false, Ordering::Release); // Reset flag + + let scheduled = ostimer.schedule_alarm_delay(&alarm, 3_000_000); + if scheduled { + uart.write_str_blocking("Alarm scheduled. Waiting 1 second then canceling...\n"); + + // Wait 1 second + embassy_time::Timer::after_millis(1000).await; + + // Cancel the alarm + ostimer.cancel_alarm(&alarm); + uart.write_str_blocking("Alarm canceled\n"); + + // Check immediately if alarm flag is set + if !ALARM_FLAG.load(Ordering::Acquire) { + uart.write_str_blocking("Alarm was successfully canceled\n"); + } else { + uart.write_str_blocking("Alarm fired despite cancellation\n"); + } + } + + uart.write_str_blocking("Example complete\n"); +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/ostimer_async.rs b/examples/ostimer_async.rs new file mode 100644 index 000000000..181ce58ef --- /dev/null +++ b/examples/ostimer_async.rs @@ -0,0 +1,76 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa276 as hal; +use hal::uart; + +mod common; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +use embassy_time::{Duration, Timer}; + +use embassy_mcxa276::bind_interrupts; + +// Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed. +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + + // Enable/clock OSTIMER0 and UART2 before touching their registers + unsafe { + common::init_ostimer0(hal::pac()); + } + unsafe { + common::init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); + uart.write_str_blocking("boot\n"); + + // Avoid mass NVIC writes here; DefaultHandler now safely returns. + + // Initialize embassy-time global driver backed by OSTIMER0 (re-enables OS_EVENT with priority) + // The bind_interrupts! macro handles handler binding automatically + + // Initialize OSTIMER with default 1MHz frequency + // Adjust this value to match your actual OSTIMER clock frequency + hal::ostimer::time_driver::init( + hal::config::Config::default().time_interrupt_priority, + 1_000_000, + ); + + // Removed force-pend; rely on real hardware match to trigger OS_EVENT. + + // Log using defmt if enabled + #[cfg(feature = "defmt")] + defmt::info!("OSTIMER async example starting..."); + + loop { + #[cfg(feature = "defmt")] + defmt::info!("tick"); + #[cfg(not(feature = "defmt"))] + uart.write_str_blocking("tick\n"); + Timer::after(Duration::from_millis(1000)).await; + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/ostimer_counter.rs b/examples/ostimer_counter.rs new file mode 100644 index 000000000..3af0f03f2 --- /dev/null +++ b/examples/ostimer_counter.rs @@ -0,0 +1,142 @@ +//! # OSTIMER Counter Reading and Reset Example +//! +//! This example demonstrates the new timer counter reading and reset functionality +//! of the OSTIMER driver. + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::{Duration, Timer}; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +use embassy_mcxa276 as hal; +use hal::bind_interrupts; + +mod common; + +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(Default::default()); + + // Enable/clock OSTIMER0 and UART2 before touching their registers + unsafe { + common::init_ostimer0(hal::pac()); + } + unsafe { + common::init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + + uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); + + // Initialize the OSTIMER time driver + hal::ostimer::time_driver::init( + hal::interrupt::Priority::from(3), + 1_000_000, // 1MHz clock + ); + + // Create OSTIMER instance + let ostimer = hal::ostimer::Ostimer::::new( + p.OSTIMER0, + hal::ostimer::Config { + init_match_max: true, + clock_frequency_hz: 1_000_000, + }, + hal::pac(), + ); + + // Read initial counter value + let initial_counter = ostimer.now(); + uart.write_str_blocking("Initial counter value: "); + write_u64(&mut uart, initial_counter); + uart.write_str_blocking("\n"); + + // Wait a bit to let counter increment + Timer::after(Duration::from_millis(100)).await; + + // Read counter again + let counter_after_wait = ostimer.now(); + uart.write_str_blocking("Counter after 100ms wait: "); + write_u64(&mut uart, counter_after_wait); + uart.write_str_blocking("\n"); + uart.write_str_blocking("Difference: "); + write_u64(&mut uart, counter_after_wait - initial_counter); + uart.write_str_blocking(" ticks\n"); + + // Reset the timer + uart.write_str_blocking("Resetting timer...\n"); + ostimer.reset(hal::pac()); + + // Read counter after reset + let counter_after_reset = ostimer.now(); + uart.write_str_blocking("Counter after reset: "); + write_u64(&mut uart, counter_after_reset); + uart.write_str_blocking("\n"); + + // Wait again to verify timer is working + Timer::after(Duration::from_millis(50)).await; + + let final_counter = ostimer.now(); + uart.write_str_blocking("Counter after another 50ms: "); + write_u64(&mut uart, final_counter); + uart.write_str_blocking("\n"); + uart.write_str_blocking("Difference after reset: "); + write_u64(&mut uart, final_counter - counter_after_reset); + uart.write_str_blocking(" ticks\n"); + + uart.write_str_blocking("Example complete\n"); +} + +// Helper function to write a u64 value as decimal string +fn write_u64(uart: &mut hal::uart::Uart, value: u64) { + if value == 0 { + uart.write_str_blocking("0"); + return; + } + + let mut buffer = [0u8; 20]; // Enough for max u64 + let mut i = 0; + let mut v = value; + + while v > 0 { + buffer[i] = b'0' + (v % 10) as u8; + v /= 10; + i += 1; + } + + // Write digits in reverse order + while i > 0 { + i -= 1; + match buffer[i] { + b'0' => uart.write_str_blocking("0"), + b'1' => uart.write_str_blocking("1"), + b'2' => uart.write_str_blocking("2"), + b'3' => uart.write_str_blocking("3"), + b'4' => uart.write_str_blocking("4"), + b'5' => uart.write_str_blocking("5"), + b'6' => uart.write_str_blocking("6"), + b'7' => uart.write_str_blocking("7"), + b'8' => uart.write_str_blocking("8"), + b'9' => uart.write_str_blocking("9"), + _ => uart.write_str_blocking("?"), + } + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs new file mode 100644 index 000000000..4470b65fd --- /dev/null +++ b/examples/ostimer_race_test.rs @@ -0,0 +1,411 @@ +//! # OSTIMER Race Condition Test +//! +//! This example tests for race conditions in the OSTIMER driver by: +//! - Scheduling alarms sequentially (hardware limitation: only one at a time) +//! - Reading the counter during interrupt-heavy periods +//! - Testing concurrent timer operations +//! - Stress testing interrupt handling + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::{Duration, Timer}; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +use core::sync::atomic::{AtomicU32, Ordering}; +use embassy_mcxa276 as hal; +use hal::bind_interrupts; + +mod common; + +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +// Global counters for race condition detection +static ALARM_CALLBACK_COUNT: AtomicU32 = AtomicU32::new(0); +static INTERRUPT_COUNT: AtomicU32 = AtomicU32::new(0); +static RACE_DETECTED: AtomicU32 = AtomicU32::new(0); + +// Alarm callback function +fn alarm_callback() { + let _count = ALARM_CALLBACK_COUNT.fetch_add(1, Ordering::SeqCst); + INTERRUPT_COUNT.fetch_add(1, Ordering::SeqCst); + + // Simulate some work in the callback to increase chance of races + for _ in 0..10 { + cortex_m::asm::nop(); + } +} + +fn report_default_handler(uart: &mut hal::uart::Uart) { + let snapshot = hal::interrupt::default_handler_snapshot(); + if snapshot.count == 0 { + return; + } + + uart.write_str_blocking("WARNING: DefaultHandler executed "); + write_u32(uart, snapshot.count); + uart.write_str_blocking(" time(s). Vector="); + write_u32(uart, snapshot.vector as u32); + uart.write_str_blocking(" CFSR=0x"); + write_hex32(uart, snapshot.cfsr); + uart.write_str_blocking(" HFSR=0x"); + write_hex32(uart, snapshot.hfsr); + uart.write_str_blocking(" PC=0x"); + write_hex32(uart, snapshot.stacked_pc); + uart.write_str_blocking(" LR=0x"); + write_hex32(uart, snapshot.stacked_lr); + uart.write_str_blocking(" SP=0x"); + write_hex32(uart, snapshot.stacked_sp); + uart.write_str_blocking("\n"); + + hal::interrupt::clear_default_handler_snapshot(); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(Default::default()); + + // Enable/clock OSTIMER0 and UART2 before touching their registers + unsafe { + common::init_ostimer0(hal::pac()); + } + unsafe { + common::init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + + uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); + + // The bind_interrupts! macro handles handler binding automatically + + // Initialize the OSTIMER time driver FIRST + hal::ostimer::time_driver::init( + hal::interrupt::Priority::from(3), + 1_000_000, // 1MHz clock + ); + + uart.write_str_blocking("Time driver initialized\n"); + + // Create OSTIMER instance + let ostimer = hal::ostimer::Ostimer::::new( + p.OSTIMER0, + hal::ostimer::Config { + init_match_max: true, + clock_frequency_hz: 1_000_000, + }, + hal::pac(), + ); + + uart.write_str_blocking("OSTIMER instance created\n"); + + // Test 1: Sequential alarm scheduling (OSTIMER only supports one alarm at a time) + uart.write_str_blocking("Test 1: Sequential alarm scheduling...\n"); + test_rapid_alarms(&ostimer, &mut uart).await; + report_default_handler(&mut uart); + + // Test 2: Counter reading during interrupts + uart.write_str_blocking("Test 2: Counter reading during interrupts...\n"); + test_counter_reading_during_interrupts(&ostimer, &mut uart).await; + report_default_handler(&mut uart); + + // Test 3: Concurrent timer operations + uart.write_str_blocking("Test 3: Concurrent timer operations...\n"); + test_concurrent_operations(&ostimer, &mut uart).await; + report_default_handler(&mut uart); + + // Test 4: Timer reset during operation + uart.write_str_blocking("Test 4: Timer reset during operation...\n"); + test_reset_during_operation(&ostimer, &mut uart, hal::pac()).await; + report_default_handler(&mut uart); + + // Report results + uart.write_str_blocking("Race condition test complete\n"); + uart.write_str_blocking("Callback count: "); + write_u32(&mut uart, ALARM_CALLBACK_COUNT.load(Ordering::SeqCst)); + uart.write_str_blocking("\nInterrupt count: "); + write_u32(&mut uart, INTERRUPT_COUNT.load(Ordering::SeqCst)); + uart.write_str_blocking("\nRaces detected: "); + write_u32(&mut uart, RACE_DETECTED.load(Ordering::SeqCst)); + uart.write_str_blocking("\n"); +} + +// Test rapid alarm scheduling to stress interrupt handling +async fn test_rapid_alarms( + ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, + uart: &mut hal::uart::Uart, +) { + let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); + + // Schedule 10 alarms sequentially (OSTIMER only supports one alarm at a time) + for _i in 0..10 { + let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); + let delay_us = 1000; // 1ms delay for each alarm + if ostimer.schedule_alarm_delay(&alarm, delay_us) { + // Wait for this alarm to complete before scheduling the next + Timer::after(Duration::from_micros(delay_us + 100)).await; + report_default_handler(uart); + } else { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm (match not ready)\n"); + } + } + + // All alarms should have completed by now + let final_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); + let expected_count = initial_count + 10; + + if final_count != expected_count { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Expected "); + write_u32(uart, expected_count); + uart.write_str_blocking(" callbacks, got "); + write_u32(uart, final_count); + uart.write_str_blocking("\n"); + } else { + uart.write_str_blocking("PASS: All rapid alarms executed\n"); + } +} + +// Test reading counter while interrupts are firing +async fn test_counter_reading_during_interrupts( + ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, + uart: &mut hal::uart::Uart, +) { + let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); + + // Schedule an alarm that will fire soon + let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); + if !ostimer.schedule_alarm_delay(&alarm, 500) { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before counter stress\n"); + } + + // While alarm is pending, read the counter many times rapidly + // This tests if counter reading is atomic and doesn't get corrupted by interrupts + let mut last_counter = ostimer.now(); + let mut consistent_reads = 0; + let mut total_reads = 0; + + for _ in 0..1000 { + let current_counter = ostimer.now(); + total_reads += 1; + + // Check if counter is monotonically increasing (basic sanity check) + if current_counter >= last_counter { + consistent_reads += 1; + } + last_counter = current_counter; + + // Small delay between reads + for _ in 0..10 { + cortex_m::asm::nop(); + } + + report_default_handler(uart); + } + + // Wait for alarm to complete + Timer::after(Duration::from_millis(1)).await; + + let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); + + if consistent_reads == total_reads { + uart.write_str_blocking("PASS: Counter reading consistent during interrupts\n"); + } else { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Counter reading inconsistent: "); + write_u32(uart, consistent_reads); + uart.write_str_blocking("/"); + write_u32(uart, total_reads); + uart.write_str_blocking(" consistent\n"); + } + + if final_interrupt_count > initial_interrupt_count { + uart.write_str_blocking("PASS: Interrupt fired during counter reading test\n"); + } else { + uart.write_str_blocking("WARNING: No interrupt fired during counter reading test\n"); + } +} + +// Test concurrent timer operations (embassy-time + alarms) +async fn test_concurrent_operations( + ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, + uart: &mut hal::uart::Uart, +) { + let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); + + // Start an embassy-time timer + let timer_future = Timer::after(Duration::from_millis(2)); + + // Schedule an alarm that should fire before the timer + let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); + if !ostimer.schedule_alarm_delay(&alarm, 1000) { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking( + "ERROR: Failed to program OSTIMER alarm before concurrent operations\n", + ); + } + + // Wait for both to complete + timer_future.await; + + let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); + + if final_interrupt_count > initial_interrupt_count { + uart.write_str_blocking("PASS: Concurrent operations completed\n"); + } else { + uart.write_str_blocking("WARNING: No interrupts during concurrent operations\n"); + } +} + +// Test timer reset during active operations +async fn test_reset_during_operation( + ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, + uart: &mut hal::uart::Uart, + peripherals: &hal::pac::Peripherals, +) { + let initial_counter = ostimer.now(); + + // Schedule an alarm + let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); + if !ostimer.schedule_alarm_delay(&alarm, 2000) { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before reset test\n"); + } + + // Wait a bit then reset the timer + Timer::after(Duration::from_millis(1)).await; + ostimer.reset(peripherals); + + // Check counter after reset + let counter_after_reset = ostimer.now(); + + // Wait to see if the alarm still fires (it shouldn't after reset) + Timer::after(Duration::from_millis(2)).await; + + let final_counter = ostimer.now(); + + if counter_after_reset < initial_counter { + uart.write_str_blocking("PASS: Timer reset successful\n"); + } else { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Timer reset may have failed\n"); + } + + uart.write_str_blocking("Counter progression after reset: "); + write_u64(uart, initial_counter); + uart.write_str_blocking(" -> "); + write_u64(uart, counter_after_reset); + uart.write_str_blocking(" -> "); + write_u64(uart, final_counter); + uart.write_str_blocking("\n"); +} + +// Helper function to write a u32 value as decimal string +fn write_u32(uart: &mut hal::uart::Uart, value: u32) { + if value == 0 { + uart.write_str_blocking("0"); + return; + } + + let mut buffer = [0u8; 10]; // Enough for max u32 + let mut i = 0; + let mut v = value; + + while v > 0 { + buffer[i] = b'0' + (v % 10) as u8; + v /= 10; + i += 1; + } + + // Write digits in reverse order + while i > 0 { + i -= 1; + match buffer[i] { + b'0' => uart.write_str_blocking("0"), + b'1' => uart.write_str_blocking("1"), + b'2' => uart.write_str_blocking("2"), + b'3' => uart.write_str_blocking("3"), + b'4' => uart.write_str_blocking("4"), + b'5' => uart.write_str_blocking("5"), + b'6' => uart.write_str_blocking("6"), + b'7' => uart.write_str_blocking("7"), + b'8' => uart.write_str_blocking("8"), + b'9' => uart.write_str_blocking("9"), + _ => uart.write_str_blocking("?"), + } + } +} + +fn write_hex32(uart: &mut hal::uart::Uart, value: u32) { + let mut buf = [b'0'; 8]; + let mut tmp = value; + for i in (0..8).rev() { + let digit = (tmp & 0xF) as u8; + buf[i] = match digit { + 0..=9 => b'0' + digit, + 10..=15 => b'A' + (digit - 10), + _ => b'?', + }; + tmp >>= 4; + } + for b in &buf { + uart.write_byte(*b); + } +} + +// Helper function to write a u64 value as decimal string +fn write_u64(uart: &mut hal::uart::Uart, value: u64) { + if value == 0 { + uart.write_str_blocking("0"); + return; + } + + let mut buffer = [0u8; 20]; // Enough for max u64 + let mut i = 0; + let mut v = value; + + while v > 0 { + buffer[i] = b'0' + (v % 10) as u8; + v /= 10; + i += 1; + } + + // Write digits in reverse order + while i > 0 { + i -= 1; + match buffer[i] { + b'0' => uart.write_str_blocking("0"), + b'1' => uart.write_str_blocking("1"), + b'2' => uart.write_str_blocking("2"), + b'3' => uart.write_str_blocking("3"), + b'4' => uart.write_str_blocking("4"), + b'5' => uart.write_str_blocking("5"), + b'6' => uart.write_str_blocking("6"), + b'7' => uart.write_str_blocking("7"), + b'8' => uart.write_str_blocking("8"), + b'9' => uart.write_str_blocking("9"), + _ => uart.write_str_blocking("?"), + } + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/rtc_alarm.rs b/examples/rtc_alarm.rs new file mode 100644 index 000000000..8f4ff1623 --- /dev/null +++ b/examples/rtc_alarm.rs @@ -0,0 +1,105 @@ +#![no_std] +#![no_main] + + +use embassy_mcxa276 as hal; +use cortex_m; +use embassy_executor::Spawner; +use hal::rtc::{RtcDateTime, RtcInterruptEnable}; +use hal::uart; +use hal::InterruptExt; + +mod common; + +type MyRtc = hal::rtc::Rtc; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +use embassy_mcxa276::bind_interrupts; +bind_interrupts!(struct Irqs { + RTC => hal::rtc::RtcHandler; +}); + +#[used] +#[no_mangle] +static KEEP_RTC: unsafe extern "C" fn() = RTC; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + + let p = hal::init(hal::config::Config::default()); + + unsafe { + common::init_uart2(hal::pac()); + } + + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + + uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n"); + + unsafe { hal::clocks::init_fro16k(hal::pac()) }; + + let rtc_config = hal::rtc::get_default_config(); + + let rtc = MyRtc::new(p.RTC0, rtc_config); + + let now = RtcDateTime { + year: 2025, + month: 10, + day: 15, + hour: 14, + minute: 30, + second: 0, + }; + + + rtc.stop(); + + uart.write_str_blocking("Time set to: 2025-10-15 14:30:00\r\n"); + rtc.set_datetime(now); + + let mut alarm = now; + alarm.second += 10; + + rtc.set_alarm(alarm); + uart.write_str_blocking("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)\r\n"); + + rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); + + unsafe { + hal::interrupt::RTC.enable(); + } + + unsafe { + cortex_m::interrupt::enable(); + } + + rtc.start(); + + uart.write_str_blocking("RTC started, waiting for alarm...\r\n"); + + loop { + if rtc.is_alarm_triggered() { + uart.write_str_blocking("\r\n*** ALARM TRIGGERED! ***\r\n"); + break; + } + } + + uart.write_str_blocking("Example complete - Test PASSED!\r\n"); + + loop { + + } +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/examples/uart_interrupt.rs b/examples/uart_interrupt.rs new file mode 100644 index 000000000..b309ce973 --- /dev/null +++ b/examples/uart_interrupt.rs @@ -0,0 +1,86 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa276 as hal; +use hal::interrupt::typelevel::Handler; +use hal::uart; + +mod common; + +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use defmt_rtt as _; +#[cfg(feature = "defmt")] +use panic_probe as _; +#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] +use rtt_target as _; + +use embassy_mcxa276::bind_interrupts; + +// Bind LPUART2 interrupt to our handler +bind_interrupts!(struct Irqs { + LPUART2 => hal::uart::UartInterruptHandler; +}); + +#[used] +#[no_mangle] +static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2; + +// Wrapper function for the interrupt handler +unsafe extern "C" fn lpuart2_handler() { + hal::uart::UartInterruptHandler::on_interrupt(); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + + // Enable/clock UART2 before touching its registers + unsafe { + common::init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); + + // Configure LPUART2 interrupt for UART operation BEFORE any UART usage + hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3)); + + // Manually install the interrupt handler + unsafe { + hal::interrupt::LPUART2.install_handler(lpuart2_handler); + } + + // Print welcome message + uart.write_str_blocking("UART interrupt echo demo starting...\r\n"); + uart.write_str_blocking("Type characters to echo them back.\r\n"); + + // Log using defmt if enabled + #[cfg(feature = "defmt")] + defmt::info!("UART interrupt echo demo starting..."); + + loop { + // Check if we have received any data + if uart.rx_data_available() { + if let Some(byte) = uart.try_read_byte() { + // Echo it back + uart.write_byte(byte); + uart.write_str_blocking(" (received)\r\n"); + } + } else { + // No data available, wait a bit before checking again + cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz + } + } +} + +#[cfg(feature = "defmt")] +#[export_name = "_defmt_timestamp"] +fn defmt_timestamp(_fmt: defmt::Formatter<'_>) { + // Return empty timestamp for now +} + +#[cfg(not(feature = "defmt"))] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} -- cgit From a71eff2e1cea55b393e793c023b8e51e5cc369a1 Mon Sep 17 00:00:00 2001 From: Bogdan Petru Chircu Mare Date: Thu, 6 Nov 2025 21:51:56 -0800 Subject: Fix uart_interrupt example: enable RX interrupts in peripheral The uart_interrupt example was not echoing received characters because the RX interrupt enable bit (RIE) was not being set in the LPUART control register. The NVIC interrupt was configured and the handler was installed, but the peripheral itself was not generating interrupts. Added uart.enable_rx_interrupts() call to enable RX data interrupts in the LPUART2 peripheral before entering the main loop. --- examples/uart_interrupt.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/uart_interrupt.rs b/examples/uart_interrupt.rs index b309ce973..85743bb64 100644 --- a/examples/uart_interrupt.rs +++ b/examples/uart_interrupt.rs @@ -45,9 +45,11 @@ async fn main(_spawner: Spawner) { // Configure LPUART2 interrupt for UART operation BEFORE any UART usage hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3)); - // Manually install the interrupt handler + // Manually install the interrupt handler and enable RX IRQs in the peripheral unsafe { hal::interrupt::LPUART2.install_handler(lpuart2_handler); + // Enable RX interrupts so the handler actually fires on incoming bytes + uart.enable_rx_interrupts(); } // Print welcome message -- cgit From cb2ac2790f4b037056f9571abeb4d62360199426 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 7 Nov 2025 10:06:55 -0800 Subject: Reduce number of features We don't need features for drivers that always exist. Signed-off-by: Felipe Balbi --- examples/adc_interrupt.rs | 54 +++++++++++++++++-------------------------- examples/adc_polling.rs | 47 ++++++++++++++----------------------- examples/blink.rs | 6 ----- examples/hello.rs | 14 +---------- examples/lpuart_buffered.rs | 6 ----- examples/lpuart_polling.rs | 16 ++----------- examples/ostimer_alarm.rs | 16 +++---------- examples/ostimer_async.rs | 20 ++-------------- examples/ostimer_counter.rs | 16 +++---------- examples/ostimer_race_test.rs | 17 +++----------- examples/rtc_alarm.rs | 25 ++++---------------- examples/uart_interrupt.rs | 21 +---------------- 12 files changed, 58 insertions(+), 200 deletions(-) (limited to 'examples') diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs index 452eaae01..26afd70b4 100644 --- a/examples/adc_interrupt.rs +++ b/examples/adc_interrupt.rs @@ -1,28 +1,23 @@ #![no_std] #![no_main] -use embassy_mcxa276 as hal; use cortex_m; use embassy_executor::Spawner; +use embassy_mcxa276 as hal; -use hal::adc::{TriggerPriorityPolicy, LpadcConfig}; -use hal::pac::adc1::cfg::{Refsel, Pwrsel}; -use hal::pac::adc1::tctrl::{Tcmd}; +use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; +use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; -use hal::pac::adc1::ctrl::{CalAvgs}; +use hal::pac::adc1::ctrl::CalAvgs; +use hal::pac::adc1::tctrl::Tcmd; use hal::uart; mod common; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; +use {defmt_rtt as _, panic_probe as _}; -use hal::bind_interrupts; use hal::InterruptExt; +use hal::bind_interrupts; bind_interrupts!(struct Irqs { ADC1 => hal::adc::AdcHandler; @@ -40,7 +35,7 @@ async fn main(_spawner: Spawner) { common::init_uart2(hal::pac()); } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); @@ -48,19 +43,18 @@ async fn main(_spawner: Spawner) { unsafe { common::init_adc(hal::pac()); } - - + let adc_config = LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::Average128, - enable_analog_preliminary: true, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option3, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, }; let adc = hal::adc::Adc::::new(p.ADC1, adc_config); @@ -78,7 +72,7 @@ async fn main(_spawner: Spawner) { adc.set_conv_trigger_config(0, &conv_trigger_config); uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); - + adc.enable_interrupt(0x1); unsafe { @@ -92,15 +86,9 @@ async fn main(_spawner: Spawner) { loop { adc.do_software_trigger(1); while !adc.is_interrupt_triggered() { - // Wait until the interrupt is triggered + // Wait until the interrupt is triggered } uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); //TBD need to print the value } } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} \ No newline at end of file diff --git a/examples/adc_polling.rs b/examples/adc_polling.rs index 7cb728e91..90be87c3f 100644 --- a/examples/adc_polling.rs +++ b/examples/adc_polling.rs @@ -5,27 +5,21 @@ use embassy_mcxa276 as hal; use embassy_executor::Spawner; -use hal::adc::{TriggerPriorityPolicy, LpadcConfig, ConvResult}; -use hal::pac::adc1::cfg::{Refsel, Pwrsel}; -use hal::pac::adc1::tctrl::{Tcmd}; +use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; +use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; -use hal::pac::adc1::ctrl::{CalAvgs}; +use hal::pac::adc1::ctrl::CalAvgs; +use hal::pac::adc1::tctrl::Tcmd; use hal::uart; mod common; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; +use {defmt_rtt as _, panic_probe as _}; use core::fmt::Write; use heapless::String; - const G_LPADC_RESULT_SHIFT: u32 = 0; #[embassy_executor::main] @@ -44,19 +38,18 @@ async fn main(_spawner: Spawner) { unsafe { common::init_adc(hal::pac()); } - - + let adc_config = LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::Average128, - enable_analog_preliminary: true, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option3, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, }; let adc = hal::adc::Adc::::new(p.ADC1, adc_config); @@ -74,7 +67,7 @@ async fn main(_spawner: Spawner) { adc.set_conv_trigger_config(0, &conv_trigger_config); uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); - + loop { adc.do_software_trigger(1); let mut result: Option = None; @@ -87,9 +80,3 @@ async fn main(_spawner: Spawner) { uart.write_str_blocking(&buf); } } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} \ No newline at end of file diff --git a/examples/blink.rs b/examples/blink.rs index 6289ac14e..a9b6e7093 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -85,9 +85,3 @@ async fn main(_spawner: Spawner) { Timer::after(Duration::from_millis(1000)).await; } } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/examples/hello.rs b/examples/hello.rs index 591bf2460..e39adaced 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -7,12 +7,7 @@ use hal::uart; mod common; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; +use {defmt_rtt as _, panic_probe as _}; /// Simple helper to write a byte as hex to UART fn write_hex_byte(uart: &hal::uart::Uart, byte: u8) { @@ -25,7 +20,6 @@ fn write_hex_byte(uart: &hal::uart::Uart, byte: u8) { async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); - #[cfg(feature = "defmt")] defmt::info!("boot"); // Board-level init for UART2 clocks and pins. @@ -118,9 +112,3 @@ fn parse_u8(bytes: &[u8]) -> Result { } Ok(result) } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs index 88f256096..d0d4d2ee0 100644 --- a/examples/lpuart_buffered.rs +++ b/examples/lpuart_buffered.rs @@ -80,9 +80,3 @@ async fn main(_spawner: Spawner) { tx.write_all(&buf[..]).await.unwrap(); } } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/examples/lpuart_polling.rs b/examples/lpuart_polling.rs index c83c959e8..f9172de40 100644 --- a/examples/lpuart_polling.rs +++ b/examples/lpuart_polling.rs @@ -1,16 +1,11 @@ #![no_std] #![no_main] -use crate::hal::lpuart::{lib, Config, Lpuart}; +use crate::hal::lpuart::{Config, Lpuart, lib}; use embassy_executor::Spawner; use embassy_mcxa276 as hal; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; +use {defmt_rtt as _, panic_probe as _}; mod common; @@ -19,7 +14,6 @@ async fn main(_spawner: Spawner) { let _p = hal::init(hal::config::Config::default()); let p2 = lib::init(); - #[cfg(feature = "defmt")] defmt::info!("boot"); // Board-level init for UART2 clocks and pins. @@ -59,9 +53,3 @@ async fn main(_spawner: Spawner) { tx.blocking_write(&buf).unwrap(); } } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/examples/ostimer_alarm.rs b/examples/ostimer_alarm.rs index 823e37c15..eca669509 100644 --- a/examples/ostimer_alarm.rs +++ b/examples/ostimer_alarm.rs @@ -9,12 +9,7 @@ use hal::uart; mod common; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; +use {defmt_rtt as _, panic_probe as _}; use embassy_mcxa276::bind_interrupts; @@ -61,7 +56,8 @@ async fn main(_spawner: Spawner) { init_match_max: true, clock_frequency_hz: 1_000_000, // 1MHz }; - let ostimer = hal::ostimer::Ostimer::::new(p.OSTIMER0, config, hal::pac()); + let ostimer = + hal::ostimer::Ostimer::::new(p.OSTIMER0, config, hal::pac()); // Create alarm with callback let alarm = hal::ostimer::Alarm::new() @@ -118,9 +114,3 @@ async fn main(_spawner: Spawner) { uart.write_str_blocking("Example complete\n"); } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/examples/ostimer_async.rs b/examples/ostimer_async.rs index 181ce58ef..37fb3b3d1 100644 --- a/examples/ostimer_async.rs +++ b/examples/ostimer_async.rs @@ -7,16 +7,9 @@ use hal::uart; mod common; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; - -use embassy_time::{Duration, Timer}; - use embassy_mcxa276::bind_interrupts; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; // Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed. bind_interrupts!(struct Irqs { @@ -57,20 +50,11 @@ async fn main(_spawner: Spawner) { // Removed force-pend; rely on real hardware match to trigger OS_EVENT. // Log using defmt if enabled - #[cfg(feature = "defmt")] defmt::info!("OSTIMER async example starting..."); loop { - #[cfg(feature = "defmt")] defmt::info!("tick"); - #[cfg(not(feature = "defmt"))] uart.write_str_blocking("tick\n"); Timer::after(Duration::from_millis(1000)).await; } } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/examples/ostimer_counter.rs b/examples/ostimer_counter.rs index 3af0f03f2..1f5bdf434 100644 --- a/examples/ostimer_counter.rs +++ b/examples/ostimer_counter.rs @@ -9,12 +9,7 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; +use {defmt_rtt as _, panic_probe as _}; use embassy_mcxa276 as hal; use hal::bind_interrupts; @@ -37,7 +32,8 @@ async fn main(_spawner: Spawner) { common::init_uart2(hal::pac()); } let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + let mut uart = + hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); @@ -134,9 +130,3 @@ fn write_u64(uart: &mut hal::uart::Uart, value: u64) { } } } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs index 4470b65fd..072310309 100644 --- a/examples/ostimer_race_test.rs +++ b/examples/ostimer_race_test.rs @@ -12,16 +12,10 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; - use core::sync::atomic::{AtomicU32, Ordering}; use embassy_mcxa276 as hal; use hal::bind_interrupts; +use {defmt_rtt as _, panic_probe as _}; mod common; @@ -86,7 +80,8 @@ async fn main(_spawner: Spawner) { common::init_uart2(hal::pac()); } let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + let mut uart = + hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); @@ -403,9 +398,3 @@ fn write_u64(uart: &mut hal::uart::Uart, value: u64) { } } } - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/examples/rtc_alarm.rs b/examples/rtc_alarm.rs index 8f4ff1623..a190b8ba5 100644 --- a/examples/rtc_alarm.rs +++ b/examples/rtc_alarm.rs @@ -1,26 +1,21 @@ #![no_std] #![no_main] - -use embassy_mcxa276 as hal; use cortex_m; use embassy_executor::Spawner; +use embassy_mcxa276 as hal; +use hal::InterruptExt; use hal::rtc::{RtcDateTime, RtcInterruptEnable}; use hal::uart; -use hal::InterruptExt; mod common; type MyRtc = hal::rtc::Rtc; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; +use {defmt_rtt as _, panic_probe as _}; use embassy_mcxa276::bind_interrupts; + bind_interrupts!(struct Irqs { RTC => hal::rtc::RtcHandler; }); @@ -31,7 +26,6 @@ static KEEP_RTC: unsafe extern "C" fn() = RTC; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); unsafe { @@ -58,12 +52,11 @@ async fn main(_spawner: Spawner) { second: 0, }; - rtc.stop(); uart.write_str_blocking("Time set to: 2025-10-15 14:30:00\r\n"); rtc.set_datetime(now); - + let mut alarm = now; alarm.second += 10; @@ -92,14 +85,6 @@ async fn main(_spawner: Spawner) { } uart.write_str_blocking("Example complete - Test PASSED!\r\n"); - - loop { - - } -} -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} } diff --git a/examples/uart_interrupt.rs b/examples/uart_interrupt.rs index 85743bb64..bd734f859 100644 --- a/examples/uart_interrupt.rs +++ b/examples/uart_interrupt.rs @@ -8,14 +8,8 @@ use hal::uart; mod common; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use defmt_rtt as _; -#[cfg(feature = "defmt")] -use panic_probe as _; -#[cfg(all(feature = "defmt", feature = "defmt-rtt"))] -use rtt_target as _; - use embassy_mcxa276::bind_interrupts; +use {defmt_rtt as _, panic_probe as _}; // Bind LPUART2 interrupt to our handler bind_interrupts!(struct Irqs { @@ -57,7 +51,6 @@ async fn main(_spawner: Spawner) { uart.write_str_blocking("Type characters to echo them back.\r\n"); // Log using defmt if enabled - #[cfg(feature = "defmt")] defmt::info!("UART interrupt echo demo starting..."); loop { @@ -74,15 +67,3 @@ async fn main(_spawner: Spawner) { } } } - -#[cfg(feature = "defmt")] -#[export_name = "_defmt_timestamp"] -fn defmt_timestamp(_fmt: defmt::Formatter<'_>) { - // Return empty timestamp for now -} - -#[cfg(not(feature = "defmt"))] -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} -- cgit From e75066820ad320495ca70570641c90d75247b19b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 7 Nov 2025 10:07:33 -0800 Subject: cargo +nightly fmt Signed-off-by: Felipe Balbi --- examples/adc_interrupt.rs | 9 ++------- examples/adc_polling.rs | 9 +++------ examples/blink.rs | 5 +---- examples/lpuart_buffered.rs | 9 ++------- examples/lpuart_polling.rs | 8 +++----- examples/ostimer_alarm.rs | 15 +++++---------- examples/ostimer_async.rs | 5 +---- examples/ostimer_counter.rs | 8 ++------ examples/ostimer_race_test.rs | 14 +++++--------- examples/rtc_alarm.rs | 9 +++------ 10 files changed, 27 insertions(+), 64 deletions(-) (limited to 'examples') diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs index 26afd70b4..f0df3196c 100644 --- a/examples/adc_interrupt.rs +++ b/examples/adc_interrupt.rs @@ -1,24 +1,19 @@ #![no_std] #![no_main] -use cortex_m; use embassy_executor::Spawner; -use embassy_mcxa276 as hal; - use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; - use hal::uart; +use {cortex_m, embassy_mcxa276 as hal}; mod common; +use hal::{bind_interrupts, InterruptExt}; use {defmt_rtt as _, panic_probe as _}; -use hal::InterruptExt; -use hal::bind_interrupts; - bind_interrupts!(struct Irqs { ADC1 => hal::adc::AdcHandler; }); diff --git a/examples/adc_polling.rs b/examples/adc_polling.rs index 90be87c3f..561500d2d 100644 --- a/examples/adc_polling.rs +++ b/examples/adc_polling.rs @@ -1,24 +1,21 @@ #![no_std] #![no_main] -use embassy_mcxa276 as hal; - use embassy_executor::Spawner; - +use embassy_mcxa276 as hal; use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; - use hal::uart; mod common; -use {defmt_rtt as _, panic_probe as _}; - use core::fmt::Write; + use heapless::String; +use {defmt_rtt as _, panic_probe as _}; const G_LPADC_RESULT_SHIFT: u32 = 0; diff --git a/examples/blink.rs b/examples/blink.rs index a9b6e7093..564353d5c 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -34,10 +34,7 @@ async fn main(_spawner: Spawner) { } // Initialize embassy-time global driver backed by OSTIMER0 - hal::ostimer::time_driver::init( - hal::config::Config::default().time_interrupt_priority, - 1_000_000, - ); + hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); // Configure LED pin for GPIO mode PIO3_18::set_mux_gpio(); diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs index d0d4d2ee0..30ba3f333 100644 --- a/examples/lpuart_buffered.rs +++ b/examples/lpuart_buffered.rs @@ -4,13 +4,10 @@ use embassy_executor::Spawner; use embassy_mcxa276 as hal; use embassy_mcxa276::interrupt::typelevel::Handler; -use embassy_mcxa276::lpuart; use embassy_mcxa276::lpuart::buffered::BufferedLpuart; - +use embassy_mcxa276::{bind_interrupts, lpuart}; use embedded_io_async::{Read, Write}; -use embassy_mcxa276::bind_interrupts; - mod common; // Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver @@ -69,9 +66,7 @@ async fn main(_spawner: Spawner) { let (tx, rx) = uart.split_ref(); tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); - tx.write(b"Type characters to echo them back.\r\n") - .await - .unwrap(); + tx.write(b"Type characters to echo them back.\r\n").await.unwrap(); // Echo loop let mut buf = [0u8; 4]; diff --git a/examples/lpuart_polling.rs b/examples/lpuart_polling.rs index f9172de40..067c7eb53 100644 --- a/examples/lpuart_polling.rs +++ b/examples/lpuart_polling.rs @@ -1,11 +1,10 @@ #![no_std] #![no_main] -use crate::hal::lpuart::{Config, Lpuart, lib}; use embassy_executor::Spawner; -use embassy_mcxa276 as hal; +use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; -use {defmt_rtt as _, panic_probe as _}; +use crate::hal::lpuart::{lib, Config, Lpuart}; mod common; @@ -43,8 +42,7 @@ async fn main(_spawner: Spawner) { // Write hello messages tx.blocking_write(b"Hello world.\r\n").unwrap(); - tx.blocking_write(b"Echoing. Type characters...\r\n") - .unwrap(); + tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap(); // Echo loop loop { diff --git a/examples/ostimer_alarm.rs b/examples/ostimer_alarm.rs index eca669509..78ca4bbc5 100644 --- a/examples/ostimer_alarm.rs +++ b/examples/ostimer_alarm.rs @@ -2,16 +2,15 @@ #![no_main] use core::sync::atomic::{AtomicBool, Ordering}; -use cortex_m; + use embassy_executor::Spawner; -use embassy_mcxa276 as hal; use hal::uart; +use {cortex_m, embassy_mcxa276 as hal}; mod common; -use {defmt_rtt as _, panic_probe as _}; - use embassy_mcxa276::bind_interrupts; +use {defmt_rtt as _, panic_probe as _}; // Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. bind_interrupts!(struct Irqs { @@ -46,18 +45,14 @@ async fn main(_spawner: Spawner) { uart.write_str_blocking("OSTIMER Alarm Example\n"); // Initialize embassy-time global driver backed by OSTIMER0 - hal::ostimer::time_driver::init( - hal::config::Config::default().time_interrupt_priority, - 1_000_000, - ); + hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); // Create OSTIMER instance let config = hal::ostimer::Config { init_match_max: true, clock_frequency_hz: 1_000_000, // 1MHz }; - let ostimer = - hal::ostimer::Ostimer::::new(p.OSTIMER0, config, hal::pac()); + let ostimer = hal::ostimer::Ostimer::::new(p.OSTIMER0, config, hal::pac()); // Create alarm with callback let alarm = hal::ostimer::Alarm::new() diff --git a/examples/ostimer_async.rs b/examples/ostimer_async.rs index 37fb3b3d1..27e14e022 100644 --- a/examples/ostimer_async.rs +++ b/examples/ostimer_async.rs @@ -42,10 +42,7 @@ async fn main(_spawner: Spawner) { // Initialize OSTIMER with default 1MHz frequency // Adjust this value to match your actual OSTIMER clock frequency - hal::ostimer::time_driver::init( - hal::config::Config::default().time_interrupt_priority, - 1_000_000, - ); + hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); // Removed force-pend; rely on real hardware match to trigger OS_EVENT. diff --git a/examples/ostimer_counter.rs b/examples/ostimer_counter.rs index 1f5bdf434..e95140a88 100644 --- a/examples/ostimer_counter.rs +++ b/examples/ostimer_counter.rs @@ -8,11 +8,8 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; - -use {defmt_rtt as _, panic_probe as _}; - -use embassy_mcxa276 as hal; use hal::bind_interrupts; +use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; mod common; @@ -32,8 +29,7 @@ async fn main(_spawner: Spawner) { common::init_uart2(hal::pac()); } let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let mut uart = - hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs index 072310309..a637b6353 100644 --- a/examples/ostimer_race_test.rs +++ b/examples/ostimer_race_test.rs @@ -9,13 +9,12 @@ #![no_std] #![no_main] +use core::sync::atomic::{AtomicU32, Ordering}; + use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; - -use core::sync::atomic::{AtomicU32, Ordering}; -use embassy_mcxa276 as hal; use hal::bind_interrupts; -use {defmt_rtt as _, panic_probe as _}; +use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; mod common; @@ -80,8 +79,7 @@ async fn main(_spawner: Spawner) { common::init_uart2(hal::pac()); } let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let mut uart = - hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); @@ -250,9 +248,7 @@ async fn test_concurrent_operations( let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); if !ostimer.schedule_alarm_delay(&alarm, 1000) { RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking( - "ERROR: Failed to program OSTIMER alarm before concurrent operations\n", - ); + uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before concurrent operations\n"); } // Wait for both to complete diff --git a/examples/rtc_alarm.rs b/examples/rtc_alarm.rs index a190b8ba5..c27fd4c55 100644 --- a/examples/rtc_alarm.rs +++ b/examples/rtc_alarm.rs @@ -1,20 +1,17 @@ #![no_std] #![no_main] -use cortex_m; use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use hal::InterruptExt; use hal::rtc::{RtcDateTime, RtcInterruptEnable}; -use hal::uart; +use hal::{uart, InterruptExt}; +use {cortex_m, embassy_mcxa276 as hal}; mod common; type MyRtc = hal::rtc::Rtc; -use {defmt_rtt as _, panic_probe as _}; - use embassy_mcxa276::bind_interrupts; +use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { RTC => hal::rtc::RtcHandler; -- cgit From 110a5eb4e58ecee5bc45bd47c3366ea241587e1b Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 12 Nov 2025 17:16:19 +0100 Subject: Remove example feats, get examples building No CI, but this can be checked with `cargo check --all --examples`, which now succeeds. --- examples/adc_interrupt.rs | 8 ++++---- examples/adc_polling.rs | 8 ++++---- examples/common/mod.rs | 10 +++++----- examples/lpuart_buffered.rs | 2 +- examples/ostimer_race_test.rs | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) (limited to 'examples') diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs index f0df3196c..dc82cfd30 100644 --- a/examples/adc_interrupt.rs +++ b/examples/adc_interrupt.rs @@ -3,11 +3,11 @@ use embassy_executor::Spawner; use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; -use hal::pac::adc1::cfg::{Pwrsel, Refsel}; -use hal::pac::adc1::cmdl1::{Adch, Mode}; -use hal::pac::adc1::ctrl::CalAvgs; -use hal::pac::adc1::tctrl::Tcmd; use hal::uart; +use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; +use mcxa_pac::adc1::cmdl1::{Adch, Mode}; +use mcxa_pac::adc1::ctrl::CalAvgs; +use mcxa_pac::adc1::tctrl::Tcmd; use {cortex_m, embassy_mcxa276 as hal}; mod common; diff --git a/examples/adc_polling.rs b/examples/adc_polling.rs index 561500d2d..4b5f9422d 100644 --- a/examples/adc_polling.rs +++ b/examples/adc_polling.rs @@ -4,11 +4,11 @@ use embassy_executor::Spawner; use embassy_mcxa276 as hal; use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; -use hal::pac::adc1::cfg::{Pwrsel, Refsel}; -use hal::pac::adc1::cmdl1::{Adch, Mode}; -use hal::pac::adc1::ctrl::CalAvgs; -use hal::pac::adc1::tctrl::Tcmd; use hal::uart; +use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; +use mcxa_pac::adc1::cmdl1::{Adch, Mode}; +use mcxa_pac::adc1::ctrl::CalAvgs; +use mcxa_pac::adc1::tctrl::Tcmd; mod common; diff --git a/examples/common/mod.rs b/examples/common/mod.rs index 7ada4c456..8c52c8e86 100644 --- a/examples/common/mod.rs +++ b/examples/common/mod.rs @@ -1,13 +1,13 @@ //! Shared board-specific helpers for the FRDM-MCXA276 examples. //! These live with the examples so the HAL stays generic. -use embassy_mcxa276 as hal; use hal::{clocks, pins, reset}; +use {embassy_mcxa276 as hal, panic_probe as _}; /// Initialize clocks and pin muxing for UART2 debug console. /// Safe to call multiple times; writes are idempotent for our use. #[allow(dead_code)] -pub unsafe fn init_uart2(p: &hal::pac::Peripherals) { +pub unsafe fn init_uart2(p: &mcxa_pac::Peripherals) { clocks::ensure_frolf_running(p); clocks::enable_uart2_port2(p); reset::release_reset_port2(p); @@ -18,7 +18,7 @@ pub unsafe fn init_uart2(p: &hal::pac::Peripherals) { /// Initialize clocks for the LED GPIO/PORT used by the blink example. #[allow(dead_code)] -pub unsafe fn init_led(p: &hal::pac::Peripherals) { +pub unsafe fn init_led(p: &mcxa_pac::Peripherals) { clocks::enable_led_port(p); reset::release_reset_gpio3(p); reset::release_reset_port3(p); @@ -26,7 +26,7 @@ pub unsafe fn init_led(p: &hal::pac::Peripherals) { /// Initialize clocks for OSTIMER0 (1 MHz source). #[allow(dead_code)] -pub unsafe fn init_ostimer0(p: &hal::pac::Peripherals) { +pub unsafe fn init_ostimer0(p: &mcxa_pac::Peripherals) { clocks::ensure_frolf_running(p); clocks::enable_ostimer0(p); reset::release_reset_ostimer0(p); @@ -35,7 +35,7 @@ pub unsafe fn init_ostimer0(p: &hal::pac::Peripherals) { /// Initialize clocks and pin muxing for ADC. #[allow(dead_code)] -pub unsafe fn init_adc(p: &hal::pac::Peripherals) { +pub unsafe fn init_adc(p: &mcxa_pac::Peripherals) { clocks::ensure_frolf_running(p); clocks::enable_adc(p); reset::release_reset_port1(p); diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs index 30ba3f333..35d311143 100644 --- a/examples/lpuart_buffered.rs +++ b/examples/lpuart_buffered.rs @@ -26,7 +26,7 @@ async fn main(_spawner: Spawner) { let p2 = lpuart::lib::init(); unsafe { - hal::interrupt::install_irq_handler(mcxa276_pac::Interrupt::LPUART2, lpuart2_handler); + hal::interrupt::install_irq_handler(mcxa_pac::Interrupt::LPUART2, lpuart2_handler); } // Configure NVIC for LPUART2 diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs index a637b6353..368a3e52f 100644 --- a/examples/ostimer_race_test.rs +++ b/examples/ostimer_race_test.rs @@ -267,7 +267,7 @@ async fn test_concurrent_operations( async fn test_reset_during_operation( ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, uart: &mut hal::uart::Uart, - peripherals: &hal::pac::Peripherals, + peripherals: &mcxa_pac::Peripherals, ) { let initial_counter = ostimer.now(); -- cgit From 77b2c602a60e41c7c977003a6d40367ac285930e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 13 Nov 2025 13:17:44 -0800 Subject: Move examples to a package of their own (#16) * Move examples to a package of their own * cargo +nightly fmt * Add missing safety doc * cargo clippy examples * fmt again --------- Co-authored-by: Felipe Balbi --- examples/.cargo/config.toml | 17 + examples/.gitignore | 1 + examples/Cargo.lock | 625 ++++++++++++++++++++++++++++++++++ examples/Cargo.toml | 21 ++ examples/adc_interrupt.rs | 89 ----- examples/adc_polling.rs | 79 ----- examples/blink.rs | 84 ----- examples/build.rs | 20 ++ examples/common/mod.rs | 45 --- examples/hello.rs | 114 ------- examples/lpuart_buffered.rs | 77 ----- examples/lpuart_polling.rs | 53 --- examples/memory.x | 5 + examples/ostimer_alarm.rs | 111 ------ examples/ostimer_async.rs | 57 ---- examples/ostimer_counter.rs | 128 ------- examples/ostimer_race_test.rs | 396 --------------------- examples/rtc_alarm.rs | 87 ----- examples/src/bin/adc_interrupt.rs | 86 +++++ examples/src/bin/adc_polling.rs | 76 +++++ examples/src/bin/blink.rs | 78 +++++ examples/src/bin/hello.rs | 111 ++++++ examples/src/bin/lpuart_buffered.rs | 76 +++++ examples/src/bin/lpuart_polling.rs | 51 +++ examples/src/bin/ostimer_alarm.rs | 106 ++++++ examples/src/bin/ostimer_async.rs | 52 +++ examples/src/bin/ostimer_counter.rs | 125 +++++++ examples/src/bin/ostimer_race_test.rs | 393 +++++++++++++++++++++ examples/src/bin/rtc_alarm.rs | 84 +++++ examples/src/bin/uart_interrupt.rs | 66 ++++ examples/src/common/mod.rs | 45 +++ examples/src/lib.rs | 63 ++++ examples/uart_interrupt.rs | 69 ---- 33 files changed, 2101 insertions(+), 1389 deletions(-) create mode 100644 examples/.cargo/config.toml create mode 100644 examples/.gitignore create mode 100644 examples/Cargo.lock create mode 100644 examples/Cargo.toml delete mode 100644 examples/adc_interrupt.rs delete mode 100644 examples/adc_polling.rs delete mode 100644 examples/blink.rs create mode 100644 examples/build.rs delete mode 100644 examples/common/mod.rs delete mode 100644 examples/hello.rs delete mode 100644 examples/lpuart_buffered.rs delete mode 100644 examples/lpuart_polling.rs create mode 100644 examples/memory.x delete mode 100644 examples/ostimer_alarm.rs delete mode 100644 examples/ostimer_async.rs delete mode 100644 examples/ostimer_counter.rs delete mode 100644 examples/ostimer_race_test.rs delete mode 100644 examples/rtc_alarm.rs create mode 100644 examples/src/bin/adc_interrupt.rs create mode 100644 examples/src/bin/adc_polling.rs create mode 100644 examples/src/bin/blink.rs create mode 100644 examples/src/bin/hello.rs create mode 100644 examples/src/bin/lpuart_buffered.rs create mode 100644 examples/src/bin/lpuart_polling.rs create mode 100644 examples/src/bin/ostimer_alarm.rs create mode 100644 examples/src/bin/ostimer_async.rs create mode 100644 examples/src/bin/ostimer_counter.rs create mode 100644 examples/src/bin/ostimer_race_test.rs create mode 100644 examples/src/bin/rtc_alarm.rs create mode 100644 examples/src/bin/uart_interrupt.rs create mode 100644 examples/src/common/mod.rs create mode 100644 examples/src/lib.rs delete mode 100644 examples/uart_interrupt.rs (limited to 'examples') diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml new file mode 100644 index 000000000..ecb11be64 --- /dev/null +++ b/examples/.cargo/config.toml @@ -0,0 +1,17 @@ +[target.thumbv8m.main-none-eabihf] +runner = 'probe-rs run --chip MCXA276 --preverify --verify' + +rustflags = [ + "-C", "linker=flip-link", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x + # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + "-C", "link-arg=--nmagic", +] + +[build] +target = "thumbv8m.main-none-eabihf" # Cortex-M33 + +[env] +DEFMT_LOG = "trace" diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 000000000..2f7896d1d --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/examples/Cargo.lock b/examples/Cargo.lock new file mode 100644 index 000000000..b774aff97 --- /dev/null +++ b/examples/Cargo.lock @@ -0,0 +1,625 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "defmt-rtt" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e" +dependencies = [ + "critical-section", + "defmt", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "embassy-embedded-hal" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" +dependencies = [ + "embassy-futures", + "embassy-hal-internal", + "embassy-sync", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-executor" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" +dependencies = [ + "cortex-m", + "critical-section", + "document-features", + "embassy-executor-macros", + "embassy-executor-timer-queue", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "embassy-executor-timer-queue" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" + +[[package]] +name = "embassy-futures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" + +[[package]] +name = "embassy-hal-internal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" +dependencies = [ + "cortex-m", + "critical-section", + "num-traits", +] + +[[package]] +name = "embassy-mcxa" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt", + "embassy-embedded-hal", + "embassy-executor", + "embassy-hal-internal", + "embassy-sync", + "embassy-time", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-nb", + "embedded-io", + "embedded-io-async", + "heapless 0.8.0", + "mcxa-pac", + "nb 1.1.0", + "paste", +] + +[[package]] +name = "embassy-mcxa-examples" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt", + "defmt-rtt", + "embassy-embedded-hal", + "embassy-executor", + "embassy-mcxa", + "embassy-sync", + "embassy-time", + "embassy-time-driver", + "embedded-io-async", + "heapless 0.9.2", + "panic-probe", +] + +[[package]] +name = "embassy-sync" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-core", + "futures-sink", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-time" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-core", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" +dependencies = [ + "document-features", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal 1.0.0", + "nb 1.1.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "embedded-io-async" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] +name = "embedded-storage-async" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" +dependencies = [ + "embedded-storage", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heapless" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "mcxa-pac" +version = "0.1.0" +source = "git+https://github.com/OpenDevicePartnership/mcxa-pac?rev=3ab4c868f75a9240bb8fdce24982d34f2273aabf#3ab4c868f75a9240bb8fdce24982d34f2273aabf" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "panic-probe" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a" +dependencies = [ + "cortex-m", + "defmt", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 000000000..6b100de42 --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "embassy-mcxa-examples" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } +cortex-m-rt = { version = "0.7", features = ["device"] } +critical-section = "1.2.0" +defmt = "1.0" +defmt-rtt = "1.0" +embassy-embedded-hal = "0.5.0" +embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } +embassy-mcxa = { path = "../", features = ["defmt", "rt", "unstable-pac"] } +embassy-sync = "0.7.2" +embassy-time = "0.5.0" +embassy-time-driver = "0.2.1" +embedded-io-async = "0.6.1" +heapless = "0.9.2" +panic-probe = { version = "1.0", features = ["print-defmt"] } diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs deleted file mode 100644 index dc82cfd30..000000000 --- a/examples/adc_interrupt.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; -use hal::uart; -use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; -use mcxa_pac::adc1::cmdl1::{Adch, Mode}; -use mcxa_pac::adc1::ctrl::CalAvgs; -use mcxa_pac::adc1::tctrl::Tcmd; -use {cortex_m, embassy_mcxa276 as hal}; -mod common; - -use hal::{bind_interrupts, InterruptExt}; -use {defmt_rtt as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - ADC1 => hal::adc::AdcHandler; -}); - -#[used] -#[no_mangle] -static KEEP_ADC: unsafe extern "C" fn() = ADC1; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - unsafe { - common::init_uart2(hal::pac()); - } - - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); - - uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); - - unsafe { - common::init_adc(hal::pac()); - } - - let adc_config = LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::Average128, - enable_analog_preliminary: true, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option3, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, - }; - let adc = hal::adc::Adc::::new(p.ADC1, adc_config); - - adc.do_offset_calibration(); - adc.do_auto_calibration(); - - let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits; - adc.set_conv_command_config(1, &conv_command_config); - - let mut conv_trigger_config = adc.get_default_conv_trigger_config(); - conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; - conv_trigger_config.enable_hardware_trigger = false; - adc.set_conv_trigger_config(0, &conv_trigger_config); - - uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); - - adc.enable_interrupt(0x1); - - unsafe { - hal::interrupt::ADC1.enable(); - } - - unsafe { - cortex_m::interrupt::enable(); - } - - loop { - adc.do_software_trigger(1); - while !adc.is_interrupt_triggered() { - // Wait until the interrupt is triggered - } - uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); - //TBD need to print the value - } -} diff --git a/examples/adc_polling.rs b/examples/adc_polling.rs deleted file mode 100644 index 4b5f9422d..000000000 --- a/examples/adc_polling.rs +++ /dev/null @@ -1,79 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; -use hal::uart; -use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; -use mcxa_pac::adc1::cmdl1::{Adch, Mode}; -use mcxa_pac::adc1::ctrl::CalAvgs; -use mcxa_pac::adc1::tctrl::Tcmd; - -mod common; - -use core::fmt::Write; - -use heapless::String; -use {defmt_rtt as _, panic_probe as _}; - -const G_LPADC_RESULT_SHIFT: u32 = 0; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - unsafe { - common::init_uart2(hal::pac()); - } - - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); - - uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); - - unsafe { - common::init_adc(hal::pac()); - } - - let adc_config = LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::Average128, - enable_analog_preliminary: true, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option3, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, - }; - let adc = hal::adc::Adc::::new(p.ADC1, adc_config); - - adc.do_offset_calibration(); - adc.do_auto_calibration(); - - let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits; - adc.set_conv_command_config(1, &conv_command_config); - - let mut conv_trigger_config = adc.get_default_conv_trigger_config(); - conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; - conv_trigger_config.enable_hardware_trigger = false; - adc.set_conv_trigger_config(0, &conv_trigger_config); - - uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); - - loop { - adc.do_software_trigger(1); - let mut result: Option = None; - while result.is_none() { - result = hal::adc::get_conv_result(); - } - let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; - let mut buf: String<16> = String::new(); // adjust size as needed - write!(buf, "\r\nvalue: {}\r\n", value).unwrap(); - uart.write_str_blocking(&buf); - } -} diff --git a/examples/blink.rs b/examples/blink.rs deleted file mode 100644 index 564353d5c..000000000 --- a/examples/blink.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use embassy_time::{Duration, Timer}; -use hal::gpio::pins::PIO3_18; -use hal::gpio::{Level, Output}; - -mod common; - -use embassy_mcxa276::bind_interrupts; - -// Bind only OS_EVENT for timer interrupts -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); - - // Board-style init: enable LED GPIO/PORT clocks used by blink - unsafe { - common::init_led(hal::pac()); - } - // Initialize OSTIMER for async timing - unsafe { - common::init_ostimer0(hal::pac()); - } - - // Initialize embassy-time global driver backed by OSTIMER0 - hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); - - // Configure LED pin for GPIO mode - PIO3_18::set_mux_gpio(); - - let mut led = Output::new(PIO3_18::degrade(), Level::High); - - // Complex blinking pattern: SOS in Morse code - // S: ... (3 short) - // O: --- (3 long) - // S: ... (3 short) - // With pauses between letters and words - - loop { - // S: three short blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(150)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Pause between letters - Timer::after(Duration::from_millis(300)).await; - - // O: three long blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(450)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Pause between letters - Timer::after(Duration::from_millis(300)).await; - - // S: three short blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(150)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Long pause between words (SOS repeats) - Timer::after(Duration::from_millis(1000)).await; - } -} diff --git a/examples/build.rs b/examples/build.rs new file mode 100644 index 000000000..f076bba9f --- /dev/null +++ b/examples/build.rs @@ -0,0 +1,20 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + // Generate memory.x - put "FLASH" at start of RAM, RAM after "FLASH" + // cortex-m-rt expects FLASH for code, RAM for data/bss/stack + // Both are in RAM, but separated to satisfy cortex-m-rt's expectations + // MCXA256 has 128KB RAM total + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/examples/common/mod.rs b/examples/common/mod.rs deleted file mode 100644 index 8c52c8e86..000000000 --- a/examples/common/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Shared board-specific helpers for the FRDM-MCXA276 examples. -//! These live with the examples so the HAL stays generic. - -use hal::{clocks, pins, reset}; -use {embassy_mcxa276 as hal, panic_probe as _}; - -/// Initialize clocks and pin muxing for UART2 debug console. -/// Safe to call multiple times; writes are idempotent for our use. -#[allow(dead_code)] -pub unsafe fn init_uart2(p: &mcxa_pac::Peripherals) { - clocks::ensure_frolf_running(p); - clocks::enable_uart2_port2(p); - reset::release_reset_port2(p); - reset::release_reset_lpuart2(p); - pins::configure_uart2_pins_port2(); - clocks::select_uart2_clock(p); -} - -/// Initialize clocks for the LED GPIO/PORT used by the blink example. -#[allow(dead_code)] -pub unsafe fn init_led(p: &mcxa_pac::Peripherals) { - clocks::enable_led_port(p); - reset::release_reset_gpio3(p); - reset::release_reset_port3(p); -} - -/// Initialize clocks for OSTIMER0 (1 MHz source). -#[allow(dead_code)] -pub unsafe fn init_ostimer0(p: &mcxa_pac::Peripherals) { - clocks::ensure_frolf_running(p); - clocks::enable_ostimer0(p); - reset::release_reset_ostimer0(p); - clocks::select_ostimer0_clock_1m(p); -} - -/// Initialize clocks and pin muxing for ADC. -#[allow(dead_code)] -pub unsafe fn init_adc(p: &mcxa_pac::Peripherals) { - clocks::ensure_frolf_running(p); - clocks::enable_adc(p); - reset::release_reset_port1(p); - reset::release_reset_adc1(p); - pins::configure_adc_pins(); - clocks::select_adc_clock(p); -} diff --git a/examples/hello.rs b/examples/hello.rs deleted file mode 100644 index e39adaced..000000000 --- a/examples/hello.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use hal::uart; - -mod common; - -use {defmt_rtt as _, panic_probe as _}; - -/// Simple helper to write a byte as hex to UART -fn write_hex_byte(uart: &hal::uart::Uart, byte: u8) { - const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; - uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); - uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("boot"); - - // Board-level init for UART2 clocks and pins. - unsafe { - common::init_uart2(hal::pac()); - } - - // Get UART source frequency from clock configuration - // Using hardcoded frequency for now - dynamic detection may have issues - let src = 12_000_000; // FRO_LF_DIV at 12MHz with DIV=0 - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); - - // Print welcome message before any async delays to guarantee early console output - uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); - uart.write_str_blocking("Available commands:\r\n"); - uart.write_str_blocking(" help - Show this help\r\n"); - uart.write_str_blocking(" echo - Echo back the text\r\n"); - uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); - uart.write_str_blocking("Type a command: "); - - let mut buffer = [0u8; 64]; - let mut buf_idx = 0; - - loop { - // Read a byte from UART - let byte = uart.read_byte_blocking(); - - // Echo the character back - if byte == b'\r' || byte == b'\n' { - // Enter pressed - process command - uart.write_str_blocking("\r\n"); - - if buf_idx > 0 { - let command = &buffer[0..buf_idx]; - - if command == b"help" { - uart.write_str_blocking("Available commands:\r\n"); - uart.write_str_blocking(" help - Show this help\r\n"); - uart.write_str_blocking(" echo - Echo back the text\r\n"); - uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); - } else if command.starts_with(b"echo ") && command.len() > 5 { - uart.write_str_blocking("Echo: "); - uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or("")); - uart.write_str_blocking("\r\n"); - } else if command.starts_with(b"hex ") && command.len() > 4 { - // Parse the byte value - let num_str = &command[4..]; - if let Ok(num) = parse_u8(num_str) { - uart.write_str_blocking("Hex: 0x"); - write_hex_byte(&uart, num); - uart.write_str_blocking("\r\n"); - } else { - uart.write_str_blocking("Invalid number for hex command\r\n"); - } - } else if command.len() > 0 { - uart.write_str_blocking("Unknown command: "); - uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); - uart.write_str_blocking("\r\n"); - } - } - - // Reset buffer and prompt - buf_idx = 0; - uart.write_str_blocking("Type a command: "); - } else if byte == 8 || byte == 127 { - // Backspace - if buf_idx > 0 { - buf_idx -= 1; - uart.write_str_blocking("\x08 \x08"); // Erase character - } - } else if buf_idx < buffer.len() - 1 { - // Regular character - buffer[buf_idx] = byte; - buf_idx += 1; - uart.write_byte(byte); - } - } -} - -/// Simple parser for u8 from ASCII bytes -fn parse_u8(bytes: &[u8]) -> Result { - let mut result = 0u8; - for &b in bytes { - if b >= b'0' && b <= b'9' { - result = result.checked_mul(10).ok_or(())?; - result = result.checked_add(b - b'0').ok_or(())?; - } else { - return Err(()); - } - } - Ok(result) -} diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs deleted file mode 100644 index 35d311143..000000000 --- a/examples/lpuart_buffered.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use embassy_mcxa276::interrupt::typelevel::Handler; -use embassy_mcxa276::lpuart::buffered::BufferedLpuart; -use embassy_mcxa276::{bind_interrupts, lpuart}; -use embedded_io_async::{Read, Write}; - -mod common; - -// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver -bind_interrupts!(struct Irqs { - LPUART2 => lpuart::buffered::BufferedInterruptHandler::; -}); - -// Wrapper function for the interrupt handler -unsafe extern "C" fn lpuart2_handler() { - lpuart::buffered::BufferedInterruptHandler::::on_interrupt(); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); - let p2 = lpuart::lib::init(); - - unsafe { - hal::interrupt::install_irq_handler(mcxa_pac::Interrupt::LPUART2, lpuart2_handler); - } - - // Configure NVIC for LPUART2 - hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); - - unsafe { - common::init_uart2(hal::pac()); - common::init_ostimer0(hal::pac()); - } - - // UART configuration (enable both TX and RX) - let config = lpuart::Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - rx_fifo_watermark: 0, - tx_fifo_watermark: 0, - ..Default::default() - }; - - let mut tx_buf = [0u8; 256]; - let mut rx_buf = [0u8; 256]; - - // Create a buffered LPUART2 instance with both TX and RX - let mut uart = BufferedLpuart::new( - p2.LPUART2, - p2.PIO2_2, // TX pin - p2.PIO2_3, // RX pin - Irqs, - &mut tx_buf, - &mut rx_buf, - config, - ) - .unwrap(); - - // Split into TX and RX parts - let (tx, rx) = uart.split_ref(); - - tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); - tx.write(b"Type characters to echo them back.\r\n").await.unwrap(); - - // Echo loop - let mut buf = [0u8; 4]; - loop { - rx.read_exact(&mut buf[..]).await.unwrap(); - tx.write_all(&buf[..]).await.unwrap(); - } -} diff --git a/examples/lpuart_polling.rs b/examples/lpuart_polling.rs deleted file mode 100644 index 067c7eb53..000000000 --- a/examples/lpuart_polling.rs +++ /dev/null @@ -1,53 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; - -use crate::hal::lpuart::{lib, Config, Lpuart}; - -mod common; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); - let p2 = lib::init(); - - defmt::info!("boot"); - - // Board-level init for UART2 clocks and pins. - unsafe { - common::init_uart2(hal::pac()); - } - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - ..Default::default() - }; - - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX - let lpuart = Lpuart::new_blocking( - p2.LPUART2, // Peripheral - p2.PIO2_2, // TX pin - p2.PIO2_3, // RX pin - config, - ) - .unwrap(); - - // Split into separate TX and RX parts - let (mut tx, mut rx) = lpuart.split(); - - // Write hello messages - tx.blocking_write(b"Hello world.\r\n").unwrap(); - tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap(); - - // Echo loop - loop { - let mut buf = [0u8; 1]; - rx.blocking_read(&mut buf).unwrap(); - tx.blocking_write(&buf).unwrap(); - } -} diff --git a/examples/memory.x b/examples/memory.x new file mode 100644 index 000000000..f4263a412 --- /dev/null +++ b/examples/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x20000000, LENGTH = 64K + RAM : ORIGIN = 0x20010000, LENGTH = 64K +} diff --git a/examples/ostimer_alarm.rs b/examples/ostimer_alarm.rs deleted file mode 100644 index 78ca4bbc5..000000000 --- a/examples/ostimer_alarm.rs +++ /dev/null @@ -1,111 +0,0 @@ -#![no_std] -#![no_main] - -use core::sync::atomic::{AtomicBool, Ordering}; - -use embassy_executor::Spawner; -use hal::uart; -use {cortex_m, embassy_mcxa276 as hal}; - -mod common; - -use embassy_mcxa276::bind_interrupts; -use {defmt_rtt as _, panic_probe as _}; - -// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -// Global flag for alarm callback -static ALARM_FLAG: AtomicBool = AtomicBool::new(false); - -// Alarm callback function -fn alarm_callback() { - ALARM_FLAG.store(true, Ordering::Release); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - // Enable/clock OSTIMER0 and UART2 before touching their registers - unsafe { - common::init_ostimer0(hal::pac()); - } - unsafe { - common::init_uart2(hal::pac()); - } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); - uart.write_str_blocking("OSTIMER Alarm Example\n"); - - // Initialize embassy-time global driver backed by OSTIMER0 - hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); - - // Create OSTIMER instance - let config = hal::ostimer::Config { - init_match_max: true, - clock_frequency_hz: 1_000_000, // 1MHz - }; - let ostimer = hal::ostimer::Ostimer::::new(p.OSTIMER0, config, hal::pac()); - - // Create alarm with callback - let alarm = hal::ostimer::Alarm::new() - .with_callback(alarm_callback) - .with_flag(&ALARM_FLAG); - - uart.write_str_blocking("Scheduling alarm for 2 seconds...\n"); - - // Schedule alarm to expire in 2 seconds (2,000,000 microseconds) - let scheduled = ostimer.schedule_alarm_delay(&alarm, 2_000_000); - if scheduled { - uart.write_str_blocking("Alarm scheduled successfully\n"); - } else { - uart.write_str_blocking("Failed to schedule alarm (would exceed timer capacity)\n"); - return; - } - - // Wait for alarm to expire - loop { - // Check if alarm has expired - if ALARM_FLAG.load(Ordering::Acquire) { - uart.write_str_blocking("Alarm expired! Callback executed.\n"); - break; - } - - // Busy wait - don't use Timer::after_millis as it interferes with alarm MATCH - for _ in 0..100000 { - cortex_m::asm::nop(); - } - } - - // Demonstrate canceling an alarm - uart.write_str_blocking("Scheduling another alarm for 3 seconds...\n"); - ALARM_FLAG.store(false, Ordering::Release); // Reset flag - - let scheduled = ostimer.schedule_alarm_delay(&alarm, 3_000_000); - if scheduled { - uart.write_str_blocking("Alarm scheduled. Waiting 1 second then canceling...\n"); - - // Wait 1 second - embassy_time::Timer::after_millis(1000).await; - - // Cancel the alarm - ostimer.cancel_alarm(&alarm); - uart.write_str_blocking("Alarm canceled\n"); - - // Check immediately if alarm flag is set - if !ALARM_FLAG.load(Ordering::Acquire) { - uart.write_str_blocking("Alarm was successfully canceled\n"); - } else { - uart.write_str_blocking("Alarm fired despite cancellation\n"); - } - } - - uart.write_str_blocking("Example complete\n"); -} diff --git a/examples/ostimer_async.rs b/examples/ostimer_async.rs deleted file mode 100644 index 27e14e022..000000000 --- a/examples/ostimer_async.rs +++ /dev/null @@ -1,57 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use hal::uart; - -mod common; - -use embassy_mcxa276::bind_interrupts; -use embassy_time::{Duration, Timer}; -use {defmt_rtt as _, panic_probe as _}; - -// Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed. -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); - - // Enable/clock OSTIMER0 and UART2 before touching their registers - unsafe { - common::init_ostimer0(hal::pac()); - } - unsafe { - common::init_uart2(hal::pac()); - } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); - uart.write_str_blocking("boot\n"); - - // Avoid mass NVIC writes here; DefaultHandler now safely returns. - - // Initialize embassy-time global driver backed by OSTIMER0 (re-enables OS_EVENT with priority) - // The bind_interrupts! macro handles handler binding automatically - - // Initialize OSTIMER with default 1MHz frequency - // Adjust this value to match your actual OSTIMER clock frequency - hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); - - // Removed force-pend; rely on real hardware match to trigger OS_EVENT. - - // Log using defmt if enabled - defmt::info!("OSTIMER async example starting..."); - - loop { - defmt::info!("tick"); - uart.write_str_blocking("tick\n"); - Timer::after(Duration::from_millis(1000)).await; - } -} diff --git a/examples/ostimer_counter.rs b/examples/ostimer_counter.rs deleted file mode 100644 index e95140a88..000000000 --- a/examples/ostimer_counter.rs +++ /dev/null @@ -1,128 +0,0 @@ -//! # OSTIMER Counter Reading and Reset Example -//! -//! This example demonstrates the new timer counter reading and reset functionality -//! of the OSTIMER driver. - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::{Duration, Timer}; -use hal::bind_interrupts; -use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; - -mod common; - -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(Default::default()); - - // Enable/clock OSTIMER0 and UART2 before touching their registers - unsafe { - common::init_ostimer0(hal::pac()); - } - unsafe { - common::init_uart2(hal::pac()); - } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); - - uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); - - // Initialize the OSTIMER time driver - hal::ostimer::time_driver::init( - hal::interrupt::Priority::from(3), - 1_000_000, // 1MHz clock - ); - - // Create OSTIMER instance - let ostimer = hal::ostimer::Ostimer::::new( - p.OSTIMER0, - hal::ostimer::Config { - init_match_max: true, - clock_frequency_hz: 1_000_000, - }, - hal::pac(), - ); - - // Read initial counter value - let initial_counter = ostimer.now(); - uart.write_str_blocking("Initial counter value: "); - write_u64(&mut uart, initial_counter); - uart.write_str_blocking("\n"); - - // Wait a bit to let counter increment - Timer::after(Duration::from_millis(100)).await; - - // Read counter again - let counter_after_wait = ostimer.now(); - uart.write_str_blocking("Counter after 100ms wait: "); - write_u64(&mut uart, counter_after_wait); - uart.write_str_blocking("\n"); - uart.write_str_blocking("Difference: "); - write_u64(&mut uart, counter_after_wait - initial_counter); - uart.write_str_blocking(" ticks\n"); - - // Reset the timer - uart.write_str_blocking("Resetting timer...\n"); - ostimer.reset(hal::pac()); - - // Read counter after reset - let counter_after_reset = ostimer.now(); - uart.write_str_blocking("Counter after reset: "); - write_u64(&mut uart, counter_after_reset); - uart.write_str_blocking("\n"); - - // Wait again to verify timer is working - Timer::after(Duration::from_millis(50)).await; - - let final_counter = ostimer.now(); - uart.write_str_blocking("Counter after another 50ms: "); - write_u64(&mut uart, final_counter); - uart.write_str_blocking("\n"); - uart.write_str_blocking("Difference after reset: "); - write_u64(&mut uart, final_counter - counter_after_reset); - uart.write_str_blocking(" ticks\n"); - - uart.write_str_blocking("Example complete\n"); -} - -// Helper function to write a u64 value as decimal string -fn write_u64(uart: &mut hal::uart::Uart, value: u64) { - if value == 0 { - uart.write_str_blocking("0"); - return; - } - - let mut buffer = [0u8; 20]; // Enough for max u64 - let mut i = 0; - let mut v = value; - - while v > 0 { - buffer[i] = b'0' + (v % 10) as u8; - v /= 10; - i += 1; - } - - // Write digits in reverse order - while i > 0 { - i -= 1; - match buffer[i] { - b'0' => uart.write_str_blocking("0"), - b'1' => uart.write_str_blocking("1"), - b'2' => uart.write_str_blocking("2"), - b'3' => uart.write_str_blocking("3"), - b'4' => uart.write_str_blocking("4"), - b'5' => uart.write_str_blocking("5"), - b'6' => uart.write_str_blocking("6"), - b'7' => uart.write_str_blocking("7"), - b'8' => uart.write_str_blocking("8"), - b'9' => uart.write_str_blocking("9"), - _ => uart.write_str_blocking("?"), - } - } -} diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs deleted file mode 100644 index 368a3e52f..000000000 --- a/examples/ostimer_race_test.rs +++ /dev/null @@ -1,396 +0,0 @@ -//! # OSTIMER Race Condition Test -//! -//! This example tests for race conditions in the OSTIMER driver by: -//! - Scheduling alarms sequentially (hardware limitation: only one at a time) -//! - Reading the counter during interrupt-heavy periods -//! - Testing concurrent timer operations -//! - Stress testing interrupt handling - -#![no_std] -#![no_main] - -use core::sync::atomic::{AtomicU32, Ordering}; - -use embassy_executor::Spawner; -use embassy_time::{Duration, Timer}; -use hal::bind_interrupts; -use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; - -mod common; - -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -// Global counters for race condition detection -static ALARM_CALLBACK_COUNT: AtomicU32 = AtomicU32::new(0); -static INTERRUPT_COUNT: AtomicU32 = AtomicU32::new(0); -static RACE_DETECTED: AtomicU32 = AtomicU32::new(0); - -// Alarm callback function -fn alarm_callback() { - let _count = ALARM_CALLBACK_COUNT.fetch_add(1, Ordering::SeqCst); - INTERRUPT_COUNT.fetch_add(1, Ordering::SeqCst); - - // Simulate some work in the callback to increase chance of races - for _ in 0..10 { - cortex_m::asm::nop(); - } -} - -fn report_default_handler(uart: &mut hal::uart::Uart) { - let snapshot = hal::interrupt::default_handler_snapshot(); - if snapshot.count == 0 { - return; - } - - uart.write_str_blocking("WARNING: DefaultHandler executed "); - write_u32(uart, snapshot.count); - uart.write_str_blocking(" time(s). Vector="); - write_u32(uart, snapshot.vector as u32); - uart.write_str_blocking(" CFSR=0x"); - write_hex32(uart, snapshot.cfsr); - uart.write_str_blocking(" HFSR=0x"); - write_hex32(uart, snapshot.hfsr); - uart.write_str_blocking(" PC=0x"); - write_hex32(uart, snapshot.stacked_pc); - uart.write_str_blocking(" LR=0x"); - write_hex32(uart, snapshot.stacked_lr); - uart.write_str_blocking(" SP=0x"); - write_hex32(uart, snapshot.stacked_sp); - uart.write_str_blocking("\n"); - - hal::interrupt::clear_default_handler_snapshot(); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(Default::default()); - - // Enable/clock OSTIMER0 and UART2 before touching their registers - unsafe { - common::init_ostimer0(hal::pac()); - } - unsafe { - common::init_uart2(hal::pac()); - } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); - - uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); - - // The bind_interrupts! macro handles handler binding automatically - - // Initialize the OSTIMER time driver FIRST - hal::ostimer::time_driver::init( - hal::interrupt::Priority::from(3), - 1_000_000, // 1MHz clock - ); - - uart.write_str_blocking("Time driver initialized\n"); - - // Create OSTIMER instance - let ostimer = hal::ostimer::Ostimer::::new( - p.OSTIMER0, - hal::ostimer::Config { - init_match_max: true, - clock_frequency_hz: 1_000_000, - }, - hal::pac(), - ); - - uart.write_str_blocking("OSTIMER instance created\n"); - - // Test 1: Sequential alarm scheduling (OSTIMER only supports one alarm at a time) - uart.write_str_blocking("Test 1: Sequential alarm scheduling...\n"); - test_rapid_alarms(&ostimer, &mut uart).await; - report_default_handler(&mut uart); - - // Test 2: Counter reading during interrupts - uart.write_str_blocking("Test 2: Counter reading during interrupts...\n"); - test_counter_reading_during_interrupts(&ostimer, &mut uart).await; - report_default_handler(&mut uart); - - // Test 3: Concurrent timer operations - uart.write_str_blocking("Test 3: Concurrent timer operations...\n"); - test_concurrent_operations(&ostimer, &mut uart).await; - report_default_handler(&mut uart); - - // Test 4: Timer reset during operation - uart.write_str_blocking("Test 4: Timer reset during operation...\n"); - test_reset_during_operation(&ostimer, &mut uart, hal::pac()).await; - report_default_handler(&mut uart); - - // Report results - uart.write_str_blocking("Race condition test complete\n"); - uart.write_str_blocking("Callback count: "); - write_u32(&mut uart, ALARM_CALLBACK_COUNT.load(Ordering::SeqCst)); - uart.write_str_blocking("\nInterrupt count: "); - write_u32(&mut uart, INTERRUPT_COUNT.load(Ordering::SeqCst)); - uart.write_str_blocking("\nRaces detected: "); - write_u32(&mut uart, RACE_DETECTED.load(Ordering::SeqCst)); - uart.write_str_blocking("\n"); -} - -// Test rapid alarm scheduling to stress interrupt handling -async fn test_rapid_alarms( - ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut hal::uart::Uart, -) { - let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); - - // Schedule 10 alarms sequentially (OSTIMER only supports one alarm at a time) - for _i in 0..10 { - let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); - let delay_us = 1000; // 1ms delay for each alarm - if ostimer.schedule_alarm_delay(&alarm, delay_us) { - // Wait for this alarm to complete before scheduling the next - Timer::after(Duration::from_micros(delay_us + 100)).await; - report_default_handler(uart); - } else { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm (match not ready)\n"); - } - } - - // All alarms should have completed by now - let final_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); - let expected_count = initial_count + 10; - - if final_count != expected_count { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Expected "); - write_u32(uart, expected_count); - uart.write_str_blocking(" callbacks, got "); - write_u32(uart, final_count); - uart.write_str_blocking("\n"); - } else { - uart.write_str_blocking("PASS: All rapid alarms executed\n"); - } -} - -// Test reading counter while interrupts are firing -async fn test_counter_reading_during_interrupts( - ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut hal::uart::Uart, -) { - let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); - - // Schedule an alarm that will fire soon - let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); - if !ostimer.schedule_alarm_delay(&alarm, 500) { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before counter stress\n"); - } - - // While alarm is pending, read the counter many times rapidly - // This tests if counter reading is atomic and doesn't get corrupted by interrupts - let mut last_counter = ostimer.now(); - let mut consistent_reads = 0; - let mut total_reads = 0; - - for _ in 0..1000 { - let current_counter = ostimer.now(); - total_reads += 1; - - // Check if counter is monotonically increasing (basic sanity check) - if current_counter >= last_counter { - consistent_reads += 1; - } - last_counter = current_counter; - - // Small delay between reads - for _ in 0..10 { - cortex_m::asm::nop(); - } - - report_default_handler(uart); - } - - // Wait for alarm to complete - Timer::after(Duration::from_millis(1)).await; - - let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); - - if consistent_reads == total_reads { - uart.write_str_blocking("PASS: Counter reading consistent during interrupts\n"); - } else { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Counter reading inconsistent: "); - write_u32(uart, consistent_reads); - uart.write_str_blocking("/"); - write_u32(uart, total_reads); - uart.write_str_blocking(" consistent\n"); - } - - if final_interrupt_count > initial_interrupt_count { - uart.write_str_blocking("PASS: Interrupt fired during counter reading test\n"); - } else { - uart.write_str_blocking("WARNING: No interrupt fired during counter reading test\n"); - } -} - -// Test concurrent timer operations (embassy-time + alarms) -async fn test_concurrent_operations( - ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut hal::uart::Uart, -) { - let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); - - // Start an embassy-time timer - let timer_future = Timer::after(Duration::from_millis(2)); - - // Schedule an alarm that should fire before the timer - let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); - if !ostimer.schedule_alarm_delay(&alarm, 1000) { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before concurrent operations\n"); - } - - // Wait for both to complete - timer_future.await; - - let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); - - if final_interrupt_count > initial_interrupt_count { - uart.write_str_blocking("PASS: Concurrent operations completed\n"); - } else { - uart.write_str_blocking("WARNING: No interrupts during concurrent operations\n"); - } -} - -// Test timer reset during active operations -async fn test_reset_during_operation( - ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut hal::uart::Uart, - peripherals: &mcxa_pac::Peripherals, -) { - let initial_counter = ostimer.now(); - - // Schedule an alarm - let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); - if !ostimer.schedule_alarm_delay(&alarm, 2000) { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before reset test\n"); - } - - // Wait a bit then reset the timer - Timer::after(Duration::from_millis(1)).await; - ostimer.reset(peripherals); - - // Check counter after reset - let counter_after_reset = ostimer.now(); - - // Wait to see if the alarm still fires (it shouldn't after reset) - Timer::after(Duration::from_millis(2)).await; - - let final_counter = ostimer.now(); - - if counter_after_reset < initial_counter { - uart.write_str_blocking("PASS: Timer reset successful\n"); - } else { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Timer reset may have failed\n"); - } - - uart.write_str_blocking("Counter progression after reset: "); - write_u64(uart, initial_counter); - uart.write_str_blocking(" -> "); - write_u64(uart, counter_after_reset); - uart.write_str_blocking(" -> "); - write_u64(uart, final_counter); - uart.write_str_blocking("\n"); -} - -// Helper function to write a u32 value as decimal string -fn write_u32(uart: &mut hal::uart::Uart, value: u32) { - if value == 0 { - uart.write_str_blocking("0"); - return; - } - - let mut buffer = [0u8; 10]; // Enough for max u32 - let mut i = 0; - let mut v = value; - - while v > 0 { - buffer[i] = b'0' + (v % 10) as u8; - v /= 10; - i += 1; - } - - // Write digits in reverse order - while i > 0 { - i -= 1; - match buffer[i] { - b'0' => uart.write_str_blocking("0"), - b'1' => uart.write_str_blocking("1"), - b'2' => uart.write_str_blocking("2"), - b'3' => uart.write_str_blocking("3"), - b'4' => uart.write_str_blocking("4"), - b'5' => uart.write_str_blocking("5"), - b'6' => uart.write_str_blocking("6"), - b'7' => uart.write_str_blocking("7"), - b'8' => uart.write_str_blocking("8"), - b'9' => uart.write_str_blocking("9"), - _ => uart.write_str_blocking("?"), - } - } -} - -fn write_hex32(uart: &mut hal::uart::Uart, value: u32) { - let mut buf = [b'0'; 8]; - let mut tmp = value; - for i in (0..8).rev() { - let digit = (tmp & 0xF) as u8; - buf[i] = match digit { - 0..=9 => b'0' + digit, - 10..=15 => b'A' + (digit - 10), - _ => b'?', - }; - tmp >>= 4; - } - for b in &buf { - uart.write_byte(*b); - } -} - -// Helper function to write a u64 value as decimal string -fn write_u64(uart: &mut hal::uart::Uart, value: u64) { - if value == 0 { - uart.write_str_blocking("0"); - return; - } - - let mut buffer = [0u8; 20]; // Enough for max u64 - let mut i = 0; - let mut v = value; - - while v > 0 { - buffer[i] = b'0' + (v % 10) as u8; - v /= 10; - i += 1; - } - - // Write digits in reverse order - while i > 0 { - i -= 1; - match buffer[i] { - b'0' => uart.write_str_blocking("0"), - b'1' => uart.write_str_blocking("1"), - b'2' => uart.write_str_blocking("2"), - b'3' => uart.write_str_blocking("3"), - b'4' => uart.write_str_blocking("4"), - b'5' => uart.write_str_blocking("5"), - b'6' => uart.write_str_blocking("6"), - b'7' => uart.write_str_blocking("7"), - b'8' => uart.write_str_blocking("8"), - b'9' => uart.write_str_blocking("9"), - _ => uart.write_str_blocking("?"), - } - } -} diff --git a/examples/rtc_alarm.rs b/examples/rtc_alarm.rs deleted file mode 100644 index c27fd4c55..000000000 --- a/examples/rtc_alarm.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use hal::rtc::{RtcDateTime, RtcInterruptEnable}; -use hal::{uart, InterruptExt}; -use {cortex_m, embassy_mcxa276 as hal}; - -mod common; - -type MyRtc = hal::rtc::Rtc; - -use embassy_mcxa276::bind_interrupts; -use {defmt_rtt as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - RTC => hal::rtc::RtcHandler; -}); - -#[used] -#[no_mangle] -static KEEP_RTC: unsafe extern "C" fn() = RTC; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - unsafe { - common::init_uart2(hal::pac()); - } - - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); - - uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n"); - - unsafe { hal::clocks::init_fro16k(hal::pac()) }; - - let rtc_config = hal::rtc::get_default_config(); - - let rtc = MyRtc::new(p.RTC0, rtc_config); - - let now = RtcDateTime { - year: 2025, - month: 10, - day: 15, - hour: 14, - minute: 30, - second: 0, - }; - - rtc.stop(); - - uart.write_str_blocking("Time set to: 2025-10-15 14:30:00\r\n"); - rtc.set_datetime(now); - - let mut alarm = now; - alarm.second += 10; - - rtc.set_alarm(alarm); - uart.write_str_blocking("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)\r\n"); - - rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); - - unsafe { - hal::interrupt::RTC.enable(); - } - - unsafe { - cortex_m::interrupt::enable(); - } - - rtc.start(); - - uart.write_str_blocking("RTC started, waiting for alarm...\r\n"); - - loop { - if rtc.is_alarm_triggered() { - uart.write_str_blocking("\r\n*** ALARM TRIGGERED! ***\r\n"); - break; - } - } - - uart.write_str_blocking("Example complete - Test PASSED!\r\n"); - - loop {} -} diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs new file mode 100644 index 000000000..e174a5272 --- /dev/null +++ b/examples/src/bin/adc_interrupt.rs @@ -0,0 +1,86 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa_examples::{init_adc, init_uart2}; +use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; +use hal::pac::adc1::cfg::{Pwrsel, Refsel}; +use hal::pac::adc1::cmdl1::{Adch, Mode}; +use hal::pac::adc1::ctrl::CalAvgs; +use hal::pac::adc1::tctrl::Tcmd; +use hal::{bind_interrupts, uart, InterruptExt}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ADC1 => hal::adc::AdcHandler; +}); + +#[used] +#[no_mangle] +static KEEP_ADC: unsafe extern "C" fn() = ADC1; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + unsafe { + init_uart2(hal::pac()); + } + + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + + uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); + + unsafe { + init_adc(hal::pac()); + } + + let adc_config = LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + }; + let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + + adc.do_offset_calibration(); + adc.do_auto_calibration(); + + let mut conv_command_config = adc.get_default_conv_command_config(); + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + adc.set_conv_command_config(1, &conv_command_config); + + let mut conv_trigger_config = adc.get_default_conv_trigger_config(); + conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; + conv_trigger_config.enable_hardware_trigger = false; + adc.set_conv_trigger_config(0, &conv_trigger_config); + + uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); + + adc.enable_interrupt(0x1); + + unsafe { + hal::interrupt::ADC1.enable(); + } + + unsafe { + cortex_m::interrupt::enable(); + } + + loop { + adc.do_software_trigger(1); + while !adc.is_interrupt_triggered() { + // Wait until the interrupt is triggered + } + uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); + //TBD need to print the value + } +} diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs new file mode 100644 index 000000000..741551d49 --- /dev/null +++ b/examples/src/bin/adc_polling.rs @@ -0,0 +1,76 @@ +#![no_std] +#![no_main] + +use core::fmt::Write; + +use embassy_executor::Spawner; +use embassy_mcxa_examples::{init_adc, init_uart2}; +use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; +use hal::pac::adc1::cfg::{Pwrsel, Refsel}; +use hal::pac::adc1::cmdl1::{Adch, Mode}; +use hal::pac::adc1::ctrl::CalAvgs; +use hal::pac::adc1::tctrl::Tcmd; +use hal::uart; +use heapless::String; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +const G_LPADC_RESULT_SHIFT: u32 = 0; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + unsafe { + init_uart2(hal::pac()); + } + + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + + uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); + + unsafe { + init_adc(hal::pac()); + } + + let adc_config = LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + }; + let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + + adc.do_offset_calibration(); + adc.do_auto_calibration(); + + let mut conv_command_config = adc.get_default_conv_command_config(); + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + adc.set_conv_command_config(1, &conv_command_config); + + let mut conv_trigger_config = adc.get_default_conv_trigger_config(); + conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; + conv_trigger_config.enable_hardware_trigger = false; + adc.set_conv_trigger_config(0, &conv_trigger_config); + + uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); + + loop { + adc.do_software_trigger(1); + let mut result: Option = None; + while result.is_none() { + result = hal::adc::get_conv_result(); + } + let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; + let mut buf: String<16> = String::new(); // adjust size as needed + write!(buf, "\r\nvalue: {}\r\n", value).unwrap(); + uart.write_str_blocking(&buf); + } +} diff --git a/examples/src/bin/blink.rs b/examples/src/bin/blink.rs new file mode 100644 index 000000000..d8a57c546 --- /dev/null +++ b/examples/src/bin/blink.rs @@ -0,0 +1,78 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa as hal; +use embassy_mcxa::bind_interrupts; +use embassy_mcxa_examples::{init_led, init_ostimer0}; +use embassy_time::{Duration, Timer}; +use hal::gpio::pins::PIO3_18; +use hal::gpio::{Level, Output}; + +// Bind only OS_EVENT for timer interrupts +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + + unsafe { + init_led(hal::pac()); + init_ostimer0(hal::pac()); + } + + // Initialize embassy-time global driver backed by OSTIMER0 + hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); + + // Configure LED pin for GPIO mode + PIO3_18::set_mux_gpio(); + + let mut led = Output::new(PIO3_18::degrade(), Level::High); + + // Complex blinking pattern: SOS in Morse code + // S: ... (3 short) + // O: --- (3 long) + // S: ... (3 short) + // With pauses between letters and words + + loop { + // S: three short blinks + for _ in 0..3 { + led.set_low(); + Timer::after(Duration::from_millis(150)).await; + led.set_high(); + Timer::after(Duration::from_millis(150)).await; + } + + // Pause between letters + Timer::after(Duration::from_millis(300)).await; + + // O: three long blinks + for _ in 0..3 { + led.set_low(); + Timer::after(Duration::from_millis(450)).await; + led.set_high(); + Timer::after(Duration::from_millis(150)).await; + } + + // Pause between letters + Timer::after(Duration::from_millis(300)).await; + + // S: three short blinks + for _ in 0..3 { + led.set_low(); + Timer::after(Duration::from_millis(150)).await; + led.set_high(); + Timer::after(Duration::from_millis(150)).await; + } + + // Long pause between words (SOS repeats) + Timer::after(Duration::from_millis(1000)).await; + } +} diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs new file mode 100644 index 000000000..5c4336d50 --- /dev/null +++ b/examples/src/bin/hello.rs @@ -0,0 +1,111 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa_examples::init_uart2; +use hal::uart; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Simple helper to write a byte as hex to UART +fn write_hex_byte(uart: &hal::uart::Uart, byte: u8) { + const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; + uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); + uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("boot"); + + // Board-level init for UART2 clocks and pins. + unsafe { + init_uart2(hal::pac()); + } + + // Get UART source frequency from clock configuration + // Using hardcoded frequency for now - dynamic detection may have issues + let src = 12_000_000; // FRO_LF_DIV at 12MHz with DIV=0 + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + + // Print welcome message before any async delays to guarantee early console output + uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); + uart.write_str_blocking("Available commands:\r\n"); + uart.write_str_blocking(" help - Show this help\r\n"); + uart.write_str_blocking(" echo - Echo back the text\r\n"); + uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); + uart.write_str_blocking("Type a command: "); + + let mut buffer = [0u8; 64]; + let mut buf_idx = 0; + + loop { + // Read a byte from UART + let byte = uart.read_byte_blocking(); + + // Echo the character back + if byte == b'\r' || byte == b'\n' { + // Enter pressed - process command + uart.write_str_blocking("\r\n"); + + if buf_idx > 0 { + let command = &buffer[0..buf_idx]; + + if command == b"help" { + uart.write_str_blocking("Available commands:\r\n"); + uart.write_str_blocking(" help - Show this help\r\n"); + uart.write_str_blocking(" echo - Echo back the text\r\n"); + uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); + } else if command.starts_with(b"echo ") && command.len() > 5 { + uart.write_str_blocking("Echo: "); + uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or("")); + uart.write_str_blocking("\r\n"); + } else if command.starts_with(b"hex ") && command.len() > 4 { + // Parse the byte value + let num_str = &command[4..]; + if let Ok(num) = parse_u8(num_str) { + uart.write_str_blocking("Hex: 0x"); + write_hex_byte(&uart, num); + uart.write_str_blocking("\r\n"); + } else { + uart.write_str_blocking("Invalid number for hex command\r\n"); + } + } else if !command.is_empty() { + uart.write_str_blocking("Unknown command: "); + uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); + uart.write_str_blocking("\r\n"); + } + } + + // Reset buffer and prompt + buf_idx = 0; + uart.write_str_blocking("Type a command: "); + } else if byte == 8 || byte == 127 { + // Backspace + if buf_idx > 0 { + buf_idx -= 1; + uart.write_str_blocking("\x08 \x08"); // Erase character + } + } else if buf_idx < buffer.len() - 1 { + // Regular character + buffer[buf_idx] = byte; + buf_idx += 1; + uart.write_byte(byte); + } + } +} + +/// Simple parser for u8 from ASCII bytes +fn parse_u8(bytes: &[u8]) -> Result { + let mut result = 0u8; + for &b in bytes { + if b.is_ascii_digit() { + result = result.checked_mul(10).ok_or(())?; + result = result.checked_add(b - b'0').ok_or(())?; + } else { + return Err(()); + } + } + Ok(result) +} diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs new file mode 100644 index 000000000..480d8e1f7 --- /dev/null +++ b/examples/src/bin/lpuart_buffered.rs @@ -0,0 +1,76 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa as hal; +use embassy_mcxa::interrupt::typelevel::Handler; +use embassy_mcxa::lpuart::buffered::BufferedLpuart; +use embassy_mcxa::{bind_interrupts, lpuart}; +use embassy_mcxa_examples::{init_ostimer0, init_uart2}; +use embedded_io_async::{Read, Write}; + +// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver +bind_interrupts!(struct Irqs { + LPUART2 => lpuart::buffered::BufferedInterruptHandler::; +}); + +// Wrapper function for the interrupt handler +unsafe extern "C" fn lpuart2_handler() { + lpuart::buffered::BufferedInterruptHandler::::on_interrupt(); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + let p2 = lpuart::lib::init(); + + unsafe { + hal::interrupt::install_irq_handler(hal::pac::Interrupt::LPUART2, lpuart2_handler); + } + + // Configure NVIC for LPUART2 + hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); + + unsafe { + init_uart2(hal::pac()); + init_ostimer0(hal::pac()); + } + + // UART configuration (enable both TX and RX) + let config = lpuart::Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + rx_fifo_watermark: 0, + tx_fifo_watermark: 0, + ..Default::default() + }; + + let mut tx_buf = [0u8; 256]; + let mut rx_buf = [0u8; 256]; + + // Create a buffered LPUART2 instance with both TX and RX + let mut uart = BufferedLpuart::new( + p2.LPUART2, + p2.PIO2_2, // TX pin + p2.PIO2_3, // RX pin + Irqs, + &mut tx_buf, + &mut rx_buf, + config, + ) + .unwrap(); + + // Split into TX and RX parts + let (tx, rx) = uart.split_ref(); + + tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); + tx.write(b"Type characters to echo them back.\r\n").await.unwrap(); + + // Echo loop + let mut buf = [0u8; 4]; + loop { + rx.read_exact(&mut buf[..]).await.unwrap(); + tx.write_all(&buf[..]).await.unwrap(); + } +} diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs new file mode 100644 index 000000000..215714569 --- /dev/null +++ b/examples/src/bin/lpuart_polling.rs @@ -0,0 +1,51 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa_examples::init_uart2; +use hal::lpuart::{lib, Config, Lpuart}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + let p2 = lib::init(); + + defmt::info!("boot"); + + // Board-level init for UART2 clocks and pins. + unsafe { + init_uart2(hal::pac()); + } + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + let lpuart = Lpuart::new_blocking( + p2.LPUART2, // Peripheral + p2.PIO2_2, // TX pin + p2.PIO2_3, // RX pin + config, + ) + .unwrap(); + + // Split into separate TX and RX parts + let (mut tx, mut rx) = lpuart.split(); + + // Write hello messages + tx.blocking_write(b"Hello world.\r\n").unwrap(); + tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap(); + + // Echo loop + loop { + let mut buf = [0u8; 1]; + rx.blocking_read(&mut buf).unwrap(); + tx.blocking_write(&buf).unwrap(); + } +} diff --git a/examples/src/bin/ostimer_alarm.rs b/examples/src/bin/ostimer_alarm.rs new file mode 100644 index 000000000..953f98c01 --- /dev/null +++ b/examples/src/bin/ostimer_alarm.rs @@ -0,0 +1,106 @@ +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use embassy_executor::Spawner; +use embassy_mcxa::bind_interrupts; +use embassy_mcxa_examples::{init_ostimer0, init_uart2}; +use hal::uart; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +// Global flag for alarm callback +static ALARM_FLAG: AtomicBool = AtomicBool::new(false); + +// Alarm callback function +fn alarm_callback() { + ALARM_FLAG.store(true, Ordering::Release); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + // Enable/clock OSTIMER0 and UART2 before touching their registers + unsafe { + init_ostimer0(hal::pac()); + init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + uart.write_str_blocking("OSTIMER Alarm Example\n"); + + // Initialize embassy-time global driver backed by OSTIMER0 + hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); + + // Create OSTIMER instance + let config = hal::ostimer::Config { + init_match_max: true, + clock_frequency_hz: 1_000_000, // 1MHz + }; + let ostimer = hal::ostimer::Ostimer::::new(p.OSTIMER0, config, hal::pac()); + + // Create alarm with callback + let alarm = hal::ostimer::Alarm::new() + .with_callback(alarm_callback) + .with_flag(&ALARM_FLAG); + + uart.write_str_blocking("Scheduling alarm for 2 seconds...\n"); + + // Schedule alarm to expire in 2 seconds (2,000,000 microseconds) + let scheduled = ostimer.schedule_alarm_delay(&alarm, 2_000_000); + if scheduled { + uart.write_str_blocking("Alarm scheduled successfully\n"); + } else { + uart.write_str_blocking("Failed to schedule alarm (would exceed timer capacity)\n"); + return; + } + + // Wait for alarm to expire + loop { + // Check if alarm has expired + if ALARM_FLAG.load(Ordering::Acquire) { + uart.write_str_blocking("Alarm expired! Callback executed.\n"); + break; + } + + // Busy wait - don't use Timer::after_millis as it interferes with alarm MATCH + for _ in 0..100000 { + cortex_m::asm::nop(); + } + } + + // Demonstrate canceling an alarm + uart.write_str_blocking("Scheduling another alarm for 3 seconds...\n"); + ALARM_FLAG.store(false, Ordering::Release); // Reset flag + + let scheduled = ostimer.schedule_alarm_delay(&alarm, 3_000_000); + if scheduled { + uart.write_str_blocking("Alarm scheduled. Waiting 1 second then canceling...\n"); + + // Wait 1 second + embassy_time::Timer::after_millis(1000).await; + + // Cancel the alarm + ostimer.cancel_alarm(&alarm); + uart.write_str_blocking("Alarm canceled\n"); + + // Check immediately if alarm flag is set + if !ALARM_FLAG.load(Ordering::Acquire) { + uart.write_str_blocking("Alarm was successfully canceled\n"); + } else { + uart.write_str_blocking("Alarm fired despite cancellation\n"); + } + } + + uart.write_str_blocking("Example complete\n"); +} diff --git a/examples/src/bin/ostimer_async.rs b/examples/src/bin/ostimer_async.rs new file mode 100644 index 000000000..34862b61f --- /dev/null +++ b/examples/src/bin/ostimer_async.rs @@ -0,0 +1,52 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::bind_interrupts; +use embassy_mcxa_examples::{init_ostimer0, init_uart2}; +use embassy_time::{Duration, Timer}; +use hal::uart; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed. +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + + // Enable/clock OSTIMER0 and UART2 before touching their registers + unsafe { + init_ostimer0(hal::pac()); + init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); + uart.write_str_blocking("boot\n"); + + // Avoid mass NVIC writes here; DefaultHandler now safely returns. + + // Initialize embassy-time global driver backed by OSTIMER0 (re-enables OS_EVENT with priority) + // The bind_interrupts! macro handles handler binding automatically + + // Initialize OSTIMER with default 1MHz frequency + // Adjust this value to match your actual OSTIMER clock frequency + hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); + + // Removed force-pend; rely on real hardware match to trigger OS_EVENT. + + // Log using defmt if enabled + defmt::info!("OSTIMER async example starting..."); + + loop { + defmt::info!("tick"); + uart.write_str_blocking("tick\n"); + Timer::after(Duration::from_millis(1000)).await; + } +} diff --git a/examples/src/bin/ostimer_counter.rs b/examples/src/bin/ostimer_counter.rs new file mode 100644 index 000000000..20044760a --- /dev/null +++ b/examples/src/bin/ostimer_counter.rs @@ -0,0 +1,125 @@ +//! # OSTIMER Counter Reading and Reset Example +//! +//! This example demonstrates the new timer counter reading and reset functionality +//! of the OSTIMER driver. + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa_examples::{init_ostimer0, init_uart2}; +use embassy_time::{Duration, Timer}; +use hal::bind_interrupts; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(Default::default()); + + // Enable/clock OSTIMER0 and UART2 before touching their registers + unsafe { + init_ostimer0(hal::pac()); + init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + + uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); + + // Initialize the OSTIMER time driver + hal::ostimer::time_driver::init( + hal::interrupt::Priority::from(3), + 1_000_000, // 1MHz clock + ); + + // Create OSTIMER instance + let ostimer = hal::ostimer::Ostimer::::new( + p.OSTIMER0, + hal::ostimer::Config { + init_match_max: true, + clock_frequency_hz: 1_000_000, + }, + hal::pac(), + ); + + // Read initial counter value + let initial_counter = ostimer.now(); + uart.write_str_blocking("Initial counter value: "); + write_u64(&mut uart, initial_counter); + uart.write_str_blocking("\n"); + + // Wait a bit to let counter increment + Timer::after(Duration::from_millis(100)).await; + + // Read counter again + let counter_after_wait = ostimer.now(); + uart.write_str_blocking("Counter after 100ms wait: "); + write_u64(&mut uart, counter_after_wait); + uart.write_str_blocking("\n"); + uart.write_str_blocking("Difference: "); + write_u64(&mut uart, counter_after_wait - initial_counter); + uart.write_str_blocking(" ticks\n"); + + // Reset the timer + uart.write_str_blocking("Resetting timer...\n"); + ostimer.reset(hal::pac()); + + // Read counter after reset + let counter_after_reset = ostimer.now(); + uart.write_str_blocking("Counter after reset: "); + write_u64(&mut uart, counter_after_reset); + uart.write_str_blocking("\n"); + + // Wait again to verify timer is working + Timer::after(Duration::from_millis(50)).await; + + let final_counter = ostimer.now(); + uart.write_str_blocking("Counter after another 50ms: "); + write_u64(&mut uart, final_counter); + uart.write_str_blocking("\n"); + uart.write_str_blocking("Difference after reset: "); + write_u64(&mut uart, final_counter - counter_after_reset); + uart.write_str_blocking(" ticks\n"); + + uart.write_str_blocking("Example complete\n"); +} + +// Helper function to write a u64 value as decimal string +fn write_u64(uart: &mut hal::uart::Uart, value: u64) { + if value == 0 { + uart.write_str_blocking("0"); + return; + } + + let mut buffer = [0u8; 20]; // Enough for max u64 + let mut i = 0; + let mut v = value; + + while v > 0 { + buffer[i] = b'0' + (v % 10) as u8; + v /= 10; + i += 1; + } + + // Write digits in reverse order + while i > 0 { + i -= 1; + match buffer[i] { + b'0' => uart.write_str_blocking("0"), + b'1' => uart.write_str_blocking("1"), + b'2' => uart.write_str_blocking("2"), + b'3' => uart.write_str_blocking("3"), + b'4' => uart.write_str_blocking("4"), + b'5' => uart.write_str_blocking("5"), + b'6' => uart.write_str_blocking("6"), + b'7' => uart.write_str_blocking("7"), + b'8' => uart.write_str_blocking("8"), + b'9' => uart.write_str_blocking("9"), + _ => uart.write_str_blocking("?"), + } + } +} diff --git a/examples/src/bin/ostimer_race_test.rs b/examples/src/bin/ostimer_race_test.rs new file mode 100644 index 000000000..720a058d5 --- /dev/null +++ b/examples/src/bin/ostimer_race_test.rs @@ -0,0 +1,393 @@ +//! # OSTIMER Race Condition Test +//! +//! This example tests for race conditions in the OSTIMER driver by: +//! - Scheduling alarms sequentially (hardware limitation: only one at a time) +//! - Reading the counter during interrupt-heavy periods +//! - Testing concurrent timer operations +//! - Stress testing interrupt handling + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicU32, Ordering}; + +use embassy_executor::Spawner; +use embassy_mcxa_examples::{init_ostimer0, init_uart2}; +use embassy_time::{Duration, Timer}; +use hal::bind_interrupts; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +// Global counters for race condition detection +static ALARM_CALLBACK_COUNT: AtomicU32 = AtomicU32::new(0); +static INTERRUPT_COUNT: AtomicU32 = AtomicU32::new(0); +static RACE_DETECTED: AtomicU32 = AtomicU32::new(0); + +// Alarm callback function +fn alarm_callback() { + let _count = ALARM_CALLBACK_COUNT.fetch_add(1, Ordering::SeqCst); + INTERRUPT_COUNT.fetch_add(1, Ordering::SeqCst); + + // Simulate some work in the callback to increase chance of races + for _ in 0..10 { + cortex_m::asm::nop(); + } +} + +fn report_default_handler(uart: &mut hal::uart::Uart) { + let snapshot = hal::interrupt::default_handler_snapshot(); + if snapshot.count == 0 { + return; + } + + uart.write_str_blocking("WARNING: DefaultHandler executed "); + write_u32(uart, snapshot.count); + uart.write_str_blocking(" time(s). Vector="); + write_u32(uart, snapshot.vector as u32); + uart.write_str_blocking(" CFSR=0x"); + write_hex32(uart, snapshot.cfsr); + uart.write_str_blocking(" HFSR=0x"); + write_hex32(uart, snapshot.hfsr); + uart.write_str_blocking(" PC=0x"); + write_hex32(uart, snapshot.stacked_pc); + uart.write_str_blocking(" LR=0x"); + write_hex32(uart, snapshot.stacked_lr); + uart.write_str_blocking(" SP=0x"); + write_hex32(uart, snapshot.stacked_sp); + uart.write_str_blocking("\n"); + + hal::interrupt::clear_default_handler_snapshot(); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(Default::default()); + + // Enable/clock OSTIMER0 and UART2 before touching their registers + unsafe { + init_ostimer0(hal::pac()); + init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + + uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); + + // The bind_interrupts! macro handles handler binding automatically + + // Initialize the OSTIMER time driver FIRST + hal::ostimer::time_driver::init( + hal::interrupt::Priority::from(3), + 1_000_000, // 1MHz clock + ); + + uart.write_str_blocking("Time driver initialized\n"); + + // Create OSTIMER instance + let ostimer = hal::ostimer::Ostimer::::new( + p.OSTIMER0, + hal::ostimer::Config { + init_match_max: true, + clock_frequency_hz: 1_000_000, + }, + hal::pac(), + ); + + uart.write_str_blocking("OSTIMER instance created\n"); + + // Test 1: Sequential alarm scheduling (OSTIMER only supports one alarm at a time) + uart.write_str_blocking("Test 1: Sequential alarm scheduling...\n"); + test_rapid_alarms(&ostimer, &mut uart).await; + report_default_handler(&mut uart); + + // Test 2: Counter reading during interrupts + uart.write_str_blocking("Test 2: Counter reading during interrupts...\n"); + test_counter_reading_during_interrupts(&ostimer, &mut uart).await; + report_default_handler(&mut uart); + + // Test 3: Concurrent timer operations + uart.write_str_blocking("Test 3: Concurrent timer operations...\n"); + test_concurrent_operations(&ostimer, &mut uart).await; + report_default_handler(&mut uart); + + // Test 4: Timer reset during operation + uart.write_str_blocking("Test 4: Timer reset during operation...\n"); + test_reset_during_operation(&ostimer, &mut uart, hal::pac()).await; + report_default_handler(&mut uart); + + // Report results + uart.write_str_blocking("Race condition test complete\n"); + uart.write_str_blocking("Callback count: "); + write_u32(&mut uart, ALARM_CALLBACK_COUNT.load(Ordering::SeqCst)); + uart.write_str_blocking("\nInterrupt count: "); + write_u32(&mut uart, INTERRUPT_COUNT.load(Ordering::SeqCst)); + uart.write_str_blocking("\nRaces detected: "); + write_u32(&mut uart, RACE_DETECTED.load(Ordering::SeqCst)); + uart.write_str_blocking("\n"); +} + +// Test rapid alarm scheduling to stress interrupt handling +async fn test_rapid_alarms( + ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, + uart: &mut hal::uart::Uart, +) { + let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); + + // Schedule 10 alarms sequentially (OSTIMER only supports one alarm at a time) + for _i in 0..10 { + let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); + let delay_us = 1000; // 1ms delay for each alarm + if ostimer.schedule_alarm_delay(&alarm, delay_us) { + // Wait for this alarm to complete before scheduling the next + Timer::after(Duration::from_micros(delay_us + 100)).await; + report_default_handler(uart); + } else { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm (match not ready)\n"); + } + } + + // All alarms should have completed by now + let final_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); + let expected_count = initial_count + 10; + + if final_count != expected_count { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Expected "); + write_u32(uart, expected_count); + uart.write_str_blocking(" callbacks, got "); + write_u32(uart, final_count); + uart.write_str_blocking("\n"); + } else { + uart.write_str_blocking("PASS: All rapid alarms executed\n"); + } +} + +// Test reading counter while interrupts are firing +async fn test_counter_reading_during_interrupts( + ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, + uart: &mut hal::uart::Uart, +) { + let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); + + // Schedule an alarm that will fire soon + let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); + if !ostimer.schedule_alarm_delay(&alarm, 500) { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before counter stress\n"); + } + + // While alarm is pending, read the counter many times rapidly + // This tests if counter reading is atomic and doesn't get corrupted by interrupts + let mut last_counter = ostimer.now(); + let mut consistent_reads = 0; + let mut total_reads = 0; + + for _ in 0..1000 { + let current_counter = ostimer.now(); + total_reads += 1; + + // Check if counter is monotonically increasing (basic sanity check) + if current_counter >= last_counter { + consistent_reads += 1; + } + last_counter = current_counter; + + // Small delay between reads + for _ in 0..10 { + cortex_m::asm::nop(); + } + + report_default_handler(uart); + } + + // Wait for alarm to complete + Timer::after(Duration::from_millis(1)).await; + + let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); + + if consistent_reads == total_reads { + uart.write_str_blocking("PASS: Counter reading consistent during interrupts\n"); + } else { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Counter reading inconsistent: "); + write_u32(uart, consistent_reads); + uart.write_str_blocking("/"); + write_u32(uart, total_reads); + uart.write_str_blocking(" consistent\n"); + } + + if final_interrupt_count > initial_interrupt_count { + uart.write_str_blocking("PASS: Interrupt fired during counter reading test\n"); + } else { + uart.write_str_blocking("WARNING: No interrupt fired during counter reading test\n"); + } +} + +// Test concurrent timer operations (embassy-time + alarms) +async fn test_concurrent_operations( + ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, + uart: &mut hal::uart::Uart, +) { + let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); + + // Start an embassy-time timer + let timer_future = Timer::after(Duration::from_millis(2)); + + // Schedule an alarm that should fire before the timer + let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); + if !ostimer.schedule_alarm_delay(&alarm, 1000) { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before concurrent operations\n"); + } + + // Wait for both to complete + timer_future.await; + + let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); + + if final_interrupt_count > initial_interrupt_count { + uart.write_str_blocking("PASS: Concurrent operations completed\n"); + } else { + uart.write_str_blocking("WARNING: No interrupts during concurrent operations\n"); + } +} + +// Test timer reset during active operations +async fn test_reset_during_operation( + ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, + uart: &mut hal::uart::Uart, + peripherals: &hal::pac::Peripherals, +) { + let initial_counter = ostimer.now(); + + // Schedule an alarm + let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); + if !ostimer.schedule_alarm_delay(&alarm, 2000) { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before reset test\n"); + } + + // Wait a bit then reset the timer + Timer::after(Duration::from_millis(1)).await; + ostimer.reset(peripherals); + + // Check counter after reset + let counter_after_reset = ostimer.now(); + + // Wait to see if the alarm still fires (it shouldn't after reset) + Timer::after(Duration::from_millis(2)).await; + + let final_counter = ostimer.now(); + + if counter_after_reset < initial_counter { + uart.write_str_blocking("PASS: Timer reset successful\n"); + } else { + RACE_DETECTED.fetch_add(1, Ordering::SeqCst); + uart.write_str_blocking("ERROR: Timer reset may have failed\n"); + } + + uart.write_str_blocking("Counter progression after reset: "); + write_u64(uart, initial_counter); + uart.write_str_blocking(" -> "); + write_u64(uart, counter_after_reset); + uart.write_str_blocking(" -> "); + write_u64(uart, final_counter); + uart.write_str_blocking("\n"); +} + +// Helper function to write a u32 value as decimal string +fn write_u32(uart: &mut hal::uart::Uart, value: u32) { + if value == 0 { + uart.write_str_blocking("0"); + return; + } + + let mut buffer = [0u8; 10]; // Enough for max u32 + let mut i = 0; + let mut v = value; + + while v > 0 { + buffer[i] = b'0' + (v % 10) as u8; + v /= 10; + i += 1; + } + + // Write digits in reverse order + while i > 0 { + i -= 1; + match buffer[i] { + b'0' => uart.write_str_blocking("0"), + b'1' => uart.write_str_blocking("1"), + b'2' => uart.write_str_blocking("2"), + b'3' => uart.write_str_blocking("3"), + b'4' => uart.write_str_blocking("4"), + b'5' => uart.write_str_blocking("5"), + b'6' => uart.write_str_blocking("6"), + b'7' => uart.write_str_blocking("7"), + b'8' => uart.write_str_blocking("8"), + b'9' => uart.write_str_blocking("9"), + _ => uart.write_str_blocking("?"), + } + } +} + +fn write_hex32(uart: &mut hal::uart::Uart, value: u32) { + let mut buf = [b'0'; 8]; + let mut tmp = value; + for i in (0..8).rev() { + let digit = (tmp & 0xF) as u8; + buf[i] = match digit { + 0..=9 => b'0' + digit, + 10..=15 => b'A' + (digit - 10), + _ => b'?', + }; + tmp >>= 4; + } + for b in &buf { + uart.write_byte(*b); + } +} + +// Helper function to write a u64 value as decimal string +fn write_u64(uart: &mut hal::uart::Uart, value: u64) { + if value == 0 { + uart.write_str_blocking("0"); + return; + } + + let mut buffer = [0u8; 20]; // Enough for max u64 + let mut i = 0; + let mut v = value; + + while v > 0 { + buffer[i] = b'0' + (v % 10) as u8; + v /= 10; + i += 1; + } + + // Write digits in reverse order + while i > 0 { + i -= 1; + match buffer[i] { + b'0' => uart.write_str_blocking("0"), + b'1' => uart.write_str_blocking("1"), + b'2' => uart.write_str_blocking("2"), + b'3' => uart.write_str_blocking("3"), + b'4' => uart.write_str_blocking("4"), + b'5' => uart.write_str_blocking("5"), + b'6' => uart.write_str_blocking("6"), + b'7' => uart.write_str_blocking("7"), + b'8' => uart.write_str_blocking("8"), + b'9' => uart.write_str_blocking("9"), + _ => uart.write_str_blocking("?"), + } + } +} diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs new file mode 100644 index 000000000..dc07b5757 --- /dev/null +++ b/examples/src/bin/rtc_alarm.rs @@ -0,0 +1,84 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa as hal; +use embassy_mcxa_examples::init_uart2; +use hal::rtc::{RtcDateTime, RtcInterruptEnable}; +use hal::{uart, InterruptExt}; + +type MyRtc = hal::rtc::Rtc; + +use embassy_mcxa::bind_interrupts; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RTC => hal::rtc::RtcHandler; +}); + +#[used] +#[no_mangle] +static KEEP_RTC: unsafe extern "C" fn() = RTC; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + unsafe { + init_uart2(hal::pac()); + } + + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + + uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n"); + + unsafe { hal::clocks::init_fro16k(hal::pac()) }; + + let rtc_config = hal::rtc::get_default_config(); + + let rtc = MyRtc::new(p.RTC0, rtc_config); + + let now = RtcDateTime { + year: 2025, + month: 10, + day: 15, + hour: 14, + minute: 30, + second: 0, + }; + + rtc.stop(); + + uart.write_str_blocking("Time set to: 2025-10-15 14:30:00\r\n"); + rtc.set_datetime(now); + + let mut alarm = now; + alarm.second += 10; + + rtc.set_alarm(alarm); + uart.write_str_blocking("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)\r\n"); + + rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); + + unsafe { + hal::interrupt::RTC.enable(); + } + + unsafe { + cortex_m::interrupt::enable(); + } + + rtc.start(); + + uart.write_str_blocking("RTC started, waiting for alarm...\r\n"); + + loop { + if rtc.is_alarm_triggered() { + uart.write_str_blocking("\r\n*** ALARM TRIGGERED! ***\r\n"); + break; + } + } + + uart.write_str_blocking("Example complete - Test PASSED!\r\n"); +} diff --git a/examples/src/bin/uart_interrupt.rs b/examples/src/bin/uart_interrupt.rs new file mode 100644 index 000000000..100588727 --- /dev/null +++ b/examples/src/bin/uart_interrupt.rs @@ -0,0 +1,66 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::bind_interrupts; +use embassy_mcxa_examples::init_uart2; +use hal::interrupt::typelevel::Handler; +use hal::uart; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind LPUART2 interrupt to our handler +bind_interrupts!(struct Irqs { + LPUART2 => hal::uart::UartInterruptHandler; +}); + +#[used] +#[no_mangle] +static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2; + +// Wrapper function for the interrupt handler +unsafe extern "C" fn lpuart2_handler() { + hal::uart::UartInterruptHandler::on_interrupt(); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let _p = hal::init(hal::config::Config::default()); + + // Enable/clock UART2 before touching its registers + unsafe { + init_uart2(hal::pac()); + } + let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); + + // Configure LPUART2 interrupt for UART operation BEFORE any UART usage + hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3)); + + // Manually install the interrupt handler and enable RX IRQs in the peripheral + unsafe { + hal::interrupt::LPUART2.install_handler(lpuart2_handler); + // Enable RX interrupts so the handler actually fires on incoming bytes + uart.enable_rx_interrupts(); + } + + // Print welcome message + uart.write_str_blocking("UART interrupt echo demo starting...\r\n"); + uart.write_str_blocking("Type characters to echo them back.\r\n"); + + // Log using defmt if enabled + defmt::info!("UART interrupt echo demo starting..."); + + loop { + // Check if we have received any data + if uart.rx_data_available() { + if let Some(byte) = uart.try_read_byte() { + // Echo it back + uart.write_byte(byte); + uart.write_str_blocking(" (received)\r\n"); + } + } else { + // No data available, wait a bit before checking again + cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz + } + } +} diff --git a/examples/src/common/mod.rs b/examples/src/common/mod.rs new file mode 100644 index 000000000..8cb4590f8 --- /dev/null +++ b/examples/src/common/mod.rs @@ -0,0 +1,45 @@ +//! Shared board-specific helpers for the FRDM-MCXA276 examples. +//! These live with the examples so the HAL stays generic. + +use hal::{clocks, pins, reset}; +use {embassy_mcxa as hal, panic_probe as _}; + +/// Initialize clocks and pin muxing for UART2 debug console. +/// Safe to call multiple times; writes are idempotent for our use. +#[allow(dead_code)] +pub unsafe fn init_uart2(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_uart2_port2(p); + reset::release_reset_port2(p); + reset::release_reset_lpuart2(p); + pins::configure_uart2_pins_port2(); + clocks::select_uart2_clock(p); +} + +/// Initialize clocks for the LED GPIO/PORT used by the blink example. +#[allow(dead_code)] +pub unsafe fn init_led(p: &hal::pac::Peripherals) { + clocks::enable_led_port(p); + reset::release_reset_gpio3(p); + reset::release_reset_port3(p); +} + +/// Initialize clocks for OSTIMER0 (1 MHz source). +#[allow(dead_code)] +pub unsafe fn init_ostimer0(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_ostimer0(p); + reset::release_reset_ostimer0(p); + clocks::select_ostimer0_clock_1m(p); +} + +/// Initialize clocks and pin muxing for ADC. +#[allow(dead_code)] +pub unsafe fn init_adc(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_adc(p); + reset::release_reset_port1(p); + reset::release_reset_adc1(p); + pins::configure_adc_pins(); + clocks::select_adc_clock(p); +} diff --git a/examples/src/lib.rs b/examples/src/lib.rs new file mode 100644 index 000000000..cf4194559 --- /dev/null +++ b/examples/src/lib.rs @@ -0,0 +1,63 @@ +#![no_std] + +//! Shared board-specific helpers for the FRDM-MCXA276 examples. +//! These live with the examples so the HAL stays generic. + +use hal::{clocks, pins, reset}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Initialize clocks and pin muxing for UART2 debug console. +/// Safe to call multiple times; writes are idempotent for our use. +/// +/// # Safety +/// +/// Called only once to initialize the peripheral +#[allow(dead_code)] +pub unsafe fn init_uart2(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_uart2_port2(p); + reset::release_reset_port2(p); + reset::release_reset_lpuart2(p); + pins::configure_uart2_pins_port2(); + clocks::select_uart2_clock(p); +} + +/// Initialize clocks for the LED GPIO/PORT used by the blink example. +/// +/// # Safety +/// +/// Called only once to initialize the peripheral +#[allow(dead_code)] +pub unsafe fn init_led(p: &hal::pac::Peripherals) { + clocks::enable_led_port(p); + reset::release_reset_gpio3(p); + reset::release_reset_port3(p); +} + +/// Initialize clocks for OSTIMER0 (1 MHz source). +/// +/// # Safety +/// +/// Called only once to initialize the peripheral +#[allow(dead_code)] +pub unsafe fn init_ostimer0(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_ostimer0(p); + reset::release_reset_ostimer0(p); + clocks::select_ostimer0_clock_1m(p); +} + +/// Initialize clocks and pin muxing for ADC. +/// +/// # Safety +/// +/// Called only once to initialize the peripheral +#[allow(dead_code)] +pub unsafe fn init_adc(p: &hal::pac::Peripherals) { + clocks::ensure_frolf_running(p); + clocks::enable_adc(p); + reset::release_reset_port1(p); + reset::release_reset_adc1(p); + pins::configure_adc_pins(); + clocks::select_adc_clock(p); +} diff --git a/examples/uart_interrupt.rs b/examples/uart_interrupt.rs deleted file mode 100644 index bd734f859..000000000 --- a/examples/uart_interrupt.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use hal::interrupt::typelevel::Handler; -use hal::uart; - -mod common; - -use embassy_mcxa276::bind_interrupts; -use {defmt_rtt as _, panic_probe as _}; - -// Bind LPUART2 interrupt to our handler -bind_interrupts!(struct Irqs { - LPUART2 => hal::uart::UartInterruptHandler; -}); - -#[used] -#[no_mangle] -static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2; - -// Wrapper function for the interrupt handler -unsafe extern "C" fn lpuart2_handler() { - hal::uart::UartInterruptHandler::on_interrupt(); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); - - // Enable/clock UART2 before touching its registers - unsafe { - common::init_uart2(hal::pac()); - } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); - - // Configure LPUART2 interrupt for UART operation BEFORE any UART usage - hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3)); - - // Manually install the interrupt handler and enable RX IRQs in the peripheral - unsafe { - hal::interrupt::LPUART2.install_handler(lpuart2_handler); - // Enable RX interrupts so the handler actually fires on incoming bytes - uart.enable_rx_interrupts(); - } - - // Print welcome message - uart.write_str_blocking("UART interrupt echo demo starting...\r\n"); - uart.write_str_blocking("Type characters to echo them back.\r\n"); - - // Log using defmt if enabled - defmt::info!("UART interrupt echo demo starting..."); - - loop { - // Check if we have received any data - if uart.rx_data_available() { - if let Some(byte) = uart.try_read_byte() { - // Echo it back - uart.write_byte(byte); - uart.write_str_blocking(" (received)\r\n"); - } - } else { - // No data available, wait a bit before checking again - cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz - } - } -} -- cgit From e799d6c8956ed3ea5ced65d58c3065a22927ad10 Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 14 Nov 2025 17:29:31 +0100 Subject: More work on examples --- examples/adc_interrupt.rs | 15 ++++--- examples/common/mod.rs | 38 +++++----------- examples/lpuart_buffered.rs | 5 +-- examples/ostimer_alarm.rs | 7 +-- examples/ostimer_counter.rs | 8 ++-- examples/ostimer_race_test.rs | 5 ++- examples/uart_interrupt.rs | 100 +++++++++++++++++++++--------------------- 7 files changed, 84 insertions(+), 94 deletions(-) (limited to 'examples') diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs index dc82cfd30..3be85ac75 100644 --- a/examples/adc_interrupt.rs +++ b/examples/adc_interrupt.rs @@ -2,6 +2,8 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4}; +use embassy_mcxa276::clocks::PoweredClock; use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; use hal::uart; use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; @@ -30,10 +32,10 @@ async fn main(_spawner: Spawner) { common::init_uart2(hal::pac()); } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + // let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; + // let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); - uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); + // uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); unsafe { common::init_adc(hal::pac()); @@ -50,6 +52,9 @@ async fn main(_spawner: Spawner) { enable_conv_pause: false, conv_pause_delay: 0, fifo_watermark: 0, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: AdcClockSel::FroLfDiv, + div: Div4::no_div(), }; let adc = hal::adc::Adc::::new(p.ADC1, adc_config); @@ -66,7 +71,7 @@ async fn main(_spawner: Spawner) { conv_trigger_config.enable_hardware_trigger = false; adc.set_conv_trigger_config(0, &conv_trigger_config); - uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); + // uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); adc.enable_interrupt(0x1); @@ -83,7 +88,7 @@ async fn main(_spawner: Spawner) { while !adc.is_interrupt_triggered() { // Wait until the interrupt is triggered } - uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); + // uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); //TBD need to print the value } } diff --git a/examples/common/mod.rs b/examples/common/mod.rs index 8c52c8e86..7b197a590 100644 --- a/examples/common/mod.rs +++ b/examples/common/mod.rs @@ -1,45 +1,31 @@ //! Shared board-specific helpers for the FRDM-MCXA276 examples. //! These live with the examples so the HAL stays generic. -use hal::{clocks, pins, reset}; +use hal::{clocks, pins}; use {embassy_mcxa276 as hal, panic_probe as _}; /// Initialize clocks and pin muxing for UART2 debug console. /// Safe to call multiple times; writes are idempotent for our use. #[allow(dead_code)] -pub unsafe fn init_uart2(p: &mcxa_pac::Peripherals) { - clocks::ensure_frolf_running(p); - clocks::enable_uart2_port2(p); - reset::release_reset_port2(p); - reset::release_reset_lpuart2(p); +pub unsafe fn init_uart2(_p: &mcxa_pac::Peripherals) { + // NOTE: Lpuart has been updated to properly enable + reset its own clocks. + // GPIO has not. + _ = clocks::enable_and_reset::(&clocks::NoConfig); pins::configure_uart2_pins_port2(); - clocks::select_uart2_clock(p); } /// Initialize clocks for the LED GPIO/PORT used by the blink example. #[allow(dead_code)] -pub unsafe fn init_led(p: &mcxa_pac::Peripherals) { - clocks::enable_led_port(p); - reset::release_reset_gpio3(p); - reset::release_reset_port3(p); -} - -/// Initialize clocks for OSTIMER0 (1 MHz source). -#[allow(dead_code)] -pub unsafe fn init_ostimer0(p: &mcxa_pac::Peripherals) { - clocks::ensure_frolf_running(p); - clocks::enable_ostimer0(p); - reset::release_reset_ostimer0(p); - clocks::select_ostimer0_clock_1m(p); +pub unsafe fn init_led(_p: &mcxa_pac::Peripherals) { + _ = clocks::enable_and_reset::(&clocks::NoConfig); + _ = clocks::enable_and_reset::(&clocks::NoConfig); } /// Initialize clocks and pin muxing for ADC. #[allow(dead_code)] -pub unsafe fn init_adc(p: &mcxa_pac::Peripherals) { - clocks::ensure_frolf_running(p); - clocks::enable_adc(p); - reset::release_reset_port1(p); - reset::release_reset_adc1(p); +pub unsafe fn init_adc(_p: &mcxa_pac::Peripherals) { + // NOTE: Lpuart has been updated to properly enable + reset its own clocks. + // GPIO has not. + _ = clocks::enable_and_reset::(&clocks::NoConfig); pins::configure_adc_pins(); - clocks::select_adc_clock(p); } diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs index 35d311143..6ae690c56 100644 --- a/examples/lpuart_buffered.rs +++ b/examples/lpuart_buffered.rs @@ -12,18 +12,17 @@ mod common; // Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver bind_interrupts!(struct Irqs { - LPUART2 => lpuart::buffered::BufferedInterruptHandler::; + LPUART2 => lpuart::buffered::BufferedInterruptHandler::; }); // Wrapper function for the interrupt handler unsafe extern "C" fn lpuart2_handler() { - lpuart::buffered::BufferedInterruptHandler::::on_interrupt(); + lpuart::buffered::BufferedInterruptHandler::::on_interrupt(); } #[embassy_executor::main] async fn main(_spawner: Spawner) { let _p = hal::init(hal::config::Config::default()); - let p2 = lpuart::lib::init(); unsafe { hal::interrupt::install_irq_handler(mcxa_pac::Interrupt::LPUART2, lpuart2_handler); diff --git a/examples/ostimer_alarm.rs b/examples/ostimer_alarm.rs index 78ca4bbc5..4f29a2c7c 100644 --- a/examples/ostimer_alarm.rs +++ b/examples/ostimer_alarm.rs @@ -9,7 +9,7 @@ use {cortex_m, embassy_mcxa276 as hal}; mod common; -use embassy_mcxa276::bind_interrupts; +use embassy_mcxa276::{bind_interrupts, clocks::{periph_helpers::OstimerClockSel, PoweredClock}}; use {defmt_rtt as _, panic_probe as _}; // Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. @@ -50,9 +50,10 @@ async fn main(_spawner: Spawner) { // Create OSTIMER instance let config = hal::ostimer::Config { init_match_max: true, - clock_frequency_hz: 1_000_000, // 1MHz + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: OstimerClockSel::Clk1M, }; - let ostimer = hal::ostimer::Ostimer::::new(p.OSTIMER0, config, hal::pac()); + let ostimer = hal::ostimer::Ostimer::::new(p.OSTIMER0, config); // Create alarm with callback let alarm = hal::ostimer::Alarm::new() diff --git a/examples/ostimer_counter.rs b/examples/ostimer_counter.rs index e95140a88..069e879d8 100644 --- a/examples/ostimer_counter.rs +++ b/examples/ostimer_counter.rs @@ -7,6 +7,7 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa276::clocks::{periph_helpers::OstimerClockSel, PoweredClock}; use embassy_time::{Duration, Timer}; use hal::bind_interrupts; use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; @@ -22,9 +23,6 @@ async fn main(_spawner: Spawner) { let p = hal::init(Default::default()); // Enable/clock OSTIMER0 and UART2 before touching their registers - unsafe { - common::init_ostimer0(hal::pac()); - } unsafe { common::init_uart2(hal::pac()); } @@ -44,9 +42,9 @@ async fn main(_spawner: Spawner) { p.OSTIMER0, hal::ostimer::Config { init_match_max: true, - clock_frequency_hz: 1_000_000, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: OstimerClockSel::Clk1M, }, - hal::pac(), ); // Read initial counter value diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs index 368a3e52f..6e3d4ac21 100644 --- a/examples/ostimer_race_test.rs +++ b/examples/ostimer_race_test.rs @@ -12,6 +12,7 @@ use core::sync::atomic::{AtomicU32, Ordering}; use embassy_executor::Spawner; +use embassy_mcxa276::clocks::{periph_helpers::OstimerClockSel, PoweredClock}; use embassy_time::{Duration, Timer}; use hal::bind_interrupts; use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; @@ -98,9 +99,9 @@ async fn main(_spawner: Spawner) { p.OSTIMER0, hal::ostimer::Config { init_match_max: true, - clock_frequency_hz: 1_000_000, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: OstimerClockSel::Clk1M, }, - hal::pac(), ); uart.write_str_blocking("OSTIMER instance created\n"); diff --git a/examples/uart_interrupt.rs b/examples/uart_interrupt.rs index bd734f859..190a4d850 100644 --- a/examples/uart_interrupt.rs +++ b/examples/uart_interrupt.rs @@ -2,68 +2,68 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use hal::interrupt::typelevel::Handler; -use hal::uart; +// use embassy_mcxa276 as hal; +// use hal::interrupt::typelevel::Handler; +// use hal::uart; -mod common; +// mod common; -use embassy_mcxa276::bind_interrupts; -use {defmt_rtt as _, panic_probe as _}; +// use embassy_mcxa276::bind_interrupts; +// use {defmt_rtt as _, panic_probe as _}; -// Bind LPUART2 interrupt to our handler -bind_interrupts!(struct Irqs { - LPUART2 => hal::uart::UartInterruptHandler; -}); +// // Bind LPUART2 interrupt to our handler +// bind_interrupts!(struct Irqs { +// LPUART2 => hal::uart::UartInterruptHandler; +// }); -#[used] -#[no_mangle] -static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2; +// #[used] +// #[no_mangle] +// static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2; -// Wrapper function for the interrupt handler -unsafe extern "C" fn lpuart2_handler() { - hal::uart::UartInterruptHandler::on_interrupt(); -} +// // Wrapper function for the interrupt handler +// unsafe extern "C" fn lpuart2_handler() { +// hal::uart::UartInterruptHandler::on_interrupt(); +// } #[embassy_executor::main] async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); +// let _p = hal::init(hal::config::Config::default()); - // Enable/clock UART2 before touching its registers - unsafe { - common::init_uart2(hal::pac()); - } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); +// // Enable/clock UART2 before touching its registers +// unsafe { +// common::init_uart2(hal::pac()); +// } +// let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; +// let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); - // Configure LPUART2 interrupt for UART operation BEFORE any UART usage - hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3)); +// // Configure LPUART2 interrupt for UART operation BEFORE any UART usage +// hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3)); - // Manually install the interrupt handler and enable RX IRQs in the peripheral - unsafe { - hal::interrupt::LPUART2.install_handler(lpuart2_handler); - // Enable RX interrupts so the handler actually fires on incoming bytes - uart.enable_rx_interrupts(); - } +// // Manually install the interrupt handler and enable RX IRQs in the peripheral +// unsafe { +// hal::interrupt::LPUART2.install_handler(lpuart2_handler); +// // Enable RX interrupts so the handler actually fires on incoming bytes +// uart.enable_rx_interrupts(); +// } - // Print welcome message - uart.write_str_blocking("UART interrupt echo demo starting...\r\n"); - uart.write_str_blocking("Type characters to echo them back.\r\n"); +// // Print welcome message +// uart.write_str_blocking("UART interrupt echo demo starting...\r\n"); +// uart.write_str_blocking("Type characters to echo them back.\r\n"); - // Log using defmt if enabled - defmt::info!("UART interrupt echo demo starting..."); +// // Log using defmt if enabled +// defmt::info!("UART interrupt echo demo starting..."); - loop { - // Check if we have received any data - if uart.rx_data_available() { - if let Some(byte) = uart.try_read_byte() { - // Echo it back - uart.write_byte(byte); - uart.write_str_blocking(" (received)\r\n"); - } - } else { - // No data available, wait a bit before checking again - cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz - } - } +// loop { +// // Check if we have received any data +// if uart.rx_data_available() { +// if let Some(byte) = uart.try_read_byte() { +// // Echo it back +// uart.write_byte(byte); +// uart.write_str_blocking(" (received)\r\n"); +// } +// } else { +// // No data available, wait a bit before checking again +// cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz +// } +// } } -- cgit From 8cdccae3c6c4a805cf5003b1a859734c105d76e8 Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 14 Nov 2025 18:43:27 +0100 Subject: Continue working on examples --- examples/adc_interrupt.rs | 29 ++++++++++++------ examples/adc_polling.rs | 30 +++++++++++++++--- examples/blink.rs | 4 --- examples/hello.rs | 33 ++++++++++++-------- examples/lpuart_buffered.rs | 9 +++--- examples/lpuart_polling.rs | 11 +++---- examples/ostimer_alarm.rs | 32 +++++++++++++------ examples/ostimer_async.rs | 29 ++++++++++++------ examples/ostimer_counter.rs | 26 +++++++++++++--- examples/ostimer_race_test.rs | 71 +++++++++++++++++++++++++------------------ examples/rtc_alarm.rs | 28 ++++++++++++----- examples/uart_interrupt.rs | 69 ----------------------------------------- 12 files changed, 200 insertions(+), 171 deletions(-) delete mode 100644 examples/uart_interrupt.rs (limited to 'examples') diff --git a/examples/adc_interrupt.rs b/examples/adc_interrupt.rs index 3be85ac75..536152539 100644 --- a/examples/adc_interrupt.rs +++ b/examples/adc_interrupt.rs @@ -4,13 +4,13 @@ use embassy_executor::Spawner; use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4}; use embassy_mcxa276::clocks::PoweredClock; +use embassy_mcxa276::lpuart::{Config, Lpuart}; use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; -use hal::uart; use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; use mcxa_pac::adc1::cmdl1::{Adch, Mode}; use mcxa_pac::adc1::ctrl::CalAvgs; use mcxa_pac::adc1::tctrl::Tcmd; -use {cortex_m, embassy_mcxa276 as hal}; +use {embassy_mcxa276 as hal}; mod common; use hal::{bind_interrupts, InterruptExt}; @@ -28,14 +28,25 @@ static KEEP_ADC: unsafe extern "C" fn() = ADC1; async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { common::init_uart2(hal::pac()); } - - // let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - // let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); - - // uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin + config, + ) + .unwrap(); unsafe { common::init_adc(hal::pac()); @@ -71,7 +82,7 @@ async fn main(_spawner: Spawner) { conv_trigger_config.enable_hardware_trigger = false; adc.set_conv_trigger_config(0, &conv_trigger_config); - // uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); + uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); adc.enable_interrupt(0x1); @@ -88,7 +99,7 @@ async fn main(_spawner: Spawner) { while !adc.is_interrupt_triggered() { // Wait until the interrupt is triggered } - // uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); + uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); //TBD need to print the value } } diff --git a/examples/adc_polling.rs b/examples/adc_polling.rs index 4b5f9422d..2fe4153db 100644 --- a/examples/adc_polling.rs +++ b/examples/adc_polling.rs @@ -2,9 +2,11 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa276::clocks::periph_helpers::{AdcClockSel, Div4}; +use embassy_mcxa276::clocks::PoweredClock; +use embassy_mcxa276::lpuart::{Config, Lpuart}; use embassy_mcxa276 as hal; use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; -use hal::uart; use mcxa_pac::adc1::cfg::{Pwrsel, Refsel}; use mcxa_pac::adc1::cmdl1::{Adch, Mode}; use mcxa_pac::adc1::ctrl::CalAvgs; @@ -27,10 +29,27 @@ async fn main(_spawner: Spawner) { common::init_uart2(hal::pac()); } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + unsafe { + common::init_uart2(hal::pac()); + } + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin + config, + ) + .unwrap(); - uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); + uart.blocking_write(b"\r\n=== ADC polling Example ===\r\n").unwrap(); unsafe { common::init_adc(hal::pac()); @@ -47,6 +66,9 @@ async fn main(_spawner: Spawner) { enable_conv_pause: false, conv_pause_delay: 0, fifo_watermark: 0, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: AdcClockSel::FroLfDiv, + div: Div4::no_div(), }; let adc = hal::adc::Adc::::new(p.ADC1, adc_config); diff --git a/examples/blink.rs b/examples/blink.rs index 564353d5c..0f489abb9 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -28,10 +28,6 @@ async fn main(_spawner: Spawner) { unsafe { common::init_led(hal::pac()); } - // Initialize OSTIMER for async timing - unsafe { - common::init_ostimer0(hal::pac()); - } // Initialize embassy-time global driver backed by OSTIMER0 hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); diff --git a/examples/hello.rs b/examples/hello.rs index e39adaced..dbb53fdcf 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -2,15 +2,14 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use hal::uart; +use embassy_mcxa276::{self as hal, lpuart::{Blocking, Config, Lpuart}}; mod common; use {defmt_rtt as _, panic_probe as _}; /// Simple helper to write a byte as hex to UART -fn write_hex_byte(uart: &hal::uart::Uart, byte: u8) { +fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) { const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); @@ -22,15 +21,25 @@ async fn main(_spawner: Spawner) { defmt::info!("boot"); - // Board-level init for UART2 clocks and pins. + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { common::init_uart2(hal::pac()); } - - // Get UART source frequency from clock configuration - // Using hardcoded frequency for now - dynamic detection may have issues - let src = 12_000_000; // FRO_LF_DIV at 12MHz with DIV=0 - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin + config, + ) + .unwrap(); // Print welcome message before any async delays to guarantee early console output uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); @@ -69,12 +78,12 @@ async fn main(_spawner: Spawner) { let num_str = &command[4..]; if let Ok(num) = parse_u8(num_str) { uart.write_str_blocking("Hex: 0x"); - write_hex_byte(&uart, num); + write_hex_byte(&mut uart, num); uart.write_str_blocking("\r\n"); } else { uart.write_str_blocking("Invalid number for hex command\r\n"); } - } else if command.len() > 0 { + } else if !command.is_empty() { uart.write_str_blocking("Unknown command: "); uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); uart.write_str_blocking("\r\n"); @@ -103,7 +112,7 @@ async fn main(_spawner: Spawner) { fn parse_u8(bytes: &[u8]) -> Result { let mut result = 0u8; for &b in bytes { - if b >= b'0' && b <= b'9' { + if b.is_ascii_digit() { result = result.checked_mul(10).ok_or(())?; result = result.checked_add(b - b'0').ok_or(())?; } else { diff --git a/examples/lpuart_buffered.rs b/examples/lpuart_buffered.rs index 6ae690c56..9e297ca67 100644 --- a/examples/lpuart_buffered.rs +++ b/examples/lpuart_buffered.rs @@ -22,7 +22,7 @@ unsafe extern "C" fn lpuart2_handler() { #[embassy_executor::main] async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); + let p = hal::init(hal::config::Config::default()); unsafe { hal::interrupt::install_irq_handler(mcxa_pac::Interrupt::LPUART2, lpuart2_handler); @@ -33,7 +33,6 @@ async fn main(_spawner: Spawner) { unsafe { common::init_uart2(hal::pac()); - common::init_ostimer0(hal::pac()); } // UART configuration (enable both TX and RX) @@ -51,9 +50,9 @@ async fn main(_spawner: Spawner) { // Create a buffered LPUART2 instance with both TX and RX let mut uart = BufferedLpuart::new( - p2.LPUART2, - p2.PIO2_2, // TX pin - p2.PIO2_3, // RX pin + p.LPUART2, + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin Irqs, &mut tx_buf, &mut rx_buf, diff --git a/examples/lpuart_polling.rs b/examples/lpuart_polling.rs index 067c7eb53..c9630dca5 100644 --- a/examples/lpuart_polling.rs +++ b/examples/lpuart_polling.rs @@ -4,14 +4,13 @@ use embassy_executor::Spawner; use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; -use crate::hal::lpuart::{lib, Config, Lpuart}; +use crate::hal::lpuart::{Config, Lpuart}; mod common; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); - let p2 = lib::init(); + let p = hal::init(hal::config::Config::default()); defmt::info!("boot"); @@ -30,9 +29,9 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX let lpuart = Lpuart::new_blocking( - p2.LPUART2, // Peripheral - p2.PIO2_2, // TX pin - p2.PIO2_3, // RX pin + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin config, ) .unwrap(); diff --git a/examples/ostimer_alarm.rs b/examples/ostimer_alarm.rs index 4f29a2c7c..f3a84d312 100644 --- a/examples/ostimer_alarm.rs +++ b/examples/ostimer_alarm.rs @@ -4,12 +4,15 @@ use core::sync::atomic::{AtomicBool, Ordering}; use embassy_executor::Spawner; -use hal::uart; -use {cortex_m, embassy_mcxa276 as hal}; +use embassy_mcxa276 as hal; mod common; -use embassy_mcxa276::{bind_interrupts, clocks::{periph_helpers::OstimerClockSel, PoweredClock}}; +use embassy_mcxa276::{ + bind_interrupts, + clocks::{periph_helpers::OstimerClockSel, PoweredClock}, + lpuart::{Config, Lpuart}, +}; use {defmt_rtt as _, panic_probe as _}; // Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. @@ -33,15 +36,26 @@ fn alarm_callback() { async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); - // Enable/clock OSTIMER0 and UART2 before touching their registers - unsafe { - common::init_ostimer0(hal::pac()); - } + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { common::init_uart2(hal::pac()); } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin + config, + ) + .unwrap(); + uart.write_str_blocking("OSTIMER Alarm Example\n"); // Initialize embassy-time global driver backed by OSTIMER0 diff --git a/examples/ostimer_async.rs b/examples/ostimer_async.rs index 27e14e022..2642a633d 100644 --- a/examples/ostimer_async.rs +++ b/examples/ostimer_async.rs @@ -2,8 +2,7 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa276 as hal; -use hal::uart; +use embassy_mcxa276::{self as hal, lpuart::{Config, Lpuart}}; mod common; @@ -22,18 +21,28 @@ static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); + let p = hal::init(hal::config::Config::default()); - // Enable/clock OSTIMER0 and UART2 before touching their registers - unsafe { - common::init_ostimer0(hal::pac()); - } + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { common::init_uart2(hal::pac()); } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); - uart.write_str_blocking("boot\n"); + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin + config, + ) + .unwrap(); + uart.blocking_write(b"boot\n").unwrap(); // Avoid mass NVIC writes here; DefaultHandler now safely returns. diff --git a/examples/ostimer_counter.rs b/examples/ostimer_counter.rs index 069e879d8..590c5a14b 100644 --- a/examples/ostimer_counter.rs +++ b/examples/ostimer_counter.rs @@ -7,7 +7,10 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa276::clocks::{periph_helpers::OstimerClockSel, PoweredClock}; +use embassy_mcxa276::{ + clocks::{periph_helpers::OstimerClockSel, PoweredClock}, + lpuart::{Blocking, Config, Lpuart}, +}; use embassy_time::{Duration, Timer}; use hal::bind_interrupts; use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; @@ -22,12 +25,25 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let p = hal::init(Default::default()); - // Enable/clock OSTIMER0 and UART2 before touching their registers + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { common::init_uart2(hal::pac()); } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin + config, + ) + .unwrap(); uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); @@ -90,7 +106,7 @@ async fn main(_spawner: Spawner) { } // Helper function to write a u64 value as decimal string -fn write_u64(uart: &mut hal::uart::Uart, value: u64) { +fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) { if value == 0 { uart.write_str_blocking("0"); return; diff --git a/examples/ostimer_race_test.rs b/examples/ostimer_race_test.rs index 6e3d4ac21..131d10f64 100644 --- a/examples/ostimer_race_test.rs +++ b/examples/ostimer_race_test.rs @@ -12,7 +12,10 @@ use core::sync::atomic::{AtomicU32, Ordering}; use embassy_executor::Spawner; -use embassy_mcxa276::clocks::{periph_helpers::OstimerClockSel, PoweredClock}; +use embassy_mcxa276::{ + clocks::{periph_helpers::OstimerClockSel, PoweredClock}, + lpuart::{Blocking, Config, Lpuart}, +}; use embassy_time::{Duration, Timer}; use hal::bind_interrupts; use {defmt_rtt as _, embassy_mcxa276 as hal, panic_probe as _}; @@ -43,7 +46,7 @@ fn alarm_callback() { } } -fn report_default_handler(uart: &mut hal::uart::Uart) { +fn report_default_handler(uart: &mut Lpuart<'_, Blocking>) { let snapshot = hal::interrupt::default_handler_snapshot(); if snapshot.count == 0 { return; @@ -72,15 +75,25 @@ fn report_default_handler(uart: &mut hal::uart::Uart) { async fn main(_spawner: Spawner) { let p = hal::init(Default::default()); - // Enable/clock OSTIMER0 and UART2 before touching their registers - unsafe { - common::init_ostimer0(hal::pac()); - } + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { common::init_uart2(hal::pac()); } - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let mut uart = hal::uart::Uart::::new(p.LPUART2, hal::uart::Config::new(src)); + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin + config, + ) + .unwrap(); uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); @@ -140,7 +153,7 @@ async fn main(_spawner: Spawner) { // Test rapid alarm scheduling to stress interrupt handling async fn test_rapid_alarms( ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut hal::uart::Uart, + uart: &mut Lpuart<'_, Blocking>, ) { let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); @@ -177,7 +190,7 @@ async fn test_rapid_alarms( // Test reading counter while interrupts are firing async fn test_counter_reading_during_interrupts( ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut hal::uart::Uart, + uart: &mut Lpuart<'_, Blocking>, ) { let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); @@ -238,7 +251,7 @@ async fn test_counter_reading_during_interrupts( // Test concurrent timer operations (embassy-time + alarms) async fn test_concurrent_operations( ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut hal::uart::Uart, + uart: &mut Lpuart<'_, Blocking>, ) { let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); @@ -267,7 +280,7 @@ async fn test_concurrent_operations( // Test timer reset during active operations async fn test_reset_during_operation( ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut hal::uart::Uart, + uart: &mut Lpuart<'_, Blocking>, peripherals: &mcxa_pac::Peripherals, ) { let initial_counter = ostimer.now(); @@ -308,7 +321,7 @@ async fn test_reset_during_operation( } // Helper function to write a u32 value as decimal string -fn write_u32(uart: &mut hal::uart::Uart, value: u32) { +fn write_u32(uart: &mut Lpuart<'_, Blocking>, value: u32) { if value == 0 { uart.write_str_blocking("0"); return; @@ -343,7 +356,7 @@ fn write_u32(uart: &mut hal::uart::Uart, value: u32) { } } -fn write_hex32(uart: &mut hal::uart::Uart, value: u32) { +fn write_hex32(uart: &mut Lpuart<'_, Blocking>, value: u32) { let mut buf = [b'0'; 8]; let mut tmp = value; for i in (0..8).rev() { @@ -355,15 +368,13 @@ fn write_hex32(uart: &mut hal::uart::Uart, value: u32) { }; tmp >>= 4; } - for b in &buf { - uart.write_byte(*b); - } + uart.blocking_write(&buf).unwrap(); } // Helper function to write a u64 value as decimal string -fn write_u64(uart: &mut hal::uart::Uart, value: u64) { +fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) { if value == 0 { - uart.write_str_blocking("0"); + uart.blocking_write(b"0").unwrap(); return; } @@ -381,17 +392,17 @@ fn write_u64(uart: &mut hal::uart::Uart, value: u64) { while i > 0 { i -= 1; match buffer[i] { - b'0' => uart.write_str_blocking("0"), - b'1' => uart.write_str_blocking("1"), - b'2' => uart.write_str_blocking("2"), - b'3' => uart.write_str_blocking("3"), - b'4' => uart.write_str_blocking("4"), - b'5' => uart.write_str_blocking("5"), - b'6' => uart.write_str_blocking("6"), - b'7' => uart.write_str_blocking("7"), - b'8' => uart.write_str_blocking("8"), - b'9' => uart.write_str_blocking("9"), - _ => uart.write_str_blocking("?"), + b'0' => uart.blocking_write(b"0").unwrap(), + b'1' => uart.blocking_write(b"1").unwrap(), + b'2' => uart.blocking_write(b"2").unwrap(), + b'3' => uart.blocking_write(b"3").unwrap(), + b'4' => uart.blocking_write(b"4").unwrap(), + b'5' => uart.blocking_write(b"5").unwrap(), + b'6' => uart.blocking_write(b"6").unwrap(), + b'7' => uart.blocking_write(b"7").unwrap(), + b'8' => uart.blocking_write(b"8").unwrap(), + b'9' => uart.blocking_write(b"9").unwrap(), + _ => uart.blocking_write(b"?").unwrap(), } } } diff --git a/examples/rtc_alarm.rs b/examples/rtc_alarm.rs index c27fd4c55..1cda37054 100644 --- a/examples/rtc_alarm.rs +++ b/examples/rtc_alarm.rs @@ -2,13 +2,14 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa276::lpuart::{Config, Lpuart}; use hal::rtc::{RtcDateTime, RtcInterruptEnable}; -use hal::{uart, InterruptExt}; -use {cortex_m, embassy_mcxa276 as hal}; +use hal::InterruptExt; +use {embassy_mcxa276 as hal}; mod common; -type MyRtc = hal::rtc::Rtc; +type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>; use embassy_mcxa276::bind_interrupts; use {defmt_rtt as _, panic_probe as _}; @@ -25,17 +26,28 @@ static KEEP_RTC: unsafe extern "C" fn() = RTC; async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { common::init_uart2(hal::pac()); } - - let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; - let uart = uart::Uart::::new(p.LPUART2, uart::Config::new(src)); + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.PIO2_2, // TX pin + p.PIO2_3, // RX pin + config, + ) + .unwrap(); uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n"); - unsafe { hal::clocks::init_fro16k(hal::pac()) }; - let rtc_config = hal::rtc::get_default_config(); let rtc = MyRtc::new(p.RTC0, rtc_config); diff --git a/examples/uart_interrupt.rs b/examples/uart_interrupt.rs deleted file mode 100644 index 190a4d850..000000000 --- a/examples/uart_interrupt.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -// use embassy_mcxa276 as hal; -// use hal::interrupt::typelevel::Handler; -// use hal::uart; - -// mod common; - -// use embassy_mcxa276::bind_interrupts; -// use {defmt_rtt as _, panic_probe as _}; - -// // Bind LPUART2 interrupt to our handler -// bind_interrupts!(struct Irqs { -// LPUART2 => hal::uart::UartInterruptHandler; -// }); - -// #[used] -// #[no_mangle] -// static KEEP_LPUART2: unsafe extern "C" fn() = LPUART2; - -// // Wrapper function for the interrupt handler -// unsafe extern "C" fn lpuart2_handler() { -// hal::uart::UartInterruptHandler::on_interrupt(); -// } - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { -// let _p = hal::init(hal::config::Config::default()); - -// // Enable/clock UART2 before touching its registers -// unsafe { -// common::init_uart2(hal::pac()); -// } -// let src = unsafe { hal::clocks::uart2_src_hz(hal::pac()) }; -// let uart = uart::Uart::::new(_p.LPUART2, uart::Config::new(src)); - -// // Configure LPUART2 interrupt for UART operation BEFORE any UART usage -// hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::from(3)); - -// // Manually install the interrupt handler and enable RX IRQs in the peripheral -// unsafe { -// hal::interrupt::LPUART2.install_handler(lpuart2_handler); -// // Enable RX interrupts so the handler actually fires on incoming bytes -// uart.enable_rx_interrupts(); -// } - -// // Print welcome message -// uart.write_str_blocking("UART interrupt echo demo starting...\r\n"); -// uart.write_str_blocking("Type characters to echo them back.\r\n"); - -// // Log using defmt if enabled -// defmt::info!("UART interrupt echo demo starting..."); - -// loop { -// // Check if we have received any data -// if uart.rx_data_available() { -// if let Some(byte) = uart.try_read_byte() { -// // Echo it back -// uart.write_byte(byte); -// uart.write_str_blocking(" (received)\r\n"); -// } -// } else { -// // No data available, wait a bit before checking again -// cortex_m::asm::delay(12_000_000); // ~1 second at 12MHz -// } -// } -} -- cgit From 1f589e9428542cd94bc630b623accf04d9c36edf Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 14 Nov 2025 19:08:16 +0100 Subject: A little follow-up cleanup --- examples/src/bin/adc_interrupt.rs | 5 +++-- examples/src/bin/adc_polling.rs | 8 ++++---- examples/src/bin/blink.rs | 4 ++-- examples/src/bin/hello.rs | 2 +- examples/src/bin/lpuart_buffered.rs | 7 ++++--- examples/src/bin/lpuart_polling.rs | 4 ++-- examples/src/bin/ostimer_alarm.rs | 4 ++-- examples/src/bin/ostimer_async.rs | 9 +++++---- examples/src/bin/ostimer_counter.rs | 2 +- examples/src/bin/ostimer_race_test.rs | 2 +- examples/src/bin/rtc_alarm.rs | 9 +++++---- examples/src/lib.rs | 10 ++++------ 12 files changed, 34 insertions(+), 32 deletions(-) (limited to 'examples') diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs index be08ebf8c..6812ba5d3 100644 --- a/examples/src/bin/adc_interrupt.rs +++ b/examples/src/bin/adc_interrupt.rs @@ -2,6 +2,7 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa_examples::init_adc_pins; use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::clocks::PoweredClock; @@ -35,7 +36,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { - embassy_mcxa_examples::init_uart2(hal::pac()); + embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral @@ -47,7 +48,7 @@ async fn main(_spawner: Spawner) { uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); unsafe { - embassy_mcxa_examples::init_adc(hal::pac()); + init_adc_pins(hal::pac()); } let adc_config = LpadcConfig { diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs index 723f1e044..421306e9b 100644 --- a/examples/src/bin/adc_polling.rs +++ b/examples/src/bin/adc_polling.rs @@ -4,7 +4,7 @@ use core::fmt::Write; use embassy_executor::Spawner; -use embassy_mcxa_examples::{init_adc, init_uart2}; +use embassy_mcxa_examples::{init_adc_pins, init_uart2_pins}; use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::clocks::PoweredClock; @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); unsafe { - init_uart2(hal::pac()); + init_uart2_pins(hal::pac()); } // Create UART configuration @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { - init_uart2(hal::pac()); + init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral @@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) { uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); unsafe { - init_adc(hal::pac()); + init_adc_pins(hal::pac()); } let adc_config = LpadcConfig { diff --git a/examples/src/bin/blink.rs b/examples/src/bin/blink.rs index ee59ac591..8c48e79f1 100644 --- a/examples/src/bin/blink.rs +++ b/examples/src/bin/blink.rs @@ -4,7 +4,7 @@ use embassy_executor::Spawner; use embassy_mcxa as hal; use embassy_mcxa::bind_interrupts; -use embassy_mcxa_examples::init_led; +use embassy_mcxa_examples::init_led_gpio_clocks; use embassy_time::{Duration, Timer}; use hal::gpio::pins::PIO3_18; use hal::gpio::{Level, Output}; @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { let _p = hal::init(hal::config::Config::default()); unsafe { - init_led(hal::pac()); + init_led_gpio_clocks(hal::pac()); } // Initialize embassy-time global driver backed by OSTIMER0 diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs index ff7afa01d..207c157c3 100644 --- a/examples/src/bin/hello.rs +++ b/examples/src/bin/hello.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { - embassy_mcxa_examples::init_uart2(hal::pac()); + embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs index e96ab7b81..642d4af65 100644 --- a/examples/src/bin/lpuart_buffered.rs +++ b/examples/src/bin/lpuart_buffered.rs @@ -5,8 +5,9 @@ use embassy_executor::Spawner; use embassy_mcxa as hal; use embassy_mcxa::interrupt::typelevel::Handler; use embassy_mcxa::lpuart::buffered::BufferedLpuart; +use embassy_mcxa::lpuart::Config; use embassy_mcxa::{bind_interrupts, lpuart}; -use embassy_mcxa_examples::init_uart2; +use embassy_mcxa_examples::init_uart2_pins; use embedded_io_async::{Read, Write}; // Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver @@ -31,11 +32,11 @@ async fn main(_spawner: Spawner) { hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); unsafe { - init_uart2(hal::pac()); + init_uart2_pins(hal::pac()); } // UART configuration (enable both TX and RX) - let config = lpuart::Config { + let config = Config { baudrate_bps: 115_200, enable_tx: true, enable_rx: true, diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs index bdcfa0776..bea82c33e 100644 --- a/examples/src/bin/lpuart_polling.rs +++ b/examples/src/bin/lpuart_polling.rs @@ -2,7 +2,7 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa_examples::init_uart2; +use embassy_mcxa_examples::init_uart2_pins; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; use crate::hal::lpuart::{Config, Lpuart}; @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { // Board-level init for UART2 clocks and pins. unsafe { - init_uart2(hal::pac()); + init_uart2_pins(hal::pac()); } // Create UART configuration diff --git a/examples/src/bin/ostimer_alarm.rs b/examples/src/bin/ostimer_alarm.rs index 9e858b60b..36b1f403a 100644 --- a/examples/src/bin/ostimer_alarm.rs +++ b/examples/src/bin/ostimer_alarm.rs @@ -8,7 +8,7 @@ use embassy_mcxa::bind_interrupts; use embassy_mcxa::clocks::periph_helpers::OstimerClockSel; use embassy_mcxa::clocks::PoweredClock; use embassy_mcxa::lpuart::{Config, Lpuart}; -use embassy_mcxa_examples::init_uart2; +use embassy_mcxa_examples::init_uart2_pins; use {cortex_m, defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. @@ -42,7 +42,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { - init_uart2(hal::pac()); + init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral diff --git a/examples/src/bin/ostimer_async.rs b/examples/src/bin/ostimer_async.rs index 4e692a744..881f09374 100644 --- a/examples/src/bin/ostimer_async.rs +++ b/examples/src/bin/ostimer_async.rs @@ -3,8 +3,9 @@ use embassy_executor::Spawner; use embassy_mcxa::bind_interrupts; -use embassy_mcxa_examples::init_uart2; +use embassy_mcxa_examples::init_uart2_pins; use embassy_time::{Duration, Timer}; +use hal::lpuart::{Config, Lpuart}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed. @@ -21,7 +22,7 @@ async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); // Create UART configuration - let config = hal::lpuart::Config { + let config = Config { baudrate_bps: 115_200, enable_tx: true, enable_rx: true, @@ -30,9 +31,9 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { - init_uart2(hal::pac()); + init_uart2_pins(hal::pac()); } - let mut uart = hal::lpuart::Lpuart::new_blocking( + let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral p.PIO2_2, // TX pin p.PIO2_3, // RX pin diff --git a/examples/src/bin/ostimer_counter.rs b/examples/src/bin/ostimer_counter.rs index 47543160b..2fbc251b9 100644 --- a/examples/src/bin/ostimer_counter.rs +++ b/examples/src/bin/ostimer_counter.rs @@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { - embassy_mcxa_examples::init_uart2(hal::pac()); + embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral diff --git a/examples/src/bin/ostimer_race_test.rs b/examples/src/bin/ostimer_race_test.rs index c2ecff969..168a952cd 100644 --- a/examples/src/bin/ostimer_race_test.rs +++ b/examples/src/bin/ostimer_race_test.rs @@ -82,7 +82,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { - embassy_mcxa_examples::init_uart2(hal::pac()); + embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs index e2eaa6ae2..40a1207df 100644 --- a/examples/src/bin/rtc_alarm.rs +++ b/examples/src/bin/rtc_alarm.rs @@ -2,9 +2,10 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa as hal; +use hal::lpuart::{Config, Lpuart}; use hal::rtc::{RtcDateTime, RtcInterruptEnable}; use hal::InterruptExt; -use {cortex_m, embassy_mcxa as hal}; type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>; @@ -24,7 +25,7 @@ async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); // Create UART configuration - let config = hal::lpuart::Config { + let config = Config { baudrate_bps: 115_200, enable_tx: true, enable_rx: true, @@ -33,9 +34,9 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX unsafe { - embassy_mcxa_examples::init_uart2(hal::pac()); + embassy_mcxa_examples::init_uart2_pins(hal::pac()); } - let mut uart = hal::lpuart::Lpuart::new_blocking( + let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral p.PIO2_2, // TX pin p.PIO2_3, // RX pin diff --git a/examples/src/lib.rs b/examples/src/lib.rs index a45ab708d..be4761c32 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![allow(clippy::missing_safety_doc)] //! Shared board-specific helpers for the FRDM-MCXA276 examples. //! These live with the examples so the HAL stays generic. @@ -8,8 +9,7 @@ use {embassy_mcxa as hal, panic_probe as _}; /// Initialize clocks and pin muxing for UART2 debug console. /// Safe to call multiple times; writes are idempotent for our use. -#[allow(dead_code)] -pub unsafe fn init_uart2(_p: &hal::pac::Peripherals) { +pub unsafe fn init_uart2_pins(_p: &hal::pac::Peripherals) { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. // GPIO has not. _ = clocks::enable_and_reset::(&clocks::NoConfig); @@ -17,15 +17,13 @@ pub unsafe fn init_uart2(_p: &hal::pac::Peripherals) { } /// Initialize clocks for the LED GPIO/PORT used by the blink example. -#[allow(dead_code)] -pub unsafe fn init_led(_p: &hal::pac::Peripherals) { +pub unsafe fn init_led_gpio_clocks(_p: &hal::pac::Peripherals) { _ = clocks::enable_and_reset::(&clocks::NoConfig); _ = clocks::enable_and_reset::(&clocks::NoConfig); } /// Initialize clocks and pin muxing for ADC. -#[allow(dead_code)] -pub unsafe fn init_adc(_p: &hal::pac::Peripherals) { +pub unsafe fn init_adc_pins(_p: &hal::pac::Peripherals) { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. // GPIO has not. _ = clocks::enable_and_reset::(&clocks::NoConfig); -- cgit From 728340ba05e9a16ceb472b147737c38c144d292d Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 14 Nov 2025 19:11:06 +0100 Subject: Remove redundant import --- examples/src/bin/ostimer_alarm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/src/bin/ostimer_alarm.rs b/examples/src/bin/ostimer_alarm.rs index 36b1f403a..03fb93319 100644 --- a/examples/src/bin/ostimer_alarm.rs +++ b/examples/src/bin/ostimer_alarm.rs @@ -9,7 +9,7 @@ use embassy_mcxa::clocks::periph_helpers::OstimerClockSel; use embassy_mcxa::clocks::PoweredClock; use embassy_mcxa::lpuart::{Config, Lpuart}; use embassy_mcxa_examples::init_uart2_pins; -use {cortex_m, defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. bind_interrupts!(struct Irqs { -- cgit From a0c8e2d0299f3ae8eb24cd264d2b8e87f2bce464 Mon Sep 17 00:00:00 2001 From: James Munns Date: Mon, 17 Nov 2025 15:02:26 +0100 Subject: Restore examples --- examples/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/src/lib.rs b/examples/src/lib.rs index be4761c32..2018a3c25 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -12,20 +12,20 @@ use {embassy_mcxa as hal, panic_probe as _}; pub unsafe fn init_uart2_pins(_p: &hal::pac::Peripherals) { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. // GPIO has not. - _ = clocks::enable_and_reset::(&clocks::NoConfig); + _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); pins::configure_uart2_pins_port2(); } /// Initialize clocks for the LED GPIO/PORT used by the blink example. pub unsafe fn init_led_gpio_clocks(_p: &hal::pac::Peripherals) { - _ = clocks::enable_and_reset::(&clocks::NoConfig); - _ = clocks::enable_and_reset::(&clocks::NoConfig); + _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); + _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); } /// Initialize clocks and pin muxing for ADC. pub unsafe fn init_adc_pins(_p: &hal::pac::Peripherals) { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. // GPIO has not. - _ = clocks::enable_and_reset::(&clocks::NoConfig); + _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); pins::configure_adc_pins(); } -- cgit From 02285c2153d22f2c0c93a4ce920cdebc03f18658 Mon Sep 17 00:00:00 2001 From: James Munns Date: Mon, 17 Nov 2025 16:38:32 +0100 Subject: Correct clk/rst field logic --- examples/memory.x | 4 ++-- examples/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/memory.x b/examples/memory.x index f4263a412..528545b64 100644 --- a/examples/memory.x +++ b/examples/memory.x @@ -1,5 +1,5 @@ MEMORY { - FLASH : ORIGIN = 0x20000000, LENGTH = 64K - RAM : ORIGIN = 0x20010000, LENGTH = 64K + FLASH : ORIGIN = 0x20000000, LENGTH = 80K + RAM : ORIGIN = 0x20014000, LENGTH = 48K } diff --git a/examples/src/lib.rs b/examples/src/lib.rs index 2018a3c25..4bb334da5 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -5,7 +5,7 @@ //! These live with the examples so the HAL stays generic. use hal::{clocks, pins}; -use {embassy_mcxa as hal, panic_probe as _}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; /// Initialize clocks and pin muxing for UART2 debug console. /// Safe to call multiple times; writes are idempotent for our use. -- cgit From bf3ae8e4d69ef2e2ecfdf0b48734d9c91637eb16 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 17 Nov 2025 16:27:39 -0800 Subject: Let HAL build in isolation (#21) * Revert "chore(deps): bump embedded-io-async from 0.6.1 to 0.7.0 (#17)" This reverts commit 011c3b2de9361496faa0eea75ae19a77f2698f88. * Let HAL build in isolation while at that, also remove bogus dependency on embassy-executor. Signed-off-by: Felipe Balbi * Certify syn 2.0.110 Signed-off-by: Felipe Balbi --------- Signed-off-by: Felipe Balbi --- examples/Cargo.lock | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/Cargo.lock b/examples/Cargo.lock index b774aff97..b2ac9a051 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -240,7 +240,6 @@ dependencies = [ "critical-section", "defmt", "embassy-embedded-hal", - "embassy-executor", "embassy-hal-internal", "embassy-sync", "embassy-time", -- cgit From 62e297c130ac26afe4d7d5752bb79709bd370e39 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 17 Nov 2025 16:34:11 -0800 Subject: Allow writing binary to flash (#20) Turns out probe-rs works out of the box. Signed-off-by: Felipe Balbi --- examples/.cargo/config.toml | 2 +- examples/Cargo.toml | 4 ++++ examples/memory.x | 4 ++-- examples/src/bin/blink.rs | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml index ecb11be64..aedc55b06 100644 --- a/examples/.cargo/config.toml +++ b/examples/.cargo/config.toml @@ -1,5 +1,5 @@ [target.thumbv8m.main-none-eabihf] -runner = 'probe-rs run --chip MCXA276 --preverify --verify' +runner = 'probe-rs run --chip MCXA276 --preverify --verify --protocol swd --speed 12000' rustflags = [ "-C", "linker=flip-link", diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 6b100de42..d03d3d95c 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -19,3 +19,7 @@ embassy-time-driver = "0.2.1" embedded-io-async = "0.6.1" heapless = "0.9.2" panic-probe = { version = "1.0", features = ["print-defmt"] } + +[profile.release] +lto = true # better optimizations +debug = 2 # enough information for defmt/rtt locations diff --git a/examples/memory.x b/examples/memory.x index f4263a412..315ced58a 100644 --- a/examples/memory.x +++ b/examples/memory.x @@ -1,5 +1,5 @@ MEMORY { - FLASH : ORIGIN = 0x20000000, LENGTH = 64K - RAM : ORIGIN = 0x20010000, LENGTH = 64K + FLASH : ORIGIN = 0x00000000, LENGTH = 1M + RAM : ORIGIN = 0x20000000, LENGTH = 128K } diff --git a/examples/src/bin/blink.rs b/examples/src/bin/blink.rs index d8a57c546..c36fc9421 100644 --- a/examples/src/bin/blink.rs +++ b/examples/src/bin/blink.rs @@ -27,6 +27,8 @@ async fn main(_spawner: Spawner) { init_ostimer0(hal::pac()); } + defmt::info!("Blink example"); + // Initialize embassy-time global driver backed by OSTIMER0 hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); @@ -42,6 +44,8 @@ async fn main(_spawner: Spawner) { // With pauses between letters and words loop { + defmt::info!("SOS"); + // S: three short blinks for _ in 0..3 { led.set_low(); -- cgit From ffe3e5acae6c0038db4176dc7d031b57f865e07f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 18 Nov 2025 12:16:14 -0800 Subject: Correct gpio driver (#9) * Correct gpio driver Signed-off-by: Felipe Balbi * Simplify blinky example Make it look like every other HAL for consistency. While at that, also rename the example to match the name used by other HALs. Signed-off-by: Felipe Balbi * Add some documentation to GPIO driver Signed-off-by: Felipe Balbi * Enable GPIO clocks during HAL initialization Provide the user with working GPIO clocks. Signed-off-by: Felipe Balbi --------- Signed-off-by: Felipe Balbi Co-authored-by: Felipe Balbi --- examples/src/bin/adc_interrupt.rs | 6 +-- examples/src/bin/adc_polling.rs | 6 +-- examples/src/bin/blink.rs | 81 ----------------------------------- examples/src/bin/blinky.rs | 49 +++++++++++++++++++++ examples/src/bin/hello.rs | 6 +-- examples/src/bin/lpuart_buffered.rs | 4 +- examples/src/bin/lpuart_polling.rs | 6 +-- examples/src/bin/ostimer_alarm.rs | 6 +-- examples/src/bin/ostimer_async.rs | 6 +-- examples/src/bin/ostimer_counter.rs | 6 +-- examples/src/bin/ostimer_race_test.rs | 6 +-- examples/src/bin/rtc_alarm.rs | 6 +-- examples/src/lib.rs | 6 --- 13 files changed, 78 insertions(+), 116 deletions(-) delete mode 100644 examples/src/bin/blink.rs create mode 100644 examples/src/bin/blinky.rs (limited to 'examples') diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs index 6812ba5d3..9fed052fd 100644 --- a/examples/src/bin/adc_interrupt.rs +++ b/examples/src/bin/adc_interrupt.rs @@ -34,14 +34,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs index 421306e9b..545f8f77a 100644 --- a/examples/src/bin/adc_polling.rs +++ b/examples/src/bin/adc_polling.rs @@ -34,14 +34,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/blink.rs b/examples/src/bin/blink.rs deleted file mode 100644 index d8b158d50..000000000 --- a/examples/src/bin/blink.rs +++ /dev/null @@ -1,81 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa as hal; -use embassy_mcxa::bind_interrupts; -use embassy_mcxa_examples::init_led_gpio_clocks; -use embassy_time::{Duration, Timer}; -use hal::gpio::pins::PIO3_18; -use hal::gpio::{Level, Output}; - -// Bind only OS_EVENT for timer interrupts -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let _p = hal::init(hal::config::Config::default()); - - unsafe { - init_led_gpio_clocks(hal::pac()); - } - - defmt::info!("Blink example"); - - // Initialize embassy-time global driver backed by OSTIMER0 - hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); - - // Configure LED pin for GPIO mode - PIO3_18::set_mux_gpio(); - - let mut led = Output::new(PIO3_18::degrade(), Level::High); - - // Complex blinking pattern: SOS in Morse code - // S: ... (3 short) - // O: --- (3 long) - // S: ... (3 short) - // With pauses between letters and words - - loop { - defmt::info!("SOS"); - - // S: three short blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(150)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Pause between letters - Timer::after(Duration::from_millis(300)).await; - - // O: three long blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(450)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Pause between letters - Timer::after(Duration::from_millis(300)).await; - - // S: three short blinks - for _ in 0..3 { - led.set_low(); - Timer::after(Duration::from_millis(150)).await; - led.set_high(); - Timer::after(Duration::from_millis(150)).await; - } - - // Long pause between words (SOS repeats) - Timer::after(Duration::from_millis(1000)).await; - } -} diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs new file mode 100644 index 000000000..28d83a12e --- /dev/null +++ b/examples/src/bin/blinky.rs @@ -0,0 +1,49 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::bind_interrupts; +use embassy_time::Timer; +use hal::gpio::{Level, Output}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind only OS_EVENT for timer interrupts +bind_interrupts!(struct Irqs { + OS_EVENT => hal::ostimer::time_driver::OsEventHandler; +}); + +#[used] +#[no_mangle] +static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("Blink example"); + + // Initialize embassy-time global driver backed by OSTIMER0 + hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); + + let mut red = Output::new(p.P3_18, Level::High); + let mut green = Output::new(p.P3_19, Level::High); + let mut blue = Output::new(p.P3_21, Level::High); + + loop { + defmt::info!("Toggle LEDs"); + + red.toggle(); + Timer::after_millis(250).await; + + red.toggle(); + green.toggle(); + Timer::after_millis(250).await; + + green.toggle(); + blue.toggle(); + Timer::after_millis(250).await; + blue.toggle(); + + Timer::after_millis(250).await; + } +} diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs index 207c157c3..e2d0b413d 100644 --- a/examples/src/bin/hello.rs +++ b/examples/src/bin/hello.rs @@ -26,14 +26,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs index 642d4af65..b0d19ef16 100644 --- a/examples/src/bin/lpuart_buffered.rs +++ b/examples/src/bin/lpuart_buffered.rs @@ -51,8 +51,8 @@ async fn main(_spawner: Spawner) { // Create a buffered LPUART2 instance with both TX and RX let mut uart = BufferedLpuart::new( p.LPUART2, - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin Irqs, &mut tx_buf, &mut rx_buf, diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs index bea82c33e..525d42e2c 100644 --- a/examples/src/bin/lpuart_polling.rs +++ b/examples/src/bin/lpuart_polling.rs @@ -26,11 +26,11 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX let lpuart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/ostimer_alarm.rs b/examples/src/bin/ostimer_alarm.rs index 03fb93319..6d38741b7 100644 --- a/examples/src/bin/ostimer_alarm.rs +++ b/examples/src/bin/ostimer_alarm.rs @@ -40,14 +40,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/ostimer_async.rs b/examples/src/bin/ostimer_async.rs index 881f09374..f043184e7 100644 --- a/examples/src/bin/ostimer_async.rs +++ b/examples/src/bin/ostimer_async.rs @@ -29,14 +29,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/ostimer_counter.rs b/examples/src/bin/ostimer_counter.rs index 2fbc251b9..f36915ff2 100644 --- a/examples/src/bin/ostimer_counter.rs +++ b/examples/src/bin/ostimer_counter.rs @@ -30,14 +30,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/ostimer_race_test.rs b/examples/src/bin/ostimer_race_test.rs index 168a952cd..0106b92a7 100644 --- a/examples/src/bin/ostimer_race_test.rs +++ b/examples/src/bin/ostimer_race_test.rs @@ -80,14 +80,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs index 40a1207df..a54b4a817 100644 --- a/examples/src/bin/rtc_alarm.rs +++ b/examples/src/bin/rtc_alarm.rs @@ -32,14 +32,14 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create UART instance using LPUART2 with PIO2_2 as TX and PIO2_3 as RX + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { embassy_mcxa_examples::init_uart2_pins(hal::pac()); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral - p.PIO2_2, // TX pin - p.PIO2_3, // RX pin + p.P2_2, // TX pin + p.P2_3, // RX pin config, ) .unwrap(); diff --git a/examples/src/lib.rs b/examples/src/lib.rs index 4bb334da5..66b93450a 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -16,12 +16,6 @@ pub unsafe fn init_uart2_pins(_p: &hal::pac::Peripherals) { pins::configure_uart2_pins_port2(); } -/// Initialize clocks for the LED GPIO/PORT used by the blink example. -pub unsafe fn init_led_gpio_clocks(_p: &hal::pac::Peripherals) { - _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); - _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); -} - /// Initialize clocks and pin muxing for ADC. pub unsafe fn init_adc_pins(_p: &hal::pac::Peripherals) { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. -- cgit From a8eb124e47e633cd81e0863253d5f6bdd7545260 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 19 Nov 2025 09:11:54 -0800 Subject: OSTimer updates (#24) * Initialize OSTIMER0 during HAL initialization Provide the user with a working time driver. Signed-off-by: Felipe Balbi * Handle time_driver interrupt internally Signed-off-by: Felipe Balbi * Gate `time-driver` impl behind a `time` flag Also prevents creation of an `Ostimer` instance if the `time` feature is active. * Remove some dead code --------- Signed-off-by: Felipe Balbi Co-authored-by: James Munns --- examples/Cargo.lock | 1 + examples/Cargo.toml | 4 +- examples/src/bin/blinky.rs | 13 -- examples/src/bin/ostimer_alarm.rs | 122 ---------- examples/src/bin/ostimer_async.rs | 64 ------ examples/src/bin/ostimer_counter.rs | 139 ------------ examples/src/bin/ostimer_race_test.rs | 405 ---------------------------------- 7 files changed, 3 insertions(+), 745 deletions(-) delete mode 100644 examples/src/bin/ostimer_alarm.rs delete mode 100644 examples/src/bin/ostimer_async.rs delete mode 100644 examples/src/bin/ostimer_counter.rs delete mode 100644 examples/src/bin/ostimer_race_test.rs (limited to 'examples') diff --git a/examples/Cargo.lock b/examples/Cargo.lock index b2ac9a051..14f472cbf 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -446,6 +446,7 @@ source = "git+https://github.com/OpenDevicePartnership/mcxa-pac?rev=3ab4c868f75a dependencies = [ "cortex-m", "cortex-m-rt", + "critical-section", "vcell", ] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d03d3d95c..d1c6a2071 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -6,13 +6,13 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = { version = "0.7", features = ["critical-section-single-core"] } -cortex-m-rt = { version = "0.7", features = ["device"] } +cortex-m-rt = { version = "0.7" } critical-section = "1.2.0" defmt = "1.0" defmt-rtt = "1.0" embassy-embedded-hal = "0.5.0" embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } -embassy-mcxa = { path = "../", features = ["defmt", "rt", "unstable-pac"] } +embassy-mcxa = { path = "../", features = ["defmt", "rt", "unstable-pac", "time"] } embassy-sync = "0.7.2" embassy-time = "0.5.0" embassy-time-driver = "0.2.1" diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs index 28d83a12e..ab1e59bdb 100644 --- a/examples/src/bin/blinky.rs +++ b/examples/src/bin/blinky.rs @@ -2,29 +2,16 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa::bind_interrupts; use embassy_time::Timer; use hal::gpio::{Level, Output}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -// Bind only OS_EVENT for timer interrupts -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); defmt::info!("Blink example"); - // Initialize embassy-time global driver backed by OSTIMER0 - hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); - let mut red = Output::new(p.P3_18, Level::High); let mut green = Output::new(p.P3_19, Level::High); let mut blue = Output::new(p.P3_21, Level::High); diff --git a/examples/src/bin/ostimer_alarm.rs b/examples/src/bin/ostimer_alarm.rs deleted file mode 100644 index 6d38741b7..000000000 --- a/examples/src/bin/ostimer_alarm.rs +++ /dev/null @@ -1,122 +0,0 @@ -#![no_std] -#![no_main] - -use core::sync::atomic::{AtomicBool, Ordering}; - -use embassy_executor::Spawner; -use embassy_mcxa::bind_interrupts; -use embassy_mcxa::clocks::periph_helpers::OstimerClockSel; -use embassy_mcxa::clocks::PoweredClock; -use embassy_mcxa::lpuart::{Config, Lpuart}; -use embassy_mcxa_examples::init_uart2_pins; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind only OS_EVENT, and retain the symbol explicitly so it can't be GC'ed. -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -// Global flag for alarm callback -static ALARM_FLAG: AtomicBool = AtomicBool::new(false); - -// Alarm callback function -fn alarm_callback() { - ALARM_FLAG.store(true, Ordering::Release); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - unsafe { - init_uart2_pins(hal::pac()); - } - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - - uart.write_str_blocking("OSTIMER Alarm Example\n"); - - // Initialize embassy-time global driver backed by OSTIMER0 - hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); - - // Create OSTIMER instance - let config = hal::ostimer::Config { - init_match_max: true, - power: PoweredClock::NormalEnabledDeepSleepDisabled, - source: OstimerClockSel::Clk1M, - }; - let ostimer = hal::ostimer::Ostimer::::new(p.OSTIMER0, config); - - // Create alarm with callback - let alarm = hal::ostimer::Alarm::new() - .with_callback(alarm_callback) - .with_flag(&ALARM_FLAG); - - uart.write_str_blocking("Scheduling alarm for 2 seconds...\n"); - - // Schedule alarm to expire in 2 seconds (2,000,000 microseconds) - let scheduled = ostimer.schedule_alarm_delay(&alarm, 2_000_000); - if scheduled { - uart.write_str_blocking("Alarm scheduled successfully\n"); - } else { - uart.write_str_blocking("Failed to schedule alarm (would exceed timer capacity)\n"); - return; - } - - // Wait for alarm to expire - loop { - // Check if alarm has expired - if ALARM_FLAG.load(Ordering::Acquire) { - uart.write_str_blocking("Alarm expired! Callback executed.\n"); - break; - } - - // Busy wait - don't use Timer::after_millis as it interferes with alarm MATCH - for _ in 0..100000 { - cortex_m::asm::nop(); - } - } - - // Demonstrate canceling an alarm - uart.write_str_blocking("Scheduling another alarm for 3 seconds...\n"); - ALARM_FLAG.store(false, Ordering::Release); // Reset flag - - let scheduled = ostimer.schedule_alarm_delay(&alarm, 3_000_000); - if scheduled { - uart.write_str_blocking("Alarm scheduled. Waiting 1 second then canceling...\n"); - - // Wait 1 second - embassy_time::Timer::after_millis(1000).await; - - // Cancel the alarm - ostimer.cancel_alarm(&alarm); - uart.write_str_blocking("Alarm canceled\n"); - - // Check immediately if alarm flag is set - if !ALARM_FLAG.load(Ordering::Acquire) { - uart.write_str_blocking("Alarm was successfully canceled\n"); - } else { - uart.write_str_blocking("Alarm fired despite cancellation\n"); - } - } - - uart.write_str_blocking("Example complete\n"); -} diff --git a/examples/src/bin/ostimer_async.rs b/examples/src/bin/ostimer_async.rs deleted file mode 100644 index f043184e7..000000000 --- a/examples/src/bin/ostimer_async.rs +++ /dev/null @@ -1,64 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::bind_interrupts; -use embassy_mcxa_examples::init_uart2_pins; -use embassy_time::{Duration, Timer}; -use hal::lpuart::{Config, Lpuart}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind only OS_EVENT, and retain the symbol explicitly so it can’t be GC’ed. -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - unsafe { - init_uart2_pins(hal::pac()); - } - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - uart.blocking_write(b"boot\n").unwrap(); - - // Avoid mass NVIC writes here; DefaultHandler now safely returns. - - // Initialize embassy-time global driver backed by OSTIMER0 (re-enables OS_EVENT with priority) - // The bind_interrupts! macro handles handler binding automatically - - // Initialize OSTIMER with default 1MHz frequency - // Adjust this value to match your actual OSTIMER clock frequency - hal::ostimer::time_driver::init(hal::config::Config::default().time_interrupt_priority, 1_000_000); - - // Removed force-pend; rely on real hardware match to trigger OS_EVENT. - - // Log using defmt if enabled - defmt::info!("OSTIMER async example starting..."); - - loop { - defmt::info!("tick"); - uart.write_str_blocking("tick\n"); - Timer::after(Duration::from_millis(1000)).await; - } -} diff --git a/examples/src/bin/ostimer_counter.rs b/examples/src/bin/ostimer_counter.rs deleted file mode 100644 index f36915ff2..000000000 --- a/examples/src/bin/ostimer_counter.rs +++ /dev/null @@ -1,139 +0,0 @@ -//! # OSTIMER Counter Reading and Reset Example -//! -//! This example demonstrates the new timer counter reading and reset functionality -//! of the OSTIMER driver. - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::periph_helpers::OstimerClockSel; -use embassy_mcxa::clocks::PoweredClock; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart}; -use embassy_time::{Duration, Timer}; -use hal::bind_interrupts; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(Default::default()); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - unsafe { - embassy_mcxa_examples::init_uart2_pins(hal::pac()); - } - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - - uart.write_str_blocking("OSTIMER Counter Reading and Reset Example\n"); - - // Initialize the OSTIMER time driver - hal::ostimer::time_driver::init( - hal::interrupt::Priority::from(3), - 1_000_000, // 1MHz clock - ); - - // Create OSTIMER instance - let ostimer = hal::ostimer::Ostimer::::new( - p.OSTIMER0, - hal::ostimer::Config { - init_match_max: true, - power: PoweredClock::NormalEnabledDeepSleepDisabled, - source: OstimerClockSel::Clk1M, - }, - ); - - // Read initial counter value - let initial_counter = ostimer.now(); - uart.write_str_blocking("Initial counter value: "); - write_u64(&mut uart, initial_counter); - uart.write_str_blocking("\n"); - - // Wait a bit to let counter increment - Timer::after(Duration::from_millis(100)).await; - - // Read counter again - let counter_after_wait = ostimer.now(); - uart.write_str_blocking("Counter after 100ms wait: "); - write_u64(&mut uart, counter_after_wait); - uart.write_str_blocking("\n"); - uart.write_str_blocking("Difference: "); - write_u64(&mut uart, counter_after_wait - initial_counter); - uart.write_str_blocking(" ticks\n"); - - // Reset the timer - uart.write_str_blocking("Resetting timer...\n"); - ostimer.reset(hal::pac()); - - // Read counter after reset - let counter_after_reset = ostimer.now(); - uart.write_str_blocking("Counter after reset: "); - write_u64(&mut uart, counter_after_reset); - uart.write_str_blocking("\n"); - - // Wait again to verify timer is working - Timer::after(Duration::from_millis(50)).await; - - let final_counter = ostimer.now(); - uart.write_str_blocking("Counter after another 50ms: "); - write_u64(&mut uart, final_counter); - uart.write_str_blocking("\n"); - uart.write_str_blocking("Difference after reset: "); - write_u64(&mut uart, final_counter - counter_after_reset); - uart.write_str_blocking(" ticks\n"); - - uart.write_str_blocking("Example complete\n"); -} - -// Helper function to write a u64 value as decimal string -fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) { - if value == 0 { - uart.write_str_blocking("0"); - return; - } - - let mut buffer = [0u8; 20]; // Enough for max u64 - let mut i = 0; - let mut v = value; - - while v > 0 { - buffer[i] = b'0' + (v % 10) as u8; - v /= 10; - i += 1; - } - - // Write digits in reverse order - while i > 0 { - i -= 1; - match buffer[i] { - b'0' => uart.write_str_blocking("0"), - b'1' => uart.write_str_blocking("1"), - b'2' => uart.write_str_blocking("2"), - b'3' => uart.write_str_blocking("3"), - b'4' => uart.write_str_blocking("4"), - b'5' => uart.write_str_blocking("5"), - b'6' => uart.write_str_blocking("6"), - b'7' => uart.write_str_blocking("7"), - b'8' => uart.write_str_blocking("8"), - b'9' => uart.write_str_blocking("9"), - _ => uart.write_str_blocking("?"), - } - } -} diff --git a/examples/src/bin/ostimer_race_test.rs b/examples/src/bin/ostimer_race_test.rs deleted file mode 100644 index 0106b92a7..000000000 --- a/examples/src/bin/ostimer_race_test.rs +++ /dev/null @@ -1,405 +0,0 @@ -//! # OSTIMER Race Condition Test -//! -//! This example tests for race conditions in the OSTIMER driver by: -//! - Scheduling alarms sequentially (hardware limitation: only one at a time) -//! - Reading the counter during interrupt-heavy periods -//! - Testing concurrent timer operations -//! - Stress testing interrupt handling - -#![no_std] -#![no_main] - -use core::sync::atomic::{AtomicU32, Ordering}; - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::periph_helpers::OstimerClockSel; -use embassy_mcxa::clocks::PoweredClock; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart}; -use embassy_time::{Duration, Timer}; -use hal::bind_interrupts; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -bind_interrupts!(struct Irqs { - OS_EVENT => hal::ostimer::time_driver::OsEventHandler; -}); - -#[used] -#[no_mangle] -static KEEP_OS_EVENT: unsafe extern "C" fn() = OS_EVENT; - -// Global counters for race condition detection -static ALARM_CALLBACK_COUNT: AtomicU32 = AtomicU32::new(0); -static INTERRUPT_COUNT: AtomicU32 = AtomicU32::new(0); -static RACE_DETECTED: AtomicU32 = AtomicU32::new(0); - -// Alarm callback function -fn alarm_callback() { - let _count = ALARM_CALLBACK_COUNT.fetch_add(1, Ordering::SeqCst); - INTERRUPT_COUNT.fetch_add(1, Ordering::SeqCst); - - // Simulate some work in the callback to increase chance of races - for _ in 0..10 { - cortex_m::asm::nop(); - } -} - -fn report_default_handler(uart: &mut Lpuart<'_, Blocking>) { - let snapshot = hal::interrupt::default_handler_snapshot(); - if snapshot.count == 0 { - return; - } - - uart.write_str_blocking("WARNING: DefaultHandler executed "); - write_u32(uart, snapshot.count); - uart.write_str_blocking(" time(s). Vector="); - write_u32(uart, snapshot.vector as u32); - uart.write_str_blocking(" CFSR=0x"); - write_hex32(uart, snapshot.cfsr); - uart.write_str_blocking(" HFSR=0x"); - write_hex32(uart, snapshot.hfsr); - uart.write_str_blocking(" PC=0x"); - write_hex32(uart, snapshot.stacked_pc); - uart.write_str_blocking(" LR=0x"); - write_hex32(uart, snapshot.stacked_lr); - uart.write_str_blocking(" SP=0x"); - write_hex32(uart, snapshot.stacked_sp); - uart.write_str_blocking("\n"); - - hal::interrupt::clear_default_handler_snapshot(); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(Default::default()); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - unsafe { - embassy_mcxa_examples::init_uart2_pins(hal::pac()); - } - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - - uart.write_str_blocking("OSTIMER Race Condition Test Starting...\n"); - - // The bind_interrupts! macro handles handler binding automatically - - // Initialize the OSTIMER time driver FIRST - hal::ostimer::time_driver::init( - hal::interrupt::Priority::from(3), - 1_000_000, // 1MHz clock - ); - - uart.write_str_blocking("Time driver initialized\n"); - - // Create OSTIMER instance - let ostimer = hal::ostimer::Ostimer::::new( - p.OSTIMER0, - hal::ostimer::Config { - init_match_max: true, - power: PoweredClock::NormalEnabledDeepSleepDisabled, - source: OstimerClockSel::Clk1M, - }, - ); - - uart.write_str_blocking("OSTIMER instance created\n"); - - // Test 1: Sequential alarm scheduling (OSTIMER only supports one alarm at a time) - uart.write_str_blocking("Test 1: Sequential alarm scheduling...\n"); - test_rapid_alarms(&ostimer, &mut uart).await; - report_default_handler(&mut uart); - - // Test 2: Counter reading during interrupts - uart.write_str_blocking("Test 2: Counter reading during interrupts...\n"); - test_counter_reading_during_interrupts(&ostimer, &mut uart).await; - report_default_handler(&mut uart); - - // Test 3: Concurrent timer operations - uart.write_str_blocking("Test 3: Concurrent timer operations...\n"); - test_concurrent_operations(&ostimer, &mut uart).await; - report_default_handler(&mut uart); - - // Test 4: Timer reset during operation - uart.write_str_blocking("Test 4: Timer reset during operation...\n"); - test_reset_during_operation(&ostimer, &mut uart, hal::pac()).await; - report_default_handler(&mut uart); - - // Report results - uart.write_str_blocking("Race condition test complete\n"); - uart.write_str_blocking("Callback count: "); - write_u32(&mut uart, ALARM_CALLBACK_COUNT.load(Ordering::SeqCst)); - uart.write_str_blocking("\nInterrupt count: "); - write_u32(&mut uart, INTERRUPT_COUNT.load(Ordering::SeqCst)); - uart.write_str_blocking("\nRaces detected: "); - write_u32(&mut uart, RACE_DETECTED.load(Ordering::SeqCst)); - uart.write_str_blocking("\n"); -} - -// Test rapid alarm scheduling to stress interrupt handling -async fn test_rapid_alarms( - ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut Lpuart<'_, Blocking>, -) { - let initial_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); - - // Schedule 10 alarms sequentially (OSTIMER only supports one alarm at a time) - for _i in 0..10 { - let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); - let delay_us = 1000; // 1ms delay for each alarm - if ostimer.schedule_alarm_delay(&alarm, delay_us) { - // Wait for this alarm to complete before scheduling the next - Timer::after(Duration::from_micros(delay_us + 100)).await; - report_default_handler(uart); - } else { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm (match not ready)\n"); - } - } - - // All alarms should have completed by now - let final_count = ALARM_CALLBACK_COUNT.load(Ordering::SeqCst); - let expected_count = initial_count + 10; - - if final_count != expected_count { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Expected "); - write_u32(uart, expected_count); - uart.write_str_blocking(" callbacks, got "); - write_u32(uart, final_count); - uart.write_str_blocking("\n"); - } else { - uart.write_str_blocking("PASS: All rapid alarms executed\n"); - } -} - -// Test reading counter while interrupts are firing -async fn test_counter_reading_during_interrupts( - ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut Lpuart<'_, Blocking>, -) { - let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); - - // Schedule an alarm that will fire soon - let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); - if !ostimer.schedule_alarm_delay(&alarm, 500) { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before counter stress\n"); - } - - // While alarm is pending, read the counter many times rapidly - // This tests if counter reading is atomic and doesn't get corrupted by interrupts - let mut last_counter = ostimer.now(); - let mut consistent_reads = 0; - let mut total_reads = 0; - - for _ in 0..1000 { - let current_counter = ostimer.now(); - total_reads += 1; - - // Check if counter is monotonically increasing (basic sanity check) - if current_counter >= last_counter { - consistent_reads += 1; - } - last_counter = current_counter; - - // Small delay between reads - for _ in 0..10 { - cortex_m::asm::nop(); - } - - report_default_handler(uart); - } - - // Wait for alarm to complete - Timer::after(Duration::from_millis(1)).await; - - let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); - - if consistent_reads == total_reads { - uart.write_str_blocking("PASS: Counter reading consistent during interrupts\n"); - } else { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Counter reading inconsistent: "); - write_u32(uart, consistent_reads); - uart.write_str_blocking("/"); - write_u32(uart, total_reads); - uart.write_str_blocking(" consistent\n"); - } - - if final_interrupt_count > initial_interrupt_count { - uart.write_str_blocking("PASS: Interrupt fired during counter reading test\n"); - } else { - uart.write_str_blocking("WARNING: No interrupt fired during counter reading test\n"); - } -} - -// Test concurrent timer operations (embassy-time + alarms) -async fn test_concurrent_operations( - ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut Lpuart<'_, Blocking>, -) { - let initial_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); - - // Start an embassy-time timer - let timer_future = Timer::after(Duration::from_millis(2)); - - // Schedule an alarm that should fire before the timer - let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); - if !ostimer.schedule_alarm_delay(&alarm, 1000) { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before concurrent operations\n"); - } - - // Wait for both to complete - timer_future.await; - - let final_interrupt_count = INTERRUPT_COUNT.load(Ordering::SeqCst); - - if final_interrupt_count > initial_interrupt_count { - uart.write_str_blocking("PASS: Concurrent operations completed\n"); - } else { - uart.write_str_blocking("WARNING: No interrupts during concurrent operations\n"); - } -} - -// Test timer reset during active operations -async fn test_reset_during_operation( - ostimer: &hal::ostimer::Ostimer<'_, hal::ostimer::Ostimer0>, - uart: &mut Lpuart<'_, Blocking>, - peripherals: &hal::pac::Peripherals, -) { - let initial_counter = ostimer.now(); - - // Schedule an alarm - let alarm = hal::ostimer::Alarm::new().with_callback(alarm_callback); - if !ostimer.schedule_alarm_delay(&alarm, 2000) { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Failed to program OSTIMER alarm before reset test\n"); - } - - // Wait a bit then reset the timer - Timer::after(Duration::from_millis(1)).await; - ostimer.reset(peripherals); - - // Check counter after reset - let counter_after_reset = ostimer.now(); - - // Wait to see if the alarm still fires (it shouldn't after reset) - Timer::after(Duration::from_millis(2)).await; - - let final_counter = ostimer.now(); - - if counter_after_reset < initial_counter { - uart.write_str_blocking("PASS: Timer reset successful\n"); - } else { - RACE_DETECTED.fetch_add(1, Ordering::SeqCst); - uart.write_str_blocking("ERROR: Timer reset may have failed\n"); - } - - uart.write_str_blocking("Counter progression after reset: "); - write_u64(uart, initial_counter); - uart.write_str_blocking(" -> "); - write_u64(uart, counter_after_reset); - uart.write_str_blocking(" -> "); - write_u64(uart, final_counter); - uart.write_str_blocking("\n"); -} - -// Helper function to write a u32 value as decimal string -fn write_u32(uart: &mut Lpuart<'_, Blocking>, value: u32) { - if value == 0 { - uart.write_str_blocking("0"); - return; - } - - let mut buffer = [0u8; 10]; // Enough for max u32 - let mut i = 0; - let mut v = value; - - while v > 0 { - buffer[i] = b'0' + (v % 10) as u8; - v /= 10; - i += 1; - } - - // Write digits in reverse order - while i > 0 { - i -= 1; - match buffer[i] { - b'0' => uart.write_str_blocking("0"), - b'1' => uart.write_str_blocking("1"), - b'2' => uart.write_str_blocking("2"), - b'3' => uart.write_str_blocking("3"), - b'4' => uart.write_str_blocking("4"), - b'5' => uart.write_str_blocking("5"), - b'6' => uart.write_str_blocking("6"), - b'7' => uart.write_str_blocking("7"), - b'8' => uart.write_str_blocking("8"), - b'9' => uart.write_str_blocking("9"), - _ => uart.write_str_blocking("?"), - } - } -} - -fn write_hex32(uart: &mut Lpuart<'_, Blocking>, value: u32) { - let mut buf = [b'0'; 8]; - let mut tmp = value; - for i in (0..8).rev() { - let digit = (tmp & 0xF) as u8; - buf[i] = match digit { - 0..=9 => b'0' + digit, - 10..=15 => b'A' + (digit - 10), - _ => b'?', - }; - tmp >>= 4; - } - uart.blocking_write(&buf).unwrap(); -} - -// Helper function to write a u64 value as decimal string -fn write_u64(uart: &mut Lpuart<'_, Blocking>, value: u64) { - if value == 0 { - uart.blocking_write(b"0").unwrap(); - return; - } - - let mut buffer = [0u8; 20]; // Enough for max u64 - let mut i = 0; - let mut v = value; - - while v > 0 { - buffer[i] = b'0' + (v % 10) as u8; - v /= 10; - i += 1; - } - - // Write digits in reverse order - while i > 0 { - i -= 1; - match buffer[i] { - b'0' => uart.blocking_write(b"0").unwrap(), - b'1' => uart.blocking_write(b"1").unwrap(), - b'2' => uart.blocking_write(b"2").unwrap(), - b'3' => uart.blocking_write(b"3").unwrap(), - b'4' => uart.blocking_write(b"4").unwrap(), - b'5' => uart.blocking_write(b"5").unwrap(), - b'6' => uart.blocking_write(b"6").unwrap(), - b'7' => uart.blocking_write(b"7").unwrap(), - b'8' => uart.blocking_write(b"8").unwrap(), - b'9' => uart.blocking_write(b"9").unwrap(), - _ => uart.blocking_write(b"?").unwrap(), - } - } -} -- cgit From eed314ebb58772476971af49b36b68301eb0d8cc Mon Sep 17 00:00:00 2001 From: MathisDerooNXP <52401665+MathisDeroo@users.noreply.github.com> Date: Fri, 21 Nov 2025 10:00:01 -0800 Subject: Gpio support v2 (#26) * Improve GPIO driver and add button example - port and pcr registers are defined using paste! - added pin configuration for slew rate, drive strength, mux function, etc... - added button example to showcase input gpio feature Signed-off-by: Mathis Deroo * Add pull-up pull-down config support for input gpio Signed-off-by: Mathis Deroo * Replace GPIOs enum with existing ones in the PAC Signed-off-by: Mathis Deroo * Remove init_gpio_pin function as it is done in hal init config Signed-off-by: Mathis Deroo * Integrate feedback for the GPIO driver - Add again missing IO peripherals - Added function to configure separately slew rate, drive strength, pull. - Revert comment changes Signed-off-by: Mathis Deroo * Create user-readable field for the pin configuration Signed-off-by: Mathis Deroo * examples: button: remove left-over OSTIMER initialization While at that, also cargo fmt * Fix warnings * Add documentation for public functions Signed-off-by: Mathis Deroo * Expose port and pcr registers to AnyPin implementation Signed-off-by: Mathis Deroo * Remove unnecessary change Signed-off-by: Mathis Deroo * Run cargo fmt --------- Signed-off-by: Mathis Deroo Co-authored-by: Felipe Balbi --- examples/src/bin/blinky.rs | 8 ++++---- examples/src/bin/button.rs | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 examples/src/bin/button.rs (limited to 'examples') diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs index ab1e59bdb..dd08ec0d9 100644 --- a/examples/src/bin/blinky.rs +++ b/examples/src/bin/blinky.rs @@ -3,7 +3,7 @@ use embassy_executor::Spawner; use embassy_time::Timer; -use hal::gpio::{Level, Output}; +use hal::gpio::{DriveStrength, Level, Output, SlewRate}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; #[embassy_executor::main] @@ -12,9 +12,9 @@ async fn main(_spawner: Spawner) { defmt::info!("Blink example"); - let mut red = Output::new(p.P3_18, Level::High); - let mut green = Output::new(p.P3_19, Level::High); - let mut blue = Output::new(p.P3_21, Level::High); + let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast); + let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast); + let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast); loop { defmt::info!("Toggle LEDs"); diff --git a/examples/src/bin/button.rs b/examples/src/bin/button.rs new file mode 100644 index 000000000..2abfe0a9f --- /dev/null +++ b/examples/src/bin/button.rs @@ -0,0 +1,21 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::gpio::{DriveStrength, Input, Pull, SlewRate}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("Button example"); + + let monitor = Input::new(p.P1_7, Pull::Disabled, DriveStrength::Normal, SlewRate::Slow); + + loop { + defmt::info!("Pin level is {:?}", monitor.get_level()); + Timer::after_millis(1000).await; + } +} -- cgit From afbf72fb7842c926a9ac9b62f794ed010d4f7b27 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 21 Nov 2025 11:42:11 -0800 Subject: Update to latest PAC (#39) It adds a complete Mux enum Co-authored-by: Felipe Balbi --- examples/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 14f472cbf..473ce2b3f 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -442,7 +442,7 @@ checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "mcxa-pac" version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/mcxa-pac?rev=3ab4c868f75a9240bb8fdce24982d34f2273aabf#3ab4c868f75a9240bb8fdce24982d34f2273aabf" +source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#3b36508ab1ac397861bae3431cc95c204f3ca6e9" dependencies = [ "cortex-m", "cortex-m-rt", -- cgit From c552cf2434b847b7a8af06e15982eb29d07ad2fa Mon Sep 17 00:00:00 2001 From: James Munns Date: Mon, 24 Nov 2025 17:37:57 +0100 Subject: Introduce clkout peripheral (#36) Introduces a ClockOut peripheral, allowing for ensuring that internal clocks are operating correctly. Also fixes some incorrect PLL/Div4 usage. --- examples/Cargo.toml | 2 +- examples/src/bin/clkout.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 examples/src/bin/clkout.rs (limited to 'examples') diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d1c6a2071..4f15a6aff 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = { version = "0.7", features = ["critical-section-single-core"] } -cortex-m-rt = { version = "0.7" } +cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] } critical-section = "1.2.0" defmt = "1.0" defmt-rtt = "1.0" diff --git a/examples/src/bin/clkout.rs b/examples/src/bin/clkout.rs new file mode 100644 index 000000000..bfd963540 --- /dev/null +++ b/examples/src/bin/clkout.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4}; +use embassy_mcxa::clocks::PoweredClock; +use embassy_mcxa::gpio::{DriveStrength, SlewRate}; +use embassy_mcxa::{Level, Output}; +use embassy_time::Timer; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Demonstrate CLKOUT, using Pin P4.2 +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + let mut pin = p.P4_2; + let mut clkout = p.CLKOUT; + + loop { + defmt::info!("Set Low..."); + let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); + Timer::after_millis(500).await; + + defmt::info!("Set High..."); + output.set_high(); + Timer::after_millis(400).await; + + defmt::info!("Set Low..."); + output.set_low(); + Timer::after_millis(500).await; + + defmt::info!("16k..."); + // Run Clock Out with the 16K clock + let _clock_out = ClockOut::new( + clkout.reborrow(), + pin.reborrow(), + Config { + sel: ClockOutSel::Clk16K, + div: Div4::no_div(), + level: PoweredClock::NormalEnabledDeepSleepDisabled, + }, + ) + .unwrap(); + + Timer::after_millis(3000).await; + + defmt::info!("Set Low..."); + drop(_clock_out); + + let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); + Timer::after_millis(500).await; + + // Run Clock Out with the 12M clock, divided by 3 + defmt::info!("4M..."); + let _clock_out = ClockOut::new( + clkout.reborrow(), + pin.reborrow(), + Config { + sel: ClockOutSel::Fro12M, + div: const { Div4::from_divisor(3).unwrap() }, + level: PoweredClock::NormalEnabledDeepSleepDisabled, + }, + ) + .unwrap(); + + // Let it run for 3 seconds... + Timer::after_millis(3000).await; + } +} -- cgit From 6e1bc1139b7dcc8407fd1213bf0cb0788d26288e Mon Sep 17 00:00:00 2001 From: James Munns Date: Mon, 24 Nov 2025 17:50:46 +0100 Subject: Update to patched PAC with corrected Div4 (#41) --- examples/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 473ce2b3f..56ae41d48 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -442,7 +442,7 @@ checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "mcxa-pac" version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#3b36508ab1ac397861bae3431cc95c204f3ca6e9" +source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#9a857ec9780527679978b42cc60288aeef03baa2" dependencies = [ "cortex-m", "cortex-m-rt", -- cgit From 7ee5cb570f0c0daeb2e6a9d5120fd96ee885025f Mon Sep 17 00:00:00 2001 From: James Munns Date: Mon, 24 Nov 2025 18:41:43 +0100 Subject: Remove the pac singleton function (#42) There will be a follow up PR that removes the unsafe `init` functions, but I wanted to squash this out first in case I don't get to it all today. --- examples/src/bin/adc_interrupt.rs | 4 ++-- examples/src/bin/adc_polling.rs | 11 ++--------- examples/src/bin/hello.rs | 2 +- examples/src/bin/lpuart_buffered.rs | 2 +- examples/src/bin/lpuart_polling.rs | 2 +- examples/src/bin/rtc_alarm.rs | 2 +- examples/src/lib.rs | 4 ++-- 7 files changed, 10 insertions(+), 17 deletions(-) (limited to 'examples') diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs index 9fed052fd..0d3a75a28 100644 --- a/examples/src/bin/adc_interrupt.rs +++ b/examples/src/bin/adc_interrupt.rs @@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { - embassy_mcxa_examples::init_uart2_pins(hal::pac()); + embassy_mcxa_examples::init_uart2_pins(); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral @@ -48,7 +48,7 @@ async fn main(_spawner: Spawner) { uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); unsafe { - init_adc_pins(hal::pac()); + init_adc_pins(); } let adc_config = LpadcConfig { diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs index 545f8f77a..02ac321b5 100644 --- a/examples/src/bin/adc_polling.rs +++ b/examples/src/bin/adc_polling.rs @@ -22,10 +22,6 @@ const G_LPADC_RESULT_SHIFT: u32 = 0; async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); - unsafe { - init_uart2_pins(hal::pac()); - } - // Create UART configuration let config = Config { baudrate_bps: 115_200, @@ -36,7 +32,8 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { - init_uart2_pins(hal::pac()); + init_uart2_pins(); + init_adc_pins(); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral @@ -48,10 +45,6 @@ async fn main(_spawner: Spawner) { uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); - unsafe { - init_adc_pins(hal::pac()); - } - let adc_config = LpadcConfig { enable_in_doze_mode: true, conversion_average_mode: CalAvgs::Average128, diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs index e2d0b413d..0362480c1 100644 --- a/examples/src/bin/hello.rs +++ b/examples/src/bin/hello.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { - embassy_mcxa_examples::init_uart2_pins(hal::pac()); + embassy_mcxa_examples::init_uart2_pins(); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs index b0d19ef16..4c9294f57 100644 --- a/examples/src/bin/lpuart_buffered.rs +++ b/examples/src/bin/lpuart_buffered.rs @@ -32,7 +32,7 @@ async fn main(_spawner: Spawner) { hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); unsafe { - init_uart2_pins(hal::pac()); + init_uart2_pins(); } // UART configuration (enable both TX and RX) diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs index 525d42e2c..c8666e64a 100644 --- a/examples/src/bin/lpuart_polling.rs +++ b/examples/src/bin/lpuart_polling.rs @@ -15,7 +15,7 @@ async fn main(_spawner: Spawner) { // Board-level init for UART2 clocks and pins. unsafe { - init_uart2_pins(hal::pac()); + init_uart2_pins(); } // Create UART configuration diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs index a54b4a817..6f8a77101 100644 --- a/examples/src/bin/rtc_alarm.rs +++ b/examples/src/bin/rtc_alarm.rs @@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) { // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { - embassy_mcxa_examples::init_uart2_pins(hal::pac()); + embassy_mcxa_examples::init_uart2_pins(); } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral diff --git a/examples/src/lib.rs b/examples/src/lib.rs index 66b93450a..f5f6124c0 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -9,7 +9,7 @@ use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; /// Initialize clocks and pin muxing for UART2 debug console. /// Safe to call multiple times; writes are idempotent for our use. -pub unsafe fn init_uart2_pins(_p: &hal::pac::Peripherals) { +pub unsafe fn init_uart2_pins() { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. // GPIO has not. _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); @@ -17,7 +17,7 @@ pub unsafe fn init_uart2_pins(_p: &hal::pac::Peripherals) { } /// Initialize clocks and pin muxing for ADC. -pub unsafe fn init_adc_pins(_p: &hal::pac::Peripherals) { +pub unsafe fn init_adc_pins() { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. // GPIO has not. _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); -- cgit From 05bf2d0438fe8c41d0fe26b85106ff73a6e273e9 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 25 Nov 2025 18:08:13 +0100 Subject: Wire up Lpuart pins (#43) Allow the HAL lpuart driver to correctly configure pins as requested on init. --- examples/Cargo.lock | 2 +- examples/src/bin/adc_interrupt.rs | 26 +++----------------------- examples/src/bin/adc_polling.rs | 31 ++++--------------------------- examples/src/bin/hello.rs | 3 --- examples/src/bin/lpuart_buffered.rs | 29 +++++++++-------------------- examples/src/bin/lpuart_polling.rs | 12 +++++------- examples/src/bin/rtc_alarm.rs | 33 ++++++--------------------------- examples/src/lib.rs | 9 --------- 8 files changed, 28 insertions(+), 117 deletions(-) (limited to 'examples') diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 56ae41d48..263807120 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -442,7 +442,7 @@ checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" [[package]] name = "mcxa-pac" version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#9a857ec9780527679978b42cc60288aeef03baa2" +source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca" dependencies = [ "cortex-m", "cortex-m-rt", diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs index 0d3a75a28..83d8046b3 100644 --- a/examples/src/bin/adc_interrupt.rs +++ b/examples/src/bin/adc_interrupt.rs @@ -6,7 +6,6 @@ use embassy_mcxa_examples::init_adc_pins; use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::clocks::PoweredClock; -use hal::lpuart::{Config, Lpuart}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; @@ -26,26 +25,7 @@ static KEEP_ADC: unsafe extern "C" fn() = ADC1; async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - unsafe { - embassy_mcxa_examples::init_uart2_pins(); - } - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - uart.write_str_blocking("\r\n=== ADC interrupt Example ===\r\n"); + defmt::info!("ADC interrupt Example"); unsafe { init_adc_pins(); @@ -81,7 +61,7 @@ async fn main(_spawner: Spawner) { conv_trigger_config.enable_hardware_trigger = false; adc.set_conv_trigger_config(0, &conv_trigger_config); - uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); + defmt::info!("ADC configuration done..."); adc.enable_interrupt(0x1); @@ -98,7 +78,7 @@ async fn main(_spawner: Spawner) { while !adc.is_interrupt_triggered() { // Wait until the interrupt is triggered } - uart.write_str_blocking("\r\n*** ADC interrupt TRIGGERED! ***\r\n"); + defmt::info!("*** ADC interrupt TRIGGERED! ***"); //TBD need to print the value } } diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs index 02ac321b5..ddf3f586b 100644 --- a/examples/src/bin/adc_polling.rs +++ b/examples/src/bin/adc_polling.rs @@ -1,19 +1,15 @@ #![no_std] #![no_main] -use core::fmt::Write; - use embassy_executor::Spawner; -use embassy_mcxa_examples::{init_adc_pins, init_uart2_pins}; +use embassy_mcxa_examples::init_adc_pins; use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::clocks::PoweredClock; -use hal::lpuart::{Config, Lpuart}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; -use heapless::String; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; const G_LPADC_RESULT_SHIFT: u32 = 0; @@ -22,28 +18,11 @@ const G_LPADC_RESULT_SHIFT: u32 = 0; async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX unsafe { - init_uart2_pins(); init_adc_pins(); } - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - uart.write_str_blocking("\r\n=== ADC polling Example ===\r\n"); + defmt::info!("=== ADC polling Example ==="); let adc_config = LpadcConfig { enable_in_doze_mode: true, @@ -75,7 +54,7 @@ async fn main(_spawner: Spawner) { conv_trigger_config.enable_hardware_trigger = false; adc.set_conv_trigger_config(0, &conv_trigger_config); - uart.write_str_blocking("\r\n=== ADC configuration done... ===\r\n"); + defmt::info!("=== ADC configuration done... ==="); loop { adc.do_software_trigger(1); @@ -84,8 +63,6 @@ async fn main(_spawner: Spawner) { result = hal::adc::get_conv_result(); } let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; - let mut buf: String<16> = String::new(); // adjust size as needed - write!(buf, "\r\nvalue: {}\r\n", value).unwrap(); - uart.write_str_blocking(&buf); + defmt::info!("value: {=u16}", value); } } diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs index 0362480c1..f426d1898 100644 --- a/examples/src/bin/hello.rs +++ b/examples/src/bin/hello.rs @@ -27,9 +27,6 @@ async fn main(_spawner: Spawner) { }; // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - unsafe { - embassy_mcxa_examples::init_uart2_pins(); - } let mut uart = Lpuart::new_blocking( p.LPUART2, // Peripheral p.P2_2, // TX pin diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs index 4c9294f57..7f77d557d 100644 --- a/examples/src/bin/lpuart_buffered.rs +++ b/examples/src/bin/lpuart_buffered.rs @@ -2,39 +2,28 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa as hal; -use embassy_mcxa::interrupt::typelevel::Handler; +use embassy_mcxa::clocks::config::Div8; use embassy_mcxa::lpuart::buffered::BufferedLpuart; use embassy_mcxa::lpuart::Config; use embassy_mcxa::{bind_interrupts, lpuart}; -use embassy_mcxa_examples::init_uart2_pins; -use embedded_io_async::{Read, Write}; +use embedded_io_async::Write; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver bind_interrupts!(struct Irqs { LPUART2 => lpuart::buffered::BufferedInterruptHandler::; }); -// Wrapper function for the interrupt handler -unsafe extern "C" fn lpuart2_handler() { - lpuart::buffered::BufferedInterruptHandler::::on_interrupt(); -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - unsafe { - hal::interrupt::install_irq_handler(hal::pac::Interrupt::LPUART2, lpuart2_handler); - } + 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); // Configure NVIC for LPUART2 hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); - unsafe { - init_uart2_pins(); - } - // UART configuration (enable both TX and RX) let config = Config { baudrate_bps: 115_200, @@ -69,7 +58,7 @@ async fn main(_spawner: Spawner) { // Echo loop let mut buf = [0u8; 4]; loop { - rx.read_exact(&mut buf[..]).await.unwrap(); - tx.write_all(&buf[..]).await.unwrap(); + let used = rx.read(&mut buf).await.unwrap(); + tx.write_all(&buf[..used]).await.unwrap(); } } diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs index c8666e64a..9cea418cc 100644 --- a/examples/src/bin/lpuart_polling.rs +++ b/examples/src/bin/lpuart_polling.rs @@ -2,22 +2,20 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa_examples::init_uart2_pins; +use embassy_mcxa::clocks::config::Div8; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; use crate::hal::lpuart::{Config, Lpuart}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); + 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!("boot"); - // Board-level init for UART2 clocks and pins. - unsafe { - init_uart2_pins(); - } - // Create UART configuration let config = Config { baudrate_bps: 115_200, diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs index 6f8a77101..a7800a2d1 100644 --- a/examples/src/bin/rtc_alarm.rs +++ b/examples/src/bin/rtc_alarm.rs @@ -3,7 +3,6 @@ use embassy_executor::Spawner; use embassy_mcxa as hal; -use hal::lpuart::{Config, Lpuart}; use hal::rtc::{RtcDateTime, RtcInterruptEnable}; use hal::InterruptExt; @@ -24,27 +23,7 @@ static KEEP_RTC: unsafe extern "C" fn() = RTC; async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - unsafe { - embassy_mcxa_examples::init_uart2_pins(); - } - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - - uart.write_str_blocking("\r\n=== RTC Alarm Example ===\r\n"); + defmt::info!("=== RTC Alarm Example ==="); let rtc_config = hal::rtc::get_default_config(); @@ -61,14 +40,14 @@ async fn main(_spawner: Spawner) { rtc.stop(); - uart.write_str_blocking("Time set to: 2025-10-15 14:30:00\r\n"); + defmt::info!("Time set to: 2025-10-15 14:30:00"); rtc.set_datetime(now); let mut alarm = now; alarm.second += 10; rtc.set_alarm(alarm); - uart.write_str_blocking("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)\r\n"); + defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)"); rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); @@ -82,14 +61,14 @@ async fn main(_spawner: Spawner) { rtc.start(); - uart.write_str_blocking("RTC started, waiting for alarm...\r\n"); + defmt::info!("RTC started, waiting for alarm..."); loop { if rtc.is_alarm_triggered() { - uart.write_str_blocking("\r\n*** ALARM TRIGGERED! ***\r\n"); + defmt::info!("*** ALARM TRIGGERED! ***"); break; } } - uart.write_str_blocking("Example complete - Test PASSED!\r\n"); + defmt::info!("Example complete - Test PASSED!"); } diff --git a/examples/src/lib.rs b/examples/src/lib.rs index f5f6124c0..2573a6adc 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -7,15 +7,6 @@ use hal::{clocks, pins}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -/// Initialize clocks and pin muxing for UART2 debug console. -/// Safe to call multiple times; writes are idempotent for our use. -pub unsafe fn init_uart2_pins() { - // NOTE: Lpuart has been updated to properly enable + reset its own clocks. - // GPIO has not. - _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); - pins::configure_uart2_pins_port2(); -} - /// Initialize clocks and pin muxing for ADC. pub unsafe fn init_adc_pins() { // NOTE: Lpuart has been updated to properly enable + reset its own clocks. -- cgit From 1efaaa4025120413ec17de90106244445208804a Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 25 Nov 2025 11:32:37 -0800 Subject: I2c Controller Blocking Driver (#27) * I2c Master Signed-off-by: Felipe Balbi * Fix review comments Signed-off-by: Felipe Balbi * More review comments Signed-off-by: Felipe Balbi --------- Signed-off-by: Felipe Balbi Co-authored-by: Felipe Balbi --- examples/Cargo.lock | 532 +++++++++++++++++++++++++++++++++- examples/Cargo.toml | 1 + examples/src/bin/i2c-blocking.rs | 31 ++ examples/src/bin/i2c-scan-blocking.rs | 34 +++ 4 files changed, 590 insertions(+), 8 deletions(-) create mode 100644 examples/src/bin/i2c-blocking.rs create mode 100644 examples/src/bin/i2c-scan-blocking.rs (limited to 'examples') diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 263807120..cda1f9ec8 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -2,6 +2,49 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "askama" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" +dependencies = [ + "askama_parser", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "syn 2.0.110", +] + +[[package]] +name = "askama_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" +dependencies = [ + "memchr", + "winnow 0.7.13", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -29,6 +72,24 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "byteorder" version = "1.5.0" @@ -41,6 +102,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cortex-m" version = "0.7.7" @@ -71,7 +141,7 @@ checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.110", ] [[package]] @@ -101,7 +171,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 2.0.110", ] [[package]] @@ -112,7 +182,16 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn", + "syn 2.0.110", +] + +[[package]] +name = "dd-manifest-tree" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" +dependencies = [ + "toml", ] [[package]] @@ -121,7 +200,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" dependencies = [ - "bitflags", + "bitflags 1.3.2", "defmt-macros", ] @@ -135,7 +214,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn", + "syn 2.0.110", ] [[package]] @@ -157,6 +236,46 @@ dependencies = [ "defmt", ] +[[package]] +name = "device-driver" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" +dependencies = [ + "device-driver-macros", + "embedded-io", + "embedded-io-async", +] + +[[package]] +name = "device-driver-generation" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" +dependencies = [ + "anyhow", + "askama", + "bitvec", + "convert_case", + "dd-manifest-tree", + "itertools", + "kdl", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "device-driver-macros" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" +dependencies = [ + "device-driver-generation", + "proc-macro2", + "syn 2.0.110", +] + [[package]] name = "document-features" version = "0.2.12" @@ -166,6 +285,12 @@ dependencies = [ "litrs", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "embassy-embedded-hal" version = "0.5.0" @@ -205,7 +330,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 2.0.110", ] [[package]] @@ -274,6 +399,7 @@ dependencies = [ "embedded-io-async", "heapless 0.9.2", "panic-probe", + "tmp108", ] [[package]] @@ -380,12 +506,24 @@ dependencies = [ "embedded-storage", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures-core" version = "0.3.31" @@ -407,6 +545,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "heapless" version = "0.8.0" @@ -433,12 +577,85 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "indexmap" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "kdl" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e" +dependencies = [ + "miette", + "num", + "winnow 0.6.24", +] + [[package]] name = "litrs" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn 1.0.109", + "syn 2.0.110", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + +[[package]] +name = "maybe-async-cfg" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627" +dependencies = [ + "manyhow", + "proc-macro2", + "pulldown-cmark", + "quote", + "syn 1.0.109", +] + [[package]] name = "mcxa-pac" version = "0.1.0" @@ -447,9 +664,26 @@ dependencies = [ "cortex-m", "cortex-m-rt", "critical-section", + "defmt", "vcell", ] +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "cfg-if", + "unicode-width", +] + [[package]] name = "nb" version = "0.1.3" @@ -465,6 +699,70 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -490,6 +788,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -509,7 +813,18 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn", + "syn 2.0.110", +] + +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", ] [[package]] @@ -521,6 +836,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "pulldown-cmark" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" +dependencies = [ + "bitflags 2.10.0", + "memchr", + "unicase", +] + [[package]] name = "quote" version = "1.0.42" @@ -530,6 +856,18 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" version = "0.2.3" @@ -539,6 +877,12 @@ dependencies = [ "semver", ] +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + [[package]] name = "semver" version = "0.9.0" @@ -554,6 +898,63 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -566,6 +967,17 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.110" @@ -577,6 +989,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "thiserror" version = "2.0.17" @@ -594,15 +1012,86 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.110", +] + +[[package]] +name = "tmp108" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d644cc97d3cee96793f454b834881f78b5d4e89c90ecf26b3690f42004d111" +dependencies = [ + "device-driver", + "embedded-hal 1.0.0", + "maybe-async-cfg", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", ] +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow 0.7.13", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "vcell" version = "0.1.3" @@ -623,3 +1112,30 @@ checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" dependencies = [ "vcell", ] + +[[package]] +name = "winnow" +version = "0.6.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 4f15a6aff..1022e91df 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -19,6 +19,7 @@ embassy-time-driver = "0.2.1" embedded-io-async = "0.6.1" heapless = "0.9.2" panic-probe = { version = "1.0", features = ["print-defmt"] } +tmp108 = "0.4.0" [profile.release] lto = true # better optimizations diff --git a/examples/src/bin/i2c-blocking.rs b/examples/src/bin/i2c-blocking.rs new file mode 100644 index 000000000..0f6c8cbae --- /dev/null +++ b/examples/src/bin/i2c-blocking.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::clocks::config::Div8; +use hal::config::Config; +use hal::i2c::controller::{self, I2c, Speed}; +use tmp108::Tmp108; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); + + defmt::info!("I2C example"); + + let mut config = controller::Config::default(); + config.speed = Speed::Standard; + let i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap(); + let mut tmp = Tmp108::new_with_a0_gnd(i2c); + + loop { + let temperature = tmp.temperature().unwrap(); + defmt::info!("Temperature: {}C", temperature); + Timer::after_secs(1).await; + } +} diff --git a/examples/src/bin/i2c-scan-blocking.rs b/examples/src/bin/i2c-scan-blocking.rs new file mode 100644 index 000000000..6d1247e7a --- /dev/null +++ b/examples/src/bin/i2c-scan-blocking.rs @@ -0,0 +1,34 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::clocks::config::Div8; +use hal::config::Config; +use hal::i2c::controller::{self, I2c, Speed}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); + + defmt::info!("I2C example"); + + let mut config = controller::Config::default(); + config.speed = Speed::Standard; + let mut i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap(); + + for addr in 0x01..=0x7f { + let result = i2c.blocking_write(addr, &[]); + if result.is_ok() { + defmt::info!("Device found at addr {:02x}", addr); + } + } + + loop { + Timer::after_secs(10).await; + } +} -- cgit From d12bc9785399991065e511efbea34f0138c7645e Mon Sep 17 00:00:00 2001 From: MathisDerooNXP <52401665+MathisDeroo@users.noreply.github.com> Date: Wed, 26 Nov 2025 10:05:16 -0800 Subject: Add GPIO interrupt support and embedded-hal-async trait implementation (#38) * Add GPIO interrupt support and embedded-hal-async trait implementation Signed-off-by: Mathis Deroo * Run cargo fmt * Improve GPIO driver interrupt mechanism and example - GPIO interrupt managed internally at the HAL level, - Renamed and cleaned gpio_interrupt example; now button_async.rs, - Use BitIter instead of simple for loop in the irq handler, - Fix comments and add "rt" wrappen to GPIO IRQ handler. Signed-off-by: Mathis Deroo * Modify INTERRUPT_DETECTED (AtomicBool to AtomicU32) to work with pin number and not only port number interrupt Signed-off-by: Mathis Deroo * add embedded_hal_async::digital::* traits Signed-off-by: Mathis Deroo * Update irq_handler with BitIter loop Co-authored-by: Felipe Balbi * Add suggested changes Signed-off-by: Mathis Deroo * cargo fmt Signed-off-by: Felipe Balbi * WIP: Modify Wakers from AtomicWaker to WaitMap, with pin number (per PORT) as key Signed-off-by: Mathis Deroo * Tweak maitake-sync usage * Improve docs * refactor a bit * Move all of the async+interrupt stuff into a module * Remove defmt debug traces Signed-off-by: Mathis Deroo * cargo vet * Move e-hal-async impls into the gated block * "rt", begone! --------- Signed-off-by: Mathis Deroo Signed-off-by: Felipe Balbi Co-authored-by: Felipe Balbi Co-authored-by: Felipe Balbi Co-authored-by: Felipe Balbi Co-authored-by: James Munns --- examples/Cargo.lock | 414 +++++++++++++++++++++++++++++++++++++++ examples/Cargo.toml | 2 +- examples/src/bin/button_async.rs | 28 +++ 3 files changed, 443 insertions(+), 1 deletion(-) create mode 100644 examples/src/bin/button_async.rs (limited to 'examples') diff --git a/examples/Cargo.lock b/examples/Cargo.lock index cda1f9ec8..c6e864df2 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -96,6 +105,16 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cc" +version = "1.2.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -111,6 +130,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "cordyceps" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" +dependencies = [ + "loom", + "tracing", +] + [[package]] name = "cortex-m" version = "0.7.7" @@ -376,6 +405,7 @@ dependencies = [ "embedded-io", "embedded-io-async", "heapless 0.8.0", + "maitake-sync", "mcxa-pac", "nb 1.1.0", "paste", @@ -512,6 +542,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + [[package]] name = "fnv" version = "1.0.7" @@ -536,6 +572,20 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +[[package]] +name = "generator" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + [[package]] name = "hash32" version = "0.3.1" @@ -613,12 +663,59 @@ dependencies = [ "winnow 0.6.24", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + [[package]] name = "litrs" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "maitake-sync" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" +dependencies = [ + "cordyceps", + "critical-section", + "loom", + "mutex-traits", + "mycelium-bitfield", + "pin-project", + "portable-atomic", + "tracing", +] + [[package]] name = "manyhow" version = "0.11.4" @@ -643,6 +740,15 @@ dependencies = [ "quote", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "maybe-async-cfg" version = "0.2.5" @@ -684,6 +790,18 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "mutex-traits" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" + +[[package]] +name = "mycelium-bitfield" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc" + [[package]] name = "nb" version = "0.1.3" @@ -699,6 +817,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + [[package]] name = "num" version = "0.4.3" @@ -772,6 +899,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "panic-probe" version = "1.0.0" @@ -794,6 +927,41 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +dependencies = [ + "critical-section", +] + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -862,6 +1030,23 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + [[package]] name = "rustc-hash" version = "2.1.1" @@ -877,12 +1062,24 @@ dependencies = [ "semver", ] +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + [[package]] name = "semver" version = "0.9.0" @@ -949,6 +1146,21 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "smallvec" version = "1.15.1" @@ -1015,6 +1227,15 @@ dependencies = [ "syn 2.0.110", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "tmp108" version = "0.4.0" @@ -1068,6 +1289,67 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" +[[package]] +name = "tracing" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb41cbdb933e23b7929f47bb577710643157d7602ef3a2ebd3902b13ac5eda6" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "tracing-core" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + [[package]] name = "unicase" version = "2.8.1" @@ -1092,6 +1374,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcell" version = "0.1.3" @@ -1113,6 +1401,132 @@ dependencies = [ "vcell", ] +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "winnow" version = "0.6.24" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 1022e91df..a1092c416 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -12,7 +12,7 @@ defmt = "1.0" defmt-rtt = "1.0" embassy-embedded-hal = "0.5.0" embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } -embassy-mcxa = { path = "../", features = ["defmt", "rt", "unstable-pac", "time"] } +embassy-mcxa = { path = "../", features = ["defmt", "unstable-pac", "time"] } embassy-sync = "0.7.2" embassy-time = "0.5.0" embassy-time-driver = "0.2.1" diff --git a/examples/src/bin/button_async.rs b/examples/src/bin/button_async.rs new file mode 100644 index 000000000..1ecec2e48 --- /dev/null +++ b/examples/src/bin/button_async.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::gpio::{DriveStrength, Input, Pull, SlewRate}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("GPIO interrupt example"); + + // This button is labeled "WAKEUP" on the FRDM-MCXA276 + let mut pin = Input::new(p.P1_7, Pull::Up, DriveStrength::Normal, SlewRate::Fast); + + let mut press_count = 0u32; + + loop { + pin.wait_for_falling_edge().await; + + press_count += 1; + + defmt::info!("Button pressed! Count: {}", press_count); + Timer::after_millis(50).await; + } +} -- cgit From 87c4eaf3380505ca15ef7ed1d5dc435e9af2200e Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 28 Nov 2025 18:49:10 +0100 Subject: Fix LPI2C2 example (#56) Fix LPI2C2 example --- examples/src/bin/i2c-scan-blocking.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/src/bin/i2c-scan-blocking.rs b/examples/src/bin/i2c-scan-blocking.rs index 6d1247e7a..72f9d09e0 100644 --- a/examples/src/bin/i2c-scan-blocking.rs +++ b/examples/src/bin/i2c-scan-blocking.rs @@ -2,6 +2,8 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa::gpio::{DriveStrength, Pull, SlewRate}; +use embassy_mcxa::Input; use embassy_time::Timer; use hal::clocks::config::Div8; use hal::config::Config; @@ -19,7 +21,12 @@ async fn main(_spawner: Spawner) { let mut config = controller::Config::default(); config.speed = Speed::Standard; - let mut i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap(); + + // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and + // defaults to SWO on the debug peripheral. Explicitly make it a high-z + // input. + let _pin = Input::new(p.P0_2, Pull::Disabled, DriveStrength::Normal, SlewRate::Slow); + let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap(); for addr in 0x01..=0x7f { let result = i2c.blocking_write(addr, &[]); -- cgit From 03356a261801d7ee234490809eef3eac3c27cc52 Mon Sep 17 00:00:00 2001 From: Bogdan Petru Chircu Mare Date: Tue, 25 Nov 2025 22:09:01 -0800 Subject: feat(dma): add DMA driver with 10 verified examples Initial DMA driver implementation for MCXA276 with: Core DMA Features: - DmaChannel type with ownership tracking via Channel trait - Transfer, RingBuffer, and ScatterGatherBuilder abstractions - Support for mem-to-mem, mem-to-peripheral, peripheral-to-mem transfers - Interrupt-driven completion with embassy async/await integration - Word size abstraction (u8, u16, u32) via Word trait LPUART DMA Integration: - LpuartTxDma and LpuartRxDma drivers for async UART with DMA - LpuartDma combined TX/RX driver - Automatic chunking for buffers > 0x7FFF bytes - DMA guards with Drop impl for safe cancellation 10 Verified Examples: - dma_mem2mem: Basic memory-to-memory copy - dma_memset: Memory fill with pattern - dma_uart_tx: UART transmit via DMA - dma_uart_rx: UART receive via DMA - dma_uart_loopback: Combined TX/RX loopback test - dma_scatter_gather: Linked descriptor chains - dma_channel_linking: Major/minor loop channel linking - dma_ring_buffer: Circular buffer for continuous streaming - dma_ping_pong: Double-buffering pattern - dma_software_trigger: Manual transfer triggering PR Feedback Addressed: - Use PAC accessor for LPUART DATA register instead of manual offset - Add EnableInterrupt enum to replace boolean parameter for readability - Add DMA guards with Drop impl for safe async cancellation - Automatic chunking for large buffers instead of returning error - Use NonNull<[W]> + PhantomData for RingBuffer (DMA acts like separate thread) - Remove edma parameter from all methods (single eDMA instance steals ptr internally) - Make edma_tcd() non-public (HAL should not expose PAC items) --- examples/src/bin/dma_channel_link.rs | 396 +++++++++++++++++++++++++ examples/src/bin/dma_interleave_transfer.rs | 226 ++++++++++++++ examples/src/bin/dma_mem_to_mem.rs | 248 ++++++++++++++++ examples/src/bin/dma_memset.rs | 232 +++++++++++++++ examples/src/bin/dma_ping_pong_transfer.rs | 384 ++++++++++++++++++++++++ examples/src/bin/dma_scatter_gather.rs | 281 ++++++++++++++++++ examples/src/bin/dma_scatter_gather_builder.rs | 244 +++++++++++++++ examples/src/bin/dma_wrap_transfer.rs | 231 +++++++++++++++ examples/src/bin/lpuart_dma.rs | 127 ++++++++ examples/src/bin/lpuart_ring_buffer.rs | 162 ++++++++++ 10 files changed, 2531 insertions(+) create mode 100644 examples/src/bin/dma_channel_link.rs create mode 100644 examples/src/bin/dma_interleave_transfer.rs create mode 100644 examples/src/bin/dma_mem_to_mem.rs create mode 100644 examples/src/bin/dma_memset.rs create mode 100644 examples/src/bin/dma_ping_pong_transfer.rs create mode 100644 examples/src/bin/dma_scatter_gather.rs create mode 100644 examples/src/bin/dma_scatter_gather_builder.rs create mode 100644 examples/src/bin/dma_wrap_transfer.rs create mode 100644 examples/src/bin/lpuart_dma.rs create mode 100644 examples/src/bin/lpuart_ring_buffer.rs (limited to 'examples') diff --git a/examples/src/bin/dma_channel_link.rs b/examples/src/bin/dma_channel_link.rs new file mode 100644 index 000000000..d585f8e3a --- /dev/null +++ b/examples/src/bin/dma_channel_link.rs @@ -0,0 +1,396 @@ +//! DMA channel linking example for MCXA276. +//! +//! This example demonstrates DMA channel linking (minor and major loop linking): +//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with: +//! - Minor Link to Channel 1 (triggers CH1 after each minor loop) +//! - Major Link to Channel 2 (triggers CH2 after major loop completes) +//! - Channel 1: Transfers SRC_BUFFER to DEST_BUFFER1 (triggered by CH0 minor link) +//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link) +//! +//! # Embassy-style features demonstrated: +//! - `dma::edma_tcd()` accessor for simplified register access +//! - `DmaChannel::new()` for channel creation +//! - `DmaChannel::is_done()` and `clear_done()` helper methods +//! - Channel linking with `set_minor_link()` and `set_major_link()` + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{edma_tcd, DmaChannel}; +use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Buffers +static mut SRC_BUFFER: [u32; 4] = [1, 2, 3, 4]; +static mut DEST_BUFFER0: [u32; 4] = [0; 4]; +static mut DEST_BUFFER1: [u32; 4] = [0; 4]; +static mut DEST_BUFFER2: [u32; 4] = [0; 4]; + +static DMA_CH2_DONE: AtomicBool = AtomicBool::new(false); + +// Custom DMA interrupt handlers for channel linking +// CH0 and CH1 just clear flags, CH2 signals completion + +pub struct Ch0Handler; +impl embassy_mcxa::interrupt::typelevel::Handler for Ch0Handler { + unsafe fn on_interrupt() { + let edma = edma_tcd(); + edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one()); + if edma.tcd(0).ch_csr().read().done().bit_is_set() { + edma.tcd(0).ch_csr().write(|w| w.done().clear_bit_by_one()); + } + } +} + +pub struct Ch1Handler; +impl embassy_mcxa::interrupt::typelevel::Handler for Ch1Handler { + unsafe fn on_interrupt() { + let edma = edma_tcd(); + edma.tcd(1).ch_int().write(|w| w.int().clear_bit_by_one()); + if edma.tcd(1).ch_csr().read().done().bit_is_set() { + edma.tcd(1).ch_csr().write(|w| w.done().clear_bit_by_one()); + } + } +} + +pub struct Ch2Handler; +impl embassy_mcxa::interrupt::typelevel::Handler for Ch2Handler { + unsafe fn on_interrupt() { + let edma = edma_tcd(); + edma.tcd(2).ch_int().write(|w| w.int().clear_bit_by_one()); + if edma.tcd(2).ch_csr().read().done().bit_is_set() { + edma.tcd(2).ch_csr().write(|w| w.done().clear_bit_by_one()); + } + DMA_CH2_DONE.store(true, Ordering::Release); + } +} + +bind_interrupts!(struct Irqs { + DMA_CH0 => Ch0Handler; + DMA_CH1 => Ch1Handler; + DMA_CH2 => Ch2Handler; +}); + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 channel link example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + unsafe { + dma::init(&pac_periphs); + } + + // Use edma_tcd() accessor instead of passing register block around + let edma = edma_tcd(); + let dma0 = &pac_periphs.dma0; + + // Clear any residual state + for i in 0..3 { + let t = edma.tcd(i); + t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one()); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + t.ch_es().write(|w| w.err().clear_bit_by_one()); + t.ch_mux().write(|w| unsafe { w.bits(0) }); + } + + // Clear Global Halt/Error state + dma0.mp_csr().modify(|_, w| { + w.halt().normal_operation() + .hae().normal_operation() + .ecx().normal_operation() + .cx().normal_operation() + }); + + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH2); + } + + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: false, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA channel link example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC_BUFFER = [1, 2, 3, 4]; + DEST_BUFFER0 = [0; 4]; + DEST_BUFFER1 = [0; 4]; + DEST_BUFFER2 = [0; 4]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST0 (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST1 (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST2 (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA channels with Embassy-style API...\r\n") + .unwrap(); + + let ch0 = DmaChannel::new(p.DMA_CH0); + let ch1 = DmaChannel::new(p.DMA_CH1); + let _ch2 = DmaChannel::new(p.DMA_CH2); + + // Configure channels using direct TCD access (advanced feature demo) + // This example demonstrates channel linking which requires direct TCD manipulation + + // Helper to configure TCD for memory-to-memory transfer + // Parameters: channel, src, dst, width, nbytes (minor loop), count (major loop), interrupt + #[allow(clippy::too_many_arguments)] + unsafe fn configure_tcd( + edma: &embassy_mcxa::pac::edma_0_tcd0::RegisterBlock, + ch: usize, + src: u32, + dst: u32, + width: u8, + nbytes: u32, + count: u16, + enable_int: bool, + ) { + let t = edma.tcd(ch); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq().disable() + .earq().disable() + .eei().no_error() + .ebw().disable() + .done().clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source/destination addresses + t.tcd_saddr().write(|w| w.saddr().bits(src)); + t.tcd_daddr().write(|w| w.daddr().bits(dst)); + + // Offsets: increment by width + t.tcd_soff().write(|w| w.soff().bits(width as u16)); + t.tcd_doff().write(|w| w.doff().bits(width as u16)); + + // Attributes: size = log2(width) + let size = match width { + 1 => 0, + 2 => 1, + 4 => 2, + _ => 0, + }; + t.tcd_attr().write(|w| w.ssize().bits(size).dsize().bits(size)); + + // Number of bytes per minor loop + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Major loop: reset source address after major loop + let total_bytes = nbytes * count as u32; + t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32)); + t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32)); + + // Major loop count + t.tcd_biter_elinkno().write(|w| w.biter().bits(count)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(count)); + + // Control/status: enable interrupt if requested + if enable_int { + t.tcd_csr().write(|w| w.intmajor().set_bit()); + } else { + t.tcd_csr().write(|w| w.intmajor().clear_bit()); + } + + cortex_m::asm::dsb(); + } + + unsafe { + + // Channel 0: Transfer 16 bytes total (8 bytes per minor loop, 2 major iterations) + // Minor Link -> Channel 1 + // Major Link -> Channel 2 + configure_tcd( + edma, + 0, + core::ptr::addr_of!(SRC_BUFFER) as u32, + core::ptr::addr_of_mut!(DEST_BUFFER0) as u32, + 4, // src width + 8, // nbytes (minor loop = 2 words) + 2, // count (major loop = 2 iterations) + false, // no interrupt + ); + ch0.set_minor_link(edma, 1); // Link to CH1 after each minor loop + ch0.set_major_link(edma, 2); // Link to CH2 after major loop + + // Channel 1: Transfer 16 bytes (triggered by CH0 minor link) + configure_tcd( + edma, + 1, + core::ptr::addr_of!(SRC_BUFFER) as u32, + core::ptr::addr_of_mut!(DEST_BUFFER1) as u32, + 4, + 16, // full buffer in one minor loop + 1, // 1 major iteration + false, + ); + + // Channel 2: Transfer 16 bytes (triggered by CH0 major link) + configure_tcd( + edma, + 2, + core::ptr::addr_of!(SRC_BUFFER) as u32, + core::ptr::addr_of_mut!(DEST_BUFFER2) as u32, + 4, + 16, // full buffer in one minor loop + 1, // 1 major iteration + true, // enable interrupt + ); + } + + tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n").unwrap(); + + // Trigger first minor loop of CH0 + unsafe { ch0.trigger_start(edma); } + + // Wait for CH1 to complete (triggered by CH0 minor link) + while !ch1.is_done(edma) { + cortex_m::asm::nop(); + } + unsafe { ch1.clear_done(edma); } + + tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap(); + tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n").unwrap(); + + // Trigger second minor loop of CH0 + unsafe { ch0.trigger_start(edma); } + + // Wait for CH0 major loop to complete + while !ch0.is_done(edma) { + cortex_m::asm::nop(); + } + unsafe { ch0.clear_done(edma); } + + tx.blocking_write(b"CH0 major loop done.\r\n").unwrap(); + + // Wait for CH2 to complete (triggered by CH0 major link) + while !DMA_CH2_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + + tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap(); + + tx.blocking_write(b"EDMA channel link example finish.\r\n\r\n") + .unwrap(); + + tx.blocking_write(b"DEST0 (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST1 (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST2 (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify all buffers match source + let mut success = true; + unsafe { + let src_ptr = core::ptr::addr_of!(SRC_BUFFER) as *const u32; + let dst0_ptr = core::ptr::addr_of!(DEST_BUFFER0) as *const u32; + let dst1_ptr = core::ptr::addr_of!(DEST_BUFFER1) as *const u32; + let dst2_ptr = core::ptr::addr_of!(DEST_BUFFER2) as *const u32; + + for i in 0..4 { + if *dst0_ptr.add(i) != *src_ptr.add(i) { success = false; } + if *dst1_ptr.add(i) != *src_ptr.add(i) { success = false; } + if *dst2_ptr.add(i) != *src_ptr.add(i) { success = false; } + } + } + + if success { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } else { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } + + loop { + cortex_m::asm::wfe(); + } +} + diff --git a/examples/src/bin/dma_interleave_transfer.rs b/examples/src/bin/dma_interleave_transfer.rs new file mode 100644 index 000000000..710f18de3 --- /dev/null +++ b/examples/src/bin/dma_interleave_transfer.rs @@ -0,0 +1,226 @@ +//! DMA interleaved transfer example for MCXA276. +//! +//! This example demonstrates using DMA with custom source/destination offsets +//! to interleave data during transfer. +//! +//! # Embassy-style features demonstrated: +//! - `dma::edma_tcd()` accessor for simplified register access +//! - `TransferOptions::default()` for configuration (used internally) +//! - DMA channel with `DmaChannel::new()` + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; +use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +const BUFFER_LENGTH: usize = 16; +const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2; + +// Buffers in RAM +static mut SRC_BUFFER: [u32; HALF_BUFF_LENGTH] = [0; HALF_BUFF_LENGTH]; +static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 interleave transfer example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + unsafe { + dma::init(&pac_periphs); + } + + // Enable DMA interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: false, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA interleave transfer example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC_BUFFER = [1, 2, 3, 4, 5, 6, 7, 8]; + DEST_BUFFER = [0; BUFFER_LENGTH]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, HALF_BUFF_LENGTH); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") + .unwrap(); + + // Create DMA channel using Embassy-style API + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Use edma_tcd() accessor instead of passing register block around + let edma = edma_tcd(); + + // Configure interleaved transfer using direct TCD access: + // - src_offset = 4: advance source by 4 bytes after each read + // - dst_offset = 8: advance dest by 8 bytes after each write + // This spreads source data across every other word in destination + unsafe { + let t = edma.tcd(0); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq().disable() + .earq().disable() + .eei().no_error() + .ebw().disable() + .done().clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source/destination addresses + t.tcd_saddr().write(|w| w.saddr().bits(core::ptr::addr_of_mut!(SRC_BUFFER) as u32)); + t.tcd_daddr().write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); + + // Custom offsets for interleaving + t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read + t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write + + // Attributes: 32-bit transfers (size = 2) + t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); + + // Transfer entire source buffer in one minor loop + let nbytes = (HALF_BUFF_LENGTH * 4) as u32; + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Reset source address after major loop + t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32)); + // Destination uses 2x offset, so adjust accordingly + let dst_total = (HALF_BUFF_LENGTH * 8) as u32; + t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32)); + + // Major loop count = 1 + t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); + + // Enable interrupt on major loop completion + t.tcd_csr().write(|w| w.intmajor().set_bit()); + + cortex_m::asm::dsb(); + + tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); + dma_ch0.trigger_start(edma); + } + + // Wait for completion using channel helper method + while !dma_ch0.is_done(edma) { + cortex_m::asm::nop(); + } + unsafe { dma_ch0.clear_done(edma); } + + tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0 + let mut mismatch = false; + unsafe { + for i in 0..BUFFER_LENGTH { + if i % 2 == 0 { + if DEST_BUFFER[i] != SRC_BUFFER[i / 2] { + mismatch = true; + } + } else if DEST_BUFFER[i] != 0 { + mismatch = true; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } + + loop { + cortex_m::asm::wfe(); + } +} + diff --git a/examples/src/bin/dma_mem_to_mem.rs b/examples/src/bin/dma_mem_to_mem.rs new file mode 100644 index 000000000..e193e8c6a --- /dev/null +++ b/examples/src/bin/dma_mem_to_mem.rs @@ -0,0 +1,248 @@ +//! DMA memory-to-memory transfer example for MCXA276. +//! +//! This example demonstrates using DMA to copy data between memory buffers +//! using the Embassy-style async API with type-safe transfers. +//! +//! # Embassy-style features demonstrated: +//! - `TransferOptions` for configuration +//! - Type-safe `mem_to_mem()` method with async `.await` +//! - `Transfer` Future that can be `.await`ed +//! - `Word` trait for automatic transfer width detection +//! - `memset()` method for filling memory with a pattern + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, TransferOptions}; +use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +const BUFFER_LENGTH: usize = 4; + +// Buffers in RAM (static mut is automatically placed in .bss/.data) +static mut SRC_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; +static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; +static mut MEMSET_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; // u32 max is 4294967295 (10 digits) + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer as [v1, v2, v3, v4] to UART +/// Takes a raw pointer to avoid warnings about shared references to mutable statics +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const [u32; BUFFER_LENGTH]) { + tx.blocking_write(b"[").ok(); + unsafe { + let buf = &*buf_ptr; + for (i, val) in buf.iter().enumerate() { + write_u32(tx, *val); + if i < buf.len() - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 memory-to-memory example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + // Get PAC peripherals for DMA init + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + // Initialize DMA + unsafe { + dma::init(&pac_periphs); + } + + // Enable DMA interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + // Create UART for debug output + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: false, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA memory to memory example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC_BUFFER = [1, 2, 3, 4]; + DEST_BUFFER = [0; BUFFER_LENGTH]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, &raw const SRC_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, &raw const DEST_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") + .unwrap(); + + // Create DMA channel + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure transfer options (Embassy-style) + // TransferOptions defaults to: complete_transfer_interrupt = true + let options = TransferOptions::default(); + + // ========================================================================= + // Part 1: Embassy-style async API demonstration (mem_to_mem) + // ========================================================================= + // + // Use the new type-safe `mem_to_mem()` method: + // - Automatically determines transfer width from buffer element type (u32) + // - Returns a `Transfer` future that can be `.await`ed + // - Uses TransferOptions for consistent configuration + // + // Using async `.await` - the executor can run other tasks while waiting! + + // Perform type-safe memory-to-memory transfer using Embassy-style async API + unsafe { + let src = &*core::ptr::addr_of!(SRC_BUFFER); + let dst = &mut *core::ptr::addr_of_mut!(DEST_BUFFER); + + // Using async `.await` - the executor can run other tasks while waiting! + let transfer = dma_ch0.mem_to_mem(src, dst, options); + transfer.await; + } + + tx.blocking_write(b"DMA mem-to-mem transfer complete!\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, &raw const DEST_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + // Verify data + let mut mismatch = false; + unsafe { + for i in 0..BUFFER_LENGTH { + if SRC_BUFFER[i] != DEST_BUFFER[i] { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: mem_to_mem mismatch!\r\n").unwrap(); + defmt::error!("FAIL: mem_to_mem mismatch!"); + } else { + tx.blocking_write(b"PASS: mem_to_mem verified.\r\n\r\n").unwrap(); + defmt::info!("PASS: mem_to_mem verified."); + } + + // ========================================================================= + // Part 2: memset() demonstration + // ========================================================================= + // + // The `memset()` method fills a buffer with a pattern value: + // - Fixed source address (pattern is read repeatedly) + // - Incrementing destination address + // - Uses the same Transfer future pattern + + tx.blocking_write(b"--- Demonstrating memset() feature ---\r\n\r\n").unwrap(); + + tx.blocking_write(b"Memset Buffer (before): ").unwrap(); + print_buffer(&mut tx, &raw const MEMSET_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + // Fill buffer with a pattern value using DMA memset + let pattern: u32 = 0xDEADBEEF; + tx.blocking_write(b"Filling with pattern 0xDEADBEEF...\r\n").unwrap(); + + unsafe { + let dst = &mut *core::ptr::addr_of_mut!(MEMSET_BUFFER); + + // Using blocking_wait() for demonstration - also shows non-async usage + let transfer = dma_ch0.memset(&pattern, dst, options); + transfer.blocking_wait(); + } + + tx.blocking_write(b"DMA memset complete!\r\n\r\n").unwrap(); + tx.blocking_write(b"Memset Buffer (after): ").unwrap(); + print_buffer(&mut tx, &raw const MEMSET_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + // Verify memset result + let mut memset_ok = true; + unsafe { + #[allow(clippy::needless_range_loop)] + for i in 0..BUFFER_LENGTH { + if MEMSET_BUFFER[i] != pattern { + memset_ok = false; + break; + } + } + } + + if !memset_ok { + tx.blocking_write(b"FAIL: memset mismatch!\r\n").unwrap(); + defmt::error!("FAIL: memset mismatch!"); + } else { + tx.blocking_write(b"PASS: memset verified.\r\n\r\n").unwrap(); + defmt::info!("PASS: memset verified."); + } + + tx.blocking_write(b"=== All DMA tests complete ===\r\n").unwrap(); + + loop { + cortex_m::asm::wfe(); + } +} + diff --git a/examples/src/bin/dma_memset.rs b/examples/src/bin/dma_memset.rs new file mode 100644 index 000000000..b76ba988d --- /dev/null +++ b/examples/src/bin/dma_memset.rs @@ -0,0 +1,232 @@ +//! DMA memset example for MCXA276. +//! +//! This example demonstrates using DMA to fill a buffer with a repeated pattern. +//! The source address stays fixed while the destination increments. +//! +//! # Embassy-style features demonstrated: +//! - `dma::edma_tcd()` accessor for simplified register access +//! - `DmaChannel::is_done()` and `clear_done()` helper methods +//! - No need to pass register block around + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; +use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +const BUFFER_LENGTH: usize = 4; + +// Buffers in RAM +static mut PATTERN: u32 = 0; +static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 memset example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + unsafe { + dma::init(&pac_periphs); + } + + // Enable DMA interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: false, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA memset example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + PATTERN = 0xDEADBEEF; + DEST_BUFFER = [0; BUFFER_LENGTH]; + } + + tx.blocking_write(b"Pattern value: 0x").unwrap(); + // Print pattern in hex + unsafe { + let hex_chars = b"0123456789ABCDEF"; + let mut hex_buf = [0u8; 8]; + let mut val = PATTERN; + for i in (0..8).rev() { + hex_buf[i] = hex_chars[(val & 0xF) as usize]; + val >>= 4; + } + tx.blocking_write(&hex_buf).ok(); + } + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") + .unwrap(); + + // Create DMA channel using Embassy-style API + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Use edma_tcd() accessor instead of passing register block around + let edma = edma_tcd(); + + // Configure memset transfer using direct TCD access: + // Source stays fixed (soff = 0, reads same pattern repeatedly) + // Destination increments (doff = 4) + unsafe { + let t = edma.tcd(0); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq().disable() + .earq().disable() + .eei().no_error() + .ebw().disable() + .done().clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source address (pattern) - fixed + t.tcd_saddr().write(|w| w.saddr().bits(core::ptr::addr_of_mut!(PATTERN) as u32)); + // Destination address - increments + t.tcd_daddr().write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); + + // Source offset = 0 (stays fixed), Dest offset = 4 (increments) + t.tcd_soff().write(|w| w.soff().bits(0)); + t.tcd_doff().write(|w| w.doff().bits(4)); + + // Attributes: 32-bit transfers (size = 2) + t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); + + // Transfer entire buffer in one minor loop + let nbytes = (BUFFER_LENGTH * 4) as u32; + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Source doesn't need adjustment (stays fixed) + t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); + // Reset dest address after major loop + t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32)); + + // Major loop count = 1 + t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); + + // Enable interrupt on major loop completion + t.tcd_csr().write(|w| w.intmajor().set_bit()); + + cortex_m::asm::dsb(); + + tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); + dma_ch0.trigger_start(edma); + } + + // Wait for completion using channel helper method + while !dma_ch0.is_done(edma) { + cortex_m::asm::nop(); + } + unsafe { dma_ch0.clear_done(edma); } + + tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: All elements should equal PATTERN + let mut mismatch = false; + unsafe { + #[allow(clippy::needless_range_loop)] + for i in 0..BUFFER_LENGTH { + if DEST_BUFFER[i] != PATTERN { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } + + loop { + cortex_m::asm::wfe(); + } +} + diff --git a/examples/src/bin/dma_ping_pong_transfer.rs b/examples/src/bin/dma_ping_pong_transfer.rs new file mode 100644 index 000000000..13ad9782d --- /dev/null +++ b/examples/src/bin/dma_ping_pong_transfer.rs @@ -0,0 +1,384 @@ +//! DMA ping-pong/double-buffer transfer example for MCXA276. +//! +//! This example demonstrates two approaches for ping-pong/double-buffering: +//! +//! ## Approach 1: Scatter/Gather with linked TCDs (manual) +//! - Two TCDs link to each other for alternating transfers +//! - Uses custom interrupt handler with AtomicBool flag +//! +//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!) +//! - Single continuous transfer over entire buffer +//! - Uses half-transfer interrupt to know when first half is ready +//! - Application can process first half while second half is being filled +//! +//! # Embassy-style features demonstrated: +//! - `dma::edma_tcd()` accessor for simplified register access +//! - `DmaChannel::new()` for channel creation +//! - Scatter/gather with linked TCDs +//! - NEW: `wait_half()` for half-transfer interrupt handling + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh1InterruptHandler, Tcd, TransferOptions}; +use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Source and destination buffers for Approach 1 (scatter/gather) +static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; +static mut DST: [u32; 8] = [0; 8]; + +// Source and destination buffers for Approach 2 (wait_half) +static mut SRC2: [u32; 8] = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; +static mut DST2: [u32; 8] = [0; 8]; + +// TCD pool for scatter/gather - must be 32-byte aligned +#[repr(C, align(32))] +struct TcdPool([Tcd; 2]); + +static mut TCD_POOL: TcdPool = TcdPool([Tcd { + saddr: 0, + soff: 0, + attr: 0, + nbytes: 0, + slast: 0, + daddr: 0, + doff: 0, + citer: 0, + dlast_sga: 0, + csr: 0, + biter: 0, +}; 2]); + +static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); + +// Custom DMA interrupt handler for ping-pong transfer +// We need a custom handler because we signal completion via TRANSFER_DONE flag +// and don't clear DONE bit when using Scatter/Gather (ESG=1) +pub struct PingPongDmaHandler; + +impl embassy_mcxa::interrupt::typelevel::Handler for PingPongDmaHandler { + unsafe fn on_interrupt() { + let edma = edma_tcd(); + + // Clear interrupt flag + edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one()); + + // Do NOT clear DONE bit when using Scatter/Gather (ESG=1), + // as the hardware loads the next TCD which resets the status. + + TRANSFER_DONE.store(true, Ordering::Release); + } +} + +bind_interrupts!(struct Irqs { + DMA_CH0 => PingPongDmaHandler; + DMA_CH1 => DmaCh1InterruptHandler; // For wait_half() demo +}); + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 ping-pong transfer example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + unsafe { + dma::init(&pac_periphs); + } + + // Use edma_tcd() accessor instead of passing register block around + let edma = edma_tcd(); + + // Enable DMA interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: false, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA ping-pong transfer example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC = [1, 2, 3, 4, 5, 6, 7, 8]; + DST = [0; 8]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring ping-pong DMA with Embassy-style API...\r\n") + .unwrap(); + + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure ping-pong transfer using direct TCD access: + // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. + // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1. + // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0. + unsafe { + let tcds = &mut *core::ptr::addr_of_mut!(TCD_POOL.0); + let src_ptr = core::ptr::addr_of!(SRC) as *const u32; + let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; + + let half_len = 4usize; + let half_bytes = (half_len * 4) as u32; + + let tcd0_addr = &tcds[0] as *const _ as u32; + let tcd1_addr = &tcds[1] as *const _ as u32; + + // TCD0: First half -> Links to TCD1 + tcds[0] = Tcd { + saddr: src_ptr as u32, + soff: 4, + attr: 0x0202, // 32-bit src/dst + nbytes: half_bytes, + slast: 0, + daddr: dst_ptr as u32, + doff: 4, + citer: 1, + dlast_sga: tcd1_addr as i32, + csr: 0x0012, // ESG | INTMAJOR + biter: 1, + }; + + // TCD1: Second half -> Links to TCD0 + tcds[1] = Tcd { + saddr: src_ptr.add(half_len) as u32, + soff: 4, + attr: 0x0202, + nbytes: half_bytes, + slast: 0, + daddr: dst_ptr.add(half_len) as u32, + doff: 4, + citer: 1, + dlast_sga: tcd0_addr as i32, + csr: 0x0012, + biter: 1, + }; + + // Load TCD0 into hardware registers + dma_ch0.load_tcd(edma, &tcds[0]); + } + + tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); + + // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) + unsafe { + dma_ch0.trigger_start(edma); + } + + // Wait for first half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + tx.blocking_write(b"First half transferred.\r\n").unwrap(); + tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); + + // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) + unsafe { + dma_ch0.trigger_start(edma); + } + + // Wait for second half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); + + tx.blocking_write(b"EDMA ping-pong transfer example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: DST should match SRC + let mut mismatch = false; + unsafe { + let src_ptr = core::ptr::addr_of!(SRC) as *const u32; + let dst_ptr = core::ptr::addr_of!(DST) as *const u32; + for i in 0..8 { + if *src_ptr.add(i) != *dst_ptr.add(i) { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Approach 1 mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Approach 1 mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Approach 1 data verified.\r\n\r\n").unwrap(); + defmt::info!("PASS: Approach 1 data verified."); + } + + // ========================================================================= + // Approach 2: Half-Transfer Interrupt with wait_half() (NEW!) + // ========================================================================= + // + // This approach uses a single continuous DMA transfer with half-transfer + // interrupt enabled. The wait_half() method allows you to be notified + // when the first half of the buffer is complete, so you can process it + // while the second half is still being filled. + // + // Benefits: + // - Simpler setup (no TCD pool needed) + // - True async/await support + // - Good for streaming data processing + + tx.blocking_write(b"--- Approach 2: wait_half() demo ---\r\n\r\n").unwrap(); + + // Enable DMA CH1 interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); + } + + // Initialize approach 2 buffers + unsafe { + SRC2 = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; + DST2 = [0; 8]; + } + + tx.blocking_write(b"SRC2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + let dma_ch1 = DmaChannel::new(p.DMA_CH1); + + // Configure transfer with half-transfer interrupt enabled + let mut options = TransferOptions::default(); + options.half_transfer_interrupt = true; // Enable half-transfer interrupt + options.complete_transfer_interrupt = true; + + tx.blocking_write(b"Starting transfer with half_transfer_interrupt...\r\n").unwrap(); + + unsafe { + let src = &*core::ptr::addr_of!(SRC2); + let dst = &mut *core::ptr::addr_of_mut!(DST2); + + // Create the transfer + let mut transfer = dma_ch1.mem_to_mem(src, dst, options); + + // Wait for half-transfer (first 4 elements) + tx.blocking_write(b"Waiting for first half...\r\n").unwrap(); + let half_ok = transfer.wait_half().await; + + if half_ok { + tx.blocking_write(b"Half-transfer complete! First half of DST2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b"(Processing first half while second half transfers...)\r\n").unwrap(); + } + + // Wait for complete transfer + tx.blocking_write(b"Waiting for second half...\r\n").unwrap(); + transfer.await; + } + + tx.blocking_write(b"Transfer complete! Full DST2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 8); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify approach 2 + let mut mismatch2 = false; + unsafe { + let src_ptr = core::ptr::addr_of!(SRC2) as *const u32; + let dst_ptr = core::ptr::addr_of!(DST2) as *const u32; + for i in 0..8 { + if *src_ptr.add(i) != *dst_ptr.add(i) { + mismatch2 = true; + break; + } + } + } + + if mismatch2 { + tx.blocking_write(b"FAIL: Approach 2 mismatch!\r\n").unwrap(); + defmt::error!("FAIL: Approach 2 mismatch!"); + } else { + tx.blocking_write(b"PASS: Approach 2 verified.\r\n").unwrap(); + defmt::info!("PASS: Approach 2 verified."); + } + + tx.blocking_write(b"\r\n=== All ping-pong demos complete ===\r\n").unwrap(); + + loop { + cortex_m::asm::wfe(); + } +} + diff --git a/examples/src/bin/dma_scatter_gather.rs b/examples/src/bin/dma_scatter_gather.rs new file mode 100644 index 000000000..86dd881cd --- /dev/null +++ b/examples/src/bin/dma_scatter_gather.rs @@ -0,0 +1,281 @@ +//! DMA scatter-gather transfer example for MCXA276. +//! +//! This example demonstrates using DMA with scatter/gather to chain multiple +//! transfer descriptors. The first TCD transfers the first half of the buffer, +//! then automatically loads the second TCD to transfer the second half. +//! +//! # Embassy-style features demonstrated: +//! - `dma::edma_tcd()` accessor for simplified register access +//! - `DmaChannel::new()` for channel creation +//! - Scatter/gather with chained TCDs + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{edma_tcd, DmaChannel, Tcd}; +use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Source and destination buffers +static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; +static mut DST: [u32; 8] = [0; 8]; + +// TCD pool for scatter/gather - must be 32-byte aligned +#[repr(C, align(32))] +struct TcdPool([Tcd; 2]); + +static mut TCD_POOL: TcdPool = TcdPool([Tcd { + saddr: 0, + soff: 0, + attr: 0, + nbytes: 0, + slast: 0, + daddr: 0, + doff: 0, + citer: 0, + dlast_sga: 0, + csr: 0, + biter: 0, +}; 2]); + +static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); + +// Custom DMA interrupt handler for scatter-gather transfer +// We need a custom handler because we signal completion via TRANSFER_DONE flag +// and need to conditionally clear DONE bit based on ESG status +pub struct ScatterGatherDmaHandler; + +impl embassy_mcxa::interrupt::typelevel::Handler for ScatterGatherDmaHandler { + unsafe fn on_interrupt() { + let edma = edma_tcd(); + + // Clear interrupt flag + edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one()); + + // If ESG=1 (Scatter/Gather), the hardware loads the next TCD and clears DONE. + // If ESG=0 (Last TCD), DONE remains set and must be cleared. + if edma.tcd(0).ch_csr().read().done().bit_is_set() { + edma.tcd(0).ch_csr().write(|w| w.done().clear_bit_by_one()); + } + + TRANSFER_DONE.store(true, Ordering::Release); + } +} + +bind_interrupts!(struct Irqs { + DMA_CH0 => ScatterGatherDmaHandler; +}); + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 transfer example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + unsafe { + dma::init(&pac_periphs); + } + + // Use edma_tcd() accessor instead of passing register block around + let edma = edma_tcd(); + + // Enable DMA interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: false, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA scatter-gather transfer example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC = [1, 2, 3, 4, 5, 6, 7, 8]; + DST = [0; 8]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring scatter-gather DMA with Embassy-style API...\r\n") + .unwrap(); + + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure scatter-gather transfer using direct TCD access: + // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. + // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1. + // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD. + unsafe { + let tcds = core::slice::from_raw_parts_mut( + core::ptr::addr_of_mut!(TCD_POOL.0) as *mut Tcd, + 2, + ); + let src_ptr = core::ptr::addr_of!(SRC) as *const u32; + let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; + + let num_tcds = 2usize; + let chunk_len = 4usize; // 8 / 2 + let chunk_bytes = (chunk_len * 4) as u32; + + for i in 0..num_tcds { + let is_last = i == num_tcds - 1; + let next_tcd_addr = if is_last { + 0 // No next TCD + } else { + &tcds[i + 1] as *const _ as u32 + }; + + tcds[i] = Tcd { + saddr: src_ptr.add(i * chunk_len) as u32, + soff: 4, + attr: 0x0202, // 32-bit src/dst + nbytes: chunk_bytes, + slast: 0, + daddr: dst_ptr.add(i * chunk_len) as u32, + doff: 4, + citer: 1, + dlast_sga: next_tcd_addr as i32, + // ESG (scatter/gather) for non-last, INTMAJOR for all + csr: if is_last { 0x0002 } else { 0x0012 }, + biter: 1, + }; + } + + // Load TCD0 into hardware registers + dma_ch0.load_tcd(edma, &tcds[0]); + } + + tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); + + // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) + // TCD0 is currently loaded. + unsafe { + dma_ch0.trigger_start(edma); + } + + // Wait for first half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + tx.blocking_write(b"First half transferred.\r\n").unwrap(); + tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); + + // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) + // TCD1 should have been loaded by the scatter/gather engine. + unsafe { + dma_ch0.trigger_start(edma); + } + + // Wait for second half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); + + tx.blocking_write(b"EDMA scatter-gather transfer example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: DST should match SRC + let mut mismatch = false; + unsafe { + let src_ptr = core::ptr::addr_of!(SRC) as *const u32; + let dst_ptr = core::ptr::addr_of!(DST) as *const u32; + for i in 0..8 { + if *src_ptr.add(i) != *dst_ptr.add(i) { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } + + loop { + cortex_m::asm::wfe(); + } +} + diff --git a/examples/src/bin/dma_scatter_gather_builder.rs b/examples/src/bin/dma_scatter_gather_builder.rs new file mode 100644 index 000000000..078e26c60 --- /dev/null +++ b/examples/src/bin/dma_scatter_gather_builder.rs @@ -0,0 +1,244 @@ +//! 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::clocks::Gate; +use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, ScatterGatherBuilder}; +use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +// Source buffers (multiple segments) +static mut SRC1: [u32; 4] = [0x11111111, 0x22222222, 0x33333333, 0x44444444]; +static mut SRC2: [u32; 4] = [0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD]; +static mut SRC3: [u32; 4] = [0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]; + +// Destination buffers (one per segment) +static mut DST1: [u32; 4] = [0; 4]; +static mut DST2: [u32; 4] = [0; 4]; +static mut DST3: [u32; 4] = [0; 4]; + +/// Helper to write a u32 as hex to UART +fn write_hex(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + const HEX: &[u8; 16] = b"0123456789ABCDEF"; + for i in (0..8).rev() { + let nibble = ((val >> (i * 4)) & 0xF) as usize; + tx.blocking_write(&[HEX[nibble]]).ok(); + } +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_hex(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + // Initialize DMA + unsafe { + dma::init(&pac_periphs); + } + + // Enable DMA interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + // Create UART for debug output + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: false, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"DMA Scatter-Gather Builder Example\r\n").unwrap(); + tx.blocking_write(b"===================================\r\n\r\n").unwrap(); + + // Show source buffers + tx.blocking_write(b"Source buffers:\r\n").unwrap(); + tx.blocking_write(b" SRC1: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" SRC2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" SRC3: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC3) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + tx.blocking_write(b"Destination buffers (before):\r\n").unwrap(); + tx.blocking_write(b" DST1: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" DST2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" DST3: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Create DMA channel + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + tx.blocking_write(b"Building scatter-gather chain with builder API...\r\n").unwrap(); + + // ========================================================================= + // 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::::new(); + + // Add three transfer segments - the builder handles TCD linking automatically + unsafe { + let src1 = &*core::ptr::addr_of!(SRC1); + let dst1 = &mut *core::ptr::addr_of_mut!(DST1); + builder.add_transfer(src1, dst1); + } + + unsafe { + let src2 = &*core::ptr::addr_of!(SRC2); + let dst2 = &mut *core::ptr::addr_of_mut!(DST2); + builder.add_transfer(src2, dst2); + } + + unsafe { + let src3 = &*core::ptr::addr_of!(SRC3); + let dst3 = &mut *core::ptr::addr_of_mut!(DST3); + builder.add_transfer(src3, dst3); + } + + tx.blocking_write(b"Added 3 transfer segments to chain.\r\n").unwrap(); + tx.blocking_write(b"Starting scatter-gather transfer with .await...\r\n\r\n").unwrap(); + + // 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 + unsafe { + let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather"); + transfer.blocking_wait(); + } + + tx.blocking_write(b"Scatter-gather transfer complete!\r\n\r\n").unwrap(); + + // Show results + tx.blocking_write(b"Destination buffers (after):\r\n").unwrap(); + tx.blocking_write(b" DST1: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" DST2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" DST3: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify all three segments + let mut all_ok = true; + unsafe { + let src1 = core::ptr::addr_of!(SRC1) as *const u32; + let dst1 = core::ptr::addr_of!(DST1) as *const u32; + for i in 0..4 { + if *src1.add(i) != *dst1.add(i) { + all_ok = false; + } + } + + let src2 = core::ptr::addr_of!(SRC2) as *const u32; + let dst2 = core::ptr::addr_of!(DST2) as *const u32; + for i in 0..4 { + if *src2.add(i) != *dst2.add(i) { + all_ok = false; + } + } + + let src3 = core::ptr::addr_of!(SRC3) as *const u32; + let dst3 = core::ptr::addr_of!(DST3) as *const u32; + for i in 0..4 { + if *src3.add(i) != *dst3.add(i) { + all_ok = false; + } + } + } + + if all_ok { + tx.blocking_write(b"PASS: All segments verified!\r\n").unwrap(); + defmt::info!("PASS: All segments verified!"); + } else { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } + + tx.blocking_write(b"\r\n=== Scatter-Gather Builder example complete ===\r\n").unwrap(); + + loop { + cortex_m::asm::wfe(); + } +} diff --git a/examples/src/bin/dma_wrap_transfer.rs b/examples/src/bin/dma_wrap_transfer.rs new file mode 100644 index 000000000..b115a2c19 --- /dev/null +++ b/examples/src/bin/dma_wrap_transfer.rs @@ -0,0 +1,231 @@ +//! DMA wrap transfer example for MCXA276. +//! +//! This example demonstrates using DMA with modulo addressing to wrap around +//! a source buffer, effectively repeating the source data in the destination. +//! +//! # Embassy-style features demonstrated: +//! - `dma::edma_tcd()` accessor for simplified register access +//! - `DmaChannel::is_done()` and `clear_done()` helper methods +//! - No need to pass register block around + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; +use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +// Source buffer: 4 words (16 bytes), aligned to 16 bytes for modulo +#[repr(align(16))] +struct AlignedSrc([u32; 4]); + +static mut SRC: AlignedSrc = AlignedSrc([0; 4]); +static mut DST: [u32; 8] = [0; 8]; + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 wrap transfer example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + unsafe { + dma::init(&pac_periphs); + } + + // Enable DMA interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: false, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA wrap transfer example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC.0 = [1, 2, 3, 4]; + DST = [0; 8]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, unsafe { core::ptr::addr_of!(SRC.0) } as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") + .unwrap(); + + // Create DMA channel using Embassy-style API + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Use edma_tcd() accessor instead of passing register block around + let edma = edma_tcd(); + + // Configure wrap transfer using direct TCD access: + // SRC is 16 bytes (4 * u32). We want to transfer 32 bytes (8 * u32). + // SRC modulo is 16 bytes (2^4 = 16) - wraps source address. + // DST modulo is 0 (disabled). + // This causes the source address to wrap around after 16 bytes, + // effectively repeating the source data. + unsafe { + let t = edma.tcd(0); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq().disable() + .earq().disable() + .eei().no_error() + .ebw().disable() + .done().clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source/destination addresses + t.tcd_saddr().write(|w| w.saddr().bits(core::ptr::addr_of!(SRC.0) as u32)); + t.tcd_daddr().write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DST) as u32)); + + // Offsets: both increment by 4 bytes + t.tcd_soff().write(|w| w.soff().bits(4)); + t.tcd_doff().write(|w| w.doff().bits(4)); + + // Attributes: 32-bit transfers (size = 2) + // SMOD = 4 (2^4 = 16 byte modulo for source), DMOD = 0 (disabled) + t.tcd_attr().write(|w| { + w.ssize().bits(2) + .dsize().bits(2) + .smod().bits(4) // Source modulo: 2^4 = 16 bytes + .dmod().bits(0) // Dest modulo: disabled + }); + + // Transfer 32 bytes total in one minor loop + let nbytes = 32u32; + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Source wraps via modulo, no adjustment needed + t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); + // Reset dest address after major loop + t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32)); + + // Major loop count = 1 + t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); + + // Enable interrupt on major loop completion + t.tcd_csr().write(|w| w.intmajor().set_bit()); + + cortex_m::asm::dsb(); + + tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); + dma_ch0.trigger_start(edma); + } + + // Wait for completion using channel helper method + while !dma_ch0.is_done(edma) { + cortex_m::asm::nop(); + } + unsafe { dma_ch0.clear_done(edma); } + + tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: DST should be [1, 2, 3, 4, 1, 2, 3, 4] + let expected = [1u32, 2, 3, 4, 1, 2, 3, 4]; + let mut mismatch = false; + unsafe { + for i in 0..8 { + if DST[i] != expected[i] { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } + + loop { + cortex_m::asm::wfe(); + } +} + diff --git a/examples/src/bin/lpuart_dma.rs b/examples/src/bin/lpuart_dma.rs new file mode 100644 index 000000000..5ccf97ecc --- /dev/null +++ b/examples/src/bin/lpuart_dma.rs @@ -0,0 +1,127 @@ +//! LPUART DMA example for MCXA276. +//! +//! This example demonstrates using DMA for UART TX and RX operations. +//! It sends a message using DMA, then waits for 16 characters to be received +//! via DMA and echoes them back. + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{self, DMA_REQ_LPUART2_RX, DMA_REQ_LPUART2_TX}; +use embassy_mcxa::lpuart::{Config, LpuartDma}; +use embassy_mcxa::pac; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// DMA interrupt handlers +#[no_mangle] +pub extern "C" fn DMA_CH0() { + unsafe { dma::on_interrupt(0) }; +} + +#[no_mangle] +pub extern "C" fn DMA_CH1() { + unsafe { dma::on_interrupt(1) }; +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + 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!("LPUART DMA example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + // Get PAC peripherals for DMA init + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + // Initialize DMA + unsafe { + dma::init(&pac_periphs); + } + + // Get EDMA TCD register block for transfers + let edma = &pac_periphs.edma_0_tcd0; + + // Enable DMA interrupts + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); + } + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create UART instance with DMA channels + let mut lpuart = LpuartDma::new( + p.LPUART2, + p.P2_2, // TX pin + p.P2_3, // RX pin + p.DMA_CH0, // TX DMA channel + p.DMA_CH1, // RX DMA channel + config, + ) + .unwrap(); + + // Send a message using DMA + let tx_msg = b"Hello from LPUART2 DMA TX!\r\n"; + lpuart + .write_dma(edma, DMA_REQ_LPUART2_TX, tx_msg) + .await + .unwrap(); + + defmt::info!("TX DMA complete"); + + // Send prompt + let prompt = b"Type 16 characters to echo via DMA:\r\n"; + lpuart + .write_dma(edma, DMA_REQ_LPUART2_TX, prompt) + .await + .unwrap(); + + // Receive 16 characters using DMA + let mut rx_buf = [0u8; 16]; + lpuart + .read_dma(edma, DMA_REQ_LPUART2_RX, &mut rx_buf) + .await + .unwrap(); + + defmt::info!("RX DMA complete"); + + // Echo back the received data + let echo_prefix = b"\r\nReceived: "; + lpuart + .write_dma(edma, DMA_REQ_LPUART2_TX, echo_prefix) + .await + .unwrap(); + lpuart + .write_dma(edma, DMA_REQ_LPUART2_TX, &rx_buf) + .await + .unwrap(); + let done_msg = b"\r\nDone!\r\n"; + lpuart + .write_dma(edma, DMA_REQ_LPUART2_TX, done_msg) + .await + .unwrap(); + + defmt::info!("Example complete"); + + loop { + cortex_m::asm::wfe(); + } +} + diff --git a/examples/src/bin/lpuart_ring_buffer.rs b/examples/src/bin/lpuart_ring_buffer.rs new file mode 100644 index 000000000..bc666560c --- /dev/null +++ b/examples/src/bin/lpuart_ring_buffer.rs @@ -0,0 +1,162 @@ +//! LPUART Ring Buffer DMA example for MCXA276. +//! +//! This example demonstrates using the new `RingBuffer` API for continuous +//! circular DMA reception from a UART peripheral. +//! +//! # Features demonstrated: +//! - `setup_circular_read()` for continuous peripheral-to-memory DMA +//! - `RingBuffer` for async reading of received data +//! - Handling of potential overrun conditions +//! - Half-transfer and complete-transfer interrupts for timely wakeups +//! +//! # How it works: +//! 1. Set up a circular DMA transfer from LPUART RX to a ring buffer +//! 2. DMA continuously writes received bytes into the buffer, wrapping around +//! 3. Application asynchronously reads data as it arrives +//! 4. Both half-transfer and complete-transfer interrupts wake the reader + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::clocks::Gate; +use embassy_mcxa::dma::{self, DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DMA_REQ_LPUART2_RX}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel interrupts +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; + DMA_CH1 => DmaCh1InterruptHandler; +}); + +// Ring buffer for RX - power of 2 is ideal for modulo efficiency +static mut RX_RING_BUFFER: [u8; 64] = [0; 64]; + +/// Helper to write a byte as hex to UART +fn write_hex(tx: &mut LpuartTx<'_, Blocking>, byte: u8) { + const HEX: &[u8; 16] = b"0123456789ABCDEF"; + let buf = [HEX[(byte >> 4) as usize], HEX[(byte & 0x0F) as usize]]; + tx.blocking_write(&buf).ok(); +} + +#[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!("LPUART Ring Buffer DMA example starting..."); + + // Enable DMA0 clock and release reset + unsafe { + hal::peripherals::DMA0::enable_clock(); + hal::peripherals::DMA0::release_reset(); + } + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + + // Initialize DMA + unsafe { + dma::init(&pac_periphs); + } + + // Enable DMA interrupts + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); + } + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + enable_tx: true, + enable_rx: true, + ..Default::default() + }; + + // Create blocking UART for TX (we'll use DMA for RX only) + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"LPUART Ring Buffer DMA Example\r\n").unwrap(); + tx.blocking_write(b"==============================\r\n\r\n").unwrap(); + + // Get LPUART2 RX data register address for DMA + let lpuart2 = unsafe { &*pac::Lpuart2::ptr() }; + let rx_data_addr = lpuart2.data().as_ptr() as *const u8; + + // Enable RX DMA request in LPUART + lpuart2.baud().modify(|_, w| w.rdmae().enabled()); + + // Create DMA channel for RX + let dma_ch_rx = DmaChannel::new(p.DMA_CH0); + let edma = dma::edma_tcd(); + + // Configure the DMA mux for LPUART2 RX + unsafe { + dma_ch_rx.set_request_source(edma, DMA_REQ_LPUART2_RX); + } + + tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n").unwrap(); + + // Set up the ring buffer with circular DMA + // This configures the DMA for continuous reception + let ring_buf = unsafe { + let buf = &mut *core::ptr::addr_of_mut!(RX_RING_BUFFER); + dma_ch_rx.setup_circular_read(rx_data_addr, buf) + }; + + // Enable DMA requests to start continuous reception + unsafe { + dma_ch_rx.enable_request(edma); + } + + tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n").unwrap(); + tx.blocking_write(b"The DMA continuously receives in the background.\r\n\r\n").unwrap(); + + // Main loop: read from ring buffer and echo back + let mut read_buf = [0u8; 16]; + let mut total_received: usize = 0; + + loop { + // Async read - waits until data is available + match ring_buf.read(&mut read_buf).await { + Ok(n) if n > 0 => { + total_received += n; + + // Echo back what we received + tx.blocking_write(b"RX[").unwrap(); + for (i, &byte) in read_buf.iter().enumerate().take(n) { + write_hex(&mut tx, byte); + if i < n - 1 { + tx.blocking_write(b" ").unwrap(); + } + } + tx.blocking_write(b"]: ").unwrap(); + tx.blocking_write(&read_buf[..n]).unwrap(); + tx.blocking_write(b"\r\n").unwrap(); + + defmt::info!("Received {} bytes, total: {}", n, total_received); + } + Ok(_) => { + // No data, shouldn't happen with async read + } + Err(_) => { + // Overrun detected + tx.blocking_write(b"ERROR: Ring buffer overrun!\r\n").unwrap(); + defmt::error!("Ring buffer overrun!"); + ring_buf.clear(); + } + } + } +} + -- cgit From 5a6394666e23555e4f329f7b1bd470d0728434a1 Mon Sep 17 00:00:00 2001 From: Bogdan Petru Chircu Mare Date: Thu, 27 Nov 2025 21:39:31 -0800 Subject: Updated per PR #52 feedback --- examples/src/bin/dma_channel_link.rs | 93 +++++++------------------- examples/src/bin/dma_interleave_transfer.rs | 31 ++------- examples/src/bin/dma_mem_to_mem.rs | 19 +----- examples/src/bin/dma_memset.rs | 31 ++------- examples/src/bin/dma_ping_pong_transfer.rs | 60 +++++++---------- examples/src/bin/dma_scatter_gather.rs | 54 ++++++--------- examples/src/bin/dma_scatter_gather_builder.rs | 18 +---- examples/src/bin/dma_wrap_transfer.rs | 31 ++------- examples/src/bin/lpuart_dma.rs | 78 +++++---------------- examples/src/bin/lpuart_ring_buffer.rs | 23 ++----- 10 files changed, 114 insertions(+), 324 deletions(-) (limited to 'examples') diff --git a/examples/src/bin/dma_channel_link.rs b/examples/src/bin/dma_channel_link.rs index d585f8e3a..d541dc7f4 100644 --- a/examples/src/bin/dma_channel_link.rs +++ b/examples/src/bin/dma_channel_link.rs @@ -8,20 +8,18 @@ //! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link) //! //! # Embassy-style features demonstrated: -//! - `dma::edma_tcd()` accessor for simplified register access //! - `DmaChannel::new()` for channel creation //! - `DmaChannel::is_done()` and `clear_done()` helper methods //! - Channel linking with `set_minor_link()` and `set_major_link()` +//! - Standard `DmaCh*InterruptHandler` with `bind_interrupts!` macro #![no_std] #![no_main] -use core::sync::atomic::{AtomicBool, Ordering}; use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; -use embassy_mcxa::dma::{edma_tcd, DmaChannel}; -use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::dma::{self, DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler}; +use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -32,49 +30,12 @@ static mut DEST_BUFFER0: [u32; 4] = [0; 4]; static mut DEST_BUFFER1: [u32; 4] = [0; 4]; static mut DEST_BUFFER2: [u32; 4] = [0; 4]; -static DMA_CH2_DONE: AtomicBool = AtomicBool::new(false); - -// Custom DMA interrupt handlers for channel linking -// CH0 and CH1 just clear flags, CH2 signals completion - -pub struct Ch0Handler; -impl embassy_mcxa::interrupt::typelevel::Handler for Ch0Handler { - unsafe fn on_interrupt() { - let edma = edma_tcd(); - edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one()); - if edma.tcd(0).ch_csr().read().done().bit_is_set() { - edma.tcd(0).ch_csr().write(|w| w.done().clear_bit_by_one()); - } - } -} - -pub struct Ch1Handler; -impl embassy_mcxa::interrupt::typelevel::Handler for Ch1Handler { - unsafe fn on_interrupt() { - let edma = edma_tcd(); - edma.tcd(1).ch_int().write(|w| w.int().clear_bit_by_one()); - if edma.tcd(1).ch_csr().read().done().bit_is_set() { - edma.tcd(1).ch_csr().write(|w| w.done().clear_bit_by_one()); - } - } -} - -pub struct Ch2Handler; -impl embassy_mcxa::interrupt::typelevel::Handler for Ch2Handler { - unsafe fn on_interrupt() { - let edma = edma_tcd(); - edma.tcd(2).ch_int().write(|w| w.int().clear_bit_by_one()); - if edma.tcd(2).ch_csr().read().done().bit_is_set() { - edma.tcd(2).ch_csr().write(|w| w.done().clear_bit_by_one()); - } - DMA_CH2_DONE.store(true, Ordering::Release); - } -} - +// Bind DMA channel interrupts using Embassy-style macro +// The standard handlers call on_interrupt() which wakes wakers and clears flags bind_interrupts!(struct Irqs { - DMA_CH0 => Ch0Handler; - DMA_CH1 => Ch1Handler; - DMA_CH2 => Ch2Handler; + DMA_CH0 => DmaCh0InterruptHandler; + DMA_CH1 => DmaCh1InterruptHandler; + DMA_CH2 => DmaCh2InterruptHandler; }); /// Helper to write a u32 as decimal ASCII to UART @@ -125,21 +86,12 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA channel link example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } + // Ensure DMA is initialized (clock/reset/init handled automatically by HAL) + dma::ensure_init(); let pac_periphs = unsafe { pac::Peripherals::steal() }; - - unsafe { - dma::init(&pac_periphs); - } - - // Use edma_tcd() accessor instead of passing register block around - let edma = edma_tcd(); let dma0 = &pac_periphs.dma0; + let edma = unsafe { &*pac::Edma0Tcd0::ptr() }; // Clear any residual state for i in 0..3 { @@ -206,7 +158,7 @@ async fn main(_spawner: Spawner) { let ch0 = DmaChannel::new(p.DMA_CH0); let ch1 = DmaChannel::new(p.DMA_CH1); - let _ch2 = DmaChannel::new(p.DMA_CH2); + let ch2 = DmaChannel::new(p.DMA_CH2); // Configure channels using direct TCD access (advanced feature demo) // This example demonstrates channel linking which requires direct TCD manipulation @@ -291,8 +243,8 @@ async fn main(_spawner: Spawner) { 2, // count (major loop = 2 iterations) false, // no interrupt ); - ch0.set_minor_link(edma, 1); // Link to CH1 after each minor loop - ch0.set_major_link(edma, 2); // Link to CH2 after major loop + ch0.set_minor_link(1); // Link to CH1 after each minor loop + ch0.set_major_link(2); // Link to CH2 after major loop // Channel 1: Transfer 16 bytes (triggered by CH0 minor link) configure_tcd( @@ -322,32 +274,35 @@ async fn main(_spawner: Spawner) { tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n").unwrap(); // Trigger first minor loop of CH0 - unsafe { ch0.trigger_start(edma); } + unsafe { ch0.trigger_start(); } // Wait for CH1 to complete (triggered by CH0 minor link) - while !ch1.is_done(edma) { + while !ch1.is_done() { cortex_m::asm::nop(); } - unsafe { ch1.clear_done(edma); } + unsafe { ch1.clear_done(); } tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap(); tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n").unwrap(); // Trigger second minor loop of CH0 - unsafe { ch0.trigger_start(edma); } + unsafe { ch0.trigger_start(); } // Wait for CH0 major loop to complete - while !ch0.is_done(edma) { + while !ch0.is_done() { cortex_m::asm::nop(); } - unsafe { ch0.clear_done(edma); } + unsafe { ch0.clear_done(); } tx.blocking_write(b"CH0 major loop done.\r\n").unwrap(); // Wait for CH2 to complete (triggered by CH0 major link) - while !DMA_CH2_DONE.load(Ordering::Acquire) { + // Using is_done() instead of AtomicBool - the standard interrupt handler + // clears the interrupt flag and wakes wakers, but DONE bit remains set + while !ch2.is_done() { cortex_m::asm::nop(); } + unsafe { ch2.clear_done(); } tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap(); diff --git a/examples/src/bin/dma_interleave_transfer.rs b/examples/src/bin/dma_interleave_transfer.rs index 710f18de3..949ea0605 100644 --- a/examples/src/bin/dma_interleave_transfer.rs +++ b/examples/src/bin/dma_interleave_transfer.rs @@ -4,7 +4,6 @@ //! to interleave data during transfer. //! //! # Embassy-style features demonstrated: -//! - `dma::edma_tcd()` accessor for simplified register access //! - `TransferOptions::default()` for configuration (used internally) //! - DMA channel with `DmaChannel::new()` @@ -13,9 +12,8 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; -use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; -use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler}; +use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -80,19 +78,7 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA interleave transfer example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - unsafe { - dma::init(&pac_periphs); - } - - // Enable DMA interrupt + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); } @@ -130,15 +116,12 @@ async fn main(_spawner: Spawner) { // Create DMA channel using Embassy-style API let dma_ch0 = DmaChannel::new(p.DMA_CH0); - // Use edma_tcd() accessor instead of passing register block around - let edma = edma_tcd(); - // Configure interleaved transfer using direct TCD access: // - src_offset = 4: advance source by 4 bytes after each read // - dst_offset = 8: advance dest by 8 bytes after each write // This spreads source data across every other word in destination unsafe { - let t = edma.tcd(0); + let t = dma_ch0.tcd(); // Reset channel state t.ch_csr().write(|w| { @@ -182,14 +165,14 @@ async fn main(_spawner: Spawner) { cortex_m::asm::dsb(); tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); - dma_ch0.trigger_start(edma); + dma_ch0.trigger_start(); } // Wait for completion using channel helper method - while !dma_ch0.is_done(edma) { + while !dma_ch0.is_done() { cortex_m::asm::nop(); } - unsafe { dma_ch0.clear_done(edma); } + unsafe { dma_ch0.clear_done(); } tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") .unwrap(); diff --git a/examples/src/bin/dma_mem_to_mem.rs b/examples/src/bin/dma_mem_to_mem.rs index e193e8c6a..01e5edb1e 100644 --- a/examples/src/bin/dma_mem_to_mem.rs +++ b/examples/src/bin/dma_mem_to_mem.rs @@ -15,9 +15,8 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, TransferOptions}; -use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -84,21 +83,7 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA memory-to-memory example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - // Get PAC peripherals for DMA init - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - // Initialize DMA - unsafe { - dma::init(&pac_periphs); - } - - // Enable DMA interrupt + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); } diff --git a/examples/src/bin/dma_memset.rs b/examples/src/bin/dma_memset.rs index b76ba988d..8a1636e57 100644 --- a/examples/src/bin/dma_memset.rs +++ b/examples/src/bin/dma_memset.rs @@ -4,7 +4,6 @@ //! The source address stays fixed while the destination increments. //! //! # Embassy-style features demonstrated: -//! - `dma::edma_tcd()` accessor for simplified register access //! - `DmaChannel::is_done()` and `clear_done()` helper methods //! - No need to pass register block around @@ -13,9 +12,8 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; -use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; -use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler}; +use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -79,19 +77,7 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA memset example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - unsafe { - dma::init(&pac_periphs); - } - - // Enable DMA interrupt + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); } @@ -139,14 +125,11 @@ async fn main(_spawner: Spawner) { // Create DMA channel using Embassy-style API let dma_ch0 = DmaChannel::new(p.DMA_CH0); - // Use edma_tcd() accessor instead of passing register block around - let edma = edma_tcd(); - // Configure memset transfer using direct TCD access: // Source stays fixed (soff = 0, reads same pattern repeatedly) // Destination increments (doff = 4) unsafe { - let t = edma.tcd(0); + let t = dma_ch0.tcd(); // Reset channel state t.ch_csr().write(|w| { @@ -190,14 +173,14 @@ async fn main(_spawner: Spawner) { cortex_m::asm::dsb(); tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); - dma_ch0.trigger_start(edma); + dma_ch0.trigger_start(); } // Wait for completion using channel helper method - while !dma_ch0.is_done(edma) { + while !dma_ch0.is_done() { cortex_m::asm::nop(); } - unsafe { dma_ch0.clear_done(edma); } + unsafe { dma_ch0.clear_done(); } tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n") .unwrap(); diff --git a/examples/src/bin/dma_ping_pong_transfer.rs b/examples/src/bin/dma_ping_pong_transfer.rs index 13ad9782d..d765ea575 100644 --- a/examples/src/bin/dma_ping_pong_transfer.rs +++ b/examples/src/bin/dma_ping_pong_transfer.rs @@ -4,7 +4,9 @@ //! //! ## Approach 1: Scatter/Gather with linked TCDs (manual) //! - Two TCDs link to each other for alternating transfers -//! - Uses custom interrupt handler with AtomicBool flag +//! - Uses custom handler that delegates to on_interrupt() then signals completion +//! - Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +//! so we need an AtomicBool to track completion //! //! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!) //! - Single continuous transfer over entire buffer @@ -12,9 +14,10 @@ //! - Application can process first half while second half is being filled //! //! # Embassy-style features demonstrated: -//! - `dma::edma_tcd()` accessor for simplified register access //! - `DmaChannel::new()` for channel creation //! - Scatter/gather with linked TCDs +//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) +//! - Standard `DmaCh1InterruptHandler` with `bind_interrupts!` macro //! - NEW: `wait_half()` for half-transfer interrupt handling #![no_std] @@ -23,9 +26,8 @@ use core::sync::atomic::{AtomicBool, Ordering}; use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; -use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh1InterruptHandler, Tcd, TransferOptions}; -use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::dma::{self, DmaChannel, DmaCh1InterruptHandler, Tcd, TransferOptions}; +use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -56,30 +58,31 @@ static mut TCD_POOL: TcdPool = TcdPool([Tcd { biter: 0, }; 2]); +// AtomicBool to track scatter/gather completion +// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +// so we need this flag to detect when each transfer completes static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); -// Custom DMA interrupt handler for ping-pong transfer -// We need a custom handler because we signal completion via TRANSFER_DONE flag -// and don't clear DONE bit when using Scatter/Gather (ESG=1) +// Custom handler for scatter/gather that delegates to HAL's on_interrupt() +// This follows the "interrupts as threads" pattern - the handler does minimal work +// (delegates to HAL + sets a flag) and the main task does the actual processing pub struct PingPongDmaHandler; impl embassy_mcxa::interrupt::typelevel::Handler for PingPongDmaHandler { unsafe fn on_interrupt() { - let edma = edma_tcd(); - - // Clear interrupt flag - edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one()); - - // Do NOT clear DONE bit when using Scatter/Gather (ESG=1), - // as the hardware loads the next TCD which resets the status. - + // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers + dma::on_interrupt(0); + // Signal completion for polling (needed because ESG clears DONE bit) TRANSFER_DONE.store(true, Ordering::Release); } } +// Bind DMA channel interrupts +// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag) +// CH1: Standard handler for wait_half() demo bind_interrupts!(struct Irqs { DMA_CH0 => PingPongDmaHandler; - DMA_CH1 => DmaCh1InterruptHandler; // For wait_half() demo + DMA_CH1 => DmaCh1InterruptHandler; }); /// Helper to write a u32 as decimal ASCII to UART @@ -130,22 +133,7 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA ping-pong transfer example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - unsafe { - dma::init(&pac_periphs); - } - - // Use edma_tcd() accessor instead of passing register block around - let edma = edma_tcd(); - - // Enable DMA interrupt + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); } @@ -228,14 +216,14 @@ async fn main(_spawner: Spawner) { }; // Load TCD0 into hardware registers - dma_ch0.load_tcd(edma, &tcds[0]); + dma_ch0.load_tcd(&tcds[0]); } tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) unsafe { - dma_ch0.trigger_start(edma); + dma_ch0.trigger_start(); } // Wait for first half @@ -249,7 +237,7 @@ async fn main(_spawner: Spawner) { // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) unsafe { - dma_ch0.trigger_start(edma); + dma_ch0.trigger_start(); } // Wait for second half diff --git a/examples/src/bin/dma_scatter_gather.rs b/examples/src/bin/dma_scatter_gather.rs index 86dd881cd..d78605acc 100644 --- a/examples/src/bin/dma_scatter_gather.rs +++ b/examples/src/bin/dma_scatter_gather.rs @@ -5,9 +5,9 @@ //! then automatically loads the second TCD to transfer the second half. //! //! # Embassy-style features demonstrated: -//! - `dma::edma_tcd()` accessor for simplified register access //! - `DmaChannel::new()` for channel creation //! - Scatter/gather with chained TCDs +//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) #![no_std] #![no_main] @@ -15,9 +15,8 @@ use core::sync::atomic::{AtomicBool, Ordering}; use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; -use embassy_mcxa::dma::{edma_tcd, DmaChannel, Tcd}; -use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::dma::{self, DmaChannel, Tcd}; +use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -44,30 +43,27 @@ static mut TCD_POOL: TcdPool = TcdPool([Tcd { biter: 0, }; 2]); +// AtomicBool to track scatter/gather completion +// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +// so we need this flag to detect when each transfer completes static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); -// Custom DMA interrupt handler for scatter-gather transfer -// We need a custom handler because we signal completion via TRANSFER_DONE flag -// and need to conditionally clear DONE bit based on ESG status +// Custom handler for scatter/gather that delegates to HAL's on_interrupt() +// This follows the "interrupts as threads" pattern - the handler does minimal work +// (delegates to HAL + sets a flag) and the main task does the actual processing pub struct ScatterGatherDmaHandler; impl embassy_mcxa::interrupt::typelevel::Handler for ScatterGatherDmaHandler { unsafe fn on_interrupt() { - let edma = edma_tcd(); - - // Clear interrupt flag - edma.tcd(0).ch_int().write(|w| w.int().clear_bit_by_one()); - - // If ESG=1 (Scatter/Gather), the hardware loads the next TCD and clears DONE. - // If ESG=0 (Last TCD), DONE remains set and must be cleared. - if edma.tcd(0).ch_csr().read().done().bit_is_set() { - edma.tcd(0).ch_csr().write(|w| w.done().clear_bit_by_one()); - } - + // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers + dma::on_interrupt(0); + // Signal completion for polling (needed because ESG clears DONE bit) TRANSFER_DONE.store(true, Ordering::Release); } } +// Bind DMA channel interrupt +// Custom handler for scatter/gather (delegates to on_interrupt + sets flag) bind_interrupts!(struct Irqs { DMA_CH0 => ScatterGatherDmaHandler; }); @@ -120,20 +116,8 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA scatter-gather transfer example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - unsafe { - dma::init(&pac_periphs); - } - - // Use edma_tcd() accessor instead of passing register block around - let edma = edma_tcd(); + // Ensure DMA is initialized (clock/reset/init handled automatically by HAL) + dma::ensure_init(); // Enable DMA interrupt unsafe { @@ -213,7 +197,7 @@ async fn main(_spawner: Spawner) { } // Load TCD0 into hardware registers - dma_ch0.load_tcd(edma, &tcds[0]); + dma_ch0.load_tcd(&tcds[0]); } tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); @@ -221,7 +205,7 @@ async fn main(_spawner: Spawner) { // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) // TCD0 is currently loaded. unsafe { - dma_ch0.trigger_start(edma); + dma_ch0.trigger_start(); } // Wait for first half @@ -236,7 +220,7 @@ async fn main(_spawner: Spawner) { // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) // TCD1 should have been loaded by the scatter/gather engine. unsafe { - dma_ch0.trigger_start(edma); + dma_ch0.trigger_start(); } // Wait for second half diff --git a/examples/src/bin/dma_scatter_gather_builder.rs b/examples/src/bin/dma_scatter_gather_builder.rs index 078e26c60..51bfbeb67 100644 --- a/examples/src/bin/dma_scatter_gather_builder.rs +++ b/examples/src/bin/dma_scatter_gather_builder.rs @@ -22,9 +22,8 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, ScatterGatherBuilder}; -use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -81,20 +80,7 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA Scatter-Gather Builder example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - // Initialize DMA - unsafe { - dma::init(&pac_periphs); - } - - // Enable DMA interrupt + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); } diff --git a/examples/src/bin/dma_wrap_transfer.rs b/examples/src/bin/dma_wrap_transfer.rs index b115a2c19..8e9aedbfb 100644 --- a/examples/src/bin/dma_wrap_transfer.rs +++ b/examples/src/bin/dma_wrap_transfer.rs @@ -4,7 +4,6 @@ //! a source buffer, effectively repeating the source data in the destination. //! //! # Embassy-style features demonstrated: -//! - `dma::edma_tcd()` accessor for simplified register access //! - `DmaChannel::is_done()` and `clear_done()` helper methods //! - No need to pass register block around @@ -13,9 +12,8 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; -use embassy_mcxa::dma::{edma_tcd, DmaChannel, DmaCh0InterruptHandler}; -use embassy_mcxa::{bind_interrupts, dma}; +use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler}; +use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -80,19 +78,7 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA wrap transfer example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - unsafe { - dma::init(&pac_periphs); - } - - // Enable DMA interrupt + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); } @@ -130,9 +116,6 @@ async fn main(_spawner: Spawner) { // Create DMA channel using Embassy-style API let dma_ch0 = DmaChannel::new(p.DMA_CH0); - // Use edma_tcd() accessor instead of passing register block around - let edma = edma_tcd(); - // Configure wrap transfer using direct TCD access: // SRC is 16 bytes (4 * u32). We want to transfer 32 bytes (8 * u32). // SRC modulo is 16 bytes (2^4 = 16) - wraps source address. @@ -140,7 +123,7 @@ async fn main(_spawner: Spawner) { // This causes the source address to wrap around after 16 bytes, // effectively repeating the source data. unsafe { - let t = edma.tcd(0); + let t = dma_ch0.tcd(); // Reset channel state t.ch_csr().write(|w| { @@ -189,14 +172,14 @@ async fn main(_spawner: Spawner) { cortex_m::asm::dsb(); tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); - dma_ch0.trigger_start(edma); + dma_ch0.trigger_start(); } // Wait for completion using channel helper method - while !dma_ch0.is_done(edma) { + while !dma_ch0.is_done() { cortex_m::asm::nop(); } - unsafe { dma_ch0.clear_done(edma); } + unsafe { dma_ch0.clear_done(); } tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n") .unwrap(); diff --git a/examples/src/bin/lpuart_dma.rs b/examples/src/bin/lpuart_dma.rs index 5ccf97ecc..4e321b111 100644 --- a/examples/src/bin/lpuart_dma.rs +++ b/examples/src/bin/lpuart_dma.rs @@ -3,28 +3,25 @@ //! This example demonstrates using DMA for UART TX and RX operations. //! It sends a message using DMA, then waits for 16 characters to be received //! via DMA and echoes them back. +//! +//! The DMA request sources are automatically derived from the LPUART instance type. +//! DMA clock/reset/init is handled automatically by the HAL. #![no_std] #![no_main] use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; -use embassy_mcxa::dma::{self, DMA_REQ_LPUART2_RX, DMA_REQ_LPUART2_TX}; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; use embassy_mcxa::lpuart::{Config, LpuartDma}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -// DMA interrupt handlers -#[no_mangle] -pub extern "C" fn DMA_CH0() { - unsafe { dma::on_interrupt(0) }; -} - -#[no_mangle] -pub extern "C" fn DMA_CH1() { - unsafe { dma::on_interrupt(1) }; -} +// Bind DMA channel interrupts using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; + DMA_CH1 => DmaCh1InterruptHandler; +}); #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -35,24 +32,7 @@ async fn main(_spawner: Spawner) { defmt::info!("LPUART DMA example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - // Get PAC peripherals for DMA init - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - // Initialize DMA - unsafe { - dma::init(&pac_periphs); - } - - // Get EDMA TCD register block for transfers - let edma = &pac_periphs.edma_0_tcd0; - - // Enable DMA interrupts + // Enable DMA interrupts (per-channel, as needed) unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); @@ -77,51 +57,29 @@ async fn main(_spawner: Spawner) { ) .unwrap(); - // Send a message using DMA + // Send a message using DMA (DMA request source is automatically derived from LPUART2) let tx_msg = b"Hello from LPUART2 DMA TX!\r\n"; - lpuart - .write_dma(edma, DMA_REQ_LPUART2_TX, tx_msg) - .await - .unwrap(); + lpuart.write_dma(tx_msg).await.unwrap(); defmt::info!("TX DMA complete"); // Send prompt let prompt = b"Type 16 characters to echo via DMA:\r\n"; - lpuart - .write_dma(edma, DMA_REQ_LPUART2_TX, prompt) - .await - .unwrap(); + lpuart.write_dma(prompt).await.unwrap(); // Receive 16 characters using DMA let mut rx_buf = [0u8; 16]; - lpuart - .read_dma(edma, DMA_REQ_LPUART2_RX, &mut rx_buf) - .await - .unwrap(); + lpuart.read_dma(&mut rx_buf).await.unwrap(); defmt::info!("RX DMA complete"); // Echo back the received data let echo_prefix = b"\r\nReceived: "; - lpuart - .write_dma(edma, DMA_REQ_LPUART2_TX, echo_prefix) - .await - .unwrap(); - lpuart - .write_dma(edma, DMA_REQ_LPUART2_TX, &rx_buf) - .await - .unwrap(); + lpuart.write_dma(echo_prefix).await.unwrap(); + lpuart.write_dma(&rx_buf).await.unwrap(); let done_msg = b"\r\nDone!\r\n"; - lpuart - .write_dma(edma, DMA_REQ_LPUART2_TX, done_msg) - .await - .unwrap(); + lpuart.write_dma(done_msg).await.unwrap(); defmt::info!("Example complete"); - - loop { - cortex_m::asm::wfe(); - } } diff --git a/examples/src/bin/lpuart_ring_buffer.rs b/examples/src/bin/lpuart_ring_buffer.rs index bc666560c..d71876ade 100644 --- a/examples/src/bin/lpuart_ring_buffer.rs +++ b/examples/src/bin/lpuart_ring_buffer.rs @@ -20,8 +20,7 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::clocks::Gate; -use embassy_mcxa::dma::{self, DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DMA_REQ_LPUART2_RX}; +use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DMA_REQ_LPUART2_RX}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -56,20 +55,7 @@ async fn main(_spawner: Spawner) { defmt::info!("LPUART Ring Buffer DMA example starting..."); - // Enable DMA0 clock and release reset - unsafe { - hal::peripherals::DMA0::enable_clock(); - hal::peripherals::DMA0::release_reset(); - } - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - - // Initialize DMA - unsafe { - dma::init(&pac_periphs); - } - - // Enable DMA interrupts + // Enable DMA interrupts (DMA clock/reset/init is handled automatically by HAL) unsafe { cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); @@ -99,11 +85,10 @@ async fn main(_spawner: Spawner) { // Create DMA channel for RX let dma_ch_rx = DmaChannel::new(p.DMA_CH0); - let edma = dma::edma_tcd(); // Configure the DMA mux for LPUART2 RX unsafe { - dma_ch_rx.set_request_source(edma, DMA_REQ_LPUART2_RX); + dma_ch_rx.set_request_source(DMA_REQ_LPUART2_RX); } tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n").unwrap(); @@ -117,7 +102,7 @@ async fn main(_spawner: Spawner) { // Enable DMA requests to start continuous reception unsafe { - dma_ch_rx.enable_request(edma); + dma_ch_rx.enable_request(); } tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n").unwrap(); -- cgit From 3b239cb6de22b7bb8c2d87defb3205294653be7a Mon Sep 17 00:00:00 2001 From: James Munns Date: Sat, 29 Nov 2025 16:07:30 +0100 Subject: Remove Drive/Slew settings for Input pin (#57) * Don't set slew+strength for inputs * Update example --- examples/src/bin/button.rs | 6 ++++-- examples/src/bin/button_async.rs | 5 +++-- examples/src/bin/i2c-scan-blocking.rs | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/src/bin/button.rs b/examples/src/bin/button.rs index 2abfe0a9f..943edbb15 100644 --- a/examples/src/bin/button.rs +++ b/examples/src/bin/button.rs @@ -3,7 +3,7 @@ use embassy_executor::Spawner; use embassy_time::Timer; -use hal::gpio::{DriveStrength, Input, Pull, SlewRate}; +use hal::gpio::{Input, Pull}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; #[embassy_executor::main] @@ -12,7 +12,9 @@ async fn main(_spawner: Spawner) { defmt::info!("Button example"); - let monitor = Input::new(p.P1_7, Pull::Disabled, DriveStrength::Normal, SlewRate::Slow); + // This button is labeled "WAKEUP" on the FRDM-MCXA276 + // The board already has a 10K pullup + let monitor = Input::new(p.P1_7, Pull::Disabled); loop { defmt::info!("Pin level is {:?}", monitor.get_level()); diff --git a/examples/src/bin/button_async.rs b/examples/src/bin/button_async.rs index 1ecec2e48..6cc7b62cd 100644 --- a/examples/src/bin/button_async.rs +++ b/examples/src/bin/button_async.rs @@ -3,7 +3,7 @@ use embassy_executor::Spawner; use embassy_time::Timer; -use hal::gpio::{DriveStrength, Input, Pull, SlewRate}; +use hal::gpio::{Input, Pull}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; #[embassy_executor::main] @@ -13,7 +13,8 @@ async fn main(_spawner: Spawner) { defmt::info!("GPIO interrupt example"); // This button is labeled "WAKEUP" on the FRDM-MCXA276 - let mut pin = Input::new(p.P1_7, Pull::Up, DriveStrength::Normal, SlewRate::Fast); + // The board already has a 10K pullup + let mut pin = Input::new(p.P1_7, Pull::Disabled); let mut press_count = 0u32; diff --git a/examples/src/bin/i2c-scan-blocking.rs b/examples/src/bin/i2c-scan-blocking.rs index 72f9d09e0..4e203597b 100644 --- a/examples/src/bin/i2c-scan-blocking.rs +++ b/examples/src/bin/i2c-scan-blocking.rs @@ -2,7 +2,7 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa::gpio::{DriveStrength, Pull, SlewRate}; +use embassy_mcxa::gpio::Pull; use embassy_mcxa::Input; use embassy_time::Timer; use hal::clocks::config::Div8; @@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) { // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and // defaults to SWO on the debug peripheral. Explicitly make it a high-z // input. - let _pin = Input::new(p.P0_2, Pull::Disabled, DriveStrength::Normal, SlewRate::Slow); + let _pin = Input::new(p.P0_2, Pull::Disabled); let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap(); for addr in 0x01..=0x7f { -- cgit From 970138277bdbf176a3a9320c9d0de9256945d21e Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 1 Dec 2025 09:44:07 -0600 Subject: timer: use u32 for high-level api --- examples/stm32f4/src/bin/pwm_complementary.rs | 2 +- examples/stm32f4/src/bin/ws2812_pwm.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs index 50008a37b..5e39a06f5 100644 --- a/examples/stm32f4/src/bin/pwm_complementary.rs +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -33,7 +33,7 @@ async fn main(_spawner: Spawner) { ); let max = pwm.get_max_duty(); - pwm.set_dead_time(max / 1024); + pwm.set_dead_time((max / 1024) as u16); pwm.enable(Channel::Ch1); diff --git a/examples/stm32f4/src/bin/ws2812_pwm.rs b/examples/stm32f4/src/bin/ws2812_pwm.rs index ccfd0661e..4e556f0d4 100644 --- a/examples/stm32f4/src/bin/ws2812_pwm.rs +++ b/examples/stm32f4/src/bin/ws2812_pwm.rs @@ -61,7 +61,7 @@ async fn main(_spawner: Spawner) { // construct ws2812 non-return-to-zero (NRZ) code bit by bit // ws2812 only need 24 bits for each LED, but we add one bit more to keep PWM output low - let max_duty = ws2812_pwm.max_duty_cycle(); + let max_duty = ws2812_pwm.max_duty_cycle() as u16; let n0 = 8 * max_duty / 25; // ws2812 Bit 0 high level timing let n1 = 2 * n0; // ws2812 Bit 1 high level timing -- cgit From 717346f21a4cf4993c2a1f046e26b6bf647d89cb Mon Sep 17 00:00:00 2001 From: JanKomarekNXP <151725448+JanKomarekNXP@users.noreply.github.com> Date: Mon, 1 Dec 2025 18:07:58 +0100 Subject: Refactor LPUART driver constructors (#51) * Refactor LPUART driver constructors - Add new_with_rtscts(), new_with_rts(), new_with_cts() methods - Store RTS/CTS pins in TX/RX structs - Remove enable_tx, enable_rx, enable_rx_rts, enable_tx_cts config fields - Fix typo: msb_firs -> msb_first - Fix write_byte() return type to Result<()> * Update hello example for LPUART driver changes * Refactor buffered LPUART initialization logic - Split new_inner() into init_common() and separate helpers for full-duplex, TX-only, and RX-only - Replace assert!() with proper Error::InvalidArgument returns for empty buffers - Simplify constructor implementations by removing expect() calls --- examples/src/bin/hello.rs | 14 ++++++++------ examples/src/bin/lpuart_buffered.rs | 2 -- examples/src/bin/lpuart_polling.rs | 2 -- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'examples') diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs index f426d1898..e371d9413 100644 --- a/examples/src/bin/hello.rs +++ b/examples/src/bin/hello.rs @@ -2,27 +2,29 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; use hal::lpuart::{Blocking, Config, Lpuart}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; /// Simple helper to write a byte as hex to UART fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) { const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; - uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); - uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); + let _ = uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); + let _ = uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); } #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); + 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!("boot"); // Create UART configuration let config = Config { baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, ..Default::default() }; @@ -97,7 +99,7 @@ async fn main(_spawner: Spawner) { // Regular character buffer[buf_idx] = byte; buf_idx += 1; - uart.write_byte(byte); + let _ = uart.write_byte(byte); } } } diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs index 7f77d557d..420589d00 100644 --- a/examples/src/bin/lpuart_buffered.rs +++ b/examples/src/bin/lpuart_buffered.rs @@ -27,8 +27,6 @@ async fn main(_spawner: Spawner) { // UART configuration (enable both TX and RX) let config = Config { baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, rx_fifo_watermark: 0, tx_fifo_watermark: 0, ..Default::default() diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs index 9cea418cc..b80668834 100644 --- a/examples/src/bin/lpuart_polling.rs +++ b/examples/src/bin/lpuart_polling.rs @@ -19,8 +19,6 @@ async fn main(_spawner: Spawner) { // Create UART configuration let config = Config { baudrate_bps: 115_200, - enable_tx: true, - enable_rx: true, ..Default::default() }; -- cgit From 230237b73cbe6f31780ea407ed13bee1adf8eaa2 Mon Sep 17 00:00:00 2001 From: Bogdan Petru Chircu Mare Date: Mon, 1 Dec 2025 09:08:03 -0800 Subject: Apply rustfmt formatting fixes --- examples/src/bin/dma_channel_link.rs | 88 ++++++++++++++++---------- examples/src/bin/dma_interleave_transfer.rs | 38 ++++++----- examples/src/bin/dma_mem_to_mem.rs | 12 ++-- examples/src/bin/dma_memset.rs | 37 ++++++----- examples/src/bin/dma_ping_pong_transfer.rs | 52 ++++++++------- examples/src/bin/dma_scatter_gather.rs | 42 ++++++------ examples/src/bin/dma_scatter_gather_builder.rs | 17 +++-- examples/src/bin/dma_wrap_transfer.rs | 46 ++++++++------ examples/src/bin/lpuart_dma.rs | 4 +- examples/src/bin/lpuart_ring_buffer.rs | 12 ++-- 10 files changed, 201 insertions(+), 147 deletions(-) (limited to 'examples') diff --git a/examples/src/bin/dma_channel_link.rs b/examples/src/bin/dma_channel_link.rs index d541dc7f4..34162d931 100644 --- a/examples/src/bin/dma_channel_link.rs +++ b/examples/src/bin/dma_channel_link.rs @@ -18,10 +18,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler}; -use embassy_mcxa::bind_interrupts; +use embassy_mcxa::dma::{self, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler, DmaChannel}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Buffers @@ -104,10 +103,14 @@ async fn main(_spawner: Spawner) { // Clear Global Halt/Error state dma0.mp_csr().modify(|_, w| { - w.halt().normal_operation() - .hae().normal_operation() - .ecx().normal_operation() - .cx().normal_operation() + w.halt() + .normal_operation() + .hae() + .normal_operation() + .ecx() + .normal_operation() + .cx() + .normal_operation() }); unsafe { @@ -126,8 +129,7 @@ async fn main(_spawner: Spawner) { let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); let (mut tx, _rx) = lpuart.split(); - tx.blocking_write(b"EDMA channel link example begin.\r\n\r\n") - .unwrap(); + tx.blocking_write(b"EDMA channel link example begin.\r\n\r\n").unwrap(); // Initialize buffers unsafe { @@ -180,11 +182,16 @@ async fn main(_spawner: Spawner) { // Reset channel state t.ch_csr().write(|w| { - w.erq().disable() - .earq().disable() - .eei().no_error() - .ebw().disable() - .done().clear_bit_by_one() + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() }); t.ch_es().write(|w| w.bits(0)); t.ch_int().write(|w| w.int().clear_bit_by_one()); @@ -211,8 +218,10 @@ async fn main(_spawner: Spawner) { // Major loop: reset source address after major loop let total_bytes = nbytes * count as u32; - t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32)); - t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32)); + t.tcd_slast_sda() + .write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32)); + t.tcd_dlast_sga() + .write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32)); // Major loop count t.tcd_biter_elinkno().write(|w| w.biter().bits(count)); @@ -229,7 +238,6 @@ async fn main(_spawner: Spawner) { } unsafe { - // Channel 0: Transfer 16 bytes total (8 bytes per minor loop, 2 major iterations) // Minor Link -> Channel 1 // Major Link -> Channel 2 @@ -265,34 +273,44 @@ async fn main(_spawner: Spawner) { core::ptr::addr_of!(SRC_BUFFER) as u32, core::ptr::addr_of_mut!(DEST_BUFFER2) as u32, 4, - 16, // full buffer in one minor loop - 1, // 1 major iteration + 16, // full buffer in one minor loop + 1, // 1 major iteration true, // enable interrupt ); } - tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n").unwrap(); + tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n") + .unwrap(); // Trigger first minor loop of CH0 - unsafe { ch0.trigger_start(); } + unsafe { + ch0.trigger_start(); + } // Wait for CH1 to complete (triggered by CH0 minor link) while !ch1.is_done() { cortex_m::asm::nop(); } - unsafe { ch1.clear_done(); } + unsafe { + ch1.clear_done(); + } tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap(); - tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n").unwrap(); + tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n") + .unwrap(); // Trigger second minor loop of CH0 - unsafe { ch0.trigger_start(); } + unsafe { + ch0.trigger_start(); + } // Wait for CH0 major loop to complete while !ch0.is_done() { cortex_m::asm::nop(); } - unsafe { ch0.clear_done(); } + unsafe { + ch0.clear_done(); + } tx.blocking_write(b"CH0 major loop done.\r\n").unwrap(); @@ -302,12 +320,13 @@ async fn main(_spawner: Spawner) { while !ch2.is_done() { cortex_m::asm::nop(); } - unsafe { ch2.clear_done(); } + unsafe { + ch2.clear_done(); + } tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap(); - tx.blocking_write(b"EDMA channel link example finish.\r\n\r\n") - .unwrap(); + tx.blocking_write(b"EDMA channel link example finish.\r\n\r\n").unwrap(); tx.blocking_write(b"DEST0 (after): ").unwrap(); print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); @@ -330,9 +349,15 @@ async fn main(_spawner: Spawner) { let dst2_ptr = core::ptr::addr_of!(DEST_BUFFER2) as *const u32; for i in 0..4 { - if *dst0_ptr.add(i) != *src_ptr.add(i) { success = false; } - if *dst1_ptr.add(i) != *src_ptr.add(i) { success = false; } - if *dst2_ptr.add(i) != *src_ptr.add(i) { success = false; } + if *dst0_ptr.add(i) != *src_ptr.add(i) { + success = false; + } + if *dst1_ptr.add(i) != *src_ptr.add(i) { + success = false; + } + if *dst2_ptr.add(i) != *src_ptr.add(i) { + success = false; + } } } @@ -348,4 +373,3 @@ async fn main(_spawner: Spawner) { cortex_m::asm::wfe(); } } - diff --git a/examples/src/bin/dma_interleave_transfer.rs b/examples/src/bin/dma_interleave_transfer.rs index 949ea0605..c0ebb0a46 100644 --- a/examples/src/bin/dma_interleave_transfer.rs +++ b/examples/src/bin/dma_interleave_transfer.rs @@ -12,10 +12,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler}; -use embassy_mcxa::bind_interrupts; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind DMA channel 0 interrupt using Embassy-style macro @@ -125,22 +124,29 @@ async fn main(_spawner: Spawner) { // Reset channel state t.ch_csr().write(|w| { - w.erq().disable() - .earq().disable() - .eei().no_error() - .ebw().disable() - .done().clear_bit_by_one() + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() }); t.ch_es().write(|w| w.bits(0)); t.ch_int().write(|w| w.int().clear_bit_by_one()); // Source/destination addresses - t.tcd_saddr().write(|w| w.saddr().bits(core::ptr::addr_of_mut!(SRC_BUFFER) as u32)); - t.tcd_daddr().write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); + t.tcd_saddr() + .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(SRC_BUFFER) as u32)); + t.tcd_daddr() + .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); // Custom offsets for interleaving - t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read - t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write + t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read + t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write // Attributes: 32-bit transfers (size = 2) t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); @@ -153,7 +159,8 @@ async fn main(_spawner: Spawner) { t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32)); // Destination uses 2x offset, so adjust accordingly let dst_total = (HALF_BUFF_LENGTH * 8) as u32; - t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32)); + t.tcd_dlast_sga() + .write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32)); // Major loop count = 1 t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); @@ -172,7 +179,9 @@ async fn main(_spawner: Spawner) { while !dma_ch0.is_done() { cortex_m::asm::nop(); } - unsafe { dma_ch0.clear_done(); } + unsafe { + dma_ch0.clear_done(); + } tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") .unwrap(); @@ -206,4 +215,3 @@ async fn main(_spawner: Spawner) { cortex_m::asm::wfe(); } } - diff --git a/examples/src/bin/dma_mem_to_mem.rs b/examples/src/bin/dma_mem_to_mem.rs index 01e5edb1e..72916384f 100644 --- a/examples/src/bin/dma_mem_to_mem.rs +++ b/examples/src/bin/dma_mem_to_mem.rs @@ -15,10 +15,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, TransferOptions}; -use embassy_mcxa::bind_interrupts; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, TransferOptions}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind DMA channel 0 interrupt using Embassy-style macro @@ -147,8 +146,7 @@ async fn main(_spawner: Spawner) { transfer.await; } - tx.blocking_write(b"DMA mem-to-mem transfer complete!\r\n\r\n") - .unwrap(); + tx.blocking_write(b"DMA mem-to-mem transfer complete!\r\n\r\n").unwrap(); tx.blocking_write(b"Destination Buffer (after): ").unwrap(); print_buffer(&mut tx, &raw const DEST_BUFFER); tx.blocking_write(b"\r\n").unwrap(); @@ -181,7 +179,8 @@ async fn main(_spawner: Spawner) { // - Incrementing destination address // - Uses the same Transfer future pattern - tx.blocking_write(b"--- Demonstrating memset() feature ---\r\n\r\n").unwrap(); + tx.blocking_write(b"--- Demonstrating memset() feature ---\r\n\r\n") + .unwrap(); tx.blocking_write(b"Memset Buffer (before): ").unwrap(); print_buffer(&mut tx, &raw const MEMSET_BUFFER); @@ -230,4 +229,3 @@ async fn main(_spawner: Spawner) { cortex_m::asm::wfe(); } } - diff --git a/examples/src/bin/dma_memset.rs b/examples/src/bin/dma_memset.rs index 8a1636e57..9fbba85e9 100644 --- a/examples/src/bin/dma_memset.rs +++ b/examples/src/bin/dma_memset.rs @@ -12,10 +12,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler}; -use embassy_mcxa::bind_interrupts; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind DMA channel 0 interrupt using Embassy-style macro @@ -92,8 +91,7 @@ async fn main(_spawner: Spawner) { let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); let (mut tx, _rx) = lpuart.split(); - tx.blocking_write(b"EDMA memset example begin.\r\n\r\n") - .unwrap(); + tx.blocking_write(b"EDMA memset example begin.\r\n\r\n").unwrap(); // Initialize buffers unsafe { @@ -133,19 +131,26 @@ async fn main(_spawner: Spawner) { // Reset channel state t.ch_csr().write(|w| { - w.erq().disable() - .earq().disable() - .eei().no_error() - .ebw().disable() - .done().clear_bit_by_one() + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() }); t.ch_es().write(|w| w.bits(0)); t.ch_int().write(|w| w.int().clear_bit_by_one()); // Source address (pattern) - fixed - t.tcd_saddr().write(|w| w.saddr().bits(core::ptr::addr_of_mut!(PATTERN) as u32)); + t.tcd_saddr() + .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(PATTERN) as u32)); // Destination address - increments - t.tcd_daddr().write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); + t.tcd_daddr() + .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); // Source offset = 0 (stays fixed), Dest offset = 4 (increments) t.tcd_soff().write(|w| w.soff().bits(0)); @@ -180,10 +185,11 @@ async fn main(_spawner: Spawner) { while !dma_ch0.is_done() { cortex_m::asm::nop(); } - unsafe { dma_ch0.clear_done(); } + unsafe { + dma_ch0.clear_done(); + } - tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n") - .unwrap(); + tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n").unwrap(); tx.blocking_write(b"Destination Buffer (after): ").unwrap(); print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); tx.blocking_write(b"\r\n\r\n").unwrap(); @@ -212,4 +218,3 @@ async fn main(_spawner: Spawner) { cortex_m::asm::wfe(); } } - diff --git a/examples/src/bin/dma_ping_pong_transfer.rs b/examples/src/bin/dma_ping_pong_transfer.rs index d765ea575..692515441 100644 --- a/examples/src/bin/dma_ping_pong_transfer.rs +++ b/examples/src/bin/dma_ping_pong_transfer.rs @@ -24,12 +24,12 @@ #![no_main] use core::sync::atomic::{AtomicBool, Ordering}; + use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaChannel, DmaCh1InterruptHandler, Tcd, TransferOptions}; -use embassy_mcxa::bind_interrupts; +use embassy_mcxa::dma::{self, DmaCh1InterruptHandler, DmaChannel, Tcd, TransferOptions}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Source and destination buffers for Approach 1 (scatter/gather) @@ -44,19 +44,21 @@ static mut DST2: [u32; 8] = [0; 8]; #[repr(C, align(32))] struct TcdPool([Tcd; 2]); -static mut TCD_POOL: TcdPool = TcdPool([Tcd { - saddr: 0, - soff: 0, - attr: 0, - nbytes: 0, - slast: 0, - daddr: 0, - doff: 0, - citer: 0, - dlast_sga: 0, - csr: 0, - biter: 0, -}; 2]); +static mut TCD_POOL: TcdPool = TcdPool( + [Tcd { + saddr: 0, + soff: 0, + attr: 0, + nbytes: 0, + slast: 0, + daddr: 0, + doff: 0, + citer: 0, + dlast_sga: 0, + csr: 0, + biter: 0, + }; 2], +); // AtomicBool to track scatter/gather completion // Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, @@ -289,7 +291,8 @@ async fn main(_spawner: Spawner) { // - True async/await support // - Good for streaming data processing - tx.blocking_write(b"--- Approach 2: wait_half() demo ---\r\n\r\n").unwrap(); + tx.blocking_write(b"--- Approach 2: wait_half() demo ---\r\n\r\n") + .unwrap(); // Enable DMA CH1 interrupt unsafe { @@ -310,10 +313,11 @@ async fn main(_spawner: Spawner) { // Configure transfer with half-transfer interrupt enabled let mut options = TransferOptions::default(); - options.half_transfer_interrupt = true; // Enable half-transfer interrupt + options.half_transfer_interrupt = true; // Enable half-transfer interrupt options.complete_transfer_interrupt = true; - tx.blocking_write(b"Starting transfer with half_transfer_interrupt...\r\n").unwrap(); + tx.blocking_write(b"Starting transfer with half_transfer_interrupt...\r\n") + .unwrap(); unsafe { let src = &*core::ptr::addr_of!(SRC2); @@ -327,10 +331,12 @@ async fn main(_spawner: Spawner) { let half_ok = transfer.wait_half().await; if half_ok { - tx.blocking_write(b"Half-transfer complete! First half of DST2: ").unwrap(); + tx.blocking_write(b"Half-transfer complete! First half of DST2: ") + .unwrap(); print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b"(Processing first half while second half transfers...)\r\n").unwrap(); + tx.blocking_write(b"(Processing first half while second half transfers...)\r\n") + .unwrap(); } // Wait for complete transfer @@ -363,10 +369,10 @@ async fn main(_spawner: Spawner) { defmt::info!("PASS: Approach 2 verified."); } - tx.blocking_write(b"\r\n=== All ping-pong demos complete ===\r\n").unwrap(); + tx.blocking_write(b"\r\n=== All ping-pong demos complete ===\r\n") + .unwrap(); loop { cortex_m::asm::wfe(); } } - diff --git a/examples/src/bin/dma_scatter_gather.rs b/examples/src/bin/dma_scatter_gather.rs index d78605acc..b5ae00057 100644 --- a/examples/src/bin/dma_scatter_gather.rs +++ b/examples/src/bin/dma_scatter_gather.rs @@ -13,12 +13,12 @@ #![no_main] use core::sync::atomic::{AtomicBool, Ordering}; + use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; use embassy_mcxa::dma::{self, DmaChannel, Tcd}; -use embassy_mcxa::bind_interrupts; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Source and destination buffers @@ -29,19 +29,21 @@ static mut DST: [u32; 8] = [0; 8]; #[repr(C, align(32))] struct TcdPool([Tcd; 2]); -static mut TCD_POOL: TcdPool = TcdPool([Tcd { - saddr: 0, - soff: 0, - attr: 0, - nbytes: 0, - slast: 0, - daddr: 0, - doff: 0, - citer: 0, - dlast_sga: 0, - csr: 0, - biter: 0, -}; 2]); +static mut TCD_POOL: TcdPool = TcdPool( + [Tcd { + saddr: 0, + soff: 0, + attr: 0, + nbytes: 0, + slast: 0, + daddr: 0, + doff: 0, + citer: 0, + dlast_sga: 0, + csr: 0, + biter: 0, + }; 2], +); // AtomicBool to track scatter/gather completion // Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, @@ -53,7 +55,9 @@ static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); // (delegates to HAL + sets a flag) and the main task does the actual processing pub struct ScatterGatherDmaHandler; -impl embassy_mcxa::interrupt::typelevel::Handler for ScatterGatherDmaHandler { +impl embassy_mcxa::interrupt::typelevel::Handler + for ScatterGatherDmaHandler +{ unsafe fn on_interrupt() { // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers dma::on_interrupt(0); @@ -161,10 +165,7 @@ async fn main(_spawner: Spawner) { // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1. // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD. unsafe { - let tcds = core::slice::from_raw_parts_mut( - core::ptr::addr_of_mut!(TCD_POOL.0) as *mut Tcd, - 2, - ); + let tcds = core::slice::from_raw_parts_mut(core::ptr::addr_of_mut!(TCD_POOL.0) as *mut Tcd, 2); let src_ptr = core::ptr::addr_of!(SRC) as *const u32; let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; @@ -262,4 +263,3 @@ async fn main(_spawner: Spawner) { cortex_m::asm::wfe(); } } - diff --git a/examples/src/bin/dma_scatter_gather_builder.rs b/examples/src/bin/dma_scatter_gather_builder.rs index 51bfbeb67..d42ff841e 100644 --- a/examples/src/bin/dma_scatter_gather_builder.rs +++ b/examples/src/bin/dma_scatter_gather_builder.rs @@ -22,10 +22,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, ScatterGatherBuilder}; -use embassy_mcxa::bind_interrupts; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, ScatterGatherBuilder}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind DMA channel 0 interrupt @@ -97,7 +96,8 @@ async fn main(_spawner: Spawner) { let (mut tx, _rx) = lpuart.split(); tx.blocking_write(b"DMA Scatter-Gather Builder Example\r\n").unwrap(); - tx.blocking_write(b"===================================\r\n\r\n").unwrap(); + tx.blocking_write(b"===================================\r\n\r\n") + .unwrap(); // Show source buffers tx.blocking_write(b"Source buffers:\r\n").unwrap(); @@ -125,7 +125,8 @@ async fn main(_spawner: Spawner) { // Create DMA channel let dma_ch0 = DmaChannel::new(p.DMA_CH0); - tx.blocking_write(b"Building scatter-gather chain with builder API...\r\n").unwrap(); + tx.blocking_write(b"Building scatter-gather chain with builder API...\r\n") + .unwrap(); // ========================================================================= // ScatterGatherBuilder API demonstration @@ -159,7 +160,8 @@ async fn main(_spawner: Spawner) { } tx.blocking_write(b"Added 3 transfer segments to chain.\r\n").unwrap(); - tx.blocking_write(b"Starting scatter-gather transfer with .await...\r\n\r\n").unwrap(); + tx.blocking_write(b"Starting scatter-gather transfer with .await...\r\n\r\n") + .unwrap(); // Build and execute the scatter-gather chain // The build() method: @@ -222,7 +224,8 @@ async fn main(_spawner: Spawner) { defmt::error!("FAIL: Mismatch detected!"); } - tx.blocking_write(b"\r\n=== Scatter-Gather Builder example complete ===\r\n").unwrap(); + tx.blocking_write(b"\r\n=== Scatter-Gather Builder example complete ===\r\n") + .unwrap(); loop { cortex_m::asm::wfe(); diff --git a/examples/src/bin/dma_wrap_transfer.rs b/examples/src/bin/dma_wrap_transfer.rs index 8e9aedbfb..0babf4c20 100644 --- a/examples/src/bin/dma_wrap_transfer.rs +++ b/examples/src/bin/dma_wrap_transfer.rs @@ -12,10 +12,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler}; -use embassy_mcxa::bind_interrupts; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; +use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind DMA channel 0 interrupt using Embassy-style macro @@ -93,8 +92,7 @@ async fn main(_spawner: Spawner) { let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); let (mut tx, _rx) = lpuart.split(); - tx.blocking_write(b"EDMA wrap transfer example begin.\r\n\r\n") - .unwrap(); + tx.blocking_write(b"EDMA wrap transfer example begin.\r\n\r\n").unwrap(); // Initialize buffers unsafe { @@ -127,18 +125,25 @@ async fn main(_spawner: Spawner) { // Reset channel state t.ch_csr().write(|w| { - w.erq().disable() - .earq().disable() - .eei().no_error() - .ebw().disable() - .done().clear_bit_by_one() + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() }); t.ch_es().write(|w| w.bits(0)); t.ch_int().write(|w| w.int().clear_bit_by_one()); // Source/destination addresses - t.tcd_saddr().write(|w| w.saddr().bits(core::ptr::addr_of!(SRC.0) as u32)); - t.tcd_daddr().write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DST) as u32)); + t.tcd_saddr() + .write(|w| w.saddr().bits(core::ptr::addr_of!(SRC.0) as u32)); + t.tcd_daddr() + .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DST) as u32)); // Offsets: both increment by 4 bytes t.tcd_soff().write(|w| w.soff().bits(4)); @@ -147,10 +152,14 @@ async fn main(_spawner: Spawner) { // Attributes: 32-bit transfers (size = 2) // SMOD = 4 (2^4 = 16 byte modulo for source), DMOD = 0 (disabled) t.tcd_attr().write(|w| { - w.ssize().bits(2) - .dsize().bits(2) - .smod().bits(4) // Source modulo: 2^4 = 16 bytes - .dmod().bits(0) // Dest modulo: disabled + w.ssize() + .bits(2) + .dsize() + .bits(2) + .smod() + .bits(4) // Source modulo: 2^4 = 16 bytes + .dmod() + .bits(0) // Dest modulo: disabled }); // Transfer 32 bytes total in one minor loop @@ -179,7 +188,9 @@ async fn main(_spawner: Spawner) { while !dma_ch0.is_done() { cortex_m::asm::nop(); } - unsafe { dma_ch0.clear_done(); } + unsafe { + dma_ch0.clear_done(); + } tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n") .unwrap(); @@ -211,4 +222,3 @@ async fn main(_spawner: Spawner) { cortex_m::asm::wfe(); } } - diff --git a/examples/src/bin/lpuart_dma.rs b/examples/src/bin/lpuart_dma.rs index 4e321b111..f4dfbcf39 100644 --- a/examples/src/bin/lpuart_dma.rs +++ b/examples/src/bin/lpuart_dma.rs @@ -48,8 +48,7 @@ async fn main(_spawner: Spawner) { // Create UART instance with DMA channels let mut lpuart = LpuartDma::new( - p.LPUART2, - p.P2_2, // TX pin + p.LPUART2, p.P2_2, // TX pin p.P2_3, // RX pin p.DMA_CH0, // TX DMA channel p.DMA_CH1, // RX DMA channel @@ -82,4 +81,3 @@ async fn main(_spawner: Spawner) { defmt::info!("Example complete"); } - diff --git a/examples/src/bin/lpuart_ring_buffer.rs b/examples/src/bin/lpuart_ring_buffer.rs index d71876ade..6cc14f1c7 100644 --- a/examples/src/bin/lpuart_ring_buffer.rs +++ b/examples/src/bin/lpuart_ring_buffer.rs @@ -20,7 +20,7 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaChannel, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DMA_REQ_LPUART2_RX}; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaChannel, DMA_REQ_LPUART2_RX}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -91,7 +91,8 @@ async fn main(_spawner: Spawner) { dma_ch_rx.set_request_source(DMA_REQ_LPUART2_RX); } - tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n").unwrap(); + tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n") + .unwrap(); // Set up the ring buffer with circular DMA // This configures the DMA for continuous reception @@ -105,8 +106,10 @@ async fn main(_spawner: Spawner) { dma_ch_rx.enable_request(); } - tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n").unwrap(); - tx.blocking_write(b"The DMA continuously receives in the background.\r\n\r\n").unwrap(); + tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n") + .unwrap(); + tx.blocking_write(b"The DMA continuously receives in the background.\r\n\r\n") + .unwrap(); // Main loop: read from ring buffer and echo back let mut read_buf = [0u8; 16]; @@ -144,4 +147,3 @@ async fn main(_spawner: Spawner) { } } } - -- cgit From bc21f9b35e09fe9ef2556adf53f1d600af909d03 Mon Sep 17 00:00:00 2001 From: Bogdan Petru Chircu Mare Date: Mon, 1 Dec 2025 17:07:58 -0800 Subject: refactor(dma): move DMA_MAX_TRANSFER_SIZE to dma module and init during HAL startup Address felipebalbi's review comments on PR #52: - Move DMA_MAX_TRANSFER_SIZE constant from lpuart/mod.rs to dma.rs where it logically belongs (describes eDMA4 hardware limitation) - Add public dma::init() function called during hal::init() instead of lazy initialization via ensure_init() - Remove ensure_init() entirely since it's no longer needed - Remove ensure_init() calls from DmaChannel::new() and from_token() - Remove ensure_init() calls from examples (dma_channel_link, dma_scatter_gather) - Refactor lpuart_ring_buffer example to use LpuartDma::new() + split() pattern instead of separate TX/RX drivers - Add [lints.rust] section to suppress unexpected_cfgs warning for 'rt' feature used by embassy_hal_internal::interrupt_mod! macro This makes DMA initialization explicit during HAL startup (like GPIO) and keeps DMA-specific constants in the DMA module. --- examples/src/bin/dma_channel_link.rs | 5 ++- examples/src/bin/dma_scatter_gather.rs | 3 +- examples/src/bin/lpuart_ring_buffer.rs | 57 ++++++++++++---------------------- 3 files changed, 23 insertions(+), 42 deletions(-) (limited to 'examples') diff --git a/examples/src/bin/dma_channel_link.rs b/examples/src/bin/dma_channel_link.rs index 34162d931..361c9ebc7 100644 --- a/examples/src/bin/dma_channel_link.rs +++ b/examples/src/bin/dma_channel_link.rs @@ -18,7 +18,7 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler, DmaChannel}; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler, DmaChannel}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -85,8 +85,7 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA channel link example starting..."); - // Ensure DMA is initialized (clock/reset/init handled automatically by HAL) - dma::ensure_init(); + // DMA is initialized during hal::init() - no need to call ensure_init() let pac_periphs = unsafe { pac::Peripherals::steal() }; let dma0 = &pac_periphs.dma0; diff --git a/examples/src/bin/dma_scatter_gather.rs b/examples/src/bin/dma_scatter_gather.rs index b5ae00057..9844071b7 100644 --- a/examples/src/bin/dma_scatter_gather.rs +++ b/examples/src/bin/dma_scatter_gather.rs @@ -120,8 +120,7 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA scatter-gather transfer example starting..."); - // Ensure DMA is initialized (clock/reset/init handled automatically by HAL) - dma::ensure_init(); + // DMA is initialized during hal::init() - no need to call ensure_init() // Enable DMA interrupt unsafe { diff --git a/examples/src/bin/lpuart_ring_buffer.rs b/examples/src/bin/lpuart_ring_buffer.rs index 6cc14f1c7..0946bad03 100644 --- a/examples/src/bin/lpuart_ring_buffer.rs +++ b/examples/src/bin/lpuart_ring_buffer.rs @@ -1,18 +1,18 @@ //! LPUART Ring Buffer DMA example for MCXA276. //! -//! This example demonstrates using the new `RingBuffer` API for continuous -//! circular DMA reception from a UART peripheral. +//! This example demonstrates using the high-level `LpuartRxDma::setup_ring_buffer()` +//! API for continuous circular DMA reception from a UART peripheral. //! //! # Features demonstrated: -//! - `setup_circular_read()` for continuous peripheral-to-memory DMA +//! - `LpuartRxDma::setup_ring_buffer()` for continuous peripheral-to-memory DMA //! - `RingBuffer` for async reading of received data //! - Handling of potential overrun conditions //! - Half-transfer and complete-transfer interrupts for timely wakeups //! //! # How it works: -//! 1. Set up a circular DMA transfer from LPUART RX to a ring buffer -//! 2. DMA continuously writes received bytes into the buffer, wrapping around -//! 3. Application asynchronously reads data as it arrives +//! 1. Create an `LpuartRxDma` driver with a DMA channel +//! 2. Call `setup_ring_buffer()` which handles all low-level DMA configuration +//! 3. Application asynchronously reads data as it arrives via `ring_buf.read()` //! 4. Both half-transfer and complete-transfer interrupts wake the reader #![no_std] @@ -20,9 +20,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaChannel, DMA_REQ_LPUART2_RX}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; +use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; +use embassy_mcxa::bind_interrupts; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind DMA channel interrupts @@ -35,7 +35,10 @@ bind_interrupts!(struct Irqs { static mut RX_RING_BUFFER: [u8; 64] = [0; 64]; /// Helper to write a byte as hex to UART -fn write_hex(tx: &mut LpuartTx<'_, Blocking>, byte: u8) { +fn write_hex( + tx: &mut LpuartTxDma<'_, T, C>, + byte: u8, +) { const HEX: &[u8; 16] = b"0123456789ABCDEF"; let buf = [HEX[(byte >> 4) as usize], HEX[(byte & 0x0F) as usize]]; tx.blocking_write(&buf).ok(); @@ -55,12 +58,6 @@ async fn main(_spawner: Spawner) { defmt::info!("LPUART Ring Buffer DMA example starting..."); - // Enable DMA interrupts (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); - } - // Create UART configuration let config = Config { baudrate_bps: 115_200, @@ -69,41 +66,27 @@ async fn main(_spawner: Spawner) { ..Default::default() }; - // Create blocking UART for TX (we'll use DMA for RX only) - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); + // Create LPUART with DMA support for both TX and RX, then split + // This is the proper Embassy pattern - create once, split into TX and RX + let lpuart = LpuartDma::new(p.LPUART2, p.P2_2, p.P2_3, p.DMA_CH1, p.DMA_CH0, config).unwrap(); + let (mut tx, rx) = lpuart.split(); tx.blocking_write(b"LPUART Ring Buffer DMA Example\r\n").unwrap(); tx.blocking_write(b"==============================\r\n\r\n").unwrap(); - // Get LPUART2 RX data register address for DMA - let lpuart2 = unsafe { &*pac::Lpuart2::ptr() }; - let rx_data_addr = lpuart2.data().as_ptr() as *const u8; - - // Enable RX DMA request in LPUART - lpuart2.baud().modify(|_, w| w.rdmae().enabled()); - - // Create DMA channel for RX - let dma_ch_rx = DmaChannel::new(p.DMA_CH0); - - // Configure the DMA mux for LPUART2 RX - unsafe { - dma_ch_rx.set_request_source(DMA_REQ_LPUART2_RX); - } - tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n") .unwrap(); // Set up the ring buffer with circular DMA - // This configures the DMA for continuous reception + // The HAL handles: DMA request source, RDMAE enable, circular transfer config, NVIC enable let ring_buf = unsafe { let buf = &mut *core::ptr::addr_of_mut!(RX_RING_BUFFER); - dma_ch_rx.setup_circular_read(rx_data_addr, buf) + rx.setup_ring_buffer(buf) }; // Enable DMA requests to start continuous reception unsafe { - dma_ch_rx.enable_request(); + rx.enable_dma_request(); } tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n") -- cgit From df396688eb31da484db371632cb76ebf9143d8f7 Mon Sep 17 00:00:00 2001 From: 9names <60134748+9names@users.noreply.github.com> Date: Wed, 3 Dec 2025 22:19:40 +1100 Subject: docs: fix rp235x pio_i2s example comment --- examples/rp235x/src/bin/pio_i2s.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/rp235x/src/bin/pio_i2s.rs b/examples/rp235x/src/bin/pio_i2s.rs index cfcb0221d..7ed952a40 100644 --- a/examples/rp235x/src/bin/pio_i2s.rs +++ b/examples/rp235x/src/bin/pio_i2s.rs @@ -5,7 +5,7 @@ //! bclk : GPIO 18 //! lrc : GPIO 19 //! din : GPIO 20 -//! Then hold down the boot select button to trigger a rising triangle waveform. +//! Then short GPIO 0 to GND to trigger a rising triangle waveform. #![no_std] #![no_main] @@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) { // but don't await the returned future, yet let dma_future = i2s.write(front_buffer); - // fade in audio when bootsel is pressed + // fade in audio when GPIO 0 pin is shorted to GND let fade_target = if fade_input.is_low() { i32::MAX } else { 0 }; // fill back buffer with fresh audio samples before awaiting the dma future -- cgit From 8798306fb2c124efc06443c2913c3d7a4919dd83 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 3 Dec 2025 09:52:03 -0800 Subject: I2c Async (#50) * I2c Async Signed-off-by: Felipe Balbi * Fix i2c read bug Signed-off-by: Felipe Balbi * Introduce wait_for() Signed-off-by: Felipe Balbi * Review comments Signed-off-by: Felipe Balbi * more review comments Signed-off-by: Felipe Balbi * review comments Signed-off-by: Felipe Balbi * review comments Signed-off-by: Felipe Balbi * convert async fn to impl Future Signed-off-by: Felipe Balbi --------- Signed-off-by: Felipe Balbi Co-authored-by: Felipe Balbi --- examples/src/bin/i2c-async.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 examples/src/bin/i2c-async.rs (limited to 'examples') diff --git a/examples/src/bin/i2c-async.rs b/examples/src/bin/i2c-async.rs new file mode 100644 index 000000000..47b5f3cbe --- /dev/null +++ b/examples/src/bin/i2c-async.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::bind_interrupts; +use hal::clocks::config::Div8; +use hal::config::Config; +use hal::i2c::controller::{self, I2c, Speed}; +use hal::i2c::InterruptHandler; +use hal::peripherals::LPI2C3; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +bind_interrupts!( + struct Irqs { + LPI2C3 => InterruptHandler; + } +); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); + + defmt::info!("I2C example"); + + let mut config = controller::Config::default(); + config.speed = Speed::Standard; + let mut i2c = I2c::new_async(p.LPI2C3, p.P3_27, p.P3_28, Irqs, config).unwrap(); + let mut buf = [0u8; 2]; + + loop { + i2c.async_write_read(0x48, &[0x00], &mut buf).await.unwrap(); + defmt::info!("Buffer: {:02x}", buf); + Timer::after_secs(1).await; + } +} -- cgit From b9a89626a4121887c4c73551f169b279340b0a36 Mon Sep 17 00:00:00 2001 From: Cesar Tamayo Claro Date: Wed, 3 Dec 2025 15:26:36 -0700 Subject: Update blinky example logic --- examples/stm32wba6/src/bin/blinky.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32wba6/src/bin/blinky.rs b/examples/stm32wba6/src/bin/blinky.rs index 0d803b257..e490ad6eb 100644 --- a/examples/stm32wba6/src/bin/blinky.rs +++ b/examples/stm32wba6/src/bin/blinky.rs @@ -3,13 +3,41 @@ use defmt::*; use embassy_executor::Spawner; +use embassy_stm32::Config; use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::rcc::{ + AHB5Prescaler, AHBPrescaler, APBPrescaler, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, +}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let mut config = Config::default(); + // Fine-tune PLL1 dividers/multipliers + config.rcc.pll1 = Some(embassy_stm32::rcc::Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz + mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO + divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk) + // divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED) + divq: None, + divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG) + frac: Some(0), // Fractional part (enabled) + }); + + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.apb7_pre = APBPrescaler::DIV1; + config.rcc.ahb5_pre = AHB5Prescaler::DIV4; + + // voltage scale for max performance + config.rcc.voltage_scale = VoltageScale::RANGE1; + // route PLL1_P into the USB‐OTG‐HS block + config.rcc.sys = Sysclk::PLL1_R; + + let p = embassy_stm32::init(config); info!("Hello World!"); let mut led = Output::new(p.PB4, Level::High, Speed::Low); -- cgit From fab778e108814fae68e91c67e38c164b37075744 Mon Sep 17 00:00:00 2001 From: Cesar Tamayo Claro Date: Wed, 3 Dec 2025 15:39:26 -0700 Subject: Update LED pin number to PC4 --- examples/stm32wba6/src/bin/blinky.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32wba6/src/bin/blinky.rs b/examples/stm32wba6/src/bin/blinky.rs index e490ad6eb..95f3339b7 100644 --- a/examples/stm32wba6/src/bin/blinky.rs +++ b/examples/stm32wba6/src/bin/blinky.rs @@ -40,7 +40,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); info!("Hello World!"); - let mut led = Output::new(p.PB4, Level::High, Speed::Low); + // LD2 - PC4 + let mut led = Output::new(p.PC4, Level::High, Speed::Low); loop { info!("high"); -- cgit From 7c7f6ce38600b9fbc99a1a0129d00cc2dbcb8406 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 3 Dec 2025 18:15:52 -0600 Subject: wpan: refactor into wb55 --- examples/stm32wb/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 83119e3a0..83f7cb56b 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -26,8 +26,8 @@ static_cell = "2" [features] default = ["ble", "mac"] -mac = ["embassy-stm32-wpan/mac", "dep:embassy-net"] -ble = ["embassy-stm32-wpan/ble"] +mac = ["embassy-stm32-wpan/wb55_mac", "dep:embassy-net"] +ble = ["embassy-stm32-wpan/wb55_ble"] [[bin]] name = "tl_mbox_ble" -- cgit From 2e23e877148d5873ff4e995452325c97707fdfed Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 3 Dec 2025 18:24:55 -0600 Subject: stm32: add wpan dependency to wba examples --- examples/stm32wba/Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'examples') diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 3496b41b0..e071b24f0 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -7,6 +7,7 @@ publish = false [dependencies] embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba55cg", "time-driver-any", "memory-x", "exti"] } +embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wba55cg"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } @@ -22,6 +23,11 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } heapless = { version = "0.8", default-features = false } static_cell = "2" +[features] +default = ["ble", "mac"] +mac = ["embassy-stm32-wpan/wba_mac", "dep:embassy-net"] +ble = ["embassy-stm32-wpan/wba_ble"] + [profile.release] debug = 2 -- cgit From 22bae2d80153003af4637c4b0cc26d52858f5228 Mon Sep 17 00:00:00 2001 From: MathisDerooNXP <52401665+MathisDeroo@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:42:46 -0800 Subject: Rtc support v2 (#91) Signed-off-by: Mathis Deroo Signed-off-by: Felipe Balbi --- examples/src/bin/rtc_alarm.rs | 39 ++++++--------------------------------- 1 file changed, 6 insertions(+), 33 deletions(-) (limited to 'examples') diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs index a7800a2d1..fe355888b 100644 --- a/examples/src/bin/rtc_alarm.rs +++ b/examples/src/bin/rtc_alarm.rs @@ -2,23 +2,14 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa as hal; -use hal::rtc::{RtcDateTime, RtcInterruptEnable}; -use hal::InterruptExt; - -type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>; - use embassy_mcxa::bind_interrupts; -use {defmt_rtt as _, panic_probe as _}; +use hal::rtc::{InterruptHandler, Rtc, RtcDateTime}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; bind_interrupts!(struct Irqs { - RTC => hal::rtc::RtcHandler; + RTC => InterruptHandler; }); -#[used] -#[no_mangle] -static KEEP_RTC: unsafe extern "C" fn() = RTC; - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = hal::init(hal::config::Config::default()); @@ -27,7 +18,7 @@ async fn main(_spawner: Spawner) { let rtc_config = hal::rtc::get_default_config(); - let rtc = MyRtc::new(p.RTC0, rtc_config); + let mut rtc = Rtc::new(p.RTC0, Irqs, rtc_config); let now = RtcDateTime { year: 2025, @@ -46,29 +37,11 @@ async fn main(_spawner: Spawner) { let mut alarm = now; alarm.second += 10; - rtc.set_alarm(alarm); defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)"); - - rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); - - unsafe { - hal::interrupt::RTC.enable(); - } - - unsafe { - cortex_m::interrupt::enable(); - } - - rtc.start(); - defmt::info!("RTC started, waiting for alarm..."); - loop { - if rtc.is_alarm_triggered() { - defmt::info!("*** ALARM TRIGGERED! ***"); - break; - } - } + rtc.wait_for_alarm(alarm).await; + defmt::info!("*** ALARM TRIGGERED! ***"); defmt::info!("Example complete - Test PASSED!"); } -- cgit From dc6bf5d44675f6f2013ddfab6b14df25a996a965 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 4 Dec 2025 18:37:01 +0100 Subject: Move to subfolder --- examples/.cargo/config.toml | 17 - examples/.gitignore | 1 - examples/Cargo.lock | 1555 --------------------------------- examples/Cargo.toml | 26 - examples/build.rs | 20 - examples/memory.x | 5 - examples/src/bin/adc_interrupt.rs | 84 -- examples/src/bin/adc_polling.rs | 68 -- examples/src/bin/blinky.rs | 36 - examples/src/bin/button.rs | 23 - examples/src/bin/button_async.rs | 29 - examples/src/bin/clkout.rs | 69 -- examples/src/bin/hello.rs | 119 --- examples/src/bin/i2c-async.rs | 39 - examples/src/bin/i2c-blocking.rs | 31 - examples/src/bin/i2c-scan-blocking.rs | 41 - examples/src/bin/lpuart_buffered.rs | 62 -- examples/src/bin/lpuart_polling.rs | 47 - examples/src/bin/rtc_alarm.rs | 47 - examples/src/lib.rs | 16 - 20 files changed, 2335 deletions(-) delete mode 100644 examples/.cargo/config.toml delete mode 100644 examples/.gitignore delete mode 100644 examples/Cargo.lock delete mode 100644 examples/Cargo.toml delete mode 100644 examples/build.rs delete mode 100644 examples/memory.x delete mode 100644 examples/src/bin/adc_interrupt.rs delete mode 100644 examples/src/bin/adc_polling.rs delete mode 100644 examples/src/bin/blinky.rs delete mode 100644 examples/src/bin/button.rs delete mode 100644 examples/src/bin/button_async.rs delete mode 100644 examples/src/bin/clkout.rs delete mode 100644 examples/src/bin/hello.rs delete mode 100644 examples/src/bin/i2c-async.rs delete mode 100644 examples/src/bin/i2c-blocking.rs delete mode 100644 examples/src/bin/i2c-scan-blocking.rs delete mode 100644 examples/src/bin/lpuart_buffered.rs delete mode 100644 examples/src/bin/lpuart_polling.rs delete mode 100644 examples/src/bin/rtc_alarm.rs delete mode 100644 examples/src/lib.rs (limited to 'examples') diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml deleted file mode 100644 index aedc55b06..000000000 --- a/examples/.cargo/config.toml +++ /dev/null @@ -1,17 +0,0 @@ -[target.thumbv8m.main-none-eabihf] -runner = 'probe-rs run --chip MCXA276 --preverify --verify --protocol swd --speed 12000' - -rustflags = [ - "-C", "linker=flip-link", - "-C", "link-arg=-Tlink.x", - "-C", "link-arg=-Tdefmt.x", - # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x - # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 - "-C", "link-arg=--nmagic", -] - -[build] -target = "thumbv8m.main-none-eabihf" # Cortex-M33 - -[env] -DEFMT_LOG = "trace" diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/examples/Cargo.lock b/examples/Cargo.lock deleted file mode 100644 index c6e864df2..000000000 --- a/examples/Cargo.lock +++ /dev/null @@ -1,1555 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser", - "memchr", - "proc-macro2", - "quote", - "rustc-hash", - "syn 2.0.110", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "winnow 0.7.13", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.2.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cordyceps" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" -dependencies = [ - "loom", - "tracing", -] - -[[package]] -name = "cortex-m" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" -dependencies = [ - "bare-metal", - "bitfield", - "critical-section", - "embedded-hal 0.2.7", - "volatile-register", -] - -[[package]] -name = "cortex-m-rt" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" -dependencies = [ - "cortex-m-rt-macros", -] - -[[package]] -name = "cortex-m-rt-macros" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.110", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "dd-manifest-tree" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" -dependencies = [ - "toml", -] - -[[package]] -name = "defmt" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" -dependencies = [ - "bitflags 1.3.2", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" -dependencies = [ - "defmt-parser", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "defmt-parser" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" -dependencies = [ - "thiserror", -] - -[[package]] -name = "defmt-rtt" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e" -dependencies = [ - "critical-section", - "defmt", -] - -[[package]] -name = "device-driver" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" -dependencies = [ - "device-driver-macros", - "embedded-io", - "embedded-io-async", -] - -[[package]] -name = "device-driver-generation" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" -dependencies = [ - "anyhow", - "askama", - "bitvec", - "convert_case", - "dd-manifest-tree", - "itertools", - "kdl", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "device-driver-macros" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" -dependencies = [ - "device-driver-generation", - "proc-macro2", - "syn 2.0.110", -] - -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "embassy-embedded-hal" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" -dependencies = [ - "embassy-futures", - "embassy-hal-internal", - "embassy-sync", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-storage", - "embedded-storage-async", - "nb 1.1.0", -] - -[[package]] -name = "embassy-executor" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" -dependencies = [ - "cortex-m", - "critical-section", - "document-features", - "embassy-executor-macros", - "embassy-executor-timer-queue", -] - -[[package]] -name = "embassy-executor-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "embassy-executor-timer-queue" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" - -[[package]] -name = "embassy-futures" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" - -[[package]] -name = "embassy-hal-internal" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" -dependencies = [ - "cortex-m", - "critical-section", - "num-traits", -] - -[[package]] -name = "embassy-mcxa" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "embassy-embedded-hal", - "embassy-hal-internal", - "embassy-sync", - "embassy-time", - "embassy-time-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-hal-nb", - "embedded-io", - "embedded-io-async", - "heapless 0.8.0", - "maitake-sync", - "mcxa-pac", - "nb 1.1.0", - "paste", -] - -[[package]] -name = "embassy-mcxa-examples" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "defmt-rtt", - "embassy-embedded-hal", - "embassy-executor", - "embassy-mcxa", - "embassy-sync", - "embassy-time", - "embassy-time-driver", - "embedded-io-async", - "heapless 0.9.2", - "panic-probe", - "tmp108", -] - -[[package]] -name = "embassy-sync" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" -dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-core", - "futures-sink", - "heapless 0.8.0", -] - -[[package]] -name = "embassy-time" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" -dependencies = [ - "cfg-if", - "critical-section", - "document-features", - "embassy-time-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "futures-core", -] - -[[package]] -name = "embassy-time-driver" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" -dependencies = [ - "document-features", -] - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" -dependencies = [ - "embedded-hal 1.0.0", -] - -[[package]] -name = "embedded-hal-nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" -dependencies = [ - "embedded-hal 1.0.0", - "nb 1.1.0", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "embedded-io-async" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" -dependencies = [ - "embedded-io", -] - -[[package]] -name = "embedded-storage" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" - -[[package]] -name = "embedded-storage-async" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" -dependencies = [ - "embedded-storage", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "find-msvc-tools" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "generator" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" -dependencies = [ - "cc", - "cfg-if", - "libc", - "log", - "rustversion", - "windows", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "heapless" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" -dependencies = [ - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indexmap" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "kdl" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e" -dependencies = [ - "miette", - "num", - "winnow 0.6.24", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.177" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" - -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "maitake-sync" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" -dependencies = [ - "cordyceps", - "critical-section", - "loom", - "mutex-traits", - "mycelium-bitfield", - "pin-project", - "portable-atomic", - "tracing", -] - -[[package]] -name = "manyhow" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" -dependencies = [ - "manyhow-macros", - "proc-macro2", - "quote", - "syn 1.0.109", - "syn 2.0.110", -] - -[[package]] -name = "manyhow-macros" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" -dependencies = [ - "proc-macro-utils", - "proc-macro2", - "quote", -] - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "maybe-async-cfg" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627" -dependencies = [ - "manyhow", - "proc-macro2", - "pulldown-cmark", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "mcxa-pac" -version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "vcell", -] - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "cfg-if", - "unicode-width", -] - -[[package]] -name = "mutex-traits" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" - -[[package]] -name = "mycelium-bitfield" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc" - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "panic-probe" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a" -dependencies = [ - "cortex-m", - "defmt", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" -dependencies = [ - "critical-section", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "proc-macro-utils" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" -dependencies = [ - "proc-macro2", - "quote", - "smallvec", -] - -[[package]] -name = "proc-macro2" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pulldown-cmark" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" -dependencies = [ - "bitflags 2.10.0", - "memchr", - "unicase", -] - -[[package]] -name = "quote" -version = "1.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.110" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "tmp108" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d644cc97d3cee96793f454b834881f78b5d4e89c90ecf26b3690f42004d111" -dependencies = [ - "device-driver", - "embedded-hal 1.0.0", - "maybe-async-cfg", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow 0.7.13", -] - -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - -[[package]] -name = "tracing" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb41cbdb933e23b7929f47bb577710643157d7602ef3a2ebd3902b13ac5eda6" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "tracing-core" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" -dependencies = [ - "vcell", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core", - "windows-link 0.1.3", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core", - "windows-link 0.1.3", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] diff --git a/examples/Cargo.toml b/examples/Cargo.toml deleted file mode 100644 index a1092c416..000000000 --- a/examples/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "embassy-mcxa-examples" -version = "0.1.0" -edition = "2021" -license = "MIT OR Apache-2.0" - -[dependencies] -cortex-m = { version = "0.7", features = ["critical-section-single-core"] } -cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] } -critical-section = "1.2.0" -defmt = "1.0" -defmt-rtt = "1.0" -embassy-embedded-hal = "0.5.0" -embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } -embassy-mcxa = { path = "../", features = ["defmt", "unstable-pac", "time"] } -embassy-sync = "0.7.2" -embassy-time = "0.5.0" -embassy-time-driver = "0.2.1" -embedded-io-async = "0.6.1" -heapless = "0.9.2" -panic-probe = { version = "1.0", features = ["print-defmt"] } -tmp108 = "0.4.0" - -[profile.release] -lto = true # better optimizations -debug = 2 # enough information for defmt/rtt locations diff --git a/examples/build.rs b/examples/build.rs deleted file mode 100644 index f076bba9f..000000000 --- a/examples/build.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -fn main() { - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - - // Generate memory.x - put "FLASH" at start of RAM, RAM after "FLASH" - // cortex-m-rt expects FLASH for code, RAM for data/bss/stack - // Both are in RAM, but separated to satisfy cortex-m-rt's expectations - // MCXA256 has 128KB RAM total - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - - println!("cargo:rustc-link-search={}", out.display()); - println!("cargo:rerun-if-changed=memory.x"); -} diff --git a/examples/memory.x b/examples/memory.x deleted file mode 100644 index 315ced58a..000000000 --- a/examples/memory.x +++ /dev/null @@ -1,5 +0,0 @@ -MEMORY -{ - FLASH : ORIGIN = 0x00000000, LENGTH = 1M - RAM : ORIGIN = 0x20000000, LENGTH = 128K -} diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs deleted file mode 100644 index 83d8046b3..000000000 --- a/examples/src/bin/adc_interrupt.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa_examples::init_adc_pins; -use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::periph_helpers::{AdcClockSel, Div4}; -use hal::clocks::PoweredClock; -use hal::pac::adc1::cfg::{Pwrsel, Refsel}; -use hal::pac::adc1::cmdl1::{Adch, Mode}; -use hal::pac::adc1::ctrl::CalAvgs; -use hal::pac::adc1::tctrl::Tcmd; -use hal::{bind_interrupts, InterruptExt}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -bind_interrupts!(struct Irqs { - ADC1 => hal::adc::AdcHandler; -}); - -#[used] -#[no_mangle] -static KEEP_ADC: unsafe extern "C" fn() = ADC1; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("ADC interrupt Example"); - - unsafe { - init_adc_pins(); - } - - let adc_config = LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::Average128, - enable_analog_preliminary: true, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option3, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, - power: PoweredClock::NormalEnabledDeepSleepDisabled, - source: AdcClockSel::FroLfDiv, - div: Div4::no_div(), - }; - let adc = hal::adc::Adc::::new(p.ADC1, adc_config); - - adc.do_offset_calibration(); - adc.do_auto_calibration(); - - let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits; - adc.set_conv_command_config(1, &conv_command_config); - - let mut conv_trigger_config = adc.get_default_conv_trigger_config(); - conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; - conv_trigger_config.enable_hardware_trigger = false; - adc.set_conv_trigger_config(0, &conv_trigger_config); - - defmt::info!("ADC configuration done..."); - - adc.enable_interrupt(0x1); - - unsafe { - hal::interrupt::ADC1.enable(); - } - - unsafe { - cortex_m::interrupt::enable(); - } - - loop { - adc.do_software_trigger(1); - while !adc.is_interrupt_triggered() { - // Wait until the interrupt is triggered - } - defmt::info!("*** ADC interrupt TRIGGERED! ***"); - //TBD need to print the value - } -} diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs deleted file mode 100644 index ddf3f586b..000000000 --- a/examples/src/bin/adc_polling.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa_examples::init_adc_pins; -use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::periph_helpers::{AdcClockSel, Div4}; -use hal::clocks::PoweredClock; -use hal::pac::adc1::cfg::{Pwrsel, Refsel}; -use hal::pac::adc1::cmdl1::{Adch, Mode}; -use hal::pac::adc1::ctrl::CalAvgs; -use hal::pac::adc1::tctrl::Tcmd; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -const G_LPADC_RESULT_SHIFT: u32 = 0; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - unsafe { - init_adc_pins(); - } - - defmt::info!("=== ADC polling Example ==="); - - let adc_config = LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::Average128, - enable_analog_preliminary: true, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option3, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, - power: PoweredClock::NormalEnabledDeepSleepDisabled, - source: AdcClockSel::FroLfDiv, - div: Div4::no_div(), - }; - let adc = hal::adc::Adc::::new(p.ADC1, adc_config); - - adc.do_offset_calibration(); - adc.do_auto_calibration(); - - let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits; - adc.set_conv_command_config(1, &conv_command_config); - - let mut conv_trigger_config = adc.get_default_conv_trigger_config(); - conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; - conv_trigger_config.enable_hardware_trigger = false; - adc.set_conv_trigger_config(0, &conv_trigger_config); - - defmt::info!("=== ADC configuration done... ==="); - - loop { - adc.do_software_trigger(1); - let mut result: Option = None; - while result.is_none() { - result = hal::adc::get_conv_result(); - } - let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; - defmt::info!("value: {=u16}", value); - } -} diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs deleted file mode 100644 index dd08ec0d9..000000000 --- a/examples/src/bin/blinky.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::gpio::{DriveStrength, Level, Output, SlewRate}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("Blink example"); - - let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast); - let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast); - let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast); - - loop { - defmt::info!("Toggle LEDs"); - - red.toggle(); - Timer::after_millis(250).await; - - red.toggle(); - green.toggle(); - Timer::after_millis(250).await; - - green.toggle(); - blue.toggle(); - Timer::after_millis(250).await; - blue.toggle(); - - Timer::after_millis(250).await; - } -} diff --git a/examples/src/bin/button.rs b/examples/src/bin/button.rs deleted file mode 100644 index 943edbb15..000000000 --- a/examples/src/bin/button.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::gpio::{Input, Pull}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("Button example"); - - // This button is labeled "WAKEUP" on the FRDM-MCXA276 - // The board already has a 10K pullup - let monitor = Input::new(p.P1_7, Pull::Disabled); - - loop { - defmt::info!("Pin level is {:?}", monitor.get_level()); - Timer::after_millis(1000).await; - } -} diff --git a/examples/src/bin/button_async.rs b/examples/src/bin/button_async.rs deleted file mode 100644 index 6cc7b62cd..000000000 --- a/examples/src/bin/button_async.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::gpio::{Input, Pull}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("GPIO interrupt example"); - - // This button is labeled "WAKEUP" on the FRDM-MCXA276 - // The board already has a 10K pullup - let mut pin = Input::new(p.P1_7, Pull::Disabled); - - let mut press_count = 0u32; - - loop { - pin.wait_for_falling_edge().await; - - press_count += 1; - - defmt::info!("Button pressed! Count: {}", press_count); - Timer::after_millis(50).await; - } -} diff --git a/examples/src/bin/clkout.rs b/examples/src/bin/clkout.rs deleted file mode 100644 index bfd963540..000000000 --- a/examples/src/bin/clkout.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4}; -use embassy_mcxa::clocks::PoweredClock; -use embassy_mcxa::gpio::{DriveStrength, SlewRate}; -use embassy_mcxa::{Level, Output}; -use embassy_time::Timer; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -/// Demonstrate CLKOUT, using Pin P4.2 -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - let mut pin = p.P4_2; - let mut clkout = p.CLKOUT; - - loop { - defmt::info!("Set Low..."); - let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); - Timer::after_millis(500).await; - - defmt::info!("Set High..."); - output.set_high(); - Timer::after_millis(400).await; - - defmt::info!("Set Low..."); - output.set_low(); - Timer::after_millis(500).await; - - defmt::info!("16k..."); - // Run Clock Out with the 16K clock - let _clock_out = ClockOut::new( - clkout.reborrow(), - pin.reborrow(), - Config { - sel: ClockOutSel::Clk16K, - div: Div4::no_div(), - level: PoweredClock::NormalEnabledDeepSleepDisabled, - }, - ) - .unwrap(); - - Timer::after_millis(3000).await; - - defmt::info!("Set Low..."); - drop(_clock_out); - - let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); - Timer::after_millis(500).await; - - // Run Clock Out with the 12M clock, divided by 3 - defmt::info!("4M..."); - let _clock_out = ClockOut::new( - clkout.reborrow(), - pin.reborrow(), - Config { - sel: ClockOutSel::Fro12M, - div: const { Div4::from_divisor(3).unwrap() }, - level: PoweredClock::NormalEnabledDeepSleepDisabled, - }, - ) - .unwrap(); - - // Let it run for 3 seconds... - Timer::after_millis(3000).await; - } -} diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs deleted file mode 100644 index e371d9413..000000000 --- a/examples/src/bin/hello.rs +++ /dev/null @@ -1,119 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use hal::lpuart::{Blocking, Config, Lpuart}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -/// Simple helper to write a byte as hex to UART -fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) { - const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; - let _ = uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); - let _ = uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - 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!("boot"); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - - // Print welcome message before any async delays to guarantee early console output - uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); - uart.write_str_blocking("Available commands:\r\n"); - uart.write_str_blocking(" help - Show this help\r\n"); - uart.write_str_blocking(" echo - Echo back the text\r\n"); - uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); - uart.write_str_blocking("Type a command: "); - - let mut buffer = [0u8; 64]; - let mut buf_idx = 0; - - loop { - // Read a byte from UART - let byte = uart.read_byte_blocking(); - - // Echo the character back - if byte == b'\r' || byte == b'\n' { - // Enter pressed - process command - uart.write_str_blocking("\r\n"); - - if buf_idx > 0 { - let command = &buffer[0..buf_idx]; - - if command == b"help" { - uart.write_str_blocking("Available commands:\r\n"); - uart.write_str_blocking(" help - Show this help\r\n"); - uart.write_str_blocking(" echo - Echo back the text\r\n"); - uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); - } else if command.starts_with(b"echo ") && command.len() > 5 { - uart.write_str_blocking("Echo: "); - uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or("")); - uart.write_str_blocking("\r\n"); - } else if command.starts_with(b"hex ") && command.len() > 4 { - // Parse the byte value - let num_str = &command[4..]; - if let Ok(num) = parse_u8(num_str) { - uart.write_str_blocking("Hex: 0x"); - write_hex_byte(&mut uart, num); - uart.write_str_blocking("\r\n"); - } else { - uart.write_str_blocking("Invalid number for hex command\r\n"); - } - } else if !command.is_empty() { - uart.write_str_blocking("Unknown command: "); - uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); - uart.write_str_blocking("\r\n"); - } - } - - // Reset buffer and prompt - buf_idx = 0; - uart.write_str_blocking("Type a command: "); - } else if byte == 8 || byte == 127 { - // Backspace - if buf_idx > 0 { - buf_idx -= 1; - uart.write_str_blocking("\x08 \x08"); // Erase character - } - } else if buf_idx < buffer.len() - 1 { - // Regular character - buffer[buf_idx] = byte; - buf_idx += 1; - let _ = uart.write_byte(byte); - } - } -} - -/// Simple parser for u8 from ASCII bytes -fn parse_u8(bytes: &[u8]) -> Result { - let mut result = 0u8; - for &b in bytes { - if b.is_ascii_digit() { - result = result.checked_mul(10).ok_or(())?; - result = result.checked_add(b - b'0').ok_or(())?; - } else { - return Err(()); - } - } - Ok(result) -} diff --git a/examples/src/bin/i2c-async.rs b/examples/src/bin/i2c-async.rs deleted file mode 100644 index 47b5f3cbe..000000000 --- a/examples/src/bin/i2c-async.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::bind_interrupts; -use hal::clocks::config::Div8; -use hal::config::Config; -use hal::i2c::controller::{self, I2c, Speed}; -use hal::i2c::InterruptHandler; -use hal::peripherals::LPI2C3; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -bind_interrupts!( - struct Irqs { - LPI2C3 => InterruptHandler; - } -); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let mut config = Config::default(); - config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); - - let p = hal::init(config); - - defmt::info!("I2C example"); - - let mut config = controller::Config::default(); - config.speed = Speed::Standard; - let mut i2c = I2c::new_async(p.LPI2C3, p.P3_27, p.P3_28, Irqs, config).unwrap(); - let mut buf = [0u8; 2]; - - loop { - i2c.async_write_read(0x48, &[0x00], &mut buf).await.unwrap(); - defmt::info!("Buffer: {:02x}", buf); - Timer::after_secs(1).await; - } -} diff --git a/examples/src/bin/i2c-blocking.rs b/examples/src/bin/i2c-blocking.rs deleted file mode 100644 index 0f6c8cbae..000000000 --- a/examples/src/bin/i2c-blocking.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::clocks::config::Div8; -use hal::config::Config; -use hal::i2c::controller::{self, I2c, Speed}; -use tmp108::Tmp108; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let mut config = Config::default(); - config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); - - let p = hal::init(config); - - defmt::info!("I2C example"); - - let mut config = controller::Config::default(); - config.speed = Speed::Standard; - let i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap(); - let mut tmp = Tmp108::new_with_a0_gnd(i2c); - - loop { - let temperature = tmp.temperature().unwrap(); - defmt::info!("Temperature: {}C", temperature); - Timer::after_secs(1).await; - } -} diff --git a/examples/src/bin/i2c-scan-blocking.rs b/examples/src/bin/i2c-scan-blocking.rs deleted file mode 100644 index 4e203597b..000000000 --- a/examples/src/bin/i2c-scan-blocking.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::gpio::Pull; -use embassy_mcxa::Input; -use embassy_time::Timer; -use hal::clocks::config::Div8; -use hal::config::Config; -use hal::i2c::controller::{self, I2c, Speed}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let mut config = Config::default(); - config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); - - let p = hal::init(config); - - defmt::info!("I2C example"); - - let mut config = controller::Config::default(); - config.speed = Speed::Standard; - - // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and - // defaults to SWO on the debug peripheral. Explicitly make it a high-z - // input. - let _pin = Input::new(p.P0_2, Pull::Disabled); - let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap(); - - for addr in 0x01..=0x7f { - let result = i2c.blocking_write(addr, &[]); - if result.is_ok() { - defmt::info!("Device found at addr {:02x}", addr); - } - } - - loop { - Timer::after_secs(10).await; - } -} diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs deleted file mode 100644 index 420589d00..000000000 --- a/examples/src/bin/lpuart_buffered.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::lpuart::buffered::BufferedLpuart; -use embassy_mcxa::lpuart::Config; -use embassy_mcxa::{bind_interrupts, lpuart}; -use embedded_io_async::Write; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver -bind_interrupts!(struct Irqs { - LPUART2 => lpuart::buffered::BufferedInterruptHandler::; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - 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); - - // Configure NVIC for LPUART2 - hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); - - // UART configuration (enable both TX and RX) - let config = Config { - baudrate_bps: 115_200, - rx_fifo_watermark: 0, - tx_fifo_watermark: 0, - ..Default::default() - }; - - let mut tx_buf = [0u8; 256]; - let mut rx_buf = [0u8; 256]; - - // Create a buffered LPUART2 instance with both TX and RX - let mut uart = BufferedLpuart::new( - p.LPUART2, - p.P2_2, // TX pin - p.P2_3, // RX pin - Irqs, - &mut tx_buf, - &mut rx_buf, - config, - ) - .unwrap(); - - // Split into TX and RX parts - let (tx, rx) = uart.split_ref(); - - tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); - tx.write(b"Type characters to echo them back.\r\n").await.unwrap(); - - // Echo loop - let mut buf = [0u8; 4]; - loop { - let used = rx.read(&mut buf).await.unwrap(); - tx.write_all(&buf[..used]).await.unwrap(); - } -} diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs deleted file mode 100644 index b80668834..000000000 --- a/examples/src/bin/lpuart_polling.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -use crate::hal::lpuart::{Config, Lpuart}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - 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!("boot"); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - let lpuart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - - // Split into separate TX and RX parts - let (mut tx, mut rx) = lpuart.split(); - - // Write hello messages - tx.blocking_write(b"Hello world.\r\n").unwrap(); - tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap(); - - // Echo loop - loop { - let mut buf = [0u8; 1]; - rx.blocking_read(&mut buf).unwrap(); - tx.blocking_write(&buf).unwrap(); - } -} diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs deleted file mode 100644 index fe355888b..000000000 --- a/examples/src/bin/rtc_alarm.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::bind_interrupts; -use hal::rtc::{InterruptHandler, Rtc, RtcDateTime}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -bind_interrupts!(struct Irqs { - RTC => InterruptHandler; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("=== RTC Alarm Example ==="); - - let rtc_config = hal::rtc::get_default_config(); - - let mut rtc = Rtc::new(p.RTC0, Irqs, rtc_config); - - let now = RtcDateTime { - year: 2025, - month: 10, - day: 15, - hour: 14, - minute: 30, - second: 0, - }; - - rtc.stop(); - - defmt::info!("Time set to: 2025-10-15 14:30:00"); - rtc.set_datetime(now); - - let mut alarm = now; - alarm.second += 10; - - defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)"); - defmt::info!("RTC started, waiting for alarm..."); - - rtc.wait_for_alarm(alarm).await; - defmt::info!("*** ALARM TRIGGERED! ***"); - - defmt::info!("Example complete - Test PASSED!"); -} diff --git a/examples/src/lib.rs b/examples/src/lib.rs deleted file mode 100644 index 2573a6adc..000000000 --- a/examples/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_std] -#![allow(clippy::missing_safety_doc)] - -//! Shared board-specific helpers for the FRDM-MCXA276 examples. -//! These live with the examples so the HAL stays generic. - -use hal::{clocks, pins}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -/// Initialize clocks and pin muxing for ADC. -pub unsafe fn init_adc_pins() { - // NOTE: Lpuart has been updated to properly enable + reset its own clocks. - // GPIO has not. - _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); - pins::configure_adc_pins(); -} -- cgit From 277ab0d2e8714edf37a0ee84cda1059d9944ecef Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 4 Dec 2025 18:41:46 +0100 Subject: Move examples to top level example folder --- examples/mcxa/.cargo/config.toml | 17 + examples/mcxa/.gitignore | 1 + examples/mcxa/Cargo.lock | 1555 ++++++++++++++++++++++++++++ examples/mcxa/Cargo.toml | 26 + examples/mcxa/build.rs | 20 + examples/mcxa/memory.x | 5 + examples/mcxa/src/bin/adc_interrupt.rs | 84 ++ examples/mcxa/src/bin/adc_polling.rs | 68 ++ examples/mcxa/src/bin/blinky.rs | 36 + examples/mcxa/src/bin/button.rs | 23 + examples/mcxa/src/bin/button_async.rs | 29 + examples/mcxa/src/bin/clkout.rs | 69 ++ examples/mcxa/src/bin/hello.rs | 119 +++ examples/mcxa/src/bin/i2c-async.rs | 39 + examples/mcxa/src/bin/i2c-blocking.rs | 31 + examples/mcxa/src/bin/i2c-scan-blocking.rs | 41 + examples/mcxa/src/bin/lpuart_buffered.rs | 62 ++ examples/mcxa/src/bin/lpuart_polling.rs | 47 + examples/mcxa/src/bin/rtc_alarm.rs | 47 + examples/mcxa/src/lib.rs | 16 + 20 files changed, 2335 insertions(+) create mode 100644 examples/mcxa/.cargo/config.toml create mode 100644 examples/mcxa/.gitignore create mode 100644 examples/mcxa/Cargo.lock create mode 100644 examples/mcxa/Cargo.toml create mode 100644 examples/mcxa/build.rs create mode 100644 examples/mcxa/memory.x create mode 100644 examples/mcxa/src/bin/adc_interrupt.rs create mode 100644 examples/mcxa/src/bin/adc_polling.rs create mode 100644 examples/mcxa/src/bin/blinky.rs create mode 100644 examples/mcxa/src/bin/button.rs create mode 100644 examples/mcxa/src/bin/button_async.rs create mode 100644 examples/mcxa/src/bin/clkout.rs create mode 100644 examples/mcxa/src/bin/hello.rs create mode 100644 examples/mcxa/src/bin/i2c-async.rs create mode 100644 examples/mcxa/src/bin/i2c-blocking.rs create mode 100644 examples/mcxa/src/bin/i2c-scan-blocking.rs create mode 100644 examples/mcxa/src/bin/lpuart_buffered.rs create mode 100644 examples/mcxa/src/bin/lpuart_polling.rs create mode 100644 examples/mcxa/src/bin/rtc_alarm.rs create mode 100644 examples/mcxa/src/lib.rs (limited to 'examples') diff --git a/examples/mcxa/.cargo/config.toml b/examples/mcxa/.cargo/config.toml new file mode 100644 index 000000000..aedc55b06 --- /dev/null +++ b/examples/mcxa/.cargo/config.toml @@ -0,0 +1,17 @@ +[target.thumbv8m.main-none-eabihf] +runner = 'probe-rs run --chip MCXA276 --preverify --verify --protocol swd --speed 12000' + +rustflags = [ + "-C", "linker=flip-link", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x + # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + "-C", "link-arg=--nmagic", +] + +[build] +target = "thumbv8m.main-none-eabihf" # Cortex-M33 + +[env] +DEFMT_LOG = "trace" diff --git a/examples/mcxa/.gitignore b/examples/mcxa/.gitignore new file mode 100644 index 000000000..2f7896d1d --- /dev/null +++ b/examples/mcxa/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/examples/mcxa/Cargo.lock b/examples/mcxa/Cargo.lock new file mode 100644 index 000000000..c6e864df2 --- /dev/null +++ b/examples/mcxa/Cargo.lock @@ -0,0 +1,1555 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "askama" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" +dependencies = [ + "askama_parser", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "syn 2.0.110", +] + +[[package]] +name = "askama_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" +dependencies = [ + "memchr", + "winnow 0.7.13", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.2.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cordyceps" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" +dependencies = [ + "loom", + "tracing", +] + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.110", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "dd-manifest-tree" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" +dependencies = [ + "toml", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "defmt-rtt" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e" +dependencies = [ + "critical-section", + "defmt", +] + +[[package]] +name = "device-driver" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" +dependencies = [ + "device-driver-macros", + "embedded-io", + "embedded-io-async", +] + +[[package]] +name = "device-driver-generation" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" +dependencies = [ + "anyhow", + "askama", + "bitvec", + "convert_case", + "dd-manifest-tree", + "itertools", + "kdl", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "device-driver-macros" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" +dependencies = [ + "device-driver-generation", + "proc-macro2", + "syn 2.0.110", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "embassy-embedded-hal" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" +dependencies = [ + "embassy-futures", + "embassy-hal-internal", + "embassy-sync", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-executor" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" +dependencies = [ + "cortex-m", + "critical-section", + "document-features", + "embassy-executor-macros", + "embassy-executor-timer-queue", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "embassy-executor-timer-queue" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" + +[[package]] +name = "embassy-futures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" + +[[package]] +name = "embassy-hal-internal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" +dependencies = [ + "cortex-m", + "critical-section", + "num-traits", +] + +[[package]] +name = "embassy-mcxa" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt", + "embassy-embedded-hal", + "embassy-hal-internal", + "embassy-sync", + "embassy-time", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-nb", + "embedded-io", + "embedded-io-async", + "heapless 0.8.0", + "maitake-sync", + "mcxa-pac", + "nb 1.1.0", + "paste", +] + +[[package]] +name = "embassy-mcxa-examples" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt", + "defmt-rtt", + "embassy-embedded-hal", + "embassy-executor", + "embassy-mcxa", + "embassy-sync", + "embassy-time", + "embassy-time-driver", + "embedded-io-async", + "heapless 0.9.2", + "panic-probe", + "tmp108", +] + +[[package]] +name = "embassy-sync" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-core", + "futures-sink", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-time" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-core", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" +dependencies = [ + "document-features", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal 1.0.0", + "nb 1.1.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "embedded-io-async" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] +name = "embedded-storage-async" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" +dependencies = [ + "embedded-storage", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "generator" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heapless" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "kdl" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e" +dependencies = [ + "miette", + "num", + "winnow 0.6.24", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "maitake-sync" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" +dependencies = [ + "cordyceps", + "critical-section", + "loom", + "mutex-traits", + "mycelium-bitfield", + "pin-project", + "portable-atomic", + "tracing", +] + +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn 1.0.109", + "syn 2.0.110", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "maybe-async-cfg" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627" +dependencies = [ + "manyhow", + "proc-macro2", + "pulldown-cmark", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "mcxa-pac" +version = "0.1.0" +source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt", + "vcell", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "cfg-if", + "unicode-width", +] + +[[package]] +name = "mutex-traits" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" + +[[package]] +name = "mycelium-bitfield" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc" + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "panic-probe" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a" +dependencies = [ + "cortex-m", + "defmt", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +dependencies = [ + "critical-section", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulldown-cmark" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" +dependencies = [ + "bitflags 2.10.0", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tmp108" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d644cc97d3cee96793f454b834881f78b5d4e89c90ecf26b3690f42004d111" +dependencies = [ + "device-driver", + "embedded-hal 1.0.0", + "maybe-async-cfg", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow 0.7.13", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tracing" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb41cbdb933e23b7929f47bb577710643157d7602ef3a2ebd3902b13ac5eda6" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "tracing-core" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "winnow" +version = "0.6.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml new file mode 100644 index 000000000..4da94811f --- /dev/null +++ b/examples/mcxa/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "embassy-mcxa-examples" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } +cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] } +critical-section = "1.2.0" +defmt = "1.0" +defmt-rtt = "1.0" +embassy-embedded-hal = "0.5.0" +embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } +embassy-mcxa = { path = "../../embassy-mcxa", features = ["defmt", "unstable-pac", "time"] } +embassy-sync = "0.7.2" +embassy-time = "0.5.0" +embassy-time-driver = "0.2.1" +embedded-io-async = "0.6.1" +heapless = "0.9.2" +panic-probe = { version = "1.0", features = ["print-defmt"] } +tmp108 = "0.4.0" + +[profile.release] +lto = true # better optimizations +debug = 2 # enough information for defmt/rtt locations diff --git a/examples/mcxa/build.rs b/examples/mcxa/build.rs new file mode 100644 index 000000000..f076bba9f --- /dev/null +++ b/examples/mcxa/build.rs @@ -0,0 +1,20 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + // Generate memory.x - put "FLASH" at start of RAM, RAM after "FLASH" + // cortex-m-rt expects FLASH for code, RAM for data/bss/stack + // Both are in RAM, but separated to satisfy cortex-m-rt's expectations + // MCXA256 has 128KB RAM total + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/examples/mcxa/memory.x b/examples/mcxa/memory.x new file mode 100644 index 000000000..315ced58a --- /dev/null +++ b/examples/mcxa/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 1M + RAM : ORIGIN = 0x20000000, LENGTH = 128K +} diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs new file mode 100644 index 000000000..83d8046b3 --- /dev/null +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -0,0 +1,84 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa_examples::init_adc_pins; +use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; +use hal::clocks::periph_helpers::{AdcClockSel, Div4}; +use hal::clocks::PoweredClock; +use hal::pac::adc1::cfg::{Pwrsel, Refsel}; +use hal::pac::adc1::cmdl1::{Adch, Mode}; +use hal::pac::adc1::ctrl::CalAvgs; +use hal::pac::adc1::tctrl::Tcmd; +use hal::{bind_interrupts, InterruptExt}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ADC1 => hal::adc::AdcHandler; +}); + +#[used] +#[no_mangle] +static KEEP_ADC: unsafe extern "C" fn() = ADC1; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("ADC interrupt Example"); + + unsafe { + init_adc_pins(); + } + + let adc_config = LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: AdcClockSel::FroLfDiv, + div: Div4::no_div(), + }; + let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + + adc.do_offset_calibration(); + adc.do_auto_calibration(); + + let mut conv_command_config = adc.get_default_conv_command_config(); + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + adc.set_conv_command_config(1, &conv_command_config); + + let mut conv_trigger_config = adc.get_default_conv_trigger_config(); + conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; + conv_trigger_config.enable_hardware_trigger = false; + adc.set_conv_trigger_config(0, &conv_trigger_config); + + defmt::info!("ADC configuration done..."); + + adc.enable_interrupt(0x1); + + unsafe { + hal::interrupt::ADC1.enable(); + } + + unsafe { + cortex_m::interrupt::enable(); + } + + loop { + adc.do_software_trigger(1); + while !adc.is_interrupt_triggered() { + // Wait until the interrupt is triggered + } + defmt::info!("*** ADC interrupt TRIGGERED! ***"); + //TBD need to print the value + } +} diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs new file mode 100644 index 000000000..ddf3f586b --- /dev/null +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa_examples::init_adc_pins; +use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; +use hal::clocks::periph_helpers::{AdcClockSel, Div4}; +use hal::clocks::PoweredClock; +use hal::pac::adc1::cfg::{Pwrsel, Refsel}; +use hal::pac::adc1::cmdl1::{Adch, Mode}; +use hal::pac::adc1::ctrl::CalAvgs; +use hal::pac::adc1::tctrl::Tcmd; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +const G_LPADC_RESULT_SHIFT: u32 = 0; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + unsafe { + init_adc_pins(); + } + + defmt::info!("=== ADC polling Example ==="); + + let adc_config = LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: AdcClockSel::FroLfDiv, + div: Div4::no_div(), + }; + let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + + adc.do_offset_calibration(); + adc.do_auto_calibration(); + + let mut conv_command_config = adc.get_default_conv_command_config(); + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + adc.set_conv_command_config(1, &conv_command_config); + + let mut conv_trigger_config = adc.get_default_conv_trigger_config(); + conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; + conv_trigger_config.enable_hardware_trigger = false; + adc.set_conv_trigger_config(0, &conv_trigger_config); + + defmt::info!("=== ADC configuration done... ==="); + + loop { + adc.do_software_trigger(1); + let mut result: Option = None; + while result.is_none() { + result = hal::adc::get_conv_result(); + } + let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; + defmt::info!("value: {=u16}", value); + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::gpio::{DriveStrength, Level, Output, SlewRate}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("Blink example"); + + let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast); + let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast); + let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast); + + loop { + defmt::info!("Toggle LEDs"); + + red.toggle(); + Timer::after_millis(250).await; + + red.toggle(); + green.toggle(); + Timer::after_millis(250).await; + + green.toggle(); + blue.toggle(); + Timer::after_millis(250).await; + blue.toggle(); + + Timer::after_millis(250).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::gpio::{Input, Pull}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("Button example"); + + // This button is labeled "WAKEUP" on the FRDM-MCXA276 + // The board already has a 10K pullup + let monitor = Input::new(p.P1_7, Pull::Disabled); + + loop { + defmt::info!("Pin level is {:?}", monitor.get_level()); + Timer::after_millis(1000).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::gpio::{Input, Pull}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("GPIO interrupt example"); + + // This button is labeled "WAKEUP" on the FRDM-MCXA276 + // The board already has a 10K pullup + let mut pin = Input::new(p.P1_7, Pull::Disabled); + + let mut press_count = 0u32; + + loop { + pin.wait_for_falling_edge().await; + + press_count += 1; + + defmt::info!("Button pressed! Count: {}", press_count); + Timer::after_millis(50).await; + } +} diff --git a/examples/mcxa/src/bin/clkout.rs b/examples/mcxa/src/bin/clkout.rs new file mode 100644 index 000000000..bfd963540 --- /dev/null +++ b/examples/mcxa/src/bin/clkout.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4}; +use embassy_mcxa::clocks::PoweredClock; +use embassy_mcxa::gpio::{DriveStrength, SlewRate}; +use embassy_mcxa::{Level, Output}; +use embassy_time::Timer; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Demonstrate CLKOUT, using Pin P4.2 +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + let mut pin = p.P4_2; + let mut clkout = p.CLKOUT; + + loop { + defmt::info!("Set Low..."); + let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); + Timer::after_millis(500).await; + + defmt::info!("Set High..."); + output.set_high(); + Timer::after_millis(400).await; + + defmt::info!("Set Low..."); + output.set_low(); + Timer::after_millis(500).await; + + defmt::info!("16k..."); + // Run Clock Out with the 16K clock + let _clock_out = ClockOut::new( + clkout.reborrow(), + pin.reborrow(), + Config { + sel: ClockOutSel::Clk16K, + div: Div4::no_div(), + level: PoweredClock::NormalEnabledDeepSleepDisabled, + }, + ) + .unwrap(); + + Timer::after_millis(3000).await; + + defmt::info!("Set Low..."); + drop(_clock_out); + + let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); + Timer::after_millis(500).await; + + // Run Clock Out with the 12M clock, divided by 3 + defmt::info!("4M..."); + let _clock_out = ClockOut::new( + clkout.reborrow(), + pin.reborrow(), + Config { + sel: ClockOutSel::Fro12M, + div: const { Div4::from_divisor(3).unwrap() }, + level: PoweredClock::NormalEnabledDeepSleepDisabled, + }, + ) + .unwrap(); + + // Let it run for 3 seconds... + Timer::after_millis(3000).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use hal::lpuart::{Blocking, Config, Lpuart}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Simple helper to write a byte as hex to UART +fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) { + const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; + let _ = uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); + let _ = uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + 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!("boot"); + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.P2_2, // TX pin + p.P2_3, // RX pin + config, + ) + .unwrap(); + + // Print welcome message before any async delays to guarantee early console output + uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); + uart.write_str_blocking("Available commands:\r\n"); + uart.write_str_blocking(" help - Show this help\r\n"); + uart.write_str_blocking(" echo - Echo back the text\r\n"); + uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); + uart.write_str_blocking("Type a command: "); + + let mut buffer = [0u8; 64]; + let mut buf_idx = 0; + + loop { + // Read a byte from UART + let byte = uart.read_byte_blocking(); + + // Echo the character back + if byte == b'\r' || byte == b'\n' { + // Enter pressed - process command + uart.write_str_blocking("\r\n"); + + if buf_idx > 0 { + let command = &buffer[0..buf_idx]; + + if command == b"help" { + uart.write_str_blocking("Available commands:\r\n"); + uart.write_str_blocking(" help - Show this help\r\n"); + uart.write_str_blocking(" echo - Echo back the text\r\n"); + uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); + } else if command.starts_with(b"echo ") && command.len() > 5 { + uart.write_str_blocking("Echo: "); + uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or("")); + uart.write_str_blocking("\r\n"); + } else if command.starts_with(b"hex ") && command.len() > 4 { + // Parse the byte value + let num_str = &command[4..]; + if let Ok(num) = parse_u8(num_str) { + uart.write_str_blocking("Hex: 0x"); + write_hex_byte(&mut uart, num); + uart.write_str_blocking("\r\n"); + } else { + uart.write_str_blocking("Invalid number for hex command\r\n"); + } + } else if !command.is_empty() { + uart.write_str_blocking("Unknown command: "); + uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); + uart.write_str_blocking("\r\n"); + } + } + + // Reset buffer and prompt + buf_idx = 0; + uart.write_str_blocking("Type a command: "); + } else if byte == 8 || byte == 127 { + // Backspace + if buf_idx > 0 { + buf_idx -= 1; + uart.write_str_blocking("\x08 \x08"); // Erase character + } + } else if buf_idx < buffer.len() - 1 { + // Regular character + buffer[buf_idx] = byte; + buf_idx += 1; + let _ = uart.write_byte(byte); + } + } +} + +/// Simple parser for u8 from ASCII bytes +fn parse_u8(bytes: &[u8]) -> Result { + let mut result = 0u8; + for &b in bytes { + if b.is_ascii_digit() { + result = result.checked_mul(10).ok_or(())?; + result = result.checked_add(b - b'0').ok_or(())?; + } else { + return Err(()); + } + } + Ok(result) +} diff --git a/examples/mcxa/src/bin/i2c-async.rs b/examples/mcxa/src/bin/i2c-async.rs new file mode 100644 index 000000000..47b5f3cbe --- /dev/null +++ b/examples/mcxa/src/bin/i2c-async.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::bind_interrupts; +use hal::clocks::config::Div8; +use hal::config::Config; +use hal::i2c::controller::{self, I2c, Speed}; +use hal::i2c::InterruptHandler; +use hal::peripherals::LPI2C3; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +bind_interrupts!( + struct Irqs { + LPI2C3 => InterruptHandler; + } +); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); + + defmt::info!("I2C example"); + + let mut config = controller::Config::default(); + config.speed = Speed::Standard; + let mut i2c = I2c::new_async(p.LPI2C3, p.P3_27, p.P3_28, Irqs, config).unwrap(); + let mut buf = [0u8; 2]; + + loop { + i2c.async_write_read(0x48, &[0x00], &mut buf).await.unwrap(); + defmt::info!("Buffer: {:02x}", buf); + Timer::after_secs(1).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::clocks::config::Div8; +use hal::config::Config; +use hal::i2c::controller::{self, I2c, Speed}; +use tmp108::Tmp108; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); + + defmt::info!("I2C example"); + + let mut config = controller::Config::default(); + config.speed = Speed::Standard; + let i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap(); + let mut tmp = Tmp108::new_with_a0_gnd(i2c); + + loop { + let temperature = tmp.temperature().unwrap(); + defmt::info!("Temperature: {}C", temperature); + Timer::after_secs(1).await; + } +} 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..4e203597b --- /dev/null +++ b/examples/mcxa/src/bin/i2c-scan-blocking.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::gpio::Pull; +use embassy_mcxa::Input; +use embassy_time::Timer; +use hal::clocks::config::Div8; +use hal::config::Config; +use hal::i2c::controller::{self, I2c, Speed}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); + + defmt::info!("I2C example"); + + let mut config = controller::Config::default(); + config.speed = Speed::Standard; + + // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and + // defaults to SWO on the debug peripheral. Explicitly make it a high-z + // input. + let _pin = Input::new(p.P0_2, Pull::Disabled); + let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap(); + + for addr in 0x01..=0x7f { + let result = i2c.blocking_write(addr, &[]); + if result.is_ok() { + defmt::info!("Device found at addr {:02x}", addr); + } + } + + loop { + Timer::after_secs(10).await; + } +} diff --git a/examples/mcxa/src/bin/lpuart_buffered.rs b/examples/mcxa/src/bin/lpuart_buffered.rs new file mode 100644 index 000000000..420589d00 --- /dev/null +++ b/examples/mcxa/src/bin/lpuart_buffered.rs @@ -0,0 +1,62 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::lpuart::buffered::BufferedLpuart; +use embassy_mcxa::lpuart::Config; +use embassy_mcxa::{bind_interrupts, lpuart}; +use embedded_io_async::Write; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver +bind_interrupts!(struct Irqs { + LPUART2 => lpuart::buffered::BufferedInterruptHandler::; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + 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); + + // Configure NVIC for LPUART2 + hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); + + // UART configuration (enable both TX and RX) + let config = Config { + baudrate_bps: 115_200, + rx_fifo_watermark: 0, + tx_fifo_watermark: 0, + ..Default::default() + }; + + let mut tx_buf = [0u8; 256]; + let mut rx_buf = [0u8; 256]; + + // Create a buffered LPUART2 instance with both TX and RX + let mut uart = BufferedLpuart::new( + p.LPUART2, + p.P2_2, // TX pin + p.P2_3, // RX pin + Irqs, + &mut tx_buf, + &mut rx_buf, + config, + ) + .unwrap(); + + // Split into TX and RX parts + let (tx, rx) = uart.split_ref(); + + tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); + tx.write(b"Type characters to echo them back.\r\n").await.unwrap(); + + // Echo loop + let mut buf = [0u8; 4]; + loop { + let used = rx.read(&mut buf).await.unwrap(); + tx.write_all(&buf[..used]).await.unwrap(); + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +use crate::hal::lpuart::{Config, Lpuart}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + 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!("boot"); + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX + let lpuart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.P2_2, // TX pin + p.P2_3, // RX pin + config, + ) + .unwrap(); + + // Split into separate TX and RX parts + let (mut tx, mut rx) = lpuart.split(); + + // Write hello messages + tx.blocking_write(b"Hello world.\r\n").unwrap(); + tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap(); + + // Echo loop + loop { + let mut buf = [0u8; 1]; + rx.blocking_read(&mut buf).unwrap(); + tx.blocking_write(&buf).unwrap(); + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::bind_interrupts; +use hal::rtc::{InterruptHandler, Rtc, RtcDateTime}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RTC => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("=== RTC Alarm Example ==="); + + let rtc_config = hal::rtc::get_default_config(); + + let mut rtc = Rtc::new(p.RTC0, Irqs, rtc_config); + + let now = RtcDateTime { + year: 2025, + month: 10, + day: 15, + hour: 14, + minute: 30, + second: 0, + }; + + rtc.stop(); + + defmt::info!("Time set to: 2025-10-15 14:30:00"); + rtc.set_datetime(now); + + let mut alarm = now; + alarm.second += 10; + + defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)"); + defmt::info!("RTC started, waiting for alarm..."); + + rtc.wait_for_alarm(alarm).await; + defmt::info!("*** ALARM TRIGGERED! ***"); + + defmt::info!("Example complete - Test PASSED!"); +} diff --git a/examples/mcxa/src/lib.rs b/examples/mcxa/src/lib.rs new file mode 100644 index 000000000..2573a6adc --- /dev/null +++ b/examples/mcxa/src/lib.rs @@ -0,0 +1,16 @@ +#![no_std] +#![allow(clippy::missing_safety_doc)] + +//! Shared board-specific helpers for the FRDM-MCXA276 examples. +//! These live with the examples so the HAL stays generic. + +use hal::{clocks, pins}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Initialize clocks and pin muxing for ADC. +pub unsafe fn init_adc_pins() { + // NOTE: Lpuart has been updated to properly enable + reset its own clocks. + // GPIO has not. + _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); + pins::configure_adc_pins(); +} -- cgit From 7ba524026cce5531300ec1d803d10390a6159240 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 4 Dec 2025 19:08:19 +0100 Subject: Bump mcxa-pac to lower MSRV to 1.90 --- examples/mcxa/Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/mcxa/Cargo.lock b/examples/mcxa/Cargo.lock index c6e864df2..8ac1fc8de 100644 --- a/examples/mcxa/Cargo.lock +++ b/examples/mcxa/Cargo.lock @@ -765,7 +765,7 @@ dependencies = [ [[package]] name = "mcxa-pac" version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca" +source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e7dfed8740b449b6ac646bab8ac6776a3c099267" dependencies = [ "cortex-m", "cortex-m-rt", -- cgit From 8b862572083c8233cc55bd635885b1c2b03564ee Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 4 Dec 2025 19:09:56 +0100 Subject: Add repository fields --- examples/mcxa/Cargo.toml | 1 + 1 file changed, 1 insertion(+) (limited to 'examples') diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml index 4da94811f..cfc68f067 100644 --- a/examples/mcxa/Cargo.toml +++ b/examples/mcxa/Cargo.toml @@ -3,6 +3,7 @@ name = "embassy-mcxa-examples" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" +repository = "https://github.com/embassy-rs/embassy" [dependencies] cortex-m = { version = "0.7", features = ["critical-section-single-core"] } -- cgit From 5d12ea7daef3422de26d24f902f2eedb3de2de9b Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 4 Dec 2025 19:11:29 +0100 Subject: publish false on mcxa examples --- examples/mcxa/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml index cfc68f067..f02fe73e0 100644 --- a/examples/mcxa/Cargo.toml +++ b/examples/mcxa/Cargo.toml @@ -3,7 +3,7 @@ name = "embassy-mcxa-examples" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" -repository = "https://github.com/embassy-rs/embassy" +publish = false [dependencies] cortex-m = { version = "0.7", features = ["critical-section-single-core"] } -- cgit From e7e4d0e03f6ccee7a8577058bfccefaf92b2689e Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 4 Dec 2025 19:19:23 +0100 Subject: rustfmt --- examples/mcxa/src/bin/adc_interrupt.rs | 4 ++-- examples/mcxa/src/bin/adc_polling.rs | 2 +- examples/mcxa/src/bin/i2c-async.rs | 2 +- examples/mcxa/src/bin/i2c-scan-blocking.rs | 2 +- examples/mcxa/src/bin/lpuart_buffered.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 83d8046b3..c88b1fe8d 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -4,13 +4,13 @@ use embassy_executor::Spawner; use embassy_mcxa_examples::init_adc_pins; use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::clocks::PoweredClock; +use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; -use hal::{bind_interrupts, InterruptExt}; +use hal::{InterruptExt, bind_interrupts}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index ddf3f586b..07c50f224 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -4,8 +4,8 @@ use embassy_executor::Spawner; use embassy_mcxa_examples::init_adc_pins; use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::clocks::PoweredClock; +use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; diff --git a/examples/mcxa/src/bin/i2c-async.rs b/examples/mcxa/src/bin/i2c-async.rs index 47b5f3cbe..edcfd5f22 100644 --- a/examples/mcxa/src/bin/i2c-async.rs +++ b/examples/mcxa/src/bin/i2c-async.rs @@ -6,8 +6,8 @@ use embassy_time::Timer; use hal::bind_interrupts; use hal::clocks::config::Div8; use hal::config::Config; -use hal::i2c::controller::{self, I2c, Speed}; use hal::i2c::InterruptHandler; +use hal::i2c::controller::{self, I2c, Speed}; use hal::peripherals::LPI2C3; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; diff --git a/examples/mcxa/src/bin/i2c-scan-blocking.rs b/examples/mcxa/src/bin/i2c-scan-blocking.rs index 4e203597b..0197f9b1d 100644 --- a/examples/mcxa/src/bin/i2c-scan-blocking.rs +++ b/examples/mcxa/src/bin/i2c-scan-blocking.rs @@ -2,8 +2,8 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa::gpio::Pull; use embassy_mcxa::Input; +use embassy_mcxa::gpio::Pull; use embassy_time::Timer; use hal::clocks::config::Div8; use hal::config::Config; diff --git a/examples/mcxa/src/bin/lpuart_buffered.rs b/examples/mcxa/src/bin/lpuart_buffered.rs index 420589d00..47b56b7c7 100644 --- a/examples/mcxa/src/bin/lpuart_buffered.rs +++ b/examples/mcxa/src/bin/lpuart_buffered.rs @@ -3,8 +3,8 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::lpuart::buffered::BufferedLpuart; use embassy_mcxa::lpuart::Config; +use embassy_mcxa::lpuart::buffered::BufferedLpuart; use embassy_mcxa::{bind_interrupts, lpuart}; use embedded_io_async::Write; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -- cgit From 85b92010deb835d27ce30ec0870cdedadf4465ec Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 4 Dec 2025 19:24:06 +0100 Subject: Tweak how target setting is handled --- examples/mcxa/Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'examples') diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml index f02fe73e0..4d0459f41 100644 --- a/examples/mcxa/Cargo.toml +++ b/examples/mcxa/Cargo.toml @@ -25,3 +25,8 @@ tmp108 = "0.4.0" [profile.release] lto = true # better optimizations debug = 2 # enough information for defmt/rtt locations + +[package.metadata.embassy] +build = [ + { target = "thumbv8m.main-none-eabihf", artifact-dir = "out/examples/mcxa" } +] -- cgit From a08fc1a78065fe42a5eb9a82d1c277b277a57556 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 4 Dec 2025 19:42:17 +0100 Subject: Remove some misc bits --- examples/mcxa/Cargo.lock | 1555 ---------------------------------------------- 1 file changed, 1555 deletions(-) delete mode 100644 examples/mcxa/Cargo.lock (limited to 'examples') diff --git a/examples/mcxa/Cargo.lock b/examples/mcxa/Cargo.lock deleted file mode 100644 index 8ac1fc8de..000000000 --- a/examples/mcxa/Cargo.lock +++ /dev/null @@ -1,1555 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser", - "memchr", - "proc-macro2", - "quote", - "rustc-hash", - "syn 2.0.110", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "winnow 0.7.13", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.2.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cordyceps" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" -dependencies = [ - "loom", - "tracing", -] - -[[package]] -name = "cortex-m" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" -dependencies = [ - "bare-metal", - "bitfield", - "critical-section", - "embedded-hal 0.2.7", - "volatile-register", -] - -[[package]] -name = "cortex-m-rt" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" -dependencies = [ - "cortex-m-rt-macros", -] - -[[package]] -name = "cortex-m-rt-macros" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.110", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "dd-manifest-tree" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" -dependencies = [ - "toml", -] - -[[package]] -name = "defmt" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" -dependencies = [ - "bitflags 1.3.2", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" -dependencies = [ - "defmt-parser", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "defmt-parser" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" -dependencies = [ - "thiserror", -] - -[[package]] -name = "defmt-rtt" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e" -dependencies = [ - "critical-section", - "defmt", -] - -[[package]] -name = "device-driver" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" -dependencies = [ - "device-driver-macros", - "embedded-io", - "embedded-io-async", -] - -[[package]] -name = "device-driver-generation" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" -dependencies = [ - "anyhow", - "askama", - "bitvec", - "convert_case", - "dd-manifest-tree", - "itertools", - "kdl", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "device-driver-macros" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" -dependencies = [ - "device-driver-generation", - "proc-macro2", - "syn 2.0.110", -] - -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "embassy-embedded-hal" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" -dependencies = [ - "embassy-futures", - "embassy-hal-internal", - "embassy-sync", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-storage", - "embedded-storage-async", - "nb 1.1.0", -] - -[[package]] -name = "embassy-executor" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" -dependencies = [ - "cortex-m", - "critical-section", - "document-features", - "embassy-executor-macros", - "embassy-executor-timer-queue", -] - -[[package]] -name = "embassy-executor-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "embassy-executor-timer-queue" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" - -[[package]] -name = "embassy-futures" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" - -[[package]] -name = "embassy-hal-internal" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" -dependencies = [ - "cortex-m", - "critical-section", - "num-traits", -] - -[[package]] -name = "embassy-mcxa" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "embassy-embedded-hal", - "embassy-hal-internal", - "embassy-sync", - "embassy-time", - "embassy-time-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-hal-nb", - "embedded-io", - "embedded-io-async", - "heapless 0.8.0", - "maitake-sync", - "mcxa-pac", - "nb 1.1.0", - "paste", -] - -[[package]] -name = "embassy-mcxa-examples" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "defmt-rtt", - "embassy-embedded-hal", - "embassy-executor", - "embassy-mcxa", - "embassy-sync", - "embassy-time", - "embassy-time-driver", - "embedded-io-async", - "heapless 0.9.2", - "panic-probe", - "tmp108", -] - -[[package]] -name = "embassy-sync" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" -dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-core", - "futures-sink", - "heapless 0.8.0", -] - -[[package]] -name = "embassy-time" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" -dependencies = [ - "cfg-if", - "critical-section", - "document-features", - "embassy-time-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "futures-core", -] - -[[package]] -name = "embassy-time-driver" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" -dependencies = [ - "document-features", -] - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" -dependencies = [ - "embedded-hal 1.0.0", -] - -[[package]] -name = "embedded-hal-nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" -dependencies = [ - "embedded-hal 1.0.0", - "nb 1.1.0", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "embedded-io-async" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" -dependencies = [ - "embedded-io", -] - -[[package]] -name = "embedded-storage" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" - -[[package]] -name = "embedded-storage-async" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" -dependencies = [ - "embedded-storage", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "find-msvc-tools" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "generator" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" -dependencies = [ - "cc", - "cfg-if", - "libc", - "log", - "rustversion", - "windows", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "heapless" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" -dependencies = [ - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indexmap" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "kdl" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e" -dependencies = [ - "miette", - "num", - "winnow 0.6.24", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.177" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" - -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "maitake-sync" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" -dependencies = [ - "cordyceps", - "critical-section", - "loom", - "mutex-traits", - "mycelium-bitfield", - "pin-project", - "portable-atomic", - "tracing", -] - -[[package]] -name = "manyhow" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" -dependencies = [ - "manyhow-macros", - "proc-macro2", - "quote", - "syn 1.0.109", - "syn 2.0.110", -] - -[[package]] -name = "manyhow-macros" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" -dependencies = [ - "proc-macro-utils", - "proc-macro2", - "quote", -] - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "maybe-async-cfg" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627" -dependencies = [ - "manyhow", - "proc-macro2", - "pulldown-cmark", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "mcxa-pac" -version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e7dfed8740b449b6ac646bab8ac6776a3c099267" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "vcell", -] - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "cfg-if", - "unicode-width", -] - -[[package]] -name = "mutex-traits" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" - -[[package]] -name = "mycelium-bitfield" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc" - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "panic-probe" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a" -dependencies = [ - "cortex-m", - "defmt", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" -dependencies = [ - "critical-section", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "proc-macro-utils" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" -dependencies = [ - "proc-macro2", - "quote", - "smallvec", -] - -[[package]] -name = "proc-macro2" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pulldown-cmark" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" -dependencies = [ - "bitflags 2.10.0", - "memchr", - "unicase", -] - -[[package]] -name = "quote" -version = "1.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.110" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "tmp108" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d644cc97d3cee96793f454b834881f78b5d4e89c90ecf26b3690f42004d111" -dependencies = [ - "device-driver", - "embedded-hal 1.0.0", - "maybe-async-cfg", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow 0.7.13", -] - -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - -[[package]] -name = "tracing" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb41cbdb933e23b7929f47bb577710643157d7602ef3a2ebd3902b13ac5eda6" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "tracing-core" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" -dependencies = [ - "vcell", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core", - "windows-link 0.1.3", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core", - "windows-link 0.1.3", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] -- cgit From b252db845e19603faf528cf93fe0c44757a27430 Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 5 Dec 2025 14:28:47 +0100 Subject: Move --- examples/.cargo/config.toml | 17 - examples/.gitignore | 1 - examples/Cargo.lock | 1555 -------------------- examples/Cargo.toml | 26 - examples/build.rs | 20 - examples/mcxa/.cargo/config.toml | 17 + examples/mcxa/.gitignore | 1 + examples/mcxa/Cargo.lock | 1555 ++++++++++++++++++++ examples/mcxa/Cargo.toml | 26 + examples/mcxa/build.rs | 20 + examples/mcxa/memory.x | 5 + examples/mcxa/src/bin/adc_interrupt.rs | 84 ++ examples/mcxa/src/bin/adc_polling.rs | 68 + examples/mcxa/src/bin/blinky.rs | 36 + examples/mcxa/src/bin/button.rs | 23 + examples/mcxa/src/bin/button_async.rs | 29 + examples/mcxa/src/bin/clkout.rs | 69 + examples/mcxa/src/bin/dma_channel_link.rs | 372 +++++ examples/mcxa/src/bin/dma_interleave_transfer.rs | 215 +++ examples/mcxa/src/bin/dma_mem_to_mem.rs | 229 +++ examples/mcxa/src/bin/dma_memset.rs | 218 +++ examples/mcxa/src/bin/dma_ping_pong_transfer.rs | 376 +++++ examples/mcxa/src/bin/dma_scatter_gather.rs | 262 ++++ .../mcxa/src/bin/dma_scatter_gather_builder.rs | 231 +++ examples/mcxa/src/bin/dma_wrap_transfer.rs | 222 +++ examples/mcxa/src/bin/hello.rs | 119 ++ examples/mcxa/src/bin/i2c-blocking.rs | 31 + examples/mcxa/src/bin/i2c-scan-blocking.rs | 41 + examples/mcxa/src/bin/lpuart_buffered.rs | 62 + examples/mcxa/src/bin/lpuart_dma.rs | 81 + examples/mcxa/src/bin/lpuart_polling.rs | 47 + examples/mcxa/src/bin/lpuart_ring_buffer.rs | 130 ++ examples/mcxa/src/bin/rtc_alarm.rs | 74 + examples/mcxa/src/lib.rs | 16 + examples/memory.x | 5 - examples/src/bin/adc_interrupt.rs | 84 -- examples/src/bin/adc_polling.rs | 68 - examples/src/bin/blinky.rs | 36 - examples/src/bin/button.rs | 23 - examples/src/bin/button_async.rs | 29 - examples/src/bin/clkout.rs | 69 - examples/src/bin/dma_channel_link.rs | 372 ----- examples/src/bin/dma_interleave_transfer.rs | 215 --- examples/src/bin/dma_mem_to_mem.rs | 229 --- examples/src/bin/dma_memset.rs | 218 --- examples/src/bin/dma_ping_pong_transfer.rs | 376 ----- examples/src/bin/dma_scatter_gather.rs | 262 ---- examples/src/bin/dma_scatter_gather_builder.rs | 231 --- examples/src/bin/dma_wrap_transfer.rs | 222 --- examples/src/bin/hello.rs | 119 -- examples/src/bin/i2c-blocking.rs | 31 - examples/src/bin/i2c-scan-blocking.rs | 41 - examples/src/bin/lpuart_buffered.rs | 62 - examples/src/bin/lpuart_dma.rs | 81 - examples/src/bin/lpuart_polling.rs | 47 - examples/src/bin/lpuart_ring_buffer.rs | 130 -- examples/src/bin/rtc_alarm.rs | 74 - examples/src/lib.rs | 16 - 58 files changed, 4659 insertions(+), 4659 deletions(-) delete mode 100644 examples/.cargo/config.toml delete mode 100644 examples/.gitignore delete mode 100644 examples/Cargo.lock delete mode 100644 examples/Cargo.toml delete mode 100644 examples/build.rs create mode 100644 examples/mcxa/.cargo/config.toml create mode 100644 examples/mcxa/.gitignore create mode 100644 examples/mcxa/Cargo.lock create mode 100644 examples/mcxa/Cargo.toml create mode 100644 examples/mcxa/build.rs create mode 100644 examples/mcxa/memory.x create mode 100644 examples/mcxa/src/bin/adc_interrupt.rs create mode 100644 examples/mcxa/src/bin/adc_polling.rs create mode 100644 examples/mcxa/src/bin/blinky.rs create mode 100644 examples/mcxa/src/bin/button.rs create mode 100644 examples/mcxa/src/bin/button_async.rs create mode 100644 examples/mcxa/src/bin/clkout.rs create mode 100644 examples/mcxa/src/bin/dma_channel_link.rs create mode 100644 examples/mcxa/src/bin/dma_interleave_transfer.rs create mode 100644 examples/mcxa/src/bin/dma_mem_to_mem.rs create mode 100644 examples/mcxa/src/bin/dma_memset.rs create mode 100644 examples/mcxa/src/bin/dma_ping_pong_transfer.rs create mode 100644 examples/mcxa/src/bin/dma_scatter_gather.rs create mode 100644 examples/mcxa/src/bin/dma_scatter_gather_builder.rs create mode 100644 examples/mcxa/src/bin/dma_wrap_transfer.rs create mode 100644 examples/mcxa/src/bin/hello.rs create mode 100644 examples/mcxa/src/bin/i2c-blocking.rs create mode 100644 examples/mcxa/src/bin/i2c-scan-blocking.rs create mode 100644 examples/mcxa/src/bin/lpuart_buffered.rs create mode 100644 examples/mcxa/src/bin/lpuart_dma.rs create mode 100644 examples/mcxa/src/bin/lpuart_polling.rs create mode 100644 examples/mcxa/src/bin/lpuart_ring_buffer.rs create mode 100644 examples/mcxa/src/bin/rtc_alarm.rs create mode 100644 examples/mcxa/src/lib.rs delete mode 100644 examples/memory.x delete mode 100644 examples/src/bin/adc_interrupt.rs delete mode 100644 examples/src/bin/adc_polling.rs delete mode 100644 examples/src/bin/blinky.rs delete mode 100644 examples/src/bin/button.rs delete mode 100644 examples/src/bin/button_async.rs delete mode 100644 examples/src/bin/clkout.rs delete mode 100644 examples/src/bin/dma_channel_link.rs delete mode 100644 examples/src/bin/dma_interleave_transfer.rs delete mode 100644 examples/src/bin/dma_mem_to_mem.rs delete mode 100644 examples/src/bin/dma_memset.rs delete mode 100644 examples/src/bin/dma_ping_pong_transfer.rs delete mode 100644 examples/src/bin/dma_scatter_gather.rs delete mode 100644 examples/src/bin/dma_scatter_gather_builder.rs delete mode 100644 examples/src/bin/dma_wrap_transfer.rs delete mode 100644 examples/src/bin/hello.rs delete mode 100644 examples/src/bin/i2c-blocking.rs delete mode 100644 examples/src/bin/i2c-scan-blocking.rs delete mode 100644 examples/src/bin/lpuart_buffered.rs delete mode 100644 examples/src/bin/lpuart_dma.rs delete mode 100644 examples/src/bin/lpuart_polling.rs delete mode 100644 examples/src/bin/lpuart_ring_buffer.rs delete mode 100644 examples/src/bin/rtc_alarm.rs delete mode 100644 examples/src/lib.rs (limited to 'examples') diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml deleted file mode 100644 index aedc55b06..000000000 --- a/examples/.cargo/config.toml +++ /dev/null @@ -1,17 +0,0 @@ -[target.thumbv8m.main-none-eabihf] -runner = 'probe-rs run --chip MCXA276 --preverify --verify --protocol swd --speed 12000' - -rustflags = [ - "-C", "linker=flip-link", - "-C", "link-arg=-Tlink.x", - "-C", "link-arg=-Tdefmt.x", - # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x - # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 - "-C", "link-arg=--nmagic", -] - -[build] -target = "thumbv8m.main-none-eabihf" # Cortex-M33 - -[env] -DEFMT_LOG = "trace" diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/examples/Cargo.lock b/examples/Cargo.lock deleted file mode 100644 index c6e864df2..000000000 --- a/examples/Cargo.lock +++ /dev/null @@ -1,1555 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - -[[package]] -name = "askama" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" -dependencies = [ - "askama_derive", - "itoa", - "percent-encoding", - "serde", - "serde_json", -] - -[[package]] -name = "askama_derive" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" -dependencies = [ - "askama_parser", - "memchr", - "proc-macro2", - "quote", - "rustc-hash", - "syn 2.0.110", -] - -[[package]] -name = "askama_parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" -dependencies = [ - "memchr", - "winnow 0.7.13", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.2.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cordyceps" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" -dependencies = [ - "loom", - "tracing", -] - -[[package]] -name = "cortex-m" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" -dependencies = [ - "bare-metal", - "bitfield", - "critical-section", - "embedded-hal 0.2.7", - "volatile-register", -] - -[[package]] -name = "cortex-m-rt" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" -dependencies = [ - "cortex-m-rt-macros", -] - -[[package]] -name = "cortex-m-rt-macros" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.110", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "dd-manifest-tree" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" -dependencies = [ - "toml", -] - -[[package]] -name = "defmt" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" -dependencies = [ - "bitflags 1.3.2", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" -dependencies = [ - "defmt-parser", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "defmt-parser" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" -dependencies = [ - "thiserror", -] - -[[package]] -name = "defmt-rtt" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e" -dependencies = [ - "critical-section", - "defmt", -] - -[[package]] -name = "device-driver" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" -dependencies = [ - "device-driver-macros", - "embedded-io", - "embedded-io-async", -] - -[[package]] -name = "device-driver-generation" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" -dependencies = [ - "anyhow", - "askama", - "bitvec", - "convert_case", - "dd-manifest-tree", - "itertools", - "kdl", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "device-driver-macros" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" -dependencies = [ - "device-driver-generation", - "proc-macro2", - "syn 2.0.110", -] - -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "embassy-embedded-hal" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" -dependencies = [ - "embassy-futures", - "embassy-hal-internal", - "embassy-sync", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-storage", - "embedded-storage-async", - "nb 1.1.0", -] - -[[package]] -name = "embassy-executor" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" -dependencies = [ - "cortex-m", - "critical-section", - "document-features", - "embassy-executor-macros", - "embassy-executor-timer-queue", -] - -[[package]] -name = "embassy-executor-macros" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "embassy-executor-timer-queue" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" - -[[package]] -name = "embassy-futures" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" - -[[package]] -name = "embassy-hal-internal" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" -dependencies = [ - "cortex-m", - "critical-section", - "num-traits", -] - -[[package]] -name = "embassy-mcxa" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "embassy-embedded-hal", - "embassy-hal-internal", - "embassy-sync", - "embassy-time", - "embassy-time-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "embedded-hal-nb", - "embedded-io", - "embedded-io-async", - "heapless 0.8.0", - "maitake-sync", - "mcxa-pac", - "nb 1.1.0", - "paste", -] - -[[package]] -name = "embassy-mcxa-examples" -version = "0.1.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "defmt-rtt", - "embassy-embedded-hal", - "embassy-executor", - "embassy-mcxa", - "embassy-sync", - "embassy-time", - "embassy-time-driver", - "embedded-io-async", - "heapless 0.9.2", - "panic-probe", - "tmp108", -] - -[[package]] -name = "embassy-sync" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" -dependencies = [ - "cfg-if", - "critical-section", - "embedded-io-async", - "futures-core", - "futures-sink", - "heapless 0.8.0", -] - -[[package]] -name = "embassy-time" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" -dependencies = [ - "cfg-if", - "critical-section", - "document-features", - "embassy-time-driver", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-hal-async", - "futures-core", -] - -[[package]] -name = "embassy-time-driver" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" -dependencies = [ - "document-features", -] - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" -dependencies = [ - "embedded-hal 1.0.0", -] - -[[package]] -name = "embedded-hal-nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" -dependencies = [ - "embedded-hal 1.0.0", - "nb 1.1.0", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "embedded-io-async" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" -dependencies = [ - "embedded-io", -] - -[[package]] -name = "embedded-storage" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" - -[[package]] -name = "embedded-storage-async" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" -dependencies = [ - "embedded-storage", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "find-msvc-tools" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "generator" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" -dependencies = [ - "cc", - "cfg-if", - "libc", - "log", - "rustversion", - "windows", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "heapless" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" -dependencies = [ - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indexmap" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "kdl" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e" -dependencies = [ - "miette", - "num", - "winnow 0.6.24", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.177" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" - -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "loom" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "maitake-sync" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" -dependencies = [ - "cordyceps", - "critical-section", - "loom", - "mutex-traits", - "mycelium-bitfield", - "pin-project", - "portable-atomic", - "tracing", -] - -[[package]] -name = "manyhow" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" -dependencies = [ - "manyhow-macros", - "proc-macro2", - "quote", - "syn 1.0.109", - "syn 2.0.110", -] - -[[package]] -name = "manyhow-macros" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" -dependencies = [ - "proc-macro-utils", - "proc-macro2", - "quote", -] - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "maybe-async-cfg" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627" -dependencies = [ - "manyhow", - "proc-macro2", - "pulldown-cmark", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "mcxa-pac" -version = "0.1.0" -source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "critical-section", - "defmt", - "vcell", -] - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "cfg-if", - "unicode-width", -] - -[[package]] -name = "mutex-traits" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" - -[[package]] -name = "mycelium-bitfield" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc" - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "panic-probe" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a" -dependencies = [ - "cortex-m", - "defmt", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" -dependencies = [ - "critical-section", -] - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "proc-macro-utils" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" -dependencies = [ - "proc-macro2", - "quote", - "smallvec", -] - -[[package]] -name = "proc-macro2" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "pulldown-cmark" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" -dependencies = [ - "bitflags 2.10.0", - "memchr", - "unicase", -] - -[[package]] -name = "quote" -version = "1.0.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.110" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "tmp108" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d644cc97d3cee96793f454b834881f78b5d4e89c90ecf26b3690f42004d111" -dependencies = [ - "device-driver", - "embedded-hal 1.0.0", - "maybe-async-cfg", -] - -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow 0.7.13", -] - -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - -[[package]] -name = "tracing" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb41cbdb933e23b7929f47bb577710643157d7602ef3a2ebd3902b13ac5eda6" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "tracing-core" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" -dependencies = [ - "vcell", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core", - "windows-link 0.1.3", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.110", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core", - "windows-link 0.1.3", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "winnow" -version = "0.6.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] diff --git a/examples/Cargo.toml b/examples/Cargo.toml deleted file mode 100644 index a1092c416..000000000 --- a/examples/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "embassy-mcxa-examples" -version = "0.1.0" -edition = "2021" -license = "MIT OR Apache-2.0" - -[dependencies] -cortex-m = { version = "0.7", features = ["critical-section-single-core"] } -cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] } -critical-section = "1.2.0" -defmt = "1.0" -defmt-rtt = "1.0" -embassy-embedded-hal = "0.5.0" -embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } -embassy-mcxa = { path = "../", features = ["defmt", "unstable-pac", "time"] } -embassy-sync = "0.7.2" -embassy-time = "0.5.0" -embassy-time-driver = "0.2.1" -embedded-io-async = "0.6.1" -heapless = "0.9.2" -panic-probe = { version = "1.0", features = ["print-defmt"] } -tmp108 = "0.4.0" - -[profile.release] -lto = true # better optimizations -debug = 2 # enough information for defmt/rtt locations diff --git a/examples/build.rs b/examples/build.rs deleted file mode 100644 index f076bba9f..000000000 --- a/examples/build.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -fn main() { - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - - // Generate memory.x - put "FLASH" at start of RAM, RAM after "FLASH" - // cortex-m-rt expects FLASH for code, RAM for data/bss/stack - // Both are in RAM, but separated to satisfy cortex-m-rt's expectations - // MCXA256 has 128KB RAM total - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - - println!("cargo:rustc-link-search={}", out.display()); - println!("cargo:rerun-if-changed=memory.x"); -} diff --git a/examples/mcxa/.cargo/config.toml b/examples/mcxa/.cargo/config.toml new file mode 100644 index 000000000..aedc55b06 --- /dev/null +++ b/examples/mcxa/.cargo/config.toml @@ -0,0 +1,17 @@ +[target.thumbv8m.main-none-eabihf] +runner = 'probe-rs run --chip MCXA276 --preverify --verify --protocol swd --speed 12000' + +rustflags = [ + "-C", "linker=flip-link", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x + # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + "-C", "link-arg=--nmagic", +] + +[build] +target = "thumbv8m.main-none-eabihf" # Cortex-M33 + +[env] +DEFMT_LOG = "trace" diff --git a/examples/mcxa/.gitignore b/examples/mcxa/.gitignore new file mode 100644 index 000000000..2f7896d1d --- /dev/null +++ b/examples/mcxa/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/examples/mcxa/Cargo.lock b/examples/mcxa/Cargo.lock new file mode 100644 index 000000000..c6e864df2 --- /dev/null +++ b/examples/mcxa/Cargo.lock @@ -0,0 +1,1555 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "askama" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" +dependencies = [ + "askama_derive", + "itoa", + "percent-encoding", + "serde", + "serde_json", +] + +[[package]] +name = "askama_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" +dependencies = [ + "askama_parser", + "memchr", + "proc-macro2", + "quote", + "rustc-hash", + "syn 2.0.110", +] + +[[package]] +name = "askama_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" +dependencies = [ + "memchr", + "winnow 0.7.13", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.2.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cordyceps" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" +dependencies = [ + "loom", + "tracing", +] + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.110", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "dd-manifest-tree" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5793572036e0a6638977c7370c6afc423eac848ee8495f079b8fd3964de7b9f9" +dependencies = [ + "toml", +] + +[[package]] +name = "defmt" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "defmt-rtt" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d5a25c99d89c40f5676bec8cefe0614f17f0f40e916f98e345dae941807f9e" +dependencies = [ + "critical-section", + "defmt", +] + +[[package]] +name = "device-driver" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af0e43acfcbb0bb3b7435cc1b1dbb33596cacfec1eb243336b74a398e0bd6cbf" +dependencies = [ + "device-driver-macros", + "embedded-io", + "embedded-io-async", +] + +[[package]] +name = "device-driver-generation" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3935aec9cf5bb2ab927f59ca69faecf976190390b0ce34c6023889e9041040c0" +dependencies = [ + "anyhow", + "askama", + "bitvec", + "convert_case", + "dd-manifest-tree", + "itertools", + "kdl", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "device-driver-macros" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fdc68ed515c4eddff2e95371185b4becba066085bf36d50f07f09782af98e17" +dependencies = [ + "device-driver-generation", + "proc-macro2", + "syn 2.0.110", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "embassy-embedded-hal" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "554e3e840696f54b4c9afcf28a0f24da431c927f4151040020416e7393d6d0d8" +dependencies = [ + "embassy-futures", + "embassy-hal-internal", + "embassy-sync", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-storage", + "embedded-storage-async", + "nb 1.1.0", +] + +[[package]] +name = "embassy-executor" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" +dependencies = [ + "cortex-m", + "critical-section", + "document-features", + "embassy-executor-macros", + "embassy-executor-timer-queue", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "embassy-executor-timer-queue" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" + +[[package]] +name = "embassy-futures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" + +[[package]] +name = "embassy-hal-internal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" +dependencies = [ + "cortex-m", + "critical-section", + "num-traits", +] + +[[package]] +name = "embassy-mcxa" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt", + "embassy-embedded-hal", + "embassy-hal-internal", + "embassy-sync", + "embassy-time", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-nb", + "embedded-io", + "embedded-io-async", + "heapless 0.8.0", + "maitake-sync", + "mcxa-pac", + "nb 1.1.0", + "paste", +] + +[[package]] +name = "embassy-mcxa-examples" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt", + "defmt-rtt", + "embassy-embedded-hal", + "embassy-executor", + "embassy-mcxa", + "embassy-sync", + "embassy-time", + "embassy-time-driver", + "embedded-io-async", + "heapless 0.9.2", + "panic-probe", + "tmp108", +] + +[[package]] +name = "embassy-sync" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73974a3edbd0bd286759b3d483540f0ebef705919a5f56f4fc7709066f71689b" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-core", + "futures-sink", + "heapless 0.8.0", +] + +[[package]] +name = "embassy-time" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-core", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" +dependencies = [ + "document-features", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal 1.0.0", + "nb 1.1.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "embedded-io-async" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] +name = "embedded-storage-async" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" +dependencies = [ + "embedded-storage", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "generator" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heapless" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "kdl" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a29e7b50079ff44549f68c0becb1c73d7f6de2a4ea952da77966daf3d4761e" +dependencies = [ + "miette", + "num", + "winnow 0.6.24", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "maitake-sync" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "748f86d9befd480b602c3bebc9ef30dbf2f3dfc8acc4a73d07b90f0117e6de3f" +dependencies = [ + "cordyceps", + "critical-section", + "loom", + "mutex-traits", + "mycelium-bitfield", + "pin-project", + "portable-atomic", + "tracing", +] + +[[package]] +name = "manyhow" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" +dependencies = [ + "manyhow-macros", + "proc-macro2", + "quote", + "syn 1.0.109", + "syn 2.0.110", +] + +[[package]] +name = "manyhow-macros" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" +dependencies = [ + "proc-macro-utils", + "proc-macro2", + "quote", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "maybe-async-cfg" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dbfaa67a76e2623580df07d6bb5e7956c0a4bae4b418314083a9c619bd66627" +dependencies = [ + "manyhow", + "proc-macro2", + "pulldown-cmark", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "mcxa-pac" +version = "0.1.0" +source = "git+https://github.com/OpenDevicePartnership/mcxa-pac#e18dfb52500ca77b8d8326662b966a80251182ca" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "defmt", + "vcell", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "cfg-if", + "unicode-width", +] + +[[package]] +name = "mutex-traits" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3929f2b5633d29cf7b6624992e5f3c1e9334f1193423e12d17be4faf678cde3f" + +[[package]] +name = "mycelium-bitfield" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e0cc5e2c585acbd15c5ce911dff71e1f4d5313f43345873311c4f5efd741cc" + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "panic-probe" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd402d00b0fb94c5aee000029204a46884b1262e0c443f166d86d2c0747e1a1a" +dependencies = [ + "cortex-m", + "defmt", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +dependencies = [ + "critical-section", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "proc-macro-utils" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" +dependencies = [ + "proc-macro2", + "quote", + "smallvec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulldown-cmark" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" +dependencies = [ + "bitflags 2.10.0", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tmp108" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d644cc97d3cee96793f454b834881f78b5d4e89c90ecf26b3690f42004d111" +dependencies = [ + "device-driver", + "embedded-hal 1.0.0", + "maybe-async-cfg", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow 0.7.13", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tracing" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb41cbdb933e23b7929f47bb577710643157d7602ef3a2ebd3902b13ac5eda6" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "tracing-core" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.110", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "winnow" +version = "0.6.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml new file mode 100644 index 000000000..a1092c416 --- /dev/null +++ b/examples/mcxa/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "embassy-mcxa-examples" +version = "0.1.0" +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +cortex-m = { version = "0.7", features = ["critical-section-single-core"] } +cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] } +critical-section = "1.2.0" +defmt = "1.0" +defmt-rtt = "1.0" +embassy-embedded-hal = "0.5.0" +embassy-executor = { version = "0.9.0", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"], default-features = false } +embassy-mcxa = { path = "../", features = ["defmt", "unstable-pac", "time"] } +embassy-sync = "0.7.2" +embassy-time = "0.5.0" +embassy-time-driver = "0.2.1" +embedded-io-async = "0.6.1" +heapless = "0.9.2" +panic-probe = { version = "1.0", features = ["print-defmt"] } +tmp108 = "0.4.0" + +[profile.release] +lto = true # better optimizations +debug = 2 # enough information for defmt/rtt locations diff --git a/examples/mcxa/build.rs b/examples/mcxa/build.rs new file mode 100644 index 000000000..f076bba9f --- /dev/null +++ b/examples/mcxa/build.rs @@ -0,0 +1,20 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + // Generate memory.x - put "FLASH" at start of RAM, RAM after "FLASH" + // cortex-m-rt expects FLASH for code, RAM for data/bss/stack + // Both are in RAM, but separated to satisfy cortex-m-rt's expectations + // MCXA256 has 128KB RAM total + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/examples/mcxa/memory.x b/examples/mcxa/memory.x new file mode 100644 index 000000000..315ced58a --- /dev/null +++ b/examples/mcxa/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 1M + RAM : ORIGIN = 0x20000000, LENGTH = 128K +} diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs new file mode 100644 index 000000000..83d8046b3 --- /dev/null +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -0,0 +1,84 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa_examples::init_adc_pins; +use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; +use hal::clocks::periph_helpers::{AdcClockSel, Div4}; +use hal::clocks::PoweredClock; +use hal::pac::adc1::cfg::{Pwrsel, Refsel}; +use hal::pac::adc1::cmdl1::{Adch, Mode}; +use hal::pac::adc1::ctrl::CalAvgs; +use hal::pac::adc1::tctrl::Tcmd; +use hal::{bind_interrupts, InterruptExt}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ADC1 => hal::adc::AdcHandler; +}); + +#[used] +#[no_mangle] +static KEEP_ADC: unsafe extern "C" fn() = ADC1; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("ADC interrupt Example"); + + unsafe { + init_adc_pins(); + } + + let adc_config = LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: AdcClockSel::FroLfDiv, + div: Div4::no_div(), + }; + let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + + adc.do_offset_calibration(); + adc.do_auto_calibration(); + + let mut conv_command_config = adc.get_default_conv_command_config(); + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + adc.set_conv_command_config(1, &conv_command_config); + + let mut conv_trigger_config = adc.get_default_conv_trigger_config(); + conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; + conv_trigger_config.enable_hardware_trigger = false; + adc.set_conv_trigger_config(0, &conv_trigger_config); + + defmt::info!("ADC configuration done..."); + + adc.enable_interrupt(0x1); + + unsafe { + hal::interrupt::ADC1.enable(); + } + + unsafe { + cortex_m::interrupt::enable(); + } + + loop { + adc.do_software_trigger(1); + while !adc.is_interrupt_triggered() { + // Wait until the interrupt is triggered + } + defmt::info!("*** ADC interrupt TRIGGERED! ***"); + //TBD need to print the value + } +} diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs new file mode 100644 index 000000000..ddf3f586b --- /dev/null +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa_examples::init_adc_pins; +use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; +use hal::clocks::periph_helpers::{AdcClockSel, Div4}; +use hal::clocks::PoweredClock; +use hal::pac::adc1::cfg::{Pwrsel, Refsel}; +use hal::pac::adc1::cmdl1::{Adch, Mode}; +use hal::pac::adc1::ctrl::CalAvgs; +use hal::pac::adc1::tctrl::Tcmd; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +const G_LPADC_RESULT_SHIFT: u32 = 0; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + unsafe { + init_adc_pins(); + } + + defmt::info!("=== ADC polling Example ==="); + + let adc_config = LpadcConfig { + enable_in_doze_mode: true, + conversion_average_mode: CalAvgs::Average128, + enable_analog_preliminary: true, + power_up_delay: 0x80, + reference_voltage_source: Refsel::Option3, + power_level_mode: Pwrsel::Lowest, + trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, + enable_conv_pause: false, + conv_pause_delay: 0, + fifo_watermark: 0, + power: PoweredClock::NormalEnabledDeepSleepDisabled, + source: AdcClockSel::FroLfDiv, + div: Div4::no_div(), + }; + let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + + adc.do_offset_calibration(); + adc.do_auto_calibration(); + + let mut conv_command_config = adc.get_default_conv_command_config(); + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + adc.set_conv_command_config(1, &conv_command_config); + + let mut conv_trigger_config = adc.get_default_conv_trigger_config(); + conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; + conv_trigger_config.enable_hardware_trigger = false; + adc.set_conv_trigger_config(0, &conv_trigger_config); + + defmt::info!("=== ADC configuration done... ==="); + + loop { + adc.do_software_trigger(1); + let mut result: Option = None; + while result.is_none() { + result = hal::adc::get_conv_result(); + } + let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; + defmt::info!("value: {=u16}", value); + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::gpio::{DriveStrength, Level, Output, SlewRate}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("Blink example"); + + let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast); + let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast); + let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast); + + loop { + defmt::info!("Toggle LEDs"); + + red.toggle(); + Timer::after_millis(250).await; + + red.toggle(); + green.toggle(); + Timer::after_millis(250).await; + + green.toggle(); + blue.toggle(); + Timer::after_millis(250).await; + blue.toggle(); + + Timer::after_millis(250).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::gpio::{Input, Pull}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("Button example"); + + // This button is labeled "WAKEUP" on the FRDM-MCXA276 + // The board already has a 10K pullup + let monitor = Input::new(p.P1_7, Pull::Disabled); + + loop { + defmt::info!("Pin level is {:?}", monitor.get_level()); + Timer::after_millis(1000).await; + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::gpio::{Input, Pull}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("GPIO interrupt example"); + + // This button is labeled "WAKEUP" on the FRDM-MCXA276 + // The board already has a 10K pullup + let mut pin = Input::new(p.P1_7, Pull::Disabled); + + let mut press_count = 0u32; + + loop { + pin.wait_for_falling_edge().await; + + press_count += 1; + + defmt::info!("Button pressed! Count: {}", press_count); + Timer::after_millis(50).await; + } +} diff --git a/examples/mcxa/src/bin/clkout.rs b/examples/mcxa/src/bin/clkout.rs new file mode 100644 index 000000000..bfd963540 --- /dev/null +++ b/examples/mcxa/src/bin/clkout.rs @@ -0,0 +1,69 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4}; +use embassy_mcxa::clocks::PoweredClock; +use embassy_mcxa::gpio::{DriveStrength, SlewRate}; +use embassy_mcxa::{Level, Output}; +use embassy_time::Timer; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Demonstrate CLKOUT, using Pin P4.2 +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + let mut pin = p.P4_2; + let mut clkout = p.CLKOUT; + + loop { + defmt::info!("Set Low..."); + let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); + Timer::after_millis(500).await; + + defmt::info!("Set High..."); + output.set_high(); + Timer::after_millis(400).await; + + defmt::info!("Set Low..."); + output.set_low(); + Timer::after_millis(500).await; + + defmt::info!("16k..."); + // Run Clock Out with the 16K clock + let _clock_out = ClockOut::new( + clkout.reborrow(), + pin.reborrow(), + Config { + sel: ClockOutSel::Clk16K, + div: Div4::no_div(), + level: PoweredClock::NormalEnabledDeepSleepDisabled, + }, + ) + .unwrap(); + + Timer::after_millis(3000).await; + + defmt::info!("Set Low..."); + drop(_clock_out); + + let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); + Timer::after_millis(500).await; + + // Run Clock Out with the 12M clock, divided by 3 + defmt::info!("4M..."); + let _clock_out = ClockOut::new( + clkout.reborrow(), + pin.reborrow(), + Config { + sel: ClockOutSel::Fro12M, + div: const { Div4::from_divisor(3).unwrap() }, + level: PoweredClock::NormalEnabledDeepSleepDisabled, + }, + ) + .unwrap(); + + // Let it run for 3 seconds... + Timer::after_millis(3000).await; + } +} diff --git a/examples/mcxa/src/bin/dma_channel_link.rs b/examples/mcxa/src/bin/dma_channel_link.rs new file mode 100644 index 000000000..92c7a9681 --- /dev/null +++ b/examples/mcxa/src/bin/dma_channel_link.rs @@ -0,0 +1,372 @@ +//! DMA channel linking example for MCXA276. +//! +//! This example demonstrates DMA channel linking (minor and major loop linking): +//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with: +//! - Minor Link to Channel 1 (triggers CH1 after each minor loop) +//! - Major Link to Channel 2 (triggers CH2 after major loop completes) +//! - Channel 1: Transfers SRC_BUFFER to DEST_BUFFER1 (triggered by CH0 minor link) +//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link) +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::new()` for channel creation +//! - `DmaChannel::is_done()` and `clear_done()` helper methods +//! - Channel linking with `set_minor_link()` and `set_major_link()` +//! - Standard `DmaCh*InterruptHandler` with `bind_interrupts!` macro + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler, DmaChannel}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Buffers +static mut SRC_BUFFER: [u32; 4] = [1, 2, 3, 4]; +static mut DEST_BUFFER0: [u32; 4] = [0; 4]; +static mut DEST_BUFFER1: [u32; 4] = [0; 4]; +static mut DEST_BUFFER2: [u32; 4] = [0; 4]; + +// Bind DMA channel interrupts using Embassy-style macro +// The standard handlers call on_interrupt() which wakes wakers and clears flags +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; + DMA_CH1 => DmaCh1InterruptHandler; + DMA_CH2 => DmaCh2InterruptHandler; +}); + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 channel link example starting..."); + + // DMA is initialized during hal::init() - no need to call ensure_init() + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + let dma0 = &pac_periphs.dma0; + let edma = unsafe { &*pac::Edma0Tcd0::ptr() }; + + // Clear any residual state + for i in 0..3 { + let t = edma.tcd(i); + t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one()); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + t.ch_es().write(|w| w.err().clear_bit_by_one()); + t.ch_mux().write(|w| unsafe { w.bits(0) }); + } + + // Clear Global Halt/Error state + dma0.mp_csr().modify(|_, w| { + w.halt() + .normal_operation() + .hae() + .normal_operation() + .ecx() + .normal_operation() + .cx() + .normal_operation() + }); + + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH2); + } + + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA channel link example begin.\r\n\r\n").unwrap(); + + // Initialize buffers + unsafe { + SRC_BUFFER = [1, 2, 3, 4]; + DEST_BUFFER0 = [0; 4]; + DEST_BUFFER1 = [0; 4]; + DEST_BUFFER2 = [0; 4]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST0 (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST1 (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST2 (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA channels with Embassy-style API...\r\n") + .unwrap(); + + let ch0 = DmaChannel::new(p.DMA_CH0); + let ch1 = DmaChannel::new(p.DMA_CH1); + let ch2 = DmaChannel::new(p.DMA_CH2); + + // Configure channels using direct TCD access (advanced feature demo) + // This example demonstrates channel linking which requires direct TCD manipulation + + // Helper to configure TCD for memory-to-memory transfer + // Parameters: channel, src, dst, width, nbytes (minor loop), count (major loop), interrupt + #[allow(clippy::too_many_arguments)] + unsafe fn configure_tcd( + edma: &embassy_mcxa::pac::edma_0_tcd0::RegisterBlock, + ch: usize, + src: u32, + dst: u32, + width: u8, + nbytes: u32, + count: u16, + enable_int: bool, + ) { + let t = edma.tcd(ch); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source/destination addresses + t.tcd_saddr().write(|w| w.saddr().bits(src)); + t.tcd_daddr().write(|w| w.daddr().bits(dst)); + + // Offsets: increment by width + t.tcd_soff().write(|w| w.soff().bits(width as u16)); + t.tcd_doff().write(|w| w.doff().bits(width as u16)); + + // Attributes: size = log2(width) + let size = match width { + 1 => 0, + 2 => 1, + 4 => 2, + _ => 0, + }; + t.tcd_attr().write(|w| w.ssize().bits(size).dsize().bits(size)); + + // Number of bytes per minor loop + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Major loop: reset source address after major loop + let total_bytes = nbytes * count as u32; + t.tcd_slast_sda() + .write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32)); + t.tcd_dlast_sga() + .write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32)); + + // Major loop count + t.tcd_biter_elinkno().write(|w| w.biter().bits(count)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(count)); + + // Control/status: enable interrupt if requested + if enable_int { + t.tcd_csr().write(|w| w.intmajor().set_bit()); + } else { + t.tcd_csr().write(|w| w.intmajor().clear_bit()); + } + + cortex_m::asm::dsb(); + } + + unsafe { + // Channel 0: Transfer 16 bytes total (8 bytes per minor loop, 2 major iterations) + // Minor Link -> Channel 1 + // Major Link -> Channel 2 + configure_tcd( + edma, + 0, + core::ptr::addr_of!(SRC_BUFFER) as u32, + core::ptr::addr_of_mut!(DEST_BUFFER0) as u32, + 4, // src width + 8, // nbytes (minor loop = 2 words) + 2, // count (major loop = 2 iterations) + false, // no interrupt + ); + ch0.set_minor_link(1); // Link to CH1 after each minor loop + ch0.set_major_link(2); // Link to CH2 after major loop + + // Channel 1: Transfer 16 bytes (triggered by CH0 minor link) + configure_tcd( + edma, + 1, + core::ptr::addr_of!(SRC_BUFFER) as u32, + core::ptr::addr_of_mut!(DEST_BUFFER1) as u32, + 4, + 16, // full buffer in one minor loop + 1, // 1 major iteration + false, + ); + + // Channel 2: Transfer 16 bytes (triggered by CH0 major link) + configure_tcd( + edma, + 2, + core::ptr::addr_of!(SRC_BUFFER) as u32, + core::ptr::addr_of_mut!(DEST_BUFFER2) as u32, + 4, + 16, // full buffer in one minor loop + 1, // 1 major iteration + true, // enable interrupt + ); + } + + tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n") + .unwrap(); + + // Trigger first minor loop of CH0 + unsafe { + ch0.trigger_start(); + } + + // Wait for CH1 to complete (triggered by CH0 minor link) + while !ch1.is_done() { + cortex_m::asm::nop(); + } + unsafe { + ch1.clear_done(); + } + + tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap(); + tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n") + .unwrap(); + + // Trigger second minor loop of CH0 + unsafe { + ch0.trigger_start(); + } + + // Wait for CH0 major loop to complete + while !ch0.is_done() { + cortex_m::asm::nop(); + } + unsafe { + ch0.clear_done(); + } + + tx.blocking_write(b"CH0 major loop done.\r\n").unwrap(); + + // Wait for CH2 to complete (triggered by CH0 major link) + // Using is_done() instead of AtomicBool - the standard interrupt handler + // clears the interrupt flag and wakes wakers, but DONE bit remains set + while !ch2.is_done() { + cortex_m::asm::nop(); + } + unsafe { + ch2.clear_done(); + } + + tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap(); + + tx.blocking_write(b"EDMA channel link example finish.\r\n\r\n").unwrap(); + + tx.blocking_write(b"DEST0 (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST1 (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"DEST2 (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify all buffers match source + let mut success = true; + unsafe { + let src_ptr = core::ptr::addr_of!(SRC_BUFFER) as *const u32; + let dst0_ptr = core::ptr::addr_of!(DEST_BUFFER0) as *const u32; + let dst1_ptr = core::ptr::addr_of!(DEST_BUFFER1) as *const u32; + let dst2_ptr = core::ptr::addr_of!(DEST_BUFFER2) as *const u32; + + for i in 0..4 { + if *dst0_ptr.add(i) != *src_ptr.add(i) { + success = false; + } + if *dst1_ptr.add(i) != *src_ptr.add(i) { + success = false; + } + if *dst2_ptr.add(i) != *src_ptr.add(i) { + success = false; + } + } + } + + if success { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } else { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } + + loop { + cortex_m::asm::wfe(); + } +} diff --git a/examples/mcxa/src/bin/dma_interleave_transfer.rs b/examples/mcxa/src/bin/dma_interleave_transfer.rs new file mode 100644 index 000000000..7876e8978 --- /dev/null +++ b/examples/mcxa/src/bin/dma_interleave_transfer.rs @@ -0,0 +1,215 @@ +//! DMA interleaved transfer example for MCXA276. +//! +//! This example demonstrates using DMA with custom source/destination offsets +//! to interleave data during transfer. +//! +//! # Embassy-style features demonstrated: +//! - `TransferOptions::default()` for configuration (used internally) +//! - DMA channel with `DmaChannel::new()` + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +const BUFFER_LENGTH: usize = 16; +const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2; + +// Buffers in RAM +static mut SRC_BUFFER: [u32; HALF_BUFF_LENGTH] = [0; HALF_BUFF_LENGTH]; +static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 interleave transfer example starting..."); + + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA interleave transfer example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC_BUFFER = [1, 2, 3, 4, 5, 6, 7, 8]; + DEST_BUFFER = [0; BUFFER_LENGTH]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, HALF_BUFF_LENGTH); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") + .unwrap(); + + // Create DMA channel using Embassy-style API + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure interleaved transfer using direct TCD access: + // - src_offset = 4: advance source by 4 bytes after each read + // - dst_offset = 8: advance dest by 8 bytes after each write + // This spreads source data across every other word in destination + unsafe { + let t = dma_ch0.tcd(); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source/destination addresses + t.tcd_saddr() + .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(SRC_BUFFER) as u32)); + t.tcd_daddr() + .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); + + // Custom offsets for interleaving + t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read + t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write + + // Attributes: 32-bit transfers (size = 2) + t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); + + // Transfer entire source buffer in one minor loop + let nbytes = (HALF_BUFF_LENGTH * 4) as u32; + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Reset source address after major loop + t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32)); + // Destination uses 2x offset, so adjust accordingly + let dst_total = (HALF_BUFF_LENGTH * 8) as u32; + t.tcd_dlast_sga() + .write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32)); + + // Major loop count = 1 + t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); + + // Enable interrupt on major loop completion + t.tcd_csr().write(|w| w.intmajor().set_bit()); + + cortex_m::asm::dsb(); + + tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); + dma_ch0.trigger_start(); + } + + // Wait for completion using channel helper method + while !dma_ch0.is_done() { + cortex_m::asm::nop(); + } + unsafe { + dma_ch0.clear_done(); + } + + tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0 + let mut mismatch = false; + unsafe { + for i in 0..BUFFER_LENGTH { + if i % 2 == 0 { + if DEST_BUFFER[i] != SRC_BUFFER[i / 2] { + mismatch = true; + } + } else if DEST_BUFFER[i] != 0 { + mismatch = true; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } + + loop { + cortex_m::asm::wfe(); + } +} 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..68f70e742 --- /dev/null +++ b/examples/mcxa/src/bin/dma_mem_to_mem.rs @@ -0,0 +1,229 @@ +//! DMA memory-to-memory transfer example for MCXA276. +//! +//! This example demonstrates using DMA to copy data between memory buffers +//! using the Embassy-style async API with type-safe transfers. +//! +//! # Embassy-style features demonstrated: +//! - `TransferOptions` for configuration +//! - Type-safe `mem_to_mem()` method with async `.await` +//! - `Transfer` Future that can be `.await`ed +//! - `Word` trait for automatic transfer width detection +//! - `memset()` method for filling memory with a pattern + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, TransferOptions}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +const BUFFER_LENGTH: usize = 4; + +// Buffers in RAM (static mut is automatically placed in .bss/.data) +static mut SRC_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; +static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; +static mut MEMSET_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; // u32 max is 4294967295 (10 digits) + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer as [v1, v2, v3, v4] to UART +/// Takes a raw pointer to avoid warnings about shared references to mutable statics +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const [u32; BUFFER_LENGTH]) { + tx.blocking_write(b"[").ok(); + unsafe { + let buf = &*buf_ptr; + for (i, val) in buf.iter().enumerate() { + write_u32(tx, *val); + if i < buf.len() - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 memory-to-memory example starting..."); + + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + // Create UART for debug output + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA memory to memory example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC_BUFFER = [1, 2, 3, 4]; + DEST_BUFFER = [0; BUFFER_LENGTH]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, &raw const SRC_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, &raw const DEST_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") + .unwrap(); + + // Create DMA channel + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure transfer options (Embassy-style) + // TransferOptions defaults to: complete_transfer_interrupt = true + let options = TransferOptions::default(); + + // ========================================================================= + // Part 1: Embassy-style async API demonstration (mem_to_mem) + // ========================================================================= + // + // Use the new type-safe `mem_to_mem()` method: + // - Automatically determines transfer width from buffer element type (u32) + // - Returns a `Transfer` future that can be `.await`ed + // - Uses TransferOptions for consistent configuration + // + // Using async `.await` - the executor can run other tasks while waiting! + + // Perform type-safe memory-to-memory transfer using Embassy-style async API + unsafe { + let src = &*core::ptr::addr_of!(SRC_BUFFER); + let dst = &mut *core::ptr::addr_of_mut!(DEST_BUFFER); + + // Using async `.await` - the executor can run other tasks while waiting! + let transfer = dma_ch0.mem_to_mem(src, dst, options); + transfer.await; + } + + tx.blocking_write(b"DMA mem-to-mem transfer complete!\r\n\r\n").unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, &raw const DEST_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + // Verify data + let mut mismatch = false; + unsafe { + for i in 0..BUFFER_LENGTH { + if SRC_BUFFER[i] != DEST_BUFFER[i] { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: mem_to_mem mismatch!\r\n").unwrap(); + defmt::error!("FAIL: mem_to_mem mismatch!"); + } else { + tx.blocking_write(b"PASS: mem_to_mem verified.\r\n\r\n").unwrap(); + defmt::info!("PASS: mem_to_mem verified."); + } + + // ========================================================================= + // Part 2: memset() demonstration + // ========================================================================= + // + // The `memset()` method fills a buffer with a pattern value: + // - Fixed source address (pattern is read repeatedly) + // - Incrementing destination address + // - Uses the same Transfer future pattern + + tx.blocking_write(b"--- Demonstrating memset() feature ---\r\n\r\n") + .unwrap(); + + tx.blocking_write(b"Memset Buffer (before): ").unwrap(); + print_buffer(&mut tx, &raw const MEMSET_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + // Fill buffer with a pattern value using DMA memset + let pattern: u32 = 0xDEADBEEF; + tx.blocking_write(b"Filling with pattern 0xDEADBEEF...\r\n").unwrap(); + + unsafe { + let dst = &mut *core::ptr::addr_of_mut!(MEMSET_BUFFER); + + // Using blocking_wait() for demonstration - also shows non-async usage + let transfer = dma_ch0.memset(&pattern, dst, options); + transfer.blocking_wait(); + } + + tx.blocking_write(b"DMA memset complete!\r\n\r\n").unwrap(); + tx.blocking_write(b"Memset Buffer (after): ").unwrap(); + print_buffer(&mut tx, &raw const MEMSET_BUFFER); + tx.blocking_write(b"\r\n").unwrap(); + + // Verify memset result + let mut memset_ok = true; + unsafe { + #[allow(clippy::needless_range_loop)] + for i in 0..BUFFER_LENGTH { + if MEMSET_BUFFER[i] != pattern { + memset_ok = false; + break; + } + } + } + + if !memset_ok { + tx.blocking_write(b"FAIL: memset mismatch!\r\n").unwrap(); + defmt::error!("FAIL: memset mismatch!"); + } else { + tx.blocking_write(b"PASS: memset verified.\r\n\r\n").unwrap(); + defmt::info!("PASS: memset verified."); + } + + tx.blocking_write(b"=== All DMA tests complete ===\r\n").unwrap(); + + loop { + cortex_m::asm::wfe(); + } +} diff --git a/examples/mcxa/src/bin/dma_memset.rs b/examples/mcxa/src/bin/dma_memset.rs new file mode 100644 index 000000000..95e365e47 --- /dev/null +++ b/examples/mcxa/src/bin/dma_memset.rs @@ -0,0 +1,218 @@ +//! DMA memset example for MCXA276. +//! +//! This example demonstrates using DMA to fill a buffer with a repeated pattern. +//! The source address stays fixed while the destination increments. +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::is_done()` and `clear_done()` helper methods +//! - No need to pass register block around + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +const BUFFER_LENGTH: usize = 4; + +// Buffers in RAM +static mut PATTERN: u32 = 0; +static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 memset example starting..."); + + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA memset example begin.\r\n\r\n").unwrap(); + + // Initialize buffers + unsafe { + PATTERN = 0xDEADBEEF; + DEST_BUFFER = [0; BUFFER_LENGTH]; + } + + tx.blocking_write(b"Pattern value: 0x").unwrap(); + // Print pattern in hex + unsafe { + let hex_chars = b"0123456789ABCDEF"; + let mut hex_buf = [0u8; 8]; + let mut val = PATTERN; + for i in (0..8).rev() { + hex_buf[i] = hex_chars[(val & 0xF) as usize]; + val >>= 4; + } + tx.blocking_write(&hex_buf).ok(); + } + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") + .unwrap(); + + // Create DMA channel using Embassy-style API + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure memset transfer using direct TCD access: + // Source stays fixed (soff = 0, reads same pattern repeatedly) + // Destination increments (doff = 4) + unsafe { + let t = dma_ch0.tcd(); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source address (pattern) - fixed + t.tcd_saddr() + .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(PATTERN) as u32)); + // Destination address - increments + t.tcd_daddr() + .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); + + // Source offset = 0 (stays fixed), Dest offset = 4 (increments) + t.tcd_soff().write(|w| w.soff().bits(0)); + t.tcd_doff().write(|w| w.doff().bits(4)); + + // Attributes: 32-bit transfers (size = 2) + t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); + + // Transfer entire buffer in one minor loop + let nbytes = (BUFFER_LENGTH * 4) as u32; + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Source doesn't need adjustment (stays fixed) + t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); + // Reset dest address after major loop + t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32)); + + // Major loop count = 1 + t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); + + // Enable interrupt on major loop completion + t.tcd_csr().write(|w| w.intmajor().set_bit()); + + cortex_m::asm::dsb(); + + tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); + dma_ch0.trigger_start(); + } + + // Wait for completion using channel helper method + while !dma_ch0.is_done() { + cortex_m::asm::nop(); + } + unsafe { + dma_ch0.clear_done(); + } + + tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n").unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: All elements should equal PATTERN + let mut mismatch = false; + unsafe { + #[allow(clippy::needless_range_loop)] + for i in 0..BUFFER_LENGTH { + if DEST_BUFFER[i] != PATTERN { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } + + loop { + cortex_m::asm::wfe(); + } +} diff --git a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs new file mode 100644 index 000000000..f8f543382 --- /dev/null +++ b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs @@ -0,0 +1,376 @@ +//! DMA ping-pong/double-buffer transfer example for MCXA276. +//! +//! This example demonstrates two approaches for ping-pong/double-buffering: +//! +//! ## Approach 1: Scatter/Gather with linked TCDs (manual) +//! - Two TCDs link to each other for alternating transfers +//! - Uses custom handler that delegates to on_interrupt() then signals completion +//! - Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +//! so we need an AtomicBool to track completion +//! +//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!) +//! - Single continuous transfer over entire buffer +//! - Uses half-transfer interrupt to know when first half is ready +//! - Application can process first half while second half is being filled +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::new()` for channel creation +//! - Scatter/gather with linked TCDs +//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) +//! - Standard `DmaCh1InterruptHandler` with `bind_interrupts!` macro +//! - NEW: `wait_half()` for half-transfer interrupt handling + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{self, DmaCh1InterruptHandler, DmaChannel, Tcd, TransferOptions}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Source and destination buffers for Approach 1 (scatter/gather) +static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; +static mut DST: [u32; 8] = [0; 8]; + +// Source and destination buffers for Approach 2 (wait_half) +static mut SRC2: [u32; 8] = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; +static mut DST2: [u32; 8] = [0; 8]; + +// TCD pool for scatter/gather - must be 32-byte aligned +#[repr(C, align(32))] +struct TcdPool([Tcd; 2]); + +static mut TCD_POOL: TcdPool = TcdPool( + [Tcd { + saddr: 0, + soff: 0, + attr: 0, + nbytes: 0, + slast: 0, + daddr: 0, + doff: 0, + citer: 0, + dlast_sga: 0, + csr: 0, + biter: 0, + }; 2], +); + +// AtomicBool to track scatter/gather completion +// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +// so we need this flag to detect when each transfer completes +static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); + +// Custom handler for scatter/gather that delegates to HAL's on_interrupt() +// This follows the "interrupts as threads" pattern - the handler does minimal work +// (delegates to HAL + sets a flag) and the main task does the actual processing +pub struct PingPongDmaHandler; + +impl embassy_mcxa::interrupt::typelevel::Handler for PingPongDmaHandler { + unsafe fn on_interrupt() { + // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers + dma::on_interrupt(0); + // Signal completion for polling (needed because ESG clears DONE bit) + TRANSFER_DONE.store(true, Ordering::Release); + } +} + +// Bind DMA channel interrupts +// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag) +// CH1: Standard handler for wait_half() demo +bind_interrupts!(struct Irqs { + DMA_CH0 => PingPongDmaHandler; + DMA_CH1 => DmaCh1InterruptHandler; +}); + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 ping-pong transfer example starting..."); + + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA ping-pong transfer example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC = [1, 2, 3, 4, 5, 6, 7, 8]; + DST = [0; 8]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring ping-pong DMA with Embassy-style API...\r\n") + .unwrap(); + + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure ping-pong transfer using direct TCD access: + // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. + // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1. + // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0. + unsafe { + let tcds = &mut *core::ptr::addr_of_mut!(TCD_POOL.0); + let src_ptr = core::ptr::addr_of!(SRC) as *const u32; + let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; + + let half_len = 4usize; + let half_bytes = (half_len * 4) as u32; + + let tcd0_addr = &tcds[0] as *const _ as u32; + let tcd1_addr = &tcds[1] as *const _ as u32; + + // TCD0: First half -> Links to TCD1 + tcds[0] = Tcd { + saddr: src_ptr as u32, + soff: 4, + attr: 0x0202, // 32-bit src/dst + nbytes: half_bytes, + slast: 0, + daddr: dst_ptr as u32, + doff: 4, + citer: 1, + dlast_sga: tcd1_addr as i32, + csr: 0x0012, // ESG | INTMAJOR + biter: 1, + }; + + // TCD1: Second half -> Links to TCD0 + tcds[1] = Tcd { + saddr: src_ptr.add(half_len) as u32, + soff: 4, + attr: 0x0202, + nbytes: half_bytes, + slast: 0, + daddr: dst_ptr.add(half_len) as u32, + doff: 4, + citer: 1, + dlast_sga: tcd0_addr as i32, + csr: 0x0012, + biter: 1, + }; + + // Load TCD0 into hardware registers + dma_ch0.load_tcd(&tcds[0]); + } + + tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); + + // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) + unsafe { + dma_ch0.trigger_start(); + } + + // Wait for first half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + tx.blocking_write(b"First half transferred.\r\n").unwrap(); + tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); + + // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) + unsafe { + dma_ch0.trigger_start(); + } + + // Wait for second half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); + + tx.blocking_write(b"EDMA ping-pong transfer example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: DST should match SRC + let mut mismatch = false; + unsafe { + let src_ptr = core::ptr::addr_of!(SRC) as *const u32; + let dst_ptr = core::ptr::addr_of!(DST) as *const u32; + for i in 0..8 { + if *src_ptr.add(i) != *dst_ptr.add(i) { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Approach 1 mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Approach 1 mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Approach 1 data verified.\r\n\r\n").unwrap(); + defmt::info!("PASS: Approach 1 data verified."); + } + + // ========================================================================= + // Approach 2: Half-Transfer Interrupt with wait_half() (NEW!) + // ========================================================================= + // + // This approach uses a single continuous DMA transfer with half-transfer + // interrupt enabled. The wait_half() method allows you to be notified + // when the first half of the buffer is complete, so you can process it + // while the second half is still being filled. + // + // Benefits: + // - Simpler setup (no TCD pool needed) + // - True async/await support + // - Good for streaming data processing + + tx.blocking_write(b"--- Approach 2: wait_half() demo ---\r\n\r\n") + .unwrap(); + + // Enable DMA CH1 interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); + } + + // Initialize approach 2 buffers + unsafe { + SRC2 = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; + DST2 = [0; 8]; + } + + tx.blocking_write(b"SRC2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + let dma_ch1 = DmaChannel::new(p.DMA_CH1); + + // Configure transfer with half-transfer interrupt enabled + let mut options = TransferOptions::default(); + options.half_transfer_interrupt = true; // Enable half-transfer interrupt + options.complete_transfer_interrupt = true; + + tx.blocking_write(b"Starting transfer with half_transfer_interrupt...\r\n") + .unwrap(); + + unsafe { + let src = &*core::ptr::addr_of!(SRC2); + let dst = &mut *core::ptr::addr_of_mut!(DST2); + + // Create the transfer + let mut transfer = dma_ch1.mem_to_mem(src, dst, options); + + // Wait for half-transfer (first 4 elements) + tx.blocking_write(b"Waiting for first half...\r\n").unwrap(); + let half_ok = transfer.wait_half().await; + + if half_ok { + tx.blocking_write(b"Half-transfer complete! First half of DST2: ") + .unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b"(Processing first half while second half transfers...)\r\n") + .unwrap(); + } + + // Wait for complete transfer + tx.blocking_write(b"Waiting for second half...\r\n").unwrap(); + transfer.await; + } + + tx.blocking_write(b"Transfer complete! Full DST2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 8); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify approach 2 + let mut mismatch2 = false; + unsafe { + let src_ptr = core::ptr::addr_of!(SRC2) as *const u32; + let dst_ptr = core::ptr::addr_of!(DST2) as *const u32; + for i in 0..8 { + if *src_ptr.add(i) != *dst_ptr.add(i) { + mismatch2 = true; + break; + } + } + } + + if mismatch2 { + tx.blocking_write(b"FAIL: Approach 2 mismatch!\r\n").unwrap(); + defmt::error!("FAIL: Approach 2 mismatch!"); + } else { + tx.blocking_write(b"PASS: Approach 2 verified.\r\n").unwrap(); + defmt::info!("PASS: Approach 2 verified."); + } + + tx.blocking_write(b"\r\n=== All ping-pong demos complete ===\r\n") + .unwrap(); + + loop { + cortex_m::asm::wfe(); + } +} diff --git a/examples/mcxa/src/bin/dma_scatter_gather.rs b/examples/mcxa/src/bin/dma_scatter_gather.rs new file mode 100644 index 000000000..4b26bc2ed --- /dev/null +++ b/examples/mcxa/src/bin/dma_scatter_gather.rs @@ -0,0 +1,262 @@ +//! DMA scatter-gather transfer example for MCXA276. +//! +//! This example demonstrates using DMA with scatter/gather to chain multiple +//! transfer descriptors. The first TCD transfers the first half of the buffer, +//! then automatically loads the second TCD to transfer the second half. +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::new()` for channel creation +//! - Scatter/gather with chained TCDs +//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{self, DmaChannel, Tcd}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Source and destination buffers +static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; +static mut DST: [u32; 8] = [0; 8]; + +// TCD pool for scatter/gather - must be 32-byte aligned +#[repr(C, align(32))] +struct TcdPool([Tcd; 2]); + +static mut TCD_POOL: TcdPool = TcdPool( + [Tcd { + saddr: 0, + soff: 0, + attr: 0, + nbytes: 0, + slast: 0, + daddr: 0, + doff: 0, + citer: 0, + dlast_sga: 0, + csr: 0, + biter: 0, + }; 2], +); + +// AtomicBool to track scatter/gather completion +// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +// so we need this flag to detect when each transfer completes +static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); + +// Custom handler for scatter/gather that delegates to HAL's on_interrupt() +// This follows the "interrupts as threads" pattern - the handler does minimal work +// (delegates to HAL + sets a flag) and the main task does the actual processing +pub struct ScatterGatherDmaHandler; + +impl embassy_mcxa::interrupt::typelevel::Handler + for ScatterGatherDmaHandler +{ + unsafe fn on_interrupt() { + // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers + dma::on_interrupt(0); + // Signal completion for polling (needed because ESG clears DONE bit) + TRANSFER_DONE.store(true, Ordering::Release); + } +} + +// Bind DMA channel interrupt +// Custom handler for scatter/gather (delegates to on_interrupt + sets flag) +bind_interrupts!(struct Irqs { + DMA_CH0 => ScatterGatherDmaHandler; +}); + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 transfer example starting..."); + + // DMA is initialized during hal::init() - no need to call ensure_init() + + // Enable DMA interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA scatter-gather transfer example begin.\r\n\r\n") + .unwrap(); + + // Initialize buffers + unsafe { + SRC = [1, 2, 3, 4, 5, 6, 7, 8]; + DST = [0; 8]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring scatter-gather DMA with Embassy-style API...\r\n") + .unwrap(); + + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure scatter-gather transfer using direct TCD access: + // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. + // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1. + // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD. + unsafe { + let tcds = core::slice::from_raw_parts_mut(core::ptr::addr_of_mut!(TCD_POOL.0) as *mut Tcd, 2); + let src_ptr = core::ptr::addr_of!(SRC) as *const u32; + let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; + + let num_tcds = 2usize; + let chunk_len = 4usize; // 8 / 2 + let chunk_bytes = (chunk_len * 4) as u32; + + for i in 0..num_tcds { + let is_last = i == num_tcds - 1; + let next_tcd_addr = if is_last { + 0 // No next TCD + } else { + &tcds[i + 1] as *const _ as u32 + }; + + tcds[i] = Tcd { + saddr: src_ptr.add(i * chunk_len) as u32, + soff: 4, + attr: 0x0202, // 32-bit src/dst + nbytes: chunk_bytes, + slast: 0, + daddr: dst_ptr.add(i * chunk_len) as u32, + doff: 4, + citer: 1, + dlast_sga: next_tcd_addr as i32, + // ESG (scatter/gather) for non-last, INTMAJOR for all + csr: if is_last { 0x0002 } else { 0x0012 }, + biter: 1, + }; + } + + // Load TCD0 into hardware registers + dma_ch0.load_tcd(&tcds[0]); + } + + tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); + + // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) + // TCD0 is currently loaded. + unsafe { + dma_ch0.trigger_start(); + } + + // Wait for first half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + tx.blocking_write(b"First half transferred.\r\n").unwrap(); + tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); + + // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) + // TCD1 should have been loaded by the scatter/gather engine. + unsafe { + dma_ch0.trigger_start(); + } + + // Wait for second half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); + + tx.blocking_write(b"EDMA scatter-gather transfer example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: DST should match SRC + let mut mismatch = false; + unsafe { + let src_ptr = core::ptr::addr_of!(SRC) as *const u32; + let dst_ptr = core::ptr::addr_of!(DST) as *const u32; + for i in 0..8 { + if *src_ptr.add(i) != *dst_ptr.add(i) { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } + + loop { + cortex_m::asm::wfe(); + } +} 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..e483bb81f --- /dev/null +++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs @@ -0,0 +1,231 @@ +//! 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::{DmaCh0InterruptHandler, DmaChannel, ScatterGatherBuilder}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +// Source buffers (multiple segments) +static mut SRC1: [u32; 4] = [0x11111111, 0x22222222, 0x33333333, 0x44444444]; +static mut SRC2: [u32; 4] = [0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD]; +static mut SRC3: [u32; 4] = [0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]; + +// Destination buffers (one per segment) +static mut DST1: [u32; 4] = [0; 4]; +static mut DST2: [u32; 4] = [0; 4]; +static mut DST3: [u32; 4] = [0; 4]; + +/// Helper to write a u32 as hex to UART +fn write_hex(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + const HEX: &[u8; 16] = b"0123456789ABCDEF"; + for i in (0..8).rev() { + let nibble = ((val >> (i * 4)) & 0xF) as usize; + tx.blocking_write(&[HEX[nibble]]).ok(); + } +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_hex(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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..."); + + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + // Create UART for debug output + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"DMA Scatter-Gather Builder Example\r\n").unwrap(); + tx.blocking_write(b"===================================\r\n\r\n") + .unwrap(); + + // Show source buffers + tx.blocking_write(b"Source buffers:\r\n").unwrap(); + tx.blocking_write(b" SRC1: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" SRC2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" SRC3: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(SRC3) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + tx.blocking_write(b"Destination buffers (before):\r\n").unwrap(); + tx.blocking_write(b" DST1: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" DST2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" DST3: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Create DMA channel + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + tx.blocking_write(b"Building scatter-gather chain with builder API...\r\n") + .unwrap(); + + // ========================================================================= + // 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::::new(); + + // Add three transfer segments - the builder handles TCD linking automatically + unsafe { + let src1 = &*core::ptr::addr_of!(SRC1); + let dst1 = &mut *core::ptr::addr_of_mut!(DST1); + builder.add_transfer(src1, dst1); + } + + unsafe { + let src2 = &*core::ptr::addr_of!(SRC2); + let dst2 = &mut *core::ptr::addr_of_mut!(DST2); + builder.add_transfer(src2, dst2); + } + + unsafe { + let src3 = &*core::ptr::addr_of!(SRC3); + let dst3 = &mut *core::ptr::addr_of_mut!(DST3); + builder.add_transfer(src3, dst3); + } + + tx.blocking_write(b"Added 3 transfer segments to chain.\r\n").unwrap(); + tx.blocking_write(b"Starting scatter-gather transfer with .await...\r\n\r\n") + .unwrap(); + + // 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 + unsafe { + let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather"); + transfer.blocking_wait(); + } + + tx.blocking_write(b"Scatter-gather transfer complete!\r\n\r\n").unwrap(); + + // Show results + tx.blocking_write(b"Destination buffers (after):\r\n").unwrap(); + tx.blocking_write(b" DST1: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" DST2: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + tx.blocking_write(b" DST3: ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify all three segments + let mut all_ok = true; + unsafe { + let src1 = core::ptr::addr_of!(SRC1) as *const u32; + let dst1 = core::ptr::addr_of!(DST1) as *const u32; + for i in 0..4 { + if *src1.add(i) != *dst1.add(i) { + all_ok = false; + } + } + + let src2 = core::ptr::addr_of!(SRC2) as *const u32; + let dst2 = core::ptr::addr_of!(DST2) as *const u32; + for i in 0..4 { + if *src2.add(i) != *dst2.add(i) { + all_ok = false; + } + } + + let src3 = core::ptr::addr_of!(SRC3) as *const u32; + let dst3 = core::ptr::addr_of!(DST3) as *const u32; + for i in 0..4 { + if *src3.add(i) != *dst3.add(i) { + all_ok = false; + } + } + } + + if all_ok { + tx.blocking_write(b"PASS: All segments verified!\r\n").unwrap(); + defmt::info!("PASS: All segments verified!"); + } else { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } + + tx.blocking_write(b"\r\n=== Scatter-Gather Builder example complete ===\r\n") + .unwrap(); + + loop { + cortex_m::asm::wfe(); + } +} 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..82936d9d0 --- /dev/null +++ b/examples/mcxa/src/bin/dma_wrap_transfer.rs @@ -0,0 +1,222 @@ +//! DMA wrap transfer example for MCXA276. +//! +//! This example demonstrates using DMA with modulo addressing to wrap around +//! a source buffer, effectively repeating the source data in the destination. +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::is_done()` and `clear_done()` helper methods +//! - No need to pass register block around + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; +use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel 0 interrupt using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; +}); + +// Source buffer: 4 words (16 bytes), aligned to 16 bytes for modulo +#[repr(align(16))] +struct AlignedSrc([u32; 4]); + +static mut SRC: AlignedSrc = AlignedSrc([0; 4]); +static mut DST: [u32; 8] = [0; 8]; + +/// Helper to write a u32 as decimal ASCII to UART +fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { + let mut buf = [0u8; 10]; + let mut n = val; + let mut i = buf.len(); + + if n == 0 { + tx.blocking_write(b"0").ok(); + return; + } + + while n > 0 { + i -= 1; + buf[i] = b'0' + (n % 10) as u8; + n /= 10; + } + + tx.blocking_write(&buf[i..]).ok(); +} + +/// Helper to print a buffer to UART +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { + tx.blocking_write(b"[").ok(); + unsafe { + for i in 0..len { + write_u32(tx, *buf_ptr.add(i)); + if i < len - 1 { + tx.blocking_write(b", ").ok(); + } + } + } + tx.blocking_write(b"]").ok(); +} + +#[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 wrap transfer example starting..."); + + // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + } + + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); + let (mut tx, _rx) = lpuart.split(); + + tx.blocking_write(b"EDMA wrap transfer example begin.\r\n\r\n").unwrap(); + + // Initialize buffers + unsafe { + SRC.0 = [1, 2, 3, 4]; + DST = [0; 8]; + } + + tx.blocking_write(b"Source Buffer: ").unwrap(); + print_buffer(&mut tx, unsafe { core::ptr::addr_of!(SRC.0) } as *const u32, 4); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Destination Buffer (before): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n").unwrap(); + + tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") + .unwrap(); + + // Create DMA channel using Embassy-style API + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure wrap transfer using direct TCD access: + // SRC is 16 bytes (4 * u32). We want to transfer 32 bytes (8 * u32). + // SRC modulo is 16 bytes (2^4 = 16) - wraps source address. + // DST modulo is 0 (disabled). + // This causes the source address to wrap around after 16 bytes, + // effectively repeating the source data. + unsafe { + let t = dma_ch0.tcd(); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source/destination addresses + t.tcd_saddr() + .write(|w| w.saddr().bits(core::ptr::addr_of!(SRC.0) as u32)); + t.tcd_daddr() + .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DST) as u32)); + + // Offsets: both increment by 4 bytes + t.tcd_soff().write(|w| w.soff().bits(4)); + t.tcd_doff().write(|w| w.doff().bits(4)); + + // Attributes: 32-bit transfers (size = 2) + // SMOD = 4 (2^4 = 16 byte modulo for source), DMOD = 0 (disabled) + t.tcd_attr().write(|w| { + w.ssize() + .bits(2) + .dsize() + .bits(2) + .smod() + .bits(4) // Source modulo: 2^4 = 16 bytes + .dmod() + .bits(0) // Dest modulo: disabled + }); + + // Transfer 32 bytes total in one minor loop + let nbytes = 32u32; + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Source wraps via modulo, no adjustment needed + t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); + // Reset dest address after major loop + t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32)); + + // Major loop count = 1 + t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); + + // Enable interrupt on major loop completion + t.tcd_csr().write(|w| w.intmajor().set_bit()); + + cortex_m::asm::dsb(); + + tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); + dma_ch0.trigger_start(); + } + + // Wait for completion using channel helper method + while !dma_ch0.is_done() { + cortex_m::asm::nop(); + } + unsafe { + dma_ch0.clear_done(); + } + + tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n") + .unwrap(); + tx.blocking_write(b"Destination Buffer (after): ").unwrap(); + print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); + tx.blocking_write(b"\r\n\r\n").unwrap(); + + // Verify: DST should be [1, 2, 3, 4, 1, 2, 3, 4] + let expected = [1u32, 2, 3, 4, 1, 2, 3, 4]; + let mut mismatch = false; + unsafe { + for i in 0..8 { + if DST[i] != expected[i] { + mismatch = true; + break; + } + } + } + + if mismatch { + tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); + defmt::error!("FAIL: Mismatch detected!"); + } else { + tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); + defmt::info!("PASS: Data verified."); + } + + loop { + cortex_m::asm::wfe(); + } +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use hal::lpuart::{Blocking, Config, Lpuart}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Simple helper to write a byte as hex to UART +fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) { + const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; + let _ = uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); + let _ = uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + 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!("boot"); + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX + let mut uart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.P2_2, // TX pin + p.P2_3, // RX pin + config, + ) + .unwrap(); + + // Print welcome message before any async delays to guarantee early console output + uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); + uart.write_str_blocking("Available commands:\r\n"); + uart.write_str_blocking(" help - Show this help\r\n"); + uart.write_str_blocking(" echo - Echo back the text\r\n"); + uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); + uart.write_str_blocking("Type a command: "); + + let mut buffer = [0u8; 64]; + let mut buf_idx = 0; + + loop { + // Read a byte from UART + let byte = uart.read_byte_blocking(); + + // Echo the character back + if byte == b'\r' || byte == b'\n' { + // Enter pressed - process command + uart.write_str_blocking("\r\n"); + + if buf_idx > 0 { + let command = &buffer[0..buf_idx]; + + if command == b"help" { + uart.write_str_blocking("Available commands:\r\n"); + uart.write_str_blocking(" help - Show this help\r\n"); + uart.write_str_blocking(" echo - Echo back the text\r\n"); + uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); + } else if command.starts_with(b"echo ") && command.len() > 5 { + uart.write_str_blocking("Echo: "); + uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or("")); + uart.write_str_blocking("\r\n"); + } else if command.starts_with(b"hex ") && command.len() > 4 { + // Parse the byte value + let num_str = &command[4..]; + if let Ok(num) = parse_u8(num_str) { + uart.write_str_blocking("Hex: 0x"); + write_hex_byte(&mut uart, num); + uart.write_str_blocking("\r\n"); + } else { + uart.write_str_blocking("Invalid number for hex command\r\n"); + } + } else if !command.is_empty() { + uart.write_str_blocking("Unknown command: "); + uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); + uart.write_str_blocking("\r\n"); + } + } + + // Reset buffer and prompt + buf_idx = 0; + uart.write_str_blocking("Type a command: "); + } else if byte == 8 || byte == 127 { + // Backspace + if buf_idx > 0 { + buf_idx -= 1; + uart.write_str_blocking("\x08 \x08"); // Erase character + } + } else if buf_idx < buffer.len() - 1 { + // Regular character + buffer[buf_idx] = byte; + buf_idx += 1; + let _ = uart.write_byte(byte); + } + } +} + +/// Simple parser for u8 from ASCII bytes +fn parse_u8(bytes: &[u8]) -> Result { + let mut result = 0u8; + for &b in bytes { + if b.is_ascii_digit() { + result = result.checked_mul(10).ok_or(())?; + result = result.checked_add(b - b'0').ok_or(())?; + } else { + return Err(()); + } + } + Ok(result) +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_time::Timer; +use hal::clocks::config::Div8; +use hal::config::Config; +use hal::i2c::controller::{self, I2c, Speed}; +use tmp108::Tmp108; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); + + defmt::info!("I2C example"); + + let mut config = controller::Config::default(); + config.speed = Speed::Standard; + let i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap(); + let mut tmp = Tmp108::new_with_a0_gnd(i2c); + + loop { + let temperature = tmp.temperature().unwrap(); + defmt::info!("Temperature: {}C", temperature); + Timer::after_secs(1).await; + } +} 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..4e203597b --- /dev/null +++ b/examples/mcxa/src/bin/i2c-scan-blocking.rs @@ -0,0 +1,41 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::gpio::Pull; +use embassy_mcxa::Input; +use embassy_time::Timer; +use hal::clocks::config::Div8; +use hal::config::Config; +use hal::i2c::controller::{self, I2c, Speed}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); + + defmt::info!("I2C example"); + + let mut config = controller::Config::default(); + config.speed = Speed::Standard; + + // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and + // defaults to SWO on the debug peripheral. Explicitly make it a high-z + // input. + let _pin = Input::new(p.P0_2, Pull::Disabled); + let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap(); + + for addr in 0x01..=0x7f { + let result = i2c.blocking_write(addr, &[]); + if result.is_ok() { + defmt::info!("Device found at addr {:02x}", addr); + } + } + + loop { + Timer::after_secs(10).await; + } +} diff --git a/examples/mcxa/src/bin/lpuart_buffered.rs b/examples/mcxa/src/bin/lpuart_buffered.rs new file mode 100644 index 000000000..420589d00 --- /dev/null +++ b/examples/mcxa/src/bin/lpuart_buffered.rs @@ -0,0 +1,62 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::lpuart::buffered::BufferedLpuart; +use embassy_mcxa::lpuart::Config; +use embassy_mcxa::{bind_interrupts, lpuart}; +use embedded_io_async::Write; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver +bind_interrupts!(struct Irqs { + LPUART2 => lpuart::buffered::BufferedInterruptHandler::; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + 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); + + // Configure NVIC for LPUART2 + hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); + + // UART configuration (enable both TX and RX) + let config = Config { + baudrate_bps: 115_200, + rx_fifo_watermark: 0, + tx_fifo_watermark: 0, + ..Default::default() + }; + + let mut tx_buf = [0u8; 256]; + let mut rx_buf = [0u8; 256]; + + // Create a buffered LPUART2 instance with both TX and RX + let mut uart = BufferedLpuart::new( + p.LPUART2, + p.P2_2, // TX pin + p.P2_3, // RX pin + Irqs, + &mut tx_buf, + &mut rx_buf, + config, + ) + .unwrap(); + + // Split into TX and RX parts + let (tx, rx) = uart.split_ref(); + + tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); + tx.write(b"Type characters to echo them back.\r\n").await.unwrap(); + + // Echo loop + let mut buf = [0u8; 4]; + loop { + let used = rx.read(&mut buf).await.unwrap(); + tx.write_all(&buf[..used]).await.unwrap(); + } +} diff --git a/examples/mcxa/src/bin/lpuart_dma.rs b/examples/mcxa/src/bin/lpuart_dma.rs new file mode 100644 index 000000000..5497f8646 --- /dev/null +++ b/examples/mcxa/src/bin/lpuart_dma.rs @@ -0,0 +1,81 @@ +//! LPUART DMA example for MCXA276. +//! +//! This example demonstrates using DMA for UART TX and RX operations. +//! It sends a message using DMA, then waits for 16 characters to be received +//! via DMA and echoes them back. +//! +//! The DMA request sources are automatically derived from the LPUART instance type. +//! DMA clock/reset/init is handled automatically by the HAL. + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; +use embassy_mcxa::lpuart::{Config, LpuartDma}; +use embassy_mcxa::{bind_interrupts, pac}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel interrupts using Embassy-style macro +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; + DMA_CH1 => DmaCh1InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + 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!("LPUART DMA example starting..."); + + // Enable DMA interrupts (per-channel, as needed) + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); + } + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + // Create UART instance with DMA channels + let mut lpuart = LpuartDma::new( + p.LPUART2, p.P2_2, // TX pin + p.P2_3, // RX pin + p.DMA_CH0, // TX DMA channel + p.DMA_CH1, // RX DMA channel + config, + ) + .unwrap(); + + // Send a message using DMA (DMA request source is automatically derived from LPUART2) + let tx_msg = b"Hello from LPUART2 DMA TX!\r\n"; + lpuart.write_dma(tx_msg).await.unwrap(); + + defmt::info!("TX DMA complete"); + + // Send prompt + let prompt = b"Type 16 characters to echo via DMA:\r\n"; + lpuart.write_dma(prompt).await.unwrap(); + + // Receive 16 characters using DMA + let mut rx_buf = [0u8; 16]; + lpuart.read_dma(&mut rx_buf).await.unwrap(); + + defmt::info!("RX DMA complete"); + + // Echo back the received data + let echo_prefix = b"\r\nReceived: "; + lpuart.write_dma(echo_prefix).await.unwrap(); + lpuart.write_dma(&rx_buf).await.unwrap(); + let done_msg = b"\r\nDone!\r\n"; + lpuart.write_dma(done_msg).await.unwrap(); + + defmt::info!("Example complete"); +} 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 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +use crate::hal::lpuart::{Config, Lpuart}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + 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!("boot"); + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX + let lpuart = Lpuart::new_blocking( + p.LPUART2, // Peripheral + p.P2_2, // TX pin + p.P2_3, // RX pin + config, + ) + .unwrap(); + + // Split into separate TX and RX parts + let (mut tx, mut rx) = lpuart.split(); + + // Write hello messages + tx.blocking_write(b"Hello world.\r\n").unwrap(); + tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap(); + + // Echo loop + loop { + let mut buf = [0u8; 1]; + rx.blocking_read(&mut buf).unwrap(); + tx.blocking_write(&buf).unwrap(); + } +} 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..1d1a51970 --- /dev/null +++ b/examples/mcxa/src/bin/lpuart_ring_buffer.rs @@ -0,0 +1,130 @@ +//! LPUART Ring Buffer DMA example for MCXA276. +//! +//! This example demonstrates using the high-level `LpuartRxDma::setup_ring_buffer()` +//! API for continuous circular DMA reception from a UART peripheral. +//! +//! # Features demonstrated: +//! - `LpuartRxDma::setup_ring_buffer()` for continuous peripheral-to-memory DMA +//! - `RingBuffer` for async reading of received data +//! - Handling of potential overrun conditions +//! - Half-transfer and complete-transfer interrupts for timely wakeups +//! +//! # How it works: +//! 1. Create an `LpuartRxDma` driver with a DMA channel +//! 2. Call `setup_ring_buffer()` which handles all low-level DMA configuration +//! 3. Application asynchronously reads data as it arrives via `ring_buf.read()` +//! 4. Both half-transfer and complete-transfer interrupts wake the reader + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::bind_interrupts; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; +use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Bind DMA channel interrupts +bind_interrupts!(struct Irqs { + DMA_CH0 => DmaCh0InterruptHandler; + DMA_CH1 => DmaCh1InterruptHandler; +}); + +// Ring buffer for RX - power of 2 is ideal for modulo efficiency +static mut RX_RING_BUFFER: [u8; 64] = [0; 64]; + +/// Helper to write a byte as hex to UART +fn write_hex( + tx: &mut LpuartTxDma<'_, T, C>, + byte: u8, +) { + const HEX: &[u8; 16] = b"0123456789ABCDEF"; + let buf = [HEX[(byte >> 4) as usize], HEX[(byte & 0x0F) as usize]]; + tx.blocking_write(&buf).ok(); +} + +#[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!("LPUART Ring Buffer DMA example starting..."); + + // Create UART configuration + let config = Config { + baudrate_bps: 115_200, + ..Default::default() + }; + + // Create LPUART with DMA support for both TX and RX, then split + // This is the proper Embassy pattern - create once, split into TX and RX + let lpuart = LpuartDma::new(p.LPUART2, p.P2_2, p.P2_3, p.DMA_CH1, p.DMA_CH0, config).unwrap(); + let (mut tx, rx) = lpuart.split(); + + tx.blocking_write(b"LPUART Ring Buffer DMA Example\r\n").unwrap(); + tx.blocking_write(b"==============================\r\n\r\n").unwrap(); + + tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n") + .unwrap(); + + // Set up the ring buffer with circular DMA + // The HAL handles: DMA request source, RDMAE enable, circular transfer config, NVIC enable + let ring_buf = unsafe { + let buf = &mut *core::ptr::addr_of_mut!(RX_RING_BUFFER); + rx.setup_ring_buffer(buf) + }; + + // Enable DMA requests to start continuous reception + unsafe { + rx.enable_dma_request(); + } + + tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n") + .unwrap(); + tx.blocking_write(b"The DMA continuously receives in the background.\r\n\r\n") + .unwrap(); + + // Main loop: read from ring buffer and echo back + let mut read_buf = [0u8; 16]; + let mut total_received: usize = 0; + + loop { + // Async read - waits until data is available + match ring_buf.read(&mut read_buf).await { + Ok(n) if n > 0 => { + total_received += n; + + // Echo back what we received + tx.blocking_write(b"RX[").unwrap(); + for (i, &byte) in read_buf.iter().enumerate().take(n) { + write_hex(&mut tx, byte); + if i < n - 1 { + tx.blocking_write(b" ").unwrap(); + } + } + tx.blocking_write(b"]: ").unwrap(); + tx.blocking_write(&read_buf[..n]).unwrap(); + tx.blocking_write(b"\r\n").unwrap(); + + defmt::info!("Received {} bytes, total: {}", n, total_received); + } + Ok(_) => { + // No data, shouldn't happen with async read + } + Err(_) => { + // Overrun detected + tx.blocking_write(b"ERROR: Ring buffer overrun!\r\n").unwrap(); + defmt::error!("Ring buffer overrun!"); + ring_buf.clear(); + } + } + } +} diff --git a/examples/mcxa/src/bin/rtc_alarm.rs b/examples/mcxa/src/bin/rtc_alarm.rs new file mode 100644 index 000000000..a7800a2d1 --- /dev/null +++ b/examples/mcxa/src/bin/rtc_alarm.rs @@ -0,0 +1,74 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa as hal; +use hal::rtc::{RtcDateTime, RtcInterruptEnable}; +use hal::InterruptExt; + +type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>; + +use embassy_mcxa::bind_interrupts; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + RTC => hal::rtc::RtcHandler; +}); + +#[used] +#[no_mangle] +static KEEP_RTC: unsafe extern "C" fn() = RTC; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = hal::init(hal::config::Config::default()); + + defmt::info!("=== RTC Alarm Example ==="); + + let rtc_config = hal::rtc::get_default_config(); + + let rtc = MyRtc::new(p.RTC0, rtc_config); + + let now = RtcDateTime { + year: 2025, + month: 10, + day: 15, + hour: 14, + minute: 30, + second: 0, + }; + + rtc.stop(); + + defmt::info!("Time set to: 2025-10-15 14:30:00"); + rtc.set_datetime(now); + + let mut alarm = now; + alarm.second += 10; + + rtc.set_alarm(alarm); + defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)"); + + rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); + + unsafe { + hal::interrupt::RTC.enable(); + } + + unsafe { + cortex_m::interrupt::enable(); + } + + rtc.start(); + + defmt::info!("RTC started, waiting for alarm..."); + + loop { + if rtc.is_alarm_triggered() { + defmt::info!("*** ALARM TRIGGERED! ***"); + break; + } + } + + defmt::info!("Example complete - Test PASSED!"); +} diff --git a/examples/mcxa/src/lib.rs b/examples/mcxa/src/lib.rs new file mode 100644 index 000000000..2573a6adc --- /dev/null +++ b/examples/mcxa/src/lib.rs @@ -0,0 +1,16 @@ +#![no_std] +#![allow(clippy::missing_safety_doc)] + +//! Shared board-specific helpers for the FRDM-MCXA276 examples. +//! These live with the examples so the HAL stays generic. + +use hal::{clocks, pins}; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +/// Initialize clocks and pin muxing for ADC. +pub unsafe fn init_adc_pins() { + // NOTE: Lpuart has been updated to properly enable + reset its own clocks. + // GPIO has not. + _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); + pins::configure_adc_pins(); +} diff --git a/examples/memory.x b/examples/memory.x deleted file mode 100644 index 315ced58a..000000000 --- a/examples/memory.x +++ /dev/null @@ -1,5 +0,0 @@ -MEMORY -{ - FLASH : ORIGIN = 0x00000000, LENGTH = 1M - RAM : ORIGIN = 0x20000000, LENGTH = 128K -} diff --git a/examples/src/bin/adc_interrupt.rs b/examples/src/bin/adc_interrupt.rs deleted file mode 100644 index 83d8046b3..000000000 --- a/examples/src/bin/adc_interrupt.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa_examples::init_adc_pins; -use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::periph_helpers::{AdcClockSel, Div4}; -use hal::clocks::PoweredClock; -use hal::pac::adc1::cfg::{Pwrsel, Refsel}; -use hal::pac::adc1::cmdl1::{Adch, Mode}; -use hal::pac::adc1::ctrl::CalAvgs; -use hal::pac::adc1::tctrl::Tcmd; -use hal::{bind_interrupts, InterruptExt}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -bind_interrupts!(struct Irqs { - ADC1 => hal::adc::AdcHandler; -}); - -#[used] -#[no_mangle] -static KEEP_ADC: unsafe extern "C" fn() = ADC1; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("ADC interrupt Example"); - - unsafe { - init_adc_pins(); - } - - let adc_config = LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::Average128, - enable_analog_preliminary: true, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option3, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, - power: PoweredClock::NormalEnabledDeepSleepDisabled, - source: AdcClockSel::FroLfDiv, - div: Div4::no_div(), - }; - let adc = hal::adc::Adc::::new(p.ADC1, adc_config); - - adc.do_offset_calibration(); - adc.do_auto_calibration(); - - let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits; - adc.set_conv_command_config(1, &conv_command_config); - - let mut conv_trigger_config = adc.get_default_conv_trigger_config(); - conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; - conv_trigger_config.enable_hardware_trigger = false; - adc.set_conv_trigger_config(0, &conv_trigger_config); - - defmt::info!("ADC configuration done..."); - - adc.enable_interrupt(0x1); - - unsafe { - hal::interrupt::ADC1.enable(); - } - - unsafe { - cortex_m::interrupt::enable(); - } - - loop { - adc.do_software_trigger(1); - while !adc.is_interrupt_triggered() { - // Wait until the interrupt is triggered - } - defmt::info!("*** ADC interrupt TRIGGERED! ***"); - //TBD need to print the value - } -} diff --git a/examples/src/bin/adc_polling.rs b/examples/src/bin/adc_polling.rs deleted file mode 100644 index ddf3f586b..000000000 --- a/examples/src/bin/adc_polling.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa_examples::init_adc_pins; -use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::periph_helpers::{AdcClockSel, Div4}; -use hal::clocks::PoweredClock; -use hal::pac::adc1::cfg::{Pwrsel, Refsel}; -use hal::pac::adc1::cmdl1::{Adch, Mode}; -use hal::pac::adc1::ctrl::CalAvgs; -use hal::pac::adc1::tctrl::Tcmd; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -const G_LPADC_RESULT_SHIFT: u32 = 0; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - unsafe { - init_adc_pins(); - } - - defmt::info!("=== ADC polling Example ==="); - - let adc_config = LpadcConfig { - enable_in_doze_mode: true, - conversion_average_mode: CalAvgs::Average128, - enable_analog_preliminary: true, - power_up_delay: 0x80, - reference_voltage_source: Refsel::Option3, - power_level_mode: Pwrsel::Lowest, - trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, - enable_conv_pause: false, - conv_pause_delay: 0, - fifo_watermark: 0, - power: PoweredClock::NormalEnabledDeepSleepDisabled, - source: AdcClockSel::FroLfDiv, - div: Div4::no_div(), - }; - let adc = hal::adc::Adc::::new(p.ADC1, adc_config); - - adc.do_offset_calibration(); - adc.do_auto_calibration(); - - let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits; - adc.set_conv_command_config(1, &conv_command_config); - - let mut conv_trigger_config = adc.get_default_conv_trigger_config(); - conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; - conv_trigger_config.enable_hardware_trigger = false; - adc.set_conv_trigger_config(0, &conv_trigger_config); - - defmt::info!("=== ADC configuration done... ==="); - - loop { - adc.do_software_trigger(1); - let mut result: Option = None; - while result.is_none() { - result = hal::adc::get_conv_result(); - } - let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; - defmt::info!("value: {=u16}", value); - } -} diff --git a/examples/src/bin/blinky.rs b/examples/src/bin/blinky.rs deleted file mode 100644 index dd08ec0d9..000000000 --- a/examples/src/bin/blinky.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::gpio::{DriveStrength, Level, Output, SlewRate}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("Blink example"); - - let mut red = Output::new(p.P3_18, Level::High, DriveStrength::Normal, SlewRate::Fast); - let mut green = Output::new(p.P3_19, Level::High, DriveStrength::Normal, SlewRate::Fast); - let mut blue = Output::new(p.P3_21, Level::High, DriveStrength::Normal, SlewRate::Fast); - - loop { - defmt::info!("Toggle LEDs"); - - red.toggle(); - Timer::after_millis(250).await; - - red.toggle(); - green.toggle(); - Timer::after_millis(250).await; - - green.toggle(); - blue.toggle(); - Timer::after_millis(250).await; - blue.toggle(); - - Timer::after_millis(250).await; - } -} diff --git a/examples/src/bin/button.rs b/examples/src/bin/button.rs deleted file mode 100644 index 943edbb15..000000000 --- a/examples/src/bin/button.rs +++ /dev/null @@ -1,23 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::gpio::{Input, Pull}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("Button example"); - - // This button is labeled "WAKEUP" on the FRDM-MCXA276 - // The board already has a 10K pullup - let monitor = Input::new(p.P1_7, Pull::Disabled); - - loop { - defmt::info!("Pin level is {:?}", monitor.get_level()); - Timer::after_millis(1000).await; - } -} diff --git a/examples/src/bin/button_async.rs b/examples/src/bin/button_async.rs deleted file mode 100644 index 6cc7b62cd..000000000 --- a/examples/src/bin/button_async.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::gpio::{Input, Pull}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("GPIO interrupt example"); - - // This button is labeled "WAKEUP" on the FRDM-MCXA276 - // The board already has a 10K pullup - let mut pin = Input::new(p.P1_7, Pull::Disabled); - - let mut press_count = 0u32; - - loop { - pin.wait_for_falling_edge().await; - - press_count += 1; - - defmt::info!("Button pressed! Count: {}", press_count); - Timer::after_millis(50).await; - } -} diff --git a/examples/src/bin/clkout.rs b/examples/src/bin/clkout.rs deleted file mode 100644 index bfd963540..000000000 --- a/examples/src/bin/clkout.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clkout::{ClockOut, ClockOutSel, Config, Div4}; -use embassy_mcxa::clocks::PoweredClock; -use embassy_mcxa::gpio::{DriveStrength, SlewRate}; -use embassy_mcxa::{Level, Output}; -use embassy_time::Timer; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -/// Demonstrate CLKOUT, using Pin P4.2 -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - let mut pin = p.P4_2; - let mut clkout = p.CLKOUT; - - loop { - defmt::info!("Set Low..."); - let mut output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); - Timer::after_millis(500).await; - - defmt::info!("Set High..."); - output.set_high(); - Timer::after_millis(400).await; - - defmt::info!("Set Low..."); - output.set_low(); - Timer::after_millis(500).await; - - defmt::info!("16k..."); - // Run Clock Out with the 16K clock - let _clock_out = ClockOut::new( - clkout.reborrow(), - pin.reborrow(), - Config { - sel: ClockOutSel::Clk16K, - div: Div4::no_div(), - level: PoweredClock::NormalEnabledDeepSleepDisabled, - }, - ) - .unwrap(); - - Timer::after_millis(3000).await; - - defmt::info!("Set Low..."); - drop(_clock_out); - - let _output = Output::new(pin.reborrow(), Level::Low, DriveStrength::Normal, SlewRate::Slow); - Timer::after_millis(500).await; - - // Run Clock Out with the 12M clock, divided by 3 - defmt::info!("4M..."); - let _clock_out = ClockOut::new( - clkout.reborrow(), - pin.reborrow(), - Config { - sel: ClockOutSel::Fro12M, - div: const { Div4::from_divisor(3).unwrap() }, - level: PoweredClock::NormalEnabledDeepSleepDisabled, - }, - ) - .unwrap(); - - // Let it run for 3 seconds... - Timer::after_millis(3000).await; - } -} diff --git a/examples/src/bin/dma_channel_link.rs b/examples/src/bin/dma_channel_link.rs deleted file mode 100644 index 92c7a9681..000000000 --- a/examples/src/bin/dma_channel_link.rs +++ /dev/null @@ -1,372 +0,0 @@ -//! DMA channel linking example for MCXA276. -//! -//! This example demonstrates DMA channel linking (minor and major loop linking): -//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with: -//! - Minor Link to Channel 1 (triggers CH1 after each minor loop) -//! - Major Link to Channel 2 (triggers CH2 after major loop completes) -//! - Channel 1: Transfers SRC_BUFFER to DEST_BUFFER1 (triggered by CH0 minor link) -//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link) -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::new()` for channel creation -//! - `DmaChannel::is_done()` and `clear_done()` helper methods -//! - Channel linking with `set_minor_link()` and `set_major_link()` -//! - Standard `DmaCh*InterruptHandler` with `bind_interrupts!` macro - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler, DmaChannel}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Buffers -static mut SRC_BUFFER: [u32; 4] = [1, 2, 3, 4]; -static mut DEST_BUFFER0: [u32; 4] = [0; 4]; -static mut DEST_BUFFER1: [u32; 4] = [0; 4]; -static mut DEST_BUFFER2: [u32; 4] = [0; 4]; - -// Bind DMA channel interrupts using Embassy-style macro -// The standard handlers call on_interrupt() which wakes wakers and clears flags -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; - DMA_CH1 => DmaCh1InterruptHandler; - DMA_CH2 => DmaCh2InterruptHandler; -}); - -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); -} - -#[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 channel link example starting..."); - - // DMA is initialized during hal::init() - no need to call ensure_init() - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - let dma0 = &pac_periphs.dma0; - let edma = unsafe { &*pac::Edma0Tcd0::ptr() }; - - // Clear any residual state - for i in 0..3 { - let t = edma.tcd(i); - t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one()); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - t.ch_es().write(|w| w.err().clear_bit_by_one()); - t.ch_mux().write(|w| unsafe { w.bits(0) }); - } - - // Clear Global Halt/Error state - dma0.mp_csr().modify(|_, w| { - w.halt() - .normal_operation() - .hae() - .normal_operation() - .ecx() - .normal_operation() - .cx() - .normal_operation() - }); - - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH2); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA channel link example begin.\r\n\r\n").unwrap(); - - // Initialize buffers - unsafe { - SRC_BUFFER = [1, 2, 3, 4]; - DEST_BUFFER0 = [0; 4]; - DEST_BUFFER1 = [0; 4]; - DEST_BUFFER2 = [0; 4]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST0 (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST1 (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST2 (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA channels with Embassy-style API...\r\n") - .unwrap(); - - let ch0 = DmaChannel::new(p.DMA_CH0); - let ch1 = DmaChannel::new(p.DMA_CH1); - let ch2 = DmaChannel::new(p.DMA_CH2); - - // Configure channels using direct TCD access (advanced feature demo) - // This example demonstrates channel linking which requires direct TCD manipulation - - // Helper to configure TCD for memory-to-memory transfer - // Parameters: channel, src, dst, width, nbytes (minor loop), count (major loop), interrupt - #[allow(clippy::too_many_arguments)] - unsafe fn configure_tcd( - edma: &embassy_mcxa::pac::edma_0_tcd0::RegisterBlock, - ch: usize, - src: u32, - dst: u32, - width: u8, - nbytes: u32, - count: u16, - enable_int: bool, - ) { - let t = edma.tcd(ch); - - // Reset channel state - t.ch_csr().write(|w| { - w.erq() - .disable() - .earq() - .disable() - .eei() - .no_error() - .ebw() - .disable() - .done() - .clear_bit_by_one() - }); - t.ch_es().write(|w| w.bits(0)); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - - // Source/destination addresses - t.tcd_saddr().write(|w| w.saddr().bits(src)); - t.tcd_daddr().write(|w| w.daddr().bits(dst)); - - // Offsets: increment by width - t.tcd_soff().write(|w| w.soff().bits(width as u16)); - t.tcd_doff().write(|w| w.doff().bits(width as u16)); - - // Attributes: size = log2(width) - let size = match width { - 1 => 0, - 2 => 1, - 4 => 2, - _ => 0, - }; - t.tcd_attr().write(|w| w.ssize().bits(size).dsize().bits(size)); - - // Number of bytes per minor loop - t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); - - // Major loop: reset source address after major loop - let total_bytes = nbytes * count as u32; - t.tcd_slast_sda() - .write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32)); - t.tcd_dlast_sga() - .write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32)); - - // Major loop count - t.tcd_biter_elinkno().write(|w| w.biter().bits(count)); - t.tcd_citer_elinkno().write(|w| w.citer().bits(count)); - - // Control/status: enable interrupt if requested - if enable_int { - t.tcd_csr().write(|w| w.intmajor().set_bit()); - } else { - t.tcd_csr().write(|w| w.intmajor().clear_bit()); - } - - cortex_m::asm::dsb(); - } - - unsafe { - // Channel 0: Transfer 16 bytes total (8 bytes per minor loop, 2 major iterations) - // Minor Link -> Channel 1 - // Major Link -> Channel 2 - configure_tcd( - edma, - 0, - core::ptr::addr_of!(SRC_BUFFER) as u32, - core::ptr::addr_of_mut!(DEST_BUFFER0) as u32, - 4, // src width - 8, // nbytes (minor loop = 2 words) - 2, // count (major loop = 2 iterations) - false, // no interrupt - ); - ch0.set_minor_link(1); // Link to CH1 after each minor loop - ch0.set_major_link(2); // Link to CH2 after major loop - - // Channel 1: Transfer 16 bytes (triggered by CH0 minor link) - configure_tcd( - edma, - 1, - core::ptr::addr_of!(SRC_BUFFER) as u32, - core::ptr::addr_of_mut!(DEST_BUFFER1) as u32, - 4, - 16, // full buffer in one minor loop - 1, // 1 major iteration - false, - ); - - // Channel 2: Transfer 16 bytes (triggered by CH0 major link) - configure_tcd( - edma, - 2, - core::ptr::addr_of!(SRC_BUFFER) as u32, - core::ptr::addr_of_mut!(DEST_BUFFER2) as u32, - 4, - 16, // full buffer in one minor loop - 1, // 1 major iteration - true, // enable interrupt - ); - } - - tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n") - .unwrap(); - - // Trigger first minor loop of CH0 - unsafe { - ch0.trigger_start(); - } - - // Wait for CH1 to complete (triggered by CH0 minor link) - while !ch1.is_done() { - cortex_m::asm::nop(); - } - unsafe { - ch1.clear_done(); - } - - tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap(); - tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n") - .unwrap(); - - // Trigger second minor loop of CH0 - unsafe { - ch0.trigger_start(); - } - - // Wait for CH0 major loop to complete - while !ch0.is_done() { - cortex_m::asm::nop(); - } - unsafe { - ch0.clear_done(); - } - - tx.blocking_write(b"CH0 major loop done.\r\n").unwrap(); - - // Wait for CH2 to complete (triggered by CH0 major link) - // Using is_done() instead of AtomicBool - the standard interrupt handler - // clears the interrupt flag and wakes wakers, but DONE bit remains set - while !ch2.is_done() { - cortex_m::asm::nop(); - } - unsafe { - ch2.clear_done(); - } - - tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap(); - - tx.blocking_write(b"EDMA channel link example finish.\r\n\r\n").unwrap(); - - tx.blocking_write(b"DEST0 (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST1 (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST2 (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify all buffers match source - let mut success = true; - unsafe { - let src_ptr = core::ptr::addr_of!(SRC_BUFFER) as *const u32; - let dst0_ptr = core::ptr::addr_of!(DEST_BUFFER0) as *const u32; - let dst1_ptr = core::ptr::addr_of!(DEST_BUFFER1) as *const u32; - let dst2_ptr = core::ptr::addr_of!(DEST_BUFFER2) as *const u32; - - for i in 0..4 { - if *dst0_ptr.add(i) != *src_ptr.add(i) { - success = false; - } - if *dst1_ptr.add(i) != *src_ptr.add(i) { - success = false; - } - if *dst2_ptr.add(i) != *src_ptr.add(i) { - success = false; - } - } - } - - if success { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); - defmt::info!("PASS: Data verified."); - } else { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/dma_interleave_transfer.rs b/examples/src/bin/dma_interleave_transfer.rs deleted file mode 100644 index 7876e8978..000000000 --- a/examples/src/bin/dma_interleave_transfer.rs +++ /dev/null @@ -1,215 +0,0 @@ -//! DMA interleaved transfer example for MCXA276. -//! -//! This example demonstrates using DMA with custom source/destination offsets -//! to interleave data during transfer. -//! -//! # Embassy-style features demonstrated: -//! - `TransferOptions::default()` for configuration (used internally) -//! - DMA channel with `DmaChannel::new()` - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind DMA channel 0 interrupt using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); - -const BUFFER_LENGTH: usize = 16; -const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2; - -// Buffers in RAM -static mut SRC_BUFFER: [u32; HALF_BUFF_LENGTH] = [0; HALF_BUFF_LENGTH]; -static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; - -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); -} - -#[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 interleave transfer example starting..."); - - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA interleave transfer example begin.\r\n\r\n") - .unwrap(); - - // Initialize buffers - unsafe { - SRC_BUFFER = [1, 2, 3, 4, 5, 6, 7, 8]; - DEST_BUFFER = [0; BUFFER_LENGTH]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, HALF_BUFF_LENGTH); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") - .unwrap(); - - // Create DMA channel using Embassy-style API - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure interleaved transfer using direct TCD access: - // - src_offset = 4: advance source by 4 bytes after each read - // - dst_offset = 8: advance dest by 8 bytes after each write - // This spreads source data across every other word in destination - unsafe { - let t = dma_ch0.tcd(); - - // Reset channel state - t.ch_csr().write(|w| { - w.erq() - .disable() - .earq() - .disable() - .eei() - .no_error() - .ebw() - .disable() - .done() - .clear_bit_by_one() - }); - t.ch_es().write(|w| w.bits(0)); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - - // Source/destination addresses - t.tcd_saddr() - .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(SRC_BUFFER) as u32)); - t.tcd_daddr() - .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); - - // Custom offsets for interleaving - t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read - t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write - - // Attributes: 32-bit transfers (size = 2) - t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); - - // Transfer entire source buffer in one minor loop - let nbytes = (HALF_BUFF_LENGTH * 4) as u32; - t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); - - // Reset source address after major loop - t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32)); - // Destination uses 2x offset, so adjust accordingly - let dst_total = (HALF_BUFF_LENGTH * 8) as u32; - t.tcd_dlast_sga() - .write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32)); - - // Major loop count = 1 - t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); - t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); - - // Enable interrupt on major loop completion - t.tcd_csr().write(|w| w.intmajor().set_bit()); - - cortex_m::asm::dsb(); - - tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); - dma_ch0.trigger_start(); - } - - // Wait for completion using channel helper method - while !dma_ch0.is_done() { - cortex_m::asm::nop(); - } - unsafe { - dma_ch0.clear_done(); - } - - tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") - .unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0 - let mut mismatch = false; - unsafe { - for i in 0..BUFFER_LENGTH { - if i % 2 == 0 { - if DEST_BUFFER[i] != SRC_BUFFER[i / 2] { - mismatch = true; - } - } else if DEST_BUFFER[i] != 0 { - mismatch = true; - } - } - } - - if mismatch { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } else { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); - defmt::info!("PASS: Data verified."); - } - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/dma_mem_to_mem.rs b/examples/src/bin/dma_mem_to_mem.rs deleted file mode 100644 index 68f70e742..000000000 --- a/examples/src/bin/dma_mem_to_mem.rs +++ /dev/null @@ -1,229 +0,0 @@ -//! DMA memory-to-memory transfer example for MCXA276. -//! -//! This example demonstrates using DMA to copy data between memory buffers -//! using the Embassy-style async API with type-safe transfers. -//! -//! # Embassy-style features demonstrated: -//! - `TransferOptions` for configuration -//! - Type-safe `mem_to_mem()` method with async `.await` -//! - `Transfer` Future that can be `.await`ed -//! - `Word` trait for automatic transfer width detection -//! - `memset()` method for filling memory with a pattern - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, TransferOptions}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind DMA channel 0 interrupt using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); - -const BUFFER_LENGTH: usize = 4; - -// Buffers in RAM (static mut is automatically placed in .bss/.data) -static mut SRC_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; -static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; -static mut MEMSET_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; - -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; // u32 max is 4294967295 (10 digits) - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - -/// Helper to print a buffer as [v1, v2, v3, v4] to UART -/// Takes a raw pointer to avoid warnings about shared references to mutable statics -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const [u32; BUFFER_LENGTH]) { - tx.blocking_write(b"[").ok(); - unsafe { - let buf = &*buf_ptr; - for (i, val) in buf.iter().enumerate() { - write_u32(tx, *val); - if i < buf.len() - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); -} - -#[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 memory-to-memory example starting..."); - - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - // Create UART for debug output - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA memory to memory example begin.\r\n\r\n") - .unwrap(); - - // Initialize buffers - unsafe { - SRC_BUFFER = [1, 2, 3, 4]; - DEST_BUFFER = [0; BUFFER_LENGTH]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, &raw const SRC_BUFFER); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, &raw const DEST_BUFFER); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") - .unwrap(); - - // Create DMA channel - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure transfer options (Embassy-style) - // TransferOptions defaults to: complete_transfer_interrupt = true - let options = TransferOptions::default(); - - // ========================================================================= - // Part 1: Embassy-style async API demonstration (mem_to_mem) - // ========================================================================= - // - // Use the new type-safe `mem_to_mem()` method: - // - Automatically determines transfer width from buffer element type (u32) - // - Returns a `Transfer` future that can be `.await`ed - // - Uses TransferOptions for consistent configuration - // - // Using async `.await` - the executor can run other tasks while waiting! - - // Perform type-safe memory-to-memory transfer using Embassy-style async API - unsafe { - let src = &*core::ptr::addr_of!(SRC_BUFFER); - let dst = &mut *core::ptr::addr_of_mut!(DEST_BUFFER); - - // Using async `.await` - the executor can run other tasks while waiting! - let transfer = dma_ch0.mem_to_mem(src, dst, options); - transfer.await; - } - - tx.blocking_write(b"DMA mem-to-mem transfer complete!\r\n\r\n").unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, &raw const DEST_BUFFER); - tx.blocking_write(b"\r\n").unwrap(); - - // Verify data - let mut mismatch = false; - unsafe { - for i in 0..BUFFER_LENGTH { - if SRC_BUFFER[i] != DEST_BUFFER[i] { - mismatch = true; - break; - } - } - } - - if mismatch { - tx.blocking_write(b"FAIL: mem_to_mem mismatch!\r\n").unwrap(); - defmt::error!("FAIL: mem_to_mem mismatch!"); - } else { - tx.blocking_write(b"PASS: mem_to_mem verified.\r\n\r\n").unwrap(); - defmt::info!("PASS: mem_to_mem verified."); - } - - // ========================================================================= - // Part 2: memset() demonstration - // ========================================================================= - // - // The `memset()` method fills a buffer with a pattern value: - // - Fixed source address (pattern is read repeatedly) - // - Incrementing destination address - // - Uses the same Transfer future pattern - - tx.blocking_write(b"--- Demonstrating memset() feature ---\r\n\r\n") - .unwrap(); - - tx.blocking_write(b"Memset Buffer (before): ").unwrap(); - print_buffer(&mut tx, &raw const MEMSET_BUFFER); - tx.blocking_write(b"\r\n").unwrap(); - - // Fill buffer with a pattern value using DMA memset - let pattern: u32 = 0xDEADBEEF; - tx.blocking_write(b"Filling with pattern 0xDEADBEEF...\r\n").unwrap(); - - unsafe { - let dst = &mut *core::ptr::addr_of_mut!(MEMSET_BUFFER); - - // Using blocking_wait() for demonstration - also shows non-async usage - let transfer = dma_ch0.memset(&pattern, dst, options); - transfer.blocking_wait(); - } - - tx.blocking_write(b"DMA memset complete!\r\n\r\n").unwrap(); - tx.blocking_write(b"Memset Buffer (after): ").unwrap(); - print_buffer(&mut tx, &raw const MEMSET_BUFFER); - tx.blocking_write(b"\r\n").unwrap(); - - // Verify memset result - let mut memset_ok = true; - unsafe { - #[allow(clippy::needless_range_loop)] - for i in 0..BUFFER_LENGTH { - if MEMSET_BUFFER[i] != pattern { - memset_ok = false; - break; - } - } - } - - if !memset_ok { - tx.blocking_write(b"FAIL: memset mismatch!\r\n").unwrap(); - defmt::error!("FAIL: memset mismatch!"); - } else { - tx.blocking_write(b"PASS: memset verified.\r\n\r\n").unwrap(); - defmt::info!("PASS: memset verified."); - } - - tx.blocking_write(b"=== All DMA tests complete ===\r\n").unwrap(); - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/dma_memset.rs b/examples/src/bin/dma_memset.rs deleted file mode 100644 index 95e365e47..000000000 --- a/examples/src/bin/dma_memset.rs +++ /dev/null @@ -1,218 +0,0 @@ -//! DMA memset example for MCXA276. -//! -//! This example demonstrates using DMA to fill a buffer with a repeated pattern. -//! The source address stays fixed while the destination increments. -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::is_done()` and `clear_done()` helper methods -//! - No need to pass register block around - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind DMA channel 0 interrupt using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); - -const BUFFER_LENGTH: usize = 4; - -// Buffers in RAM -static mut PATTERN: u32 = 0; -static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; - -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); -} - -#[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 memset example starting..."); - - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA memset example begin.\r\n\r\n").unwrap(); - - // Initialize buffers - unsafe { - PATTERN = 0xDEADBEEF; - DEST_BUFFER = [0; BUFFER_LENGTH]; - } - - tx.blocking_write(b"Pattern value: 0x").unwrap(); - // Print pattern in hex - unsafe { - let hex_chars = b"0123456789ABCDEF"; - let mut hex_buf = [0u8; 8]; - let mut val = PATTERN; - for i in (0..8).rev() { - hex_buf[i] = hex_chars[(val & 0xF) as usize]; - val >>= 4; - } - tx.blocking_write(&hex_buf).ok(); - } - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") - .unwrap(); - - // Create DMA channel using Embassy-style API - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure memset transfer using direct TCD access: - // Source stays fixed (soff = 0, reads same pattern repeatedly) - // Destination increments (doff = 4) - unsafe { - let t = dma_ch0.tcd(); - - // Reset channel state - t.ch_csr().write(|w| { - w.erq() - .disable() - .earq() - .disable() - .eei() - .no_error() - .ebw() - .disable() - .done() - .clear_bit_by_one() - }); - t.ch_es().write(|w| w.bits(0)); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - - // Source address (pattern) - fixed - t.tcd_saddr() - .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(PATTERN) as u32)); - // Destination address - increments - t.tcd_daddr() - .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); - - // Source offset = 0 (stays fixed), Dest offset = 4 (increments) - t.tcd_soff().write(|w| w.soff().bits(0)); - t.tcd_doff().write(|w| w.doff().bits(4)); - - // Attributes: 32-bit transfers (size = 2) - t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); - - // Transfer entire buffer in one minor loop - let nbytes = (BUFFER_LENGTH * 4) as u32; - t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); - - // Source doesn't need adjustment (stays fixed) - t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); - // Reset dest address after major loop - t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32)); - - // Major loop count = 1 - t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); - t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); - - // Enable interrupt on major loop completion - t.tcd_csr().write(|w| w.intmajor().set_bit()); - - cortex_m::asm::dsb(); - - tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); - dma_ch0.trigger_start(); - } - - // Wait for completion using channel helper method - while !dma_ch0.is_done() { - cortex_m::asm::nop(); - } - unsafe { - dma_ch0.clear_done(); - } - - tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n").unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify: All elements should equal PATTERN - let mut mismatch = false; - unsafe { - #[allow(clippy::needless_range_loop)] - for i in 0..BUFFER_LENGTH { - if DEST_BUFFER[i] != PATTERN { - mismatch = true; - break; - } - } - } - - if mismatch { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } else { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); - defmt::info!("PASS: Data verified."); - } - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/dma_ping_pong_transfer.rs b/examples/src/bin/dma_ping_pong_transfer.rs deleted file mode 100644 index f8f543382..000000000 --- a/examples/src/bin/dma_ping_pong_transfer.rs +++ /dev/null @@ -1,376 +0,0 @@ -//! DMA ping-pong/double-buffer transfer example for MCXA276. -//! -//! This example demonstrates two approaches for ping-pong/double-buffering: -//! -//! ## Approach 1: Scatter/Gather with linked TCDs (manual) -//! - Two TCDs link to each other for alternating transfers -//! - Uses custom handler that delegates to on_interrupt() then signals completion -//! - Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, -//! so we need an AtomicBool to track completion -//! -//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!) -//! - Single continuous transfer over entire buffer -//! - Uses half-transfer interrupt to know when first half is ready -//! - Application can process first half while second half is being filled -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::new()` for channel creation -//! - Scatter/gather with linked TCDs -//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) -//! - Standard `DmaCh1InterruptHandler` with `bind_interrupts!` macro -//! - NEW: `wait_half()` for half-transfer interrupt handling - -#![no_std] -#![no_main] - -use core::sync::atomic::{AtomicBool, Ordering}; - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaCh1InterruptHandler, DmaChannel, Tcd, TransferOptions}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Source and destination buffers for Approach 1 (scatter/gather) -static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; -static mut DST: [u32; 8] = [0; 8]; - -// Source and destination buffers for Approach 2 (wait_half) -static mut SRC2: [u32; 8] = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; -static mut DST2: [u32; 8] = [0; 8]; - -// TCD pool for scatter/gather - must be 32-byte aligned -#[repr(C, align(32))] -struct TcdPool([Tcd; 2]); - -static mut TCD_POOL: TcdPool = TcdPool( - [Tcd { - saddr: 0, - soff: 0, - attr: 0, - nbytes: 0, - slast: 0, - daddr: 0, - doff: 0, - citer: 0, - dlast_sga: 0, - csr: 0, - biter: 0, - }; 2], -); - -// AtomicBool to track scatter/gather completion -// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, -// so we need this flag to detect when each transfer completes -static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); - -// Custom handler for scatter/gather that delegates to HAL's on_interrupt() -// This follows the "interrupts as threads" pattern - the handler does minimal work -// (delegates to HAL + sets a flag) and the main task does the actual processing -pub struct PingPongDmaHandler; - -impl embassy_mcxa::interrupt::typelevel::Handler for PingPongDmaHandler { - unsafe fn on_interrupt() { - // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers - dma::on_interrupt(0); - // Signal completion for polling (needed because ESG clears DONE bit) - TRANSFER_DONE.store(true, Ordering::Release); - } -} - -// Bind DMA channel interrupts -// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag) -// CH1: Standard handler for wait_half() demo -bind_interrupts!(struct Irqs { - DMA_CH0 => PingPongDmaHandler; - DMA_CH1 => DmaCh1InterruptHandler; -}); - -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); -} - -#[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 ping-pong transfer example starting..."); - - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA ping-pong transfer example begin.\r\n\r\n") - .unwrap(); - - // Initialize buffers - unsafe { - SRC = [1, 2, 3, 4, 5, 6, 7, 8]; - DST = [0; 8]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring ping-pong DMA with Embassy-style API...\r\n") - .unwrap(); - - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure ping-pong transfer using direct TCD access: - // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. - // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1. - // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0. - unsafe { - let tcds = &mut *core::ptr::addr_of_mut!(TCD_POOL.0); - let src_ptr = core::ptr::addr_of!(SRC) as *const u32; - let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; - - let half_len = 4usize; - let half_bytes = (half_len * 4) as u32; - - let tcd0_addr = &tcds[0] as *const _ as u32; - let tcd1_addr = &tcds[1] as *const _ as u32; - - // TCD0: First half -> Links to TCD1 - tcds[0] = Tcd { - saddr: src_ptr as u32, - soff: 4, - attr: 0x0202, // 32-bit src/dst - nbytes: half_bytes, - slast: 0, - daddr: dst_ptr as u32, - doff: 4, - citer: 1, - dlast_sga: tcd1_addr as i32, - csr: 0x0012, // ESG | INTMAJOR - biter: 1, - }; - - // TCD1: Second half -> Links to TCD0 - tcds[1] = Tcd { - saddr: src_ptr.add(half_len) as u32, - soff: 4, - attr: 0x0202, - nbytes: half_bytes, - slast: 0, - daddr: dst_ptr.add(half_len) as u32, - doff: 4, - citer: 1, - dlast_sga: tcd0_addr as i32, - csr: 0x0012, - biter: 1, - }; - - // Load TCD0 into hardware registers - dma_ch0.load_tcd(&tcds[0]); - } - - tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); - - // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) - unsafe { - dma_ch0.trigger_start(); - } - - // Wait for first half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); - } - TRANSFER_DONE.store(false, Ordering::Release); - - tx.blocking_write(b"First half transferred.\r\n").unwrap(); - tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); - - // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) - unsafe { - dma_ch0.trigger_start(); - } - - // Wait for second half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); - } - TRANSFER_DONE.store(false, Ordering::Release); - - tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); - - tx.blocking_write(b"EDMA ping-pong transfer example finish.\r\n\r\n") - .unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify: DST should match SRC - let mut mismatch = false; - unsafe { - let src_ptr = core::ptr::addr_of!(SRC) as *const u32; - let dst_ptr = core::ptr::addr_of!(DST) as *const u32; - for i in 0..8 { - if *src_ptr.add(i) != *dst_ptr.add(i) { - mismatch = true; - break; - } - } - } - - if mismatch { - tx.blocking_write(b"FAIL: Approach 1 mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Approach 1 mismatch detected!"); - } else { - tx.blocking_write(b"PASS: Approach 1 data verified.\r\n\r\n").unwrap(); - defmt::info!("PASS: Approach 1 data verified."); - } - - // ========================================================================= - // Approach 2: Half-Transfer Interrupt with wait_half() (NEW!) - // ========================================================================= - // - // This approach uses a single continuous DMA transfer with half-transfer - // interrupt enabled. The wait_half() method allows you to be notified - // when the first half of the buffer is complete, so you can process it - // while the second half is still being filled. - // - // Benefits: - // - Simpler setup (no TCD pool needed) - // - True async/await support - // - Good for streaming data processing - - tx.blocking_write(b"--- Approach 2: wait_half() demo ---\r\n\r\n") - .unwrap(); - - // Enable DMA CH1 interrupt - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); - } - - // Initialize approach 2 buffers - unsafe { - SRC2 = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; - DST2 = [0; 8]; - } - - tx.blocking_write(b"SRC2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - let dma_ch1 = DmaChannel::new(p.DMA_CH1); - - // Configure transfer with half-transfer interrupt enabled - let mut options = TransferOptions::default(); - options.half_transfer_interrupt = true; // Enable half-transfer interrupt - options.complete_transfer_interrupt = true; - - tx.blocking_write(b"Starting transfer with half_transfer_interrupt...\r\n") - .unwrap(); - - unsafe { - let src = &*core::ptr::addr_of!(SRC2); - let dst = &mut *core::ptr::addr_of_mut!(DST2); - - // Create the transfer - let mut transfer = dma_ch1.mem_to_mem(src, dst, options); - - // Wait for half-transfer (first 4 elements) - tx.blocking_write(b"Waiting for first half...\r\n").unwrap(); - let half_ok = transfer.wait_half().await; - - if half_ok { - tx.blocking_write(b"Half-transfer complete! First half of DST2: ") - .unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b"(Processing first half while second half transfers...)\r\n") - .unwrap(); - } - - // Wait for complete transfer - tx.blocking_write(b"Waiting for second half...\r\n").unwrap(); - transfer.await; - } - - tx.blocking_write(b"Transfer complete! Full DST2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 8); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify approach 2 - let mut mismatch2 = false; - unsafe { - let src_ptr = core::ptr::addr_of!(SRC2) as *const u32; - let dst_ptr = core::ptr::addr_of!(DST2) as *const u32; - for i in 0..8 { - if *src_ptr.add(i) != *dst_ptr.add(i) { - mismatch2 = true; - break; - } - } - } - - if mismatch2 { - tx.blocking_write(b"FAIL: Approach 2 mismatch!\r\n").unwrap(); - defmt::error!("FAIL: Approach 2 mismatch!"); - } else { - tx.blocking_write(b"PASS: Approach 2 verified.\r\n").unwrap(); - defmt::info!("PASS: Approach 2 verified."); - } - - tx.blocking_write(b"\r\n=== All ping-pong demos complete ===\r\n") - .unwrap(); - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/dma_scatter_gather.rs b/examples/src/bin/dma_scatter_gather.rs deleted file mode 100644 index 4b26bc2ed..000000000 --- a/examples/src/bin/dma_scatter_gather.rs +++ /dev/null @@ -1,262 +0,0 @@ -//! DMA scatter-gather transfer example for MCXA276. -//! -//! This example demonstrates using DMA with scatter/gather to chain multiple -//! transfer descriptors. The first TCD transfers the first half of the buffer, -//! then automatically loads the second TCD to transfer the second half. -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::new()` for channel creation -//! - Scatter/gather with chained TCDs -//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) - -#![no_std] -#![no_main] - -use core::sync::atomic::{AtomicBool, Ordering}; - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaChannel, Tcd}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Source and destination buffers -static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; -static mut DST: [u32; 8] = [0; 8]; - -// TCD pool for scatter/gather - must be 32-byte aligned -#[repr(C, align(32))] -struct TcdPool([Tcd; 2]); - -static mut TCD_POOL: TcdPool = TcdPool( - [Tcd { - saddr: 0, - soff: 0, - attr: 0, - nbytes: 0, - slast: 0, - daddr: 0, - doff: 0, - citer: 0, - dlast_sga: 0, - csr: 0, - biter: 0, - }; 2], -); - -// AtomicBool to track scatter/gather completion -// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, -// so we need this flag to detect when each transfer completes -static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); - -// Custom handler for scatter/gather that delegates to HAL's on_interrupt() -// This follows the "interrupts as threads" pattern - the handler does minimal work -// (delegates to HAL + sets a flag) and the main task does the actual processing -pub struct ScatterGatherDmaHandler; - -impl embassy_mcxa::interrupt::typelevel::Handler - for ScatterGatherDmaHandler -{ - unsafe fn on_interrupt() { - // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers - dma::on_interrupt(0); - // Signal completion for polling (needed because ESG clears DONE bit) - TRANSFER_DONE.store(true, Ordering::Release); - } -} - -// Bind DMA channel interrupt -// Custom handler for scatter/gather (delegates to on_interrupt + sets flag) -bind_interrupts!(struct Irqs { - DMA_CH0 => ScatterGatherDmaHandler; -}); - -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); -} - -#[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 transfer example starting..."); - - // DMA is initialized during hal::init() - no need to call ensure_init() - - // Enable DMA interrupt - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA scatter-gather transfer example begin.\r\n\r\n") - .unwrap(); - - // Initialize buffers - unsafe { - SRC = [1, 2, 3, 4, 5, 6, 7, 8]; - DST = [0; 8]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring scatter-gather DMA with Embassy-style API...\r\n") - .unwrap(); - - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure scatter-gather transfer using direct TCD access: - // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. - // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1. - // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD. - unsafe { - let tcds = core::slice::from_raw_parts_mut(core::ptr::addr_of_mut!(TCD_POOL.0) as *mut Tcd, 2); - let src_ptr = core::ptr::addr_of!(SRC) as *const u32; - let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; - - let num_tcds = 2usize; - let chunk_len = 4usize; // 8 / 2 - let chunk_bytes = (chunk_len * 4) as u32; - - for i in 0..num_tcds { - let is_last = i == num_tcds - 1; - let next_tcd_addr = if is_last { - 0 // No next TCD - } else { - &tcds[i + 1] as *const _ as u32 - }; - - tcds[i] = Tcd { - saddr: src_ptr.add(i * chunk_len) as u32, - soff: 4, - attr: 0x0202, // 32-bit src/dst - nbytes: chunk_bytes, - slast: 0, - daddr: dst_ptr.add(i * chunk_len) as u32, - doff: 4, - citer: 1, - dlast_sga: next_tcd_addr as i32, - // ESG (scatter/gather) for non-last, INTMAJOR for all - csr: if is_last { 0x0002 } else { 0x0012 }, - biter: 1, - }; - } - - // Load TCD0 into hardware registers - dma_ch0.load_tcd(&tcds[0]); - } - - tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); - - // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) - // TCD0 is currently loaded. - unsafe { - dma_ch0.trigger_start(); - } - - // Wait for first half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); - } - TRANSFER_DONE.store(false, Ordering::Release); - - tx.blocking_write(b"First half transferred.\r\n").unwrap(); - tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); - - // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) - // TCD1 should have been loaded by the scatter/gather engine. - unsafe { - dma_ch0.trigger_start(); - } - - // Wait for second half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); - } - TRANSFER_DONE.store(false, Ordering::Release); - - tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); - - tx.blocking_write(b"EDMA scatter-gather transfer example finish.\r\n\r\n") - .unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify: DST should match SRC - let mut mismatch = false; - unsafe { - let src_ptr = core::ptr::addr_of!(SRC) as *const u32; - let dst_ptr = core::ptr::addr_of!(DST) as *const u32; - for i in 0..8 { - if *src_ptr.add(i) != *dst_ptr.add(i) { - mismatch = true; - break; - } - } - } - - if mismatch { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } else { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); - defmt::info!("PASS: Data verified."); - } - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/dma_scatter_gather_builder.rs b/examples/src/bin/dma_scatter_gather_builder.rs deleted file mode 100644 index e483bb81f..000000000 --- a/examples/src/bin/dma_scatter_gather_builder.rs +++ /dev/null @@ -1,231 +0,0 @@ -//! 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::{DmaCh0InterruptHandler, DmaChannel, ScatterGatherBuilder}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind DMA channel 0 interrupt -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); - -// Source buffers (multiple segments) -static mut SRC1: [u32; 4] = [0x11111111, 0x22222222, 0x33333333, 0x44444444]; -static mut SRC2: [u32; 4] = [0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD]; -static mut SRC3: [u32; 4] = [0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]; - -// Destination buffers (one per segment) -static mut DST1: [u32; 4] = [0; 4]; -static mut DST2: [u32; 4] = [0; 4]; -static mut DST3: [u32; 4] = [0; 4]; - -/// Helper to write a u32 as hex to UART -fn write_hex(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - const HEX: &[u8; 16] = b"0123456789ABCDEF"; - for i in (0..8).rev() { - let nibble = ((val >> (i * 4)) & 0xF) as usize; - tx.blocking_write(&[HEX[nibble]]).ok(); - } -} - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_hex(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); -} - -#[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..."); - - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - // Create UART for debug output - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"DMA Scatter-Gather Builder Example\r\n").unwrap(); - tx.blocking_write(b"===================================\r\n\r\n") - .unwrap(); - - // Show source buffers - tx.blocking_write(b"Source buffers:\r\n").unwrap(); - tx.blocking_write(b" SRC1: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" SRC2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" SRC3: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC3) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - tx.blocking_write(b"Destination buffers (before):\r\n").unwrap(); - tx.blocking_write(b" DST1: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" DST2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" DST3: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Create DMA channel - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - tx.blocking_write(b"Building scatter-gather chain with builder API...\r\n") - .unwrap(); - - // ========================================================================= - // 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::::new(); - - // Add three transfer segments - the builder handles TCD linking automatically - unsafe { - let src1 = &*core::ptr::addr_of!(SRC1); - let dst1 = &mut *core::ptr::addr_of_mut!(DST1); - builder.add_transfer(src1, dst1); - } - - unsafe { - let src2 = &*core::ptr::addr_of!(SRC2); - let dst2 = &mut *core::ptr::addr_of_mut!(DST2); - builder.add_transfer(src2, dst2); - } - - unsafe { - let src3 = &*core::ptr::addr_of!(SRC3); - let dst3 = &mut *core::ptr::addr_of_mut!(DST3); - builder.add_transfer(src3, dst3); - } - - tx.blocking_write(b"Added 3 transfer segments to chain.\r\n").unwrap(); - tx.blocking_write(b"Starting scatter-gather transfer with .await...\r\n\r\n") - .unwrap(); - - // 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 - unsafe { - let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather"); - transfer.blocking_wait(); - } - - tx.blocking_write(b"Scatter-gather transfer complete!\r\n\r\n").unwrap(); - - // Show results - tx.blocking_write(b"Destination buffers (after):\r\n").unwrap(); - tx.blocking_write(b" DST1: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" DST2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" DST3: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify all three segments - let mut all_ok = true; - unsafe { - let src1 = core::ptr::addr_of!(SRC1) as *const u32; - let dst1 = core::ptr::addr_of!(DST1) as *const u32; - for i in 0..4 { - if *src1.add(i) != *dst1.add(i) { - all_ok = false; - } - } - - let src2 = core::ptr::addr_of!(SRC2) as *const u32; - let dst2 = core::ptr::addr_of!(DST2) as *const u32; - for i in 0..4 { - if *src2.add(i) != *dst2.add(i) { - all_ok = false; - } - } - - let src3 = core::ptr::addr_of!(SRC3) as *const u32; - let dst3 = core::ptr::addr_of!(DST3) as *const u32; - for i in 0..4 { - if *src3.add(i) != *dst3.add(i) { - all_ok = false; - } - } - } - - if all_ok { - tx.blocking_write(b"PASS: All segments verified!\r\n").unwrap(); - defmt::info!("PASS: All segments verified!"); - } else { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } - - tx.blocking_write(b"\r\n=== Scatter-Gather Builder example complete ===\r\n") - .unwrap(); - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/dma_wrap_transfer.rs b/examples/src/bin/dma_wrap_transfer.rs deleted file mode 100644 index 82936d9d0..000000000 --- a/examples/src/bin/dma_wrap_transfer.rs +++ /dev/null @@ -1,222 +0,0 @@ -//! DMA wrap transfer example for MCXA276. -//! -//! This example demonstrates using DMA with modulo addressing to wrap around -//! a source buffer, effectively repeating the source data in the destination. -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::is_done()` and `clear_done()` helper methods -//! - No need to pass register block around - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind DMA channel 0 interrupt using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); - -// Source buffer: 4 words (16 bytes), aligned to 16 bytes for modulo -#[repr(align(16))] -struct AlignedSrc([u32; 4]); - -static mut SRC: AlignedSrc = AlignedSrc([0; 4]); -static mut DST: [u32; 8] = [0; 8]; - -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); -} - -#[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 wrap transfer example starting..."); - - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA wrap transfer example begin.\r\n\r\n").unwrap(); - - // Initialize buffers - unsafe { - SRC.0 = [1, 2, 3, 4]; - DST = [0; 8]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, unsafe { core::ptr::addr_of!(SRC.0) } as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") - .unwrap(); - - // Create DMA channel using Embassy-style API - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure wrap transfer using direct TCD access: - // SRC is 16 bytes (4 * u32). We want to transfer 32 bytes (8 * u32). - // SRC modulo is 16 bytes (2^4 = 16) - wraps source address. - // DST modulo is 0 (disabled). - // This causes the source address to wrap around after 16 bytes, - // effectively repeating the source data. - unsafe { - let t = dma_ch0.tcd(); - - // Reset channel state - t.ch_csr().write(|w| { - w.erq() - .disable() - .earq() - .disable() - .eei() - .no_error() - .ebw() - .disable() - .done() - .clear_bit_by_one() - }); - t.ch_es().write(|w| w.bits(0)); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - - // Source/destination addresses - t.tcd_saddr() - .write(|w| w.saddr().bits(core::ptr::addr_of!(SRC.0) as u32)); - t.tcd_daddr() - .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DST) as u32)); - - // Offsets: both increment by 4 bytes - t.tcd_soff().write(|w| w.soff().bits(4)); - t.tcd_doff().write(|w| w.doff().bits(4)); - - // Attributes: 32-bit transfers (size = 2) - // SMOD = 4 (2^4 = 16 byte modulo for source), DMOD = 0 (disabled) - t.tcd_attr().write(|w| { - w.ssize() - .bits(2) - .dsize() - .bits(2) - .smod() - .bits(4) // Source modulo: 2^4 = 16 bytes - .dmod() - .bits(0) // Dest modulo: disabled - }); - - // Transfer 32 bytes total in one minor loop - let nbytes = 32u32; - t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); - - // Source wraps via modulo, no adjustment needed - t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); - // Reset dest address after major loop - t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32)); - - // Major loop count = 1 - t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); - t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); - - // Enable interrupt on major loop completion - t.tcd_csr().write(|w| w.intmajor().set_bit()); - - cortex_m::asm::dsb(); - - tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); - dma_ch0.trigger_start(); - } - - // Wait for completion using channel helper method - while !dma_ch0.is_done() { - cortex_m::asm::nop(); - } - unsafe { - dma_ch0.clear_done(); - } - - tx.blocking_write(b"\r\nEDMA wrap transfer example finish.\r\n\r\n") - .unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify: DST should be [1, 2, 3, 4, 1, 2, 3, 4] - let expected = [1u32, 2, 3, 4, 1, 2, 3, 4]; - let mut mismatch = false; - unsafe { - for i in 0..8 { - if DST[i] != expected[i] { - mismatch = true; - break; - } - } - } - - if mismatch { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } else { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); - defmt::info!("PASS: Data verified."); - } - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/hello.rs b/examples/src/bin/hello.rs deleted file mode 100644 index e371d9413..000000000 --- a/examples/src/bin/hello.rs +++ /dev/null @@ -1,119 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use hal::lpuart::{Blocking, Config, Lpuart}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -/// Simple helper to write a byte as hex to UART -fn write_hex_byte(uart: &mut Lpuart<'_, Blocking>, byte: u8) { - const HEX_DIGITS: &[u8] = b"0123456789ABCDEF"; - let _ = uart.write_byte(HEX_DIGITS[(byte >> 4) as usize]); - let _ = uart.write_byte(HEX_DIGITS[(byte & 0xF) as usize]); -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - 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!("boot"); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - let mut uart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - - // Print welcome message before any async delays to guarantee early console output - uart.write_str_blocking("\r\n=== MCXA276 UART Echo Demo ===\r\n"); - uart.write_str_blocking("Available commands:\r\n"); - uart.write_str_blocking(" help - Show this help\r\n"); - uart.write_str_blocking(" echo - Echo back the text\r\n"); - uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); - uart.write_str_blocking("Type a command: "); - - let mut buffer = [0u8; 64]; - let mut buf_idx = 0; - - loop { - // Read a byte from UART - let byte = uart.read_byte_blocking(); - - // Echo the character back - if byte == b'\r' || byte == b'\n' { - // Enter pressed - process command - uart.write_str_blocking("\r\n"); - - if buf_idx > 0 { - let command = &buffer[0..buf_idx]; - - if command == b"help" { - uart.write_str_blocking("Available commands:\r\n"); - uart.write_str_blocking(" help - Show this help\r\n"); - uart.write_str_blocking(" echo - Echo back the text\r\n"); - uart.write_str_blocking(" hex - Display byte in hex (0-255)\r\n"); - } else if command.starts_with(b"echo ") && command.len() > 5 { - uart.write_str_blocking("Echo: "); - uart.write_str_blocking(core::str::from_utf8(&command[5..]).unwrap_or("")); - uart.write_str_blocking("\r\n"); - } else if command.starts_with(b"hex ") && command.len() > 4 { - // Parse the byte value - let num_str = &command[4..]; - if let Ok(num) = parse_u8(num_str) { - uart.write_str_blocking("Hex: 0x"); - write_hex_byte(&mut uart, num); - uart.write_str_blocking("\r\n"); - } else { - uart.write_str_blocking("Invalid number for hex command\r\n"); - } - } else if !command.is_empty() { - uart.write_str_blocking("Unknown command: "); - uart.write_str_blocking(core::str::from_utf8(command).unwrap_or("")); - uart.write_str_blocking("\r\n"); - } - } - - // Reset buffer and prompt - buf_idx = 0; - uart.write_str_blocking("Type a command: "); - } else if byte == 8 || byte == 127 { - // Backspace - if buf_idx > 0 { - buf_idx -= 1; - uart.write_str_blocking("\x08 \x08"); // Erase character - } - } else if buf_idx < buffer.len() - 1 { - // Regular character - buffer[buf_idx] = byte; - buf_idx += 1; - let _ = uart.write_byte(byte); - } - } -} - -/// Simple parser for u8 from ASCII bytes -fn parse_u8(bytes: &[u8]) -> Result { - let mut result = 0u8; - for &b in bytes { - if b.is_ascii_digit() { - result = result.checked_mul(10).ok_or(())?; - result = result.checked_add(b - b'0').ok_or(())?; - } else { - return Err(()); - } - } - Ok(result) -} diff --git a/examples/src/bin/i2c-blocking.rs b/examples/src/bin/i2c-blocking.rs deleted file mode 100644 index 0f6c8cbae..000000000 --- a/examples/src/bin/i2c-blocking.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_time::Timer; -use hal::clocks::config::Div8; -use hal::config::Config; -use hal::i2c::controller::{self, I2c, Speed}; -use tmp108::Tmp108; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let mut config = Config::default(); - config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); - - let p = hal::init(config); - - defmt::info!("I2C example"); - - let mut config = controller::Config::default(); - config.speed = Speed::Standard; - let i2c = I2c::new_blocking(p.LPI2C3, p.P3_27, p.P3_28, config).unwrap(); - let mut tmp = Tmp108::new_with_a0_gnd(i2c); - - loop { - let temperature = tmp.temperature().unwrap(); - defmt::info!("Temperature: {}C", temperature); - Timer::after_secs(1).await; - } -} diff --git a/examples/src/bin/i2c-scan-blocking.rs b/examples/src/bin/i2c-scan-blocking.rs deleted file mode 100644 index 4e203597b..000000000 --- a/examples/src/bin/i2c-scan-blocking.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::gpio::Pull; -use embassy_mcxa::Input; -use embassy_time::Timer; -use hal::clocks::config::Div8; -use hal::config::Config; -use hal::i2c::controller::{self, I2c, Speed}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let mut config = Config::default(); - config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); - - let p = hal::init(config); - - defmt::info!("I2C example"); - - let mut config = controller::Config::default(); - config.speed = Speed::Standard; - - // Note: P0_2 is connected to P1_8 on the FRDM_MCXA276 via a resistor, and - // defaults to SWO on the debug peripheral. Explicitly make it a high-z - // input. - let _pin = Input::new(p.P0_2, Pull::Disabled); - let mut i2c = I2c::new_blocking(p.LPI2C2, p.P1_9, p.P1_8, config).unwrap(); - - for addr in 0x01..=0x7f { - let result = i2c.blocking_write(addr, &[]); - if result.is_ok() { - defmt::info!("Device found at addr {:02x}", addr); - } - } - - loop { - Timer::after_secs(10).await; - } -} diff --git a/examples/src/bin/lpuart_buffered.rs b/examples/src/bin/lpuart_buffered.rs deleted file mode 100644 index 420589d00..000000000 --- a/examples/src/bin/lpuart_buffered.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::lpuart::buffered::BufferedLpuart; -use embassy_mcxa::lpuart::Config; -use embassy_mcxa::{bind_interrupts, lpuart}; -use embedded_io_async::Write; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind OS_EVENT for timers plus LPUART2 IRQ for the buffered driver -bind_interrupts!(struct Irqs { - LPUART2 => lpuart::buffered::BufferedInterruptHandler::; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - 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); - - // Configure NVIC for LPUART2 - hal::interrupt::LPUART2.configure_for_uart(hal::interrupt::Priority::P3); - - // UART configuration (enable both TX and RX) - let config = Config { - baudrate_bps: 115_200, - rx_fifo_watermark: 0, - tx_fifo_watermark: 0, - ..Default::default() - }; - - let mut tx_buf = [0u8; 256]; - let mut rx_buf = [0u8; 256]; - - // Create a buffered LPUART2 instance with both TX and RX - let mut uart = BufferedLpuart::new( - p.LPUART2, - p.P2_2, // TX pin - p.P2_3, // RX pin - Irqs, - &mut tx_buf, - &mut rx_buf, - config, - ) - .unwrap(); - - // Split into TX and RX parts - let (tx, rx) = uart.split_ref(); - - tx.write(b"Hello buffered LPUART.\r\n").await.unwrap(); - tx.write(b"Type characters to echo them back.\r\n").await.unwrap(); - - // Echo loop - let mut buf = [0u8; 4]; - loop { - let used = rx.read(&mut buf).await.unwrap(); - tx.write_all(&buf[..used]).await.unwrap(); - } -} diff --git a/examples/src/bin/lpuart_dma.rs b/examples/src/bin/lpuart_dma.rs deleted file mode 100644 index 5497f8646..000000000 --- a/examples/src/bin/lpuart_dma.rs +++ /dev/null @@ -1,81 +0,0 @@ -//! LPUART DMA example for MCXA276. -//! -//! This example demonstrates using DMA for UART TX and RX operations. -//! It sends a message using DMA, then waits for 16 characters to be received -//! via DMA and echoes them back. -//! -//! The DMA request sources are automatically derived from the LPUART instance type. -//! DMA clock/reset/init is handled automatically by the HAL. - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; -use embassy_mcxa::lpuart::{Config, LpuartDma}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind DMA channel interrupts using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; - DMA_CH1 => DmaCh1InterruptHandler; -}); - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - 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!("LPUART DMA example starting..."); - - // Enable DMA interrupts (per-channel, as needed) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); - } - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - // Create UART instance with DMA channels - let mut lpuart = LpuartDma::new( - p.LPUART2, p.P2_2, // TX pin - p.P2_3, // RX pin - p.DMA_CH0, // TX DMA channel - p.DMA_CH1, // RX DMA channel - config, - ) - .unwrap(); - - // Send a message using DMA (DMA request source is automatically derived from LPUART2) - let tx_msg = b"Hello from LPUART2 DMA TX!\r\n"; - lpuart.write_dma(tx_msg).await.unwrap(); - - defmt::info!("TX DMA complete"); - - // Send prompt - let prompt = b"Type 16 characters to echo via DMA:\r\n"; - lpuart.write_dma(prompt).await.unwrap(); - - // Receive 16 characters using DMA - let mut rx_buf = [0u8; 16]; - lpuart.read_dma(&mut rx_buf).await.unwrap(); - - defmt::info!("RX DMA complete"); - - // Echo back the received data - let echo_prefix = b"\r\nReceived: "; - lpuart.write_dma(echo_prefix).await.unwrap(); - lpuart.write_dma(&rx_buf).await.unwrap(); - let done_msg = b"\r\nDone!\r\n"; - lpuart.write_dma(done_msg).await.unwrap(); - - defmt::info!("Example complete"); -} diff --git a/examples/src/bin/lpuart_polling.rs b/examples/src/bin/lpuart_polling.rs deleted file mode 100644 index b80668834..000000000 --- a/examples/src/bin/lpuart_polling.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -use crate::hal::lpuart::{Config, Lpuart}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - 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!("boot"); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - // Create UART instance using LPUART2 with P2_2 as TX and P2_3 as RX - let lpuart = Lpuart::new_blocking( - p.LPUART2, // Peripheral - p.P2_2, // TX pin - p.P2_3, // RX pin - config, - ) - .unwrap(); - - // Split into separate TX and RX parts - let (mut tx, mut rx) = lpuart.split(); - - // Write hello messages - tx.blocking_write(b"Hello world.\r\n").unwrap(); - tx.blocking_write(b"Echoing. Type characters...\r\n").unwrap(); - - // Echo loop - loop { - let mut buf = [0u8; 1]; - rx.blocking_read(&mut buf).unwrap(); - tx.blocking_write(&buf).unwrap(); - } -} diff --git a/examples/src/bin/lpuart_ring_buffer.rs b/examples/src/bin/lpuart_ring_buffer.rs deleted file mode 100644 index 1d1a51970..000000000 --- a/examples/src/bin/lpuart_ring_buffer.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! LPUART Ring Buffer DMA example for MCXA276. -//! -//! This example demonstrates using the high-level `LpuartRxDma::setup_ring_buffer()` -//! API for continuous circular DMA reception from a UART peripheral. -//! -//! # Features demonstrated: -//! - `LpuartRxDma::setup_ring_buffer()` for continuous peripheral-to-memory DMA -//! - `RingBuffer` for async reading of received data -//! - Handling of potential overrun conditions -//! - Half-transfer and complete-transfer interrupts for timely wakeups -//! -//! # How it works: -//! 1. Create an `LpuartRxDma` driver with a DMA channel -//! 2. Call `setup_ring_buffer()` which handles all low-level DMA configuration -//! 3. Application asynchronously reads data as it arrives via `ring_buf.read()` -//! 4. Both half-transfer and complete-transfer interrupts wake the reader - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::bind_interrupts; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; -use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Bind DMA channel interrupts -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; - DMA_CH1 => DmaCh1InterruptHandler; -}); - -// Ring buffer for RX - power of 2 is ideal for modulo efficiency -static mut RX_RING_BUFFER: [u8; 64] = [0; 64]; - -/// Helper to write a byte as hex to UART -fn write_hex( - tx: &mut LpuartTxDma<'_, T, C>, - byte: u8, -) { - const HEX: &[u8; 16] = b"0123456789ABCDEF"; - let buf = [HEX[(byte >> 4) as usize], HEX[(byte & 0x0F) as usize]]; - tx.blocking_write(&buf).ok(); -} - -#[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!("LPUART Ring Buffer DMA example starting..."); - - // Create UART configuration - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - // Create LPUART with DMA support for both TX and RX, then split - // This is the proper Embassy pattern - create once, split into TX and RX - let lpuart = LpuartDma::new(p.LPUART2, p.P2_2, p.P2_3, p.DMA_CH1, p.DMA_CH0, config).unwrap(); - let (mut tx, rx) = lpuart.split(); - - tx.blocking_write(b"LPUART Ring Buffer DMA Example\r\n").unwrap(); - tx.blocking_write(b"==============================\r\n\r\n").unwrap(); - - tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n") - .unwrap(); - - // Set up the ring buffer with circular DMA - // The HAL handles: DMA request source, RDMAE enable, circular transfer config, NVIC enable - let ring_buf = unsafe { - let buf = &mut *core::ptr::addr_of_mut!(RX_RING_BUFFER); - rx.setup_ring_buffer(buf) - }; - - // Enable DMA requests to start continuous reception - unsafe { - rx.enable_dma_request(); - } - - tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n") - .unwrap(); - tx.blocking_write(b"The DMA continuously receives in the background.\r\n\r\n") - .unwrap(); - - // Main loop: read from ring buffer and echo back - let mut read_buf = [0u8; 16]; - let mut total_received: usize = 0; - - loop { - // Async read - waits until data is available - match ring_buf.read(&mut read_buf).await { - Ok(n) if n > 0 => { - total_received += n; - - // Echo back what we received - tx.blocking_write(b"RX[").unwrap(); - for (i, &byte) in read_buf.iter().enumerate().take(n) { - write_hex(&mut tx, byte); - if i < n - 1 { - tx.blocking_write(b" ").unwrap(); - } - } - tx.blocking_write(b"]: ").unwrap(); - tx.blocking_write(&read_buf[..n]).unwrap(); - tx.blocking_write(b"\r\n").unwrap(); - - defmt::info!("Received {} bytes, total: {}", n, total_received); - } - Ok(_) => { - // No data, shouldn't happen with async read - } - Err(_) => { - // Overrun detected - tx.blocking_write(b"ERROR: Ring buffer overrun!\r\n").unwrap(); - defmt::error!("Ring buffer overrun!"); - ring_buf.clear(); - } - } - } -} diff --git a/examples/src/bin/rtc_alarm.rs b/examples/src/bin/rtc_alarm.rs deleted file mode 100644 index a7800a2d1..000000000 --- a/examples/src/bin/rtc_alarm.rs +++ /dev/null @@ -1,74 +0,0 @@ -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa as hal; -use hal::rtc::{RtcDateTime, RtcInterruptEnable}; -use hal::InterruptExt; - -type MyRtc = hal::rtc::Rtc<'static, hal::rtc::Rtc0>; - -use embassy_mcxa::bind_interrupts; -use {defmt_rtt as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - RTC => hal::rtc::RtcHandler; -}); - -#[used] -#[no_mangle] -static KEEP_RTC: unsafe extern "C" fn() = RTC; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - defmt::info!("=== RTC Alarm Example ==="); - - let rtc_config = hal::rtc::get_default_config(); - - let rtc = MyRtc::new(p.RTC0, rtc_config); - - let now = RtcDateTime { - year: 2025, - month: 10, - day: 15, - hour: 14, - minute: 30, - second: 0, - }; - - rtc.stop(); - - defmt::info!("Time set to: 2025-10-15 14:30:00"); - rtc.set_datetime(now); - - let mut alarm = now; - alarm.second += 10; - - rtc.set_alarm(alarm); - defmt::info!("Alarm set for: 2025-10-15 14:30:10 (+10 seconds)"); - - rtc.set_interrupt(RtcInterruptEnable::RTC_ALARM_INTERRUPT_ENABLE); - - unsafe { - hal::interrupt::RTC.enable(); - } - - unsafe { - cortex_m::interrupt::enable(); - } - - rtc.start(); - - defmt::info!("RTC started, waiting for alarm..."); - - loop { - if rtc.is_alarm_triggered() { - defmt::info!("*** ALARM TRIGGERED! ***"); - break; - } - } - - defmt::info!("Example complete - Test PASSED!"); -} diff --git a/examples/src/lib.rs b/examples/src/lib.rs deleted file mode 100644 index 2573a6adc..000000000 --- a/examples/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_std] -#![allow(clippy::missing_safety_doc)] - -//! Shared board-specific helpers for the FRDM-MCXA276 examples. -//! These live with the examples so the HAL stays generic. - -use hal::{clocks, pins}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -/// Initialize clocks and pin muxing for ADC. -pub unsafe fn init_adc_pins() { - // NOTE: Lpuart has been updated to properly enable + reset its own clocks. - // GPIO has not. - _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); - pins::configure_adc_pins(); -} -- cgit From 1ce2083f9a0fcf1cfbb10de0fb3ed44b460a5cc7 Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 5 Dec 2025 14:57:25 +0100 Subject: Enable DMA interrupts in constructors --- examples/mcxa/src/bin/lpuart_dma.rs | 6 ------ 1 file changed, 6 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/lpuart_dma.rs b/examples/mcxa/src/bin/lpuart_dma.rs index 5497f8646..1fc6595e6 100644 --- a/examples/mcxa/src/bin/lpuart_dma.rs +++ b/examples/mcxa/src/bin/lpuart_dma.rs @@ -32,12 +32,6 @@ async fn main(_spawner: Spawner) { defmt::info!("LPUART DMA example starting..."); - // Enable DMA interrupts (per-channel, as needed) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); - } - // Create UART configuration let config = Config { baudrate_bps: 115_200, -- cgit From fa54dd5849a083b286b2a3f1928428c8704d3d70 Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 5 Dec 2025 15:22:38 +0100 Subject: Create separate ring buffered RX receiver to encapsulate unsafe --- examples/mcxa/Cargo.toml | 1 + examples/mcxa/src/bin/lpuart_dma.rs | 2 +- examples/mcxa/src/bin/lpuart_ring_buffer.rs | 15 ++++----------- 3 files changed, 6 insertions(+), 12 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml index 4d0459f41..1ac8eac53 100644 --- a/examples/mcxa/Cargo.toml +++ b/examples/mcxa/Cargo.toml @@ -20,6 +20,7 @@ embassy-time-driver = "0.2.1" embedded-io-async = "0.6.1" heapless = "0.9.2" panic-probe = { version = "1.0", features = ["print-defmt"] } +static_cell = "2.1.1" tmp108 = "0.4.0" [profile.release] diff --git a/examples/mcxa/src/bin/lpuart_dma.rs b/examples/mcxa/src/bin/lpuart_dma.rs index 1fc6595e6..34d343452 100644 --- a/examples/mcxa/src/bin/lpuart_dma.rs +++ b/examples/mcxa/src/bin/lpuart_dma.rs @@ -14,7 +14,7 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; use embassy_mcxa::lpuart::{Config, LpuartDma}; -use embassy_mcxa::{bind_interrupts, pac}; +use embassy_mcxa::bind_interrupts; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind DMA channel interrupts using Embassy-style macro diff --git a/examples/mcxa/src/bin/lpuart_ring_buffer.rs b/examples/mcxa/src/bin/lpuart_ring_buffer.rs index 1d1a51970..b707e20f8 100644 --- a/examples/mcxa/src/bin/lpuart_ring_buffer.rs +++ b/examples/mcxa/src/bin/lpuart_ring_buffer.rs @@ -23,6 +23,7 @@ use embassy_mcxa::bind_interrupts; use embassy_mcxa::clocks::config::Div8; use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; +use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Bind DMA channel interrupts @@ -32,7 +33,7 @@ bind_interrupts!(struct Irqs { }); // Ring buffer for RX - power of 2 is ideal for modulo efficiency -static mut RX_RING_BUFFER: [u8; 64] = [0; 64]; +static RX_RING_BUFFER: ConstStaticCell<[u8; 64]> = ConstStaticCell::new([0; 64]); /// Helper to write a byte as hex to UART fn write_hex( @@ -75,17 +76,9 @@ async fn main(_spawner: Spawner) { tx.blocking_write(b"Setting up circular DMA for UART RX...\r\n") .unwrap(); + let buf = RX_RING_BUFFER.take(); // Set up the ring buffer with circular DMA - // The HAL handles: DMA request source, RDMAE enable, circular transfer config, NVIC enable - let ring_buf = unsafe { - let buf = &mut *core::ptr::addr_of_mut!(RX_RING_BUFFER); - rx.setup_ring_buffer(buf) - }; - - // Enable DMA requests to start continuous reception - unsafe { - rx.enable_dma_request(); - } + let mut ring_buf = rx.into_ring_dma_rx(buf); tx.blocking_write(b"Ring buffer ready! Type characters to see them echoed.\r\n") .unwrap(); -- cgit From 787bf84963ecd32306b6b2993504b2196f71cf72 Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 5 Dec 2025 15:55:28 +0100 Subject: use core::fmt::Write instead of home-rolled fmt --- examples/mcxa/src/bin/dma_channel_link.rs | 32 ++------------------- examples/mcxa/src/bin/dma_interleave_transfer.rs | 32 ++------------------- examples/mcxa/src/bin/dma_mem_to_mem.rs | 33 ++-------------------- examples/mcxa/src/bin/dma_memset.rs | 32 ++------------------- examples/mcxa/src/bin/dma_ping_pong_transfer.rs | 32 ++------------------- examples/mcxa/src/bin/dma_scatter_gather.rs | 31 ++------------------ .../mcxa/src/bin/dma_scatter_gather_builder.rs | 21 ++------------ examples/mcxa/src/bin/dma_wrap_transfer.rs | 32 ++------------------- 8 files changed, 16 insertions(+), 229 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/dma_channel_link.rs b/examples/mcxa/src/bin/dma_channel_link.rs index 92c7a9681..f7ab5d8fd 100644 --- a/examples/mcxa/src/bin/dma_channel_link.rs +++ b/examples/mcxa/src/bin/dma_channel_link.rs @@ -22,6 +22,7 @@ use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2In use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use core::fmt::Write as _; // Buffers static mut SRC_BUFFER: [u32; 4] = [1, 2, 3, 4]; @@ -37,38 +38,9 @@ bind_interrupts!(struct Irqs { DMA_CH2 => DmaCh2InterruptHandler; }); -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); + write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); } #[embassy_executor::main] diff --git a/examples/mcxa/src/bin/dma_interleave_transfer.rs b/examples/mcxa/src/bin/dma_interleave_transfer.rs index 7876e8978..98e301a7c 100644 --- a/examples/mcxa/src/bin/dma_interleave_transfer.rs +++ b/examples/mcxa/src/bin/dma_interleave_transfer.rs @@ -16,6 +16,7 @@ use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use core::fmt::Write as _; // Bind DMA channel 0 interrupt using Embassy-style macro bind_interrupts!(struct Irqs { @@ -29,38 +30,9 @@ const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2; static mut SRC_BUFFER: [u32; HALF_BUFF_LENGTH] = [0; HALF_BUFF_LENGTH]; static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); + write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); } #[embassy_executor::main] diff --git a/examples/mcxa/src/bin/dma_mem_to_mem.rs b/examples/mcxa/src/bin/dma_mem_to_mem.rs index 68f70e742..149e37326 100644 --- a/examples/mcxa/src/bin/dma_mem_to_mem.rs +++ b/examples/mcxa/src/bin/dma_mem_to_mem.rs @@ -19,6 +19,7 @@ use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, TransferOptions}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use core::fmt::Write as _; // Bind DMA channel 0 interrupt using Embassy-style macro bind_interrupts!(struct Irqs { @@ -32,40 +33,10 @@ static mut SRC_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; static mut MEMSET_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; // u32 max is 4294967295 (10 digits) - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - /// Helper to print a buffer as [v1, v2, v3, v4] to UART /// Takes a raw pointer to avoid warnings about shared references to mutable statics fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const [u32; BUFFER_LENGTH]) { - tx.blocking_write(b"[").ok(); - unsafe { - let buf = &*buf_ptr; - for (i, val) in buf.iter().enumerate() { - write_u32(tx, *val); - if i < buf.len() - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); + write!(tx, "{:?}", unsafe { &*buf_ptr }).ok(); } #[embassy_executor::main] diff --git a/examples/mcxa/src/bin/dma_memset.rs b/examples/mcxa/src/bin/dma_memset.rs index 95e365e47..bc4e78701 100644 --- a/examples/mcxa/src/bin/dma_memset.rs +++ b/examples/mcxa/src/bin/dma_memset.rs @@ -16,6 +16,7 @@ use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use core::fmt::Write as _; // Bind DMA channel 0 interrupt using Embassy-style macro bind_interrupts!(struct Irqs { @@ -28,38 +29,9 @@ const BUFFER_LENGTH: usize = 4; static mut PATTERN: u32 = 0; static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); + write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); } #[embassy_executor::main] diff --git a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs index f8f543382..728e4d408 100644 --- a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs +++ b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs @@ -31,6 +31,7 @@ use embassy_mcxa::dma::{self, DmaCh1InterruptHandler, DmaChannel, Tcd, TransferO use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use core::fmt::Write as _; // Source and destination buffers for Approach 1 (scatter/gather) static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; @@ -87,38 +88,9 @@ bind_interrupts!(struct Irqs { DMA_CH1 => DmaCh1InterruptHandler; }); -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); + write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); } #[embassy_executor::main] diff --git a/examples/mcxa/src/bin/dma_scatter_gather.rs b/examples/mcxa/src/bin/dma_scatter_gather.rs index 4b26bc2ed..ea553b843 100644 --- a/examples/mcxa/src/bin/dma_scatter_gather.rs +++ b/examples/mcxa/src/bin/dma_scatter_gather.rs @@ -20,6 +20,7 @@ use embassy_mcxa::dma::{self, DmaChannel, Tcd}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use core::fmt::Write as _; // Source and destination buffers static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; @@ -72,38 +73,10 @@ bind_interrupts!(struct Irqs { DMA_CH0 => ScatterGatherDmaHandler; }); -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); + write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); } #[embassy_executor::main] diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs index e483bb81f..29c54ca42 100644 --- a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs +++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs @@ -26,6 +26,7 @@ use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, ScatterGatherBuilder use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use core::fmt::Write as _; // Bind DMA channel 0 interrupt bind_interrupts!(struct Irqs { @@ -42,27 +43,9 @@ static mut DST1: [u32; 4] = [0; 4]; static mut DST2: [u32; 4] = [0; 4]; static mut DST3: [u32; 4] = [0; 4]; -/// Helper to write a u32 as hex to UART -fn write_hex(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - const HEX: &[u8; 16] = b"0123456789ABCDEF"; - for i in (0..8).rev() { - let nibble = ((val >> (i * 4)) & 0xF) as usize; - tx.blocking_write(&[HEX[nibble]]).ok(); - } -} - /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_hex(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); + write!(tx, "{:08X?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); } #[embassy_executor::main] diff --git a/examples/mcxa/src/bin/dma_wrap_transfer.rs b/examples/mcxa/src/bin/dma_wrap_transfer.rs index 82936d9d0..7fea4bf76 100644 --- a/examples/mcxa/src/bin/dma_wrap_transfer.rs +++ b/examples/mcxa/src/bin/dma_wrap_transfer.rs @@ -16,6 +16,7 @@ use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +use core::fmt::Write as _; // Bind DMA channel 0 interrupt using Embassy-style macro bind_interrupts!(struct Irqs { @@ -29,38 +30,9 @@ struct AlignedSrc([u32; 4]); static mut SRC: AlignedSrc = AlignedSrc([0; 4]); static mut DST: [u32; 8] = [0; 8]; -/// Helper to write a u32 as decimal ASCII to UART -fn write_u32(tx: &mut LpuartTx<'_, Blocking>, val: u32) { - let mut buf = [0u8; 10]; - let mut n = val; - let mut i = buf.len(); - - if n == 0 { - tx.blocking_write(b"0").ok(); - return; - } - - while n > 0 { - i -= 1; - buf[i] = b'0' + (n % 10) as u8; - n /= 10; - } - - tx.blocking_write(&buf[i..]).ok(); -} - /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - tx.blocking_write(b"[").ok(); - unsafe { - for i in 0..len { - write_u32(tx, *buf_ptr.add(i)); - if i < len - 1 { - tx.blocking_write(b", ").ok(); - } - } - } - tx.blocking_write(b"]").ok(); + write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); } #[embassy_executor::main] -- cgit From ae285b84ed551aa5c81443fcacb73e788a6d36c2 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 3 Dec 2025 14:07:57 -0800 Subject: CRC Fixes #74 Signed-off-by: Felipe Balbi --- examples/mcxa/src/bin/crc.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 examples/mcxa/src/bin/crc.rs (limited to 'examples') diff --git a/examples/mcxa/src/bin/crc.rs b/examples/mcxa/src/bin/crc.rs new file mode 100644 index 000000000..417b4f865 --- /dev/null +++ b/examples/mcxa/src/bin/crc.rs @@ -0,0 +1,39 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use hal::config::Config; +use hal::crc::Crc; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let config = Config::default(); + let mut p = hal::init(config); + + defmt::info!("CRC example"); + + let buf = b"123456789"; + + let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); + let sum = crc.feed_bytes(buf); + assert_eq!(sum, 0x29b1); + + let mut crc = Crc::new_maxim(p.CRC0.reborrow()); + let sum = crc.feed_bytes(buf); + assert_eq!(sum, 0x44c2); + + let mut crc = Crc::new_kermit(p.CRC0.reborrow()); + let sum = crc.feed_bytes(buf); + assert_eq!(sum, 0x2189); + + let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); + let sum = crc.feed_bytes(buf); + assert_eq!(sum, 0xcbf4_3926); + + let mut crc = Crc::new_posix(p.CRC0.reborrow()); + let sum = crc.feed_bytes(buf); + assert_eq!(sum, 0x765e_7680); + + defmt::info!("CRC successful"); +} -- cgit From b943d71365ef05b23db7066727f8bb6158b1a624 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 5 Dec 2025 08:41:43 -0800 Subject: mcxa/crc: document the use of align_to --- examples/mcxa/src/bin/crc.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/crc.rs b/examples/mcxa/src/bin/crc.rs index 417b4f865..f963620cc 100644 --- a/examples/mcxa/src/bin/crc.rs +++ b/examples/mcxa/src/bin/crc.rs @@ -16,23 +16,23 @@ async fn main(_spawner: Spawner) { let buf = b"123456789"; let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); - let sum = crc.feed_bytes(buf); + let sum = crc.feed(buf); assert_eq!(sum, 0x29b1); let mut crc = Crc::new_maxim(p.CRC0.reborrow()); - let sum = crc.feed_bytes(buf); + let sum = crc.feed(buf); assert_eq!(sum, 0x44c2); let mut crc = Crc::new_kermit(p.CRC0.reborrow()); - let sum = crc.feed_bytes(buf); + let sum = crc.feed(buf); assert_eq!(sum, 0x2189); let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); - let sum = crc.feed_bytes(buf); + let sum = crc.feed(buf); assert_eq!(sum, 0xcbf4_3926); let mut crc = Crc::new_posix(p.CRC0.reborrow()); - let sum = crc.feed_bytes(buf); + let sum = crc.feed(buf); assert_eq!(sum, 0x765e_7680); defmt::info!("CRC successful"); -- cgit From 5d8f3a3d18eda339e258193295cf332d7e01882e Mon Sep 17 00:00:00 2001 From: James Munns Date: Fri, 5 Dec 2025 20:45:59 +0100 Subject: Clean up some common PAC operations using helper methods --- examples/mcxa/src/bin/dma_mem_to_mem.rs | 75 ++++++++++----------------------- 1 file changed, 22 insertions(+), 53 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/dma_mem_to_mem.rs b/examples/mcxa/src/bin/dma_mem_to_mem.rs index 149e37326..b78745464 100644 --- a/examples/mcxa/src/bin/dma_mem_to_mem.rs +++ b/examples/mcxa/src/bin/dma_mem_to_mem.rs @@ -18,6 +18,7 @@ use embassy_mcxa::clocks::config::Div8; use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, TransferOptions}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; +use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; use core::fmt::Write as _; @@ -29,14 +30,14 @@ bind_interrupts!(struct Irqs { const BUFFER_LENGTH: usize = 4; // Buffers in RAM (static mut is automatically placed in .bss/.data) -static mut SRC_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; -static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; -static mut MEMSET_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; +static SRC_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([1, 2, 3, 4]); +static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); +static MEMSET_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); /// Helper to print a buffer as [v1, v2, v3, v4] to UART /// Takes a raw pointer to avoid warnings about shared references to mutable statics -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const [u32; BUFFER_LENGTH]) { - write!(tx, "{:?}", unsafe { &*buf_ptr }).ok(); +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: &[u32; BUFFER_LENGTH]) { + write!(tx, "{:?}", buf_ptr).ok(); } #[embassy_executor::main] @@ -70,18 +71,16 @@ async fn main(_spawner: Spawner) { tx.blocking_write(b"EDMA memory to memory example begin.\r\n\r\n") .unwrap(); - // Initialize buffers - unsafe { - SRC_BUFFER = [1, 2, 3, 4]; - DEST_BUFFER = [0; BUFFER_LENGTH]; - } + let src = SRC_BUFFER.take(); + let dst = DEST_BUFFER.take(); + let mst = MEMSET_BUFFER.take(); tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, &raw const SRC_BUFFER); + print_buffer(&mut tx, src); tx.blocking_write(b"\r\n").unwrap(); tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, &raw const DEST_BUFFER); + print_buffer(&mut tx, dst); tx.blocking_write(b"\r\n").unwrap(); tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") @@ -106,30 +105,17 @@ async fn main(_spawner: Spawner) { // Using async `.await` - the executor can run other tasks while waiting! // Perform type-safe memory-to-memory transfer using Embassy-style async API - unsafe { - let src = &*core::ptr::addr_of!(SRC_BUFFER); - let dst = &mut *core::ptr::addr_of_mut!(DEST_BUFFER); - - // Using async `.await` - the executor can run other tasks while waiting! - let transfer = dma_ch0.mem_to_mem(src, dst, options); - transfer.await; - } + // Using async `.await` - the executor can run other tasks while waiting! + let transfer = dma_ch0.mem_to_mem(src, dst, options); + transfer.await; tx.blocking_write(b"DMA mem-to-mem transfer complete!\r\n\r\n").unwrap(); tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, &raw const DEST_BUFFER); + print_buffer(&mut tx, dst); tx.blocking_write(b"\r\n").unwrap(); // Verify data - let mut mismatch = false; - unsafe { - for i in 0..BUFFER_LENGTH { - if SRC_BUFFER[i] != DEST_BUFFER[i] { - mismatch = true; - break; - } - } - } + let mut mismatch = src != dst; if mismatch { tx.blocking_write(b"FAIL: mem_to_mem mismatch!\r\n").unwrap(); @@ -152,37 +138,24 @@ async fn main(_spawner: Spawner) { .unwrap(); tx.blocking_write(b"Memset Buffer (before): ").unwrap(); - print_buffer(&mut tx, &raw const MEMSET_BUFFER); + print_buffer(&mut tx, mst); tx.blocking_write(b"\r\n").unwrap(); // Fill buffer with a pattern value using DMA memset let pattern: u32 = 0xDEADBEEF; tx.blocking_write(b"Filling with pattern 0xDEADBEEF...\r\n").unwrap(); - unsafe { - let dst = &mut *core::ptr::addr_of_mut!(MEMSET_BUFFER); - - // Using blocking_wait() for demonstration - also shows non-async usage - let transfer = dma_ch0.memset(&pattern, dst, options); - transfer.blocking_wait(); - } + // Using blocking_wait() for demonstration - also shows non-async usage + let transfer = dma_ch0.memset(&pattern, mst, options); + transfer.blocking_wait(); tx.blocking_write(b"DMA memset complete!\r\n\r\n").unwrap(); tx.blocking_write(b"Memset Buffer (after): ").unwrap(); - print_buffer(&mut tx, &raw const MEMSET_BUFFER); + print_buffer(&mut tx, mst); tx.blocking_write(b"\r\n").unwrap(); // Verify memset result - let mut memset_ok = true; - unsafe { - #[allow(clippy::needless_range_loop)] - for i in 0..BUFFER_LENGTH { - if MEMSET_BUFFER[i] != pattern { - memset_ok = false; - break; - } - } - } + let memset_ok = mst.iter().all(|&v| v == pattern); if !memset_ok { tx.blocking_write(b"FAIL: memset mismatch!\r\n").unwrap(); @@ -193,8 +166,4 @@ async fn main(_spawner: Spawner) { } tx.blocking_write(b"=== All DMA tests complete ===\r\n").unwrap(); - - loop { - cortex_m::asm::wfe(); - } } -- cgit From c48aa4c1a9820d3875995ca707c3aa133f17d19e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 5 Dec 2025 09:58:17 -0800 Subject: mcxa: crc: check all word types Signed-off-by: Felipe Balbi --- examples/mcxa/src/bin/crc.rs | 74 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 63 insertions(+), 11 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/crc.rs b/examples/mcxa/src/bin/crc.rs index f963620cc..12c423980 100644 --- a/examples/mcxa/src/bin/crc.rs +++ b/examples/mcxa/src/bin/crc.rs @@ -13,27 +13,79 @@ async fn main(_spawner: Spawner) { defmt::info!("CRC example"); - let buf = b"123456789"; + let buf_u8 = [0x00u8, 0x11, 0x22, 0x33]; + let buf_u16 = [0x0000u16, 0x1111, 0x2222, 0x3333]; + let buf_u32 = [0x0000_0000u32, 0x1111_1111, 0x2222_2222, 0x3333_3333]; + + // CCITT False + + let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u8); + assert_eq!(sum, 0x9627); let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); - let sum = crc.feed(buf); - assert_eq!(sum, 0x29b1); + let sum = crc.feed(&buf_u16); + assert_eq!(sum, 0xa467); + + let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u32); + assert_eq!(sum, 0xe5c7); + + // Maxim let mut crc = Crc::new_maxim(p.CRC0.reborrow()); - let sum = crc.feed(buf); - assert_eq!(sum, 0x44c2); + let sum = crc.feed(&buf_u8); + assert_eq!(sum, 0x4ff7); + + let mut crc = Crc::new_maxim(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u16); + assert_eq!(sum, 0x2afe); + + let mut crc = Crc::new_maxim(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u32); + assert_eq!(sum, 0x17d7); + + // Kermit + + let mut crc = Crc::new_kermit(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u8); + assert_eq!(sum, 0xccd2); let mut crc = Crc::new_kermit(p.CRC0.reborrow()); - let sum = crc.feed(buf); - assert_eq!(sum, 0x2189); + let sum = crc.feed(&buf_u16); + assert_eq!(sum, 0x66eb); + + let mut crc = Crc::new_kermit(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u32); + assert_eq!(sum, 0x75ea); + + // ISO HDLC + + let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u8); + assert_eq!(sum, 0x24c2_316d); + + let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u16); + assert_eq!(sum, 0x8a61_4178); let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); - let sum = crc.feed(buf); - assert_eq!(sum, 0xcbf4_3926); + let sum = crc.feed(&buf_u32); + assert_eq!(sum, 0xfab5_d04e); + + // POSIX + + let mut crc = Crc::new_posix(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u8); + assert_eq!(sum, 0xba8d_7868); + + let mut crc = Crc::new_posix(p.CRC0.reborrow()); + let sum = crc.feed(&buf_u16); + assert_eq!(sum, 0x6d76_4f58); let mut crc = Crc::new_posix(p.CRC0.reborrow()); - let sum = crc.feed(buf); - assert_eq!(sum, 0x765e_7680); + let sum = crc.feed(&buf_u32); + assert_eq!(sum, 0x2a5b_cb90); defmt::info!("CRC successful"); } -- cgit From 92f814962bbef71ef2f541f0d4dade54e6c58b11 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 6 Dec 2025 10:32:51 -0600 Subject: wpan: add libraries for wba --- examples/stm32wba/Cargo.toml | 4 +-- examples/stm32wba/src/bin/mac_ffd.rs | 58 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 examples/stm32wba/src/bin/mac_ffd.rs (limited to 'examples') diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index e071b24f0..b10114420 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -6,8 +6,8 @@ license = "MIT OR Apache-2.0" publish = false [dependencies] -embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba55cg", "time-driver-any", "memory-x", "exti"] } -embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wba55cg"] } +embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } +embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wba52cg"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } diff --git a/examples/stm32wba/src/bin/mac_ffd.rs b/examples/stm32wba/src/bin/mac_ffd.rs new file mode 100644 index 000000000..b15fb3452 --- /dev/null +++ b/examples/stm32wba/src/bin/mac_ffd.rs @@ -0,0 +1,58 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::Config; +use embassy_stm32::rcc::{Sysclk, mux}; +use embassy_stm32_wpan::bindings::mac::ST_MAC_callbacks_t; +use {defmt_rtt as _, panic_probe as _}; + +static _MAC_CALLBACKS: ST_MAC_callbacks_t = ST_MAC_callbacks_t { + mlmeAssociateCnfCb: None, // ST_MAC_MLMEAssociateCnfCbPtr, + mlmeAssociateIndCb: None, // ST_MAC_MLMEAssociateIndCbPtr, + mlmeBeaconNotifyIndCb: None, // ST_MAC_MLMEBeaconNotifyIndCbPtr, + mlmeCalibrateCnfCb: None, // ST_MAC_MLMECalibrateCnfCbPtr, + mlmeCommStatusIndCb: None, // ST_MAC_MLMECommStatusIndCbPtr, + mlmeDisassociateCnfCb: None, // ST_MAC_MLMEDisassociateCnfCbPtr, + mlmeDisassociateIndCb: None, // ST_MAC_MLMEDisassociateIndCbPtr, + mlmeDpsCnfCb: None, // ST_MAC_MLMEDpsCnfCbPtr, + mlmeDpsIndCb: None, // ST_MAC_MLMEDpsIndCbPtr, + mlmeGetCnfCb: None, // ST_MAC_MLMEGetCnfCbPtr, + mlmeGtsCnfCb: None, // ST_MAC_MLMEGtsCnfCbPtr, + mlmeGtsIndCb: None, // ST_MAC_MLMEGtsIndCbPtr, + mlmeOrphanIndCb: None, // ST_MAC_MLMEOrphanIndCbPtr, + mlmePollCnfCb: None, // ST_MAC_MLMEPollCnfCbPtr, + mlmeResetCnfCb: None, // ST_MAC_MLMEResetCnfCbPtr, + mlmeRxEnableCnfCb: None, // ST_MAC_MLMERxEnableCnfCbPtr, + mlmeScanCnfCb: None, // ST_MAC_MLMEScanCnfCbPtr, + mlmeSetCnfCb: None, // ST_MAC_MLMESetCnfCbPtr, + mlmeSoundingCnfCb: None, // ST_MAC_MLMESoundingCnfCbPtr, + mlmeStartCnfCb: None, // ST_MAC_MLMEStartCnfCbPtr, + mlmeSyncLossIndCb: None, // ST_MAC_MLMESyncLossIndCbPtr, + mcpsDataIndCb: None, // ST_MAC_MCPSDataIndCbPtr, + mcpsDataCnfCb: None, // ST_MAC_MCPSDataCnfCbPtr, + mcpsPurgeCnfCb: None, // ST_MAC_MCPSPurgeCnfCbPtr, + mlmePollIndCb: None, // ST_MAC_MLMEPollIndCbPtr, + mlmeBeaconReqIndCb: None, // ST_MAC_MLMEBeaconReqIndCbPtr, + mlmeBeaconCnfCb: None, // ST_MAC_MLMEBeaconCnfCbPtr, + mlmeGetPwrInfoTableCnfCb: None, // ST_MAC_MLMEGetPwrInfoTableCnfCbPtr, + mlmeSetPwrInfoTableCnfCb: None, // ST_MAC_MLMESetPwrInfoTableCnfCbPtr, +}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + + config.rcc.sys = Sysclk::HSI; + config.rcc.mux.rngsel = mux::Rngsel::HSI; + + let _p = embassy_stm32::init(config); + info!("Hello World!"); + + // let status = unsafe { ST_MAC_init(&_MAC_CALLBACKS as *const _ as *mut _) }; + // + // info!("mac init: {}", status); + + cortex_m::asm::bkpt(); +} -- cgit From 4f66b2f2090e2fcfd7d92f9ebd07cc9048eb70d7 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 6 Dec 2025 12:17:00 -0600 Subject: adc: type-erase regs instance --- examples/stm32h5/src/bin/adc_dma.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32h5/src/bin/adc_dma.rs b/examples/stm32h5/src/bin/adc_dma.rs index 2138257f7..e625e3a34 100644 --- a/examples/stm32h5/src/bin/adc_dma.rs +++ b/examples/stm32h5/src/bin/adc_dma.rs @@ -66,7 +66,7 @@ async fn adc2_task( adc_task(adc, dma, pin1, pin2).await; } -async fn adc_task<'a, T: adc::Instance>( +async fn adc_task<'a, T: adc::DefaultInstance>( adc: Peri<'a, T>, mut dma: Peri<'a, impl RxDma>, pin1: impl AdcChannel, -- cgit From 8cf8b2406d4be014d466a9318303a65c5c7ff076 Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Mon, 8 Dec 2025 17:21:27 +0800 Subject: feat: add nRF54LM20A support Signed-off-by: Haobo Gu --- examples/nrf54lm20/.cargo/config.toml | 10 ++++++ examples/nrf54lm20/Cargo.toml | 37 +++++++++++++++++++++ examples/nrf54lm20/build.rs | 35 ++++++++++++++++++++ examples/nrf54lm20/memory.x | 5 +++ examples/nrf54lm20/run.sh | 15 +++++++++ examples/nrf54lm20/src/bin/blinky.rs | 23 +++++++++++++ examples/nrf54lm20/src/bin/gpio.rs | 23 +++++++++++++ examples/nrf54lm20/src/bin/gpiote_channel.rs | 49 ++++++++++++++++++++++++++++ examples/nrf54lm20/src/bin/gpiote_port.rs | 33 +++++++++++++++++++ examples/nrf54lm20/src/bin/timer.rs | 30 +++++++++++++++++ 10 files changed, 260 insertions(+) create mode 100644 examples/nrf54lm20/.cargo/config.toml create mode 100644 examples/nrf54lm20/Cargo.toml create mode 100644 examples/nrf54lm20/build.rs create mode 100644 examples/nrf54lm20/memory.x create mode 100755 examples/nrf54lm20/run.sh create mode 100644 examples/nrf54lm20/src/bin/blinky.rs create mode 100644 examples/nrf54lm20/src/bin/gpio.rs create mode 100644 examples/nrf54lm20/src/bin/gpiote_channel.rs create mode 100644 examples/nrf54lm20/src/bin/gpiote_port.rs create mode 100644 examples/nrf54lm20/src/bin/timer.rs (limited to 'examples') diff --git a/examples/nrf54lm20/.cargo/config.toml b/examples/nrf54lm20/.cargo/config.toml new file mode 100644 index 000000000..e26853bef --- /dev/null +++ b/examples/nrf54lm20/.cargo/config.toml @@ -0,0 +1,10 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# runner = "probe-rs run --chip nrf54lm20" +# probe-rs doesn't support nRF54LM20A right now, so jlink is needed +runner = "./run.sh" + +[build] +target = "thumbv8m.main-none-eabihf" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/nrf54lm20/Cargo.toml b/examples/nrf54lm20/Cargo.toml new file mode 100644 index 000000000..5482fc77a --- /dev/null +++ b/examples/nrf54lm20/Cargo.toml @@ -0,0 +1,37 @@ +[package] +edition = "2024" +name = "embassy-nrf54lm20-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" +publish = false + +[dependencies] +embassy-futures = { version = "0.1.2", path = "../../embassy-futures" } +embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } +embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54lm20-app-s", "time-driver-grtc", "gpiote", "unstable-pac", "time"] } +embedded-io = { version = "0.6.0", features = ["defmt-03"] } +embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } + +rand = { version = "0.9.0", default-features = false } + +defmt = "1.0.1" +defmt-rtt = "1.0.0" +panic-probe = { version = "1.0.0", features = ["print-defmt"] } + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" + +embedded-storage = "0.3.1" +portable-atomic = "1" + +static_cell = "2" + +[profile.release] +debug = 2 + +[package.metadata.embassy] +build = [ + { target = "thumbv8m.main-none-eabihf", artifact-dir = "out/examples/nrf54lm20" } +] diff --git a/examples/nrf54lm20/build.rs b/examples/nrf54lm20/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/nrf54lm20/build.rs @@ -0,0 +1,35 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); + + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/nrf54lm20/memory.x b/examples/nrf54lm20/memory.x new file mode 100644 index 000000000..564f488ac --- /dev/null +++ b/examples/nrf54lm20/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 2036K + RAM : ORIGIN = 0x20000000, LENGTH = 512K +} diff --git a/examples/nrf54lm20/run.sh b/examples/nrf54lm20/run.sh new file mode 100755 index 000000000..2386163a7 --- /dev/null +++ b/examples/nrf54lm20/run.sh @@ -0,0 +1,15 @@ +cp $1 $1.elf + +ELF_FILE="$1.elf" + +JLinkExe <) { + loop { + pin.wait_for_low().await; + info!("Button {:?} pressed!", n); + pin.wait_for_high().await; + info!("Button {:?} released!", n); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + info!("Starting!"); + + let btn1 = Input::new(p.P1_26, Pull::Up); + let btn2 = Input::new(p.P1_09, Pull::Up); + let btn3 = Input::new(p.P1_08, Pull::Up); + let btn4 = Input::new(p.P0_05, Pull::Up); + + spawner.spawn(unwrap!(button_task(1, btn1))); + spawner.spawn(unwrap!(button_task(2, btn2))); + spawner.spawn(unwrap!(button_task(3, btn3))); + spawner.spawn(unwrap!(button_task(4, btn4))); +} diff --git a/examples/nrf54lm20/src/bin/timer.rs b/examples/nrf54lm20/src/bin/timer.rs new file mode 100644 index 000000000..68acc91c1 --- /dev/null +++ b/examples/nrf54lm20/src/bin/timer.rs @@ -0,0 +1,30 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task] +async fn run1() { + loop { + info!("BIG INFREQUENT TICK"); + Timer::after_secs(10).await; + } +} + +#[embassy_executor::task] +async fn run2() { + loop { + info!("tick"); + Timer::after_secs(1).await; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let _p = embassy_nrf::init(Default::default()); + spawner.spawn(unwrap!(run1())); + spawner.spawn(unwrap!(run2())); +} -- cgit From 31543f38ec05965b0903c7da0854b375ac6a3d1c Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 8 Dec 2025 11:28:54 +0100 Subject: feat: add support for nrf54 to embassy-boot examples --- examples/boot/application/nrf/Cargo.toml | 5 +++-- examples/boot/application/nrf/README.md | 2 +- examples/boot/application/nrf/src/bin/a.rs | 13 ++++++++++--- examples/boot/application/nrf/src/bin/b.rs | 2 ++ examples/boot/bootloader/nrf/Cargo.toml | 4 +++- examples/boot/bootloader/nrf/src/main.rs | 3 +++ 6 files changed, 22 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 55053bc33..4176fd499 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -9,7 +9,7 @@ publish = false embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" } embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] } -embassy-nrf = { version = "0.8.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } +embassy-nrf = { version = "0.8.0", path = "../../../../embassy-nrf", features = ["gpiote", ] } embassy-boot = { version = "0.6.1", path = "../../../../embassy-boot", features = [] } embassy-boot-nrf = { version = "0.9.0", path = "../../../../embassy-boot-nrf", features = [] } embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" } @@ -40,5 +40,6 @@ build = [ { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9160-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9160" }, { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9120-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9120" }, { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9151-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9151" }, - { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9161-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9161" } + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9161-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9161" }, + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf54l15-app-s", "skip-include"], artifact-dir = "out/examples/boot/nrf54l15" } ] diff --git a/examples/boot/application/nrf/README.md b/examples/boot/application/nrf/README.md index 9d6d20336..c92ccb358 100644 --- a/examples/boot/application/nrf/README.md +++ b/examples/boot/application/nrf/README.md @@ -22,7 +22,7 @@ cp memory-bl.x ../../bootloader/nrf/memory.x # Flash bootloader cargo flash --manifest-path ../../bootloader/nrf/Cargo.toml --features embassy-nrf/nrf52840 --target thumbv7em-none-eabi --release --chip nRF52840_xxAA # Build 'b' -cargo build --release --bin b --features embassy-nrf/nrf52840 +cargo build --release --bin b --features embassy-nrf/nrf52840,time-driver-rtc1 # Generate binary for 'b' cargo objcopy --release --bin b --features embassy-nrf/nrf52840 --target thumbv7em-none-eabi -- -O binary b.bin ``` diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index 2c1d1a7bb..f317414fc 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -27,6 +27,11 @@ async fn main(_spawner: Spawner) { let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard); + // nRF54 DK + // let mut button = Input::new(p.P1_13, Pull::Up); + // let mut led = Output::new(p.P1_14, Level::Low, OutputDrive::Standard); + // let mut led_reverted = Output::new(p.P2_09, Level::High, OutputDrive::Standard); + //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); //let mut button = Input::new(p.P1_02, Pull::Up); @@ -40,8 +45,8 @@ async fn main(_spawner: Spawner) { // the watchdog will cause the device to reset as per its configured timeout in the bootloader. // This helps is avoid a situation where new firmware might be bad and block our executor. // If firmware is bad in this way then the bootloader will revert to any previous version. - let wdt_config = wdt::Config::try_new(&p.WDT).unwrap(); - let (_wdt, [_wdt_handle]) = match Watchdog::try_new(p.WDT, wdt_config) { + let wdt_config = wdt::Config::try_new(&p.WDT0).unwrap(); + let (_wdt, [_wdt_handle]) = match Watchdog::try_new(p.WDT0, wdt_config) { Ok(x) => x, Err(_) => { // Watchdog already active with the wrong number of handles, waiting for it to timeout... @@ -51,11 +56,13 @@ async fn main(_spawner: Spawner) { } }; + // RRAMC for nRF54 + // let nvmc = Nvmc::new(p.RRAMC); let nvmc = Nvmc::new(p.NVMC); let nvmc = Mutex::new(BlockingAsync::new(nvmc)); let config = FirmwareUpdaterConfig::from_linkerfile(&nvmc, &nvmc); - let mut magic = [0; 4]; + let mut magic = [0; 16]; let mut updater = FirmwareUpdater::new(config, &mut magic); let state = updater.get_state().await.unwrap(); if state == State::Revert { diff --git a/examples/boot/application/nrf/src/bin/b.rs b/examples/boot/application/nrf/src/bin/b.rs index de97b6a22..7ed78ea85 100644 --- a/examples/boot/application/nrf/src/bin/b.rs +++ b/examples/boot/application/nrf/src/bin/b.rs @@ -15,6 +15,8 @@ async fn main(_spawner: Spawner) { // nRF91 DK // let mut led = Output::new(p.P0_02, Level::Low, OutputDrive::Standard); + // nrf54l15 dk + // let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); loop { led.set_high(); diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml index 1fea2b7d7..59fc6e4ed 100644 --- a/examples/boot/bootloader/nrf/Cargo.toml +++ b/examples/boot/bootloader/nrf/Cargo.toml @@ -27,6 +27,7 @@ defmt = [ softdevice = [ "embassy-boot-nrf/softdevice", ] +nrf54 = [] [profile.dev] debug = 2 @@ -65,5 +66,6 @@ build = [ { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9160-ns"] }, { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9120-ns"] }, { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9151-ns"] }, - { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9161-ns"] } + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9161-ns"] }, + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf54l15-app-s", "nrf54"] } ] diff --git a/examples/boot/bootloader/nrf/src/main.rs b/examples/boot/bootloader/nrf/src/main.rs index 76c4c1048..9ba57e81b 100644 --- a/examples/boot/bootloader/nrf/src/main.rs +++ b/examples/boot/bootloader/nrf/src/main.rs @@ -28,7 +28,10 @@ fn main() -> ! { wdt_config.action_during_sleep = SleepConfig::RUN; wdt_config.action_during_debug_halt = HaltConfig::PAUSE; + #[cfg(not(feature = "nrf54"))] let flash = WatchdogFlash::start(Nvmc::new(p.NVMC), p.WDT, wdt_config); + #[cfg(feature = "nrf54")] + let flash = WatchdogFlash::start(Nvmc::new(p.RRAMC), p.WDT0, wdt_config); let flash = Mutex::new(RefCell::new(flash)); let config = BootLoaderConfig::from_linkerfile_blocking(&flash, &flash, &flash); -- cgit From 427c6a495d5d3a9b76da7f1673a85f45ad6e1227 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Mon, 8 Dec 2025 11:43:51 +0100 Subject: chore: use feature guards for nrf54 in examples --- examples/boot/application/nrf/Cargo.toml | 13 +++++++------ examples/boot/application/nrf/src/bin/a.rs | 24 ++++++++++++++++++------ examples/boot/application/nrf/src/bin/b.rs | 4 +++- 3 files changed, 28 insertions(+), 13 deletions(-) (limited to 'examples') diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 4176fd499..79286e295 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -33,13 +33,14 @@ defmt = [ "embassy-boot-nrf/defmt", "embassy-sync/defmt", ] +nrf54 = ["embassy-nrf/time-driver-grtc"] [package.metadata.embassy] build = [ - { target = "thumbv7em-none-eabi", features = ["embassy-nrf/nrf52840", "skip-include"], artifact-dir = "out/examples/boot/nrf52840" }, - { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9160-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9160" }, - { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9120-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9120" }, - { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9151-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9151" }, - { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9161-ns", "skip-include"], artifact-dir = "out/examples/boot/nrf9161" }, - { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf54l15-app-s", "skip-include"], artifact-dir = "out/examples/boot/nrf54l15" } + { target = "thumbv7em-none-eabi", features = ["embassy-nrf/nrf52840", "embassy-nrf/time-driver-rtc1", "skip-include"], artifact-dir = "out/examples/boot/nrf52840" }, + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9160-ns", "embassy-nrf/time-driver-rtc1", "skip-include"], artifact-dir = "out/examples/boot/nrf9160" }, + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9120-ns", "embassy-nrf/time-driver-rtc1", "skip-include"], artifact-dir = "out/examples/boot/nrf9120" }, + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9151-ns", "embassy-nrf/time-driver-rtc1", "skip-include"], artifact-dir = "out/examples/boot/nrf9151" }, + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf9161-ns", "embassy-nrf/time-driver-rtc1", "skip-include"], artifact-dir = "out/examples/boot/nrf9161" }, + { target = "thumbv8m.main-none-eabihf", features = ["embassy-nrf/nrf54l15-app-s", "nrf54", "skip-include"], artifact-dir = "out/examples/boot/nrf54l15" } ] diff --git a/examples/boot/application/nrf/src/bin/a.rs b/examples/boot/application/nrf/src/bin/a.rs index f317414fc..035ffe214 100644 --- a/examples/boot/application/nrf/src/bin/a.rs +++ b/examples/boot/application/nrf/src/bin/a.rs @@ -23,14 +23,20 @@ static APP_B: &[u8] = include_bytes!("../../b.bin"); async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); + #[cfg(not(feature = "nrf54"))] let mut button = Input::new(p.P0_11, Pull::Up); + #[cfg(not(feature = "nrf54"))] let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); + #[cfg(not(feature = "nrf54"))] let mut led_reverted = Output::new(p.P0_14, Level::High, OutputDrive::Standard); // nRF54 DK - // let mut button = Input::new(p.P1_13, Pull::Up); - // let mut led = Output::new(p.P1_14, Level::Low, OutputDrive::Standard); - // let mut led_reverted = Output::new(p.P2_09, Level::High, OutputDrive::Standard); + #[cfg(feature = "nrf54")] + let mut button = Input::new(p.P1_13, Pull::Up); + #[cfg(feature = "nrf54")] + let mut led = Output::new(p.P1_14, Level::Low, OutputDrive::Standard); + #[cfg(feature = "nrf54")] + let mut led_reverted = Output::new(p.P2_09, Level::High, OutputDrive::Standard); //let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); //let mut button = Input::new(p.P1_02, Pull::Up); @@ -45,8 +51,12 @@ async fn main(_spawner: Spawner) { // the watchdog will cause the device to reset as per its configured timeout in the bootloader. // This helps is avoid a situation where new firmware might be bad and block our executor. // If firmware is bad in this way then the bootloader will revert to any previous version. - let wdt_config = wdt::Config::try_new(&p.WDT0).unwrap(); - let (_wdt, [_wdt_handle]) = match Watchdog::try_new(p.WDT0, wdt_config) { + #[cfg(feature = "nrf54")] + let wdt = p.WDT0; + #[cfg(not(feature = "nrf54"))] + let wdt = p.WDT; + let wdt_config = wdt::Config::try_new(&wdt).unwrap(); + let (_wdt, [_wdt_handle]) = match Watchdog::try_new(wdt, wdt_config) { Ok(x) => x, Err(_) => { // Watchdog already active with the wrong number of handles, waiting for it to timeout... @@ -57,7 +67,9 @@ async fn main(_spawner: Spawner) { }; // RRAMC for nRF54 - // let nvmc = Nvmc::new(p.RRAMC); + #[cfg(feature = "nrf54")] + let nvmc = Nvmc::new(p.RRAMC); + #[cfg(not(feature = "nrf54"))] let nvmc = Nvmc::new(p.NVMC); let nvmc = Mutex::new(BlockingAsync::new(nvmc)); diff --git a/examples/boot/application/nrf/src/bin/b.rs b/examples/boot/application/nrf/src/bin/b.rs index 7ed78ea85..6718df5a1 100644 --- a/examples/boot/application/nrf/src/bin/b.rs +++ b/examples/boot/application/nrf/src/bin/b.rs @@ -10,13 +10,15 @@ use panic_reset as _; #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); + #[cfg(not(feature = "nrf54"))] let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); // let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); // nRF91 DK // let mut led = Output::new(p.P0_02, Level::Low, OutputDrive::Standard); // nrf54l15 dk - // let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); + #[cfg(feature = "nrf54")] + let mut led = Output::new(p.P1_10, Level::Low, OutputDrive::Standard); loop { led.set_high(); -- cgit From a2b9df58483531a5eb7be701a6f6c3f1a772b4ca Mon Sep 17 00:00:00 2001 From: Haobo Gu Date: Mon, 8 Dec 2025 21:27:38 +0800 Subject: chore: remove jlink script in nRF54LM20A example, use probe-rs instead Signed-off-by: Haobo Gu chore: remove jlink script in nRF54LM20A example, use probe-rs instead Signed-off-by: Haobo Gu --- examples/nrf54lm20/.cargo/config.toml | 5 ++--- examples/nrf54lm20/run.sh | 15 --------------- 2 files changed, 2 insertions(+), 18 deletions(-) delete mode 100755 examples/nrf54lm20/run.sh (limited to 'examples') diff --git a/examples/nrf54lm20/.cargo/config.toml b/examples/nrf54lm20/.cargo/config.toml index e26853bef..0ffebed14 100644 --- a/examples/nrf54lm20/.cargo/config.toml +++ b/examples/nrf54lm20/.cargo/config.toml @@ -1,7 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# runner = "probe-rs run --chip nrf54lm20" -# probe-rs doesn't support nRF54LM20A right now, so jlink is needed -runner = "./run.sh" +# Note: it needs the latest git version of probe-rs +runner = "probe-rs run --chip nrf54lm20a" [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/nrf54lm20/run.sh b/examples/nrf54lm20/run.sh deleted file mode 100755 index 2386163a7..000000000 --- a/examples/nrf54lm20/run.sh +++ /dev/null @@ -1,15 +0,0 @@ -cp $1 $1.elf - -ELF_FILE="$1.elf" - -JLinkExe < Date: Mon, 8 Dec 2025 17:58:00 +0100 Subject: Clean up examples, move interrupts to be more fully managed --- examples/mcxa/src/bin/adc_interrupt.rs | 4 +- examples/mcxa/src/bin/adc_polling.rs | 2 +- examples/mcxa/src/bin/dma_channel_link.rs | 21 +---- examples/mcxa/src/bin/dma_interleave_transfer.rs | 58 +++++-------- examples/mcxa/src/bin/dma_mem_to_mem.rs | 81 ++++-------------- examples/mcxa/src/bin/dma_memset.rs | 97 ++++------------------ examples/mcxa/src/bin/dma_ping_pong_transfer.rs | 5 +- examples/mcxa/src/bin/dma_scatter_gather.rs | 3 +- .../mcxa/src/bin/dma_scatter_gather_builder.rs | 16 +--- examples/mcxa/src/bin/dma_wrap_transfer.rs | 16 +--- examples/mcxa/src/bin/i2c-async.rs | 2 +- examples/mcxa/src/bin/i2c-scan-blocking.rs | 2 +- examples/mcxa/src/bin/lpuart_buffered.rs | 2 +- examples/mcxa/src/bin/lpuart_dma.rs | 11 +-- examples/mcxa/src/bin/lpuart_ring_buffer.rs | 8 -- 15 files changed, 72 insertions(+), 256 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index c88b1fe8d..83d8046b3 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -4,13 +4,13 @@ use embassy_executor::Spawner; use embassy_mcxa_examples::init_adc_pins; use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::PoweredClock; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; +use hal::clocks::PoweredClock; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; -use hal::{InterruptExt, bind_interrupts}; +use hal::{bind_interrupts, InterruptExt}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index 07c50f224..ddf3f586b 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -4,8 +4,8 @@ use embassy_executor::Spawner; use embassy_mcxa_examples::init_adc_pins; use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::PoweredClock; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; +use hal::clocks::PoweredClock; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; diff --git a/examples/mcxa/src/bin/dma_channel_link.rs b/examples/mcxa/src/bin/dma_channel_link.rs index f7ab5d8fd..2d757a636 100644 --- a/examples/mcxa/src/bin/dma_channel_link.rs +++ b/examples/mcxa/src/bin/dma_channel_link.rs @@ -16,13 +16,14 @@ #![no_std] #![no_main] +use core::fmt::Write as _; + use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler, DmaCh2InterruptHandler, DmaChannel}; +use embassy_mcxa::dma::DmaChannel; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; +use embassy_mcxa::pac; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -use core::fmt::Write as _; // Buffers static mut SRC_BUFFER: [u32; 4] = [1, 2, 3, 4]; @@ -30,14 +31,6 @@ static mut DEST_BUFFER0: [u32; 4] = [0; 4]; static mut DEST_BUFFER1: [u32; 4] = [0; 4]; static mut DEST_BUFFER2: [u32; 4] = [0; 4]; -// Bind DMA channel interrupts using Embassy-style macro -// The standard handlers call on_interrupt() which wakes wakers and clears flags -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; - DMA_CH1 => DmaCh1InterruptHandler; - DMA_CH2 => DmaCh2InterruptHandler; -}); - /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); @@ -84,12 +77,6 @@ async fn main(_spawner: Spawner) { .normal_operation() }); - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH2); - } - let config = Config { baudrate_bps: 115_200, ..Default::default() diff --git a/examples/mcxa/src/bin/dma_interleave_transfer.rs b/examples/mcxa/src/bin/dma_interleave_transfer.rs index 98e301a7c..03441fc32 100644 --- a/examples/mcxa/src/bin/dma_interleave_transfer.rs +++ b/examples/mcxa/src/bin/dma_interleave_transfer.rs @@ -10,29 +10,25 @@ #![no_std] #![no_main] +use core::fmt::Write as _; + use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; +use embassy_mcxa::dma::DmaChannel; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; +use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -use core::fmt::Write as _; - -// Bind DMA channel 0 interrupt using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); const BUFFER_LENGTH: usize = 16; const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2; // Buffers in RAM -static mut SRC_BUFFER: [u32; HALF_BUFF_LENGTH] = [0; HALF_BUFF_LENGTH]; -static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; +static SRC_BUFFER: ConstStaticCell<[u32; HALF_BUFF_LENGTH]> = ConstStaticCell::new([0; HALF_BUFF_LENGTH]); +static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); /// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); +fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf: &[u32]) { + write!(tx, "{:?}", buf).ok(); } #[embassy_executor::main] @@ -49,11 +45,6 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA interleave transfer example starting..."); - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - let config = Config { baudrate_bps: 115_200, ..Default::default() @@ -66,17 +57,16 @@ async fn main(_spawner: Spawner) { .unwrap(); // Initialize buffers - unsafe { - SRC_BUFFER = [1, 2, 3, 4, 5, 6, 7, 8]; - DEST_BUFFER = [0; BUFFER_LENGTH]; - } + let src = SRC_BUFFER.take(); + *src = [1, 2, 3, 4, 5, 6, 7, 8]; + let dst = DEST_BUFFER.take(); tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, HALF_BUFF_LENGTH); + print_buffer(&mut tx, src); tx.blocking_write(b"\r\n").unwrap(); tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + print_buffer(&mut tx, dst); tx.blocking_write(b"\r\n").unwrap(); tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") @@ -109,10 +99,8 @@ async fn main(_spawner: Spawner) { t.ch_int().write(|w| w.int().clear_bit_by_one()); // Source/destination addresses - t.tcd_saddr() - .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(SRC_BUFFER) as u32)); - t.tcd_daddr() - .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); + t.tcd_saddr().write(|w| w.saddr().bits(src.as_ptr() as u32)); + t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32)); // Custom offsets for interleaving t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read @@ -156,21 +144,15 @@ async fn main(_spawner: Spawner) { tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") .unwrap(); tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); + print_buffer(&mut tx, dst); tx.blocking_write(b"\r\n\r\n").unwrap(); // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0 let mut mismatch = false; - unsafe { - for i in 0..BUFFER_LENGTH { - if i % 2 == 0 { - if DEST_BUFFER[i] != SRC_BUFFER[i / 2] { - mismatch = true; - } - } else if DEST_BUFFER[i] != 0 { - mismatch = true; - } - } + let diter = dst.chunks_exact(2); + let siter = src.iter(); + for (ch, src) in diter.zip(siter) { + mismatch |= !matches!(ch, [a, 0] if a == src); } if mismatch { diff --git a/examples/mcxa/src/bin/dma_mem_to_mem.rs b/examples/mcxa/src/bin/dma_mem_to_mem.rs index b78745464..b20068b79 100644 --- a/examples/mcxa/src/bin/dma_mem_to_mem.rs +++ b/examples/mcxa/src/bin/dma_mem_to_mem.rs @@ -15,17 +15,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, TransferOptions}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; +use embassy_mcxa::dma::{DmaChannel, TransferOptions}; use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -use core::fmt::Write as _; - -// Bind DMA channel 0 interrupt using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); const BUFFER_LENGTH: usize = 4; @@ -34,12 +26,6 @@ static SRC_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new( static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); static MEMSET_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); -/// Helper to print a buffer as [v1, v2, v3, v4] to UART -/// Takes a raw pointer to avoid warnings about shared references to mutable statics -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: &[u32; BUFFER_LENGTH]) { - write!(tx, "{:?}", buf_ptr).ok(); -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { // Small delay to allow probe-rs to attach after reset @@ -54,37 +40,15 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA memory-to-memory example starting..."); - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - // Create UART for debug output - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA memory to memory example begin.\r\n\r\n") - .unwrap(); + defmt::info!("EDMA memory to memory example begin."); let src = SRC_BUFFER.take(); let dst = DEST_BUFFER.take(); let mst = MEMSET_BUFFER.take(); - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, src); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, dst); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") - .unwrap(); + defmt::info!("Source Buffer: {=[?]}", src.as_slice()); + defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice()); + defmt::info!("Configuring DMA with Embassy-style API..."); // Create DMA channel let dma_ch0 = DmaChannel::new(p.DMA_CH0); @@ -109,19 +73,13 @@ async fn main(_spawner: Spawner) { let transfer = dma_ch0.mem_to_mem(src, dst, options); transfer.await; - tx.blocking_write(b"DMA mem-to-mem transfer complete!\r\n\r\n").unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, dst); - tx.blocking_write(b"\r\n").unwrap(); + defmt::info!("DMA mem-to-mem transfer complete!"); + defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice()); // Verify data - let mut mismatch = src != dst; - - if mismatch { - tx.blocking_write(b"FAIL: mem_to_mem mismatch!\r\n").unwrap(); + if src != dst { defmt::error!("FAIL: mem_to_mem mismatch!"); } else { - tx.blocking_write(b"PASS: mem_to_mem verified.\r\n\r\n").unwrap(); defmt::info!("PASS: mem_to_mem verified."); } @@ -134,36 +92,27 @@ async fn main(_spawner: Spawner) { // - Incrementing destination address // - Uses the same Transfer future pattern - tx.blocking_write(b"--- Demonstrating memset() feature ---\r\n\r\n") - .unwrap(); + defmt::info!("--- Demonstrating memset() feature ---"); - tx.blocking_write(b"Memset Buffer (before): ").unwrap(); - print_buffer(&mut tx, mst); - tx.blocking_write(b"\r\n").unwrap(); + defmt::info!("Memset Buffer (before): {=[?]}", mst.as_slice()); // Fill buffer with a pattern value using DMA memset let pattern: u32 = 0xDEADBEEF; - tx.blocking_write(b"Filling with pattern 0xDEADBEEF...\r\n").unwrap(); + defmt::info!("Filling with pattern 0xDEADBEEF..."); // Using blocking_wait() for demonstration - also shows non-async usage let transfer = dma_ch0.memset(&pattern, mst, options); transfer.blocking_wait(); - tx.blocking_write(b"DMA memset complete!\r\n\r\n").unwrap(); - tx.blocking_write(b"Memset Buffer (after): ").unwrap(); - print_buffer(&mut tx, mst); - tx.blocking_write(b"\r\n").unwrap(); + defmt::info!("DMA memset complete!"); + defmt::info!("Memset Buffer (after): {=[?]}", mst.as_slice()); // Verify memset result - let memset_ok = mst.iter().all(|&v| v == pattern); - - if !memset_ok { - tx.blocking_write(b"FAIL: memset mismatch!\r\n").unwrap(); + if !mst.iter().all(|&v| v == pattern) { defmt::error!("FAIL: memset mismatch!"); } else { - tx.blocking_write(b"PASS: memset verified.\r\n\r\n").unwrap(); defmt::info!("PASS: memset verified."); } - tx.blocking_write(b"=== All DMA tests complete ===\r\n").unwrap(); + defmt::info!("=== All DMA tests complete ==="); } diff --git a/examples/mcxa/src/bin/dma_memset.rs b/examples/mcxa/src/bin/dma_memset.rs index bc4e78701..d7b03e91b 100644 --- a/examples/mcxa/src/bin/dma_memset.rs +++ b/examples/mcxa/src/bin/dma_memset.rs @@ -12,27 +12,15 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; +use embassy_mcxa::dma::DmaChannel; +use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -use core::fmt::Write as _; - -// Bind DMA channel 0 interrupt using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); const BUFFER_LENGTH: usize = 4; // Buffers in RAM -static mut PATTERN: u32 = 0; -static mut DEST_BUFFER: [u32; BUFFER_LENGTH] = [0; BUFFER_LENGTH]; - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); -} +static PATTERN: u32 = 0xDEADBEEF; +static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -47,48 +35,14 @@ async fn main(_spawner: Spawner) { let p = hal::init(cfg); defmt::info!("DMA memset example starting..."); - - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA memset example begin.\r\n\r\n").unwrap(); + defmt::info!("EDMA memset example begin."); // Initialize buffers - unsafe { - PATTERN = 0xDEADBEEF; - DEST_BUFFER = [0; BUFFER_LENGTH]; - } - - tx.blocking_write(b"Pattern value: 0x").unwrap(); - // Print pattern in hex - unsafe { - let hex_chars = b"0123456789ABCDEF"; - let mut hex_buf = [0u8; 8]; - let mut val = PATTERN; - for i in (0..8).rev() { - hex_buf[i] = hex_chars[(val & 0xF) as usize]; - val >>= 4; - } - tx.blocking_write(&hex_buf).ok(); - } - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") - .unwrap(); + let pat = &PATTERN; + let dst = DEST_BUFFER.take(); + defmt::info!("Pattern Value: {=u32}", pat); + defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice()); + defmt::info!("Configuring DMA with Embassy-style API..."); // Create DMA channel using Embassy-style API let dma_ch0 = DmaChannel::new(p.DMA_CH0); @@ -116,11 +70,9 @@ async fn main(_spawner: Spawner) { t.ch_int().write(|w| w.int().clear_bit_by_one()); // Source address (pattern) - fixed - t.tcd_saddr() - .write(|w| w.saddr().bits(core::ptr::addr_of_mut!(PATTERN) as u32)); + t.tcd_saddr().write(|w| w.saddr().bits(pat as *const _ as u32)); // Destination address - increments - t.tcd_daddr() - .write(|w| w.daddr().bits(core::ptr::addr_of_mut!(DEST_BUFFER) as u32)); + t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32)); // Source offset = 0 (stays fixed), Dest offset = 4 (increments) t.tcd_soff().write(|w| w.soff().bits(0)); @@ -147,7 +99,7 @@ async fn main(_spawner: Spawner) { cortex_m::asm::dsb(); - tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); + defmt::info!("Triggering transfer..."); dma_ch0.trigger_start(); } @@ -159,32 +111,15 @@ async fn main(_spawner: Spawner) { dma_ch0.clear_done(); } - tx.blocking_write(b"\r\nEDMA memset example finish.\r\n\r\n").unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER) as *const u32, BUFFER_LENGTH); - tx.blocking_write(b"\r\n\r\n").unwrap(); + defmt::info!("EDMA memset example finish."); + defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice()); // Verify: All elements should equal PATTERN - let mut mismatch = false; - unsafe { - #[allow(clippy::needless_range_loop)] - for i in 0..BUFFER_LENGTH { - if DEST_BUFFER[i] != PATTERN { - mismatch = true; - break; - } - } - } + let mismatch = dst.iter().any(|i| *i != *pat); if mismatch { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); defmt::error!("FAIL: Mismatch detected!"); } else { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); defmt::info!("PASS: Data verified."); } - - loop { - cortex_m::asm::wfe(); - } } diff --git a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs index 728e4d408..58f643b80 100644 --- a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs +++ b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs @@ -23,15 +23,15 @@ #![no_std] #![no_main] +use core::fmt::Write as _; use core::sync::atomic::{AtomicBool, Ordering}; use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaCh1InterruptHandler, DmaChannel, Tcd, TransferOptions}; +use embassy_mcxa::dma::{self, DmaChannel, Tcd, TransferOptions}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -use core::fmt::Write as _; // Source and destination buffers for Approach 1 (scatter/gather) static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; @@ -85,7 +85,6 @@ impl embassy_mcxa::interrupt::typelevel::Handler PingPongDmaHandler; - DMA_CH1 => DmaCh1InterruptHandler; }); /// Helper to print a buffer to UART diff --git a/examples/mcxa/src/bin/dma_scatter_gather.rs b/examples/mcxa/src/bin/dma_scatter_gather.rs index ea553b843..3e34e95b1 100644 --- a/examples/mcxa/src/bin/dma_scatter_gather.rs +++ b/examples/mcxa/src/bin/dma_scatter_gather.rs @@ -12,6 +12,7 @@ #![no_std] #![no_main] +use core::fmt::Write as _; use core::sync::atomic::{AtomicBool, Ordering}; use embassy_executor::Spawner; @@ -20,7 +21,6 @@ use embassy_mcxa::dma::{self, DmaChannel, Tcd}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -use core::fmt::Write as _; // Source and destination buffers static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; @@ -73,7 +73,6 @@ bind_interrupts!(struct Irqs { DMA_CH0 => ScatterGatherDmaHandler; }); - /// Helper to print a buffer to UART fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs index 29c54ca42..d0f9ae9c4 100644 --- a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs +++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs @@ -20,18 +20,13 @@ #![no_std] #![no_main] +use core::fmt::Write as _; + use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel, ScatterGatherBuilder}; +use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder}; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -use core::fmt::Write as _; - -// Bind DMA channel 0 interrupt -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); // Source buffers (multiple segments) static mut SRC1: [u32; 4] = [0x11111111, 0x22222222, 0x33333333, 0x44444444]; @@ -62,11 +57,6 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA Scatter-Gather Builder example starting..."); - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - // Create UART for debug output let config = Config { baudrate_bps: 115_200, diff --git a/examples/mcxa/src/bin/dma_wrap_transfer.rs b/examples/mcxa/src/bin/dma_wrap_transfer.rs index 7fea4bf76..acfd29f08 100644 --- a/examples/mcxa/src/bin/dma_wrap_transfer.rs +++ b/examples/mcxa/src/bin/dma_wrap_transfer.rs @@ -10,18 +10,13 @@ #![no_std] #![no_main] +use core::fmt::Write as _; + use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaChannel}; +use embassy_mcxa::dma::DmaChannel; use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -use core::fmt::Write as _; - -// Bind DMA channel 0 interrupt using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; -}); // Source buffer: 4 words (16 bytes), aligned to 16 bytes for modulo #[repr(align(16))] @@ -49,11 +44,6 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA wrap transfer example starting..."); - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - let config = Config { baudrate_bps: 115_200, ..Default::default() diff --git a/examples/mcxa/src/bin/i2c-async.rs b/examples/mcxa/src/bin/i2c-async.rs index edcfd5f22..47b5f3cbe 100644 --- a/examples/mcxa/src/bin/i2c-async.rs +++ b/examples/mcxa/src/bin/i2c-async.rs @@ -6,8 +6,8 @@ use embassy_time::Timer; use hal::bind_interrupts; use hal::clocks::config::Div8; use hal::config::Config; -use hal::i2c::InterruptHandler; use hal::i2c::controller::{self, I2c, Speed}; +use hal::i2c::InterruptHandler; use hal::peripherals::LPI2C3; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; diff --git a/examples/mcxa/src/bin/i2c-scan-blocking.rs b/examples/mcxa/src/bin/i2c-scan-blocking.rs index 0197f9b1d..4e203597b 100644 --- a/examples/mcxa/src/bin/i2c-scan-blocking.rs +++ b/examples/mcxa/src/bin/i2c-scan-blocking.rs @@ -2,8 +2,8 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa::Input; use embassy_mcxa::gpio::Pull; +use embassy_mcxa::Input; use embassy_time::Timer; use hal::clocks::config::Div8; use hal::config::Config; diff --git a/examples/mcxa/src/bin/lpuart_buffered.rs b/examples/mcxa/src/bin/lpuart_buffered.rs index 47b56b7c7..420589d00 100644 --- a/examples/mcxa/src/bin/lpuart_buffered.rs +++ b/examples/mcxa/src/bin/lpuart_buffered.rs @@ -3,8 +3,8 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::lpuart::Config; use embassy_mcxa::lpuart::buffered::BufferedLpuart; +use embassy_mcxa::lpuart::Config; use embassy_mcxa::{bind_interrupts, lpuart}; use embedded_io_async::Write; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; diff --git a/examples/mcxa/src/bin/lpuart_dma.rs b/examples/mcxa/src/bin/lpuart_dma.rs index 34d343452..cc86f6a40 100644 --- a/examples/mcxa/src/bin/lpuart_dma.rs +++ b/examples/mcxa/src/bin/lpuart_dma.rs @@ -12,17 +12,9 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; use embassy_mcxa::lpuart::{Config, LpuartDma}; -use embassy_mcxa::bind_interrupts; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -// Bind DMA channel interrupts using Embassy-style macro -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; - DMA_CH1 => DmaCh1InterruptHandler; -}); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut cfg = hal::config::Config::default(); @@ -40,7 +32,8 @@ async fn main(_spawner: Spawner) { // Create UART instance with DMA channels let mut lpuart = LpuartDma::new( - p.LPUART2, p.P2_2, // TX pin + p.LPUART2, // Instance + p.P2_2, // TX pin p.P2_3, // RX pin p.DMA_CH0, // TX DMA channel p.DMA_CH1, // RX DMA channel diff --git a/examples/mcxa/src/bin/lpuart_ring_buffer.rs b/examples/mcxa/src/bin/lpuart_ring_buffer.rs index b707e20f8..be7fd4534 100644 --- a/examples/mcxa/src/bin/lpuart_ring_buffer.rs +++ b/examples/mcxa/src/bin/lpuart_ring_buffer.rs @@ -19,19 +19,11 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa::bind_interrupts; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{DmaCh0InterruptHandler, DmaCh1InterruptHandler}; use embassy_mcxa::lpuart::{Config, LpuartDma, LpuartTxDma}; use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -// Bind DMA channel interrupts -bind_interrupts!(struct Irqs { - DMA_CH0 => DmaCh0InterruptHandler; - DMA_CH1 => DmaCh1InterruptHandler; -}); - // Ring buffer for RX - power of 2 is ideal for modulo efficiency static RX_RING_BUFFER: ConstStaticCell<[u8; 64]> = ConstStaticCell::new([0; 64]); -- cgit From cc34871ebef2513f69ce52f8f8f717473e701ec2 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 8 Dec 2025 08:44:50 -0800 Subject: review comments --- examples/mcxa/Cargo.toml | 1 + examples/mcxa/src/bin/crc.rs | 103 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 20 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/Cargo.toml b/examples/mcxa/Cargo.toml index 4d0459f41..19d8d8657 100644 --- a/examples/mcxa/Cargo.toml +++ b/examples/mcxa/Cargo.toml @@ -8,6 +8,7 @@ publish = false [dependencies] cortex-m = { version = "0.7", features = ["critical-section-single-core"] } cortex-m-rt = { version = "0.7", features = ["set-sp", "set-vtor"] } +crc = "3.4.0" critical-section = "1.2.0" defmt = "1.0" defmt-rtt = "1.0" diff --git a/examples/mcxa/src/bin/crc.rs b/examples/mcxa/src/bin/crc.rs index 12c423980..0125e625c 100644 --- a/examples/mcxa/src/bin/crc.rs +++ b/examples/mcxa/src/bin/crc.rs @@ -6,6 +6,28 @@ use hal::config::Config; use hal::crc::Crc; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; +const CCITT_FALSE: crc::Algorithm = crc::Algorithm { + width: 16, + poly: 0x1021, + init: 0xffff, + refin: false, + refout: false, + xorout: 0, + check: 0x29b1, + residue: 0x0000, +}; + +const POSIX: crc::Algorithm = crc::Algorithm { + width: 32, + poly: 0x04c1_1db7, + init: 0, + refin: false, + refout: false, + xorout: 0xffff_ffff, + check: 0x765e_7680, + residue: 0x0000, +}; + #[embassy_executor::main] async fn main(_spawner: Spawner) { let config = Config::default(); @@ -19,72 +41,113 @@ async fn main(_spawner: Spawner) { // CCITT False + let sw_crc = crc::Crc::::new(&CCITT_FALSE); + let mut digest = sw_crc.digest(); + digest.update(&buf_u8); + let sw_sum = digest.finalize(); + let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u8); - assert_eq!(sum, 0x9627); + crc.feed(&buf_u8); + let sum = crc.finalize(); + assert_eq!(sum, sw_sum); let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u16); + crc.feed(&buf_u16); + let sum = crc.finalize(); assert_eq!(sum, 0xa467); let mut crc = Crc::new_ccitt_false(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u32); + crc.feed(&buf_u32); + let sum = crc.finalize(); assert_eq!(sum, 0xe5c7); // Maxim + let sw_crc = crc::Crc::::new(&crc::CRC_16_MAXIM_DOW); + let mut digest = sw_crc.digest(); + digest.update(&buf_u8); + let sw_sum = digest.finalize(); + let mut crc = Crc::new_maxim(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u8); - assert_eq!(sum, 0x4ff7); + crc.feed(&buf_u8); + let sum = crc.finalize(); + assert_eq!(sum, sw_sum); let mut crc = Crc::new_maxim(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u16); + crc.feed(&buf_u16); + let sum = crc.finalize(); assert_eq!(sum, 0x2afe); let mut crc = Crc::new_maxim(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u32); + crc.feed(&buf_u32); + let sum = crc.finalize(); assert_eq!(sum, 0x17d7); // Kermit + let sw_crc = crc::Crc::::new(&crc::CRC_16_KERMIT); + let mut digest = sw_crc.digest(); + digest.update(&buf_u8); + let sw_sum = digest.finalize(); + let mut crc = Crc::new_kermit(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u8); - assert_eq!(sum, 0xccd2); + crc.feed(&buf_u8); + let sum = crc.finalize(); + assert_eq!(sum, sw_sum); let mut crc = Crc::new_kermit(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u16); + crc.feed(&buf_u16); + let sum = crc.finalize(); assert_eq!(sum, 0x66eb); let mut crc = Crc::new_kermit(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u32); + crc.feed(&buf_u32); + let sum = crc.finalize(); assert_eq!(sum, 0x75ea); // ISO HDLC + let sw_crc = crc::Crc::::new(&crc::CRC_32_ISO_HDLC); + let mut digest = sw_crc.digest(); + digest.update(&buf_u8); + let sw_sum = digest.finalize(); + let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u8); - assert_eq!(sum, 0x24c2_316d); + crc.feed(&buf_u8); + let sum = crc.finalize(); + assert_eq!(sum, sw_sum); let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u16); + crc.feed(&buf_u16); + let sum = crc.finalize(); assert_eq!(sum, 0x8a61_4178); let mut crc = Crc::new_iso_hdlc(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u32); + crc.feed(&buf_u32); + let sum = crc.finalize(); assert_eq!(sum, 0xfab5_d04e); // POSIX + let sw_crc = crc::Crc::::new(&POSIX); + let mut digest = sw_crc.digest(); + digest.update(&buf_u8); + let sw_sum = digest.finalize(); + let mut crc = Crc::new_posix(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u8); - assert_eq!(sum, 0xba8d_7868); + crc.feed(&buf_u8); + let sum = crc.finalize(); + + assert_eq!(sum, sw_sum); let mut crc = Crc::new_posix(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u16); + crc.feed(&buf_u16); + let sum = crc.finalize(); assert_eq!(sum, 0x6d76_4f58); let mut crc = Crc::new_posix(p.CRC0.reborrow()); - let sum = crc.feed(&buf_u32); + crc.feed(&buf_u32); + let sum = crc.finalize(); assert_eq!(sum, 0x2a5b_cb90); defmt::info!("CRC successful"); -- cgit From f7d5abfe946e71d426c9d0e96231e48faf27f6cd Mon Sep 17 00:00:00 2001 From: James Munns Date: Mon, 8 Dec 2025 20:33:45 +0100 Subject: Work on scatter-gather-builder --- .../mcxa/src/bin/dma_scatter_gather_builder.rs | 168 +++++++-------------- 1 file changed, 57 insertions(+), 111 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs index d0f9ae9c4..ba8682cee 100644 --- a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs +++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs @@ -25,23 +25,18 @@ use core::fmt::Write as _; use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; +use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Source buffers (multiple segments) -static mut SRC1: [u32; 4] = [0x11111111, 0x22222222, 0x33333333, 0x44444444]; -static mut SRC2: [u32; 4] = [0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD]; -static mut SRC3: [u32; 4] = [0x12345678, 0x9ABCDEF0, 0xFEDCBA98, 0x76543210]; +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 mut DST1: [u32; 4] = [0; 4]; -static mut DST2: [u32; 4] = [0; 4]; -static mut DST3: [u32; 4] = [0; 4]; - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - write!(tx, "{:08X?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); -} +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) { @@ -57,47 +52,30 @@ async fn main(_spawner: Spawner) { defmt::info!("DMA Scatter-Gather Builder example starting..."); - // Create UART for debug output - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"DMA Scatter-Gather Builder Example\r\n").unwrap(); - tx.blocking_write(b"===================================\r\n\r\n") - .unwrap(); + 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 - tx.blocking_write(b"Source buffers:\r\n").unwrap(); - tx.blocking_write(b" SRC1: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" SRC2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" SRC3: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC3) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - tx.blocking_write(b"Destination buffers (before):\r\n").unwrap(); - tx.blocking_write(b" DST1: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" DST2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" DST3: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); + 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); - tx.blocking_write(b"Building scatter-gather chain with builder API...\r\n") - .unwrap(); + defmt::info!("Building scatter-gather chain with builder API..."); // ========================================================================= // ScatterGatherBuilder API demonstration @@ -112,27 +90,24 @@ async fn main(_spawner: Spawner) { let mut builder = ScatterGatherBuilder::::new(); // Add three transfer segments - the builder handles TCD linking automatically - unsafe { - let src1 = &*core::ptr::addr_of!(SRC1); - let dst1 = &mut *core::ptr::addr_of_mut!(DST1); - builder.add_transfer(src1, dst1); - } - - unsafe { - let src2 = &*core::ptr::addr_of!(SRC2); - let dst2 = &mut *core::ptr::addr_of_mut!(DST2); - builder.add_transfer(src2, dst2); - } - - unsafe { - let src3 = &*core::ptr::addr_of!(SRC3); - let dst3 = &mut *core::ptr::addr_of_mut!(DST3); - builder.add_transfer(src3, dst3); - } - - tx.blocking_write(b"Added 3 transfer segments to chain.\r\n").unwrap(); - tx.blocking_write(b"Starting scatter-gather transfer with .await...\r\n\r\n") - .unwrap(); + 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..."); + + // TODO START + defmt::info!("Destination buffers (after):"); + defmt::info!(" DST1: {=[?]}", dst1.as_slice()); + defmt::info!(" DST2: {=[?]}", dst2.as_slice()); + defmt::info!(" DST3: {=[?]}", dst3.as_slice()); + // TODO: If we want to make the `builder.build()` below safe, the above prints SHOULD NOT + // compile. We need to make sure that the lifetime of the builder reflects that it is + // "consuming" the slices until the builder is dropped, since we can access them to print here, + // that means that the borrow checker isn't enforcing that yet. + todo!("ABOVE CODE SHOULDN'T COMPILE"); + // TODO END // Build and execute the scatter-gather chain // The build() method: @@ -145,60 +120,31 @@ async fn main(_spawner: Spawner) { transfer.blocking_wait(); } - tx.blocking_write(b"Scatter-gather transfer complete!\r\n\r\n").unwrap(); + defmt::info!("Scatter-gather transfer complete!"); // Show results - tx.blocking_write(b"Destination buffers (after):\r\n").unwrap(); - tx.blocking_write(b" DST1: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" DST2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b" DST3: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST3) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); + 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; - unsafe { - let src1 = core::ptr::addr_of!(SRC1) as *const u32; - let dst1 = core::ptr::addr_of!(DST1) as *const u32; - for i in 0..4 { - if *src1.add(i) != *dst1.add(i) { - all_ok = false; - } - } - - let src2 = core::ptr::addr_of!(SRC2) as *const u32; - let dst2 = core::ptr::addr_of!(DST2) as *const u32; - for i in 0..4 { - if *src2.add(i) != *dst2.add(i) { - all_ok = false; - } - } - - let src3 = core::ptr::addr_of!(SRC3) as *const u32; - let dst3 = core::ptr::addr_of!(DST3) as *const u32; - for i in 0..4 { - if *src3.add(i) != *dst3.add(i) { - all_ok = false; - } - } + for (src, dst) in comps { + all_ok &= src == dst; } if all_ok { - tx.blocking_write(b"PASS: All segments verified!\r\n").unwrap(); defmt::info!("PASS: All segments verified!"); } else { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); defmt::error!("FAIL: Mismatch detected!"); } - tx.blocking_write(b"\r\n=== Scatter-Gather Builder example complete ===\r\n") - .unwrap(); - - loop { - cortex_m::asm::wfe(); - } + defmt::info!("=== Scatter-Gather Builder example complete ==="); } -- cgit From 4386b39e2516c453966d894b4fd265fae9d82c1a Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 9 Dec 2025 14:41:19 +0100 Subject: Enforce scatter gather API statically --- examples/mcxa/src/bin/dma_scatter_gather_builder.rs | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs index ba8682cee..1691129f6 100644 --- a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs +++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs @@ -20,8 +20,6 @@ #![no_std] #![no_main] -use core::fmt::Write as _; - use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; use embassy_mcxa::dma::{DmaChannel, ScatterGatherBuilder}; @@ -97,28 +95,14 @@ async fn main(_spawner: Spawner) { defmt::info!("Added 3 transfer segments to chain."); defmt::info!("Starting scatter-gather transfer with .await..."); - // TODO START - defmt::info!("Destination buffers (after):"); - defmt::info!(" DST1: {=[?]}", dst1.as_slice()); - defmt::info!(" DST2: {=[?]}", dst2.as_slice()); - defmt::info!(" DST3: {=[?]}", dst3.as_slice()); - // TODO: If we want to make the `builder.build()` below safe, the above prints SHOULD NOT - // compile. We need to make sure that the lifetime of the builder reflects that it is - // "consuming" the slices until the builder is dropped, since we can access them to print here, - // that means that the borrow checker isn't enforcing that yet. - todo!("ABOVE CODE SHOULDN'T COMPILE"); - // TODO END - // 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 - unsafe { - let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather"); - transfer.blocking_wait(); - } + let transfer = builder.build(&dma_ch0).expect("Failed to build scatter-gather"); + transfer.blocking_wait(); defmt::info!("Scatter-gather transfer complete!"); -- cgit From e962f5568a9f6433dcd6ad3e41d3faabb8b7c552 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 9 Dec 2025 15:52:12 +0100 Subject: Clean up remaining examples, move some to "raw" examples --- examples/mcxa/src/bin/dma_channel_link.rs | 331 -------------------- examples/mcxa/src/bin/dma_interleave_transfer.rs | 169 ---------- examples/mcxa/src/bin/dma_memset.rs | 125 -------- examples/mcxa/src/bin/dma_ping_pong_transfer.rs | 347 --------------------- examples/mcxa/src/bin/dma_scatter_gather.rs | 234 -------------- .../mcxa/src/bin/dma_scatter_gather_builder.rs | 6 +- examples/mcxa/src/bin/raw_dma_channel_link.rs | 279 +++++++++++++++++ .../mcxa/src/bin/raw_dma_interleave_transfer.rs | 141 +++++++++ examples/mcxa/src/bin/raw_dma_memset.rs | 129 ++++++++ .../mcxa/src/bin/raw_dma_ping_pong_transfer.rs | 269 ++++++++++++++++ examples/mcxa/src/bin/raw_dma_scatter_gather.rs | 188 +++++++++++ 11 files changed, 1007 insertions(+), 1211 deletions(-) delete mode 100644 examples/mcxa/src/bin/dma_channel_link.rs delete mode 100644 examples/mcxa/src/bin/dma_interleave_transfer.rs delete mode 100644 examples/mcxa/src/bin/dma_memset.rs delete mode 100644 examples/mcxa/src/bin/dma_ping_pong_transfer.rs delete mode 100644 examples/mcxa/src/bin/dma_scatter_gather.rs create mode 100644 examples/mcxa/src/bin/raw_dma_channel_link.rs create mode 100644 examples/mcxa/src/bin/raw_dma_interleave_transfer.rs create mode 100644 examples/mcxa/src/bin/raw_dma_memset.rs create mode 100644 examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs create mode 100644 examples/mcxa/src/bin/raw_dma_scatter_gather.rs (limited to 'examples') diff --git a/examples/mcxa/src/bin/dma_channel_link.rs b/examples/mcxa/src/bin/dma_channel_link.rs deleted file mode 100644 index 2d757a636..000000000 --- a/examples/mcxa/src/bin/dma_channel_link.rs +++ /dev/null @@ -1,331 +0,0 @@ -//! DMA channel linking example for MCXA276. -//! -//! This example demonstrates DMA channel linking (minor and major loop linking): -//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with: -//! - Minor Link to Channel 1 (triggers CH1 after each minor loop) -//! - Major Link to Channel 2 (triggers CH2 after major loop completes) -//! - Channel 1: Transfers SRC_BUFFER to DEST_BUFFER1 (triggered by CH0 minor link) -//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link) -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::new()` for channel creation -//! - `DmaChannel::is_done()` and `clear_done()` helper methods -//! - Channel linking with `set_minor_link()` and `set_major_link()` -//! - Standard `DmaCh*InterruptHandler` with `bind_interrupts!` macro - -#![no_std] -#![no_main] - -use core::fmt::Write as _; - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::DmaChannel; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::pac; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Buffers -static mut SRC_BUFFER: [u32; 4] = [1, 2, 3, 4]; -static mut DEST_BUFFER0: [u32; 4] = [0; 4]; -static mut DEST_BUFFER1: [u32; 4] = [0; 4]; -static mut DEST_BUFFER2: [u32; 4] = [0; 4]; - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); -} - -#[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 channel link example starting..."); - - // DMA is initialized during hal::init() - no need to call ensure_init() - - let pac_periphs = unsafe { pac::Peripherals::steal() }; - let dma0 = &pac_periphs.dma0; - let edma = unsafe { &*pac::Edma0Tcd0::ptr() }; - - // Clear any residual state - for i in 0..3 { - let t = edma.tcd(i); - t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one()); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - t.ch_es().write(|w| w.err().clear_bit_by_one()); - t.ch_mux().write(|w| unsafe { w.bits(0) }); - } - - // Clear Global Halt/Error state - dma0.mp_csr().modify(|_, w| { - w.halt() - .normal_operation() - .hae() - .normal_operation() - .ecx() - .normal_operation() - .cx() - .normal_operation() - }); - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA channel link example begin.\r\n\r\n").unwrap(); - - // Initialize buffers - unsafe { - SRC_BUFFER = [1, 2, 3, 4]; - DEST_BUFFER0 = [0; 4]; - DEST_BUFFER1 = [0; 4]; - DEST_BUFFER2 = [0; 4]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC_BUFFER) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST0 (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST1 (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST2 (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA channels with Embassy-style API...\r\n") - .unwrap(); - - let ch0 = DmaChannel::new(p.DMA_CH0); - let ch1 = DmaChannel::new(p.DMA_CH1); - let ch2 = DmaChannel::new(p.DMA_CH2); - - // Configure channels using direct TCD access (advanced feature demo) - // This example demonstrates channel linking which requires direct TCD manipulation - - // Helper to configure TCD for memory-to-memory transfer - // Parameters: channel, src, dst, width, nbytes (minor loop), count (major loop), interrupt - #[allow(clippy::too_many_arguments)] - unsafe fn configure_tcd( - edma: &embassy_mcxa::pac::edma_0_tcd0::RegisterBlock, - ch: usize, - src: u32, - dst: u32, - width: u8, - nbytes: u32, - count: u16, - enable_int: bool, - ) { - let t = edma.tcd(ch); - - // Reset channel state - t.ch_csr().write(|w| { - w.erq() - .disable() - .earq() - .disable() - .eei() - .no_error() - .ebw() - .disable() - .done() - .clear_bit_by_one() - }); - t.ch_es().write(|w| w.bits(0)); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - - // Source/destination addresses - t.tcd_saddr().write(|w| w.saddr().bits(src)); - t.tcd_daddr().write(|w| w.daddr().bits(dst)); - - // Offsets: increment by width - t.tcd_soff().write(|w| w.soff().bits(width as u16)); - t.tcd_doff().write(|w| w.doff().bits(width as u16)); - - // Attributes: size = log2(width) - let size = match width { - 1 => 0, - 2 => 1, - 4 => 2, - _ => 0, - }; - t.tcd_attr().write(|w| w.ssize().bits(size).dsize().bits(size)); - - // Number of bytes per minor loop - t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); - - // Major loop: reset source address after major loop - let total_bytes = nbytes * count as u32; - t.tcd_slast_sda() - .write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32)); - t.tcd_dlast_sga() - .write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32)); - - // Major loop count - t.tcd_biter_elinkno().write(|w| w.biter().bits(count)); - t.tcd_citer_elinkno().write(|w| w.citer().bits(count)); - - // Control/status: enable interrupt if requested - if enable_int { - t.tcd_csr().write(|w| w.intmajor().set_bit()); - } else { - t.tcd_csr().write(|w| w.intmajor().clear_bit()); - } - - cortex_m::asm::dsb(); - } - - unsafe { - // Channel 0: Transfer 16 bytes total (8 bytes per minor loop, 2 major iterations) - // Minor Link -> Channel 1 - // Major Link -> Channel 2 - configure_tcd( - edma, - 0, - core::ptr::addr_of!(SRC_BUFFER) as u32, - core::ptr::addr_of_mut!(DEST_BUFFER0) as u32, - 4, // src width - 8, // nbytes (minor loop = 2 words) - 2, // count (major loop = 2 iterations) - false, // no interrupt - ); - ch0.set_minor_link(1); // Link to CH1 after each minor loop - ch0.set_major_link(2); // Link to CH2 after major loop - - // Channel 1: Transfer 16 bytes (triggered by CH0 minor link) - configure_tcd( - edma, - 1, - core::ptr::addr_of!(SRC_BUFFER) as u32, - core::ptr::addr_of_mut!(DEST_BUFFER1) as u32, - 4, - 16, // full buffer in one minor loop - 1, // 1 major iteration - false, - ); - - // Channel 2: Transfer 16 bytes (triggered by CH0 major link) - configure_tcd( - edma, - 2, - core::ptr::addr_of!(SRC_BUFFER) as u32, - core::ptr::addr_of_mut!(DEST_BUFFER2) as u32, - 4, - 16, // full buffer in one minor loop - 1, // 1 major iteration - true, // enable interrupt - ); - } - - tx.blocking_write(b"Triggering Channel 0 (1st minor loop)...\r\n") - .unwrap(); - - // Trigger first minor loop of CH0 - unsafe { - ch0.trigger_start(); - } - - // Wait for CH1 to complete (triggered by CH0 minor link) - while !ch1.is_done() { - cortex_m::asm::nop(); - } - unsafe { - ch1.clear_done(); - } - - tx.blocking_write(b"CH1 done (via minor link).\r\n").unwrap(); - tx.blocking_write(b"Triggering Channel 0 (2nd minor loop)...\r\n") - .unwrap(); - - // Trigger second minor loop of CH0 - unsafe { - ch0.trigger_start(); - } - - // Wait for CH0 major loop to complete - while !ch0.is_done() { - cortex_m::asm::nop(); - } - unsafe { - ch0.clear_done(); - } - - tx.blocking_write(b"CH0 major loop done.\r\n").unwrap(); - - // Wait for CH2 to complete (triggered by CH0 major link) - // Using is_done() instead of AtomicBool - the standard interrupt handler - // clears the interrupt flag and wakes wakers, but DONE bit remains set - while !ch2.is_done() { - cortex_m::asm::nop(); - } - unsafe { - ch2.clear_done(); - } - - tx.blocking_write(b"CH2 done (via major link).\r\n\r\n").unwrap(); - - tx.blocking_write(b"EDMA channel link example finish.\r\n\r\n").unwrap(); - - tx.blocking_write(b"DEST0 (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER0) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST1 (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER1) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"DEST2 (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DEST_BUFFER2) as *const u32, 4); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify all buffers match source - let mut success = true; - unsafe { - let src_ptr = core::ptr::addr_of!(SRC_BUFFER) as *const u32; - let dst0_ptr = core::ptr::addr_of!(DEST_BUFFER0) as *const u32; - let dst1_ptr = core::ptr::addr_of!(DEST_BUFFER1) as *const u32; - let dst2_ptr = core::ptr::addr_of!(DEST_BUFFER2) as *const u32; - - for i in 0..4 { - if *dst0_ptr.add(i) != *src_ptr.add(i) { - success = false; - } - if *dst1_ptr.add(i) != *src_ptr.add(i) { - success = false; - } - if *dst2_ptr.add(i) != *src_ptr.add(i) { - success = false; - } - } - } - - if success { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); - defmt::info!("PASS: Data verified."); - } else { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/mcxa/src/bin/dma_interleave_transfer.rs b/examples/mcxa/src/bin/dma_interleave_transfer.rs deleted file mode 100644 index 03441fc32..000000000 --- a/examples/mcxa/src/bin/dma_interleave_transfer.rs +++ /dev/null @@ -1,169 +0,0 @@ -//! DMA interleaved transfer example for MCXA276. -//! -//! This example demonstrates using DMA with custom source/destination offsets -//! to interleave data during transfer. -//! -//! # Embassy-style features demonstrated: -//! - `TransferOptions::default()` for configuration (used internally) -//! - DMA channel with `DmaChannel::new()` - -#![no_std] -#![no_main] - -use core::fmt::Write as _; - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::DmaChannel; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use static_cell::ConstStaticCell; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -const BUFFER_LENGTH: usize = 16; -const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2; - -// Buffers in RAM -static SRC_BUFFER: ConstStaticCell<[u32; HALF_BUFF_LENGTH]> = ConstStaticCell::new([0; HALF_BUFF_LENGTH]); -static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf: &[u32]) { - write!(tx, "{:?}", buf).ok(); -} - -#[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 interleave transfer example starting..."); - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA interleave transfer example begin.\r\n\r\n") - .unwrap(); - - // Initialize buffers - let src = SRC_BUFFER.take(); - *src = [1, 2, 3, 4, 5, 6, 7, 8]; - let dst = DEST_BUFFER.take(); - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, src); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, dst); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring DMA with Embassy-style API...\r\n") - .unwrap(); - - // Create DMA channel using Embassy-style API - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure interleaved transfer using direct TCD access: - // - src_offset = 4: advance source by 4 bytes after each read - // - dst_offset = 8: advance dest by 8 bytes after each write - // This spreads source data across every other word in destination - unsafe { - let t = dma_ch0.tcd(); - - // Reset channel state - t.ch_csr().write(|w| { - w.erq() - .disable() - .earq() - .disable() - .eei() - .no_error() - .ebw() - .disable() - .done() - .clear_bit_by_one() - }); - t.ch_es().write(|w| w.bits(0)); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - - // Source/destination addresses - t.tcd_saddr().write(|w| w.saddr().bits(src.as_ptr() as u32)); - t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32)); - - // Custom offsets for interleaving - t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read - t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write - - // Attributes: 32-bit transfers (size = 2) - t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); - - // Transfer entire source buffer in one minor loop - let nbytes = (HALF_BUFF_LENGTH * 4) as u32; - t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); - - // Reset source address after major loop - t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32)); - // Destination uses 2x offset, so adjust accordingly - let dst_total = (HALF_BUFF_LENGTH * 8) as u32; - t.tcd_dlast_sga() - .write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32)); - - // Major loop count = 1 - t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); - t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); - - // Enable interrupt on major loop completion - t.tcd_csr().write(|w| w.intmajor().set_bit()); - - cortex_m::asm::dsb(); - - tx.blocking_write(b"Triggering transfer...\r\n").unwrap(); - dma_ch0.trigger_start(); - } - - // Wait for completion using channel helper method - while !dma_ch0.is_done() { - cortex_m::asm::nop(); - } - unsafe { - dma_ch0.clear_done(); - } - - tx.blocking_write(b"\r\nEDMA interleave transfer example finish.\r\n\r\n") - .unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, dst); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0 - let mut mismatch = false; - let diter = dst.chunks_exact(2); - let siter = src.iter(); - for (ch, src) in diter.zip(siter) { - mismatch |= !matches!(ch, [a, 0] if a == src); - } - - if mismatch { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } else { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); - defmt::info!("PASS: Data verified."); - } - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/mcxa/src/bin/dma_memset.rs b/examples/mcxa/src/bin/dma_memset.rs deleted file mode 100644 index d7b03e91b..000000000 --- a/examples/mcxa/src/bin/dma_memset.rs +++ /dev/null @@ -1,125 +0,0 @@ -//! DMA memset example for MCXA276. -//! -//! This example demonstrates using DMA to fill a buffer with a repeated pattern. -//! The source address stays fixed while the destination increments. -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::is_done()` and `clear_done()` helper methods -//! - No need to pass register block around - -#![no_std] -#![no_main] - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::DmaChannel; -use static_cell::ConstStaticCell; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -const BUFFER_LENGTH: usize = 4; - -// Buffers in RAM -static PATTERN: u32 = 0xDEADBEEF; -static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); - -#[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 memset example starting..."); - defmt::info!("EDMA memset example begin."); - - // Initialize buffers - let pat = &PATTERN; - let dst = DEST_BUFFER.take(); - defmt::info!("Pattern Value: {=u32}", pat); - defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice()); - defmt::info!("Configuring DMA with Embassy-style API..."); - - // Create DMA channel using Embassy-style API - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure memset transfer using direct TCD access: - // Source stays fixed (soff = 0, reads same pattern repeatedly) - // Destination increments (doff = 4) - unsafe { - let t = dma_ch0.tcd(); - - // Reset channel state - t.ch_csr().write(|w| { - w.erq() - .disable() - .earq() - .disable() - .eei() - .no_error() - .ebw() - .disable() - .done() - .clear_bit_by_one() - }); - t.ch_es().write(|w| w.bits(0)); - t.ch_int().write(|w| w.int().clear_bit_by_one()); - - // Source address (pattern) - fixed - t.tcd_saddr().write(|w| w.saddr().bits(pat as *const _ as u32)); - // Destination address - increments - t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32)); - - // Source offset = 0 (stays fixed), Dest offset = 4 (increments) - t.tcd_soff().write(|w| w.soff().bits(0)); - t.tcd_doff().write(|w| w.doff().bits(4)); - - // Attributes: 32-bit transfers (size = 2) - t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); - - // Transfer entire buffer in one minor loop - let nbytes = (BUFFER_LENGTH * 4) as u32; - t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); - - // Source doesn't need adjustment (stays fixed) - t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); - // Reset dest address after major loop - t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32)); - - // Major loop count = 1 - t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); - t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); - - // Enable interrupt on major loop completion - t.tcd_csr().write(|w| w.intmajor().set_bit()); - - cortex_m::asm::dsb(); - - defmt::info!("Triggering transfer..."); - dma_ch0.trigger_start(); - } - - // Wait for completion using channel helper method - while !dma_ch0.is_done() { - cortex_m::asm::nop(); - } - unsafe { - dma_ch0.clear_done(); - } - - defmt::info!("EDMA memset example finish."); - defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice()); - - // Verify: All elements should equal PATTERN - let mismatch = dst.iter().any(|i| *i != *pat); - - if mismatch { - defmt::error!("FAIL: Mismatch detected!"); - } else { - defmt::info!("PASS: Data verified."); - } -} diff --git a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/dma_ping_pong_transfer.rs deleted file mode 100644 index 58f643b80..000000000 --- a/examples/mcxa/src/bin/dma_ping_pong_transfer.rs +++ /dev/null @@ -1,347 +0,0 @@ -//! DMA ping-pong/double-buffer transfer example for MCXA276. -//! -//! This example demonstrates two approaches for ping-pong/double-buffering: -//! -//! ## Approach 1: Scatter/Gather with linked TCDs (manual) -//! - Two TCDs link to each other for alternating transfers -//! - Uses custom handler that delegates to on_interrupt() then signals completion -//! - Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, -//! so we need an AtomicBool to track completion -//! -//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!) -//! - Single continuous transfer over entire buffer -//! - Uses half-transfer interrupt to know when first half is ready -//! - Application can process first half while second half is being filled -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::new()` for channel creation -//! - Scatter/gather with linked TCDs -//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) -//! - Standard `DmaCh1InterruptHandler` with `bind_interrupts!` macro -//! - NEW: `wait_half()` for half-transfer interrupt handling - -#![no_std] -#![no_main] - -use core::fmt::Write as _; -use core::sync::atomic::{AtomicBool, Ordering}; - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaChannel, Tcd, TransferOptions}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Source and destination buffers for Approach 1 (scatter/gather) -static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; -static mut DST: [u32; 8] = [0; 8]; - -// Source and destination buffers for Approach 2 (wait_half) -static mut SRC2: [u32; 8] = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; -static mut DST2: [u32; 8] = [0; 8]; - -// TCD pool for scatter/gather - must be 32-byte aligned -#[repr(C, align(32))] -struct TcdPool([Tcd; 2]); - -static mut TCD_POOL: TcdPool = TcdPool( - [Tcd { - saddr: 0, - soff: 0, - attr: 0, - nbytes: 0, - slast: 0, - daddr: 0, - doff: 0, - citer: 0, - dlast_sga: 0, - csr: 0, - biter: 0, - }; 2], -); - -// AtomicBool to track scatter/gather completion -// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, -// so we need this flag to detect when each transfer completes -static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); - -// Custom handler for scatter/gather that delegates to HAL's on_interrupt() -// This follows the "interrupts as threads" pattern - the handler does minimal work -// (delegates to HAL + sets a flag) and the main task does the actual processing -pub struct PingPongDmaHandler; - -impl embassy_mcxa::interrupt::typelevel::Handler for PingPongDmaHandler { - unsafe fn on_interrupt() { - // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers - dma::on_interrupt(0); - // Signal completion for polling (needed because ESG clears DONE bit) - TRANSFER_DONE.store(true, Ordering::Release); - } -} - -// Bind DMA channel interrupts -// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag) -// CH1: Standard handler for wait_half() demo -bind_interrupts!(struct Irqs { - DMA_CH0 => PingPongDmaHandler; -}); - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); -} - -#[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 ping-pong transfer example starting..."); - - // Enable DMA interrupt (DMA clock/reset/init is handled automatically by HAL) - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA ping-pong transfer example begin.\r\n\r\n") - .unwrap(); - - // Initialize buffers - unsafe { - SRC = [1, 2, 3, 4, 5, 6, 7, 8]; - DST = [0; 8]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring ping-pong DMA with Embassy-style API...\r\n") - .unwrap(); - - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure ping-pong transfer using direct TCD access: - // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. - // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1. - // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0. - unsafe { - let tcds = &mut *core::ptr::addr_of_mut!(TCD_POOL.0); - let src_ptr = core::ptr::addr_of!(SRC) as *const u32; - let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; - - let half_len = 4usize; - let half_bytes = (half_len * 4) as u32; - - let tcd0_addr = &tcds[0] as *const _ as u32; - let tcd1_addr = &tcds[1] as *const _ as u32; - - // TCD0: First half -> Links to TCD1 - tcds[0] = Tcd { - saddr: src_ptr as u32, - soff: 4, - attr: 0x0202, // 32-bit src/dst - nbytes: half_bytes, - slast: 0, - daddr: dst_ptr as u32, - doff: 4, - citer: 1, - dlast_sga: tcd1_addr as i32, - csr: 0x0012, // ESG | INTMAJOR - biter: 1, - }; - - // TCD1: Second half -> Links to TCD0 - tcds[1] = Tcd { - saddr: src_ptr.add(half_len) as u32, - soff: 4, - attr: 0x0202, - nbytes: half_bytes, - slast: 0, - daddr: dst_ptr.add(half_len) as u32, - doff: 4, - citer: 1, - dlast_sga: tcd0_addr as i32, - csr: 0x0012, - biter: 1, - }; - - // Load TCD0 into hardware registers - dma_ch0.load_tcd(&tcds[0]); - } - - tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); - - // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) - unsafe { - dma_ch0.trigger_start(); - } - - // Wait for first half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); - } - TRANSFER_DONE.store(false, Ordering::Release); - - tx.blocking_write(b"First half transferred.\r\n").unwrap(); - tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); - - // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) - unsafe { - dma_ch0.trigger_start(); - } - - // Wait for second half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); - } - TRANSFER_DONE.store(false, Ordering::Release); - - tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); - - tx.blocking_write(b"EDMA ping-pong transfer example finish.\r\n\r\n") - .unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify: DST should match SRC - let mut mismatch = false; - unsafe { - let src_ptr = core::ptr::addr_of!(SRC) as *const u32; - let dst_ptr = core::ptr::addr_of!(DST) as *const u32; - for i in 0..8 { - if *src_ptr.add(i) != *dst_ptr.add(i) { - mismatch = true; - break; - } - } - } - - if mismatch { - tx.blocking_write(b"FAIL: Approach 1 mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Approach 1 mismatch detected!"); - } else { - tx.blocking_write(b"PASS: Approach 1 data verified.\r\n\r\n").unwrap(); - defmt::info!("PASS: Approach 1 data verified."); - } - - // ========================================================================= - // Approach 2: Half-Transfer Interrupt with wait_half() (NEW!) - // ========================================================================= - // - // This approach uses a single continuous DMA transfer with half-transfer - // interrupt enabled. The wait_half() method allows you to be notified - // when the first half of the buffer is complete, so you can process it - // while the second half is still being filled. - // - // Benefits: - // - Simpler setup (no TCD pool needed) - // - True async/await support - // - Good for streaming data processing - - tx.blocking_write(b"--- Approach 2: wait_half() demo ---\r\n\r\n") - .unwrap(); - - // Enable DMA CH1 interrupt - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); - } - - // Initialize approach 2 buffers - unsafe { - SRC2 = [0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]; - DST2 = [0; 8]; - } - - tx.blocking_write(b"SRC2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC2) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - let dma_ch1 = DmaChannel::new(p.DMA_CH1); - - // Configure transfer with half-transfer interrupt enabled - let mut options = TransferOptions::default(); - options.half_transfer_interrupt = true; // Enable half-transfer interrupt - options.complete_transfer_interrupt = true; - - tx.blocking_write(b"Starting transfer with half_transfer_interrupt...\r\n") - .unwrap(); - - unsafe { - let src = &*core::ptr::addr_of!(SRC2); - let dst = &mut *core::ptr::addr_of_mut!(DST2); - - // Create the transfer - let mut transfer = dma_ch1.mem_to_mem(src, dst, options); - - // Wait for half-transfer (first 4 elements) - tx.blocking_write(b"Waiting for first half...\r\n").unwrap(); - let half_ok = transfer.wait_half().await; - - if half_ok { - tx.blocking_write(b"Half-transfer complete! First half of DST2: ") - .unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 4); - tx.blocking_write(b"\r\n").unwrap(); - tx.blocking_write(b"(Processing first half while second half transfers...)\r\n") - .unwrap(); - } - - // Wait for complete transfer - tx.blocking_write(b"Waiting for second half...\r\n").unwrap(); - transfer.await; - } - - tx.blocking_write(b"Transfer complete! Full DST2: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST2) as *const u32, 8); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify approach 2 - let mut mismatch2 = false; - unsafe { - let src_ptr = core::ptr::addr_of!(SRC2) as *const u32; - let dst_ptr = core::ptr::addr_of!(DST2) as *const u32; - for i in 0..8 { - if *src_ptr.add(i) != *dst_ptr.add(i) { - mismatch2 = true; - break; - } - } - } - - if mismatch2 { - tx.blocking_write(b"FAIL: Approach 2 mismatch!\r\n").unwrap(); - defmt::error!("FAIL: Approach 2 mismatch!"); - } else { - tx.blocking_write(b"PASS: Approach 2 verified.\r\n").unwrap(); - defmt::info!("PASS: Approach 2 verified."); - } - - tx.blocking_write(b"\r\n=== All ping-pong demos complete ===\r\n") - .unwrap(); - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/mcxa/src/bin/dma_scatter_gather.rs b/examples/mcxa/src/bin/dma_scatter_gather.rs deleted file mode 100644 index 3e34e95b1..000000000 --- a/examples/mcxa/src/bin/dma_scatter_gather.rs +++ /dev/null @@ -1,234 +0,0 @@ -//! DMA scatter-gather transfer example for MCXA276. -//! -//! This example demonstrates using DMA with scatter/gather to chain multiple -//! transfer descriptors. The first TCD transfers the first half of the buffer, -//! then automatically loads the second TCD to transfer the second half. -//! -//! # Embassy-style features demonstrated: -//! - `DmaChannel::new()` for channel creation -//! - Scatter/gather with chained TCDs -//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) - -#![no_std] -#![no_main] - -use core::fmt::Write as _; -use core::sync::atomic::{AtomicBool, Ordering}; - -use embassy_executor::Spawner; -use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaChannel, Tcd}; -use embassy_mcxa::lpuart::{Blocking, Config, Lpuart, LpuartTx}; -use embassy_mcxa::{bind_interrupts, pac}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -// Source and destination buffers -static mut SRC: [u32; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; -static mut DST: [u32; 8] = [0; 8]; - -// TCD pool for scatter/gather - must be 32-byte aligned -#[repr(C, align(32))] -struct TcdPool([Tcd; 2]); - -static mut TCD_POOL: TcdPool = TcdPool( - [Tcd { - saddr: 0, - soff: 0, - attr: 0, - nbytes: 0, - slast: 0, - daddr: 0, - doff: 0, - citer: 0, - dlast_sga: 0, - csr: 0, - biter: 0, - }; 2], -); - -// AtomicBool to track scatter/gather completion -// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, -// so we need this flag to detect when each transfer completes -static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); - -// Custom handler for scatter/gather that delegates to HAL's on_interrupt() -// This follows the "interrupts as threads" pattern - the handler does minimal work -// (delegates to HAL + sets a flag) and the main task does the actual processing -pub struct ScatterGatherDmaHandler; - -impl embassy_mcxa::interrupt::typelevel::Handler - for ScatterGatherDmaHandler -{ - unsafe fn on_interrupt() { - // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers - dma::on_interrupt(0); - // Signal completion for polling (needed because ESG clears DONE bit) - TRANSFER_DONE.store(true, Ordering::Release); - } -} - -// Bind DMA channel interrupt -// Custom handler for scatter/gather (delegates to on_interrupt + sets flag) -bind_interrupts!(struct Irqs { - DMA_CH0 => ScatterGatherDmaHandler; -}); - -/// Helper to print a buffer to UART -fn print_buffer(tx: &mut LpuartTx<'_, Blocking>, buf_ptr: *const u32, len: usize) { - write!(tx, "{:?}", unsafe { core::slice::from_raw_parts(buf_ptr, len) }).ok(); -} - -#[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 transfer example starting..."); - - // DMA is initialized during hal::init() - no need to call ensure_init() - - // Enable DMA interrupt - unsafe { - cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH0); - } - - let config = Config { - baudrate_bps: 115_200, - ..Default::default() - }; - - let lpuart = Lpuart::new_blocking(p.LPUART2, p.P2_2, p.P2_3, config).unwrap(); - let (mut tx, _rx) = lpuart.split(); - - tx.blocking_write(b"EDMA scatter-gather transfer example begin.\r\n\r\n") - .unwrap(); - - // Initialize buffers - unsafe { - SRC = [1, 2, 3, 4, 5, 6, 7, 8]; - DST = [0; 8]; - } - - tx.blocking_write(b"Source Buffer: ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(SRC) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Destination Buffer (before): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n").unwrap(); - - tx.blocking_write(b"Configuring scatter-gather DMA with Embassy-style API...\r\n") - .unwrap(); - - let dma_ch0 = DmaChannel::new(p.DMA_CH0); - - // Configure scatter-gather transfer using direct TCD access: - // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. - // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1. - // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD. - unsafe { - let tcds = core::slice::from_raw_parts_mut(core::ptr::addr_of_mut!(TCD_POOL.0) as *mut Tcd, 2); - let src_ptr = core::ptr::addr_of!(SRC) as *const u32; - let dst_ptr = core::ptr::addr_of_mut!(DST) as *mut u32; - - let num_tcds = 2usize; - let chunk_len = 4usize; // 8 / 2 - let chunk_bytes = (chunk_len * 4) as u32; - - for i in 0..num_tcds { - let is_last = i == num_tcds - 1; - let next_tcd_addr = if is_last { - 0 // No next TCD - } else { - &tcds[i + 1] as *const _ as u32 - }; - - tcds[i] = Tcd { - saddr: src_ptr.add(i * chunk_len) as u32, - soff: 4, - attr: 0x0202, // 32-bit src/dst - nbytes: chunk_bytes, - slast: 0, - daddr: dst_ptr.add(i * chunk_len) as u32, - doff: 4, - citer: 1, - dlast_sga: next_tcd_addr as i32, - // ESG (scatter/gather) for non-last, INTMAJOR for all - csr: if is_last { 0x0002 } else { 0x0012 }, - biter: 1, - }; - } - - // Load TCD0 into hardware registers - dma_ch0.load_tcd(&tcds[0]); - } - - tx.blocking_write(b"Triggering first half transfer...\r\n").unwrap(); - - // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) - // TCD0 is currently loaded. - unsafe { - dma_ch0.trigger_start(); - } - - // Wait for first half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); - } - TRANSFER_DONE.store(false, Ordering::Release); - - tx.blocking_write(b"First half transferred.\r\n").unwrap(); - tx.blocking_write(b"Triggering second half transfer...\r\n").unwrap(); - - // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) - // TCD1 should have been loaded by the scatter/gather engine. - unsafe { - dma_ch0.trigger_start(); - } - - // Wait for second half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); - } - TRANSFER_DONE.store(false, Ordering::Release); - - tx.blocking_write(b"Second half transferred.\r\n\r\n").unwrap(); - - tx.blocking_write(b"EDMA scatter-gather transfer example finish.\r\n\r\n") - .unwrap(); - tx.blocking_write(b"Destination Buffer (after): ").unwrap(); - print_buffer(&mut tx, core::ptr::addr_of!(DST) as *const u32, 8); - tx.blocking_write(b"\r\n\r\n").unwrap(); - - // Verify: DST should match SRC - let mut mismatch = false; - unsafe { - let src_ptr = core::ptr::addr_of!(SRC) as *const u32; - let dst_ptr = core::ptr::addr_of!(DST) as *const u32; - for i in 0..8 { - if *src_ptr.add(i) != *dst_ptr.add(i) { - mismatch = true; - break; - } - } - } - - if mismatch { - tx.blocking_write(b"FAIL: Mismatch detected!\r\n").unwrap(); - defmt::error!("FAIL: Mismatch detected!"); - } else { - tx.blocking_write(b"PASS: Data verified.\r\n").unwrap(); - defmt::info!("PASS: Data verified."); - } - - loop { - cortex_m::asm::wfe(); - } -} diff --git a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs index 1691129f6..30ce20c96 100644 --- a/examples/mcxa/src/bin/dma_scatter_gather_builder.rs +++ b/examples/mcxa/src/bin/dma_scatter_gather_builder.rs @@ -112,11 +112,7 @@ async fn main(_spawner: Spawner) { defmt::info!(" DST2: {=[?]}", dst2.as_slice()); defmt::info!(" DST3: {=[?]}", dst3.as_slice()); - let comps = [ - (src1, dst1), - (src2, dst2), - (src3, dst3), - ]; + let comps = [(src1, dst1), (src2, dst2), (src3, dst3)]; // Verify all three segments let mut all_ok = true; 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..987f1ba43 --- /dev/null +++ b/examples/mcxa/src/bin/raw_dma_channel_link.rs @@ -0,0 +1,279 @@ +//! DMA channel linking example for MCXA276. +//! +//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have +//! a high-level and safe API for. It should not be taken as typical, recommended, or +//! stable usage! +//! +//! This example demonstrates DMA channel linking (minor and major loop linking): +//! - Channel 0: Transfers SRC_BUFFER to DEST_BUFFER0, with: +//! - Minor Link to Channel 1 (triggers CH1 after each minor loop) +//! - Major Link to Channel 2 (triggers CH2 after major loop completes) +//! - Channel 1: Transfers SRC_BUFFER to DEST_BUFFER1 (triggered by CH0 minor link) +//! - Channel 2: Transfers SRC_BUFFER to DEST_BUFFER2 (triggered by CH0 major link) +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::new()` for channel creation +//! - `DmaChannel::is_done()` and `clear_done()` helper methods +//! - Channel linking with `set_minor_link()` and `set_major_link()` +//! - Standard `DmaCh*InterruptHandler` with `bind_interrupts!` macro + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::DmaChannel; +use embassy_mcxa::pac; +use static_cell::ConstStaticCell; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Buffers +static SRC_BUFFER: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([1, 2, 3, 4]); +static DEST_BUFFER0: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]); +static DEST_BUFFER1: ConstStaticCell<[u32; 4]> = ConstStaticCell::new([0; 4]); +static DEST_BUFFER2: 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 channel link example starting..."); + + // DMA is initialized during hal::init() - no need to call ensure_init() + + let pac_periphs = unsafe { pac::Peripherals::steal() }; + let dma0 = &pac_periphs.dma0; + let edma = unsafe { &*pac::Edma0Tcd0::ptr() }; + + // Clear any residual state + for i in 0..3 { + let t = edma.tcd(i); + t.ch_csr().write(|w| w.erq().disable().done().clear_bit_by_one()); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + t.ch_es().write(|w| w.err().clear_bit_by_one()); + t.ch_mux().write(|w| unsafe { w.bits(0) }); + } + + // Clear Global Halt/Error state + dma0.mp_csr().modify(|_, w| { + w.halt() + .normal_operation() + .hae() + .normal_operation() + .ecx() + .normal_operation() + .cx() + .normal_operation() + }); + + defmt::info!("EDMA channel link example begin."); + + // Initialize buffers + let src = SRC_BUFFER.take(); + let dst0 = DEST_BUFFER0.take(); + let dst1 = DEST_BUFFER1.take(); + let dst2 = DEST_BUFFER2.take(); + + defmt::info!("Source Buffer: {=[?]}", src.as_slice()); + defmt::info!("DEST0 (before): {=[?]}", dst0.as_slice()); + defmt::info!("DEST1 (before): {=[?]}", dst1.as_slice()); + defmt::info!("DEST2 (before): {=[?]}", dst2.as_slice()); + + defmt::info!("Configuring DMA channels with Embassy-style API..."); + + let ch0 = DmaChannel::new(p.DMA_CH0); + let ch1 = DmaChannel::new(p.DMA_CH1); + let ch2 = DmaChannel::new(p.DMA_CH2); + + // Configure channels using direct TCD access (advanced feature demo) + // This example demonstrates channel linking which requires direct TCD manipulation + + // Helper to configure TCD for memory-to-memory transfer + // Parameters: channel, src, dst, width, nbytes (minor loop), count (major loop), interrupt + #[allow(clippy::too_many_arguments)] + unsafe fn configure_tcd( + edma: &embassy_mcxa::pac::edma_0_tcd0::RegisterBlock, + ch: usize, + src: u32, + dst: u32, + width: u8, + nbytes: u32, + count: u16, + enable_int: bool, + ) { + let t = edma.tcd(ch); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source/destination addresses + t.tcd_saddr().write(|w| w.saddr().bits(src)); + t.tcd_daddr().write(|w| w.daddr().bits(dst)); + + // Offsets: increment by width + t.tcd_soff().write(|w| w.soff().bits(width as u16)); + t.tcd_doff().write(|w| w.doff().bits(width as u16)); + + // Attributes: size = log2(width) + let size = match width { + 1 => 0, + 2 => 1, + 4 => 2, + _ => 0, + }; + t.tcd_attr().write(|w| w.ssize().bits(size).dsize().bits(size)); + + // Number of bytes per minor loop + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Major loop: reset source address after major loop + let total_bytes = nbytes * count as u32; + t.tcd_slast_sda() + .write(|w| w.slast_sda().bits(-(total_bytes as i32) as u32)); + t.tcd_dlast_sga() + .write(|w| w.dlast_sga().bits(-(total_bytes as i32) as u32)); + + // Major loop count + t.tcd_biter_elinkno().write(|w| w.biter().bits(count)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(count)); + + // Control/status: enable interrupt if requested + if enable_int { + t.tcd_csr().write(|w| w.intmajor().set_bit()); + } else { + t.tcd_csr().write(|w| w.intmajor().clear_bit()); + } + + cortex_m::asm::dsb(); + } + + unsafe { + // Channel 0: Transfer 16 bytes total (8 bytes per minor loop, 2 major iterations) + // Minor Link -> Channel 1 + // Major Link -> Channel 2 + configure_tcd( + edma, + 0, + src.as_ptr() as u32, + dst0.as_mut_ptr() as u32, + 4, // src width + 8, // nbytes (minor loop = 2 words) + 2, // count (major loop = 2 iterations) + false, // no interrupt + ); + ch0.set_minor_link(1); // Link to CH1 after each minor loop + ch0.set_major_link(2); // Link to CH2 after major loop + + // Channel 1: Transfer 16 bytes (triggered by CH0 minor link) + configure_tcd( + edma, + 1, + src.as_ptr() as u32, + dst1.as_mut_ptr() as u32, + 4, + 16, // full buffer in one minor loop + 1, // 1 major iteration + false, + ); + + // Channel 2: Transfer 16 bytes (triggered by CH0 major link) + configure_tcd( + edma, + 2, + src.as_ptr() as u32, + dst2.as_mut_ptr() as u32, + 4, + 16, // full buffer in one minor loop + 1, // 1 major iteration + true, // enable interrupt + ); + } + + defmt::info!("Triggering Channel 0 (1st minor loop)..."); + + // Trigger first minor loop of CH0 + unsafe { + ch0.trigger_start(); + } + + // Wait for CH1 to complete (triggered by CH0 minor link) + while !ch1.is_done() { + cortex_m::asm::nop(); + } + unsafe { + ch1.clear_done(); + } + + defmt::info!("CH1 done (via minor link)."); + defmt::info!("Triggering Channel 0 (2nd minor loop)..."); + + // Trigger second minor loop of CH0 + unsafe { + ch0.trigger_start(); + } + + // Wait for CH0 major loop to complete + while !ch0.is_done() { + cortex_m::asm::nop(); + } + unsafe { + ch0.clear_done(); + } + + defmt::info!("CH0 major loop done."); + + // Wait for CH2 to complete (triggered by CH0 major link) + // Using is_done() instead of AtomicBool - the standard interrupt handler + // clears the interrupt flag and wakes wakers, but DONE bit remains set + while !ch2.is_done() { + cortex_m::asm::nop(); + } + unsafe { + ch2.clear_done(); + } + + defmt::info!("CH2 done (via major link)."); + + defmt::info!("EDMA channel link example finish."); + + defmt::info!("DEST0 (after): {=[?]}", dst0.as_slice()); + defmt::info!("DEST1 (after): {=[?]}", dst1.as_slice()); + defmt::info!("DEST2 (after): {=[?]}", dst2.as_slice()); + + // Verify all buffers match source + let mut success = true; + for sli in [dst0, dst1, dst2] { + success &= sli == src; + } + + if success { + defmt::info!("PASS: Data verified."); + } else { + defmt::error!("FAIL: Mismatch detected!"); + } + + loop { + cortex_m::asm::wfe(); + } +} 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 @@ +//! DMA interleaved transfer example for MCXA276. +//! +//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have +//! a high-level and safe API for. It should not be taken as typical, recommended, or +//! stable usage! +//! +//! This example demonstrates using DMA with custom source/destination offsets +//! to interleave data during transfer. +//! +//! # Embassy-style features demonstrated: +//! - `TransferOptions::default()` for configuration (used internally) +//! - DMA channel with `DmaChannel::new()` + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::DmaChannel; +use static_cell::ConstStaticCell; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +const BUFFER_LENGTH: usize = 16; +const HALF_BUFF_LENGTH: usize = BUFFER_LENGTH / 2; + +// Buffers in RAM +static SRC_BUFFER: ConstStaticCell<[u32; HALF_BUFF_LENGTH]> = ConstStaticCell::new([0; HALF_BUFF_LENGTH]); +static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); + +#[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 interleave transfer example starting..."); + + defmt::info!("EDMA interleave transfer example begin."); + + // Initialize buffers + let src = SRC_BUFFER.take(); + *src = [1, 2, 3, 4, 5, 6, 7, 8]; + let dst = DEST_BUFFER.take(); + + defmt::info!("Source Buffer: {=[?]}", src.as_slice()); + defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice()); + + defmt::info!("Configuring DMA with Embassy-style API..."); + + // Create DMA channel using Embassy-style API + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure interleaved transfer using direct TCD access: + // - src_offset = 4: advance source by 4 bytes after each read + // - dst_offset = 8: advance dest by 8 bytes after each write + // This spreads source data across every other word in destination + unsafe { + let t = dma_ch0.tcd(); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source/destination addresses + t.tcd_saddr().write(|w| w.saddr().bits(src.as_ptr() as u32)); + t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32)); + + // Custom offsets for interleaving + t.tcd_soff().write(|w| w.soff().bits(4)); // src: +4 bytes per read + t.tcd_doff().write(|w| w.doff().bits(8)); // dst: +8 bytes per write + + // Attributes: 32-bit transfers (size = 2) + t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); + + // Transfer entire source buffer in one minor loop + let nbytes = (HALF_BUFF_LENGTH * 4) as u32; + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Reset source address after major loop + t.tcd_slast_sda().write(|w| w.slast_sda().bits(-(nbytes as i32) as u32)); + // Destination uses 2x offset, so adjust accordingly + let dst_total = (HALF_BUFF_LENGTH * 8) as u32; + t.tcd_dlast_sga() + .write(|w| w.dlast_sga().bits(-(dst_total as i32) as u32)); + + // Major loop count = 1 + t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); + + // Enable interrupt on major loop completion + t.tcd_csr().write(|w| w.intmajor().set_bit()); + + cortex_m::asm::dsb(); + + defmt::info!("Triggering transfer..."); + dma_ch0.trigger_start(); + } + + // Wait for completion using channel helper method + while !dma_ch0.is_done() { + cortex_m::asm::nop(); + } + unsafe { + dma_ch0.clear_done(); + } + + defmt::info!("EDMA interleave transfer example finish."); + defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice()); + + // Verify: Even indices should match SRC_BUFFER[i/2], odd indices should be 0 + let mut mismatch = false; + let diter = dst.chunks_exact(2); + let siter = src.iter(); + for (ch, src) in diter.zip(siter) { + mismatch |= !matches!(ch, [a, 0] if a == src); + } + + if mismatch { + defmt::error!("FAIL: Mismatch detected!"); + } else { + defmt::info!("PASS: Data verified."); + } +} 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 @@ +//! DMA memset example for MCXA276. +//! +//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have +//! a high-level and safe API for. It should not be taken as typical, recommended, or +//! stable usage! +//! +//! This example demonstrates using DMA to fill a buffer with a repeated pattern. +//! The source address stays fixed while the destination increments. +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::is_done()` and `clear_done()` helper methods +//! - No need to pass register block around + +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::DmaChannel; +use static_cell::ConstStaticCell; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +const BUFFER_LENGTH: usize = 4; + +// Buffers in RAM +static PATTERN: u32 = 0xDEADBEEF; +static DEST_BUFFER: ConstStaticCell<[u32; BUFFER_LENGTH]> = ConstStaticCell::new([0; BUFFER_LENGTH]); + +#[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 memset example starting..."); + defmt::info!("EDMA memset example begin."); + + // Initialize buffers + let pat = &PATTERN; + let dst = DEST_BUFFER.take(); + defmt::info!("Pattern Value: {=u32}", pat); + defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice()); + defmt::info!("Configuring DMA with Embassy-style API..."); + + // Create DMA channel using Embassy-style API + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure memset transfer using direct TCD access: + // Source stays fixed (soff = 0, reads same pattern repeatedly) + // Destination increments (doff = 4) + unsafe { + let t = dma_ch0.tcd(); + + // Reset channel state + t.ch_csr().write(|w| { + w.erq() + .disable() + .earq() + .disable() + .eei() + .no_error() + .ebw() + .disable() + .done() + .clear_bit_by_one() + }); + t.ch_es().write(|w| w.bits(0)); + t.ch_int().write(|w| w.int().clear_bit_by_one()); + + // Source address (pattern) - fixed + t.tcd_saddr().write(|w| w.saddr().bits(pat as *const _ as u32)); + // Destination address - increments + t.tcd_daddr().write(|w| w.daddr().bits(dst.as_mut_ptr() as u32)); + + // Source offset = 0 (stays fixed), Dest offset = 4 (increments) + t.tcd_soff().write(|w| w.soff().bits(0)); + t.tcd_doff().write(|w| w.doff().bits(4)); + + // Attributes: 32-bit transfers (size = 2) + t.tcd_attr().write(|w| w.ssize().bits(2).dsize().bits(2)); + + // Transfer entire buffer in one minor loop + let nbytes = (BUFFER_LENGTH * 4) as u32; + t.tcd_nbytes_mloffno().write(|w| w.nbytes().bits(nbytes)); + + // Source doesn't need adjustment (stays fixed) + t.tcd_slast_sda().write(|w| w.slast_sda().bits(0)); + // Reset dest address after major loop + t.tcd_dlast_sga().write(|w| w.dlast_sga().bits(-(nbytes as i32) as u32)); + + // Major loop count = 1 + t.tcd_biter_elinkno().write(|w| w.biter().bits(1)); + t.tcd_citer_elinkno().write(|w| w.citer().bits(1)); + + // Enable interrupt on major loop completion + t.tcd_csr().write(|w| w.intmajor().set_bit()); + + cortex_m::asm::dsb(); + + defmt::info!("Triggering transfer..."); + dma_ch0.trigger_start(); + } + + // Wait for completion using channel helper method + while !dma_ch0.is_done() { + cortex_m::asm::nop(); + } + unsafe { + dma_ch0.clear_done(); + } + + defmt::info!("EDMA memset example finish."); + defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice()); + + // Verify: All elements should equal PATTERN + let mismatch = dst.iter().any(|i| *i != *pat); + + if mismatch { + defmt::error!("FAIL: Mismatch detected!"); + } else { + defmt::info!("PASS: Data verified."); + } +} 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..4a64b2498 --- /dev/null +++ b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs @@ -0,0 +1,269 @@ +//! DMA ping-pong/double-buffer transfer example for MCXA276. +//! +//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have +//! a high-level and safe API for. It should not be taken as typical, recommended, or +//! stable usage! +//! +//! This example demonstrates two approaches for ping-pong/double-buffering: +//! +//! ## Approach 1: Scatter/Gather with linked TCDs (manual) +//! - Two TCDs link to each other for alternating transfers +//! - Uses custom handler that delegates to on_interrupt() then signals completion +//! - Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +//! so we need an AtomicBool to track completion +//! +//! ## Approach 2: Half-transfer interrupt with wait_half() (NEW!) +//! - Single continuous transfer over entire buffer +//! - Uses half-transfer interrupt to know when first half is ready +//! - Application can process first half while second half is being filled +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::new()` for channel creation +//! - Scatter/gather with linked TCDs +//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) +//! - Standard `DmaCh1InterruptHandler` with `bind_interrupts!` macro +//! - NEW: `wait_half()` for half-transfer interrupt handling + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use embassy_executor::Spawner; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{self, DmaChannel, Tcd, TransferOptions}; +use embassy_mcxa::{bind_interrupts, pac}; +use static_cell::ConstStaticCell; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Source and destination buffers for Approach 1 (scatter/gather) +static SRC: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([1, 2, 3, 4, 5, 6, 7, 8]); +static DST: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]); + +// Source and destination buffers for Approach 2 (wait_half) +static SRC2: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0xA1, 0xA2, 0xA3, 0xA4, 0xB1, 0xB2, 0xB3, 0xB4]); +static DST2: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]); + +// TCD pool for scatter/gather - must be 32-byte aligned +#[repr(C, align(32))] +struct TcdPool([Tcd; 2]); + +static TCD_POOL: ConstStaticCell = ConstStaticCell::new(TcdPool( + [Tcd { + saddr: 0, + soff: 0, + attr: 0, + nbytes: 0, + slast: 0, + daddr: 0, + doff: 0, + citer: 0, + dlast_sga: 0, + csr: 0, + biter: 0, + }; 2], +)); + +// AtomicBool to track scatter/gather completion +// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +// so we need this flag to detect when each transfer completes +static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); + +// Custom handler for scatter/gather that delegates to HAL's on_interrupt() +// This follows the "interrupts as threads" pattern - the handler does minimal work +// (delegates to HAL + sets a flag) and the main task does the actual processing +pub struct PingPongDmaHandler; + +impl embassy_mcxa::interrupt::typelevel::Handler for PingPongDmaHandler { + unsafe fn on_interrupt() { + // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers + dma::on_interrupt(0); + // Signal completion for polling (needed because ESG clears DONE bit) + TRANSFER_DONE.store(true, Ordering::Release); + } +} + +// Bind DMA channel interrupts +// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag) +// CH1: Standard handler for wait_half() demo +bind_interrupts!(struct Irqs { + DMA_CH0 => PingPongDmaHandler; +}); + +#[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 ping-pong transfer example starting..."); + + defmt::info!("EDMA ping-pong transfer example begin."); + + // Initialize buffers + let src = SRC.take(); + let dst = DST.take(); + + defmt::info!("Source Buffer: {=[?]}", src.as_slice()); + defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice()); + + defmt::info!("Configuring ping-pong DMA with Embassy-style API..."); + + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure ping-pong transfer using direct TCD access: + // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. + // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1. + // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0. + unsafe { + let tcds = &mut TCD_POOL.take().0; + + let half_len = 4usize; + let half_bytes = (half_len * 4) as u32; + + let tcd0_addr = &tcds[0] as *const _ as u32; + let tcd1_addr = &tcds[1] as *const _ as u32; + + // TCD0: First half -> Links to TCD1 + tcds[0] = Tcd { + saddr: src.as_ptr() as u32, + soff: 4, + attr: 0x0202, // 32-bit src/dst + nbytes: half_bytes, + slast: 0, + daddr: dst.as_mut_ptr() as u32, + doff: 4, + citer: 1, + dlast_sga: tcd1_addr as i32, + csr: 0x0012, // ESG | INTMAJOR + biter: 1, + }; + + // TCD1: Second half -> Links to TCD0 + tcds[1] = Tcd { + saddr: src.as_ptr().add(half_len) as u32, + soff: 4, + attr: 0x0202, + nbytes: half_bytes, + slast: 0, + daddr: dst.as_mut_ptr().add(half_len) as u32, + doff: 4, + citer: 1, + dlast_sga: tcd0_addr as i32, + csr: 0x0012, + biter: 1, + }; + + // Load TCD0 into hardware registers + dma_ch0.load_tcd(&tcds[0]); + } + + defmt::info!("Triggering first half transfer..."); + + // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) + unsafe { + dma_ch0.trigger_start(); + } + + // Wait for first half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + defmt::info!("First half transferred."); + defmt::info!("Triggering second half transfer..."); + + // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) + unsafe { + dma_ch0.trigger_start(); + } + + // Wait for second half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + defmt::info!("Second half transferred."); + + defmt::info!("EDMA ping-pong transfer example finish."); + defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice()); + + // Verify: DST should match SRC + let mismatch = src != dst; + + if mismatch { + defmt::error!("FAIL: Approach 1 mismatch detected!"); + } else { + defmt::info!("PASS: Approach 1 data verified."); + } + + // ========================================================================= + // Approach 2: Half-Transfer Interrupt with wait_half() (NEW!) + // ========================================================================= + // + // This approach uses a single continuous DMA transfer with half-transfer + // interrupt enabled. The wait_half() method allows you to be notified + // when the first half of the buffer is complete, so you can process it + // while the second half is still being filled. + // + // Benefits: + // - Simpler setup (no TCD pool needed) + // - True async/await support + // - Good for streaming data processing + + defmt::info!("--- Approach 2: wait_half() demo ---"); + + // Enable DMA CH1 interrupt + unsafe { + cortex_m::peripheral::NVIC::unmask(pac::Interrupt::DMA_CH1); + } + + // Initialize approach 2 buffers + let src2 = SRC2.take(); + let dst2 = DST2.take(); + + defmt::info!("SRC2: {=[?]}", src2.as_slice()); + + let dma_ch1 = DmaChannel::new(p.DMA_CH1); + + // Configure transfer with half-transfer interrupt enabled + let mut options = TransferOptions::default(); + options.half_transfer_interrupt = true; // Enable half-transfer interrupt + options.complete_transfer_interrupt = true; + + defmt::info!("Starting transfer with half_transfer_interrupt..."); + + // Create the transfer + let mut transfer = dma_ch1.mem_to_mem(src2, dst2, options); + + // Wait for half-transfer (first 4 elements) + defmt::info!("Waiting for first half..."); + let _ok = transfer.wait_half().await; + + defmt::info!("Half-transfer complete!"); + + // Wait for complete transfer + defmt::info!("Waiting for second half..."); + transfer.await; + + defmt::info!("Transfer complete! Full DST2: {=[?]}", dst2.as_slice()); + + // Verify approach 2 + let mismatch2 = src2 != dst2; + + if mismatch2 { + defmt::error!("FAIL: Approach 2 mismatch!"); + } else { + defmt::info!("PASS: Approach 2 verified."); + } + + defmt::info!("=== All ping-pong demos complete ==="); +} 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..057e56826 --- /dev/null +++ b/examples/mcxa/src/bin/raw_dma_scatter_gather.rs @@ -0,0 +1,188 @@ +//! DMA scatter-gather transfer example for MCXA276. +//! +//! NOTE: this is a "raw dma" example! It exists as a proof of concept, as we don't have +//! a high-level and safe API for. It should not be taken as typical, recommended, or +//! stable usage! +//! +//! This example demonstrates using DMA with scatter/gather to chain multiple +//! transfer descriptors. The first TCD transfers the first half of the buffer, +//! then automatically loads the second TCD to transfer the second half. +//! +//! # Embassy-style features demonstrated: +//! - `DmaChannel::new()` for channel creation +//! - Scatter/gather with chained TCDs +//! - Custom handler that delegates to HAL's `on_interrupt()` (best practice) + +#![no_std] +#![no_main] + +use core::sync::atomic::{AtomicBool, Ordering}; + +use embassy_executor::Spawner; +use embassy_mcxa::bind_interrupts; +use embassy_mcxa::clocks::config::Div8; +use embassy_mcxa::dma::{self, DmaChannel, Tcd}; +use static_cell::ConstStaticCell; +use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; + +// Source and destination buffers +static SRC: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([1, 2, 3, 4, 5, 6, 7, 8]); +static DST: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]); + +// TCD pool for scatter/gather - must be 32-byte aligned +#[repr(C, align(32))] +struct TcdPool([Tcd; 2]); + +static TCD_POOL: ConstStaticCell = ConstStaticCell::new(TcdPool( + [Tcd { + saddr: 0, + soff: 0, + attr: 0, + nbytes: 0, + slast: 0, + daddr: 0, + doff: 0, + citer: 0, + dlast_sga: 0, + csr: 0, + biter: 0, + }; 2], +)); + +// AtomicBool to track scatter/gather completion +// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, +// so we need this flag to detect when each transfer completes +static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); + +// Custom handler for scatter/gather that delegates to HAL's on_interrupt() +// This follows the "interrupts as threads" pattern - the handler does minimal work +// (delegates to HAL + sets a flag) and the main task does the actual processing +pub struct ScatterGatherDmaHandler; + +impl embassy_mcxa::interrupt::typelevel::Handler + for ScatterGatherDmaHandler +{ + unsafe fn on_interrupt() { + // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers + dma::on_interrupt(0); + // Signal completion for polling (needed because ESG clears DONE bit) + TRANSFER_DONE.store(true, Ordering::Release); + } +} + +// Bind DMA channel interrupt +// Custom handler for scatter/gather (delegates to on_interrupt + sets flag) +bind_interrupts!(struct Irqs { + DMA_CH0 => ScatterGatherDmaHandler; +}); + +#[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 transfer example starting..."); + + defmt::info!("EDMA scatter-gather transfer example begin."); + + // Initialize buffers + let src = SRC.take(); + let dst = DST.take(); + + defmt::info!("Source Buffer: {=[?]}", src.as_slice()); + defmt::info!("Destination Buffer (before): {=[?]}", dst.as_slice()); + defmt::info!("Configuring scatter-gather DMA with Embassy-style API..."); + + let dma_ch0 = DmaChannel::new(p.DMA_CH0); + + // Configure scatter-gather transfer using direct TCD access: + // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. + // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1. + // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD. + unsafe { + let tcds = &mut TCD_POOL.take().0; + let src_ptr = src.as_ptr(); + let dst_ptr = dst.as_mut_ptr(); + + let num_tcds = 2usize; + let chunk_len = 4usize; // 8 / 2 + let chunk_bytes = (chunk_len * 4) as u32; + + for i in 0..num_tcds { + let is_last = i == num_tcds - 1; + let next_tcd_addr = if is_last { + 0 // No next TCD + } else { + &tcds[i + 1] as *const _ as u32 + }; + + tcds[i] = Tcd { + saddr: src_ptr.add(i * chunk_len) as u32, + soff: 4, + attr: 0x0202, // 32-bit src/dst + nbytes: chunk_bytes, + slast: 0, + daddr: dst_ptr.add(i * chunk_len) as u32, + doff: 4, + citer: 1, + dlast_sga: next_tcd_addr as i32, + // ESG (scatter/gather) for non-last, INTMAJOR for all + csr: if is_last { 0x0002 } else { 0x0012 }, + biter: 1, + }; + } + + // Load TCD0 into hardware registers + dma_ch0.load_tcd(&tcds[0]); + } + + defmt::info!("Triggering first half transfer..."); + + // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) + // TCD0 is currently loaded. + unsafe { + dma_ch0.trigger_start(); + } + + // Wait for first half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + defmt::info!("First half transferred."); + defmt::info!("Triggering second half transfer..."); + + // Trigger second transfer (second half: SRC[4..8] -> DST[4..8]) + // TCD1 should have been loaded by the scatter/gather engine. + unsafe { + dma_ch0.trigger_start(); + } + + // Wait for second half + while !TRANSFER_DONE.load(Ordering::Acquire) { + cortex_m::asm::nop(); + } + TRANSFER_DONE.store(false, Ordering::Release); + + defmt::info!("Second half transferred."); + + defmt::info!("EDMA scatter-gather transfer example finish."); + defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice()); + + // Verify: DST should match SRC + let mismatch = src != dst; + + if mismatch { + defmt::error!("FAIL: Mismatch detected!"); + } else { + defmt::info!("PASS: Data verified."); + } +} -- cgit From e267cb52d774e8f9db87a9b0cfe63cfa51d4fe8b Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 9 Dec 2025 16:01:50 +0100 Subject: rustfmt --- examples/mcxa/src/bin/adc_interrupt.rs | 4 ++-- examples/mcxa/src/bin/adc_polling.rs | 2 +- examples/mcxa/src/bin/i2c-async.rs | 2 +- examples/mcxa/src/bin/i2c-scan-blocking.rs | 2 +- examples/mcxa/src/bin/lpuart_buffered.rs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 83d8046b3..c88b1fe8d 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -4,13 +4,13 @@ use embassy_executor::Spawner; use embassy_mcxa_examples::init_adc_pins; use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::clocks::PoweredClock; +use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; -use hal::{bind_interrupts, InterruptExt}; +use hal::{InterruptExt, bind_interrupts}; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index ddf3f586b..07c50f224 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -4,8 +4,8 @@ use embassy_executor::Spawner; use embassy_mcxa_examples::init_adc_pins; use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; -use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::clocks::PoweredClock; +use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; diff --git a/examples/mcxa/src/bin/i2c-async.rs b/examples/mcxa/src/bin/i2c-async.rs index 47b5f3cbe..edcfd5f22 100644 --- a/examples/mcxa/src/bin/i2c-async.rs +++ b/examples/mcxa/src/bin/i2c-async.rs @@ -6,8 +6,8 @@ use embassy_time::Timer; use hal::bind_interrupts; use hal::clocks::config::Div8; use hal::config::Config; -use hal::i2c::controller::{self, I2c, Speed}; use hal::i2c::InterruptHandler; +use hal::i2c::controller::{self, I2c, Speed}; use hal::peripherals::LPI2C3; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; diff --git a/examples/mcxa/src/bin/i2c-scan-blocking.rs b/examples/mcxa/src/bin/i2c-scan-blocking.rs index 4e203597b..0197f9b1d 100644 --- a/examples/mcxa/src/bin/i2c-scan-blocking.rs +++ b/examples/mcxa/src/bin/i2c-scan-blocking.rs @@ -2,8 +2,8 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa::gpio::Pull; use embassy_mcxa::Input; +use embassy_mcxa::gpio::Pull; use embassy_time::Timer; use hal::clocks::config::Div8; use hal::config::Config; diff --git a/examples/mcxa/src/bin/lpuart_buffered.rs b/examples/mcxa/src/bin/lpuart_buffered.rs index 420589d00..47b56b7c7 100644 --- a/examples/mcxa/src/bin/lpuart_buffered.rs +++ b/examples/mcxa/src/bin/lpuart_buffered.rs @@ -3,8 +3,8 @@ use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::lpuart::buffered::BufferedLpuart; use embassy_mcxa::lpuart::Config; +use embassy_mcxa::lpuart::buffered::BufferedLpuart; use embassy_mcxa::{bind_interrupts, lpuart}; use embedded_io_async::Write; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; -- cgit From 2dd5229c8c4fea6de7a7d52cedc6b6490d567ecf Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 9 Dec 2025 16:48:43 +0100 Subject: Use saddr read instead of interrupt to avoid double handler definition --- examples/mcxa/src/bin/raw_dma_channel_link.rs | 1 - .../mcxa/src/bin/raw_dma_ping_pong_transfer.rs | 55 +++------- examples/mcxa/src/bin/raw_dma_scatter_gather.rs | 115 +++++++++------------ 3 files changed, 61 insertions(+), 110 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/raw_dma_channel_link.rs b/examples/mcxa/src/bin/raw_dma_channel_link.rs index 987f1ba43..74785e4f3 100644 --- a/examples/mcxa/src/bin/raw_dma_channel_link.rs +++ b/examples/mcxa/src/bin/raw_dma_channel_link.rs @@ -15,7 +15,6 @@ //! - `DmaChannel::new()` for channel creation //! - `DmaChannel::is_done()` and `clear_done()` helper methods //! - Channel linking with `set_minor_link()` and `set_major_link()` -//! - Standard `DmaCh*InterruptHandler` with `bind_interrupts!` macro #![no_std] #![no_main] diff --git a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs index 4a64b2498..51a7bc275 100644 --- a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs +++ b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs @@ -27,12 +27,10 @@ #![no_std] #![no_main] -use core::sync::atomic::{AtomicBool, Ordering}; - use embassy_executor::Spawner; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaChannel, Tcd, TransferOptions}; -use embassy_mcxa::{bind_interrupts, pac}; +use embassy_mcxa::dma::{DmaChannel, Tcd, TransferOptions}; +use embassy_mcxa::pac; use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -64,32 +62,6 @@ static TCD_POOL: ConstStaticCell = ConstStaticCell::new(TcdPool( }; 2], )); -// AtomicBool to track scatter/gather completion -// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, -// so we need this flag to detect when each transfer completes -static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); - -// Custom handler for scatter/gather that delegates to HAL's on_interrupt() -// This follows the "interrupts as threads" pattern - the handler does minimal work -// (delegates to HAL + sets a flag) and the main task does the actual processing -pub struct PingPongDmaHandler; - -impl embassy_mcxa::interrupt::typelevel::Handler for PingPongDmaHandler { - unsafe fn on_interrupt() { - // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers - dma::on_interrupt(0); - // Signal completion for polling (needed because ESG clears DONE bit) - TRANSFER_DONE.store(true, Ordering::Release); - } -} - -// Bind DMA channel interrupts -// CH0: Custom handler for scatter/gather (delegates to on_interrupt + sets flag) -// CH1: Standard handler for wait_half() demo -bind_interrupts!(struct Irqs { - DMA_CH0 => PingPongDmaHandler; -}); - #[embassy_executor::main] async fn main(_spawner: Spawner) { // Small delay to allow probe-rs to attach after reset @@ -121,12 +93,12 @@ async fn main(_spawner: Spawner) { // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), links to TCD1. // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), links to TCD0. - unsafe { - let tcds = &mut TCD_POOL.take().0; + let tcds = &mut TCD_POOL.take().0; - let half_len = 4usize; - let half_bytes = (half_len * 4) as u32; + let half_len = 4usize; + let half_bytes = (half_len * 4) as u32; + unsafe { let tcd0_addr = &tcds[0] as *const _ as u32; let tcd1_addr = &tcds[1] as *const _ as u32; @@ -171,11 +143,13 @@ async fn main(_spawner: Spawner) { dma_ch0.trigger_start(); } + let tcd = dma_ch0.tcd(); // Wait for first half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); + loop { + if tcd.tcd_saddr().read().bits() != src.as_ptr() as u32 { + break; + } } - TRANSFER_DONE.store(false, Ordering::Release); defmt::info!("First half transferred."); defmt::info!("Triggering second half transfer..."); @@ -186,10 +160,11 @@ async fn main(_spawner: Spawner) { } // Wait for second half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); + loop { + if tcd.tcd_saddr().read().bits() != unsafe { src.as_ptr().add(half_len) } as u32 { + break; + } } - TRANSFER_DONE.store(false, Ordering::Release); defmt::info!("Second half transferred."); diff --git a/examples/mcxa/src/bin/raw_dma_scatter_gather.rs b/examples/mcxa/src/bin/raw_dma_scatter_gather.rs index 057e56826..eb9960764 100644 --- a/examples/mcxa/src/bin/raw_dma_scatter_gather.rs +++ b/examples/mcxa/src/bin/raw_dma_scatter_gather.rs @@ -16,18 +16,15 @@ #![no_std] #![no_main] -use core::sync::atomic::{AtomicBool, Ordering}; - use embassy_executor::Spawner; -use embassy_mcxa::bind_interrupts; use embassy_mcxa::clocks::config::Div8; -use embassy_mcxa::dma::{self, DmaChannel, Tcd}; +use embassy_mcxa::dma::{DmaChannel, Tcd}; use static_cell::ConstStaticCell; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; // Source and destination buffers -static SRC: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([1, 2, 3, 4, 5, 6, 7, 8]); -static DST: ConstStaticCell<[u32; 8]> = ConstStaticCell::new([0; 8]); +static SRC: ConstStaticCell<[u32; 12]> = ConstStaticCell::new([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); +static DST: ConstStaticCell<[u32; 12]> = ConstStaticCell::new([0; 12]); // TCD pool for scatter/gather - must be 32-byte aligned #[repr(C, align(32))] @@ -49,33 +46,6 @@ static TCD_POOL: ConstStaticCell = ConstStaticCell::new(TcdPool( }; 2], )); -// AtomicBool to track scatter/gather completion -// Note: With ESG=1, DONE bit is cleared by hardware when next TCD loads, -// so we need this flag to detect when each transfer completes -static TRANSFER_DONE: AtomicBool = AtomicBool::new(false); - -// Custom handler for scatter/gather that delegates to HAL's on_interrupt() -// This follows the "interrupts as threads" pattern - the handler does minimal work -// (delegates to HAL + sets a flag) and the main task does the actual processing -pub struct ScatterGatherDmaHandler; - -impl embassy_mcxa::interrupt::typelevel::Handler - for ScatterGatherDmaHandler -{ - unsafe fn on_interrupt() { - // Delegate to HAL's on_interrupt() which clears INT flag and wakes wakers - dma::on_interrupt(0); - // Signal completion for polling (needed because ESG clears DONE bit) - TRANSFER_DONE.store(true, Ordering::Release); - } -} - -// Bind DMA channel interrupt -// Custom handler for scatter/gather (delegates to on_interrupt + sets flag) -bind_interrupts!(struct Irqs { - DMA_CH0 => ScatterGatherDmaHandler; -}); - #[embassy_executor::main] async fn main(_spawner: Spawner) { // Small delay to allow probe-rs to attach after reset @@ -101,43 +71,46 @@ async fn main(_spawner: Spawner) { defmt::info!("Configuring scatter-gather DMA with Embassy-style API..."); let dma_ch0 = DmaChannel::new(p.DMA_CH0); + let src_ptr = src.as_ptr(); + let dst_ptr = dst.as_mut_ptr(); // Configure scatter-gather transfer using direct TCD access: // This sets up TCD0 and TCD1 in RAM, and loads TCD0 into the channel. // TCD0 transfers first half (SRC[0..4] -> DST[0..4]), then loads TCD1. - // TCD1 transfers second half (SRC[4..8] -> DST[4..8]), last TCD. + // TCD1 transfers second half (SRC[4..12] -> DST[4..12]), last TCD. unsafe { let tcds = &mut TCD_POOL.take().0; - let src_ptr = src.as_ptr(); - let dst_ptr = dst.as_mut_ptr(); - - let num_tcds = 2usize; - let chunk_len = 4usize; // 8 / 2 - let chunk_bytes = (chunk_len * 4) as u32; - - for i in 0..num_tcds { - let is_last = i == num_tcds - 1; - let next_tcd_addr = if is_last { - 0 // No next TCD - } else { - &tcds[i + 1] as *const _ as u32 - }; - - tcds[i] = Tcd { - saddr: src_ptr.add(i * chunk_len) as u32, - soff: 4, - attr: 0x0202, // 32-bit src/dst - nbytes: chunk_bytes, - slast: 0, - daddr: dst_ptr.add(i * chunk_len) as u32, - doff: 4, - citer: 1, - dlast_sga: next_tcd_addr as i32, - // ESG (scatter/gather) for non-last, INTMAJOR for all - csr: if is_last { 0x0002 } else { 0x0012 }, - biter: 1, - }; - } + + // In the first transfer, copy + tcds[0] = Tcd { + saddr: src_ptr as u32, + soff: 4, + attr: 0x0202, // 32-bit src/dst + nbytes: 4 * 4, + slast: 0, + daddr: dst_ptr as u32, + doff: 4, + citer: 1, + dlast_sga: tcds.as_ptr().add(1) as i32, + // ESG (scatter/gather) for non-last, INTMAJOR for all + csr: 0x0012, + biter: 1, + }; + + tcds[1] = Tcd { + saddr: src_ptr.add(4) as u32, + soff: 4, + attr: 0x0202, // 32-bit src/dst + nbytes: 8 * 4, + slast: 0, + daddr: dst_ptr.add(4) as u32, + doff: 4, + citer: 1, + dlast_sga: 0, + // ESG (scatter/gather) for non-last, INTMAJOR for all + csr: 0x0002, + biter: 1, + }; // Load TCD0 into hardware registers dma_ch0.load_tcd(&tcds[0]); @@ -145,6 +118,8 @@ async fn main(_spawner: Spawner) { defmt::info!("Triggering first half transfer..."); + let tcd = dma_ch0.tcd(); + // Trigger first transfer (first half: SRC[0..4] -> DST[0..4]) // TCD0 is currently loaded. unsafe { @@ -152,10 +127,13 @@ async fn main(_spawner: Spawner) { } // Wait for first half - while !TRANSFER_DONE.load(Ordering::Acquire) { - cortex_m::asm::nop(); + loop { + if tcd.tcd_saddr().read().bits() != src_ptr as u32 { + defmt::info!("saddr: {=u32}", tcd.tcd_saddr().read().bits()); + defmt::info!("srptr: {=u32}", src_ptr as u32); + break; + } } - TRANSFER_DONE.store(false, Ordering::Release); defmt::info!("First half transferred."); defmt::info!("Triggering second half transfer..."); @@ -167,10 +145,9 @@ async fn main(_spawner: Spawner) { } // Wait for second half - while !TRANSFER_DONE.load(Ordering::Acquire) { + while !dma_ch0.is_done() { cortex_m::asm::nop(); } - TRANSFER_DONE.store(false, Ordering::Release); defmt::info!("Second half transferred."); -- cgit From 3e7de3a5d81e32e77aeb5232e5a7f512ce39db0e Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 9 Dec 2025 17:53:45 +0100 Subject: Change transfer to return a result --- examples/mcxa/src/bin/dma_mem_to_mem.rs | 2 +- examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/dma_mem_to_mem.rs b/examples/mcxa/src/bin/dma_mem_to_mem.rs index b20068b79..a9ee9ffdf 100644 --- a/examples/mcxa/src/bin/dma_mem_to_mem.rs +++ b/examples/mcxa/src/bin/dma_mem_to_mem.rs @@ -70,7 +70,7 @@ async fn main(_spawner: Spawner) { // Perform type-safe memory-to-memory transfer using Embassy-style async API // Using async `.await` - the executor can run other tasks while waiting! - let transfer = dma_ch0.mem_to_mem(src, dst, options); + let transfer = dma_ch0.mem_to_mem(src, dst, options).unwrap(); transfer.await; defmt::info!("DMA mem-to-mem transfer complete!"); diff --git a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs index 51a7bc275..1e16e60ba 100644 --- a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs +++ b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs @@ -217,7 +217,7 @@ async fn main(_spawner: Spawner) { defmt::info!("Starting transfer with half_transfer_interrupt..."); // Create the transfer - let mut transfer = dma_ch1.mem_to_mem(src2, dst2, options); + let mut transfer = dma_ch1.mem_to_mem(src2, dst2, options).unwrap(); // Wait for half-transfer (first 4 elements) defmt::info!("Waiting for first half..."); -- cgit From a75aa12d928d1ba0c1759052a652426ab965f739 Mon Sep 17 00:00:00 2001 From: James Munns Date: Tue, 9 Dec 2025 18:33:01 +0100 Subject: Add error state for DMA transfers --- examples/mcxa/src/bin/dma_mem_to_mem.rs | 2 +- examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/dma_mem_to_mem.rs b/examples/mcxa/src/bin/dma_mem_to_mem.rs index a9ee9ffdf..b38baccb5 100644 --- a/examples/mcxa/src/bin/dma_mem_to_mem.rs +++ b/examples/mcxa/src/bin/dma_mem_to_mem.rs @@ -71,7 +71,7 @@ async fn main(_spawner: Spawner) { // Perform type-safe memory-to-memory transfer using Embassy-style async API // Using async `.await` - the executor can run other tasks while waiting! let transfer = dma_ch0.mem_to_mem(src, dst, options).unwrap(); - transfer.await; + transfer.await.unwrap(); defmt::info!("DMA mem-to-mem transfer complete!"); defmt::info!("Destination Buffer (after): {=[?]}", dst.as_slice()); diff --git a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs index 1e16e60ba..80df40449 100644 --- a/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs +++ b/examples/mcxa/src/bin/raw_dma_ping_pong_transfer.rs @@ -221,13 +221,13 @@ async fn main(_spawner: Spawner) { // Wait for half-transfer (first 4 elements) defmt::info!("Waiting for first half..."); - let _ok = transfer.wait_half().await; + let _ok = transfer.wait_half().await.unwrap(); defmt::info!("Half-transfer complete!"); // Wait for complete transfer defmt::info!("Waiting for second half..."); - transfer.await; + transfer.await.unwrap(); defmt::info!("Transfer complete! Full DST2: {=[?]}", dst2.as_slice()); -- cgit From ac764a85a1287b9ca921352aa1fd21c78ffa0312 Mon Sep 17 00:00:00 2001 From: Roman Lim Date: Wed, 24 Sep 2025 13:52:58 +0200 Subject: allow again to set nodiv independently of master clock divider --- examples/stm32h7/src/bin/sai.rs | 2 +- examples/stm32h723/src/bin/spdifrx.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32h7/src/bin/sai.rs b/examples/stm32h7/src/bin/sai.rs index 847b70c85..0300f83bf 100644 --- a/examples/stm32h7/src/bin/sai.rs +++ b/examples/stm32h7/src/bin/sai.rs @@ -63,7 +63,7 @@ async fn main(_spawner: Spawner) { tx_config.tx_rx = TxRx::Transmitter; tx_config.sync_output = true; tx_config.clock_strobe = ClockStrobe::Falling; - tx_config.master_clock_divider = Some(mclk_div); + tx_config.master_clock_divider = mclk_div; tx_config.stereo_mono = StereoMono::Stereo; tx_config.data_size = DataSize::Data24; tx_config.bit_order = BitOrder::MsbFirst; diff --git a/examples/stm32h723/src/bin/spdifrx.rs b/examples/stm32h723/src/bin/spdifrx.rs index 5c29602c6..959e2aa18 100644 --- a/examples/stm32h723/src/bin/spdifrx.rs +++ b/examples/stm32h723/src/bin/spdifrx.rs @@ -168,7 +168,6 @@ fn new_sai_transmitter<'d>( sai_config.slot_enable = 0xFFFF; // All slots sai_config.data_size = sai::DataSize::Data32; sai_config.frame_length = (CHANNEL_COUNT * 32) as u16; - sai_config.master_clock_divider = None; let (sub_block_tx, _) = hal::sai::split_subblocks(sai); Sai::new_asynchronous(sub_block_tx, sck, sd, fs, dma, buf, sai_config) -- cgit From 1ccf45058db4e77ac2c59357cab196b659201b63 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Fri, 5 Dec 2025 14:37:19 -0800 Subject: ADC driver improvement Signed-off-by: Mathis Deroo --- examples/mcxa/src/bin/adc_interrupt.rs | 42 +++++++++++----------------------- examples/mcxa/src/bin/adc_polling.rs | 18 +++++++-------- examples/mcxa/src/lib.rs | 16 ------------- 3 files changed, 22 insertions(+), 54 deletions(-) delete mode 100644 examples/mcxa/src/lib.rs (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index c88b1fe8d..9db1173e3 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -2,35 +2,33 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa_examples::init_adc_pins; -use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; +use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy, InterruptHandler}; use hal::clocks::PoweredClock; +use hal::config::Config; +use hal::clocks::config::Div8; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; -use hal::{InterruptExt, bind_interrupts}; +use hal::bind_interrupts; +use hal::peripherals::ADC1; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; bind_interrupts!(struct Irqs { - ADC1 => hal::adc::AdcHandler; + ADC1 => InterruptHandler; }); -#[used] -#[no_mangle] -static KEEP_ADC: unsafe extern "C" fn() = ADC1; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); defmt::info!("ADC interrupt Example"); - unsafe { - init_adc_pins(); - } - let adc_config = LpadcConfig { enable_in_doze_mode: true, conversion_average_mode: CalAvgs::Average128, @@ -46,7 +44,7 @@ async fn main(_spawner: Spawner) { source: AdcClockSel::FroLfDiv, div: Div4::no_div(), }; - let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + let mut adc = Adc::new(p.ADC1, p.P1_10, Irqs, adc_config); adc.do_offset_calibration(); adc.do_auto_calibration(); @@ -63,22 +61,8 @@ async fn main(_spawner: Spawner) { defmt::info!("ADC configuration done..."); - adc.enable_interrupt(0x1); - - unsafe { - hal::interrupt::ADC1.enable(); - } - - unsafe { - cortex_m::interrupt::enable(); - } - loop { - adc.do_software_trigger(1); - while !adc.is_interrupt_triggered() { - // Wait until the interrupt is triggered - } - defmt::info!("*** ADC interrupt TRIGGERED! ***"); - //TBD need to print the value + let value = adc.read().await; + defmt::info!("*** ADC interrupt TRIGGERED! *** -- value: {}", value); } } diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index 07c50f224..65b66c8dd 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -2,9 +2,10 @@ #![no_main] use embassy_executor::Spawner; -use embassy_mcxa_examples::init_adc_pins; -use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy}; +use hal::adc::{Adc, ConvResult, LpadcConfig, TriggerPriorityPolicy}; use hal::clocks::PoweredClock; +use hal::config::Config; +use hal::clocks::config::Div8; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; @@ -16,11 +17,10 @@ const G_LPADC_RESULT_SHIFT: u32 = 0; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = hal::init(hal::config::Config::default()); - - unsafe { - init_adc_pins(); - } + let mut config = Config::default(); + config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); + + let p = hal::init(config); defmt::info!("=== ADC polling Example ==="); @@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) { source: AdcClockSel::FroLfDiv, div: Div4::no_div(), }; - let adc = hal::adc::Adc::::new(p.ADC1, adc_config); + let adc = Adc::new_polling(p.ADC1, p.P1_10, adc_config); adc.do_offset_calibration(); adc.do_auto_calibration(); @@ -60,7 +60,7 @@ async fn main(_spawner: Spawner) { adc.do_software_trigger(1); let mut result: Option = None; while result.is_none() { - result = hal::adc::get_conv_result(); + result = adc.get_conv_result(); } let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; defmt::info!("value: {=u16}", value); diff --git a/examples/mcxa/src/lib.rs b/examples/mcxa/src/lib.rs deleted file mode 100644 index 2573a6adc..000000000 --- a/examples/mcxa/src/lib.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![no_std] -#![allow(clippy::missing_safety_doc)] - -//! Shared board-specific helpers for the FRDM-MCXA276 examples. -//! These live with the examples so the HAL stays generic. - -use hal::{clocks, pins}; -use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; - -/// Initialize clocks and pin muxing for ADC. -pub unsafe fn init_adc_pins() { - // NOTE: Lpuart has been updated to properly enable + reset its own clocks. - // GPIO has not. - _ = clocks::enable_and_reset::(&clocks::periph_helpers::NoConfig); - pins::configure_adc_pins(); -} -- cgit From b9bb7c0ebdbe19832ed9e9d75b12df86523c5fd2 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 11:12:33 -0800 Subject: Modify set_conv_command_config to support command index from 1 to 7 Signed-off-by: Mathis Deroo --- examples/mcxa/src/bin/adc_interrupt.rs | 4 ++-- examples/mcxa/src/bin/adc_polling.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 9db1173e3..125e37690 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -50,8 +50,8 @@ async fn main(_spawner: Spawner) { adc.do_auto_calibration(); let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8 as u8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits as u8; adc.set_conv_command_config(1, &conv_command_config); let mut conv_trigger_config = adc.get_default_conv_trigger_config(); diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index 65b66c8dd..523035e0f 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -45,8 +45,8 @@ async fn main(_spawner: Spawner) { adc.do_auto_calibration(); let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits; + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8 as u8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits as u8; adc.set_conv_command_config(1, &conv_command_config); let mut conv_trigger_config = adc.get_default_conv_trigger_config(); -- cgit From ff068148fcbc7ea148454cffa81921cc0e0da3e9 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 13:56:31 -0800 Subject: Modify ConvCommandConfig struct Signed-off-by: Mathis Deroo --- examples/mcxa/src/bin/adc_interrupt.rs | 4 ++-- examples/mcxa/src/bin/adc_polling.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 125e37690..9db1173e3 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -50,8 +50,8 @@ async fn main(_spawner: Spawner) { adc.do_auto_calibration(); let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8 as u8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits as u8; + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; adc.set_conv_command_config(1, &conv_command_config); let mut conv_trigger_config = adc.get_default_conv_trigger_config(); diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index 523035e0f..65b66c8dd 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -45,8 +45,8 @@ async fn main(_spawner: Spawner) { adc.do_auto_calibration(); let mut conv_command_config = adc.get_default_conv_command_config(); - conv_command_config.channel_number = Adch::SelectCorrespondingChannel8 as u8; - conv_command_config.conversion_resolution_mode = Mode::Data16Bits as u8; + conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; + conv_command_config.conversion_resolution_mode = Mode::Data16Bits; adc.set_conv_command_config(1, &conv_command_config); let mut conv_trigger_config = adc.get_default_conv_trigger_config(); -- cgit From 93b0f0308abee5607efae799039e0f4ccf2914b6 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 14:08:34 -0800 Subject: Use Result enum for ConvResult structure and read function Signed-off-by: Mathis Deroo --- examples/mcxa/src/bin/adc_interrupt.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 9db1173e3..a0e392634 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -62,7 +62,13 @@ async fn main(_spawner: Spawner) { defmt::info!("ADC configuration done..."); loop { - let value = adc.read().await; - defmt::info!("*** ADC interrupt TRIGGERED! *** -- value: {}", value); + match adc.read().await { + Ok(value) => { + defmt::info!("*** ADC interrupt TRIGGERED! *** -- value: {}", value); + } + Err(e) => { + defmt::error!("ADC read error: {:?}", e); + } + } } } -- cgit From 759ab109806f447a1193954a453828b860104c3a Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 15:09:05 -0800 Subject: Add Mode trait for Async and Blocking behavior Signed-off-by: Mathis Deroo --- examples/mcxa/src/bin/adc_interrupt.rs | 2 +- examples/mcxa/src/bin/adc_polling.rs | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index a0e392634..67fcf6361 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { source: AdcClockSel::FroLfDiv, div: Div4::no_div(), }; - let mut adc = Adc::new(p.ADC1, p.P1_10, Irqs, adc_config); + let mut adc = Adc::new_async(p.ADC1, p.P1_10, Irqs, adc_config).unwrap(); adc.do_offset_calibration(); adc.do_auto_calibration(); diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index 65b66c8dd..14d47329a 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -2,7 +2,7 @@ #![no_main] use embassy_executor::Spawner; -use hal::adc::{Adc, ConvResult, LpadcConfig, TriggerPriorityPolicy}; +use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy}; use hal::clocks::PoweredClock; use hal::config::Config; use hal::clocks::config::Div8; @@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) { source: AdcClockSel::FroLfDiv, div: Div4::no_div(), }; - let adc = Adc::new_polling(p.ADC1, p.P1_10, adc_config); + let adc = Adc::new_blocking(p.ADC1, p.P1_10, adc_config).unwrap(); adc.do_offset_calibration(); adc.do_auto_calibration(); @@ -58,11 +58,15 @@ async fn main(_spawner: Spawner) { loop { adc.do_software_trigger(1); - let mut result: Option = None; - while result.is_none() { - result = adc.get_conv_result(); - } - let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; - defmt::info!("value: {=u16}", value); + let result = loop { + match adc.get_conv_result() { + Ok(res) => break res, + Err(_) => { + // Conversion not ready, continue polling + } + } + }; + let value = result.conv_value >> G_LPADC_RESULT_SHIFT; + defmt::info!("ADC value: {=u16}", value); } } -- cgit From 20ed25fbad4e7651316b4841aefdf62ee197ea31 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 15:17:54 -0800 Subject: set_conv_command_config returns Result instead of panic if index > 7 Signed-off-by: Mathis Deroo --- examples/mcxa/src/bin/adc_interrupt.rs | 2 +- examples/mcxa/src/bin/adc_polling.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 67fcf6361..257e04491 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -52,7 +52,7 @@ async fn main(_spawner: Spawner) { let mut conv_command_config = adc.get_default_conv_command_config(); conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; conv_command_config.conversion_resolution_mode = Mode::Data16Bits; - adc.set_conv_command_config(1, &conv_command_config); + adc.set_conv_command_config(1, &conv_command_config).unwrap(); let mut conv_trigger_config = adc.get_default_conv_trigger_config(); conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index 14d47329a..b11b8957f 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) { let mut conv_command_config = adc.get_default_conv_command_config(); conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; conv_command_config.conversion_resolution_mode = Mode::Data16Bits; - adc.set_conv_command_config(1, &conv_command_config); + adc.set_conv_command_config(1, &conv_command_config).unwrap(); let mut conv_trigger_config = adc.get_default_conv_trigger_config(); conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; -- cgit From b8b0bb6eee22827b4eb493c6b48b35e01b860aad Mon Sep 17 00:00:00 2001 From: Cesar Tamayo Claro Date: Tue, 9 Dec 2025 13:44:23 -0700 Subject: Add basic RTC support --- examples/stm32f3/Cargo.toml | 5 ++-- examples/stm32wba6/src/bin/rtc.rs | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 examples/stm32wba6/src/bin/rtc.rs (limited to 'examples') diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 4349e8055..e624b4092 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] # Change stm32f303ze to your chip name, if necessary. -embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } +embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f302r8", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } @@ -27,7 +27,8 @@ embedded-storage = "0.3.1" static_cell = "2" [profile.release] -debug = 2 +debug = false +opt-level = 'z' [package.metadata.embassy] build = [ diff --git a/examples/stm32wba6/src/bin/rtc.rs b/examples/stm32wba6/src/bin/rtc.rs new file mode 100644 index 000000000..1e5634c60 --- /dev/null +++ b/examples/stm32wba6/src/bin/rtc.rs @@ -0,0 +1,63 @@ +#![no_std] +#![no_main] + +// use chrono::{NaiveDate, NaiveDateTime}; +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::Config; +use embassy_stm32::rcc::*; +use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +pub fn pll_init(config: &mut Config) { + config.rcc.pll1 = Some(embassy_stm32::rcc::Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz + mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO + divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk) + // divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED) + divq: None, + divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG) + frac: Some(0), // Fractional part (enabled) + }); + + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.apb7_pre = APBPrescaler::DIV1; + config.rcc.ahb5_pre = AHB5Prescaler::DIV4; + + // voltage scale for max performance + config.rcc.voltage_scale = VoltageScale::RANGE1; + // route PLL1_P into the USB‐OTG‐HS block + config.rcc.sys = Sysclk::PLL1_R; +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + + pll_init(&mut config); + + let p = embassy_stm32::init(config); + + let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + + // Setting datetime + let initial_datetime = DateTime::from(2025, 12, 9, DayOfWeek::Tuesday, 11, 00, 00, 0).unwrap(); + match rtc.0.set_datetime(initial_datetime) { + Ok(()) => info!("RTC set successfully."), + Err(e) => error!("Failed to set RTC date/time: {:?}", e), + } + + // Reading datetime every 1s + loop { + match rtc.1.now() { + Ok(result) => info!("{}", result), + Err(e) => error!("Failed to set RTC date/time: {:?}", e), + } + + Timer::after_millis(1000).await; + } +} -- cgit From e8a84adb8d5bf3f773dfccd88c97390f36b5605a Mon Sep 17 00:00:00 2001 From: Cesar Tamayo Claro Date: Tue, 9 Dec 2025 14:03:55 -0700 Subject: Undo smt32f3 accidental change --- examples/stm32f3/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index e624b4092..a4cfe7ed8 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] # Change stm32f303ze to your chip name, if necessary. -embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f302r8", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } +embassy-stm32 = { version = "0.4.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } -- cgit From 351f300fa3be839dfddb409c764541746d19b939 Mon Sep 17 00:00:00 2001 From: Cesar Tamayo Claro Date: Tue, 9 Dec 2025 14:05:28 -0700 Subject: Undo smt32f3 accidental change 2.0 --- examples/stm32f3/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'examples') diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index a4cfe7ed8..4349e8055 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -27,8 +27,7 @@ embedded-storage = "0.3.1" static_cell = "2" [profile.release] -debug = false -opt-level = 'z' +debug = 2 [package.metadata.embassy] build = [ -- cgit From 4f0eb421de9e08bbbf7f9a58f8b29c451de59894 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Tue, 9 Dec 2025 15:13:07 -0800 Subject: run rustfmt Signed-off-by: Mathis Deroo --- examples/mcxa/src/bin/adc_interrupt.rs | 11 +++++------ examples/mcxa/src/bin/adc_polling.rs | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'examples') diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 257e04491..5876923a1 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -2,16 +2,16 @@ #![no_main] use embassy_executor::Spawner; -use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy, InterruptHandler}; +use hal::adc::{Adc, InterruptHandler, LpadcConfig, TriggerPriorityPolicy}; +use hal::bind_interrupts; use hal::clocks::PoweredClock; -use hal::config::Config; use hal::clocks::config::Div8; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; +use hal::config::Config; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; -use hal::bind_interrupts; use hal::peripherals::ADC1; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -19,12 +19,11 @@ bind_interrupts!(struct Irqs { ADC1 => InterruptHandler; }); - #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); - + let p = hal::init(config); defmt::info!("ADC interrupt Example"); @@ -62,7 +61,7 @@ async fn main(_spawner: Spawner) { defmt::info!("ADC configuration done..."); loop { - match adc.read().await { + match adc.read().await { Ok(value) => { defmt::info!("*** ADC interrupt TRIGGERED! *** -- value: {}", value); } diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index b11b8957f..d048bb56f 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -4,9 +4,9 @@ use embassy_executor::Spawner; use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy}; use hal::clocks::PoweredClock; -use hal::config::Config; use hal::clocks::config::Div8; use hal::clocks::periph_helpers::{AdcClockSel, Div4}; +use hal::config::Config; use hal::pac::adc1::cfg::{Pwrsel, Refsel}; use hal::pac::adc1::cmdl1::{Adch, Mode}; use hal::pac::adc1::ctrl::CalAvgs; @@ -19,7 +19,7 @@ const G_LPADC_RESULT_SHIFT: u32 = 0; async fn main(_spawner: Spawner) { let mut config = Config::default(); config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1); - + let p = hal::init(config); defmt::info!("=== ADC polling Example ==="); -- cgit From c5c7a2143b15530b0c8f08d1dd6e24a6985318f9 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 9 Dec 2025 19:36:05 -0600 Subject: sdmmc: refactor sd card creation --- examples/stm32f4/src/bin/sdmmc.rs | 35 ++++++++++++++--------------------- examples/stm32f7/src/bin/sdmmc.rs | 12 ++++++++---- examples/stm32h7/src/bin/sdmmc.rs | 14 ++++++++------ 3 files changed, 30 insertions(+), 31 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index fe0f887bf..897b0e05e 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::sdmmc::{DataBlock, Sdmmc}; +use embassy_stm32::sdmmc::{CmdBlock, DataBlock, Sdmmc, StorageDevice}; use embassy_stm32::time::{Hertz, mhz}; use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; @@ -57,23 +57,16 @@ async fn main(_spawner: Spawner) { // Should print 400kHz for initialization info!("Configured clock: {}", sdmmc.clock().0); - let mut err = None; - loop { - match sdmmc.init_sd_card(mhz(24)).await { - Ok(_) => break, - Err(e) => { - if err != Some(e) { - info!("waiting for card error, retrying: {:?}", e); - err = Some(e); - } - } - } - } + let mut cmd_block = CmdBlock::new(); + + let mut storage = StorageDevice::new_sd_card(&mut sdmmc, &mut cmd_block, mhz(24)) + .await + .unwrap(); - let card = unwrap!(sdmmc.card()); + let card = storage.card(); - info!("Card: {:#?}", Debug2Format(card)); - info!("Clock: {}", sdmmc.clock()); + info!("Card: {:#?}", Debug2Format(&card)); + info!("Clock: {}", storage.sdmmc.clock()); // Arbitrary block index let block_idx = 16; @@ -81,7 +74,7 @@ async fn main(_spawner: Spawner) { // SDMMC uses `DataBlock` instead of `&[u8]` to ensure 4 byte alignment required by the hardware. let mut block = DataBlock([0u8; 512]); - sdmmc.read_block(block_idx, &mut block).await.unwrap(); + storage.read_block(block_idx, &mut block).await.unwrap(); info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); if !ALLOW_WRITES { @@ -91,17 +84,17 @@ async fn main(_spawner: Spawner) { info!("Filling block with 0x55"); block.fill(0x55); - sdmmc.write_block(block_idx, &block).await.unwrap(); + storage.write_block(block_idx, &block).await.unwrap(); info!("Write done"); - sdmmc.read_block(block_idx, &mut block).await.unwrap(); + storage.read_block(block_idx, &mut block).await.unwrap(); info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); info!("Filling block with 0xAA"); block.fill(0xAA); - sdmmc.write_block(block_idx, &block).await.unwrap(); + storage.write_block(block_idx, &block).await.unwrap(); info!("Write done"); - sdmmc.read_block(block_idx, &mut block).await.unwrap(); + storage.read_block(block_idx, &mut block).await.unwrap(); info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); } diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 8809b5d0c..0dd4dd6f3 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::sdmmc::Sdmmc; +use embassy_stm32::sdmmc::{CmdBlock, Sdmmc, StorageDevice}; use embassy_stm32::time::{Hertz, mhz}; use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; @@ -54,9 +54,13 @@ async fn main(_spawner: Spawner) { // Should print 400kHz for initialization info!("Configured clock: {}", sdmmc.clock().0); - unwrap!(sdmmc.init_sd_card(mhz(25)).await); + let mut cmd_block = CmdBlock::new(); - let card = unwrap!(sdmmc.card()); + let storage = StorageDevice::new_sd_card(&mut sdmmc, &mut cmd_block, mhz(25)) + .await + .unwrap(); - info!("Card: {:#?}", Debug2Format(card)); + let card = storage.card(); + + info!("Card: {:#?}", Debug2Format(&card)); } diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index 4977fec79..548d0bd09 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -3,7 +3,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::sdmmc::Sdmmc; +use embassy_stm32::sdmmc::{CmdBlock, Sdmmc, StorageDevice}; use embassy_stm32::time::mhz; use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; @@ -13,7 +13,7 @@ bind_interrupts!(struct Irqs { }); #[embassy_executor::main] -async fn main(_spawner: Spawner) -> ! { +async fn main(_spawner: Spawner) { let mut config = Config::default(); { use embassy_stm32::rcc::*; @@ -53,11 +53,13 @@ async fn main(_spawner: Spawner) -> ! { // Should print 400kHz for initialization info!("Configured clock: {}", sdmmc.clock().0); - unwrap!(sdmmc.init_sd_card(mhz(25)).await); + let mut cmd_block = CmdBlock::new(); - let card = unwrap!(sdmmc.card()); + let storage = StorageDevice::new_sd_card(&mut sdmmc, &mut cmd_block, mhz(25)) + .await + .unwrap(); - info!("Card: {:#?}", Debug2Format(card)); + let card = storage.card(); - loop {} + info!("Card: {:#?}", Debug2Format(&card)); } -- cgit From a48bd43f6ff39f9a98357a17d02ec03461b09351 Mon Sep 17 00:00:00 2001 From: Cesar Tamayo Claro Date: Tue, 9 Dec 2025 23:13:01 -0700 Subject: Update set date to Unix Epoch --- examples/stm32wba6/src/bin/rtc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32wba6/src/bin/rtc.rs b/examples/stm32wba6/src/bin/rtc.rs index 1e5634c60..f150df1c0 100644 --- a/examples/stm32wba6/src/bin/rtc.rs +++ b/examples/stm32wba6/src/bin/rtc.rs @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) { let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); // Setting datetime - let initial_datetime = DateTime::from(2025, 12, 9, DayOfWeek::Tuesday, 11, 00, 00, 0).unwrap(); + let initial_datetime = DateTime::from(1970, 1, 1, DayOfWeek::Thursday, 0, 00, 00, 0).unwrap(); match rtc.0.set_datetime(initial_datetime) { Ok(()) => info!("RTC set successfully."), Err(e) => error!("Failed to set RTC date/time: {:?}", e), -- cgit From 1d4fb4e39ef13f5d2b1c8979e7058acf6836e85b Mon Sep 17 00:00:00 2001 From: Cesar Tamayo Claro Date: Tue, 9 Dec 2025 23:16:34 -0700 Subject: Remove commented import --- examples/stm32wba6/src/bin/rtc.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'examples') diff --git a/examples/stm32wba6/src/bin/rtc.rs b/examples/stm32wba6/src/bin/rtc.rs index f150df1c0..cef8501e0 100644 --- a/examples/stm32wba6/src/bin/rtc.rs +++ b/examples/stm32wba6/src/bin/rtc.rs @@ -1,7 +1,6 @@ #![no_std] #![no_main] -// use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::Config; -- cgit From 3892f575a0b4fc8ad2186020389d9923568a2534 Mon Sep 17 00:00:00 2001 From: Cesar Tamayo Claro Date: Tue, 9 Dec 2025 23:17:03 -0700 Subject: Copy rtc into stm32wba examples folder --- examples/stm32wba/src/bin/rtc.rs | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 examples/stm32wba/src/bin/rtc.rs (limited to 'examples') diff --git a/examples/stm32wba/src/bin/rtc.rs b/examples/stm32wba/src/bin/rtc.rs new file mode 100644 index 000000000..cef8501e0 --- /dev/null +++ b/examples/stm32wba/src/bin/rtc.rs @@ -0,0 +1,62 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::Config; +use embassy_stm32::rcc::*; +use embassy_stm32::rtc::{DateTime, DayOfWeek, Rtc, RtcConfig}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +pub fn pll_init(config: &mut Config) { + config.rcc.pll1 = Some(embassy_stm32::rcc::Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV1, // PLLM = 1 → HSI / 1 = 16 MHz + mul: PllMul::MUL30, // PLLN = 30 → 16 MHz * 30 = 480 MHz VCO + divr: Some(PllDiv::DIV5), // PLLR = 5 → 96 MHz (Sysclk) + // divq: Some(PllDiv::DIV10), // PLLQ = 10 → 48 MHz (NOT USED) + divq: None, + divp: Some(PllDiv::DIV30), // PLLP = 30 → 16 MHz (USBOTG) + frac: Some(0), // Fractional part (enabled) + }); + + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.apb7_pre = APBPrescaler::DIV1; + config.rcc.ahb5_pre = AHB5Prescaler::DIV4; + + // voltage scale for max performance + config.rcc.voltage_scale = VoltageScale::RANGE1; + // route PLL1_P into the USB‐OTG‐HS block + config.rcc.sys = Sysclk::PLL1_R; +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut config = Config::default(); + + pll_init(&mut config); + + let p = embassy_stm32::init(config); + + let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); + + // Setting datetime + let initial_datetime = DateTime::from(1970, 1, 1, DayOfWeek::Thursday, 0, 00, 00, 0).unwrap(); + match rtc.0.set_datetime(initial_datetime) { + Ok(()) => info!("RTC set successfully."), + Err(e) => error!("Failed to set RTC date/time: {:?}", e), + } + + // Reading datetime every 1s + loop { + match rtc.1.now() { + Ok(result) => info!("{}", result), + Err(e) => error!("Failed to set RTC date/time: {:?}", e), + } + + Timer::after_millis(1000).await; + } +} -- cgit From 286571a17bcb34c271eb64c8e9aca736599309e1 Mon Sep 17 00:00:00 2001 From: Lambert Sartory Date: Thu, 11 Dec 2025 00:05:24 +0100 Subject: Add more STM32N6 examples --- examples/stm32n6/Cargo.toml | 2 ++ examples/stm32n6/src/bin/crc.rs | 31 ++++++++++++++++ examples/stm32n6/src/bin/hash.rs | 78 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 examples/stm32n6/src/bin/crc.rs create mode 100644 examples/stm32n6/src/bin/hash.rs (limited to 'examples') diff --git a/examples/stm32n6/Cargo.toml b/examples/stm32n6/Cargo.toml index 5ed28eed1..5ad5b97ce 100644 --- a/examples/stm32n6/Cargo.toml +++ b/examples/stm32n6/Cargo.toml @@ -32,6 +32,8 @@ micromath = "2.0.0" stm32-fmc = "0.3.0" embedded-storage = "0.3.1" static_cell = "2" +hmac = "0.12.1" +sha2 = { version = "0.10.9", default-features = false } # cargo build/run diff --git a/examples/stm32n6/src/bin/crc.rs b/examples/stm32n6/src/bin/crc.rs new file mode 100644 index 000000000..d1b545d5b --- /dev/null +++ b/examples/stm32n6/src/bin/crc.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::crc::{Config, Crc, InputReverseConfig, PolySize}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + // Setup for: https://crccalc.com/?crc=Life, it never dieWomen are my favorite guy&method=crc32&datatype=ascii&outtype=0 + let mut crc = Crc::new( + p.CRC, + unwrap!(Config::new( + InputReverseConfig::Byte, + true, + PolySize::Width32, + 0xFFFFFFFF, + 0x04C11DB7 + )), + ); + + let output = crc.feed_bytes(b"Life, it never die\nWomen are my favorite guy") ^ 0xFFFFFFFF; + + defmt::assert_eq!(output, 0x33F0E26B); + + cortex_m::asm::bkpt(); +} diff --git a/examples/stm32n6/src/bin/hash.rs b/examples/stm32n6/src/bin/hash.rs new file mode 100644 index 000000000..9f248318f --- /dev/null +++ b/examples/stm32n6/src/bin/hash.rs @@ -0,0 +1,78 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::hash::*; +use embassy_stm32::{Config, bind_interrupts, hash, peripherals}; +use embassy_time::Instant; +use hmac::{Hmac, Mac}; +use sha2::{Digest, Sha256}; +use {defmt_rtt as _, panic_probe as _}; + +type HmacSha256 = Hmac; + +bind_interrupts!(struct Irqs { + HASH => hash::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let config = Config::default(); + let p = embassy_stm32::init(config); + + let test_1: &[u8] = b"as;dfhaslfhas;oifvnasd;nifvnhasd;nifvhndlkfghsd;nvfnahssdfgsdafgsasdfasdfasdfasdfasdfghjklmnbvcalskdjghalskdjgfbaslkdjfgbalskdjgbalskdjbdfhsdfhsfghsfghfgh"; + let test_2: &[u8] = b"fdhalksdjfhlasdjkfhalskdjfhgal;skdjfgalskdhfjgalskdjfglafgadfgdfgdafgaadsfgfgdfgadrgsyfthxfgjfhklhjkfgukhulkvhlvhukgfhfsrghzdhxyfufynufyuszeradrtydyytserr"; + + let mut hw_hasher = Hash::new_blocking(p.HASH, Irqs); + + let hw_start_time = Instant::now(); + + // Compute a digest in hardware. + let mut context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, None); + hw_hasher.update_blocking(&mut context, test_1); + hw_hasher.update_blocking(&mut context, test_2); + let mut hw_digest: [u8; 32] = [0; 32]; + hw_hasher.finish_blocking(context, &mut hw_digest); + + let hw_end_time = Instant::now(); + let hw_execution_time = hw_end_time - hw_start_time; + + let sw_start_time = Instant::now(); + + // Compute a digest in software. + let mut sw_hasher = Sha256::new(); + sw_hasher.update(test_1); + sw_hasher.update(test_2); + let sw_digest = sw_hasher.finalize(); + + let sw_end_time = Instant::now(); + let sw_execution_time = sw_end_time - sw_start_time; + + info!("Hardware Digest: {:?}", hw_digest); + info!("Software Digest: {:?}", sw_digest[..]); + info!("Hardware Execution Time: {:?}", hw_execution_time); + info!("Software Execution Time: {:?}", sw_execution_time); + assert_eq!(hw_digest, sw_digest[..]); + + let hmac_key: [u8; 64] = [0x55; 64]; + + // Compute HMAC in hardware. + let mut sha256hmac_context = hw_hasher.start(Algorithm::SHA256, DataType::Width8, Some(&hmac_key)); + hw_hasher.update_blocking(&mut sha256hmac_context, test_1); + hw_hasher.update_blocking(&mut sha256hmac_context, test_2); + let mut hw_hmac: [u8; 32] = [0; 32]; + hw_hasher.finish_blocking(sha256hmac_context, &mut hw_hmac); + + // Compute HMAC in software. + let mut sw_mac = HmacSha256::new_from_slice(&hmac_key).unwrap(); + sw_mac.update(test_1); + sw_mac.update(test_2); + let sw_hmac = sw_mac.finalize().into_bytes(); + + info!("Hardware HMAC: {:?}", hw_hmac); + info!("Software HMAC: {:?}", sw_hmac[..]); + assert_eq!(hw_hmac, sw_hmac[..]); + + loop {} +} -- cgit From 48100a2e8d15364f6243d3db0a649e5c90c9ffe7 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 11 Dec 2025 08:00:24 -0600 Subject: sdmmc: factor out sd and add sdio mod --- examples/stm32f4/src/bin/sdmmc.rs | 5 +++-- examples/stm32f7/src/bin/sdmmc.rs | 3 ++- examples/stm32h7/src/bin/sdmmc.rs | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'examples') diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 897b0e05e..098fd6986 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -3,7 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::sdmmc::{CmdBlock, DataBlock, Sdmmc, StorageDevice}; +use embassy_stm32::sdmmc::Sdmmc; +use embassy_stm32::sdmmc::sd::{CmdBlock, DataBlock, StorageDevice}; use embassy_stm32::time::{Hertz, mhz}; use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; @@ -72,7 +73,7 @@ async fn main(_spawner: Spawner) { let block_idx = 16; // SDMMC uses `DataBlock` instead of `&[u8]` to ensure 4 byte alignment required by the hardware. - let mut block = DataBlock([0u8; 512]); + let mut block = DataBlock::new(); storage.read_block(block_idx, &mut block).await.unwrap(); info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index 0dd4dd6f3..e5d261d89 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -3,7 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::sdmmc::{CmdBlock, Sdmmc, StorageDevice}; +use embassy_stm32::sdmmc::Sdmmc; +use embassy_stm32::sdmmc::sd::{CmdBlock, StorageDevice}; use embassy_stm32::time::{Hertz, mhz}; use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index 548d0bd09..f2e5bedeb 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -3,7 +3,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::sdmmc::{CmdBlock, Sdmmc, StorageDevice}; +use embassy_stm32::sdmmc::Sdmmc; +use embassy_stm32::sdmmc::sd::{CmdBlock, StorageDevice}; use embassy_stm32::time::mhz; use embassy_stm32::{Config, bind_interrupts, peripherals, sdmmc}; use {defmt_rtt as _, panic_probe as _}; -- cgit