From 4a0a11ac7aae9dd5edc623f2688fae91026802a0 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Thu, 14 Sep 2023 13:02:12 +0200 Subject: [PATCH] Add methods for checking for ADC overrun --- examples/adc-continious-dma.rs | 4 +++ src/adc.rs | 51 ++++++++++++++++++++++++++++++++++ src/dma/transfer.rs | 51 ++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/examples/adc-continious-dma.rs b/examples/adc-continious-dma.rs index 5f9b1bdd..5e3c81a1 100644 --- a/examples/adc-continious-dma.rs +++ b/examples/adc-continious-dma.rs @@ -69,6 +69,10 @@ fn main() -> ! { loop { let mut b = [0_u16; 4]; let r = transfer.read_exact(&mut b); + assert!( + !transfer.get_overrun_flag(), + "DMA did not have time to read the ADC value before ADC was done with a new conversion" + ); info!("read: {}", r); assert!(r == b.len()); diff --git a/src/adc.rs b/src/adc.rs index 44fe6461..c7100f2f 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -795,6 +795,7 @@ pub mod config { pub(crate) subgroup_len: SubGroupLength, pub(crate) dma: Dma, pub(crate) end_of_conversion_interrupt: Eoc, + pub(crate) overrun_interrupt: bool, pub(crate) default_sample_time: SampleTime, pub(crate) vdda: Option, pub(crate) auto_delay: bool, @@ -853,6 +854,15 @@ pub mod config { self.end_of_conversion_interrupt = end_of_conversion_interrupt; self } + + /// Enable/disable overrun interrupt + /// + /// This is triggered when the AD finishes a conversion before the last value was read by CPU/DMA + pub fn overrun_interrupt(mut self, enable: bool) -> Self { + self.overrun_interrupt = enable; + self + } + /// change the default_sample_time field #[inline(always)] pub fn default_sample_time(mut self, default_sample_time: SampleTime) -> Self { @@ -932,6 +942,7 @@ pub mod config { subgroup_len: SubGroupLength::One, dma: Dma::Disabled, end_of_conversion_interrupt: Eoc::Disabled, + overrun_interrupt: false, default_sample_time: SampleTime::Cycles_640_5, vdda: None, difsel: DifferentialSelection::default(), @@ -1525,6 +1536,7 @@ macro_rules! adc { self.set_subgroup_len(config.subgroup_len); self.set_dma(config.dma); self.set_end_of_conversion_interrupt(config.end_of_conversion_interrupt); + self.set_overrun_interrupt(config.overrun_interrupt); self.set_default_sample_time(config.default_sample_time); self.set_channel_input_type(config.difsel); self.set_auto_delay(config.auto_delay); @@ -1636,6 +1648,13 @@ macro_rules! adc { ); } + /// Enable/disable overrun interrupt + /// + /// This is triggered when the AD finishes a conversion before the last value was read by CPU/DMA + pub fn set_overrun_interrupt(&mut self, enable: bool) { + self.adc_reg.ier.modify(|_, w| w.ovrie().bit(enable)); + } + /// Sets the default sample time that is used for one-shot conversions. /// [configure_channel](#method.configure_channel) and [start_conversion](#method.start_conversion) can be \ /// used for configurations where different sampling times are required per channel. @@ -1919,6 +1938,18 @@ macro_rules! adc { pub fn is_vref_enabled(&mut self, common: &stm32::$common_type) -> bool { common.ccr.read().vrefen().bit_is_set() } + + /// Read overrun flag + #[inline(always)] + pub fn get_overrun_flag(&self) -> bool { + self.adc_reg.isr.read().ovr().bit() + } + + /// Resets the overrun flag + #[inline(always)] + pub fn clear_overrun_flag(&mut self) { + self.adc_reg.isr.modify(|_, w| w.ovr().set_bit()); + } } //TODO: claim now configures the clock for all ADCs in the group (12 and 345). @@ -2156,6 +2187,14 @@ macro_rules! adc { self.adc.set_end_of_conversion_interrupt(eoc) } + /// Enable/disable overrun interrupt + /// + /// This is triggered when the AD finishes a conversion before the last value was read by CPU/DMA + #[inline(always)] + pub fn set_overrun_interrupt(&mut self, enable: bool) { + self.adc.set_overrun_interrupt(enable) + } + /// Sets the default sample time that is used for one-shot conversions. /// [configure_channel](#method.configure_channel) and [start_conversion](#method.start_conversion) can be \ /// used for configurations where different sampling times are required per channel. @@ -2367,6 +2406,18 @@ macro_rules! adc { _status: PhantomData, } } + + /// Read overrun flag + #[inline(always)] + pub fn get_overrun_flag(&self) -> bool { + self.adc.get_overrun_flag() + } + + /// Resets the overrun flag + #[inline(always)] + pub fn clear_overrun_flag(&mut self) { + self.adc.clear_overrun_flag(); + } } unsafe impl TargetAddress for Adc { diff --git a/src/dma/transfer.rs b/src/dma/transfer.rs index febaf1f4..8ffda3b9 100644 --- a/src/dma/transfer.rs +++ b/src/dma/transfer.rs @@ -436,6 +436,57 @@ where } } +macro_rules! impl_adc_overrun { + ($($adc:ident, )*) => {$( + impl CircTransfer, BUF> + where + STREAM: Stream, + BUF: StaticWriteBuffer + Deref, + ::Target: Index, Output = [u16]> { + /// This is set when the AD finishes a conversion before the DMA has hade time to transfer the previous value + pub fn get_overrun_flag(&self) -> bool { + self.transfer.peripheral.get_overrun_flag() + } + + pub fn clear_overrun_flag(&mut self) { + self.transfer.peripheral.clear_overrun_flag(); + } + } + )*}; +} + +#[cfg(any( + feature = "stm32g431", + feature = "stm32g441", + feature = "stm32g471", + feature = "stm32g473", + feature = "stm32g474", + feature = "stm32g483", + feature = "stm32g484", + feature = "stm32g491", + feature = "stm32g4a1", +))] +impl_adc_overrun!(ADC1, ADC2,); + +#[cfg(any( + feature = "stm32g471", + feature = "stm32g473", + feature = "stm32g474", + feature = "stm32g483", + feature = "stm32g484", + feature = "stm32g491", + feature = "stm32g4a1", +))] +impl_adc_overrun!(ADC3,); + +#[cfg(any( + feature = "stm32g473", + feature = "stm32g474", + feature = "stm32g483", + feature = "stm32g484", +))] +impl_adc_overrun!(ADC4, ADC5,); + pub trait TransferExt where STREAM: traits::Stream,