aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2023-09-20 16:07:35 -0500
committerxoviat <[email protected]>2023-09-20 16:07:35 -0500
commitd46920dce692859e0818a6171c930af270a7a02f (patch)
tree0e9af554ade705f0e7769cfc9238169d3521fa36
parentc573959a956802eb177d04fa5b7802397af19f93 (diff)
stm32/adc: make v1 async and leave en
-rw-r--r--embassy-stm32/src/adc/mod.rs10
-rw-r--r--embassy-stm32/src/adc/v1.rs137
-rw-r--r--examples/stm32f0/src/bin/adc.rs12
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
33pub(crate) mod sealed { 33pub(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 @@
1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::task::Poll;
4
1use embassy_hal_internal::into_ref; 5use embassy_hal_internal::into_ref;
2use embedded_hal_02::blocking::delay::DelayUs; 6use embedded_hal_02::blocking::delay::DelayUs;
3 7
4use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; 8use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
9use crate::interrupt::typelevel::Interrupt;
5use crate::peripherals::ADC; 10use crate::peripherals::ADC;
6use crate::Peripheral; 11use crate::{interrupt, Peripheral};
7 12
8pub const VDDA_CALIB_MV: u32 = 3300; 13pub const VDDA_CALIB_MV: u32 = 3300;
9pub const VREF_INT: u32 = 1230; 14pub const VREF_INT: u32 = 1230;
10 15
16/// Interrupt handler.
17pub struct InterruptHandler<T: Instance> {
18 _phantom: PhantomData<T>,
19}
20
21impl<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
11pub struct Vbat; 33pub struct Vbat;
12impl InternalChannel<ADC> for Vbat {} 34impl InternalChannel<ADC> for Vbat {}
13impl super::sealed::InternalChannel<ADC> for Vbat { 35impl super::sealed::InternalChannel<ADC> for Vbat {
@@ -33,7 +55,11 @@ impl super::sealed::InternalChannel<ADC> for Temperature {
33} 55}
34 56
35impl<'d, T: Instance> Adc<'d, T> { 57impl<'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
183impl<'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 @@
5use defmt::*; 5use defmt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::adc::{Adc, SampleTime}; 7use embassy_stm32::adc::{Adc, SampleTime};
8use embassy_stm32::peripherals::ADC;
9use embassy_stm32::{adc, bind_interrupts};
8use embassy_time::{Delay, Duration, Timer}; 10use embassy_time::{Delay, Duration, Timer};
9use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
10 12
13bind_interrupts!(struct Irqs {
14 ADC1_COMP => adc::InterruptHandler<ADC>;
15});
16
11#[embassy_executor::main] 17#[embassy_executor::main]
12async fn main(_spawner: Spawner) { 18async 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 }