From e2e0464d04ba2fa16ec5217dd651dae157279efb Mon Sep 17 00:00:00 2001 From: Ben Gamari Date: Mon, 30 Aug 2021 15:33:42 -0400 Subject: [PATCH] stm32/adc: Factor out conversion logic Also guard errata workaround correctly. --- embassy-stm32/src/adc/v3.rs | 61 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 2781fc4dc..d80c9ffc0 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -229,6 +229,27 @@ impl<'d, T: Instance> Adc<'d, T> { } */ + /// Perform a single conversion. + fn convert(&mut self) -> u16 { + unsafe { + T::regs().isr().modify(|reg| { + reg.set_eos(true); + reg.set_eoc(true); + }); + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + while !T::regs().isr().read().eos() { + // spin + } + + T::regs().dr().read().0 as u16 + } + } + pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { unsafe { // Make sure bits are off @@ -259,38 +280,16 @@ impl<'d, T: Instance> Adc<'d, T> { // Select channel T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); - // Start conversion - T::regs().isr().modify(|reg| { - reg.set_eos(true); - reg.set_eoc(true); - }); - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); + // Some models are affected by an erratum: + // If we perform conversions slower than 1 kHz, the first read ADC value can be + // corrupted, so we discard it and measure again. + // + // STM32L471xx: Section 2.7.3 + // STM32G4: Section 2.7.3 + #[cfg(any(rcc_l4, rcc_g4))] + let _ = self.convert(); - while !T::regs().isr().read().eos() { - // spin - } - - // Read ADC value first time and discard it, as per errata sheet. - // The errata states that if we do conversions slower than 1 kHz, the - // first read ADC value can be corrupted, so we discard it and measure again. - - let _ = T::regs().dr().read(); - - T::regs().isr().modify(|reg| { - reg.set_eos(true); - reg.set_eoc(true); - }); - T::regs().cr().modify(|reg| { - reg.set_adstart(true); - }); - - while !T::regs().isr().read().eos() { - // spin - } - - let val = T::regs().dr().read().0 as u16; + let val = self.convert(); T::regs().cr().modify(|reg| reg.set_addis(true));