use core::sync::atomic::{Ordering, compiler_fence}; use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; use crate::adc::{Adc, AdcRegs, Instance, Resolution, SampleTime}; use crate::pac::adc::vals; pub use crate::pac::adccommon::vals::Adcpre; use crate::time::Hertz; use crate::{Peri, rcc}; fn clear_interrupt_flags(r: crate::pac::adc::Adc) { r.sr().modify(|regs| { regs.set_eoc(false); regs.set_ovr(false); }); } /// Default VREF voltage used for sample conversion to millivolts. pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3300; impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 17; } #[cfg(any(stm32f2, stm32f40x, stm32f41x))] impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 16; } #[cfg(not(any(stm32f2, stm32f40x, stm32f41x)))] impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 18; } impl super::SealedSpecialConverter for crate::peripherals::ADC1 { const CHANNEL: u8 = 18; } impl VrefInt { /// Time needed for internal voltage reference to stabilize pub fn start_time_us() -> u32 { 10 } } impl Temperature { /// Time needed for temperature sensor readings to stabilize pub fn start_time_us() -> u32 { 10 } } fn from_pclk2(freq: Hertz) -> Adcpre { // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). #[cfg(stm32f2)] const MAX_FREQUENCY: Hertz = Hertz(30_000_000); // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. #[cfg(not(stm32f2))] const MAX_FREQUENCY: Hertz = Hertz(36_000_000); let raw_div = rcc::raw_prescaler(freq.0, MAX_FREQUENCY.0); match raw_div { 0..=1 => Adcpre::DIV2, 2..=3 => Adcpre::DIV4, 4..=5 => Adcpre::DIV6, 6..=7 => Adcpre::DIV8, _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), } } /// ADC configuration #[derive(Default)] pub struct AdcConfig { pub resolution: Option, } impl super::AdcRegs for crate::pac::adc::Adc { fn data(&self) -> *mut u16 { crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16 } fn enable(&self) { self.cr2().modify(|reg| { reg.set_adon(true); }); blocking_delay_us(3); } fn start(&self) { // Begin ADC conversions self.cr2().modify(|reg| { reg.set_swstart(true); }); } fn stop(&self) { let r = self; // Stop ADC r.cr2().modify(|reg| { // Stop ADC reg.set_swstart(false); // Stop ADC reg.set_adon(false); // Stop DMA reg.set_dma(false); }); r.cr1().modify(|w| { // Disable interrupt for end of conversion w.set_eocie(false); // Disable interrupt for overrun w.set_ovrie(false); }); clear_interrupt_flags(*r); compiler_fence(Ordering::SeqCst); } fn convert(&self) { // clear end of conversion flag self.sr().modify(|reg| { reg.set_eoc(false); }); // Start conversion self.cr2().modify(|reg| { reg.set_swstart(true); }); while self.sr().read().strt() == false { // spin //wait for actual start } while self.sr().read().eoc() == false { // spin //wait for finish } } fn configure_dma(&self, conversion_mode: ConversionMode) { match conversion_mode { ConversionMode::Repeated(_) => { let r = self; // 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); }); } } } fn configure_sequence(&self, sequence: impl ExactSizeIterator) { self.cr2().modify(|reg| { reg.set_adon(true); }); // Check the sequence is long enough self.sqr1().modify(|r| { r.set_l((sequence.len() - 1).try_into().unwrap()); }); for (i, ((ch, _), sample_time)) in sequence.enumerate() { // Set the channel in the right sequence field. self.sqr3().modify(|w| w.set_sq(i, ch)); let sample_time = sample_time.into(); if ch <= 9 { self.smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); } else { self.smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); } } } } impl<'d, T> Adc<'d, T> where T: Instance, { pub fn new(adc: Peri<'d, T>) -> Self { Self::new_with_config(adc, Default::default()) } pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { rcc::enable_and_reset::(); let presc = from_pclk2(T::frequency()); T::common_regs().ccr().modify(|w| w.set_adcpre(presc)); T::regs().enable(); if let Some(resolution) = config.resolution { T::regs().cr1().modify(|reg| reg.set_res(resolution.into())); } Self { adc } } /// Enables internal voltage reference and returns [VrefInt], which can be used in /// [Adc::read_internal()] to perform conversion. pub fn enable_vrefint(&self) -> VrefInt { T::common_regs().ccr().modify(|reg| { reg.set_tsvrefe(true); }); VrefInt {} } /// Enables internal temperature sensor and returns [Temperature], which can be used in /// [Adc::read_internal()] to perform conversion. /// /// On STM32F42 and STM32F43 this can not be used together with [Vbat]. If both are enabled, /// temperature sensor will return vbat value. pub fn enable_temperature(&self) -> Temperature { T::common_regs().ccr().modify(|reg| { reg.set_tsvrefe(true); }); Temperature {} } /// Enables vbat input and returns [Vbat], which can be used in /// [Adc::read_internal()] to perform conversion. pub fn enable_vbat(&self) -> Vbat { T::common_regs().ccr().modify(|reg| { reg.set_vbate(true); }); Vbat {} } } impl<'d, T: Instance> Drop for Adc<'d, T> { fn drop(&mut self) { T::regs().stop(); rcc::disable::(); } }