1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
use core::marker::PhantomData;
use core::sync::atomic::{Ordering, compiler_fence};
#[allow(unused_imports)]
use embassy_hal_internal::Peri;
use super::AdcRegs;
#[allow(unused_imports)]
use crate::adc::{Instance, RxDma};
use crate::dma::Channel;
#[allow(unused_imports)]
use crate::dma::{ReadableRingBuffer, TransferOptions};
use crate::rcc;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct OverrunError;
pub struct RingBufferedAdc<'d, T: Instance> {
_phantom: PhantomData<T>,
ring_buf: ReadableRingBuffer<'d, u16>,
}
impl<'d, T: Instance> RingBufferedAdc<'d, T> {
pub(crate) fn new<D: RxDma<T>>(
dma: Peri<'d, D>,
irq: impl crate::interrupt::typelevel::Binding<D::Interrupt, crate::dma::InterruptHandler<D>> + 'd,
dma_buf: &'d mut [u16],
sequence_len: usize,
) -> Self {
// DMA side setup - configuration differs between DMA/BDMA and GPDMA
// For DMA/BDMA: use circular mode via TransferOptions
// For GPDMA: circular mode is achieved via linked-list ping-pong
#[cfg(not(gpdma))]
let opts = TransferOptions {
half_transfer_ir: true,
circular: true,
..Default::default()
};
#[cfg(gpdma)]
let opts = TransferOptions {
half_transfer_ir: true,
..Default::default()
};
// Safety: we forget the struct before this function returns.
let request = dma.request();
let mut ring_buf =
unsafe { ReadableRingBuffer::new(Channel::new(dma, irq), request, T::regs().data(), dma_buf, opts) };
// Align reads to the scan sequence boundary so that channel assignments
// never shift after an overrun recovery.
ring_buf.set_alignment(sequence_len);
Self {
_phantom: PhantomData,
ring_buf,
}
}
/// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
pub fn start(&mut self) {
compiler_fence(Ordering::SeqCst);
self.ring_buf.start();
T::regs().start();
}
pub fn stop(&mut self) {
self.ring_buf.request_pause();
compiler_fence(Ordering::SeqCst);
}
pub fn clear(&mut self) {
self.ring_buf.clear();
}
/// See [`ReadableDmaRingBuffer::set_alignment`] for details.
pub fn set_alignment(&mut self, alignment: usize) {
self.ring_buf.set_alignment(alignment);
}
/// Reads measurements from the DMA ring buffer.
///
/// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
/// 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.
///
/// Each call to `read` will populate the `measurements` array in the same order as the channels
/// defined with `sequence`. 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. For example if 2
/// channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`.
///
/// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly
/// running tasks. Otherwise, you'll see constant Overrun errors occurring, this means that
/// you're sampling too quickly for the task to handle, and you may need to increase the buffer size.
/// Example:
/// ```rust,ignore
/// const DMA_BUF_LEN: usize = 120;
/// use embassy_stm32::adc::{Adc, AdcChannel}
///
/// let mut adc = Adc::new(p.ADC1);
/// let mut adc_pin0 = p.PA0.degrade_adc();
/// let mut adc_pin1 = p.PA1.degrade_adc();
/// let adc_dma_buf = [0u16; DMA_BUF_LEN];
///
/// let mut ring_buffered_adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
/// p.DMA2_CH0,
/// adc_dma_buf, [
/// (&mut *adc_pin0, SampleTime::CYCLES160_5),
/// (&mut *adc_pin1, SampleTime::CYCLES160_5),
/// ].into_iter());
///
///
/// let mut measurements = [0u16; DMA_BUF_LEN / 2];
/// loop {
/// match ring_buffered_adc.read(&mut measurements).await {
/// Ok(_) => {
/// defmt::info!("adc1: {}", measurements);
/// }
/// Err(e) => {
/// defmt::warn!("Error: {:?}", e);
/// }
/// }
/// }
/// ```
///
///
/// [`teardown_adc`]: #method.teardown_adc
/// [`start_continuous_sampling`]: #method.start_continuous_sampling
pub async fn read(&mut self, measurements: &mut [u16]) -> Result<usize, OverrunError> {
assert_eq!(
self.ring_buf.capacity() / 2,
measurements.len(),
"Buffer size must be half the size of the ring buffer"
);
if !self.ring_buf.is_running() {
self.start();
}
// #[cfg(adc_v2)]
// {
// // Clear overrun flag if set.
// if T::regs().sr().read().ovr() {
// self.stop();
//
// return Err(OverrunError);
// }
// }
self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
}
/// Read the most recent ADC measurements, discarding any older data.
///
/// Returns the number of samples actually read into `measurements`. Unlike [`read`](Self::read),
/// this method **never returns an overrun error**. If the DMA has lapped the consumer
/// (e.g. because the task was not scheduled quickly enough), old data is silently
/// discarded and only the most recent samples are returned.
///
/// This is ideal for use cases like ADC oversampling where the consumer only cares about
/// the latest values and stale data can be safely ignored.
pub fn read_latest(&mut self, measurements: &mut [u16]) -> usize {
if !self.ring_buf.is_running() {
self.start();
}
self.ring_buf.read_latest(measurements)
}
/// Read bytes that are readily available in the ring buffer.
/// If no bytes are currently available in the buffer the call waits until the some
/// bytes are available (at least one byte and at most half the buffer size)
///
/// Background receive is started if `start_continuous_sampling()` has not been previously called.
///
/// Receive in the background is terminated if an error is returned.
/// It must then manually be started again by calling `start_continuous_sampling()` or by re-calling `blocking_read()`.
pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
if !self.ring_buf.is_running() {
self.start();
}
// #[cfg(adc_v2)]
// {
// // Clear overrun flag if set.
// if T::regs().sr().read().ovr() {
// self.stop();
//
// return Err(OverrunError);
// }
// }
loop {
match self.ring_buf.read(buf) {
Ok((0, _)) => {}
Ok((len, _)) => {
return Ok(len);
}
Err(_) => {
self.ring_buf.request_pause();
return Err(OverrunError);
}
}
}
}
}
impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
fn drop(&mut self) {
T::regs().stop();
compiler_fence(Ordering::SeqCst);
self.ring_buf.request_pause();
rcc::disable::<T>();
}
}