aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-03 14:35:13 -0600
committerxoviat <[email protected]>2025-11-03 14:35:13 -0600
commit7ba1eeffbb111630bd40842272cfffe82f117a51 (patch)
tree1a40d8a141f0b5f72b7f5d6036a3f00e2adc38bd
parenta967d77a0f0eedcc65778528cceee07edbba2813 (diff)
stm32/adc: update v2 iface to match v3
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v2.rs139
-rw-r--r--embassy-stm32/src/adc/v2.rs145
2 files changed, 149 insertions, 135 deletions
diff --git a/embassy-stm32/src/adc/ringbuffered_v2.rs b/embassy-stm32/src/adc/ringbuffered_v2.rs
index 9b2e5b8fe..ecb8ae3f2 100644
--- a/embassy-stm32/src/adc/ringbuffered_v2.rs
+++ b/embassy-stm32/src/adc/ringbuffered_v2.rs
@@ -1,13 +1,10 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::mem;
3use core::sync::atomic::{Ordering, compiler_fence}; 2use core::sync::atomic::{Ordering, compiler_fence};
4 3
5use stm32_metapac::adc::vals::SampleTime; 4use crate::adc::Instance;
6 5use crate::dma::ReadableRingBuffer;
7use crate::adc::{Adc, AdcChannel, Instance, RxDma};
8use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
9use crate::pac::adc::vals; 6use crate::pac::adc::vals;
10use crate::{Peri, rcc}; 7use crate::rcc;
11 8
12#[cfg_attr(feature = "defmt", derive(defmt::Format))] 9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
13pub struct OverrunError; 10pub struct OverrunError;
@@ -20,7 +17,7 @@ fn clear_interrupt_flags(r: crate::pac::adc::Adc) {
20} 17}
21 18
22#[derive(PartialOrd, PartialEq, Debug, Clone, Copy)] 19#[derive(PartialOrd, PartialEq, Debug, Clone, Copy)]
23pub enum Sequence { 20pub(super) enum Sequence {
24 One, 21 One,
25 Two, 22 Two,
26 Three, 23 Three,
@@ -87,44 +84,8 @@ impl From<u8> for Sequence {
87} 84}
88 85
89pub struct RingBufferedAdc<'d, T: Instance> { 86pub struct RingBufferedAdc<'d, T: Instance> {
90 _phantom: PhantomData<T>, 87 pub(super) _phantom: PhantomData<T>,
91 ring_buf: ReadableRingBuffer<'d, u16>, 88 pub(super) ring_buf: ReadableRingBuffer<'d, u16>,
92}
93
94impl<'d, T: Instance> Adc<'d, T> {
95 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
96 ///
97 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
98 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
99 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
100 ///
101 /// `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.
102 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
103 ///
104 /// [`read`]: #method.read
105 pub fn into_ring_buffered(self, dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> RingBufferedAdc<'d, T> {
106 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
107
108 let opts: crate::dma::TransferOptions = TransferOptions {
109 half_transfer_ir: true,
110 priority: Priority::VeryHigh,
111 ..Default::default()
112 };
113
114 // Safety: we forget the struct before this function returns.
115 let rx_src = T::regs().dr().as_ptr() as *mut u16;
116 let request = dma.request();
117
118 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) };
119
120 // Don't disable the clock
121 mem::forget(self);
122
123 RingBufferedAdc {
124 _phantom: PhantomData,
125 ring_buf,
126 }
127 }
128} 89}
129 90
130impl<'d, T: Instance> RingBufferedAdc<'d, T> { 91impl<'d, T: Instance> RingBufferedAdc<'d, T> {
@@ -132,94 +93,6 @@ impl<'d, T: Instance> RingBufferedAdc<'d, T> {
132 T::regs().cr2().read().adon() 93 T::regs().cr2().read().adon()
133 } 94 }
134 95
135 fn stop_adc() {
136 T::regs().cr2().modify(|reg| {
137 reg.set_adon(false);
138 });
139 }
140
141 fn start_adc() {
142 T::regs().cr2().modify(|reg| {
143 reg.set_adon(true);
144 });
145 }
146
147 /// Sets the channel sample time
148 ///
149 /// ## SAFETY:
150 /// - ADON == 0 i.e ADC must not be enabled when this is called.
151 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
152 if ch <= 9 {
153 T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
154 } else {
155 T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
156 }
157 }
158
159 fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) {
160 let ch_iter = ch.iter();
161 for idx in ch_iter {
162 unsafe {
163 Self::set_channel_sample_time(*idx, sample_time);
164 }
165 }
166 }
167
168 pub fn set_sample_sequence(
169 &mut self,
170 sequence: Sequence,
171 channel: &mut impl AdcChannel<T>,
172 sample_time: SampleTime,
173 ) {
174 let was_on = Self::is_on();
175 if !was_on {
176 Self::start_adc();
177 }
178
179 // Check the sequence is long enough
180 T::regs().sqr1().modify(|r| {
181 let prev: Sequence = r.l().into();
182 if prev < sequence {
183 let new_l: Sequence = sequence;
184 trace!("Setting sequence length from {:?} to {:?}", prev as u8, new_l as u8);
185 r.set_l(sequence.into())
186 } else {
187 r.set_l(prev.into())
188 }
189 });
190
191 // Set this GPIO as an analog input.
192 channel.setup();
193
194 // Set the channel in the right sequence field.
195 match sequence {
196 Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())),
197 Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())),
198 Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())),
199 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
200 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
201 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
202 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())),
203 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())),
204 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())),
205 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())),
206 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())),
207 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())),
208 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())),
209 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())),
210 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())),
211 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())),
212 };
213
214 if !was_on {
215 Self::stop_adc();
216 }
217
218 self.set_channels_sample_time(&[channel.channel()], sample_time);
219
220 Self::start_adc();
221 }
222
223 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer. 96 /// Turns on ADC if it is not already turned on and starts continuous DMA transfer.
224 pub fn start(&mut self) -> Result<(), OverrunError> { 97 pub fn start(&mut self) -> Result<(), OverrunError> {
225 self.setup_adc(); 98 self.setup_adc();
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 93ec78548..e81e820e3 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -1,11 +1,16 @@
1use core::marker::PhantomData;
2use core::mem;
3
1use super::blocking_delay_us; 4use super::blocking_delay_us;
2use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 5use crate::adc::{Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime};
6use crate::dma::{Priority, ReadableRingBuffer, TransferOptions};
3use crate::peripherals::ADC1; 7use crate::peripherals::ADC1;
4use crate::time::Hertz; 8use crate::time::Hertz;
5use crate::{Peri, rcc}; 9use crate::{Peri, rcc};
10use ringbuffered_v2::Sequence;
6 11
7mod ringbuffered_v2; 12mod ringbuffered_v2;
8pub use ringbuffered_v2::{RingBufferedAdc, Sequence}; 13pub use ringbuffered_v2::RingBufferedAdc;
9 14
10/// Default VREF voltage used for sample conversion to millivolts. 15/// Default VREF voltage used for sample conversion to millivolts.
11pub const VREF_DEFAULT_MV: u32 = 3300; 16pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -112,6 +117,142 @@ where
112 } 117 }
113 } 118 }
114 119
120 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
121 ///
122 /// The `dma_buf` should be large enough to prevent DMA buffer overrun.
123 /// The length of the `dma_buf` should be a multiple of the ADC channel count.
124 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements.
125 ///
126 /// `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.
127 /// It is critical to call `read` frequently to prevent DMA buffer overrun.
128 ///
129 /// [`read`]: #method.read
130 pub fn into_ring_buffered<'a>(
131 mut self,
132 dma: Peri<'d, impl RxDma<T>>,
133 dma_buf: &'d mut [u16],
134 sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<T>, SampleTime)>,
135 ) -> RingBufferedAdc<'d, T> {
136 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
137
138 let opts: crate::dma::TransferOptions = TransferOptions {
139 half_transfer_ir: true,
140 priority: Priority::VeryHigh,
141 ..Default::default()
142 };
143
144 // Safety: we forget the struct before this function returns.
145 let rx_src = T::regs().dr().as_ptr() as *mut u16;
146 let request = dma.request();
147
148 let ring_buf = unsafe { ReadableRingBuffer::new(dma, request, rx_src, dma_buf, opts) };
149
150 for (i, (channel, sample_time)) in sequence.enumerate() {
151 let sequence = match i {
152 0 => Sequence::One,
153 1 => Sequence::Two,
154 2 => Sequence::Three,
155 3 => Sequence::Four,
156 4 => Sequence::Five,
157 5 => Sequence::Six,
158 6 => Sequence::Seven,
159 7 => Sequence::Eight,
160 8 => Sequence::Nine,
161 9 => Sequence::Ten,
162 10 => Sequence::Eleven,
163 11 => Sequence::Twelve,
164 12 => Sequence::Thirteen,
165 13 => Sequence::Fourteen,
166 14 => Sequence::Fifteen,
167 15 => Sequence::Sixteen,
168 _ => unreachable!(),
169 };
170
171 self.set_sample_sequence(sequence, channel, sample_time);
172 }
173
174 // Don't disable the clock
175 mem::forget(self);
176
177 RingBufferedAdc {
178 _phantom: PhantomData,
179 ring_buf,
180 }
181 }
182
183 fn is_on() -> bool {
184 T::regs().cr2().read().adon()
185 }
186
187 fn stop_adc() {
188 T::regs().cr2().modify(|reg| {
189 reg.set_adon(false);
190 });
191 }
192
193 fn start_adc() {
194 T::regs().cr2().modify(|reg| {
195 reg.set_adon(true);
196 });
197 }
198
199 fn set_sample_sequence(&mut self, sequence: Sequence, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
200 let was_on = Self::is_on();
201 if !was_on {
202 Self::start_adc();
203 }
204
205 // Check the sequence is long enough
206 T::regs().sqr1().modify(|r| {
207 let prev: Sequence = r.l().into();
208 if prev < sequence {
209 let new_l: Sequence = sequence;
210 trace!("Setting sequence length from {:?} to {:?}", prev as u8, new_l as u8);
211 r.set_l(sequence.into())
212 } else {
213 r.set_l(prev.into())
214 }
215 });
216
217 // Set this GPIO as an analog input.
218 channel.setup();
219
220 // Set the channel in the right sequence field.
221 match sequence {
222 Sequence::One => T::regs().sqr3().modify(|w| w.set_sq(0, channel.channel())),
223 Sequence::Two => T::regs().sqr3().modify(|w| w.set_sq(1, channel.channel())),
224 Sequence::Three => T::regs().sqr3().modify(|w| w.set_sq(2, channel.channel())),
225 Sequence::Four => T::regs().sqr3().modify(|w| w.set_sq(3, channel.channel())),
226 Sequence::Five => T::regs().sqr3().modify(|w| w.set_sq(4, channel.channel())),
227 Sequence::Six => T::regs().sqr3().modify(|w| w.set_sq(5, channel.channel())),
228 Sequence::Seven => T::regs().sqr2().modify(|w| w.set_sq(0, channel.channel())),
229 Sequence::Eight => T::regs().sqr2().modify(|w| w.set_sq(1, channel.channel())),
230 Sequence::Nine => T::regs().sqr2().modify(|w| w.set_sq(2, channel.channel())),
231 Sequence::Ten => T::regs().sqr2().modify(|w| w.set_sq(3, channel.channel())),
232 Sequence::Eleven => T::regs().sqr2().modify(|w| w.set_sq(4, channel.channel())),
233 Sequence::Twelve => T::regs().sqr2().modify(|w| w.set_sq(5, channel.channel())),
234 Sequence::Thirteen => T::regs().sqr1().modify(|w| w.set_sq(0, channel.channel())),
235 Sequence::Fourteen => T::regs().sqr1().modify(|w| w.set_sq(1, channel.channel())),
236 Sequence::Fifteen => T::regs().sqr1().modify(|w| w.set_sq(2, channel.channel())),
237 Sequence::Sixteen => T::regs().sqr1().modify(|w| w.set_sq(3, channel.channel())),
238 };
239
240 if !was_on {
241 Self::stop_adc();
242 }
243
244 self.set_channels_sample_time(&[channel.channel()], sample_time);
245
246 Self::start_adc();
247 }
248
249 fn set_channels_sample_time(&mut self, ch: &[u8], sample_time: SampleTime) {
250 let ch_iter = ch.iter();
251 for idx in ch_iter {
252 Self::set_channel_sample_time(*idx, sample_time);
253 }
254 }
255
115 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 256 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
116 self.sample_time = sample_time; 257 self.sample_time = sample_time;
117 } 258 }