aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/build.rs6
-rw-r--r--embassy-stm32/src/adc/mod.rs2
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs368
-rw-r--r--embassy-stm32/src/adc/v2.rs3
-rw-r--r--examples/stm32f4/src/bin/adc_dma.rs83
5 files changed, 461 insertions, 1 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 6aedcc228..24e2226a2 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -764,7 +764,7 @@ fn main() {
764 764
765 #[rustfmt::skip] 765 #[rustfmt::skip]
766 let signals: HashMap<_, _> = [ 766 let signals: HashMap<_, _> = [
767 // (kind, signal) => trait 767 // (kind, signal) => trait
768 (("ucpd", "CC1"), quote!(crate::ucpd::Cc1Pin)), 768 (("ucpd", "CC1"), quote!(crate::ucpd::Cc1Pin)),
769 (("ucpd", "CC2"), quote!(crate::ucpd::Cc2Pin)), 769 (("ucpd", "CC2"), quote!(crate::ucpd::Cc2Pin)),
770 (("usart", "TX"), quote!(crate::usart::TxPin)), 770 (("usart", "TX"), quote!(crate::usart::TxPin)),
@@ -1178,6 +1178,10 @@ fn main() {
1178 1178
1179 let signals: HashMap<_, _> = [ 1179 let signals: HashMap<_, _> = [
1180 // (kind, signal) => trait 1180 // (kind, signal) => trait
1181 (("adc", "ADC"), quote!(crate::adc::RxDma)),
1182 (("adc", "ADC1"), quote!(crate::adc::RxDma)),
1183 (("adc", "ADC2"), quote!(crate::adc::RxDma)),
1184 (("adc", "ADC3"), quote!(crate::adc::RxDma)),
1181 (("ucpd", "RX"), quote!(crate::ucpd::RxDma)), 1185 (("ucpd", "RX"), quote!(crate::ucpd::RxDma)),
1182 (("ucpd", "TX"), quote!(crate::ucpd::TxDma)), 1186 (("ucpd", "TX"), quote!(crate::ucpd::TxDma)),
1183 (("usart", "RX"), quote!(crate::usart::RxDma)), 1187 (("usart", "RX"), quote!(crate::usart::RxDma)),
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 0c22a7dae..7a7d7cd8e 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -28,6 +28,8 @@ pub use crate::pac::adc::vals::Res as Resolution;
28pub use crate::pac::adc::vals::SampleTime; 28pub use crate::pac::adc::vals::SampleTime;
29use crate::peripherals; 29use crate::peripherals;
30 30
31dma_trait!(RxDma, Instance);
32
31/// Analog to Digital driver. 33/// Analog to Digital driver.
32pub struct Adc<'d, T: Instance> { 34pub struct Adc<'d, T: Instance> {
33 #[allow(unused)] 35 #[allow(unused)]
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
new file mode 100644
index 000000000..fb29d9a8c
--- /dev/null
+++ b/embassy-stm32/src/adc/ringbuffered_v2.rs
@@ -0,0 +1,368 @@
1use core::marker::PhantomData;
2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering};
4
5use embassy_hal_internal::{into_ref, Peripheral};
6use stm32_metapac::adc::vals::SampleTime;
7
8use crate::adc::{Adc, AdcChannel, Instance, RxDma};
9use crate::dma::ringbuffer::OverrunError;
10use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
11use crate::pac::adc::vals;
12use crate::rcc;
13
14fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
15 r.sr().modify(|regs| {
16 regs.set_eoc(false);
17 regs.set_ovr(false);
18 });
19}
20
21#[derive(PartialOrd, PartialEq, Debug, Clone, Copy)]
22pub enum Sequence {
23 One,
24 Two,
25 Three,
26 Four,
27 Five,
28 Six,
29 Seven,
30 Eight,
31 Nine,
32 Ten,
33 Eleven,
34 Twelve,
35 Thirteen,
36 Fourteen,
37 Fifteen,
38 Sixteen,
39}
40
41impl From<Sequence> for u8 {
42 fn from(s: Sequence) -> u8 {
43 match s {
44 Sequence::One => 0,
45 Sequence::Two => 1,
46 Sequence::Three => 2,
47 Sequence::Four => 3,
48 Sequence::Five => 4,
49 Sequence::Six => 5,
50 Sequence::Seven => 6,
51 Sequence::Eight => 7,
52 Sequence::Nine => 8,
53 Sequence::Ten => 9,
54 Sequence::Eleven => 10,
55 Sequence::Twelve => 11,
56 Sequence::Thirteen => 12,
57 Sequence::Fourteen => 13,
58 Sequence::Fifteen => 14,
59 Sequence::Sixteen => 15,
60 }
61 }
62}
63
64impl From<u8> for Sequence {
65 fn from(val: u8) -> Self {
66 match val {
67 0 => Sequence::One,
68 1 => Sequence::Two,
69 2 => Sequence::Three,
70 3 => Sequence::Four,
71 4 => Sequence::Five,
72 5 => Sequence::Six,
73 6 => Sequence::Seven,
74 7 => Sequence::Eight,
75 8 => Sequence::Nine,
76 9 => Sequence::Ten,
77 10 => Sequence::Eleven,
78 11 => Sequence::Twelve,
79 12 => Sequence::Thirteen,
80 13 => Sequence::Fourteen,
81 14 => Sequence::Fifteen,
82 15 => Sequence::Sixteen,
83 _ => panic!("Invalid sequence number"),
84 }
85 }
86}
87
88pub struct RingBufferedAdc<'d, T: Instance> {
89 _phantom: PhantomData<T>,
90 ring_buf: ReadableRingBuffer<'d, u16>,
91}
92
93impl<'d, T: Instance> Adc<'d, T> {
94 pub fn into_ring_buffered(
95 self,
96 dma: impl Peripheral<P = impl RxDma<T>> + 'd,
97 dma_buf: &'d mut [u16],
98 ) -> RingBufferedAdc<'d, T> {
99 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
100 into_ref!(dma);
101
102 let opts: crate::dma::TransferOptions = TransferOptions {
103 half_transfer_ir: true,
104 priority: Priority::VeryHigh,
105 ..Default::default()
106 };
107
108 // Safety: we forget the struct before this function returns.
109 let rx_src = T::regs().dr().as_ptr() as *mut u16;
110 let request = dma.request();
111
112 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) };
113
114 // Don't disable the clock
115 mem::forget(self);
116
117 RingBufferedAdc {
118 _phantom: PhantomData,
119 ring_buf,
120 }
121 }
122}
123
124impl<'d, T: Instance> RingBufferedAdc<'d, T> {
125 fn is_on() -> bool {
126 T::regs().cr2().read().adon()
127 }
128
129 fn stop_adc() {
130 T::regs().cr2().modify(|reg| {
131 reg.set_adon(false);
132 });
133 }
134
135 fn start_adc() {
136 T::regs().cr2().modify(|reg| {
137 reg.set_adon(true);
138 });
139 }
140
141 /// Sets the channel sample time
142 ///
143 /// ## SAFETY:
144 /// - ADON == 0 i.e ADC must not be enabled when this is called.
145 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
146 if ch <= 9 {
147 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
148 } else {
149 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
150 }
151 }
152
153 fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) {
154 let ch_iter = ch.iter();
155 for idx in ch_iter {
156 unsafe {
157 Self::set_channel_sample_time(*idx, sample_time);
158 }
159 }
160 }
161
162 pub fn set_sample_sequence(
163 &mut self,
164 sequence: Sequence,
165 channel: &mut impl AdcChannel<T>,
166 sample_time: SampleTime,
167 ) {
168 let was_on = Self::is_on();
169 if !was_on {
170 Self::start_adc();
171 }
172
173 // Check the sequence is long enough
174 T::regs().sqr1().modify(|r| {
175 let prev: Sequence = r.l().into();
176 if prev < sequence {
177 let new_l: Sequence = sequence;
178 trace!("Setting sequence length from {:?} to {:?}", prev as u8, new_l as u8);
179 r.set_l(sequence.into())
180 } else {
181 r.set_l(prev.into())
182 }
183 });
184
185 // Set this GPIO as an analog input.
186 channel.setup();
187
188 // Set the channel in the right sequence field.
189 match sequence {
190 Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())),
191 Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())),
192 Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())),
193 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
194 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
195 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
196 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(6, channel.channel())),
197 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(7, channel.channel())),
198 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(8, channel.channel())),
199 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(9, channel.channel())),
200 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(10, channel.channel())),
201 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(11, channel.channel())),
202 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(12, channel.channel())),
203 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(13, channel.channel())),
204 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(14, channel.channel())),
205 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(15, channel.channel())),
206 };
207
208 if !was_on {
209 Self::stop_adc();
210 }
211
212 self.set_channels_sample_time(&[channel.channel()], sample_time);
213
214 Self::start_adc();
215 }
216
217 pub fn start(&mut self) -> Result<(), OverrunError> {
218 self.ring_buf.clear();
219
220 self.setup_adc();
221
222 Ok(())
223 }
224
225 fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> {
226 self.teardown_adc();
227 Err(err)
228 }
229
230 pub fn teardown_adc(&mut self) {
231 // Stop the DMA transfer
232 self.ring_buf.request_stop();
233
234 let r = T::regs();
235
236 // Stop ADC
237 r.cr2().modify(|reg| {
238 // Stop ADC
239 reg.set_swstart(false);
240 // Stop DMA
241 reg.set_dma(false);
242 });
243
244 r.cr1().modify(|w| {
245 // Disable interrupt for end of conversion
246 w.set_eocie(false);
247 // Disable interrupt for overrun
248 w.set_ovrie(false);
249 });
250
251 clear_interrupt_flags(r);
252
253 compiler_fence(Ordering::SeqCst);
254 }
255
256 fn setup_adc(&mut self) {
257 compiler_fence(Ordering::SeqCst);
258
259 self.ring_buf.start();
260
261 let r = T::regs();
262
263 // Enable ADC
264 let was_on = Self::is_on();
265 if !was_on {
266 r.cr2().modify(|reg| {
267 reg.set_adon(false);
268 reg.set_swstart(false);
269 });
270 }
271
272 // Clear all interrupts
273 r.sr().modify(|regs| {
274 regs.set_eoc(false);
275 regs.set_ovr(false);
276 regs.set_strt(false);
277 });
278
279 r.cr1().modify(|w| {
280 // Enable interrupt for end of conversion
281 w.set_eocie(true);
282 // Enable interrupt for overrun
283 w.set_ovrie(true);
284 // Scanning converisons of multiple channels
285 w.set_scan(true);
286 // Continuous conversion mode
287 w.set_discen(false);
288 });
289
290 r.cr2().modify(|w| {
291 // Enable DMA mode
292 w.set_dma(true);
293 // Enable continuous conversions
294 w.set_cont(vals::Cont::CONTINUOUS);
295 // DMA requests are issues as long as DMA=1 and data are converted.
296 w.set_dds(vals::Dds::CONTINUOUS);
297 // EOC flag is set at the end of each conversion.
298 w.set_eocs(vals::Eocs::EACHCONVERSION);
299 });
300
301 // Begin ADC conversions
302 T::regs().cr2().modify(|reg| {
303 reg.set_adon(true);
304 reg.set_swstart(true);
305 });
306
307 super::blocking_delay_us(3);
308 }
309
310 /// Read bytes that are readily available in the ring buffer.
311 /// If no bytes are currently available in the buffer the call waits until the some
312 /// bytes are available (at least one byte and at most half the buffer size)
313 ///
314 /// Background receive is started if `start()` has not been previously called.
315 ///
316 /// Receive in the background is terminated if an error is returned.
317 /// It must then manually be started again by calling `start()` or by re-calling `read()`.
318 pub fn read<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> {
319 let r = T::regs();
320
321 // Start background receive if it was not already started
322 if !r.cr2().read().dma() {
323 self.start()?;
324 }
325
326 // Clear overrun flag if set.
327 if r.sr().read().ovr() {
328 return self.stop(OverrunError);
329 }
330
331 loop {
332 match self.ring_buf.read(buf) {
333 Ok((0, _)) => {}
334 Ok((len, _)) => {
335 return Ok(len);
336 }
337 Err(_) => {
338 return self.stop(OverrunError);
339 }
340 }
341 }
342 }
343
344 pub async fn read_exact<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> {
345 let r = T::regs();
346
347 // Start background receive if it was not already started
348 if !r.cr2().read().dma() {
349 self.start()?;
350 }
351
352 // Clear overrun flag if set.
353 if r.sr().read().ovr() {
354 return self.stop(OverrunError);
355 }
356 match self.ring_buf.read_exact(buf).await {
357 Ok(len) => Ok(len),
358 Err(_) => self.stop(OverrunError),
359 }
360 }
361}
362
363impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
364 fn drop(&mut self) {
365 self.teardown_adc();
366 rcc::disable::<T>();
367 }
368}
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index e3175dff5..ddeb7ea79 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -6,6 +6,9 @@ use crate::peripherals::ADC1;
6use crate::time::Hertz; 6use crate::time::Hertz;
7use crate::{rcc, Peripheral}; 7use crate::{rcc, Peripheral};
8 8
9mod ringbuffered_v2;
10pub use ringbuffered_v2::{RingBufferedAdc, Sequence};
11
9/// Default VREF voltage used for sample conversion to millivolts. 12/// Default VREF voltage used for sample conversion to millivolts.
10pub const VREF_DEFAULT_MV: u32 = 3300; 13pub const VREF_DEFAULT_MV: u32 = 3300;
11/// VREF voltage used for factory calibration of VREFINTCAL register. 14/// VREF voltage used for factory calibration of VREFINTCAL register.
diff --git a/examples/stm32f4/src/bin/adc_dma.rs b/examples/stm32f4/src/bin/adc_dma.rs
new file mode 100644
index 000000000..992bed573
--- /dev/null
+++ b/examples/stm32f4/src/bin/adc_dma.rs
@@ -0,0 +1,83 @@
1#![no_std]
2#![no_main]
3use cortex_m::singleton;
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::adc::{Adc, RingBufferedAdc, SampleTime, Sequence};
7use embassy_stm32::Peripherals;
8use embassy_time::Instant;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default());
14 spawner.must_spawn(adc_task(p));
15}
16
17#[embassy_executor::task]
18async fn adc_task(mut p: Peripherals) {
19 const ADC_BUF_SIZE: usize = 1024;
20 let adc_data: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
21 let adc_data2: &mut [u16; ADC_BUF_SIZE] = singleton!(ADCDAT2 : [u16; ADC_BUF_SIZE] = [0u16; ADC_BUF_SIZE]).unwrap();
22
23 let adc = Adc::new(p.ADC1);
24 let adc2 = Adc::new(p.ADC2);
25
26 let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_data);
27 let mut adc2: RingBufferedAdc<embassy_stm32::peripherals::ADC2> = adc2.into_ring_buffered(p.DMA2_CH2, adc_data2);
28
29 adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
30 adc.set_sample_sequence(Sequence::Two, &mut p.PA2, SampleTime::CYCLES112);
31 adc2.set_sample_sequence(Sequence::One, &mut p.PA1, SampleTime::CYCLES112);
32 adc2.set_sample_sequence(Sequence::Two, &mut p.PA3, SampleTime::CYCLES112);
33
34 // Note that overrun is a big consideration in this implementation. Whatever task is running the adc.read() calls absolutely must circle back around
35 // to the adc.read() call before the DMA buffer is wrapped around > 1 time. At this point, the overrun is so significant that the context of
36 // what channel is at what index is lost. The buffer must be cleared and reset. This *is* handled here, but allowing this to happen will cause
37 // a reduction of performance as each time the buffer is reset, the adc & dma buffer must be restarted.
38
39 // An interrupt executor with a higher priority than other tasks may be a good approach here, allowing this task to wake and read the buffer most
40 // frequently.
41 let mut tic = Instant::now();
42 let mut buffer1 = [0u16; 512];
43 let mut buffer2 = [0u16; 512];
44 let _ = adc.start();
45 let _ = adc2.start();
46 loop {
47 match adc.read_exact(&mut buffer1).await {
48 Ok(_data) => {
49 let toc = Instant::now();
50 info!(
51 "\n adc1: {} dt = {}, n = {}",
52 buffer1[0..16],
53 (toc - tic).as_micros(),
54 _data
55 );
56 tic = toc;
57 }
58 Err(e) => {
59 warn!("Error: {:?}", e);
60 buffer1 = [0u16; 512];
61 let _ = adc.start();
62 }
63 }
64
65 match adc2.read_exact(&mut buffer2).await {
66 Ok(_data) => {
67 let toc = Instant::now();
68 info!(
69 "\n adc2: {} dt = {}, n = {}",
70 buffer2[0..16],
71 (toc - tic).as_micros(),
72 _data
73 );
74 tic = toc;
75 }
76 Err(e) => {
77 warn!("Error: {:?}", e);
78 buffer2 = [0u16; 512];
79 let _ = adc2.start();
80 }
81 }
82 }
83}