aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authorAndres Vahter <[email protected]>2024-06-26 23:50:12 +0300
committerAndres Vahter <[email protected]>2024-07-02 17:07:18 +0300
commit5e2fd8623a01e8c026ba2057dd017b4d4bca3acb (patch)
tree07bbbf014578b17de905a8c242604b6467c5a08b /embassy-stm32
parent70061e74b2b4e4ca513bcefa5c3bebbb52538e5d (diff)
stm32 adc v3 read_async
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/src/adc/v3.rs192
1 files changed, 176 insertions, 16 deletions
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 398c57a92..559751555 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,8 +1,10 @@
1use cfg_if::cfg_if; 1use cfg_if::cfg_if;
2use embassy_hal_internal::into_ref; 2use embassy_hal_internal::into_ref;
3 3
4use super::blocking_delay_us; 4use super::{
5use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 5 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel,
6};
7use crate::dma::Transfer;
6use crate::{rcc, Peripheral}; 8use crate::{rcc, Peripheral};
7 9
8/// Default VREF voltage used for sample conversion to millivolts. 10/// Default VREF voltage used for sample conversion to millivolts.
@@ -12,7 +14,7 @@ pub const VREF_CALIB_MV: u32 = 3000;
12 14
13pub struct VrefInt; 15pub struct VrefInt;
14impl<T: Instance> AdcChannel<T> for VrefInt {} 16impl<T: Instance> AdcChannel<T> for VrefInt {}
15impl<T: Instance> super::SealedAdcChannel<T> for VrefInt { 17impl<T: Instance> SealedAdcChannel<T> for VrefInt {
16 fn channel(&self) -> u8 { 18 fn channel(&self) -> u8 {
17 cfg_if! { 19 cfg_if! {
18 if #[cfg(adc_g0)] { 20 if #[cfg(adc_g0)] {
@@ -31,7 +33,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for VrefInt {
31 33
32pub struct Temperature; 34pub struct Temperature;
33impl<T: Instance> AdcChannel<T> for Temperature {} 35impl<T: Instance> AdcChannel<T> for Temperature {}
34impl<T: Instance> super::SealedAdcChannel<T> for Temperature { 36impl<T: Instance> SealedAdcChannel<T> for Temperature {
35 fn channel(&self) -> u8 { 37 fn channel(&self) -> u8 {
36 cfg_if! { 38 cfg_if! {
37 if #[cfg(adc_g0)] { 39 if #[cfg(adc_g0)] {
@@ -50,7 +52,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
50 52
51pub struct Vbat; 53pub struct Vbat;
52impl<T: Instance> AdcChannel<T> for Vbat {} 54impl<T: Instance> AdcChannel<T> for Vbat {}
53impl<T: Instance> super::SealedAdcChannel<T> for Vbat { 55impl<T: Instance> SealedAdcChannel<T> for Vbat {
54 fn channel(&self) -> u8 { 56 fn channel(&self) -> u8 {
55 cfg_if! { 57 cfg_if! {
56 if #[cfg(adc_g0)] { 58 if #[cfg(adc_g0)] {
@@ -101,6 +103,7 @@ impl<'d, T: Instance> Adc<'d, T> {
101 reg.set_advregen(true); 103 reg.set_advregen(true);
102 }); 104 });
103 105
106 // If this is false then each ADC_CHSELR bit enables an input channel.
104 #[cfg(any(adc_g0, adc_u0))] 107 #[cfg(any(adc_g0, adc_u0))]
105 T::regs().cfgr1().modify(|reg| { 108 T::regs().cfgr1().modify(|reg| {
106 reg.set_chselrmod(false); 109 reg.set_chselrmod(false);
@@ -124,6 +127,28 @@ impl<'d, T: Instance> Adc<'d, T> {
124 } 127 }
125 } 128 }
126 129
130 // Enable ADC only when it is not already running.
131 fn enable(&mut self) {
132 // Make sure bits are off
133 while T::regs().cr().read().addis() {
134 // spin
135 }
136
137 if !T::regs().cr().read().aden() {
138 // Enable ADC
139 T::regs().isr().modify(|reg| {
140 reg.set_adrdy(true);
141 });
142 T::regs().cr().modify(|reg| {
143 reg.set_aden(true);
144 });
145
146 while !T::regs().isr().read().adrdy() {
147 // spin
148 }
149 }
150 }
151
127 pub fn enable_vrefint(&self) -> VrefInt { 152 pub fn enable_vrefint(&self) -> VrefInt {
128 #[cfg(not(any(adc_g0, adc_u0)))] 153 #[cfg(not(any(adc_g0, adc_u0)))]
129 T::common_regs().ccr().modify(|reg| { 154 T::common_regs().ccr().modify(|reg| {
@@ -181,10 +206,17 @@ impl<'d, T: Instance> Adc<'d, T> {
181 Vbat {} 206 Vbat {}
182 } 207 }
183 208
209 /// Set the ADC sample time.
184 pub fn set_sample_time(&mut self, sample_time: SampleTime) { 210 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
185 self.sample_time = sample_time; 211 self.sample_time = sample_time;
186 } 212 }
187 213
214 /// Get the ADC sample time.
215 pub fn sample_time(&self) -> SampleTime {
216 self.sample_time
217 }
218
219 /// Set the ADC resolution.
188 pub fn set_resolution(&mut self, resolution: Resolution) { 220 pub fn set_resolution(&mut self, resolution: Resolution) {
189 #[cfg(not(any(adc_g0, adc_u0)))] 221 #[cfg(not(any(adc_g0, adc_u0)))]
190 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); 222 T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
@@ -220,24 +252,139 @@ impl<'d, T: Instance> Adc<'d, T> {
220 T::regs().dr().read().0 as u16 252 T::regs().dr().read().0 as u16
221 } 253 }
222 254
255 /// Read an ADC channel.
223 pub fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { 256 pub fn read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
224 // Make sure bits are off 257 self.read_channel(channel)
225 while T::regs().cr().read().addis() { 258 }
226 // spin 259
260 /// Asynchronously read from sequence of ADC channels.
261 pub async fn read_async(
262 &mut self,
263 rx_dma: &mut impl RxDma<T>,
264 sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>,
265 data: &mut [u16],
266 ) {
267 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
268
269 assert!(
270 sequence.len() <= 16,
271 "Asynchronous read sequence cannot be more than 16 in length"
272 );
273
274 // Ensure no conversions are ongoing and ADC is enabled.
275 Self::cancel_conversions();
276 self.enable();
277
278 // Set sequence length
279 #[cfg(not(any(adc_g0, adc_u0)))]
280 T::regs().sqr1().modify(|w| {
281 w.set_l(sequence.len() as u8 - 1);
282 });
283
284 #[cfg(any(adc_g0, adc_u0))]
285 let mut channel_mask = 0;
286
287 // Configure channels and ranks
288 for (_i, (channel, sample_time)) in sequence.enumerate() {
289 Self::configure_channel(channel, sample_time);
290
291 // Each channel is sampled according to sequence
292 #[cfg(not(any(adc_g0, adc_u0)))]
293 match _i {
294 0..=3 => {
295 T::regs().sqr1().modify(|w| {
296 w.set_sq(_i, channel.channel());
297 });
298 }
299 4..=8 => {
300 T::regs().sqr2().modify(|w| {
301 w.set_sq(_i - 4, channel.channel());
302 });
303 }
304 9..=13 => {
305 T::regs().sqr3().modify(|w| {
306 w.set_sq(_i - 9, channel.channel());
307 });
308 }
309 14..=15 => {
310 T::regs().sqr4().modify(|w| {
311 w.set_sq(_i - 14, channel.channel());
312 });
313 }
314 _ => unreachable!(),
315 }
316
317 #[cfg(any(adc_g0, adc_u0))]
318 {
319 channel_mask |= 1 << channel.channel();
320 }
227 } 321 }
228 322
229 // Enable ADC 323 // On G0 and U0 enabled channels are sampled from 0 to last channel.
324 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
325 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
326 #[cfg(any(adc_g0, adc_u0))]
327 T::regs().chselr().modify(|reg| {
328 reg.set_chsel(channel_mask);
329 });
330
331 // Set continuous mode with oneshot dma.
332 // Clear overrun flag before starting transfer.
230 T::regs().isr().modify(|reg| { 333 T::regs().isr().modify(|reg| {
231 reg.set_adrdy(true); 334 reg.set_ovr(true);
335 });
336
337 #[cfg(not(any(adc_g0, adc_u0)))]
338 T::regs().cfgr().modify(|reg| {
339 reg.set_discen(false);
340 reg.set_cont(true);
341 // Oneshot mode
342 reg.set_dmacfg(false);
343 reg.set_dmaen(true);
232 }); 344 });
345 #[cfg(any(adc_g0, adc_u0))]
346 T::regs().cfgr1().modify(|reg| {
347 reg.set_discen(false);
348 reg.set_cont(true);
349 // Oneshot mode
350 reg.set_dmacfg(false);
351 reg.set_dmaen(true);
352 });
353
354 let request = rx_dma.request();
355 let transfer = unsafe {
356 Transfer::new_read(
357 rx_dma,
358 request,
359 T::regs().dr().as_ptr() as *mut u16,
360 data,
361 Default::default(),
362 )
363 };
364
365 // Start conversion
233 T::regs().cr().modify(|reg| { 366 T::regs().cr().modify(|reg| {
234 reg.set_aden(true); 367 reg.set_adstart(true);
235 }); 368 });
236 369
237 while !T::regs().isr().read().adrdy() { 370 // Wait for conversion sequence to finish.
238 // spin 371 transfer.await;
239 }
240 372
373 // Ensure conversions are finished.
374 Self::cancel_conversions();
375
376 // Reset configuration.
377 #[cfg(not(any(adc_g0, adc_u0)))]
378 T::regs().cfgr().modify(|reg| {
379 reg.set_cont(false);
380 });
381 #[cfg(any(adc_g0, adc_u0))]
382 T::regs().cfgr1().modify(|reg| {
383 reg.set_cont(false);
384 });
385 }
386
387 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
241 // RM0492, RM0481, etc. 388 // RM0492, RM0481, etc.
242 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." 389 // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected."
243 #[cfg(adc_h5)] 390 #[cfg(adc_h5)]
@@ -246,7 +393,12 @@ impl<'d, T: Instance> Adc<'d, T> {
246 } 393 }
247 394
248 // Configure channel 395 // Configure channel
249 Self::set_channel_sample_time(channel.channel(), self.sample_time); 396 Self::set_channel_sample_time(channel.channel(), sample_time);
397 }
398
399 fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
400 self.enable();
401 Self::configure_channel(channel, self.sample_time);
250 402
251 // Select channel 403 // Select channel
252 #[cfg(not(any(adc_g0, adc_u0)))] 404 #[cfg(not(any(adc_g0, adc_u0)))]
@@ -262,7 +414,6 @@ impl<'d, T: Instance> Adc<'d, T> {
262 // STM32G4: Section 2.7.3 414 // STM32G4: Section 2.7.3
263 #[cfg(any(rcc_l4, rcc_g4))] 415 #[cfg(any(rcc_l4, rcc_g4))]
264 let _ = self.convert(); 416 let _ = self.convert();
265
266 let val = self.convert(); 417 let val = self.convert();
267 418
268 T::regs().cr().modify(|reg| reg.set_addis(true)); 419 T::regs().cr().modify(|reg| reg.set_addis(true));
@@ -294,4 +445,13 @@ impl<'d, T: Instance> Adc<'d, T> {
294 } 445 }
295 } 446 }
296 } 447 }
448
449 fn cancel_conversions() {
450 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
451 T::regs().cr().modify(|reg| {
452 reg.set_adstp(true);
453 });
454 while T::regs().cr().read().adstart() {}
455 }
456 }
297} 457}