From d89d8d9e2bb201fe5f1d8212d317abb12a91666f Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 10 Nov 2025 13:48:24 -0600 Subject: adc: consolidate functions --- embassy-stm32/src/adc/g4.rs | 125 ++++++++++++-------------- embassy-stm32/src/adc/injected.rs | 2 +- embassy-stm32/src/adc/ringbuffered.rs | 2 +- embassy-stm32/src/adc/v2.rs | 164 +++++++++++++++++----------------- embassy-stm32/src/adc/v3.rs | 2 +- 5 files changed, 140 insertions(+), 155 deletions(-) diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 2138a82b4..5d9c6ff74 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs @@ -147,7 +147,7 @@ impl<'d, T: Instance> Adc<'d, T> { s.calibrate(); blocking_delay_us(1); - s.enable(); + Self::enable(); s.configure(); s @@ -192,7 +192,7 @@ impl<'d, T: Instance> Adc<'d, T> { blocking_delay_us(20); } - fn enable(&mut self) { + fn enable() { // Make sure bits are off while T::regs().cr().read().addis() { // spin @@ -363,7 +363,7 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Teardown method for stopping regular ADC conversions - pub(super) fn teardown_adc() { + pub(super) fn teardown_dma() { Self::stop_regular_conversions(); // Disable dma control @@ -418,39 +418,13 @@ impl<'d, T: Instance> Adc<'d, T> { // Ensure no conversions are ongoing and ADC is enabled. Self::stop_regular_conversions(); - self.enable(); + Self::enable(); - // Set sequence length - T::regs().sqr1().modify(|w| { - w.set_l(sequence.len() as u8 - 1); - }); - // Configure channels and ranks - for (_i, (channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(channel, sample_time); - match _i { - 0..=3 => { - T::regs().sqr1().modify(|w| { - w.set_sq(_i, channel.channel()); - }); - } - 4..=8 => { - T::regs().sqr2().modify(|w| { - w.set_sq(_i - 4, channel.channel()); - }); - } - 9..=13 => { - T::regs().sqr3().modify(|w| { - w.set_sq(_i - 9, channel.channel()); - }); - } - 14..=15 => { - T::regs().sqr4().modify(|w| { - w.set_sq(_i - 14, channel.channel()); - }); - } - _ => unreachable!(), - } - } + Self::configure_sequence(sequence.map(|(channel, sample_time)| { + channel.setup(); + + (channel.channel, sample_time) + })); // Set continuous mode with oneshot dma. // Clear overrun flag before starting transfer. @@ -493,6 +467,47 @@ impl<'d, T: Instance> Adc<'d, T> { }); } + pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + // Set sequence length + T::regs().sqr1().modify(|w| { + w.set_l(sequence.len() as u8 - 1); + }); + + // Configure channels and ranks + for (_i, (ch, sample_time)) in sequence.enumerate() { + let sample_time = sample_time.into(); + if ch <= 9 { + T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); + } else { + T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + } + + match _i { + 0..=3 => { + T::regs().sqr1().modify(|w| { + w.set_sq(_i, ch); + }); + } + 4..=8 => { + T::regs().sqr2().modify(|w| { + w.set_sq(_i - 4, ch); + }); + } + 9..=13 => { + T::regs().sqr3().modify(|w| { + w.set_sq(_i - 9, ch); + }); + } + 14..=15 => { + T::regs().sqr4().modify(|w| { + w.set_sq(_i - 14, ch); + }); + } + _ => unreachable!(), + } + } + } + /// Set external trigger for regular conversion sequence fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) { T::regs().cfgr().modify(|r| { @@ -546,43 +561,15 @@ impl<'d, T: Instance> Adc<'d, T> { ); // reset conversions and enable the adc Self::stop_regular_conversions(); - self.enable(); + Self::enable(); //adc side setup - // Set sequence length - T::regs().sqr1().modify(|w| { - w.set_l(sequence.len() as u8 - 1); - }); - - // Configure channels and ranks - for (_i, (mut channel, sample_time)) in sequence.enumerate() { - Self::configure_channel(&mut channel, sample_time); + Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { + channel.setup(); - match _i { - 0..=3 => { - T::regs().sqr1().modify(|w| { - w.set_sq(_i, channel.channel()); - }); - } - 4..=8 => { - T::regs().sqr2().modify(|w| { - w.set_sq(_i - 4, channel.channel()); - }); - } - 9..=13 => { - T::regs().sqr3().modify(|w| { - w.set_sq(_i - 9, channel.channel()); - }); - } - 14..=15 => { - T::regs().sqr4().modify(|w| { - w.set_sq(_i - 14, channel.channel()); - }); - } - _ => unreachable!(), - } - } + (channel.channel, sample_time) + })); // Clear overrun flag before starting transfer. T::regs().isr().modify(|reg| { @@ -655,7 +642,7 @@ impl<'d, T: Instance> Adc<'d, T> { ); Self::stop_regular_conversions(); - self.enable(); + Self::enable(); T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1)); diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs index 0e4fe5847..f9f1bba2a 100644 --- a/embassy-stm32/src/adc/injected.rs +++ b/embassy-stm32/src/adc/injected.rs @@ -38,7 +38,7 @@ impl InjectedAdc { impl Drop for InjectedAdc { fn drop(&mut self) { - Adc::::teardown_adc(); + Adc::::teardown_dma(); compiler_fence(Ordering::SeqCst); } } diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs index 971c8195c..024c6acdc 100644 --- a/embassy-stm32/src/adc/ringbuffered.rs +++ b/embassy-stm32/src/adc/ringbuffered.rs @@ -172,7 +172,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> { impl Drop for RingBufferedAdc<'_, T> { fn drop(&mut self) { - Adc::::teardown_adc(); + Adc::::teardown_dma(); compiler_fence(Ordering::SeqCst); diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index af5d486d9..88a8b96ed 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -125,57 +125,14 @@ where ) -> RingBufferedAdc<'d, T> { assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); - T::regs().cr2().modify(|reg| { - reg.set_adon(true); - }); - - // Check the sequence is long enough - T::regs().sqr1().modify(|r| { - r.set_l((sequence.len() - 1).try_into().unwrap()); - }); - - for (i, (mut channel, sample_time)) in sequence.enumerate() { - // Set this GPIO as an analog input. + Self::configure_sequence(sequence.map(|(mut channel, sample_time)| { channel.setup(); - // Set the channel in the right sequence field. - T::regs().sqr3().modify(|w| w.set_sq(i, channel.channel())); - - Self::set_channel_sample_time(channel.channel(), sample_time); - } - + (channel.channel, sample_time) + })); compiler_fence(Ordering::SeqCst); - let r = T::regs(); - - // Clear all interrupts - r.sr().modify(|regs| { - regs.set_eoc(false); - regs.set_ovr(false); - regs.set_strt(false); - }); - - r.cr1().modify(|w| { - // Enable interrupt for end of conversion - w.set_eocie(true); - // Enable interrupt for overrun - w.set_ovrie(true); - // Scanning converisons of multiple channels - w.set_scan(true); - // Continuous conversion mode - w.set_discen(false); - }); - - r.cr2().modify(|w| { - // Enable DMA mode - w.set_dma(true); - // Enable continuous conversions - w.set_cont(true); - // DMA requests are issues as long as DMA=1 and data are converted. - w.set_dds(vals::Dds::CONTINUOUS); - // EOC flag is set at the end of each conversion. - w.set_eocs(vals::Eocs::EACH_CONVERSION); - }); + Self::setup_dma(); // Don't disable the clock mem::forget(self); @@ -183,24 +140,14 @@ where RingBufferedAdc::new(dma, dma_buf) } - pub(super) fn start() { - // Begin ADC conversions - T::regs().cr2().modify(|reg| { - reg.set_adon(true); - reg.set_swstart(true); - }); - } + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { + channel.setup(); - pub(super) fn stop() { - // Stop ADC - T::regs().cr2().modify(|reg| { - // Stop ADC - reg.set_swstart(false); - }); - } + // Configure ADC + let channel = channel.channel(); - pub fn set_resolution(&mut self, resolution: Resolution) { - T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); + Self::configure_sequence([(channel, sample_time)].into_iter()); + Self::blocking_convert() } /// Enables internal voltage reference and returns [VrefInt], which can be used in @@ -236,8 +183,27 @@ where Vbat {} } - /// Perform a single conversion. - fn convert(&mut self) -> u16 { + pub(super) fn start() { + // Begin ADC conversions + T::regs().cr2().modify(|reg| { + reg.set_adon(true); + reg.set_swstart(true); + }); + } + + pub(super) fn stop() { + // Stop ADC + T::regs().cr2().modify(|reg| { + // Stop ADC + reg.set_swstart(false); + }); + } + + pub fn set_resolution(&mut self, resolution: Resolution) { + T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); + } + + pub(super) fn blocking_convert() -> u16 { // clear end of conversion flag T::regs().sr().modify(|reg| { reg.set_eoc(false); @@ -258,31 +224,63 @@ where T::regs().dr().read().0 as u16 } - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel, sample_time: SampleTime) -> u16 { - channel.setup(); + pub(super) fn configure_sequence(sequence: impl ExactSizeIterator) { + T::regs().cr2().modify(|reg| { + reg.set_adon(true); + }); - // Configure ADC - let channel = channel.channel(); + // Check the sequence is long enough + T::regs().sqr1().modify(|r| { + r.set_l((sequence.len() - 1).try_into().unwrap()); + }); - // Select channel - T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); + for (i, (ch, sample_time)) in sequence.enumerate() { + // Set the channel in the right sequence field. + T::regs().sqr3().modify(|w| w.set_sq(i, ch)); + + let sample_time = sample_time.into(); + if ch <= 9 { + T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); + } else { + T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + } + } + } - // Configure channel - Self::set_channel_sample_time(channel, sample_time); + pub(super) fn setup_dma() { + let r = T::regs(); - self.convert() - } + // Clear all interrupts + r.sr().modify(|regs| { + regs.set_eoc(false); + regs.set_ovr(false); + regs.set_strt(false); + }); - fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { - let sample_time = sample_time.into(); - if ch <= 9 { - T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); - } else { - T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); - } + r.cr1().modify(|w| { + // Enable interrupt for end of conversion + w.set_eocie(true); + // Enable interrupt for overrun + w.set_ovrie(true); + // Scanning converisons of multiple channels + w.set_scan(true); + // Continuous conversion mode + w.set_discen(false); + }); + + r.cr2().modify(|w| { + // Enable DMA mode + w.set_dma(true); + // Enable continuous conversions + w.set_cont(true); + // DMA requests are issues as long as DMA=1 and data are converted. + w.set_dds(vals::Dds::CONTINUOUS); + // EOC flag is set at the end of each conversion. + w.set_eocs(vals::Eocs::EACH_CONVERSION); + }); } - pub(super) fn teardown_adc() { + pub(super) fn teardown_dma() { let r = T::regs(); // Stop ADC diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 0822fbb69..e816907d1 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -198,7 +198,7 @@ impl<'d, T: Instance> Adc<'d, T> { } #[cfg(any(adc_v3, adc_g0, adc_u0))] - pub(super) fn teardown_adc() { + pub(super) fn teardown_dma() { //disable dma control #[cfg(not(any(adc_g0, adc_u0)))] T::regs().cfgr().modify(|reg| { -- cgit