aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-03 16:16:47 -0600
committerxoviat <[email protected]>2025-11-03 16:16:47 -0600
commitefc47c8013e957bd7f8a669e2a7ef24d9eee0cee (patch)
tree7d5381b3342212e09d1dbacd23463eba229cc402 /embassy-stm32/src
parenta69c3b5fcb8aa024b04ccbe33d83f5173250aaed (diff)
unify ringbuffered versions
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/adc/ringbuffered.rs (renamed from embassy-stm32/src/adc/ringbuffered_v3.rs)200
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs238
-rw-r--r--embassy-stm32/src/adc/v2.rs4
-rw-r--r--embassy-stm32/src/adc/v3.rs4
4 files changed, 189 insertions, 257 deletions
diff --git a/embassy-stm32/src/adc/ringbuffered_v3.rs b/embassy-stm32/src/adc/ringbuffered.rs
index 0aee309e3..bea981fe2 100644
--- a/embassy-stm32/src/adc/ringbuffered_v3.rs
+++ b/embassy-stm32/src/adc/ringbuffered.rs
@@ -1,21 +1,33 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence}; 2use core::sync::atomic::{Ordering, compiler_fence};
3 3
4#[allow(unused_imports)]
4use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
5 6
7#[allow(unused_imports)]
6use crate::adc::{Instance, RxDma}; 8use crate::adc::{Instance, RxDma};
9#[allow(unused_imports)]
7use crate::dma::{ReadableRingBuffer, TransferOptions}; 10use crate::dma::{ReadableRingBuffer, TransferOptions};
8use crate::rcc; 11use crate::rcc;
9 12
10#[cfg_attr(feature = "defmt", derive(defmt::Format))] 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11pub struct OverrunError; 14pub struct OverrunError;
12 15
16#[cfg(adc_v2)]
17fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
18 r.sr().modify(|regs| {
19 regs.set_eoc(false);
20 regs.set_ovr(false);
21 });
22}
23
13pub struct RingBufferedAdc<'d, T: Instance> { 24pub struct RingBufferedAdc<'d, T: Instance> {
14 pub _phantom: PhantomData<T>, 25 pub _phantom: PhantomData<T>,
15 pub ring_buf: ReadableRingBuffer<'d, u16>, 26 pub ring_buf: ReadableRingBuffer<'d, u16>,
16} 27}
17 28
18impl<'d, T: Instance> RingBufferedAdc<'d, T> { 29impl<'d, T: Instance> RingBufferedAdc<'d, T> {
30 #[cfg(not(adc_v2))]
19 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self { 31 pub(crate) fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self {
20 //dma side setup 32 //dma side setup
21 let opts = TransferOptions { 33 let opts = TransferOptions {
@@ -36,6 +48,116 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
36 } 48 }
37 } 49 }
38 50
51 #[cfg(adc_v2)]
52 fn is_on() -> bool {
53 T::regs().cr2().read().adon()
54 }
55
56 #[cfg(adc_v2)]
57 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
58 pub fn start(&mut self) -> Result<(), OverrunError> {
59 self.setup_adc();
60 self.ring_buf.clear();
61
62 Ok(())
63 }
64
65 #[cfg(adc_v2)]
66 fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> {
67 self.teardown_adc();
68 Err(err)
69 }
70
71 #[cfg(adc_v2)]
72 /// Stops DMA transfer.
73 /// It does not turn off ADC.
74 /// Calling `start` restarts continuous DMA transfer.
75 ///
76 /// [`start`]: #method.start
77 pub fn teardown_adc(&mut self) {
78 // Stop the DMA transfer
79 self.ring_buf.request_pause();
80
81 let r = T::regs();
82
83 // Stop ADC
84 r.cr2().modify(|reg| {
85 // Stop ADC
86 reg.set_swstart(false);
87 // Stop DMA
88 reg.set_dma(false);
89 });
90
91 r.cr1().modify(|w| {
92 // Disable interrupt for end of conversion
93 w.set_eocie(false);
94 // Disable interrupt for overrun
95 w.set_ovrie(false);
96 });
97
98 clear_interrupt_flags(r);
99
100 compiler_fence(Ordering::SeqCst);
101 }
102
103 #[cfg(adc_v2)]
104 fn setup_adc(&mut self) {
105 use crate::pac::adc::vals;
106
107 compiler_fence(Ordering::SeqCst);
108
109 self.ring_buf.start();
110
111 let r = T::regs();
112
113 // Enable ADC
114 let was_on = Self::is_on();
115 if !was_on {
116 r.cr2().modify(|reg| {
117 reg.set_adon(false);
118 reg.set_swstart(false);
119 });
120 }
121
122 // Clear all interrupts
123 r.sr().modify(|regs| {
124 regs.set_eoc(false);
125 regs.set_ovr(false);
126 regs.set_strt(false);
127 });
128
129 r.cr1().modify(|w| {
130 // Enable interrupt for end of conversion
131 w.set_eocie(true);
132 // Enable interrupt for overrun
133 w.set_ovrie(true);
134 // Scanning converisons of multiple channels
135 w.set_scan(true);
136 // Continuous conversion mode
137 w.set_discen(false);
138 });
139
140 r.cr2().modify(|w| {
141 // Enable DMA mode
142 w.set_dma(true);
143 // Enable continuous conversions
144 w.set_cont(true);
145 // DMA requests are issues as long as DMA=1 and data are converted.
146 w.set_dds(vals::Dds::CONTINUOUS);
147 // EOC flag is set at the end of each conversion.
148 w.set_eocs(vals::Eocs::EACH_CONVERSION);
149 });
150
151 // Begin ADC conversions
152 T::regs().cr2().modify(|reg| {
153 reg.set_adon(true);
154 reg.set_swstart(true);
155 });
156
157 super::blocking_delay_us(3);
158 }
159
160 #[cfg(any(adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0))]
39 #[inline] 161 #[inline]
40 fn start_continuous_sampling(&mut self) { 162 fn start_continuous_sampling(&mut self) {
41 // Start adc conversion 163 // Start adc conversion
@@ -45,6 +167,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
45 self.ring_buf.start(); 167 self.ring_buf.start();
46 } 168 }
47 169
170 #[cfg(any(adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0))]
48 #[inline] 171 #[inline]
49 pub fn stop_continuous_sampling(&mut self) { 172 pub fn stop_continuous_sampling(&mut self) {
50 // Stop adc conversion 173 // Stop adc conversion
@@ -55,12 +178,15 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
55 while T::regs().cr().read().adstart() {} 178 while T::regs().cr().read().adstart() {}
56 } 179 }
57 } 180 }
181
182 #[cfg(any(adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0))]
58 pub fn disable_adc(&mut self) { 183 pub fn disable_adc(&mut self) {
59 self.stop_continuous_sampling(); 184 self.stop_continuous_sampling();
60 self.ring_buf.clear(); 185 self.ring_buf.clear();
61 self.ring_buf.request_pause(); 186 self.ring_buf.request_pause();
62 } 187 }
63 188
189 #[cfg(any(adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0))]
64 pub fn teardown_adc(&mut self) { 190 pub fn teardown_adc(&mut self) {
65 self.disable_adc(); 191 self.disable_adc();
66 192
@@ -133,9 +259,25 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
133 259
134 let r = T::regs(); 260 let r = T::regs();
135 261
136 // Start background receive if it was not already started 262 #[cfg(adc_v2)]
137 if !r.cr().read().adstart() { 263 {
138 self.start_continuous_sampling(); 264 // Start background receive if it was not already started
265 if !r.cr2().read().dma() {
266 self.start()?;
267 }
268 }
269
270 #[cfg(not(adc_v2))]
271 {
272 // Clear overrun flag if set.
273 if r.sr().read().ovr() {
274 return self.stop(OverrunError);
275 }
276
277 // Start background receive if it was not already started
278 if !r.cr().read().adstart() {
279 self.start_continuous_sampling();
280 }
139 } 281 }
140 282
141 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError) 283 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
@@ -152,20 +294,48 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
152 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> { 294 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
153 let r = T::regs(); 295 let r = T::regs();
154 296
155 // Start background receive if it was not already started 297 #[cfg(adc_v2)]
156 if !r.cr().read().adstart() { 298 {
157 self.start_continuous_sampling(); 299 // Start background receive if it was not already started
158 } 300 if !r.cr2().read().dma() {
301 self.start()?;
302 }
159 303
160 loop { 304 // Clear overrun flag if set.
161 match self.ring_buf.read(buf) { 305 if r.sr().read().ovr() {
162 Ok((0, _)) => {} 306 return self.stop(OverrunError);
163 Ok((len, _)) => { 307 }
164 return Ok(len); 308
309 loop {
310 match self.ring_buf.read(buf) {
311 Ok((0, _)) => {}
312 Ok((len, _)) => {
313 return Ok(len);
314 }
315 Err(_) => {
316 return self.stop(OverrunError);
317 }
165 } 318 }
166 Err(_) => { 319 }
167 self.stop_continuous_sampling(); 320 }
168 return Err(OverrunError); 321
322 #[cfg(not(adc_v2))]
323 {
324 // Start background receive if it was not already started
325 if !r.cr().read().adstart() {
326 self.start_continuous_sampling();
327 }
328
329 loop {
330 match self.ring_buf.read(buf) {
331 Ok((0, _)) => {}
332 Ok((len, _)) => {
333 return Ok(len);
334 }
335 Err(_) => {
336 self.stop_continuous_sampling();
337 return Err(OverrunError);
338 }
169 } 339 }
170 } 340 }
171 } 341 }
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
deleted file mode 100644
index c520daea4..000000000
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ /dev/null
@@ -1,238 +0,0 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence};
3
4use crate::adc::Instance;
5use crate::dma::ReadableRingBuffer;
6use crate::pac::adc::vals;
7use crate::rcc;
8
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10pub struct OverrunError;
11
12fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
13 r.sr().modify(|regs| {
14 regs.set_eoc(false);
15 regs.set_ovr(false);
16 });
17}
18
19pub struct RingBufferedAdc<'d, T: Instance> {
20 pub(super) _phantom: PhantomData<T>,
21 pub(super) ring_buf: ReadableRingBuffer<'d, u16>,
22}
23
24impl<'d, T: Instance> RingBufferedAdc<'d, T> {
25 fn is_on() -> bool {
26 T::regs().cr2().read().adon()
27 }
28
29 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
30 pub fn start(&mut self) -> Result<(), OverrunError> {
31 self.setup_adc();
32 self.ring_buf.clear();
33
34 Ok(())
35 }
36
37 fn stop(&mut self, err: OverrunError) -> Result<usize, OverrunError> {
38 self.teardown_adc();
39 Err(err)
40 }
41
42 /// Stops DMA transfer.
43 /// It does not turn off ADC.
44 /// Calling `start` restarts continuous DMA transfer.
45 ///
46 /// [`start`]: #method.start
47 pub fn teardown_adc(&mut self) {
48 // Stop the DMA transfer
49 self.ring_buf.request_pause();
50
51 let r = T::regs();
52
53 // Stop ADC
54 r.cr2().modify(|reg| {
55 // Stop ADC
56 reg.set_swstart(false);
57 // Stop DMA
58 reg.set_dma(false);
59 });
60
61 r.cr1().modify(|w| {
62 // Disable interrupt for end of conversion
63 w.set_eocie(false);
64 // Disable interrupt for overrun
65 w.set_ovrie(false);
66 });
67
68 clear_interrupt_flags(r);
69
70 compiler_fence(Ordering::SeqCst);
71 }
72
73 fn setup_adc(&mut self) {
74 compiler_fence(Ordering::SeqCst);
75
76 self.ring_buf.start();
77
78 let r = T::regs();
79
80 // Enable ADC
81 let was_on = Self::is_on();
82 if !was_on {
83 r.cr2().modify(|reg| {
84 reg.set_adon(false);
85 reg.set_swstart(false);
86 });
87 }
88
89 // Clear all interrupts
90 r.sr().modify(|regs| {
91 regs.set_eoc(false);
92 regs.set_ovr(false);
93 regs.set_strt(false);
94 });
95
96 r.cr1().modify(|w| {
97 // Enable interrupt for end of conversion
98 w.set_eocie(true);
99 // Enable interrupt for overrun
100 w.set_ovrie(true);
101 // Scanning converisons of multiple channels
102 w.set_scan(true);
103 // Continuous conversion mode
104 w.set_discen(false);
105 });
106
107 r.cr2().modify(|w| {
108 // Enable DMA mode
109 w.set_dma(true);
110 // Enable continuous conversions
111 w.set_cont(true);
112 // DMA requests are issues as long as DMA=1 and data are converted.
113 w.set_dds(vals::Dds::CONTINUOUS);
114 // EOC flag is set at the end of each conversion.
115 w.set_eocs(vals::Eocs::EACH_CONVERSION);
116 });
117
118 // Begin ADC conversions
119 T::regs().cr2().modify(|reg| {
120 reg.set_adon(true);
121 reg.set_swstart(true);
122 });
123
124 super::blocking_delay_us(3);
125 }
126
127 /// Read bytes that are readily available in the ring buffer.
128 /// If no bytes are currently available in the buffer the call waits until the some
129 /// bytes are available (at least one byte and at most half the buffer size)
130 ///
131 /// Background receive is started if `start()` has not been previously called.
132 ///
133 /// Receive in the background is terminated if an error is returned.
134 /// It must then manually be started again by calling `start()` or by re-calling `read()`.
135 pub fn blocking_read<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> {
136 let r = T::regs();
137
138 // Start background receive if it was not already started
139 if !r.cr2().read().dma() {
140 self.start()?;
141 }
142
143 // Clear overrun flag if set.
144 if r.sr().read().ovr() {
145 return self.stop(OverrunError);
146 }
147
148 loop {
149 match self.ring_buf.read(buf) {
150 Ok((0, _)) => {}
151 Ok((len, _)) => {
152 return Ok(len);
153 }
154 Err(_) => {
155 return self.stop(OverrunError);
156 }
157 }
158 }
159 }
160
161 /// Reads measurements from the DMA ring buffer.
162 ///
163 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
164 /// 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.
165 ///
166 /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `set_sample_sequence`.
167 /// 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.
168 /// For example if 3 channels are sampled `measurements` contain: `[sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3..]`.
169 ///
170 /// If an error is returned, it indicates a DMA overrun, and the process must be restarted by calling `start` or `read` again.
171 ///
172 /// 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.
173 /// 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.
174 ///
175 /// Example:
176 /// ```rust,ignore
177 /// const DMA_BUF_LEN: usize = 120;
178 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
179 /// let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_dma_buf);
180 ///
181 /// adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
182 /// adc.set_sample_sequence(Sequence::Two, &mut p.PA1, SampleTime::CYCLES112);
183 /// adc.set_sample_sequence(Sequence::Three, &mut p.PA2, SampleTime::CYCLES112);
184 ///
185 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
186 /// loop {
187 /// match adc.read(&mut measurements).await {
188 /// Ok(_) => {
189 /// defmt::info!("adc1: {}", measurements);
190 /// // Only needed to manually control sample rate.
191 /// adc.teardown_adc();
192 /// }
193 /// Err(e) => {
194 /// defmt::warn!("Error: {:?}", e);
195 /// // DMA overrun, next call to `read` restarts ADC.
196 /// }
197 /// }
198 ///
199 /// // Manually control sample rate.
200 /// Timer::after_millis(100).await;
201 /// }
202 /// ```
203 ///
204 ///
205 /// [`set_sample_sequence`]: #method.set_sample_sequence
206 /// [`teardown_adc`]: #method.teardown_adc
207 /// [`start`]: #method.start
208 pub async fn read<const N: usize>(&mut self, measurements: &mut [u16; N]) -> Result<usize, OverrunError> {
209 assert_eq!(
210 self.ring_buf.capacity() / 2,
211 N,
212 "Buffer size must be half the size of the ring buffer"
213 );
214
215 let r = T::regs();
216
217 // Start background receive if it was not already started
218 if !r.cr2().read().dma() {
219 self.start()?;
220 }
221
222 // Clear overrun flag if set.
223 if r.sr().read().ovr() {
224 return self.stop(OverrunError);
225 }
226 match self.ring_buf.read_exact(measurements).await {
227 Ok(len) => Ok(len),
228 Err(_) => self.stop(OverrunError),
229 }
230 }
231}
232
233impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
234 fn drop(&mut self) {
235 self.teardown_adc();
236 rcc::disable::<T>();
237 }
238}
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 44e655b45..e57cd19b3 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -8,8 +8,8 @@ use crate::peripherals::ADC1;
8use crate::time::Hertz; 8use crate::time::Hertz;
9use crate::{Peri, rcc}; 9use crate::{Peri, rcc};
10 10
11mod ringbuffered_v2; 11mod ringbuffered;
12pub use ringbuffered_v2::RingBufferedAdc; 12pub use ringbuffered::RingBufferedAdc;
13 13
14/// Default VREF voltage used for sample conversion to millivolts. 14/// Default VREF voltage used for sample conversion to millivolts.
15pub const VREF_DEFAULT_MV: u32 = 3300; 15pub const VREF_DEFAULT_MV: u32 = 3300;
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index d9a3ce21d..8a0cc0fcf 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -14,10 +14,10 @@ use super::{
14}; 14};
15 15
16#[cfg(any(adc_v3, adc_g0, adc_u0))] 16#[cfg(any(adc_v3, adc_g0, adc_u0))]
17mod ringbuffered_v3; 17mod ringbuffered;
18 18
19#[cfg(any(adc_v3, adc_g0, adc_u0))] 19#[cfg(any(adc_v3, adc_g0, adc_u0))]
20use ringbuffered_v3::RingBufferedAdc; 20use ringbuffered::RingBufferedAdc;
21 21
22use crate::dma::Transfer; 22use crate::dma::Transfer;
23use crate::{Peri, pac, rcc}; 23use crate::{Peri, pac, rcc};