diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 147349de..c1326481 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -1,16 +1,37 @@ +use core::future::poll_fn; +use core::marker::PhantomData; +use core::task::Poll; + use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::rcc::get_freqs; use crate::time::Hertz; -use crate::Peripheral; +use crate::{interrupt, Peripheral}; pub const VDDA_CALIB_MV: u32 = 3300; pub const ADC_MAX: u32 = (1 << 12) - 1; // No calibration data for F103, voltage should be 1.2v pub const VREF_INT: u32 = 1200; +/// 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 Vref; impl AdcPin for Vref {} impl super::sealed::AdcPin for Vref { @@ -95,18 +116,28 @@ impl<'d, T: Instance> Adc<'d, T> { } /// Perform a single conversion. - fn convert(&mut self) -> u16 { + async fn convert(&mut self) -> u16 { T::regs().cr2().modify(|reg| { reg.set_adon(true); reg.set_swstart(true); }); - while T::regs().cr2().read().swstart() {} - while !T::regs().sr().read().eoc() {} + T::regs().cr1().modify(|w| w.set_eocie(true)); + + poll_fn(|cx| { + T::state().waker.register(cx.waker()); + + if !T::regs().cr2().read().swstart() && T::regs().sr().read().eoc() { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; T::regs().dr().read().0 as u16 } - pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { Self::set_channel_sample_time(pin.channel(), self.sample_time); T::regs().cr1().modify(|reg| { reg.set_scan(false); @@ -123,7 +154,7 @@ impl<'d, T: Instance> Adc<'d, T> { // Configure the channel to sample T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel())); - self.convert() + self.convert().await } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { @@ -135,3 +166,11 @@ impl<'d, T: Instance> Adc<'d, T> { } } } + +impl<'d, T: Instance> Drop for Adc<'d, T> { + fn drop(&mut self) { + T::regs().cr2().modify(|reg| reg.set_adon(false)); + + T::disable(); + } +} diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 5d2ea1da..7c13f810 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -173,3 +173,23 @@ impl<'d, T: Instance> Adc<'d, T> { } } } + +impl<'d, T: Instance> Drop for Adc<'d, T> { + fn drop(&mut self) { + use crate::pac::adc::vals; + + T::regs().cr().modify(|w| w.set_adstp(true)); + + while T::regs().cr().read().adstp() {} + + T::regs().cr().modify(|w| w.set_addis(true)); + + while T::regs().cr().read().aden() {} + + // Disable the adc regulator + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); + T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED)); + + T::disable(); + } +} diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 2f8f8f9e..365738a3 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -31,15 +31,15 @@ pub struct Adc<'d, T: Instance> { } pub(crate) mod sealed { - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] use embassy_sync::waitqueue::AtomicWaker; - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] pub struct State { pub waker: AtomicWaker, } - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] impl State { pub const fn new() -> Self { Self { @@ -58,11 +58,14 @@ pub(crate) mod sealed { fn common_regs() -> crate::pac::adccommon::AdcCommon; #[cfg(adc_f3)] fn frequency() -> crate::time::Hertz; - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] fn state() -> &'static State; } pub trait AdcPin { + #[cfg(any(adc_v1, adc_v2))] + fn set_as_analog(&mut self) {} + fn channel(&self) -> u8; } @@ -96,7 +99,7 @@ foreach_adc!( unsafe { crate::rcc::get_freqs() }.$clock.unwrap() } - #[cfg(any(adc_f3, adc_v1))] + #[cfg(any(adc_f1, adc_f3, adc_v1))] fn state() -> &'static sealed::State { static STATE: sealed::State = sealed::State::new(); &STATE @@ -120,6 +123,11 @@ macro_rules! impl_adc_pin { impl crate::adc::AdcPin for crate::peripherals::$pin {} impl crate::adc::sealed::AdcPin for crate::peripherals::$pin { + #[cfg(any(adc_v1, adc_v2))] + fn set_as_analog(&mut self) { + ::set_as_analog(self); + } + fn channel(&self) -> u8 { $ch } diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 15b2dc59..fded26e4 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -5,7 +5,7 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; +use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; use crate::{interrupt, Peripheral}; @@ -31,24 +31,24 @@ impl interrupt::typelevel::Handler for InterruptHandl } pub struct Vbat; -impl InternalChannel for Vbat {} -impl super::sealed::InternalChannel for Vbat { +impl AdcPin for Vbat {} +impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { 18 } } pub struct Vref; -impl InternalChannel for Vref {} -impl super::sealed::InternalChannel for Vref { +impl AdcPin for Vref {} +impl super::sealed::AdcPin for Vref { fn channel(&self) -> u8 { 17 } } pub struct Temperature; -impl InternalChannel for Temperature {} -impl super::sealed::InternalChannel for Temperature { +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { 16 } @@ -134,18 +134,14 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); } - pub async fn read

(&mut self, pin: &mut P) -> u16 - where - P: AdcPin + crate::gpio::sealed::Pin, - { + pub async fn read(&mut self, pin: &mut impl AdcPin) -> u16 { let channel = pin.channel(); pin.set_as_analog(); - self.read_channel(channel).await - } - pub async fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { - let channel = channel.channel(); - self.read_channel(channel).await + // A.7.5 Single conversion sequence code example - Software trigger + T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); + + self.convert().await } async fn convert(&mut self) -> u16 { @@ -171,13 +167,6 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().dr().read().data() } - - async fn read_channel(&mut self, channel: u8) -> u16 { - // A.7.5 Single conversion sequence code example - Software trigger - T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); - - self.convert().await - } } impl<'d, T: Instance> Drop for Adc<'d, T> { diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index f583c08a..a669013c 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,7 +1,6 @@ use embassy_hal_internal::into_ref; use embedded_hal_02::blocking::delay::DelayUs; -use super::InternalChannel; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; @@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300; pub const ADC_POWERUP_TIME_US: u32 = 3; pub struct VrefInt; -impl InternalChannel for VrefInt {} -impl super::sealed::InternalChannel for VrefInt { +impl AdcPin for VrefInt {} +impl super::sealed::AdcPin for VrefInt { fn channel(&self) -> u8 { 17 } @@ -31,8 +30,8 @@ impl VrefInt { } pub struct Temperature; -impl InternalChannel for Temperature {} -impl super::sealed::InternalChannel for Temperature { +impl AdcPin for Temperature {} +impl super::sealed::AdcPin for Temperature { fn channel(&self) -> u8 { cfg_if::cfg_if! { if #[cfg(any(stm32f40, stm32f41))] { @@ -52,8 +51,8 @@ impl Temperature { } pub struct Vbat; -impl InternalChannel for Vbat {} -impl super::sealed::InternalChannel for Vbat { +impl AdcPin for Vbat {} +impl super::sealed::AdcPin for Vbat { fn channel(&self) -> u8 { 18 } @@ -176,22 +175,11 @@ where T::regs().dr().read().0 as u16 } - pub fn read

(&mut self, pin: &mut P) -> u16 - where - P: AdcPin, - P: crate::gpio::sealed::Pin, - { + pub fn read(&mut self, pin: &mut impl AdcPin) -> u16 { pin.set_as_analog(); - self.read_channel(pin.channel()) - } - - pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { - self.read_channel(channel.channel()) - } - - fn read_channel(&mut self, channel: u8) -> u16 { // Configure ADC + let channel = pin.channel(); // Select channel T::regs().sqr3().write(|reg| reg.set_sq(0, channel)); @@ -199,9 +187,7 @@ where // Configure channel Self::set_channel_sample_time(channel, self.sample_time); - let val = self.convert(); - - val + self.convert() } fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { @@ -216,6 +202,10 @@ where impl<'d, T: Instance> Drop for Adc<'d, T> { fn drop(&mut self) { + T::regs().cr2().modify(|reg| { + reg.set_adon(false); + }); + T::disable(); } } diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 2ed46a94..1564ecfc 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { let mut pin = p.PA1; let mut vrefint = adc.enable_vref(&mut Delay); - let vrefint_sample = adc.read_internal(&mut vrefint).await; + let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf // 6.3.4 Embedded reference voltage diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs index ed59e279..30947c3c 100644 --- a/examples/stm32f1/src/bin/adc.rs +++ b/examples/stm32f1/src/bin/adc.rs @@ -5,9 +5,15 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::Adc; +use embassy_stm32::peripherals::ADC1; +use embassy_stm32::{adc, bind_interrupts}; use embassy_time::{Delay, Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; +bind_interrupts!(struct Irqs { + ADC1_2 => adc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); @@ -17,7 +23,7 @@ async fn main(_spawner: Spawner) { let mut pin = p.PB1; let mut vrefint = adc.enable_vref(&mut Delay); - let vrefint_sample = adc.read(&mut vrefint); + let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/CD00161566.pdf // 5.3.4 Embedded reference voltage @@ -27,7 +33,7 @@ async fn main(_spawner: Spawner) { }; loop { - let v = adc.read(&mut pin); + let v = adc.read(&mut pin).await; info!("--> {} - {} mV", v, convert_to_millivolts(v)); Timer::after(Duration::from_millis(100)).await; } diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 1c9a0b35..dd10385c 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs @@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) { // Startup delay can be combined to the maximum of either delay.delay_us(Temperature::start_time_us().max(VrefInt::start_time_us())); - let vrefint_sample = adc.read_internal(&mut vrefint); + let vrefint_sample = adc.read(&mut vrefint); let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/DM00071990.pdf @@ -55,12 +55,12 @@ async fn main(_spawner: Spawner) { info!("PC1: {} ({} mV)", v, convert_to_millivolts(v)); // Read internal temperature - let v = adc.read_internal(&mut temp); + let v = adc.read(&mut temp); let celcius = convert_to_celcius(v); info!("Internal temp: {} ({} C)", v, celcius); // Read internal voltage reference - let v = adc.read_internal(&mut vrefint); + let v = adc.read(&mut vrefint); info!("VrefInt: {}", v); Timer::after(Duration::from_millis(100)).await; diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs index 70b3b2a7..bc4ed289 100644 --- a/examples/stm32f7/src/bin/adc.rs +++ b/examples/stm32f7/src/bin/adc.rs @@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) { let mut pin = p.PA3; let mut vrefint = adc.enable_vrefint(); - let vrefint_sample = adc.read_internal(&mut vrefint); + let vrefint_sample = adc.read(&mut vrefint); let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/DM00273119.pdf // 6.3.27 Reference voltage