From efdfb3c0892f45223e8d8527e5f032fef475944e Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Dec 2025 15:34:38 +0100 Subject: Refactor the API --- embassy-mcxa/src/adc.rs | 642 +++++++++++++++++++-------------- examples/mcxa/src/bin/adc_interrupt.rs | 20 +- examples/mcxa/src/bin/adc_polling.rs | 26 +- 3 files changed, 387 insertions(+), 301 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index d7d17cf5f..e4b24cffa 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -1,4 +1,5 @@ //! ADC driver +use core::future::Future; use core::marker::PhantomData; use embassy_hal_internal::{Peri, PeripheralType}; @@ -12,12 +13,10 @@ 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}; +use crate::pac::adc1::cmdl1::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. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u8)] @@ -59,10 +58,6 @@ pub struct LpadcConfig { /// 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 @@ -83,7 +78,6 @@ impl Default for LpadcConfig { 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(), @@ -96,7 +90,6 @@ impl Default for LpadcConfig { /// Defines the parameters for a single ADC conversion operation. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct ConvCommandConfig { - pub channel_number: Adch, pub chained_next_command_number: Next, pub enable_auto_channel_increment: bool, pub loop_count: u8, @@ -109,6 +102,23 @@ pub struct ConvCommandConfig { pub enable_wait_trigger: bool, } +impl Default for ConvCommandConfig { + fn default() -> Self { + ConvCommandConfig { + chained_next_command_number: Next::NoNextCmdTerminateOnFinish, + enable_auto_channel_increment: false, + loop_count: 0, + 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, + enable_wait_trigger: false, + } + } +} + /// Configuration for a conversion trigger. /// /// Defines how a trigger initiates ADC conversions. @@ -120,6 +130,17 @@ pub struct ConvTriggerConfig { pub enable_hardware_trigger: bool, } +impl Default for ConvTriggerConfig { + fn default() -> Self { + ConvTriggerConfig { + target_command_id: Tcmd::NotValid, + delay_power: 0, + priority: Tpri::HighestPriority, + enable_hardware_trigger: false, + } + } +} + /// Shorthand for `Result`. pub type Result = core::result::Result; @@ -155,6 +176,7 @@ pub struct InterruptHandler { pub struct Adc<'a, I: Instance, M: ModeAdc> { _inst: PhantomData<&'a mut I>, _phantom: PhantomData, + index: u8, } impl<'a, I: Instance> Adc<'a, I, Blocking> { @@ -166,6 +188,104 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> { pub fn new_blocking(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, config: LpadcConfig) -> Result { Self::new_inner(_inst, pin, config) } + + /// Enable ADC interrupts. + /// + /// Enables the interrupt sources specified in the bitmask. + /// + /// # Arguments + /// * `mask` - Bitmask of interrupt sources to enable + pub fn enable_interrupt(&mut self, mask: u32) { + let adc = I::ptr(); + adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); + } + + /// Disable ADC interrupts. + /// + /// Disables the interrupt sources specified in the bitmask. + /// + /// # Arguments + /// * `mask` - Bitmask of interrupt sources to disable + pub fn disable_interrupt(&mut self, mask: u32) { + let adc = I::ptr(); + adc.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); + } + + pub fn set_fifo_watermark(&mut self, watermark: u8) -> Result<()> { + if watermark > 0b111 { + return Err(Error::InvalidConfig); + } + I::ptr().fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(watermark) }); + Ok(()) + } + + /// 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) + /// + /// # Returns + /// * `Ok(())` if the triger mask was valid + /// * `Err(Error::InvalidConfig)` if the mask was greater than `0b1111` + pub fn do_software_trigger(&self, trigger_id_mask: u8) -> Result<()> { + if trigger_id_mask > 0b1111 { + return Err(Error::InvalidConfig); + } + let adc = I::ptr(); + adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask as u32) }); + Ok(()) + } + + /// 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 (Must be in range 1..=7) + /// * `config` - Command configuration + /// + /// # 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: usize, config: &ConvCommandConfig) -> Result<()> { + self.set_conv_command_config_inner(index, config) + } + + /// 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..=3) + /// * `config` - Trigger configuration + pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> { + self.set_conv_trigger_config_inner(trigger_id, config) + } + + /// Reset the FIFO buffer. + /// + /// Clears all pending conversion results from the FIFO. + pub fn do_reset_fifo(&self) { + let adc = I::ptr(); + adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); + } + + /// 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 + /// - `Err(Error::FifoEmpty)` if the FIFO is empty + pub fn get_conv_result(&self) -> Result { + self.get_conv_result_inner() + } } impl<'a, I: Instance> Adc<'a, I, Async> { @@ -182,12 +302,65 @@ impl<'a, I: Instance> Adc<'a, I, Async> { _irq: impl crate::interrupt::typelevel::Binding> + 'a, config: LpadcConfig, ) -> Result { - let adc = Self::new_inner(_inst, pin, config); + let adc = Self::new_inner(_inst, pin, config)?; I::Interrupt::unpend(); unsafe { I::Interrupt::enable() }; - adc + let cfg = ConvCommandConfig { + chained_next_command_number: Next::NoNextCmdTerminateOnFinish, + enable_auto_channel_increment: false, + loop_count: 0, + hardware_average_mode: Avgs::NoAverage, // todo: good config? + sample_time_mode: Sts::Sample3p5, // todo: good config? + hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, + hardware_compare_value_high: 0, + hardware_compare_value_low: 0, + conversion_resolution_mode: Mode::Data16Bits, // todo: good config? + enable_wait_trigger: false, + }; + + // We always use command 1, so this cannot fail + _ = adc.set_conv_command_config_inner(1, &cfg); + + let cfg = ConvTriggerConfig { + target_command_id: Tcmd::ExecuteCmd1, + delay_power: 0, + priority: Tpri::HighestPriority, + enable_hardware_trigger: false, + }; + + // We always use trigger 0, so this cannot fail + _ = adc.set_conv_trigger_config_inner(0, &cfg); + + // We always set the watermark to 0 (trigger when 1 is available) + I::ptr().fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(0) }); + + Ok(adc) + } + + /// Set the number of averages + pub fn set_averages(&mut self, avgs: Avgs) { + // TODO: we should probably return a result or wait for idle? + // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." + I::ptr().cmdh1().modify(|_r, w| w.avgs().variant(avgs)); + } + + /// Set the sample time + pub fn set_sample_time(&mut self, st: Sts) { + // TODO: we should probably return a result or wait for idle? + // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." + I::ptr().cmdh1().modify(|_r, w| w.sts().variant(st)); + } + + pub fn set_resolution(&mut self, mode: Mode) { + // TODO: we should probably return a result or wait for idle? + // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." + I::ptr().cmdl1().modify(|_r, w| w.mode().variant(mode)); + } + + fn wait_idle(&mut self) -> impl Future> + use<'_, I> { + I::wait_cell().wait_for(|| I::ptr().ie().read().fwmie0().bit_is_clear()) } /// Read ADC value asynchronously. @@ -203,21 +376,29 @@ impl<'a, I: Instance> Adc<'a, I, Async> { /// # Returns /// 16-bit ADC conversion value pub async fn read(&mut self) -> Result { - let wait = I::wait_cell().subscribe().await; + let adc = I::ptr(); - Adc::<'a, I, Async>::enable_interrupt(self, 0x1); - Adc::<'a, I, Async>::do_software_trigger(self, 1); + // If we cancelled a previous read, we might still be busy, wait + // until the interrupt is cleared (done by the interrupt) + _ = self.wait_idle().await; - let _ = wait.await; + // Clear the fifo + adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); + + // Trigger a new conversion + adc.ie().modify(|_r, w| w.fwmie0().set_bit()); + adc.swtrig().write(|w| w.swt0().set_bit()); - let result = Adc::<'a, I, Async>::get_conv_result(self).unwrap().conv_value >> G_LPADC_RESULT_SHIFT; - Ok(result) + // Wait for completion + _ = self.wait_idle().await; + + self.get_conv_result_inner().map(|r| r.conv_value) } } 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, P>, config: LpadcConfig) -> Result { let adc = I::ptr(); _ = unsafe { @@ -241,22 +422,16 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { adc.ctrl().modify(|_, w| w.adcen().disabled()); /* Configure the module generally. */ - if config.enable_in_doze_mode { - adc.ctrl().modify(|_, w| w.dozen().enabled()); - } else { - adc.ctrl().modify(|_, w| w.dozen().disabled()); - } + adc.ctrl().modify(|_, w| w.dozen().bit(config.enable_in_doze_mode)); /* Set calibration average mode. */ adc.ctrl() .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode)); adc.cfg().write(|w| unsafe { - let w = if config.enable_analog_preliminary { - w.pwren().pre_enabled() - } else { - w - }; + if config.enable_analog_preliminary { + w.pwren().pre_enabled(); + } w.pudly() .bits(config.power_up_delay) @@ -306,8 +481,7 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { adc.pause().write(|w| unsafe { w.bits(0) }); } - adc.fctrl0() - .write(|w| unsafe { w.fwmark().bits(config.fifo_watermark) }); + adc.fctrl0().write(|w| unsafe { w.fwmark().bits(0) }); // Enable ADC adc.ctrl().modify(|_, w| w.adcen().enabled()); @@ -315,15 +489,10 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { Ok(Self { _inst: PhantomData, _phantom: PhantomData, + index: P::CHANNEL, }) } - /// Deinitialize the ADC peripheral. - pub fn deinit(&self) { - 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) { @@ -369,7 +538,7 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} let mut gcca = adc.gcc0().read().gain_cal().bits() as u32; - if gcca & ((0xFFFF + 1) >> 1) != 0 { + if gcca & 0x8000 != 0 { gcca |= !0xFFFF; } @@ -384,127 +553,58 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { 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) { + fn set_conv_command_config_inner(&self, index: usize, config: &ConvCommandConfig) -> Result<()> { 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 { - channel_number: Adch::SelectCh0, - chained_next_command_number: Next::NoNextCmdTerminateOnFinish, - enable_auto_channel_increment: false, - loop_count: 0, - 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, - enable_wait_trigger: false, - } - } - /// 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 - /// * `config` - Command configuration - /// - /// # 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); - } + let (cmdl, cmdh) = match index { + 1 => (adc.cmdl1(), adc.cmdh1()), + 2 => (adc.cmdl2(), adc.cmdh2()), + 3 => (adc.cmdl3(), adc.cmdh3()), + 4 => (adc.cmdl4(), adc.cmdh4()), + 5 => (adc.cmdl5(), adc.cmdh5()), + 6 => (adc.cmdl6(), adc.cmdh6()), + 7 => (adc.cmdl7(), adc.cmdh7()), + _ => return Err(Error::InvalidConfig), + }; - macro_rules! write_cmd { - ($idx:expr) => {{ - paste! { - adc.[]().write(|w| { - w.adch() - .variant(config.channel_number) - .mode() - .variant(config.conversion_resolution_mode) - }); - adc.[]().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) - .wait_trig() - .bit(config.enable_wait_trigger) - .lwi() - .bit(config.enable_auto_channel_increment) - }); - } - }}; - } + cmdl.write(|w| { + unsafe { + w.adch().bits(self.index); + } + w.mode().variant(config.conversion_resolution_mode) + }); - match index { - 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), - _ => unreachable!(), - } + cmdh.write(|w| { + w.next().variant(config.chained_next_command_number); + unsafe { + w.loop_().bits(config.loop_count); + } + w.avgs().variant(config.hardware_average_mode); + w.sts().variant(config.sample_time_mode); + w.cmpen().variant(config.hardware_compare_mode); + w.wait_trig().bit(config.enable_wait_trigger); + w.lwi().bit(config.enable_auto_channel_increment); + w + }); Ok(()) } - /// 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, - delay_power: 0, - priority: Tpri::HighestPriority, - enable_hardware_trigger: false, + fn set_conv_trigger_config_inner(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> { + let adc = I::ptr(); + + // 0..4 are valid + if trigger_id >= 4 { + return Err(Error::InvalidConfig); } - } - /// 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 = I::ptr(); let tctrl = &adc.tctrl(trigger_id); - tctrl.write(|w| unsafe { - let w = w.tcmd().variant(config.target_command_id); - let w = w.tdly().bits(config.delay_power); + tctrl.write(|w| { + w.tcmd().variant(config.target_command_id); + unsafe { + w.tdly().bits(config.delay_power); + } w.tpri().variant(config.priority); if config.enable_hardware_trigger { w.hten().enabled() @@ -512,36 +612,8 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { w } }); - } - /// Reset the FIFO buffer. - /// - /// Clears all pending conversion results from the FIFO. - pub fn do_reset_fifo(&self) { - 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 = I::ptr(); - adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); - } - - /// 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) }); + Ok(()) } /// Get conversion result from FIFO. @@ -552,7 +624,7 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { /// # Returns /// - `Some(ConvResult)` if a result is available /// - `Err(Error::FifoEmpty)` if the FIFO is empty - pub fn get_conv_result(&self) -> Result { + fn get_conv_result_inner(&self) -> Result { let adc = I::ptr(); let fifo = adc.resfifo0().read(); if !fifo.valid().is_valid() { @@ -570,7 +642,7 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { impl Handler for InterruptHandler { unsafe fn on_interrupt() { - T::ptr().ie().modify(|r, w| w.bits(r.bits() & !0x1)); + T::ptr().ie().modify(|_r, w| w.fwmie0().clear_bit()); T::wait_cell().wake(); } } @@ -621,6 +693,8 @@ macro_rules! impl_instance { impl_instance!(0, 1, 2, 3); pub trait AdcPin: GpioPin + sealed::Sealed + PeripheralType { + const CHANNEL: u8; + /// Set the given pin to the correct muxing state fn mux(&self); } @@ -640,8 +714,10 @@ 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 { + ($pin:ident, $peri:ident, $func:ident, $channel:literal) => { + impl AdcPin for crate::peripherals::$pin { + const CHANNEL: u8 = $channel; + fn mux(&self) { self.set_pull(crate::gpio::Pull::Disabled); self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); @@ -652,101 +728,113 @@ macro_rules! impl_pin { }; } -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); +impl_pin!(P2_0, ADC0, Mux0, 0); +impl_pin!(P2_4, ADC0, Mux0, 1); +impl_pin!(P2_15, ADC0, Mux0, 2); +impl_pin!(P2_3, ADC0, Mux0, 3); +impl_pin!(P2_2, ADC0, Mux0, 4); +impl_pin!(P2_12, ADC0, Mux0, 5); +impl_pin!(P2_16, ADC0, Mux0, 6); +impl_pin!(P2_7, ADC0, Mux0, 7); +impl_pin!(P0_18, ADC0, Mux0, 8); +impl_pin!(P0_19, ADC0, Mux0, 9); +impl_pin!(P0_20, ADC0, Mux0, 10); +impl_pin!(P0_21, ADC0, Mux0, 11); +impl_pin!(P0_22, ADC0, Mux0, 12); +impl_pin!(P0_23, ADC0, Mux0, 13); +impl_pin!(P0_3, ADC0, Mux0, 14); +impl_pin!(P0_6, ADC0, Mux0, 15); +impl_pin!(P1_0, ADC0, Mux0, 16); +impl_pin!(P1_1, ADC0, Mux0, 17); +impl_pin!(P1_2, ADC0, Mux0, 18); +impl_pin!(P1_3, ADC0, Mux0, 19); +impl_pin!(P1_4, ADC0, Mux0, 20); +impl_pin!(P1_5, ADC0, Mux0, 21); +impl_pin!(P1_6, ADC0, Mux0, 22); +impl_pin!(P1_7, ADC0, Mux0, 23); + +// ??? +// impl_pin!(P1_10, ADC0, Mux0, 255); + +impl_pin!(P2_1, ADC1, Mux0, 0); +impl_pin!(P2_5, ADC1, Mux0, 1); +impl_pin!(P2_19, ADC1, Mux0, 2); +impl_pin!(P2_6, ADC1, Mux0, 3); +impl_pin!(P2_3, ADC1, Mux0, 4); +impl_pin!(P2_13, ADC1, Mux0, 5); +impl_pin!(P2_17, ADC1, Mux0, 6); +impl_pin!(P2_7, ADC1, Mux0, 7); +impl_pin!(P1_10, ADC1, Mux0, 8); +impl_pin!(P1_11, ADC1, Mux0, 9); +impl_pin!(P1_12, ADC1, Mux0, 10); +impl_pin!(P1_13, ADC1, Mux0, 11); +impl_pin!(P1_14, ADC1, Mux0, 12); +impl_pin!(P1_15, ADC1, Mux0, 13); +// ??? +// impl_pin!(P1_16, ADC1, Mux0, 255); +// impl_pin!(P1_17, ADC1, Mux0, 255); +// impl_pin!(P1_18, ADC1, Mux0, 255); +// impl_pin!(P1_19, ADC1, Mux0, 255); +// ??? +impl_pin!(P3_31, ADC1, Mux0, 20); +impl_pin!(P3_30, ADC1, Mux0, 21); +impl_pin!(P3_29, ADC1, Mux0, 22); + +impl_pin!(P2_4, ADC2, Mux0, 0); +impl_pin!(P2_10, ADC2, Mux0, 1); +impl_pin!(P4_4, ADC2, Mux0, 2); +// impl_pin!(P2_24, ADC2, Mux0, 255); ??? +impl_pin!(P2_16, ADC2, Mux0, 4); +impl_pin!(P2_12, ADC2, Mux0, 5); +impl_pin!(P2_20, ADC2, Mux0, 6); +impl_pin!(P2_7, ADC2, Mux0, 7); +impl_pin!(P0_2, ADC2, Mux0, 8); +// ??? +// impl_pin!(P0_4, ADC2, Mux0, 255); +// impl_pin!(P0_5, ADC2, Mux0, 255); +// impl_pin!(P0_6, ADC2, Mux0, 255); +// impl_pin!(P0_7, ADC2, Mux0, 255); +// impl_pin!(P0_12, ADC2, Mux0, 255); +// impl_pin!(P0_13, ADC2, Mux0, 255); +// ??? +impl_pin!(P0_14, ADC2, Mux0, 14); +impl_pin!(P0_15, ADC2, Mux0, 15); +// ??? +// impl_pin!(P4_0, ADC2, Mux0, 255); +// impl_pin!(P4_1, ADC2, Mux0, 255); +// ??? +impl_pin!(P4_2, ADC2, Mux0, 18); +impl_pin!(P4_3, ADC2, Mux0, 19); +//impl_pin!(P4_4, ADC2, Mux0, 20); // Conflit with ADC2_A3 and ADC2_A20 using the same pin +impl_pin!(P4_5, ADC2, Mux0, 21); +impl_pin!(P4_6, ADC2, Mux0, 22); +impl_pin!(P4_7, ADC2, Mux0, 23); + +impl_pin!(P2_5, ADC3, Mux0, 0); +impl_pin!(P2_11, ADC3, Mux0, 1); +impl_pin!(P2_23, ADC3, Mux0, 2); +// impl_pin!(P2_25, ADC3, Mux0, 255); // ??? +impl_pin!(P2_17, ADC3, Mux0, 4); +impl_pin!(P2_13, ADC3, Mux0, 5); +impl_pin!(P2_21, ADC3, Mux0, 6); +impl_pin!(P2_7, ADC3, Mux0, 7); +// ??? +// impl_pin!(P3_2, ADC3, Mux0, 255); +// impl_pin!(P3_3, ADC3, Mux0, 255); +// impl_pin!(P3_4, ADC3, Mux0, 255); +// impl_pin!(P3_5, ADC3, Mux0, 255); +// ??? +impl_pin!(P3_6, ADC3, Mux0, 12); +impl_pin!(P3_7, ADC3, Mux0, 13); +impl_pin!(P3_12, ADC3, Mux0, 14); +impl_pin!(P3_13, ADC3, Mux0, 15); +impl_pin!(P3_14, ADC3, Mux0, 16); +impl_pin!(P3_15, ADC3, Mux0, 17); +impl_pin!(P3_20, ADC3, Mux0, 18); +impl_pin!(P3_21, ADC3, Mux0, 19); +impl_pin!(P3_22, ADC3, Mux0, 20); +// ??? +// impl_pin!(P3_23, ADC3, Mux0, 255); +// impl_pin!(P3_24, ADC3, Mux0, 255); +// impl_pin!(P3_25, ADC3, Mux0, 255); +// ??? diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 5876923a1..d2cda631c 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs @@ -2,6 +2,7 @@ #![no_main] use embassy_executor::Spawner; +use embassy_time::{Duration, Ticker}; use hal::adc::{Adc, InterruptHandler, LpadcConfig, TriggerPriorityPolicy}; use hal::bind_interrupts; use hal::clocks::PoweredClock; @@ -9,9 +10,8 @@ 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::cmdl1::Mode; use hal::pac::adc1::ctrl::CalAvgs; -use hal::pac::adc1::tctrl::Tcmd; use hal::peripherals::ADC1; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -38,7 +38,6 @@ async fn main(_spawner: Spawner) { 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(), @@ -47,23 +46,16 @@ async fn main(_spawner: Spawner) { 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).unwrap(); - - 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); + adc.set_resolution(Mode::Data16Bits); defmt::info!("ADC configuration done..."); + let mut ticker = Ticker::every(Duration::from_millis(100)); loop { + ticker.next().await; match adc.read().await { Ok(value) => { - defmt::info!("*** ADC interrupt TRIGGERED! *** -- value: {}", value); + defmt::info!("ADC value: {}", value); } Err(e) => { defmt::error!("ADC read error: {:?}", e); diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index d048bb56f..5c4d5524c 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs @@ -2,13 +2,15 @@ #![no_main] use embassy_executor::Spawner; +use embassy_mcxa::adc::{ConvCommandConfig, ConvTriggerConfig}; +use embassy_time::{Duration, Ticker}; use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy}; use hal::clocks::PoweredClock; 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::cmdl1::Mode; use hal::pac::adc1::ctrl::CalAvgs; use hal::pac::adc1::tctrl::Tcmd; use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; @@ -34,7 +36,6 @@ async fn main(_spawner: Spawner) { 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(), @@ -44,20 +45,25 @@ async fn main(_spawner: Spawner) { 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; + let conv_command_config = ConvCommandConfig { + conversion_resolution_mode: Mode::Data16Bits, + ..ConvCommandConfig::default() + }; 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; - conv_trigger_config.enable_hardware_trigger = false; - adc.set_conv_trigger_config(0, &conv_trigger_config); + let conv_trigger_config = ConvTriggerConfig { + target_command_id: Tcmd::ExecuteCmd1, + enable_hardware_trigger: false, + ..Default::default() + }; + adc.set_conv_trigger_config(0, &conv_trigger_config).unwrap(); defmt::info!("=== ADC configuration done... ==="); + let mut tick = Ticker::every(Duration::from_millis(100)); loop { - adc.do_software_trigger(1); + tick.next().await; + adc.do_software_trigger(1).unwrap(); let result = loop { match adc.get_conv_result() { Ok(res) => break res, -- cgit From ebe47b1856602f993a7f87669030afe1cd10dc51 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Dec 2025 16:03:04 +0100 Subject: Remove generic parameter from ADC --- embassy-mcxa/src/adc.rs | 129 ++++++++++++++++++++++++++---------------------- 1 file changed, 70 insertions(+), 59 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index e4b24cffa..c19f02431 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -173,20 +173,29 @@ pub struct InterruptHandler { } /// ADC driver instance. -pub struct Adc<'a, I: Instance, M: ModeAdc> { - _inst: PhantomData<&'a mut I>, - _phantom: PhantomData, - index: u8, +pub struct Adc<'a, M: ModeAdc> { + _inst: PhantomData<&'a mut ()>, + mode: M, + + // The channel index of the pin used to create our ADC instance + channel_idx: u8, + + // The register block of the ADC instance + info: &'static pac::adc0::RegisterBlock, } -impl<'a, I: Instance> Adc<'a, I, Blocking> { +impl<'a> Adc<'a, 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) + pub fn new_blocking( + _inst: Peri<'a, I>, + pin: Peri<'a, impl AdcPin>, + config: LpadcConfig, + ) -> Result { + Self::new_inner(_inst, pin, config, Blocking) } /// Enable ADC interrupts. @@ -196,8 +205,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> { /// # Arguments /// * `mask` - Bitmask of interrupt sources to enable pub fn enable_interrupt(&mut self, mask: u32) { - let adc = I::ptr(); - adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); + self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); } /// Disable ADC interrupts. @@ -207,15 +215,14 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> { /// # Arguments /// * `mask` - Bitmask of interrupt sources to disable pub fn disable_interrupt(&mut self, mask: u32) { - let adc = I::ptr(); - adc.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); + self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); } pub fn set_fifo_watermark(&mut self, watermark: u8) -> Result<()> { if watermark > 0b111 { return Err(Error::InvalidConfig); } - I::ptr().fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(watermark) }); + self.info.fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(watermark) }); Ok(()) } @@ -234,8 +241,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> { if trigger_id_mask > 0b1111 { return Err(Error::InvalidConfig); } - let adc = I::ptr(); - adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask as u32) }); + self.info.swtrig().write(|w| unsafe { w.bits(trigger_id_mask as u32) }); Ok(()) } @@ -271,8 +277,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> { /// /// Clears all pending conversion results from the FIFO. pub fn do_reset_fifo(&self) { - let adc = I::ptr(); - adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); + self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); } /// Get conversion result from FIFO. @@ -288,7 +293,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> { } } -impl<'a, I: Instance> Adc<'a, I, Async> { +impl<'a> Adc<'a, Async> { /// Initialize ADC with interrupt support. /// /// # Arguments @@ -296,13 +301,13 @@ impl<'a, I: Instance> Adc<'a, I, Async> { /// * `pin` - GPIO pin to use for ADC /// * `_irq` - Interrupt binding for this ADC instance /// * `config` - ADC configuration - pub fn new_async( + pub fn new_async( _inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin>, _irq: impl crate::interrupt::typelevel::Binding> + 'a, config: LpadcConfig, ) -> Result { - let adc = Self::new_inner(_inst, pin, config)?; + let adc = Self::new_inner(_inst, pin, config, Async { waiter: I::wait_cell() })?; I::Interrupt::unpend(); unsafe { I::Interrupt::enable() }; @@ -343,24 +348,26 @@ impl<'a, I: Instance> Adc<'a, I, Async> { pub fn set_averages(&mut self, avgs: Avgs) { // TODO: we should probably return a result or wait for idle? // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." - I::ptr().cmdh1().modify(|_r, w| w.avgs().variant(avgs)); + self.info.cmdh1().modify(|_r, w| w.avgs().variant(avgs)); } /// Set the sample time pub fn set_sample_time(&mut self, st: Sts) { // TODO: we should probably return a result or wait for idle? // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." - I::ptr().cmdh1().modify(|_r, w| w.sts().variant(st)); + self.info.cmdh1().modify(|_r, w| w.sts().variant(st)); } pub fn set_resolution(&mut self, mode: Mode) { // TODO: we should probably return a result or wait for idle? // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." - I::ptr().cmdl1().modify(|_r, w| w.mode().variant(mode)); + self.info.cmdl1().modify(|_r, w| w.mode().variant(mode)); } - fn wait_idle(&mut self) -> impl Future> + use<'_, I> { - I::wait_cell().wait_for(|| I::ptr().ie().read().fwmie0().bit_is_clear()) + fn wait_idle(&mut self) -> impl Future> + use<'_> { + self.mode + .waiter + .wait_for(|| self.info.ie().read().fwmie0().bit_is_clear()) } /// Read ADC value asynchronously. @@ -376,18 +383,16 @@ impl<'a, I: Instance> Adc<'a, I, Async> { /// # Returns /// 16-bit ADC conversion value pub async fn read(&mut self) -> Result { - let adc = I::ptr(); - // If we cancelled a previous read, we might still be busy, wait // until the interrupt is cleared (done by the interrupt) _ = self.wait_idle().await; // Clear the fifo - adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); + self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); // Trigger a new conversion - adc.ie().modify(|_r, w| w.fwmie0().set_bit()); - adc.swtrig().write(|w| w.swt0().set_bit()); + self.info.ie().modify(|_r, w| w.fwmie0().set_bit()); + self.info.swtrig().write(|w| w.swt0().set_bit()); // Wait for completion _ = self.wait_idle().await; @@ -396,9 +401,14 @@ impl<'a, I: Instance> Adc<'a, I, Async> { } } -impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { +impl<'a, M: ModeAdc> Adc<'a, M> { /// Internal initialization function shared by `new_async` and `new_blocking`. - fn new_inner>(_inst: Peri<'a, I>, pin: Peri<'a, P>, config: LpadcConfig) -> Result { + fn new_inner>( + _inst: Peri<'a, I>, + pin: Peri<'a, P>, + config: LpadcConfig, + mode: M, + ) -> Result { let adc = I::ptr(); _ = unsafe { @@ -488,21 +498,22 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { Ok(Self { _inst: PhantomData, - _phantom: PhantomData, - index: P::CHANNEL, + mode, + channel_idx: P::CHANNEL, + info: adc, }) } /// Perform offset calibration. /// Waits for calibration to complete before returning. pub fn do_offset_calibration(&self) { - let adc = I::ptr(); // Enable calibration mode - adc.ctrl() + self.info + .ctrl() .modify(|_, w| w.calofs().offset_calibration_request_pending()); // Wait for calibration to complete (polling status register) - while adc.stat().read().cal_rdy().is_not_set() {} + while self.info.stat().read().cal_rdy().is_not_set() {} } /// Calculate gain conversion result from gain adjustment factor. @@ -532,12 +543,13 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { /// Perform automatic gain calibration. pub fn do_auto_calibration(&self) { - let adc = I::ptr(); - adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); + self.info + .ctrl() + .modify(|_, w| w.cal_req().calibration_request_pending()); - while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} + while self.info.gcc0().read().rdy().is_gain_cal_not_valid() {} - let mut gcca = adc.gcc0().read().gain_cal().bits() as u32; + let mut gcca = self.info.gcc0().read().gain_cal().bits() as u32; if gcca & 0x8000 != 0 { gcca |= !0xFFFF; } @@ -545,31 +557,31 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { let gcra = 131072.0 / (131072.0 - gcca as f32); // Write to GCR0 - adc.gcr0().write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); + self.info + .gcr0() + .write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); - adc.gcr0().modify(|_, w| w.rdy().set_bit()); + self.info.gcr0().modify(|_, w| w.rdy().set_bit()); // Wait for calibration to complete (polling status register) - while adc.stat().read().cal_rdy().is_not_set() {} + while self.info.stat().read().cal_rdy().is_not_set() {} } fn set_conv_command_config_inner(&self, index: usize, config: &ConvCommandConfig) -> Result<()> { - let adc = I::ptr(); - let (cmdl, cmdh) = match index { - 1 => (adc.cmdl1(), adc.cmdh1()), - 2 => (adc.cmdl2(), adc.cmdh2()), - 3 => (adc.cmdl3(), adc.cmdh3()), - 4 => (adc.cmdl4(), adc.cmdh4()), - 5 => (adc.cmdl5(), adc.cmdh5()), - 6 => (adc.cmdl6(), adc.cmdh6()), - 7 => (adc.cmdl7(), adc.cmdh7()), + 1 => (self.info.cmdl1(), self.info.cmdh1()), + 2 => (self.info.cmdl2(), self.info.cmdh2()), + 3 => (self.info.cmdl3(), self.info.cmdh3()), + 4 => (self.info.cmdl4(), self.info.cmdh4()), + 5 => (self.info.cmdl5(), self.info.cmdh5()), + 6 => (self.info.cmdl6(), self.info.cmdh6()), + 7 => (self.info.cmdl7(), self.info.cmdh7()), _ => return Err(Error::InvalidConfig), }; cmdl.write(|w| { unsafe { - w.adch().bits(self.index); + w.adch().bits(self.channel_idx); } w.mode().variant(config.conversion_resolution_mode) }); @@ -591,14 +603,12 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { } fn set_conv_trigger_config_inner(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> { - let adc = I::ptr(); - // 0..4 are valid if trigger_id >= 4 { return Err(Error::InvalidConfig); } - let tctrl = &adc.tctrl(trigger_id); + let tctrl = &self.info.tctrl(trigger_id); tctrl.write(|w| { w.tcmd().variant(config.target_command_id); @@ -625,8 +635,7 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { /// - `Some(ConvResult)` if a result is available /// - `Err(Error::FifoEmpty)` if the FIFO is empty fn get_conv_result_inner(&self) -> Result { - let adc = I::ptr(); - let fifo = adc.resfifo0().read(); + let fifo = self.info.resfifo0().read(); if !fifo.valid().is_valid() { return Err(Error::FifoEmpty); } @@ -709,7 +718,9 @@ impl sealed::Sealed for Blocking {} impl ModeAdc for Blocking {} /// Async mode. -pub struct Async; +pub struct Async { + waiter: &'static WaitCell, +} impl sealed::Sealed for Async {} impl ModeAdc for Async {} -- cgit From 0e64db6bb72252ceb35725298bc8858d7949ba88 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Dec 2025 16:07:59 +0100 Subject: Remove some stale todos --- embassy-mcxa/src/adc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index c19f02431..9efac6217 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -316,12 +316,12 @@ impl<'a> Adc<'a, Async> { chained_next_command_number: Next::NoNextCmdTerminateOnFinish, enable_auto_channel_increment: false, loop_count: 0, - hardware_average_mode: Avgs::NoAverage, // todo: good config? - sample_time_mode: Sts::Sample3p5, // todo: good config? + 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::Data16Bits, // todo: good config? + conversion_resolution_mode: Mode::Data16Bits, enable_wait_trigger: false, }; -- cgit From 5c09b36a7ffbab31c97230baf0de39920e12d175 Mon Sep 17 00:00:00 2001 From: James Munns Date: Thu, 11 Dec 2025 17:44:52 +0100 Subject: Suggestion from review --- embassy-mcxa/src/adc.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 9efac6217..f88bb6b37 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs @@ -439,9 +439,7 @@ impl<'a, M: ModeAdc> Adc<'a, M> { .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode)); adc.cfg().write(|w| unsafe { - if config.enable_analog_preliminary { - w.pwren().pre_enabled(); - } + w.pwren().bit(config.enable_analog_preliminary); w.pudly() .bits(config.power_up_delay) -- cgit