py32_hal/adc/
ringbuffered_v2.rs

1// The following code is modified from embassy-stm32
2// https://github.com/embassy-rs/embassy/tree/main/embassy-stm32
3// Special thanks to the Embassy Project and its contributors for their work!
4
5use core::marker::PhantomData;
6use core::mem;
7use core::sync::atomic::{compiler_fence, Ordering};
8
9use embassy_hal_internal::{into_ref, Peripheral};
10use py32_metapac::adc::vals::SampleTime;
11
12use crate::adc::{Adc, AdcChannel, Instance, RxDma};
13use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
14use crate::rcc;
15
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17pub struct OverrunError;
18
19fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
20    r.sr().modify(|regs| {
21        regs.set_eoc(false);
22        regs.set_ovr(false);
23    });
24}
25
26#[derive(PartialOrd, PartialEq, Debug, Clone, Copy)]
27pub enum Sequence {
28    One,
29    Two,
30    Three,
31    Four,
32    Five,
33    Six,
34    Seven,
35    Eight,
36    Nine,
37    Ten,
38    Eleven,
39    Twelve,
40    Thirteen,
41    Fourteen,
42    Fifteen,
43    Sixteen,
44}
45
46impl From<Sequence> for u8 {
47    fn from(s: Sequence) -> u8 {
48        match s {
49            Sequence::One => 0,
50            Sequence::Two => 1,
51            Sequence::Three => 2,
52            Sequence::Four => 3,
53            Sequence::Five => 4,
54            Sequence::Six => 5,
55            Sequence::Seven => 6,
56            Sequence::Eight => 7,
57            Sequence::Nine => 8,
58            Sequence::Ten => 9,
59            Sequence::Eleven => 10,
60            Sequence::Twelve => 11,
61            Sequence::Thirteen => 12,
62            Sequence::Fourteen => 13,
63            Sequence::Fifteen => 14,
64            Sequence::Sixteen => 15,
65        }
66    }
67}
68
69impl From<u8> for Sequence {
70    fn from(val: u8) -> Self {
71        match val {
72            0 => Sequence::One,
73            1 => Sequence::Two,
74            2 => Sequence::Three,
75            3 => Sequence::Four,
76            4 => Sequence::Five,
77            5 => Sequence::Six,
78            6 => Sequence::Seven,
79            7 => Sequence::Eight,
80            8 => Sequence::Nine,
81            9 => Sequence::Ten,
82            10 => Sequence::Eleven,
83            11 => Sequence::Twelve,
84            12 => Sequence::Thirteen,
85            13 => Sequence::Fourteen,
86            14 => Sequence::Fifteen,
87            15 => Sequence::Sixteen,
88            _ => panic!("Invalid sequence number"),
89        }
90    }
91}
92
93pub struct RingBufferedAdc<'d, T: Instance> {
94    _phantom: PhantomData<T>,
95    ring_buf: ReadableRingBuffer<'d, u16>,
96}
97
98impl<'d, T: Instance> Adc<'d, T> {
99    /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
100    ///
101    /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
102    /// The length of the `dma_buf` should be a multiple of the ADC channel count.
103    /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
104    ///
105    /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
106    /// It is critical to call `read` frequently to prevent DMA buffer overrun.
107    ///
108    /// [`read`]: #method.read
109    pub fn into_ring_buffered(
110        self,
111        dma: impl Peripheral<P = impl RxDma<T>> + 'd,
112        dma_buf: &'d mut [u16],
113    ) -> RingBufferedAdc<'d, T> {
114        assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
115        into_ref!(dma);
116
117        let opts: crate::dma::TransferOptions = TransferOptions {
118            half_transfer_ir: true,
119            priority: Priority::VeryHigh,
120            ..Default::default()
121        };
122
123        // Safety: we forget the struct before this function returns.
124        let rx_src = T::regs().dr().as_ptr() as *mut u16;
125        let request = dma.request();
126
127        let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) };
128
129        // Don't disable the clock
130        mem::forget(self);
131
132        RingBufferedAdc {
133            _phantom: PhantomData,
134            ring_buf,
135        }
136    }
137}
138
139impl<'d, T: Instance> RingBufferedAdc<'d, T> {
140    fn is_on() -> bool {
141        T::regs().cr2().read().adon()
142    }
143
144    fn stop_adc() {
145        T::regs().cr2().modify(|reg| {
146            reg.set_adon(false);
147        });
148    }
149
150    fn start_adc() {
151        T::regs().cr2().modify(|reg| {
152            reg.set_adon(true);
153        });
154    }
155
156    /// Sets the channel sample time
157    ///
158    /// ## SAFETY:
159    /// - ADON == 0 i.e ADC must not be enabled when this is called.
160    unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
161        if ch <= 9 {
162            T::regs()
163                .smpr2()
164                .modify(|reg| reg.set_smp(ch as _, sample_time));
165        } else {
166            T::regs()
167                .smpr1()
168                .modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
169        }
170    }
171
172    fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) {
173        let ch_iter = ch.iter();
174        for idx in ch_iter {
175            unsafe {
176                Self::set_channel_sample_time(*idx, sample_time);
177            }
178        }
179    }
180
181    pub fn set_sample_sequence(
182        &mut self,
183        sequence: Sequence,
184        channel: &mut impl AdcChannel<T>,
185        sample_time: SampleTime,
186    ) {
187        let was_on = Self::is_on();
188        if !was_on {
189            Self::start_adc();
190        }
191
192        // Check the sequence is long enough
193        T::regs().sqr1().modify(|r| {
194            let prev: Sequence = r.l().into();
195            if prev < sequence {
196                let new_l: Sequence = sequence;
197                trace!(
198                    "Setting sequence length from {:?} to {:?}",
199                    prev as u8,
200                    new_l as u8
201                );
202                r.set_l(sequence.into())
203            } else {
204                r.set_l(prev.into())
205            }
206        });
207
208        // Set this GPIO as an analog input.
209        channel.setup();
210
211        // Set the channel in the right sequence field.
212        match sequence {
213            Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())),
214            Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())),
215            Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())),
216            Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
217            Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
218            Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
219            Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(6, channel.channel())),
220            Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(7, channel.channel())),
221            Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(8, channel.channel())),
222            Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(9, channel.channel())),
223            Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(10, channel.channel())),
224            Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(11, channel.channel())),
225            Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(12, channel.channel())),
226            Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(13, channel.channel())),
227            Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(14, channel.channel())),
228            Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(15, channel.channel())),
229        };
230
231        if !was_on {
232            Self::stop_adc();
233        }
234
235        self.set_channels_sample_time(&[channel.channel()], sample_time);
236
237        Self::start_adc();
238    }
239
240    /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
241    pub fn start(&mut self) -> Result<(), OverrunError> {
242        self.setup_adc();
243        self.ring_buf.clear();
244
245        Ok(())
246    }
247
248    fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> {
249        self.teardown_adc();
250        Err(err)
251    }
252
253    /// Stops DMA transfer.
254    /// It does not turn off ADC.
255    /// Calling `start` restarts continuous DMA transfer.
256    ///
257    /// [`start`]: #method.start
258    pub fn teardown_adc(&mut self) {
259        // Stop the DMA transfer
260        self.ring_buf.request_pause();
261
262        let r = T::regs();
263
264        // Stop ADC
265        r.cr2().modify(|reg| {
266            // Stop ADC
267            reg.set_swstart(false);
268            // Stop DMA
269            reg.set_dma(false);
270        });
271
272        r.cr1().modify(|w| {
273            // Disable interrupt for end of conversion
274            w.set_eocie(false);
275            // Disable interrupt for overrun
276            w.set_ovrie(false);
277        });
278
279        clear_interrupt_flags(r);
280
281        compiler_fence(Ordering::SeqCst);
282    }
283
284    fn setup_adc(&mut self) {
285        compiler_fence(Ordering::SeqCst);
286
287        self.ring_buf.start();
288
289        let r = T::regs();
290
291        // Enable ADC
292        let was_on = Self::is_on();
293        if !was_on {
294            r.cr2().modify(|reg| {
295                reg.set_adon(false);
296                reg.set_swstart(false);
297            });
298        }
299
300        // Clear all interrupts
301        r.sr().modify(|regs| {
302            regs.set_eoc(false);
303            regs.set_ovr(false);
304            regs.set_strt(false);
305        });
306
307        r.cr1().modify(|w| {
308            // Enable interrupt for end of conversion
309            w.set_eocie(true);
310            // Enable interrupt for overrun
311            w.set_ovrie(true);
312            // Scanning converisons of multiple channels
313            w.set_scan(true);
314            // Continuous conversion mode
315            w.set_discen(false);
316        });
317
318        r.cr2().modify(|w| {
319            // Enable DMA mode
320            w.set_dma(true);
321            // Enable continuous conversions
322            w.set_cont(true);
323        });
324
325        // Begin ADC conversions
326        T::regs().cr2().modify(|reg| {
327            reg.set_adon(true);
328            reg.set_swstart(true);
329            reg.set_exttrig(true);
330        });
331
332        super::blocking_delay_us(3);
333    }
334
335    /// Read bytes that are readily available in the ring buffer.
336    /// If no bytes are currently available in the buffer the call waits until the some
337    /// bytes are available (at least one byte and at most half the buffer size)
338    ///
339    /// Background receive is started if `start()` has not been previously called.
340    ///
341    /// Receive in the background is terminated if an error is returned.
342    /// It must then manually be started again by calling `start()` or by re-calling `read()`.
343    pub fn blocking_read<const N: usize>(
344        &mut self,
345        buf: &mut [u16; N],
346    ) -> Result<usize, OverrunError> {
347        let r = T::regs();
348
349        // Start background receive if it was not already started
350        if !r.cr2().read().dma() {
351            self.start()?;
352        }
353
354        // Clear overrun flag if set.
355        if r.sr().read().ovr() {
356            return self.stop(OverrunError);
357        }
358
359        loop {
360            match self.ring_buf.read(buf) {
361                Ok((0, _)) => {}
362                Ok((len, _)) => {
363                    return Ok(len);
364                }
365                Err(_) => {
366                    return self.stop(OverrunError);
367                }
368            }
369        }
370    }
371
372    /// Reads measurements from the DMA ring buffer.
373    ///
374    /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
375    /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes.
376    ///
377    /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `set_sample_sequence`.
378    /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled.
379    /// For example if 3 channels are sampled `measurements` contain: `[sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3..]`.
380    ///
381    /// If an error is returned, it indicates a DMA overrun, and the process must be restarted by calling `start` or `read` again.
382    ///
383    /// By default, the ADC fills the DMA buffer as quickly as possible. To control the sample rate, call `teardown_adc` after each readout, and then start the DMA again at the desired interval.
384    /// Note that even if using `teardown_adc` to control the sample rate, with each call to `read`, measurements equivalent to half the size of the DMA buffer are still collected.
385    ///
386    /// Example:
387    /// ```rust,ignore
388    /// const DMA_BUF_LEN: usize = 120;
389    /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
390    /// let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_dma_buf);
391    ///
392    /// adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
393    /// adc.set_sample_sequence(Sequence::Two, &mut p.PA1, SampleTime::CYCLES112);
394    /// adc.set_sample_sequence(Sequence::Three, &mut p.PA2, SampleTime::CYCLES112);
395    ///
396    /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
397    /// loop {
398    ///     match adc.read(&mut measurements).await {
399    ///         Ok(_) => {
400    ///             defmt::info!("adc1: {}", measurements);
401    ///             // Only needed to manually control sample rate.
402    ///             adc.teardown_adc();
403    ///         }
404    ///         Err(e) => {
405    ///             defmt::warn!("Error: {:?}", e);
406    ///             // DMA overrun, next call to `read` restarts ADC.
407    ///         }
408    ///     }
409    ///
410    ///     // Manually control sample rate.
411    ///     Timer::after_millis(100).await;
412    /// }
413    /// ```
414    ///
415    ///
416    /// [`set_sample_sequence`]: #method.set_sample_sequence
417    /// [`teardown_adc`]: #method.teardown_adc
418    /// [`start`]: #method.start
419    pub async fn read<const N: usize>(
420        &mut self,
421        measurements: &mut [u16; N],
422    ) -> Result<usize, OverrunError> {
423        assert_eq!(
424            self.ring_buf.capacity() / 2,
425            N,
426            "Buffer size must be half the size of the ring buffer"
427        );
428
429        let r = T::regs();
430
431        // Start background receive if it was not already started
432        if !r.cr2().read().dma() {
433            self.start()?;
434        }
435
436        // Clear overrun flag if set.
437        if r.sr().read().ovr() {
438            return self.stop(OverrunError);
439        }
440        match self.ring_buf.read_exact(measurements).await {
441            Ok(len) => Ok(len),
442            Err(_) => self.stop(OverrunError),
443        }
444    }
445}
446
447impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
448    fn drop(&mut self) {
449        self.teardown_adc();
450        rcc::disable::<T>();
451    }
452}