diff options
| -rw-r--r-- | embassy-stm32/src/adc/f3.rs | 65 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 39 | ||||
| -rw-r--r-- | examples/stm32f334/src/bin/adc.rs | 23 |
3 files changed, 109 insertions, 18 deletions
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index b39d6ac8e..5d2ea1daa 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs | |||
| @@ -1,14 +1,36 @@ | |||
| 1 | use core::future::poll_fn; | ||
| 2 | use core::marker::PhantomData; | ||
| 3 | use core::task::Poll; | ||
| 4 | |||
| 1 | use embassy_hal_internal::into_ref; | 5 | use embassy_hal_internal::into_ref; |
| 2 | use embedded_hal_02::blocking::delay::DelayUs; | 6 | use embedded_hal_02::blocking::delay::DelayUs; |
| 3 | 7 | ||
| 4 | use crate::adc::{Adc, AdcPin, Instance, SampleTime}; | 8 | use crate::adc::{Adc, AdcPin, Instance, SampleTime}; |
| 9 | use crate::interrupt::typelevel::Interrupt; | ||
| 5 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 6 | use crate::Peripheral; | 11 | use crate::{interrupt, Peripheral}; |
| 7 | 12 | ||
| 8 | pub const VDDA_CALIB_MV: u32 = 3300; | 13 | pub const VDDA_CALIB_MV: u32 = 3300; |
| 9 | pub const ADC_MAX: u32 = (1 << 12) - 1; | 14 | pub const ADC_MAX: u32 = (1 << 12) - 1; |
| 10 | pub const VREF_INT: u32 = 1230; | 15 | pub const VREF_INT: u32 = 1230; |
| 11 | 16 | ||
| 17 | /// Interrupt handler. | ||
| 18 | pub struct InterruptHandler<T: Instance> { | ||
| 19 | _phantom: PhantomData<T>, | ||
| 20 | } | ||
| 21 | |||
| 22 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 23 | unsafe fn on_interrupt() { | ||
| 24 | if T::regs().isr().read().eoc() { | ||
| 25 | T::regs().ier().modify(|w| w.set_eocie(false)); | ||
| 26 | } else { | ||
| 27 | return; | ||
| 28 | } | ||
| 29 | |||
| 30 | T::state().waker.wake(); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 12 | pub struct Vref; | 34 | pub struct Vref; |
| 13 | impl<T: Instance> AdcPin<T> for Vref {} | 35 | impl<T: Instance> AdcPin<T> for Vref {} |
| 14 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { | 36 | impl<T: Instance> super::sealed::AdcPin<T> for Vref { |
| @@ -17,6 +39,13 @@ impl<T: Instance> super::sealed::AdcPin<T> for Vref { | |||
| 17 | } | 39 | } |
| 18 | } | 40 | } |
| 19 | 41 | ||
| 42 | impl Vref { | ||
| 43 | /// The value that vref would be if vdda was at 3300mv | ||
| 44 | pub fn value(&self) -> u16 { | ||
| 45 | crate::pac::VREFINTCAL.data().read().value() | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 20 | pub struct Temperature; | 49 | pub struct Temperature; |
| 21 | impl<T: Instance> AdcPin<T> for Temperature {} | 50 | impl<T: Instance> AdcPin<T> for Temperature {} |
| 22 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | 51 | impl<T: Instance> super::sealed::AdcPin<T> for Temperature { |
| @@ -26,7 +55,11 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature { | |||
| 26 | } | 55 | } |
| 27 | 56 | ||
| 28 | impl<'d, T: Instance> Adc<'d, T> { | 57 | impl<'d, T: Instance> Adc<'d, T> { |
| 29 | pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { | 58 | pub fn new( |
| 59 | adc: impl Peripheral<P = T> + 'd, | ||
| 60 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | ||
| 61 | delay: &mut impl DelayUs<u32>, | ||
| 62 | ) -> Self { | ||
| 30 | use crate::pac::adc::vals; | 63 | use crate::pac::adc::vals; |
| 31 | 64 | ||
| 32 | into_ref!(adc); | 65 | into_ref!(adc); |
| @@ -58,6 +91,11 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 58 | // Wait until the adc is ready | 91 | // Wait until the adc is ready |
| 59 | while !T::regs().isr().read().adrdy() {} | 92 | while !T::regs().isr().read().adrdy() {} |
| 60 | 93 | ||
| 94 | T::Interrupt::unpend(); | ||
| 95 | unsafe { | ||
| 96 | T::Interrupt::enable(); | ||
| 97 | } | ||
| 98 | |||
| 61 | Self { | 99 | Self { |
| 62 | adc, | 100 | adc, |
| 63 | sample_time: Default::default(), | 101 | sample_time: Default::default(), |
| @@ -97,30 +135,41 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 97 | } | 135 | } |
| 98 | 136 | ||
| 99 | /// Perform a single conversion. | 137 | /// Perform a single conversion. |
| 100 | fn convert(&mut self) -> u16 { | 138 | async fn convert(&mut self) -> u16 { |
| 101 | T::regs().isr().write(|_| {}); | 139 | T::regs().isr().write(|_| {}); |
| 140 | T::regs().ier().modify(|w| w.set_eocie(true)); | ||
| 102 | T::regs().cr().modify(|w| w.set_adstart(true)); | 141 | T::regs().cr().modify(|w| w.set_adstart(true)); |
| 103 | 142 | ||
| 104 | while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {} | 143 | poll_fn(|cx| { |
| 144 | T::state().waker.register(cx.waker()); | ||
| 145 | |||
| 146 | if T::regs().isr().read().eoc() { | ||
| 147 | Poll::Ready(()) | ||
| 148 | } else { | ||
| 149 | Poll::Pending | ||
| 150 | } | ||
| 151 | }) | ||
| 152 | .await; | ||
| 153 | |||
| 105 | T::regs().isr().write(|_| {}); | 154 | T::regs().isr().write(|_| {}); |
| 106 | 155 | ||
| 107 | T::regs().dr().read().rdata() | 156 | T::regs().dr().read().rdata() |
| 108 | } | 157 | } |
| 109 | 158 | ||
| 110 | pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { | 159 | pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 { |
| 111 | Self::set_channel_sample_time(pin.channel(), self.sample_time); | 160 | Self::set_channel_sample_time(pin.channel(), self.sample_time); |
| 112 | 161 | ||
| 113 | // Configure the channel to sample | 162 | // Configure the channel to sample |
| 114 | T::regs().sqr1().write(|w| w.set_sq(0, pin.channel())); | 163 | T::regs().sqr1().write(|w| w.set_sq(0, pin.channel())); |
| 115 | self.convert() | 164 | self.convert().await |
| 116 | } | 165 | } |
| 117 | 166 | ||
| 118 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { | 167 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
| 119 | let sample_time = sample_time.into(); | 168 | let sample_time = sample_time.into(); |
| 120 | if ch <= 9 { | 169 | if ch <= 9 { |
| 121 | T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time)); | 170 | T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); |
| 122 | } else { | 171 | } else { |
| 123 | T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); | 172 | T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); |
| 124 | } | 173 | } |
| 125 | } | 174 | } |
| 126 | } | 175 | } |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 9334deac4..e74913da8 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -31,12 +31,35 @@ pub struct Adc<'d, T: Instance> { | |||
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | pub(crate) mod sealed { | 33 | pub(crate) mod sealed { |
| 34 | pub trait Instance { | 34 | #[cfg(adc_f3)] |
| 35 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 36 | |||
| 37 | #[cfg(adc_f3)] | ||
| 38 | pub struct State { | ||
| 39 | pub waker: AtomicWaker, | ||
| 40 | } | ||
| 41 | |||
| 42 | #[cfg(adc_f3)] | ||
| 43 | impl State { | ||
| 44 | pub const fn new() -> Self { | ||
| 45 | Self { | ||
| 46 | waker: AtomicWaker::new(), | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | pub trait InterruptableInstance { | ||
| 52 | type Interrupt: crate::interrupt::typelevel::Interrupt; | ||
| 53 | } | ||
| 54 | |||
| 55 | pub trait Instance: InterruptableInstance { | ||
| 35 | fn regs() -> crate::pac::adc::Adc; | 56 | fn regs() -> crate::pac::adc::Adc; |
| 36 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] | 57 | #[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))] |
| 37 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 58 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 38 | #[cfg(adc_f3)] | 59 | #[cfg(adc_f3)] |
| 39 | fn frequency() -> crate::time::Hertz; | 60 | fn frequency() -> crate::time::Hertz; |
| 61 | #[cfg(adc_f3)] | ||
| 62 | fn state() -> &'static State; | ||
| 40 | } | 63 | } |
| 41 | 64 | ||
| 42 | pub trait AdcPin<T: Instance> { | 65 | pub trait AdcPin<T: Instance> { |
| @@ -72,8 +95,22 @@ foreach_adc!( | |||
| 72 | fn frequency() -> crate::time::Hertz { | 95 | fn frequency() -> crate::time::Hertz { |
| 73 | unsafe { crate::rcc::get_freqs() }.$clock.unwrap() | 96 | unsafe { crate::rcc::get_freqs() }.$clock.unwrap() |
| 74 | } | 97 | } |
| 98 | |||
| 99 | #[cfg(adc_f3)] | ||
| 100 | fn state() -> &'static sealed::State { | ||
| 101 | static STATE: sealed::State = sealed::State::new(); | ||
| 102 | &STATE | ||
| 103 | } | ||
| 75 | } | 104 | } |
| 76 | 105 | ||
| 106 | foreach_interrupt!( | ||
| 107 | ($inst,adc,ADC,GLOBAL,$irq:ident) => { | ||
| 108 | impl sealed::InterruptableInstance for peripherals::$inst { | ||
| 109 | type Interrupt = crate::interrupt::typelevel::$irq; | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | ); | ||
| 113 | |||
| 77 | impl crate::adc::Instance for peripherals::$inst {} | 114 | impl crate::adc::Instance for peripherals::$inst {} |
| 78 | }; | 115 | }; |
| 79 | ); | 116 | ); |
diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index e8b2cd8a7..ed246a7db 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs | |||
| @@ -4,13 +4,18 @@ | |||
| 4 | 4 | ||
| 5 | use defmt::info; | 5 | use defmt::info; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::adc::{Adc, SampleTime, VREF_INT}; | 7 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 8 | use embassy_stm32::peripherals::ADC1; | ||
| 8 | use embassy_stm32::rcc::AdcClockSource; | 9 | use embassy_stm32::rcc::AdcClockSource; |
| 9 | use embassy_stm32::time::mhz; | 10 | use embassy_stm32::time::mhz; |
| 10 | use embassy_stm32::Config; | 11 | use embassy_stm32::{adc, bind_interrupts, Config}; |
| 11 | use embassy_time::{Delay, Duration, Timer}; | 12 | use embassy_time::{Delay, Duration, Timer}; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | ||
| 16 | ADC1_2 => adc::InterruptHandler<ADC1>; | ||
| 17 | }); | ||
| 18 | |||
| 14 | #[embassy_executor::main] | 19 | #[embassy_executor::main] |
| 15 | async fn main(_spawner: Spawner) -> ! { | 20 | async fn main(_spawner: Spawner) -> ! { |
| 16 | let mut config = Config::default(); | 21 | let mut config = Config::default(); |
| @@ -24,7 +29,7 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 24 | 29 | ||
| 25 | info!("create adc..."); | 30 | info!("create adc..."); |
| 26 | 31 | ||
| 27 | let mut adc = Adc::new(p.ADC1, &mut Delay); | 32 | let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); |
| 28 | 33 | ||
| 29 | adc.set_sample_time(SampleTime::Cycles601_5); | 34 | adc.set_sample_time(SampleTime::Cycles601_5); |
| 30 | 35 | ||
| @@ -34,18 +39,18 @@ async fn main(_spawner: Spawner) -> ! { | |||
| 34 | let mut temperature = adc.enable_temperature(); | 39 | let mut temperature = adc.enable_temperature(); |
| 35 | 40 | ||
| 36 | loop { | 41 | loop { |
| 37 | let vref = adc.read(&mut vrefint); | 42 | let vref = adc.read(&mut vrefint).await; |
| 38 | info!("read vref: {}", vref); | 43 | info!("read vref: {} (should be {})", vref, vrefint.value()); |
| 39 | 44 | ||
| 40 | let temp = adc.read(&mut temperature); | 45 | let temp = adc.read(&mut temperature).await; |
| 41 | info!("read temperature: {}", temp); | 46 | info!("read temperature: {}", temp); |
| 42 | 47 | ||
| 43 | let pin = adc.read(&mut p.PA0); | 48 | let pin = adc.read(&mut p.PA0).await; |
| 44 | info!("read pin: {}", pin); | 49 | info!("read pin: {}", pin); |
| 45 | 50 | ||
| 46 | let pin_mv = pin as u32 * VREF_INT as u32 / vref as u32; | 51 | let pin_mv = (pin as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095; |
| 47 | info!("computed pin mv: {}", pin_mv); | 52 | info!("computed pin mv: {}", pin_mv); |
| 48 | 53 | ||
| 49 | Timer::after(Duration::from_secs(1)).await; | 54 | Timer::after(Duration::from_millis(500)).await; |
| 50 | } | 55 | } |
| 51 | } | 56 | } |
