stm32/adc: Factor out conversion logic

Also guard errata workaround correctly.
This commit is contained in:
Ben Gamari 2021-08-30 15:33:42 -04:00
parent b6f84efd90
commit e2e0464d04

View File

@ -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<T>) -> u16 { pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
unsafe { unsafe {
// Make sure bits are off // Make sure bits are off
@ -259,38 +280,16 @@ impl<'d, T: Instance> Adc<'d, T> {
// Select channel // Select channel
T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel())); T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
// Start conversion // Some models are affected by an erratum:
T::regs().isr().modify(|reg| { // If we perform conversions slower than 1 kHz, the first read ADC value can be
reg.set_eos(true); // corrupted, so we discard it and measure again.
reg.set_eoc(true); //
}); // STM32L471xx: Section 2.7.3
T::regs().cr().modify(|reg| { // STM32G4: Section 2.7.3
reg.set_adstart(true); #[cfg(any(rcc_l4, rcc_g4))]
}); let _ = self.convert();
while !T::regs().isr().read().eos() { let val = self.convert();
// 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;
T::regs().cr().modify(|reg| reg.set_addis(true)); T::regs().cr().modify(|reg| reg.set_addis(true));