aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/adc/ringbuffered.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/adc/ringbuffered.rs')
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs180
1 files changed, 180 insertions, 0 deletions
diff --git a/embassy-stm32/src/adc/ringbuffered.rs b/embassy-stm32/src/adc/ringbuffered.rs
new file mode 100644
index 000000000..242a1a89c
--- /dev/null
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -0,0 +1,180 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4#[allow(unused_imports)]
5use embassy_hal_internal::Peri;
6
7use super::AdcRegs;
8#[allow(unused_imports)]
9use crate::adc::{Instance, RxDma};
10#[allow(unused_imports)]
11use crate::dma::{ReadableRingBuffer, TransferOptions};
12use crate::rcc;
13
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub struct OverrunError;
16
17pub struct RingBufferedAdc<'d, T: Instance> {
18 _phantom: PhantomData<T>,
19 ring_buf: ReadableRingBuffer<'d, u16>,
20}
21
22impl<'d, T: Instance> RingBufferedAdc<'d, T> {
23 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self {
24 //dma side setup
25 let opts = TransferOptions {
26 half_transfer_ir: true,
27 circular: true,
28 ..Default::default()
29 };
30
31 // Safety: we forget the struct before this function returns.
32 let request = dma.request();
33
34 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, T::regs().data(), dma_buf, opts) };
35
36 Self {
37 _phantom: PhantomData,
38 ring_buf,
39 }
40 }
41
42 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
43 pub fn start(&mut self) {
44 compiler_fence(Ordering::SeqCst);
45 self.ring_buf.start();
46
47 T::regs().start();
48 }
49
50 pub fn stop(&mut self) {
51 self.ring_buf.request_pause();
52
53 compiler_fence(Ordering::SeqCst);
54 }
55
56 pub fn clear(&mut self) {
57 self.ring_buf.clear();
58 }
59
60 /// Reads measurements from the DMA ring buffer.
61 ///
62 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
63 /// The length of the `measurements` array should be exactly half of the DMA buffer length.
64 /// Because interrupts are only generated if half or full DMA transfer completes.
65 ///
66 /// Each call to `read` will populate the `measurements` array in the same order as the channels
67 /// defined with `sequence`. There will be many sequences worth of measurements in this array
68 /// because it only returns if at least half of the DMA buffer is filled. For example if 2
69 /// channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`.
70 ///
71 /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly
72 /// running tasks. Otherwise, you'll see constant Overrun errors occurring, this means that
73 /// you're sampling too quickly for the task to handle, and you may need to increase the buffer size.
74 /// Example:
75 /// ```rust,ignore
76 /// const DMA_BUF_LEN: usize = 120;
77 /// use embassy_stm32::adc::{Adc, AdcChannel}
78 ///
79 /// let mut adc = Adc::new(p.ADC1);
80 /// let mut adc_pin0 = p.PA0.degrade_adc();
81 /// let mut adc_pin1 = p.PA1.degrade_adc();
82 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
83 ///
84 /// let mut ring_buffered_adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
85 /// p.DMA2_CH0,
86 /// adc_dma_buf, [
87 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
88 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
89 /// ].into_iter());
90 ///
91 ///
92 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
93 /// loop {
94 /// match ring_buffered_adc.read(&mut measurements).await {
95 /// Ok(_) => {
96 /// defmt::info!("adc1: {}", measurements);
97 /// }
98 /// Err(e) => {
99 /// defmt::warn!("Error: {:?}", e);
100 /// }
101 /// }
102 /// }
103 /// ```
104 ///
105 ///
106 /// [`teardown_adc`]: #method.teardown_adc
107 /// [`start_continuous_sampling`]: #method.start_continuous_sampling
108 pub async fn read(&mut self, measurements: &mut [u16]) -> Result<usize, OverrunError> {
109 assert_eq!(
110 self.ring_buf.capacity() / 2,
111 measurements.len(),
112 "Buffer size must be half the size of the ring buffer"
113 );
114
115 if !self.ring_buf.is_running() {
116 self.start();
117 }
118
119 // #[cfg(adc_v2)]
120 // {
121 // // Clear overrun flag if set.
122 // if T::regs().sr().read().ovr() {
123 // self.stop();
124 //
125 // return Err(OverrunError);
126 // }
127 // }
128
129 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
130 }
131
132 /// Read bytes that are readily available in the ring buffer.
133 /// If no bytes are currently available in the buffer the call waits until the some
134 /// bytes are available (at least one byte and at most half the buffer size)
135 ///
136 /// Background receive is started if `start_continuous_sampling()` has not been previously called.
137 ///
138 /// Receive in the background is terminated if an error is returned.
139 /// It must then manually be started again by calling `start_continuous_sampling()` or by re-calling `blocking_read()`.
140 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
141 if !self.ring_buf.is_running() {
142 self.start();
143 }
144
145 // #[cfg(adc_v2)]
146 // {
147 // // Clear overrun flag if set.
148 // if T::regs().sr().read().ovr() {
149 // self.stop();
150 //
151 // return Err(OverrunError);
152 // }
153 // }
154
155 loop {
156 match self.ring_buf.read(buf) {
157 Ok((0, _)) => {}
158 Ok((len, _)) => {
159 return Ok(len);
160 }
161 Err(_) => {
162 self.ring_buf.request_pause();
163
164 return Err(OverrunError);
165 }
166 }
167 }
168 }
169}
170
171impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
172 fn drop(&mut self) {
173 T::regs().stop();
174
175 compiler_fence(Ordering::SeqCst);
176
177 self.ring_buf.request_pause();
178 rcc::disable::<T>();
179 }
180}