From fc9e381bb0c5602dc1d94fa25e4b47de17cdfa1a Mon Sep 17 00:00:00 2001 From: Christopher <63494008+Christopher-06@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:39:05 +0000 Subject: [PATCH 1/2] Add async single adc readings --- embassy-stm32/src/adc/v2.rs | 40 +++++++++++++++++++++++++++++---- examples/stm32f4/src/bin/adc.rs | 14 ++++++------ 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 842a5ee6dc..3dee0f4c8f 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,3 +1,6 @@ +use core::future::poll_fn; +use core::task::Poll; + use embassy_hal_internal::into_ref; use super::blocking_delay_us; @@ -156,8 +159,7 @@ where Vbat {} } - /// Perform a single conversion. - fn convert(&mut self) -> u16 { + fn start_conversion(&mut self) { // clear end of conversion flag T::regs().sr().modify(|reg| { reg.set_eoc(false); @@ -167,6 +169,28 @@ where T::regs().cr2().modify(|reg| { reg.set_swstart(true); }); + } + + /// Perform a single conversion asynchronously. + async fn convert(&mut self) -> u16 { + self.start_conversion(); + + // wait for actual start and then finish + poll_fn(|_| { + if T::regs().sr().read().strt() && T::regs().sr().read().eoc() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; + + T::regs().dr().read().0 as u16 + } + + /// Perform a single conversion. + fn blocking_convert(&mut self) -> u16 { + self.start_conversion(); while T::regs().sr().read().strt() == false { // spin //wait for actual start @@ -178,7 +202,7 @@ where T::regs().dr().read().0 as u16 } - pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + fn configure_channel_reading(&mut self, channel: &mut impl AdcChannel) { channel.setup(); // Configure ADC @@ -189,8 +213,16 @@ where // Configure channel Self::set_channel_sample_time(channel, self.sample_time); + } + + pub async fn read(&mut self, channel: &mut impl AdcChannel) -> u16 { + self.configure_channel_reading(channel); + self.convert().await + } - self.convert() + pub fn blocking_read(&mut self, channel: &mut impl AdcChannel) -> u16 { + self.configure_channel_reading(channel); + self.blocking_convert() } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 423d292258..81b6891486 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs @@ -24,6 +24,7 @@ async fn main(_spawner: Spawner) { delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); let vrefint_sample = adc.blocking_read(&mut vrefint); + info!("VrefInt: {}", vrefint_sample); let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/DM00071990.pdf @@ -44,22 +45,21 @@ async fn main(_spawner: Spawner) { (sample_mv - V25) as f32 / AVG_SLOPE + 25.0 }; - info!("VrefInt: {}", vrefint_sample); const MAX_ADC_SAMPLE: u16 = (1 << 12) - 1; info!("VCCA: {} mV", convert_to_millivolts(MAX_ADC_SAMPLE)); loop { - // Read pin - let v = adc.blocking_read(&mut pin); + // Read pin asynchronously + let v = adc.read(&mut pin).await; info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); - // Read internal temperature - let v = adc.blocking_read(&mut temp); + // Read internal temperature asynchronously + let v = adc.read(&mut temp).await; let celcius = convert_to_celcius(v); info!("Internal temp: {} ({} C)", v, celcius); - // Read internal voltage reference - let v = adc.blocking_read(&mut vrefint); + // Read internal voltage reference asynchronously + let v = adc.read(&mut vrefint).await; info!("VrefInt: {}", v); Timer::after_millis(100).await; From 085127bb4dc340beb7449a47760bba4c5739701f Mon Sep 17 00:00:00 2001 From: Christopher <63494008+Christopher-06@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:56:22 +0000 Subject: [PATCH 2/2] Register ADC Waker --- embassy-stm32/src/adc/mod.rs | 10 +++++----- embassy-stm32/src/adc/v2.rs | 28 +++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 36898b8f97..7be5b83f26 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -21,7 +21,7 @@ use core::marker::PhantomData; #[allow(unused)] #[cfg(not(any(adc_f3_v2)))] pub use _version::*; -#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +#[cfg(any(adc_f1, adc_v2, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] use embassy_sync::waitqueue::AtomicWaker; #[cfg(adc_u5)] @@ -46,12 +46,12 @@ pub struct Adc<'d, T: Instance> { sample_time: SampleTime, } -#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +#[cfg(any(adc_f1, adc_v2, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] pub struct State { pub waker: AtomicWaker, } -#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +#[cfg(any(adc_f1, adc_v2, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] impl State { pub const fn new() -> Self { Self { @@ -66,7 +66,7 @@ trait SealedInstance { #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] #[allow(unused)] fn common_regs() -> crate::pac::adccommon::AdcCommon; - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_v2, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] fn state() -> &'static State; } @@ -208,7 +208,7 @@ foreach_adc!( return crate::pac::$common_inst } - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_v2, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] fn state() -> &'static State { static STATE: State = State::new(); &STATE diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 3dee0f4c8f..f0617ebfca 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,4 +1,5 @@ use core::future::poll_fn; +use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; @@ -7,7 +8,7 @@ use super::blocking_delay_us; use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; -use crate::{rcc, Peripheral}; +use crate::{interrupt, rcc, Peripheral}; mod ringbuffered_v2; pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; @@ -17,6 +18,23 @@ pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3300; +/// Interrupt handler. +pub struct InterruptHandler { + _phantom: PhantomData, +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + if T::regs().sr().read().eoc() { + T::regs().cr1().modify(|w| w.set_eocie(false)); + } else { + return; + } + + T::state().waker.wake(); + } +} + pub struct VrefInt; impl AdcChannel for VrefInt {} impl super::SealedAdcChannel for VrefInt { @@ -175,8 +193,12 @@ where async fn convert(&mut self) -> u16 { self.start_conversion(); - // wait for actual start and then finish - poll_fn(|_| { + T::regs().cr1().modify(|w| w.set_eocie(true)); + + // wait for actual start and finish + poll_fn(|cx| { + T::state().waker.register(cx.waker()); + if T::regs().sr().read().strt() && T::regs().sr().read().eoc() { Poll::Ready(()) } else {