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 --- embassy-mcxa/src/adc.rs | 429 +++++++++++++++++++++++++----- embassy-mcxa/src/clocks/mod.rs | 3 + embassy-mcxa/src/clocks/periph_helpers.rs | 1 + embassy-mcxa/src/interrupt.rs | 122 ++++++++- embassy-mcxa/src/lib.rs | 10 +- embassy-mcxa/src/pins.rs | 33 --- examples/mcxa/src/bin/adc_interrupt.rs | 42 +-- examples/mcxa/src/bin/adc_polling.rs | 18 +- examples/mcxa/src/lib.rs | 16 -- 9 files changed, 519 insertions(+), 155 deletions(-) delete mode 100644 embassy-mcxa/src/pins.rs delete mode 100644 examples/mcxa/src/lib.rs diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 7475299ba..2e2fb0342 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -1,42 +1,29 @@ //! ADC driver -use core::sync::atomic::{AtomicBool, Ordering}; +use core::marker::PhantomData; use embassy_hal_internal::{Peri, PeripheralType}; +use paste::paste; +use crate::pac; +use crate::interrupt::typelevel::{Handler, Interrupt}; +use crate::gpio::{GpioPin, SealedPin}; +use maitake_sync::WaitCell; + use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; use crate::clocks::{Gate, PoweredClock, enable_and_reset}; -use crate::pac; + use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; use crate::pac::adc1::ctrl::CalAvgs; use crate::pac::adc1::tctrl::{Tcmd, Tpri}; -type Regs = pac::adc1::RegisterBlock; +/// Global wait cell for alarm notifications +static WAKER: WaitCell = WaitCell::new(); -static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false); -// Token-based instance pattern like embassy-imxrt -pub trait Instance: Gate + PeripheralType { - fn ptr() -> *const Regs; -} - -/// Token for ADC1 -pub type Adc1 = crate::peripherals::ADC1; -impl Instance for crate::peripherals::ADC1 { - #[inline(always)] - fn ptr() -> *const Regs { - pac::Adc1::ptr() - } -} - -// Also implement Instance for the Peri wrapper type -// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> { -// #[inline(always)] -// fn ptr() -> *const Regs { -// pac::Adc1::ptr() -// } -// } +const G_LPADC_RESULT_SHIFT: u32 = 0; +/// Trigger priority policy for ADC conversions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] pub enum TriggerPriorityPolicy { @@ -52,20 +39,40 @@ pub enum TriggerPriorityPolicy { TriggerPriorityExceptionDisabled = 16, } +/// Configuration for the LPADC peripheral. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct LpadcConfig { + /// Control system transition to Stop and Wait power modes while ADC is converting. + /// When enabled in Doze mode, immediate entries to Wait or Stop are allowed. + /// When disabled, the ADC will wait for the current averaging iteration/FIFO storage to complete before acknowledging stop or wait mode entry. pub enable_in_doze_mode: bool, + /// Auto-Calibration Averages. pub conversion_average_mode: CalAvgs, + /// ADC analog circuits are pre-enabled and ready to execute conversions without startup delays(at the cost of higher DC current consumption). pub enable_analog_preliminary: bool, + /// Power-up delay value (in ADC clock cycles) pub power_up_delay: u8, + /// Reference voltage source selection pub reference_voltage_source: Refsel, + /// Power configuration selection. pub power_level_mode: Pwrsel, + /// Trigger priority policy for handling multiple triggers pub trigger_priority_policy: TriggerPriorityPolicy, + /// Enables the ADC pausing function. When enabled, a programmable delay is inserted during command execution sequencing between LOOP iterations, + /// between commands in a sequence, and between conversions when command is executing in "Compare Until True" configuration. pub enable_conv_pause: bool, + /// Controls the duration of pausing during command execution sequencing. The pause delay is a count of (convPauseDelay*4) ADCK cycles. + /// Only available when ADC pausing function is enabled. The available value range is in 9-bit. pub conv_pause_delay: u16, + /// FIFO watermark level for interrupt generation. + /// When the number of datawords stored in the ADC Result FIFO is greater than the value in this field, + /// the ready flag would be asserted to indicate stored data has reached the programmable threshold. pub fifo_watermark: u8, + /// Power configuration (normal/deep sleep behavior) pub power: PoweredClock, + /// ADC clock source selection pub source: AdcClockSel, + /// Clock divider for ADC clock pub div: Div4, } @@ -89,6 +96,9 @@ impl Default for LpadcConfig { } } +/// Configuration for a conversion command. +/// +/// Defines the parameters for a single ADC conversion operation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConvCommandConfig { pub sample_channel_mode: Ctype, @@ -105,6 +115,10 @@ pub struct ConvCommandConfig { pub enable_wait_trigger: bool, } + +/// Configuration for a conversion trigger. +/// +/// Defines how a trigger initiates ADC conversions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConvTriggerConfig { pub target_command_id: Tcmd, @@ -113,6 +127,9 @@ pub struct ConvTriggerConfig { pub enable_hardware_trigger: bool, } +/// Result of an ADC conversion. +/// +/// Contains the conversion value and metadata about the conversion. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConvResult { pub command_id_source: u32, @@ -121,14 +138,59 @@ pub struct ConvResult { pub conv_value: u16, } +/// ADC interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +/// ADC driver instance. pub struct Adc<'a, I: Instance> { - _inst: core::marker::PhantomData<&'a mut I>, + _inst: PhantomData<&'a mut I>, } impl<'a, I: Instance> Adc<'a, I> { - /// initialize ADC - pub fn new(_inst: Peri<'a, I>, config: LpadcConfig) -> Self { - let adc = unsafe { &*I::ptr() }; + /// Initialize ADC with interrupt support. + /// + /// # Arguments + /// * `_inst` - ADC peripheral instance + /// * `pin` - GPIO pin to use for ADC + /// * `_irq` - Interrupt binding for this ADC instance + /// * `config` - ADC configuration + pub fn new( + _inst: Peri<'a, I>, + pin: Peri<'a, impl AdcPin>, + _irq: impl crate::interrupt::typelevel::Binding> + 'a, + config: LpadcConfig, + ) -> Self { + let adc = Self::new_inner(_inst, pin, config); + + I::Interrupt::unpend(); + unsafe { I::Interrupt::enable() }; + + adc + } + + /// Initialize ADC without interrupt support (for polling mode). + /// + /// # Arguments + /// * `_inst` - ADC peripheral instance + /// * `pin` - GPIO pin to use for ADC input + /// * `config` - ADC configuration + pub fn new_polling( + _inst: Peri<'a, I>, + pin: Peri<'a, impl AdcPin>, + config: LpadcConfig, + ) -> Self { + Self::new_inner(_inst, pin, config) + } + + /// Internal initialization function shared by `new` and `new_polling`. + fn new_inner( + _inst: Peri<'a, I>, + pin: Peri<'a, impl AdcPin>, + config: LpadcConfig, + ) -> Self { + let adc = &*I::ptr(); let _clock_freq = unsafe { enable_and_reset::(&AdcConfig { @@ -139,6 +201,8 @@ impl<'a, I: Instance> Adc<'a, I> { .expect("Adc Init should not fail") }; + pin.mux(); + /* Reset the module. */ adc.ctrl().modify(|_, w| w.rst().held_in_reset()); adc.ctrl().modify(|_, w| w.rst().released_from_reset()); @@ -221,17 +285,20 @@ impl<'a, I: Instance> Adc<'a, I> { adc.ctrl().modify(|_, w| w.adcen().enabled()); Self { - _inst: core::marker::PhantomData, + _inst: PhantomData, } } + /// Deinitialize the ADC peripheral. pub fn deinit(&self) { - let adc = unsafe { &*I::ptr() }; + let adc = &*I::ptr(); adc.ctrl().modify(|_, w| w.adcen().disabled()); } + /// Perform offset calibration. + /// Waits for calibration to complete before returning. pub fn do_offset_calibration(&self) { - let adc = unsafe { &*I::ptr() }; + let adc = &*I::ptr(); // Enable calibration mode adc.ctrl() .modify(|_, w| w.calofs().offset_calibration_request_pending()); @@ -240,6 +307,13 @@ impl<'a, I: Instance> Adc<'a, I> { while adc.stat().read().cal_rdy().is_not_set() {} } + /// Calculate gain conversion result from gain adjustment factor. + /// + /// # Arguments + /// * `gain_adjustment` - Gain adjustment factor + /// + /// # Returns + /// Gain calibration register value pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 { let mut gcra_array = [0u32; 17]; let mut gcalr: u32 = 0; @@ -258,8 +332,9 @@ impl<'a, I: Instance> Adc<'a, I> { gcalr } + /// Perform automatic gain calibration. pub fn do_auto_calibration(&self) { - let adc = unsafe { &*I::ptr() }; + let adc = &*I::ptr(); adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} @@ -280,11 +355,21 @@ impl<'a, I: Instance> Adc<'a, I> { while adc.stat().read().cal_rdy().is_not_set() {} } + /// Trigger ADC conversion(s) via software. + /// + /// Initiates conversion(s) for the trigger(s) specified in the bitmask. + /// Each bit in the mask corresponds to a trigger ID (bit 0 = trigger 0, etc.). + /// + /// # Arguments + /// * `trigger_id_mask` - Bitmask of trigger IDs to activate (bit N = trigger N) pub fn do_software_trigger(&self, trigger_id_mask: u32) { - let adc = unsafe { &*I::ptr() }; + let adc = &*I::ptr(); adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); } + /// Get default conversion command configuration. + /// # Returns + /// Default conversion command configuration pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { ConvCommandConfig { sample_channel_mode: Ctype::SingleEndedASideChannel, @@ -302,9 +387,17 @@ impl<'a, I: Instance> Adc<'a, I> { } } - //TBD Need to add cmdlx and cmdhx with x {2..7} + /// Set conversion command configuration. + /// + /// Configures a conversion command slot with the specified parameters. + /// Commands define how conversions are performed (channel, resolution, etc.). + /// + /// # Arguments + /// * `index` - Command index (currently only 1 is supported) + /// * `config` - Command configuration + ///TBD Need to add cmdlx and cmdhx with x {2..7} pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { - let adc = unsafe { &*I::ptr() }; + let adc = &*I::ptr(); match index { 1 => { @@ -338,6 +431,10 @@ impl<'a, I: Instance> Adc<'a, I> { } } + /// Get default conversion trigger configuration. + /// + /// # Returns + /// Default conversion trigger configuration pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig { ConvTriggerConfig { target_command_id: Tcmd::NotValid, @@ -347,8 +444,16 @@ impl<'a, I: Instance> Adc<'a, I> { } } + /// Set conversion trigger configuration. + /// + /// Configures a trigger to initiate conversions. Triggers can be + /// activated by software or hardware signals. + /// + /// # Arguments + /// * `trigger_id` - Trigger index (0-15) + /// * `config` - Trigger configuration pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { - let adc = unsafe { &*I::ptr() }; + let adc = &*I::ptr(); let tctrl = &adc.tctrl(trigger_id); tctrl.write(|w| unsafe { @@ -363,47 +468,245 @@ impl<'a, I: Instance> Adc<'a, I> { }); } + /// Reset the FIFO buffer. + /// + /// Clears all pending conversion results from the FIFO. pub fn do_reset_fifo(&self) { - let adc = unsafe { &*I::ptr() }; + let adc = &*I::ptr(); adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); } + /// Enable ADC interrupts. + /// + /// Enables the interrupt sources specified in the bitmask. + /// + /// # Arguments + /// * `mask` - Bitmask of interrupt sources to enable pub fn enable_interrupt(&self, mask: u32) { - let adc = unsafe { &*I::ptr() }; + let adc = &*I::ptr(); adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); - INTERRUPT_TRIGGERED.store(false, Ordering::SeqCst); } - pub fn is_interrupt_triggered(&self) -> bool { - INTERRUPT_TRIGGERED.load(Ordering::Relaxed) + /// Disable ADC interrupts. + /// + /// Disables the interrupt sources specified in the bitmask. + /// + /// # Arguments + /// * `mask` - Bitmask of interrupt sources to disable + pub fn disable_interrupt(&self, mask: u32) { + let adc = &*I::ptr(); + adc.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); } -} -pub fn get_conv_result() -> Option { - let adc = unsafe { &*pac::Adc1::ptr() }; - let fifo = adc.resfifo0().read().bits(); - const VALID_MASK: u32 = 1 << 31; - if fifo & VALID_MASK == 0 { - return None; - } + /// Get conversion result from FIFO. + /// + /// Reads and returns the next conversion result from the FIFO. + /// Returns `None` if the FIFO is empty. + /// + /// # Returns + /// - `Some(ConvResult)` if a result is available + /// - `None` if the FIFO is empty + pub fn get_conv_result(&self) -> Option { + let adc = &*I::ptr(); + let fifo = adc.resfifo0().read().bits(); + const VALID_MASK: u32 = 1 << 31; + if fifo & VALID_MASK == 0 { + return None; + } - Some(ConvResult { - command_id_source: (fifo >> 24) & 0x0F, - loop_count_index: (fifo >> 20) & 0x0F, - trigger_id_source: (fifo >> 16) & 0x0F, - conv_value: (fifo & 0xFFFF) as u16, - }) -} + Some(ConvResult { + command_id_source: (fifo >> 24) & 0x0F, + loop_count_index: (fifo >> 20) & 0x0F, + trigger_id_source: (fifo >> 16) & 0x0F, + conv_value: (fifo & 0xFFFF) as u16, + }) + } -pub fn on_interrupt() { - if get_conv_result().is_some() { - INTERRUPT_TRIGGERED.store(true, Ordering::SeqCst); + /// Read ADC value asynchronously. + /// + /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered. + /// + /// The function: + /// 1. Enables the FIFO watermark interrupt + /// 2. Triggers a software conversion on trigger 0 + /// 3. Waits for the conversion to complete + /// 4. Returns the conversion result + /// + /// # Returns + /// 16-bit ADC conversion value + pub async fn read(&mut self) -> u16 { + let wait = WAKER.subscribe().await; + + self.enable_interrupt(0x1); + self.do_software_trigger(1); + + let _ = wait.await; + + let result = self.get_conv_result(); + result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT } } -pub struct AdcHandler; -impl crate::interrupt::typelevel::Handler for AdcHandler { +impl Handler for InterruptHandler { unsafe fn on_interrupt() { - on_interrupt(); + T::ptr().ie().modify(|r, w| w.bits(r.bits() & !0x1)); + WAKER.wake(); } } + +mod sealed { + /// Seal a trait + pub trait Sealed {} +} + +impl sealed::Sealed for I {} + +trait SealedInstance { + fn ptr() -> &'static pac::adc0::RegisterBlock; +} + + +/// ADC Instance +#[allow(private_bounds)] +pub trait Instance: SealedInstance + PeripheralType + Gate { + /// Interrupt for this ADC instance. + type Interrupt: Interrupt; +} + +macro_rules! impl_instance { + ($($n:expr),*) => { + $( + paste!{ + impl SealedInstance for crate::peripherals::[] { + fn ptr() -> &'static pac::adc0::RegisterBlock { + unsafe { &*pac::[]::ptr() } + } + + } + + impl Instance for crate::peripherals::[] { + type Interrupt = crate::interrupt::typelevel::[]; + } + } + )* + }; +} + +impl_instance!(0, 1); //ADC2 and ADC3 missing in the PAC ?? + +pub trait AdcPin: GpioPin + sealed::Sealed + PeripheralType { + /// Set the given pin to the correct muxing state + fn mux(&self); +} + +macro_rules! impl_pin { + ($pin:ident, $peri:ident, $func:ident, $trait:ident) => { + impl $trait for crate::peripherals::$pin { + fn mux(&self) { + self.set_pull(crate::gpio::Pull::Disabled); + self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); + self.set_drive_strength(crate::gpio::DriveStrength::Normal.into()); + self.set_function(crate::pac::port0::pcr0::Mux::$func); + } + } + }; + } + +impl_pin!(P2_0, ADC0, Mux0, AdcPin); +impl_pin!(P2_4, ADC0, Mux0, AdcPin); +impl_pin!(P2_15, ADC0, Mux0, AdcPin); +impl_pin!(P2_3, ADC0, Mux0, AdcPin); +impl_pin!(P2_2, ADC0, Mux0, AdcPin); +impl_pin!(P2_12, ADC0, Mux0, AdcPin); +impl_pin!(P2_16, ADC0, Mux0, AdcPin); +impl_pin!(P2_7, ADC0, Mux0, AdcPin); +impl_pin!(P0_18, ADC0, Mux0, AdcPin); +impl_pin!(P0_19, ADC0, Mux0, AdcPin); +impl_pin!(P0_20, ADC0, Mux0, AdcPin); +impl_pin!(P0_21, ADC0, Mux0, AdcPin); +impl_pin!(P0_22, ADC0, Mux0, AdcPin); +impl_pin!(P0_23, ADC0, Mux0, AdcPin); +impl_pin!(P0_3, ADC0, Mux0, AdcPin); +impl_pin!(P0_6, ADC0, Mux0, AdcPin); +impl_pin!(P1_0, ADC0, Mux0, AdcPin); +impl_pin!(P1_1, ADC0, Mux0, AdcPin); +impl_pin!(P1_2, ADC0, Mux0, AdcPin); +impl_pin!(P1_3, ADC0, Mux0, AdcPin); +impl_pin!(P1_4, ADC0, Mux0, AdcPin); +impl_pin!(P1_5, ADC0, Mux0, AdcPin); +impl_pin!(P1_6, ADC0, Mux0, AdcPin); +impl_pin!(P1_7, ADC0, Mux0, AdcPin); +impl_pin!(P1_10, ADC0, Mux0, AdcPin); + +impl_pin!(P2_1, ADC1, Mux0, AdcPin); +impl_pin!(P2_5, ADC1, Mux0, AdcPin); +impl_pin!(P2_19, ADC1, Mux0, AdcPin); +impl_pin!(P2_6, ADC1, Mux0, AdcPin); +impl_pin!(P2_3, ADC1, Mux0, AdcPin); +impl_pin!(P2_13, ADC1, Mux0, AdcPin); +impl_pin!(P2_17, ADC1, Mux0, AdcPin); +impl_pin!(P2_7, ADC1, Mux0, AdcPin); +impl_pin!(P1_10, ADC1, Mux0, AdcPin); +impl_pin!(P1_11, ADC1, Mux0, AdcPin); +impl_pin!(P1_12, ADC1, Mux0, AdcPin); +impl_pin!(P1_13, ADC1, Mux0, AdcPin); +impl_pin!(P1_14, ADC1, Mux0, AdcPin); +impl_pin!(P1_15, ADC1, Mux0, AdcPin); +impl_pin!(P1_16, ADC1, Mux0, AdcPin); +impl_pin!(P1_17, ADC1, Mux0, AdcPin); +impl_pin!(P1_18, ADC1, Mux0, AdcPin); +impl_pin!(P1_19, ADC1, Mux0, AdcPin); +impl_pin!(P3_31, ADC1, Mux0, AdcPin); +impl_pin!(P3_30, ADC1, Mux0, AdcPin); +impl_pin!(P3_29, ADC1, Mux0, AdcPin); + +impl_pin!(P2_4, ADC2, Mux0, AdcPin); +impl_pin!(P2_10, ADC2, Mux0, AdcPin); +impl_pin!(P4_4, ADC2, Mux0, AdcPin); +impl_pin!(P2_24, ADC2, Mux0, AdcPin); +impl_pin!(P2_16, ADC2, Mux0, AdcPin); +impl_pin!(P2_12, ADC2, Mux0, AdcPin); +impl_pin!(P2_20, ADC2, Mux0, AdcPin); +impl_pin!(P2_7, ADC2, Mux0, AdcPin); +impl_pin!(P0_2, ADC2, Mux0, AdcPin); +impl_pin!(P0_4, ADC2, Mux0, AdcPin); +impl_pin!(P0_5, ADC2, Mux0, AdcPin); +impl_pin!(P0_6, ADC2, Mux0, AdcPin); +impl_pin!(P0_7, ADC2, Mux0, AdcPin); +impl_pin!(P0_12, ADC2, Mux0, AdcPin); +impl_pin!(P0_13, ADC2, Mux0, AdcPin); +impl_pin!(P0_14, ADC2, Mux0, AdcPin); +impl_pin!(P0_15, ADC2, Mux0, AdcPin); +impl_pin!(P4_0, ADC2, Mux0, AdcPin); +impl_pin!(P4_1, ADC2, Mux0, AdcPin); +impl_pin!(P4_2, ADC2, Mux0, AdcPin); +impl_pin!(P4_3, ADC2, Mux0, AdcPin); +//impl_pin!(P4_4, ADC2, Mux0, AdcPin); // Conflit with ADC2_A3 and ADC2_A20 using the same pin +impl_pin!(P4_5, ADC2, Mux0, AdcPin); +impl_pin!(P4_6, ADC2, Mux0, AdcPin); +impl_pin!(P4_7, ADC2, Mux0, AdcPin); + +impl_pin!(P2_5, ADC3, Mux0, AdcPin); +impl_pin!(P2_11, ADC3, Mux0, AdcPin); +impl_pin!(P2_23, ADC3, Mux0, AdcPin); +impl_pin!(P2_25, ADC3, Mux0, AdcPin); +impl_pin!(P2_17, ADC3, Mux0, AdcPin); +impl_pin!(P2_13, ADC3, Mux0, AdcPin); +impl_pin!(P2_21, ADC3, Mux0, AdcPin); +impl_pin!(P2_7, ADC3, Mux0, AdcPin); +impl_pin!(P3_2, ADC3, Mux0, AdcPin); +impl_pin!(P3_3, ADC3, Mux0, AdcPin); +impl_pin!(P3_4, ADC3, Mux0, AdcPin); +impl_pin!(P3_5, ADC3, Mux0, AdcPin); +impl_pin!(P3_6, ADC3, Mux0, AdcPin); +impl_pin!(P3_7, ADC3, Mux0, AdcPin); +impl_pin!(P3_12, ADC3, Mux0, AdcPin); +impl_pin!(P3_13, ADC3, Mux0, AdcPin); +impl_pin!(P3_14, ADC3, Mux0, AdcPin); +impl_pin!(P3_15, ADC3, Mux0, AdcPin); +impl_pin!(P3_20, ADC3, Mux0, AdcPin); +impl_pin!(P3_21, ADC3, Mux0, AdcPin); +impl_pin!(P3_22, ADC3, Mux0, AdcPin); +impl_pin!(P3_23, ADC3, Mux0, AdcPin); +impl_pin!(P3_24, ADC3, Mux0, AdcPin); +impl_pin!(P3_25, ADC3, Mux0, AdcPin); diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs index 014a12519..667d79536 100644 --- a/embassy-mcxa/src/clocks/mod.rs +++ b/embassy-mcxa/src/clocks/mod.rs @@ -945,7 +945,10 @@ pub(crate) mod gate { impl_cc_gate!(LPUART3, mrcc_glb_cc0, mrcc_glb_rst0, lpuart3, LpuartConfig); impl_cc_gate!(LPUART4, mrcc_glb_cc0, mrcc_glb_rst0, lpuart4, LpuartConfig); impl_cc_gate!(LPUART5, mrcc_glb_cc1, mrcc_glb_rst1, lpuart5, LpuartConfig); + impl_cc_gate!(ADC0, mrcc_glb_cc1, mrcc_glb_rst1, adc0, AdcConfig); impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); + impl_cc_gate!(ADC2, mrcc_glb_cc1, mrcc_glb_rst1, adc2, AdcConfig); + impl_cc_gate!(ADC3, mrcc_glb_cc1, mrcc_glb_rst1, adc3, AdcConfig); // DMA0 peripheral - uses NoConfig since it has no selectable clock source impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig); diff --git a/embassy-mcxa/src/clocks/periph_helpers.rs b/embassy-mcxa/src/clocks/periph_helpers.rs index fed5e558e..f2f51c60c 100644 --- a/embassy-mcxa/src/clocks/periph_helpers.rs +++ b/embassy-mcxa/src/clocks/periph_helpers.rs @@ -427,6 +427,7 @@ impl SPConfHelper for OsTimerConfig { /// Selectable clocks for the ADC peripheral #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AdcClockSel { /// Divided `fro_lf`/`clk_12m`/FRO12M source FroLfDiv, diff --git a/embassy-mcxa/src/interrupt.rs b/embassy-mcxa/src/interrupt.rs index c960af7a2..7eabc6495 100644 --- a/embassy-mcxa/src/interrupt.rs +++ b/embassy-mcxa/src/interrupt.rs @@ -9,7 +9,10 @@ mod generated { #[rustfmt::skip] embassy_hal_internal::interrupt_mod!( + ADC0, ADC1, + ADC2, + ADC3, DMA_CH0, DMA_CH1, DMA_CH2, @@ -279,11 +282,48 @@ impl InterruptExt for Rtc { cortex_m::peripheral::NVIC::is_pending(Interrupt::RTC) } } +pub struct Adc0; +pub const ADC0: Adc0 = Adc0; -pub struct Adc; -pub const ADC1: Adc = Adc; +impl InterruptExt for Adc0 { + /// Clear any pending ADC0 in NVIC. + #[inline] + fn unpend(&self) { + cortex_m::peripheral::NVIC::unpend(Interrupt::ADC0); + } + + /// Set NVIC priority for ADC0. + #[inline] + fn set_priority(&self, priority: Priority) { + unsafe { + let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; + nvic.set_priority(Interrupt::ADC0, u8::from(priority)); + } + } -impl InterruptExt for Adc { + /// Enable ADC0 in NVIC. + #[inline] + unsafe fn enable(&self) { + cortex_m::peripheral::NVIC::unmask(Interrupt::ADC0); + } + + /// Disable ADC0 in NVIC. + #[inline] + unsafe fn disable(&self) { + cortex_m::peripheral::NVIC::mask(Interrupt::ADC0); + } + + /// Check if ADC0 is pending in NVIC. + #[inline] + fn is_pending(&self) -> bool { + cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC0) + } +} + +pub struct Adc1; +pub const ADC1: Adc1 = Adc1; + +impl InterruptExt for Adc1 { /// Clear any pending ADC1 in NVIC. #[inline] fn unpend(&self) { @@ -318,6 +358,82 @@ impl InterruptExt for Adc { } } +pub struct Adc2; +pub const ADC2: Adc2 = Adc2; + +impl InterruptExt for Adc2 { + /// Clear any pending ADC2 in NVIC. + #[inline] + fn unpend(&self) { + cortex_m::peripheral::NVIC::unpend(Interrupt::ADC2); + } + + /// Set NVIC priority for ADC2. + #[inline] + fn set_priority(&self, priority: Priority) { + unsafe { + let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; + nvic.set_priority(Interrupt::ADC2, u8::from(priority)); + } + } + + /// Enable ADC2 in NVIC. + #[inline] + unsafe fn enable(&self) { + cortex_m::peripheral::NVIC::unmask(Interrupt::ADC2); + } + + /// Disable ADC2 in NVIC. + #[inline] + unsafe fn disable(&self) { + cortex_m::peripheral::NVIC::mask(Interrupt::ADC2); + } + + /// Check if ADC2 is pending in NVIC. + #[inline] + fn is_pending(&self) -> bool { + cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC2) + } +} + +pub struct Adc3; +pub const ADC3: Adc3 = Adc3; + +impl InterruptExt for Adc3 { + /// Clear any pending ADC3 in NVIC. + #[inline] + fn unpend(&self) { + cortex_m::peripheral::NVIC::unpend(Interrupt::ADC3); + } + + /// Set NVIC priority for ADC3. + #[inline] + fn set_priority(&self, priority: Priority) { + unsafe { + let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; + nvic.set_priority(Interrupt::ADC3, u8::from(priority)); + } + } + + /// Enable ADC3 in NVIC. + #[inline] + unsafe fn enable(&self) { + cortex_m::peripheral::NVIC::unmask(Interrupt::ADC3); + } + + /// Disable ADC3 in NVIC. + #[inline] + unsafe fn disable(&self) { + cortex_m::peripheral::NVIC::mask(Interrupt::ADC3); + } + + /// Check if ADC3 is pending in NVIC. + #[inline] + fn is_pending(&self) -> bool { + cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC3) + } +} + pub struct Gpio0; pub const GPIO0: Gpio0 = Gpio0; diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs index 1bbdffa06..10b6167b6 100644 --- a/embassy-mcxa/src/lib.rs +++ b/embassy-mcxa/src/lib.rs @@ -8,7 +8,6 @@ pub mod clocks; // still provide clock helpers pub mod dma; pub mod gpio; -pub mod pins; // pin mux helpers pub mod adc; pub mod clkout; @@ -26,6 +25,8 @@ pub use crate::pac::NVIC_PRIO_BITS; embassy_hal_internal::peripherals!( ADC0, ADC1, + ADC2, + ADC3, AOI0, AOI1, @@ -336,7 +337,6 @@ embassy_hal_internal::peripherals!( // Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. // Re-export interrupt traits and types -pub use adc::Adc1 as Adc1Token; pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output}; pub use interrupt::InterruptExt; #[cfg(feature = "unstable-pac")] @@ -354,8 +354,14 @@ pub fn init(cfg: crate::config::Config) -> Peripherals { // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps + crate::interrupt::ADC0.set_priority(cfg.adc_interrupt_priority); + // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps + crate::interrupt::ADC2.set_priority(cfg.adc_interrupt_priority); + // Apply user-configured priority early; enabling is left to examples/apps + crate::interrupt::ADC3.set_priority(cfg.adc_interrupt_priority); + // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); diff --git a/embassy-mcxa/src/pins.rs b/embassy-mcxa/src/pins.rs deleted file mode 100644 index 9adbe64c8..000000000 --- a/embassy-mcxa/src/pins.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Pin configuration helpers (separate from peripheral drivers). -use crate::pac; - -/// Configure pins for ADC usage. -/// -/// # Safety -/// -/// Must be called after PORT clocks are enabled. -pub unsafe fn configure_adc_pins() { - // P1_10 = ADC1_A8 - let port1 = &*pac::Port1::ptr(); - port1.pcr10().write(|w| { - w.ps() - .ps0() - .pe() - .pe0() - .sre() - .sre0() - .ode() - .ode0() - .dse() - .dse0() - .mux() - .mux0() - .ibe() - .ibe0() - .inv() - .inv0() - .lk() - .lk0() - }); - core::arch::asm!("dsb sy; isb sy"); -} 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 f20e4225ddd03f89dc48835355eeff5c2143038a Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 10:01:20 -0800 Subject: Run cargo fmt Signed-off-by: Mathis Deroo --- embassy-mcxa/src/adc.rs | 58 ++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 2e2fb0342..1e3a6952a 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -3,11 +3,11 @@ use core::marker::PhantomData; use embassy_hal_internal::{Peri, PeripheralType}; -use paste::paste; -use crate::pac; -use crate::interrupt::typelevel::{Handler, Interrupt}; use crate::gpio::{GpioPin, SealedPin}; +use crate::interrupt::typelevel::{Handler, Interrupt}; +use crate::pac; use maitake_sync::WaitCell; +use paste::paste; use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; use crate::clocks::{Gate, PoweredClock, enable_and_reset}; @@ -42,8 +42,8 @@ pub enum TriggerPriorityPolicy { /// Configuration for the LPADC peripheral. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct LpadcConfig { - /// Control system transition to Stop and Wait power modes while ADC is converting. - /// When enabled in Doze mode, immediate entries to Wait or Stop are allowed. + /// Control system transition to Stop and Wait power modes while ADC is converting. + /// When enabled in Doze mode, immediate entries to Wait or Stop are allowed. /// When disabled, the ADC will wait for the current averaging iteration/FIFO storage to complete before acknowledging stop or wait mode entry. pub enable_in_doze_mode: bool, /// Auto-Calibration Averages. @@ -58,14 +58,14 @@ pub struct LpadcConfig { pub power_level_mode: Pwrsel, /// Trigger priority policy for handling multiple triggers pub trigger_priority_policy: TriggerPriorityPolicy, - /// Enables the ADC pausing function. When enabled, a programmable delay is inserted during command execution sequencing between LOOP iterations, + /// Enables the ADC pausing function. When enabled, a programmable delay is inserted during command execution sequencing between LOOP iterations, /// between commands in a sequence, and between conversions when command is executing in "Compare Until True" configuration. pub enable_conv_pause: bool, - /// Controls the duration of pausing during command execution sequencing. The pause delay is a count of (convPauseDelay*4) ADCK cycles. + /// Controls the duration of pausing during command execution sequencing. The pause delay is a count of (convPauseDelay*4) ADCK cycles. /// Only available when ADC pausing function is enabled. The available value range is in 9-bit. pub conv_pause_delay: u16, - /// FIFO watermark level for interrupt generation. - /// When the number of datawords stored in the ADC Result FIFO is greater than the value in this field, + /// FIFO watermark level for interrupt generation. + /// When the number of datawords stored in the ADC Result FIFO is greater than the value in this field, /// the ready flag would be asserted to indicate stored data has reached the programmable threshold. pub fifo_watermark: u8, /// Power configuration (normal/deep sleep behavior) @@ -115,7 +115,6 @@ pub struct ConvCommandConfig { pub enable_wait_trigger: bool, } - /// Configuration for a conversion trigger. /// /// Defines how a trigger initiates ADC conversions. @@ -166,7 +165,7 @@ impl<'a, I: Instance> Adc<'a, I> { I::Interrupt::unpend(); unsafe { I::Interrupt::enable() }; - + adc } @@ -176,20 +175,12 @@ impl<'a, I: Instance> Adc<'a, I> { /// * `_inst` - ADC peripheral instance /// * `pin` - GPIO pin to use for ADC input /// * `config` - ADC configuration - pub fn new_polling( - _inst: Peri<'a, I>, - pin: Peri<'a, impl AdcPin>, - config: LpadcConfig, - ) -> Self { + pub fn new_polling(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, config: LpadcConfig) -> Self { Self::new_inner(_inst, pin, config) } /// Internal initialization function shared by `new` and `new_polling`. - fn new_inner( - _inst: Peri<'a, I>, - pin: Peri<'a, impl AdcPin>, - config: LpadcConfig, - ) -> Self { + fn new_inner(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, config: LpadcConfig) -> Self { let adc = &*I::ptr(); let _clock_freq = unsafe { @@ -284,9 +275,7 @@ impl<'a, I: Instance> Adc<'a, I> { // Enable ADC adc.ctrl().modify(|_, w| w.adcen().enabled()); - Self { - _inst: PhantomData, - } + Self { _inst: PhantomData } } /// Deinitialize the ADC peripheral. @@ -565,7 +554,6 @@ trait SealedInstance { fn ptr() -> &'static pac::adc0::RegisterBlock; } - /// ADC Instance #[allow(private_bounds)] pub trait Instance: SealedInstance + PeripheralType + Gate { @@ -600,17 +588,17 @@ pub trait AdcPin: GpioPin + sealed::Sealed + PeripheralType { } macro_rules! impl_pin { - ($pin:ident, $peri:ident, $func:ident, $trait:ident) => { - impl $trait for crate::peripherals::$pin { - fn mux(&self) { - self.set_pull(crate::gpio::Pull::Disabled); - self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); - self.set_drive_strength(crate::gpio::DriveStrength::Normal.into()); - self.set_function(crate::pac::port0::pcr0::Mux::$func); - } + ($pin:ident, $peri:ident, $func:ident, $trait:ident) => { + impl $trait for crate::peripherals::$pin { + fn mux(&self) { + self.set_pull(crate::gpio::Pull::Disabled); + self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); + self.set_drive_strength(crate::gpio::DriveStrength::Normal.into()); + self.set_function(crate::pac::port0::pcr0::Mux::$func); } - }; - } + } + }; +} impl_pin!(P2_0, ADC0, Mux0, AdcPin); impl_pin!(P2_4, ADC0, Mux0, AdcPin); -- 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 --- embassy-mcxa/src/adc.rs | 94 ++++++++++++++++++---------------- examples/mcxa/src/bin/adc_interrupt.rs | 4 +- examples/mcxa/src/bin/adc_polling.rs | 4 +- 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 1e3a6952a..c2ea06e89 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -101,17 +101,17 @@ impl Default for LpadcConfig { /// Defines the parameters for a single ADC conversion operation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConvCommandConfig { - pub sample_channel_mode: Ctype, - pub channel_number: Adch, - pub chained_next_command_number: Next, + pub sample_channel_mode: u8, + pub channel_number: u8, + pub chained_next_command_number: u8, pub enable_auto_channel_increment: bool, pub loop_count: u8, - pub hardware_average_mode: Avgs, - pub sample_time_mode: Sts, - pub hardware_compare_mode: Cmpen, + pub hardware_average_mode: u8, + pub sample_time_mode: u8, + pub hardware_compare_mode: u8, pub hardware_compare_value_high: u32, pub hardware_compare_value_low: u32, - pub conversion_resolution_mode: Mode, + pub conversion_resolution_mode: u8, pub enable_wait_trigger: bool, } @@ -361,17 +361,17 @@ impl<'a, I: Instance> Adc<'a, I> { /// Default conversion command configuration pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { ConvCommandConfig { - sample_channel_mode: Ctype::SingleEndedASideChannel, - channel_number: Adch::SelectCh0, - chained_next_command_number: Next::NoNextCmdTerminateOnFinish, + sample_channel_mode: Ctype::SingleEndedASideChannel as u8, + channel_number: Adch::SelectCh0 as u8, + chained_next_command_number: Next::NoNextCmdTerminateOnFinish as u8, enable_auto_channel_increment: false, loop_count: 0, - hardware_average_mode: Avgs::NoAverage, - sample_time_mode: Sts::Sample3p5, - hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, + hardware_average_mode: Avgs::NoAverage as u8, + sample_time_mode: Sts::Sample3p5 as u8, + hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult as u8, hardware_compare_value_high: 0, hardware_compare_value_low: 0, - conversion_resolution_mode: Mode::Data12Bits, + conversion_resolution_mode: Mode::Data12Bits as u8, enable_wait_trigger: false, } } @@ -382,40 +382,48 @@ impl<'a, I: Instance> Adc<'a, I> { /// Commands define how conversions are performed (channel, resolution, etc.). /// /// # Arguments - /// * `index` - Command index (currently only 1 is supported) + /// * `index` - Command index /// * `config` - Command configuration - ///TBD Need to add cmdlx and cmdhx with x {2..7} pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { let adc = &*I::ptr(); + macro_rules! write_cmd { + ($idx:expr) => {{ + paste! { + adc.[]().write(|w| unsafe { + w.adch() + .bits(config.channel_number) + .mode() + .bit(config.conversion_resolution_mode != 0) + }); + adc.[]().write(|w| unsafe { + w.next() + .bits(config.chained_next_command_number) + .loop_() + .bits(config.loop_count) + .avgs() + .bits(config.hardware_average_mode) + .sts() + .bits(config.sample_time_mode) + .cmpen() + .bits(config.hardware_compare_mode) + .wait_trig() + .bit(config.enable_wait_trigger) + .lwi() + .bit(config.enable_auto_channel_increment) + }); + } + }}; + } + match index { - 1 => { - adc.cmdl1().write(|w| { - w.adch() - .variant(config.channel_number) - .mode() - .variant(config.conversion_resolution_mode) - }); - adc.cmdh1().write(|w| unsafe { - w.next() - .variant(config.chained_next_command_number) - .loop_() - .bits(config.loop_count) - .avgs() - .variant(config.hardware_average_mode) - .sts() - .variant(config.sample_time_mode) - .cmpen() - .variant(config.hardware_compare_mode); - if config.enable_wait_trigger { - w.wait_trig().enabled(); - } - if config.enable_auto_channel_increment { - w.lwi().enabled(); - } - w - }); - } + 1 => write_cmd!(1), + 2 => write_cmd!(2), + 3 => write_cmd!(3), + 4 => write_cmd!(4), + 5 => write_cmd!(5), + 6 => write_cmd!(6), + 7 => write_cmd!(7), _ => panic!("Invalid command index: must be between 1 and 7"), } } 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 0da28a271816b319c142254cb3598fd14096813a Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 13:29:16 -0800 Subject: Remove duplication of interrupt trait and use embassy_hal_internal Signed-off-by: Mathis Deroo --- embassy-mcxa/src/interrupt.rs | 151 ------------------------------------------ embassy-mcxa/src/lib.rs | 8 --- 2 files changed, 159 deletions(-) diff --git a/embassy-mcxa/src/interrupt.rs b/embassy-mcxa/src/interrupt.rs index 7eabc6495..725f8d499 100644 --- a/embassy-mcxa/src/interrupt.rs +++ b/embassy-mcxa/src/interrupt.rs @@ -282,157 +282,6 @@ impl InterruptExt for Rtc { cortex_m::peripheral::NVIC::is_pending(Interrupt::RTC) } } -pub struct Adc0; -pub const ADC0: Adc0 = Adc0; - -impl InterruptExt for Adc0 { - /// Clear any pending ADC0 in NVIC. - #[inline] - fn unpend(&self) { - cortex_m::peripheral::NVIC::unpend(Interrupt::ADC0); - } - - /// Set NVIC priority for ADC0. - #[inline] - fn set_priority(&self, priority: Priority) { - unsafe { - let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; - nvic.set_priority(Interrupt::ADC0, u8::from(priority)); - } - } - - /// Enable ADC0 in NVIC. - #[inline] - unsafe fn enable(&self) { - cortex_m::peripheral::NVIC::unmask(Interrupt::ADC0); - } - - /// Disable ADC0 in NVIC. - #[inline] - unsafe fn disable(&self) { - cortex_m::peripheral::NVIC::mask(Interrupt::ADC0); - } - - /// Check if ADC0 is pending in NVIC. - #[inline] - fn is_pending(&self) -> bool { - cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC0) - } -} - -pub struct Adc1; -pub const ADC1: Adc1 = Adc1; - -impl InterruptExt for Adc1 { - /// Clear any pending ADC1 in NVIC. - #[inline] - fn unpend(&self) { - cortex_m::peripheral::NVIC::unpend(Interrupt::ADC1); - } - - /// Set NVIC priority for ADC1. - #[inline] - fn set_priority(&self, priority: Priority) { - unsafe { - let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; - nvic.set_priority(Interrupt::ADC1, u8::from(priority)); - } - } - - /// Enable ADC1 in NVIC. - #[inline] - unsafe fn enable(&self) { - cortex_m::peripheral::NVIC::unmask(Interrupt::ADC1); - } - - /// Disable ADC1 in NVIC. - #[inline] - unsafe fn disable(&self) { - cortex_m::peripheral::NVIC::mask(Interrupt::ADC1); - } - - /// Check if ADC1 is pending in NVIC. - #[inline] - fn is_pending(&self) -> bool { - cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC1) - } -} - -pub struct Adc2; -pub const ADC2: Adc2 = Adc2; - -impl InterruptExt for Adc2 { - /// Clear any pending ADC2 in NVIC. - #[inline] - fn unpend(&self) { - cortex_m::peripheral::NVIC::unpend(Interrupt::ADC2); - } - - /// Set NVIC priority for ADC2. - #[inline] - fn set_priority(&self, priority: Priority) { - unsafe { - let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; - nvic.set_priority(Interrupt::ADC2, u8::from(priority)); - } - } - - /// Enable ADC2 in NVIC. - #[inline] - unsafe fn enable(&self) { - cortex_m::peripheral::NVIC::unmask(Interrupt::ADC2); - } - - /// Disable ADC2 in NVIC. - #[inline] - unsafe fn disable(&self) { - cortex_m::peripheral::NVIC::mask(Interrupt::ADC2); - } - - /// Check if ADC2 is pending in NVIC. - #[inline] - fn is_pending(&self) -> bool { - cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC2) - } -} - -pub struct Adc3; -pub const ADC3: Adc3 = Adc3; - -impl InterruptExt for Adc3 { - /// Clear any pending ADC3 in NVIC. - #[inline] - fn unpend(&self) { - cortex_m::peripheral::NVIC::unpend(Interrupt::ADC3); - } - - /// Set NVIC priority for ADC3. - #[inline] - fn set_priority(&self, priority: Priority) { - unsafe { - let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; - nvic.set_priority(Interrupt::ADC3, u8::from(priority)); - } - } - - /// Enable ADC3 in NVIC. - #[inline] - unsafe fn enable(&self) { - cortex_m::peripheral::NVIC::unmask(Interrupt::ADC3); - } - - /// Disable ADC3 in NVIC. - #[inline] - unsafe fn disable(&self) { - cortex_m::peripheral::NVIC::mask(Interrupt::ADC3); - } - - /// Check if ADC3 is pending in NVIC. - #[inline] - fn is_pending(&self) -> bool { - cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC3) - } -} pub struct Gpio0; pub const GPIO0: Gpio0 = Gpio0; diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs index 10b6167b6..be279e509 100644 --- a/embassy-mcxa/src/lib.rs +++ b/embassy-mcxa/src/lib.rs @@ -354,14 +354,6 @@ pub fn init(cfg: crate::config::Config) -> Peripherals { // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps - crate::interrupt::ADC0.set_priority(cfg.adc_interrupt_priority); - // Apply user-configured priority early; enabling is left to examples/apps - crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority); - // Apply user-configured priority early; enabling is left to examples/apps - crate::interrupt::ADC2.set_priority(cfg.adc_interrupt_priority); - // Apply user-configured priority early; enabling is left to examples/apps - crate::interrupt::ADC3.set_priority(cfg.adc_interrupt_priority); - // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); -- cgit From e39040afc7ee4080a1d3559d0b7d578420301726 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 13:40:59 -0800 Subject: Implement WaitCell per ADC instance Signed-off-by: Mathis Deroo --- embassy-mcxa/src/adc.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index c2ea06e89..94d945c88 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -18,8 +18,6 @@ use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; use crate::pac::adc1::ctrl::CalAvgs; use crate::pac::adc1::tctrl::{Tcmd, Tpri}; -/// Global wait cell for alarm notifications -static WAKER: WaitCell = WaitCell::new(); const G_LPADC_RESULT_SHIFT: u32 = 0; @@ -532,7 +530,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// # Returns /// 16-bit ADC conversion value pub async fn read(&mut self) -> u16 { - let wait = WAKER.subscribe().await; + let wait = I::wait_cell().subscribe().await; self.enable_interrupt(0x1); self.do_software_trigger(1); @@ -547,7 +545,7 @@ impl<'a, I: Instance> Adc<'a, I> { impl Handler for InterruptHandler { unsafe fn on_interrupt() { T::ptr().ie().modify(|r, w| w.bits(r.bits() & !0x1)); - WAKER.wake(); + T::wait_cell().wake(); } } @@ -560,6 +558,7 @@ impl sealed::Sealed for I {} trait SealedInstance { fn ptr() -> &'static pac::adc0::RegisterBlock; + fn wait_cell() -> &'static WaitCell; } /// ADC Instance @@ -578,6 +577,11 @@ macro_rules! impl_instance { unsafe { &*pac::[]::ptr() } } + fn wait_cell() -> &'static WaitCell { + static WAIT_CELL: WaitCell = WaitCell::new(); + &WAIT_CELL + } + } impl Instance for crate::peripherals::[] { -- 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 --- embassy-mcxa/src/adc.rs | 38 ++++++++++++++++------------------ examples/mcxa/src/bin/adc_interrupt.rs | 4 ++-- examples/mcxa/src/bin/adc_polling.rs | 4 ++-- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 94d945c88..8852fd737 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -99,17 +99,16 @@ impl Default for LpadcConfig { /// Defines the parameters for a single ADC conversion operation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConvCommandConfig { - pub sample_channel_mode: u8, - pub channel_number: u8, - pub chained_next_command_number: u8, + pub channel_number: Adch, + pub chained_next_command_number: Next, pub enable_auto_channel_increment: bool, pub loop_count: u8, - pub hardware_average_mode: u8, - pub sample_time_mode: u8, - pub hardware_compare_mode: u8, + pub hardware_average_mode: Avgs, + pub sample_time_mode: Sts, + pub hardware_compare_mode: Cmpen, pub hardware_compare_value_high: u32, pub hardware_compare_value_low: u32, - pub conversion_resolution_mode: u8, + pub conversion_resolution_mode: Mode, pub enable_wait_trigger: bool, } @@ -359,17 +358,16 @@ impl<'a, I: Instance> Adc<'a, I> { /// Default conversion command configuration pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { ConvCommandConfig { - sample_channel_mode: Ctype::SingleEndedASideChannel as u8, - channel_number: Adch::SelectCh0 as u8, - chained_next_command_number: Next::NoNextCmdTerminateOnFinish as u8, + channel_number: Adch::SelectCh0, + chained_next_command_number: Next::NoNextCmdTerminateOnFinish, enable_auto_channel_increment: false, loop_count: 0, - hardware_average_mode: Avgs::NoAverage as u8, - sample_time_mode: Sts::Sample3p5 as u8, - hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult as u8, + hardware_average_mode: Avgs::NoAverage, + sample_time_mode: Sts::Sample3p5, + hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, hardware_compare_value_high: 0, hardware_compare_value_low: 0, - conversion_resolution_mode: Mode::Data12Bits as u8, + conversion_resolution_mode: Mode::Data12Bits, enable_wait_trigger: false, } } @@ -390,21 +388,21 @@ impl<'a, I: Instance> Adc<'a, I> { paste! { adc.[]().write(|w| unsafe { w.adch() - .bits(config.channel_number) + .bits(config.channel_number.into()) .mode() - .bit(config.conversion_resolution_mode != 0) + .bit(config.conversion_resolution_mode.into()) }); adc.[]().write(|w| unsafe { w.next() - .bits(config.chained_next_command_number) + .bits(config.chained_next_command_number.into()) .loop_() .bits(config.loop_count) .avgs() - .bits(config.hardware_average_mode) + .bits(config.hardware_average_mode.into()) .sts() - .bits(config.sample_time_mode) + .bits(config.sample_time_mode.into()) .cmpen() - .bits(config.hardware_compare_mode) + .bits(config.hardware_compare_mode.into()) .wait_trig() .bit(config.enable_wait_trigger) .lwi() 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 --- embassy-mcxa/src/adc.rs | 24 +++++++++++++++++------- examples/mcxa/src/bin/adc_interrupt.rs | 10 ++++++++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 8852fd737..81b0b02f8 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -123,6 +123,16 @@ pub struct ConvTriggerConfig { pub enable_hardware_trigger: bool, } +/// ADC Error types +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum AdcError { + /// FIFO is empty, no conversion result available + FifoEmpty, + /// Invalid configuration + InvalidConfig, +} + /// Result of an ADC conversion. /// /// Contains the conversion value and metadata about the conversion. @@ -498,16 +508,16 @@ impl<'a, I: Instance> Adc<'a, I> { /// /// # Returns /// - `Some(ConvResult)` if a result is available - /// - `None` if the FIFO is empty - pub fn get_conv_result(&self) -> Option { + /// - `Err(AdcError::FifoEmpty)` if the FIFO is empty + pub fn get_conv_result(&self) -> Result { let adc = &*I::ptr(); let fifo = adc.resfifo0().read().bits(); const VALID_MASK: u32 = 1 << 31; if fifo & VALID_MASK == 0 { - return None; + return Err(AdcError::FifoEmpty); } - Some(ConvResult { + Ok(ConvResult { command_id_source: (fifo >> 24) & 0x0F, loop_count_index: (fifo >> 20) & 0x0F, trigger_id_source: (fifo >> 16) & 0x0F, @@ -527,7 +537,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// /// # Returns /// 16-bit ADC conversion value - pub async fn read(&mut self) -> u16 { + pub async fn read(&mut self) -> Result { let wait = I::wait_cell().subscribe().await; self.enable_interrupt(0x1); @@ -535,8 +545,8 @@ impl<'a, I: Instance> Adc<'a, I> { let _ = wait.await; - let result = self.get_conv_result(); - result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT + let result = self.get_conv_result().unwrap().conv_value >> G_LPADC_RESULT_SHIFT; + Ok(result) } } 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 e75e8dddb63f758419ef5d8d7c321c631f5b0a59 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 14:12:49 -0800 Subject: Remove dereference for Instance ptr Signed-off-by: Mathis Deroo --- embassy-mcxa/src/adc.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 81b0b02f8..f7340e8c2 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -188,7 +188,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// Internal initialization function shared by `new` and `new_polling`. fn new_inner(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, config: LpadcConfig) -> Self { - let adc = &*I::ptr(); + let adc = I::ptr(); let _clock_freq = unsafe { enable_and_reset::(&AdcConfig { @@ -287,14 +287,14 @@ impl<'a, I: Instance> Adc<'a, I> { /// Deinitialize the ADC peripheral. pub fn deinit(&self) { - let adc = &*I::ptr(); + let adc = I::ptr(); adc.ctrl().modify(|_, w| w.adcen().disabled()); } /// Perform offset calibration. /// Waits for calibration to complete before returning. pub fn do_offset_calibration(&self) { - let adc = &*I::ptr(); + let adc = I::ptr(); // Enable calibration mode adc.ctrl() .modify(|_, w| w.calofs().offset_calibration_request_pending()); @@ -330,7 +330,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// Perform automatic gain calibration. pub fn do_auto_calibration(&self) { - let adc = &*I::ptr(); + let adc = I::ptr(); adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} @@ -359,7 +359,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// # Arguments /// * `trigger_id_mask` - Bitmask of trigger IDs to activate (bit N = trigger N) pub fn do_software_trigger(&self, trigger_id_mask: u32) { - let adc = &*I::ptr(); + let adc = I::ptr(); adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); } @@ -391,7 +391,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// * `index` - Command index /// * `config` - Command configuration pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { - let adc = &*I::ptr(); + let adc = I::ptr(); macro_rules! write_cmd { ($idx:expr) => {{ @@ -456,7 +456,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// * `trigger_id` - Trigger index (0-15) /// * `config` - Trigger configuration pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { - let adc = &*I::ptr(); + let adc = I::ptr(); let tctrl = &adc.tctrl(trigger_id); tctrl.write(|w| unsafe { @@ -475,7 +475,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// /// Clears all pending conversion results from the FIFO. pub fn do_reset_fifo(&self) { - let adc = &*I::ptr(); + let adc = I::ptr(); adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); } @@ -486,7 +486,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// # Arguments /// * `mask` - Bitmask of interrupt sources to enable pub fn enable_interrupt(&self, mask: u32) { - let adc = &*I::ptr(); + let adc = I::ptr(); adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); } @@ -497,7 +497,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// # Arguments /// * `mask` - Bitmask of interrupt sources to disable pub fn disable_interrupt(&self, mask: u32) { - let adc = &*I::ptr(); + let adc = I::ptr(); adc.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); } @@ -510,7 +510,7 @@ impl<'a, I: Instance> Adc<'a, I> { /// - `Some(ConvResult)` if a result is available /// - `Err(AdcError::FifoEmpty)` if the FIFO is empty pub fn get_conv_result(&self) -> Result { - let adc = &*I::ptr(); + let adc = I::ptr(); let fifo = adc.resfifo0().read().bits(); const VALID_MASK: u32 = 1 << 31; if fifo & VALID_MASK == 0 { -- 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 --- embassy-mcxa/src/adc.rs | 131 +++++++++++++++++++++------------ examples/mcxa/src/bin/adc_interrupt.rs | 2 +- examples/mcxa/src/bin/adc_polling.rs | 20 +++-- 3 files changed, 96 insertions(+), 57 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index f7340e8c2..16b40fa45 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -10,11 +10,11 @@ use maitake_sync::WaitCell; use paste::paste; use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; -use crate::clocks::{Gate, PoweredClock, enable_and_reset}; +use crate::clocks::{Gate, PoweredClock, enable_and_reset, ClockError}; use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; -use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; +use crate::pac::adc1::cmdl1::{Adch, Mode}; use crate::pac::adc1::ctrl::CalAvgs; use crate::pac::adc1::tctrl::{Tcmd, Tpri}; @@ -123,14 +123,19 @@ pub struct ConvTriggerConfig { pub enable_hardware_trigger: bool, } +/// Shorthand for `Result`. +pub type Result = core::result::Result; + /// ADC Error types #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum AdcError { +pub enum Error { /// FIFO is empty, no conversion result available FifoEmpty, /// Invalid configuration InvalidConfig, + /// Clock configuration error. + ClockSetup(ClockError), } /// Result of an ADC conversion. @@ -150,11 +155,28 @@ pub struct InterruptHandler { } /// ADC driver instance. -pub struct Adc<'a, I: Instance> { +pub struct Adc<'a, I: Instance, M: ModeAdc> { _inst: PhantomData<&'a mut I>, + _phantom: PhantomData, } -impl<'a, I: Instance> Adc<'a, I> { +impl<'a, I: Instance> Adc<'a, I, Blocking> { + /// Create a new blocking instance of the ADC driver. + /// # Arguments + /// * `_inst` - ADC peripheral instance + /// * `pin` - GPIO pin to use for ADC + /// * `config` - ADC configuration + pub fn new_blocking( + _inst: Peri<'a, I>, + pin: Peri<'a, + impl AdcPin>, + config: LpadcConfig + ) -> Result { + Self::new_inner(_inst, pin, config) + } +} + +impl<'a, I: Instance> Adc<'a, I, Async> { /// Initialize ADC with interrupt support. /// /// # Arguments @@ -162,12 +184,12 @@ impl<'a, I: Instance> Adc<'a, I> { /// * `pin` - GPIO pin to use for ADC /// * `_irq` - Interrupt binding for this ADC instance /// * `config` - ADC configuration - pub fn new( + pub fn new_async( _inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, _irq: impl crate::interrupt::typelevel::Binding> + 'a, config: LpadcConfig, - ) -> Self { + ) -> Result { let adc = Self::new_inner(_inst, pin, config); I::Interrupt::unpend(); @@ -176,28 +198,48 @@ impl<'a, I: Instance> Adc<'a, I> { adc } - /// Initialize ADC without interrupt support (for polling mode). + /// Read ADC value asynchronously. /// - /// # Arguments - /// * `_inst` - ADC peripheral instance - /// * `pin` - GPIO pin to use for ADC input - /// * `config` - ADC configuration - pub fn new_polling(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, config: LpadcConfig) -> Self { - Self::new_inner(_inst, pin, config) + /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered. + /// + /// The function: + /// 1. Enables the FIFO watermark interrupt + /// 2. Triggers a software conversion on trigger 0 + /// 3. Waits for the conversion to complete + /// 4. Returns the conversion result + /// + /// # Returns + /// 16-bit ADC conversion value + pub async fn read(&mut self) -> Result { + let wait = I::wait_cell().subscribe().await; + + Adc::<'a, I, Async>::enable_interrupt(self, 0x1); + Adc::<'a, I, Async>::do_software_trigger(self, 1); + + let _ = wait.await; + + let result = Adc::<'a, I, Async>::get_conv_result(self).unwrap().conv_value >> G_LPADC_RESULT_SHIFT; + Ok(result) } +} - /// Internal initialization function shared by `new` and `new_polling`. - fn new_inner(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, config: LpadcConfig) -> Self { + + +impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { + /// Internal initialization function shared by `new_async` and `new_blocking`. + fn new_inner( + _inst: Peri<'a, I>, + pin: Peri<'a, impl AdcPin>, + config: LpadcConfig + ) -> Result { let adc = I::ptr(); - let _clock_freq = unsafe { - enable_and_reset::(&AdcConfig { + _ = unsafe { enable_and_reset::(&AdcConfig { power: config.power, source: config.source, div: config.div, }) - .expect("Adc Init should not fail") - }; + .map_err(Error::ClockSetup)? }; pin.mux(); @@ -282,7 +324,10 @@ impl<'a, I: Instance> Adc<'a, I> { // Enable ADC adc.ctrl().modify(|_, w| w.adcen().enabled()); - Self { _inst: PhantomData } + Ok(Self { + _inst: PhantomData, + _phantom: PhantomData, + }) } /// Deinitialize the ADC peripheral. @@ -508,13 +553,13 @@ impl<'a, I: Instance> Adc<'a, I> { /// /// # Returns /// - `Some(ConvResult)` if a result is available - /// - `Err(AdcError::FifoEmpty)` if the FIFO is empty - pub fn get_conv_result(&self) -> Result { + /// - `Err(Error::FifoEmpty)` if the FIFO is empty + pub fn get_conv_result(&self) -> Result { let adc = I::ptr(); let fifo = adc.resfifo0().read().bits(); const VALID_MASK: u32 = 1 << 31; if fifo & VALID_MASK == 0 { - return Err(AdcError::FifoEmpty); + return Err(Error::FifoEmpty); } Ok(ConvResult { @@ -524,30 +569,6 @@ impl<'a, I: Instance> Adc<'a, I> { conv_value: (fifo & 0xFFFF) as u16, }) } - - /// Read ADC value asynchronously. - /// - /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered. - /// - /// The function: - /// 1. Enables the FIFO watermark interrupt - /// 2. Triggers a software conversion on trigger 0 - /// 3. Waits for the conversion to complete - /// 4. Returns the conversion result - /// - /// # Returns - /// 16-bit ADC conversion value - pub async fn read(&mut self) -> Result { - let wait = I::wait_cell().subscribe().await; - - self.enable_interrupt(0x1); - self.do_software_trigger(1); - - let _ = wait.await; - - let result = self.get_conv_result().unwrap().conv_value >> G_LPADC_RESULT_SHIFT; - Ok(result) - } } impl Handler for InterruptHandler { @@ -607,6 +628,20 @@ pub trait AdcPin: GpioPin + sealed::Sealed + PeripheralType { fn mux(&self); } +/// Driver mode. +#[allow(private_bounds)] +pub trait ModeAdc: sealed::Sealed {} + +/// Blocking mode. +pub struct Blocking; +impl sealed::Sealed for Blocking {} +impl ModeAdc for Blocking {} + +/// Async mode. +pub struct Async; +impl sealed::Sealed for Async {} +impl ModeAdc for Async {} + macro_rules! impl_pin { ($pin:ident, $peri:ident, $func:ident, $trait:ident) => { impl $trait for crate::peripherals::$pin { 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 --- embassy-mcxa/src/adc.rs | 14 ++++++++++++-- examples/mcxa/src/bin/adc_interrupt.rs | 2 +- examples/mcxa/src/bin/adc_polling.rs | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 16b40fa45..af7191573 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -435,9 +435,17 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { /// # Arguments /// * `index` - Command index /// * `config` - Command configuration - pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { + /// + /// # Returns + /// * `Ok(())` if the command was configured successfully + /// * `Err(Error::InvalidConfig)` if the index is out of range + pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) -> Result<()> { let adc = I::ptr(); + if index < 1 || index > 7 { + return Err(Error::InvalidConfig); + } + macro_rules! write_cmd { ($idx:expr) => {{ paste! { @@ -475,8 +483,10 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { 5 => write_cmd!(5), 6 => write_cmd!(6), 7 => write_cmd!(7), - _ => panic!("Invalid command index: must be between 1 and 7"), + _ => unreachable!(), } + + Ok(()) } /// Get default conversion trigger configuration. 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 f81eeee3c1bfa1cab534181ff6349a0998fc26ea Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Mon, 8 Dec 2025 15:24:12 -0800 Subject: Use field accessors for FIFO results instead of hardcoded ones Signed-off-by: Mathis Deroo --- embassy-mcxa/src/adc.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index af7191573..900a3a40a 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -143,9 +143,9 @@ pub enum Error { /// Contains the conversion value and metadata about the conversion. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConvResult { - pub command_id_source: u32, - pub loop_count_index: u32, - pub trigger_id_source: u32, + pub command_id_source: u8, + pub loop_count_index: u8, + pub trigger_id_source: u8, pub conv_value: u16, } @@ -566,17 +566,16 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { /// - `Err(Error::FifoEmpty)` if the FIFO is empty pub fn get_conv_result(&self) -> Result { let adc = I::ptr(); - let fifo = adc.resfifo0().read().bits(); - const VALID_MASK: u32 = 1 << 31; - if fifo & VALID_MASK == 0 { + let fifo = adc.resfifo0().read(); + if !fifo.valid().is_valid() { return Err(Error::FifoEmpty); } Ok(ConvResult { - command_id_source: (fifo >> 24) & 0x0F, - loop_count_index: (fifo >> 20) & 0x0F, - trigger_id_source: (fifo >> 16) & 0x0F, - conv_value: (fifo & 0xFFFF) as u16, + command_id_source: fifo.cmdsrc().bits(), + loop_count_index: fifo.loopcnt().bits(), + trigger_id_source: fifo.tsrc().bits(), + conv_value: fifo.d().bits(), }) } } -- cgit From bea34ace6b4d8af29d2deb169ddb3d7c258498ee Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Tue, 9 Dec 2025 09:39:27 -0800 Subject: Add support of ADC2 and ADC3 instances Signed-off-by: Mathis Deroo --- embassy-mcxa/Cargo.toml | 2 +- embassy-mcxa/src/adc.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-mcxa/Cargo.toml b/embassy-mcxa/Cargo.toml index 8ed842aec..d1e40ab0a 100644 --- a/embassy-mcxa/Cargo.toml +++ b/embassy-mcxa/Cargo.toml @@ -39,7 +39,7 @@ embedded-hal-nb = { version = "1.0" } embedded-io = "0.6" embedded-io-async = { version = "0.6.1" } heapless = "0.8" -mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0", rev = "e7dfed8740b449b6ac646bab8ac6776a3c099267" } +mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0", rev = "ecb2af952d94a3bd3db7f9108e2258767eea4f97" } nb = "1.1.0" paste = "1.0.15" maitake-sync = { version = "0.2.2", default-features = false, features = ["critical-section", "no-cache-pad"] } diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 900a3a40a..f4ac133d7 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -630,7 +630,7 @@ macro_rules! impl_instance { }; } -impl_instance!(0, 1); //ADC2 and ADC3 missing in the PAC ?? +impl_instance!(0, 1, 2, 3); pub trait AdcPin: GpioPin + sealed::Sealed + PeripheralType { /// Set the given pin to the correct muxing state -- cgit From 06c16ca54dc846efa4b256620b4658a5b8378f81 Mon Sep 17 00:00:00 2001 From: Mathis Deroo Date: Tue, 9 Dec 2025 10:42:30 -0800 Subject: Fix cmdlX and cmdhX access using updated PAC Signed-off-by: Mathis Deroo --- embassy-mcxa/Cargo.toml | 2 +- embassy-mcxa/src/adc.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/embassy-mcxa/Cargo.toml b/embassy-mcxa/Cargo.toml index d1e40ab0a..cb985a2e9 100644 --- a/embassy-mcxa/Cargo.toml +++ b/embassy-mcxa/Cargo.toml @@ -39,7 +39,7 @@ embedded-hal-nb = { version = "1.0" } embedded-io = "0.6" embedded-io-async = { version = "0.6.1" } heapless = "0.8" -mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0", rev = "ecb2af952d94a3bd3db7f9108e2258767eea4f97" } +mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0", rev = "02bd04a21ef8f8f67f88239ff5df765bb7e60fd8" } nb = "1.1.0" paste = "1.0.15" maitake-sync = { version = "0.2.2", default-features = false, features = ["critical-section", "no-cache-pad"] } diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index f4ac133d7..abcdf86f8 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -449,23 +449,23 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { macro_rules! write_cmd { ($idx:expr) => {{ paste! { - adc.[]().write(|w| unsafe { + adc.[]().write(|w| { w.adch() - .bits(config.channel_number.into()) + .variant(config.channel_number) .mode() - .bit(config.conversion_resolution_mode.into()) + .variant(config.conversion_resolution_mode) }); adc.[]().write(|w| unsafe { w.next() - .bits(config.chained_next_command_number.into()) + .variant(config.chained_next_command_number) .loop_() .bits(config.loop_count) .avgs() - .bits(config.hardware_average_mode.into()) + .variant(config.hardware_average_mode) .sts() - .bits(config.sample_time_mode.into()) + .variant(config.sample_time_mode) .cmpen() - .bits(config.hardware_compare_mode.into()) + .variant(config.hardware_compare_mode) .wait_trig() .bit(config.enable_wait_trigger) .lwi() -- 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 --- embassy-mcxa/src/adc.rs | 30 ++++++++++-------------------- examples/mcxa/src/bin/adc_interrupt.rs | 11 +++++------ examples/mcxa/src/bin/adc_polling.rs | 4 ++-- 3 files changed, 17 insertions(+), 28 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index abcdf86f8..6500754ba 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -10,7 +10,7 @@ use maitake_sync::WaitCell; use paste::paste; use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; -use crate::clocks::{Gate, PoweredClock, enable_and_reset, ClockError}; +use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset}; use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; @@ -18,7 +18,6 @@ use crate::pac::adc1::cmdl1::{Adch, Mode}; use crate::pac::adc1::ctrl::CalAvgs; use crate::pac::adc1::tctrl::{Tcmd, Tpri}; - const G_LPADC_RESULT_SHIFT: u32 = 0; /// Trigger priority policy for ADC conversions. @@ -166,12 +165,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> { /// * `_inst` - ADC peripheral instance /// * `pin` - GPIO pin to use for ADC /// * `config` - ADC configuration - pub fn new_blocking( - _inst: Peri<'a, I>, - pin: Peri<'a, - impl AdcPin>, - config: LpadcConfig - ) -> Result { + pub fn new_blocking(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, config: LpadcConfig) -> Result { Self::new_inner(_inst, pin, config) } } @@ -223,23 +217,19 @@ impl<'a, I: Instance> Adc<'a, I, Async> { } } - - impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { /// Internal initialization function shared by `new_async` and `new_blocking`. - fn new_inner( - _inst: Peri<'a, I>, - pin: Peri<'a, impl AdcPin>, - config: LpadcConfig - ) -> Result { + fn new_inner(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, config: LpadcConfig) -> Result { let adc = I::ptr(); - _ = unsafe { enable_and_reset::(&AdcConfig { + _ = unsafe { + enable_and_reset::(&AdcConfig { power: config.power, source: config.source, div: config.div, }) - .map_err(Error::ClockSetup)? }; + .map_err(Error::ClockSetup)? + }; pin.mux(); @@ -324,9 +314,9 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { // Enable ADC adc.ctrl().modify(|_, w| w.adcen().enabled()); - Ok(Self { + Ok(Self { _inst: PhantomData, - _phantom: PhantomData, + _phantom: PhantomData, }) } @@ -435,7 +425,7 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { /// # Arguments /// * `index` - Command index /// * `config` - Command configuration - /// + /// /// # Returns /// * `Ok(())` if the command was configured successfully /// * `Err(Error::InvalidConfig)` if the index is out of range 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 62966d6fac20a7af7257e0a1a9015e1b7093b5ba Mon Sep 17 00:00:00 2001 From: James Munns Date: Wed, 10 Dec 2025 15:02:57 +0100 Subject: rustfmt --- embassy-mcxa/src/adc.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 6500754ba..d7d17cf5f 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -2,16 +2,14 @@ use core::marker::PhantomData; use embassy_hal_internal::{Peri, PeripheralType}; - -use crate::gpio::{GpioPin, SealedPin}; -use crate::interrupt::typelevel::{Handler, Interrupt}; -use crate::pac; use maitake_sync::WaitCell; use paste::paste; use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset}; - +use crate::gpio::{GpioPin, SealedPin}; +use crate::interrupt::typelevel::{Handler, Interrupt}; +use crate::pac; use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; use crate::pac::adc1::cmdl1::{Adch, Mode}; -- cgit