aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndres Vahter <[email protected]>2024-07-02 15:22:50 +0300
committerAndres Vahter <[email protected]>2024-07-02 16:53:49 +0300
commitb88e1a5d7180871d7e8564a3060b50e166602902 (patch)
tree7bf1627e8779df21b73571adee70df445ead6baf
parent6f21d5e478292352df5cabcc1aa302ae7f8998a3 (diff)
stm32 ringbuffered adc docs
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs70
1 files changed, 68 insertions, 2 deletions
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
index fb29d9a8c..82b67c533 100644
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ b/embassy-stm32/src/adc/ringbuffered_v2.rs
@@ -91,6 +91,15 @@ pub struct RingBufferedAdc<'d, T: Instance> {
91} 91}
92 92
93impl<'d, T: Instance> Adc<'d, T> { 93impl<'d, T: Instance> Adc<'d, T> {
94 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
95 ///
96 /// The `dma_buf` should be large enough to prevent buffer overflow, allowing sufficient time to read out measurements.
97 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
98 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
99 ///
100 /// `read_exact` method is used to read out measurements from the DMA ring buffer, and its buffer should be exactly half of the `dma_buf` length.
101 ///
102 /// [`read_exact`]: #method.read_exact
94 pub fn into_ring_buffered( 103 pub fn into_ring_buffered(
95 self, 104 self,
96 dma: impl Peripheral<P = impl RxDma<T>> + 'd, 105 dma: impl Peripheral<P = impl RxDma<T>> + 'd,
@@ -214,6 +223,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
214 Self::start_adc(); 223 Self::start_adc();
215 } 224 }
216 225
226 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
217 pub fn start(&mut self) -> Result<(), OverrunError> { 227 pub fn start(&mut self) -> Result<(), OverrunError> {
218 self.ring_buf.clear(); 228 self.ring_buf.clear();
219 229
@@ -227,6 +237,11 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
227 Err(err) 237 Err(err)
228 } 238 }
229 239
240 /// Stops DMA transfer.
241 /// It does not turn off ADC.
242 /// Calling `start` restarts continuous DMA transfer.
243 ///
244 /// [`start`]: #method.start
230 pub fn teardown_adc(&mut self) { 245 pub fn teardown_adc(&mut self) {
231 // Stop the DMA transfer 246 // Stop the DMA transfer
232 self.ring_buf.request_stop(); 247 self.ring_buf.request_stop();
@@ -341,7 +356,58 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
341 } 356 }
342 } 357 }
343 358
344 pub async fn read_exact<const N: usize>(&mut self, buf: &mut [u16; N]) -> Result<usize, OverrunError> { 359 /// Reads measurements from the DMA ring buffer.
360 ///
361 /// This method fills the provided `measurements` array with ADC readings.
362 /// The length of the `measurements` array should be exactly half of the DMA buffer length.
363 /// Because interrupts are only generated if half or full DMA transfer completes.
364 ///
365 /// Each call to `read_exact` will populate the `measurements` array in the same order as the channels defined with `set_sample_sequence`.
366 /// 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.
367 /// For example if 3 channels are sampled `measurements` contain: `[sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3 sq0 sq1 sq3..]`.
368 ///
369 /// If an error is returned, it indicates a DMA overrun, and the process must be restarted by calling `start` again.
370 ///
371 /// 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.
372 /// Note that even if using `teardown_adc` to control sample rate, with each call to `read_exact`, measurements equivalent to half the size of the DMA buffer are still collected.
373 ///
374 /// Example:
375 /// ```rust,ignore
376 /// const DMA_BUF_LEN: usize = 120;
377 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
378 /// let mut adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(p.DMA2_CH0, adc_dma_buf);
379 ///
380 /// adc.set_sample_sequence(Sequence::One, &mut p.PA0, SampleTime::CYCLES112);
381 /// adc.set_sample_sequence(Sequence::Two, &mut p.PA1, SampleTime::CYCLES112);
382 /// adc.set_sample_sequence(Sequence::Three, &mut p.PA2, SampleTime::CYCLES112);
383 ///
384 /// adc.start.unwrap();
385 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
386 /// loop {
387 /// match adc.read_exact(&mut measurements).await {
388 /// Ok(_) => {
389 /// defmt::info!("adc1: {}", measurements);
390 /// // Only needed to manually control sample rate.
391 /// adc.teardown_adc();
392 /// }
393 /// Err(e) => {
394 /// defmt::warn!("Error: {:?}", e);
395 /// // DMA overflow, restart ADC.
396 /// let _ = adc.start();
397 /// }
398 /// }
399 ///
400 /// // Manually control sample rate.
401 /// Timer::after_millis(100).await;
402 /// let _ = adc.start();
403 /// }
404 /// ```
405 ///
406 ///
407 /// [`set_sample_sequence`]: #method.set_sample_sequence
408 /// [`teardown_adc`]: #method.teardown_adc
409 /// [`start`]: #method.start
410 pub async fn read_exact<const N: usize>(&mut self, measurements: &mut [u16; N]) -> Result<usize, OverrunError> {
345 let r = T::regs(); 411 let r = T::regs();
346 412
347 // Start background receive if it was not already started 413 // Start background receive if it was not already started
@@ -353,7 +419,7 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
353 if r.sr().read().ovr() { 419 if r.sr().read().ovr() {
354 return self.stop(OverrunError); 420 return self.stop(OverrunError);
355 } 421 }
356 match self.ring_buf.read_exact(buf).await { 422 match self.ring_buf.read_exact(measurements).await {
357 Ok(len) => Ok(len), 423 Ok(len) => Ok(len),
358 Err(_) => self.stop(OverrunError), 424 Err(_) => self.stop(OverrunError),
359 } 425 }