diff options
| author | xoviat <[email protected]> | 2023-09-20 16:07:35 -0500 |
|---|---|---|
| committer | xoviat <[email protected]> | 2023-09-20 16:07:35 -0500 |
| commit | d46920dce692859e0818a6171c930af270a7a02f (patch) | |
| tree | 0e9af554ade705f0e7769cfc9238169d3521fa36 | |
| parent | c573959a956802eb177d04fa5b7802397af19f93 (diff) | |
stm32/adc: make v1 async and leave en
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 10 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v1.rs | 137 | ||||
| -rw-r--r-- | examples/stm32f0/src/bin/adc.rs | 12 |
3 files changed, 100 insertions, 59 deletions
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index e74913da8..2f8f8f9e3 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> { | |||
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | pub(crate) mod sealed { | 33 | pub(crate) mod sealed { |
| 34 | #[cfg(adc_f3)] | 34 | #[cfg(any(adc_f3, adc_v1))] |
| 35 | use embassy_sync::waitqueue::AtomicWaker; | 35 | use embassy_sync::waitqueue::AtomicWaker; |
| 36 | 36 | ||
| 37 | #[cfg(adc_f3)] | 37 | #[cfg(any(adc_f3, adc_v1))] |
| 38 | pub struct State { | 38 | pub struct State { |
| 39 | pub waker: AtomicWaker, | 39 | pub waker: AtomicWaker, |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | #[cfg(adc_f3)] | 42 | #[cfg(any(adc_f3, adc_v1))] |
| 43 | impl State { | 43 | impl State { |
| 44 | pub const fn new() -> Self { | 44 | pub const fn new() -> Self { |
| 45 | Self { | 45 | Self { |
| @@ -58,7 +58,7 @@ pub(crate) mod sealed { | |||
| 58 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 58 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| 59 | #[cfg(adc_f3)] | 59 | #[cfg(adc_f3)] |
| 60 | fn frequency() -> crate::time::Hertz; | 60 | fn frequency() -> crate::time::Hertz; |
| 61 | #[cfg(adc_f3)] | 61 | #[cfg(any(adc_f3, adc_v1))] |
| 62 | fn state() -> &'static State; | 62 | fn state() -> &'static State; |
| 63 | } | 63 | } |
| 64 | 64 | ||
| @@ -96,7 +96,7 @@ foreach_adc!( | |||
| 96 | unsafe { crate::rcc::get_freqs() }.$clock.unwrap() | 96 | unsafe { crate::rcc::get_freqs() }.$clock.unwrap() |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | #[cfg(adc_f3)] | 99 | #[cfg(any(adc_f3, adc_v1))] |
| 100 | fn state() -> &'static sealed::State { | 100 | fn state() -> &'static sealed::State { |
| 101 | static STATE: sealed::State = sealed::State::new(); | 101 | static STATE: sealed::State = sealed::State::new(); |
| 102 | &STATE | 102 | &STATE |
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index e8245884e..15b2dc593 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs | |||
| @@ -1,13 +1,35 @@ | |||
| 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, InternalChannel, Resolution, SampleTime}; | 8 | use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; |
| 9 | use crate::interrupt::typelevel::Interrupt; | ||
| 5 | use crate::peripherals::ADC; | 10 | use crate::peripherals::ADC; |
| 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 VREF_INT: u32 = 1230; | 14 | pub const VREF_INT: u32 = 1230; |
| 10 | 15 | ||
| 16 | /// Interrupt handler. | ||
| 17 | pub struct InterruptHandler<T: Instance> { | ||
| 18 | _phantom: PhantomData<T>, | ||
| 19 | } | ||
| 20 | |||
| 21 | impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { | ||
| 22 | unsafe fn on_interrupt() { | ||
| 23 | if T::regs().isr().read().eoc() { | ||
| 24 | T::regs().ier().modify(|w| w.set_eocie(false)); | ||
| 25 | } else { | ||
| 26 | return; | ||
| 27 | } | ||
| 28 | |||
| 29 | T::state().waker.wake(); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 11 | pub struct Vbat; | 33 | pub struct Vbat; |
| 12 | impl InternalChannel<ADC> for Vbat {} | 34 | impl InternalChannel<ADC> for Vbat {} |
| 13 | impl super::sealed::InternalChannel<ADC> for Vbat { | 35 | impl super::sealed::InternalChannel<ADC> for Vbat { |
| @@ -33,7 +55,11 @@ impl super::sealed::InternalChannel<ADC> for Temperature { | |||
| 33 | } | 55 | } |
| 34 | 56 | ||
| 35 | impl<'d, T: Instance> Adc<'d, T> { | 57 | impl<'d, T: Instance> Adc<'d, T> { |
| 36 | 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 { | ||
| 37 | into_ref!(adc); | 63 | into_ref!(adc); |
| 38 | T::enable(); | 64 | T::enable(); |
| 39 | T::reset(); | 65 | T::reset(); |
| @@ -44,12 +70,32 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 44 | // tstab = 14 * 1/fadc | 70 | // tstab = 14 * 1/fadc |
| 45 | delay.delay_us(1); | 71 | delay.delay_us(1); |
| 46 | 72 | ||
| 47 | let s = Self { | 73 | // A.7.1 ADC calibration code example |
| 74 | T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); | ||
| 75 | T::regs().cr().modify(|reg| reg.set_adcal(true)); | ||
| 76 | while T::regs().cr().read().adcal() {} | ||
| 77 | |||
| 78 | // A.7.2 ADC enable sequence code example | ||
| 79 | if T::regs().isr().read().adrdy() { | ||
| 80 | T::regs().isr().modify(|reg| reg.set_adrdy(true)); | ||
| 81 | } | ||
| 82 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 83 | while !T::regs().isr().read().adrdy() { | ||
| 84 | // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration | ||
| 85 | // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the | ||
| 86 | // ADEN bit until the ADRDY flag goes high. | ||
| 87 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 88 | } | ||
| 89 | |||
| 90 | T::Interrupt::unpend(); | ||
| 91 | unsafe { | ||
| 92 | T::Interrupt::enable(); | ||
| 93 | } | ||
| 94 | |||
| 95 | Self { | ||
| 48 | adc, | 96 | adc, |
| 49 | sample_time: Default::default(), | 97 | sample_time: Default::default(), |
| 50 | }; | 98 | } |
| 51 | s.calibrate(); | ||
| 52 | s | ||
| 53 | } | 99 | } |
| 54 | 100 | ||
| 55 | pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { | 101 | pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat { |
| @@ -80,21 +126,6 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 80 | Temperature | 126 | Temperature |
| 81 | } | 127 | } |
| 82 | 128 | ||
| 83 | fn calibrate(&self) { | ||
| 84 | // A.7.1 ADC calibration code example | ||
| 85 | if T::regs().cr().read().aden() { | ||
| 86 | T::regs().cr().modify(|reg| reg.set_addis(true)); | ||
| 87 | } | ||
| 88 | while T::regs().cr().read().aden() { | ||
| 89 | // spin | ||
| 90 | } | ||
| 91 | T::regs().cfgr1().modify(|reg| reg.set_dmaen(false)); | ||
| 92 | T::regs().cr().modify(|reg| reg.set_adcal(true)); | ||
| 93 | while T::regs().cr().read().adcal() { | ||
| 94 | // spin | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { | 129 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { |
| 99 | self.sample_time = sample_time; | 130 | self.sample_time = sample_time; |
| 100 | } | 131 | } |
| @@ -103,57 +134,61 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 103 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); | 134 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into())); |
| 104 | } | 135 | } |
| 105 | 136 | ||
| 106 | pub fn read<P>(&mut self, pin: &mut P) -> u16 | 137 | pub async fn read<P>(&mut self, pin: &mut P) -> u16 |
| 107 | where | 138 | where |
| 108 | P: AdcPin<T> + crate::gpio::sealed::Pin, | 139 | P: AdcPin<T> + crate::gpio::sealed::Pin, |
| 109 | { | 140 | { |
| 110 | let channel = pin.channel(); | 141 | let channel = pin.channel(); |
| 111 | pin.set_as_analog(); | 142 | pin.set_as_analog(); |
| 112 | self.read_channel(channel) | 143 | self.read_channel(channel).await |
| 113 | } | 144 | } |
| 114 | 145 | ||
| 115 | pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { | 146 | pub async fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 { |
| 116 | let channel = channel.channel(); | 147 | let channel = channel.channel(); |
| 117 | self.read_channel(channel) | 148 | self.read_channel(channel).await |
| 118 | } | 149 | } |
| 119 | 150 | ||
| 120 | fn read_channel(&mut self, channel: u8) -> u16 { | 151 | async fn convert(&mut self) -> u16 { |
| 121 | // A.7.2 ADC enable sequence code example | ||
| 122 | if T::regs().isr().read().adrdy() { | ||
| 123 | T::regs().isr().modify(|reg| reg.set_adrdy(true)); | ||
| 124 | } | ||
| 125 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 126 | while !T::regs().isr().read().adrdy() { | ||
| 127 | // ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration | ||
| 128 | // Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the | ||
| 129 | // ADEN bit until the ADRDY flag goes high. | ||
| 130 | T::regs().cr().modify(|reg| reg.set_aden(true)); | ||
| 131 | } | ||
| 132 | |||
| 133 | T::regs().isr().modify(|reg| { | 152 | T::regs().isr().modify(|reg| { |
| 134 | reg.set_eoc(true); | 153 | reg.set_eoc(true); |
| 135 | reg.set_eosmp(true); | 154 | reg.set_eosmp(true); |
| 136 | }); | 155 | }); |
| 137 | 156 | ||
| 138 | // A.7.5 Single conversion sequence code example - Software trigger | ||
| 139 | T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); | ||
| 140 | T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); | 157 | T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into())); |
| 158 | T::regs().ier().modify(|w| w.set_eocie(true)); | ||
| 141 | T::regs().cr().modify(|reg| reg.set_adstart(true)); | 159 | T::regs().cr().modify(|reg| reg.set_adstart(true)); |
| 142 | while !T::regs().isr().read().eoc() { | ||
| 143 | // spin | ||
| 144 | } | ||
| 145 | let value = T::regs().dr().read().0 as u16; | ||
| 146 | 160 | ||
| 161 | poll_fn(|cx| { | ||
| 162 | T::state().waker.register(cx.waker()); | ||
| 163 | |||
| 164 | if T::regs().isr().read().eoc() { | ||
| 165 | Poll::Ready(()) | ||
| 166 | } else { | ||
| 167 | Poll::Pending | ||
| 168 | } | ||
| 169 | }) | ||
| 170 | .await; | ||
| 171 | |||
| 172 | T::regs().dr().read().data() | ||
| 173 | } | ||
| 174 | |||
| 175 | async fn read_channel(&mut self, channel: u8) -> u16 { | ||
| 176 | // A.7.5 Single conversion sequence code example - Software trigger | ||
| 177 | T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true)); | ||
| 178 | |||
| 179 | self.convert().await | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | impl<'d, T: Instance> Drop for Adc<'d, T> { | ||
| 184 | fn drop(&mut self) { | ||
| 147 | // A.7.3 ADC disable code example | 185 | // A.7.3 ADC disable code example |
| 148 | T::regs().cr().modify(|reg| reg.set_adstp(true)); | 186 | T::regs().cr().modify(|reg| reg.set_adstp(true)); |
| 149 | while T::regs().cr().read().adstp() { | 187 | while T::regs().cr().read().adstp() {} |
| 150 | // spin | 188 | |
| 151 | } | ||
| 152 | T::regs().cr().modify(|reg| reg.set_addis(true)); | 189 | T::regs().cr().modify(|reg| reg.set_addis(true)); |
| 153 | while T::regs().cr().read().aden() { | 190 | while T::regs().cr().read().aden() {} |
| 154 | // spin | ||
| 155 | } | ||
| 156 | 191 | ||
| 157 | value | 192 | T::disable(); |
| 158 | } | 193 | } |
| 159 | } | 194 | } |
diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index 8ed9f98f8..2ed46a944 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs | |||
| @@ -5,20 +5,26 @@ | |||
| 5 | use defmt::*; | 5 | use defmt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::adc::{Adc, SampleTime}; | 7 | use embassy_stm32::adc::{Adc, SampleTime}; |
| 8 | use embassy_stm32::peripherals::ADC; | ||
| 9 | use embassy_stm32::{adc, bind_interrupts}; | ||
| 8 | use embassy_time::{Delay, Duration, Timer}; | 10 | use embassy_time::{Delay, Duration, Timer}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 12 | ||
| 13 | bind_interrupts!(struct Irqs { | ||
| 14 | ADC1_COMP => adc::InterruptHandler<ADC>; | ||
| 15 | }); | ||
| 16 | |||
| 11 | #[embassy_executor::main] | 17 | #[embassy_executor::main] |
| 12 | async fn main(_spawner: Spawner) { | 18 | async fn main(_spawner: Spawner) { |
| 13 | let p = embassy_stm32::init(Default::default()); | 19 | let p = embassy_stm32::init(Default::default()); |
| 14 | info!("Hello World!"); | 20 | info!("Hello World!"); |
| 15 | 21 | ||
| 16 | let mut adc = Adc::new(p.ADC, &mut Delay); | 22 | let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); |
| 17 | adc.set_sample_time(SampleTime::Cycles71_5); | 23 | adc.set_sample_time(SampleTime::Cycles71_5); |
| 18 | let mut pin = p.PA1; | 24 | let mut pin = p.PA1; |
| 19 | 25 | ||
| 20 | let mut vrefint = adc.enable_vref(&mut Delay); | 26 | let mut vrefint = adc.enable_vref(&mut Delay); |
| 21 | let vrefint_sample = adc.read_internal(&mut vrefint); | 27 | let vrefint_sample = adc.read_internal(&mut vrefint).await; |
| 22 | let convert_to_millivolts = |sample| { | 28 | let convert_to_millivolts = |sample| { |
| 23 | // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf | 29 | // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf |
| 24 | // 6.3.4 Embedded reference voltage | 30 | // 6.3.4 Embedded reference voltage |
| @@ -28,7 +34,7 @@ async fn main(_spawner: Spawner) { | |||
| 28 | }; | 34 | }; |
| 29 | 35 | ||
| 30 | loop { | 36 | loop { |
| 31 | let v = adc.read(&mut pin); | 37 | let v = adc.read(&mut pin).await; |
| 32 | info!("--> {} - {} mV", v, convert_to_millivolts(v)); | 38 | info!("--> {} - {} mV", v, convert_to_millivolts(v)); |
| 33 | Timer::after(Duration::from_millis(100)).await; | 39 | Timer::after(Duration::from_millis(100)).await; |
| 34 | } | 40 | } |
