aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/adc/adc4.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/adc/adc4.rs')
-rw-r--r--embassy-stm32/src/adc/adc4.rs477
1 files changed, 145 insertions, 332 deletions
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 255dc7956..491569c34 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -4,8 +4,8 @@ use pac::adc::vals::{Adc4Dmacfg as Dmacfg, Adc4Exten as Exten, Adc4OversamplingR
4#[cfg(stm32wba)] 4#[cfg(stm32wba)]
5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel}; 5use pac::adc::vals::{Chselrmod, Cont, Dmacfg, Exten, OversamplingRatio, Ovss, Smpsel};
6 6
7use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; 7use super::blocking_delay_us;
8use crate::dma::Transfer; 8use crate::adc::{AdcRegs, ConversionMode, Instance};
9#[cfg(stm32u5)] 9#[cfg(stm32u5)]
10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr; 10pub use crate::pac::adc::regs::Adc4Chselrmod0 as Chselr;
11#[cfg(stm32wba)] 11#[cfg(stm32wba)]
@@ -15,7 +15,7 @@ pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4S
15#[cfg(stm32wba)] 15#[cfg(stm32wba)]
16pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime}; 16pub use crate::pac::adc::vals::{Presc, Res as Resolution, SampleTime};
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{pac, rcc, Peri}; 18use crate::{Peri, pac, rcc};
19 19
20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55); 20const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
21 21
@@ -24,56 +24,24 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
24/// VREF voltage used for factory calibration of VREFINTCAL register. 24/// VREF voltage used for factory calibration of VREFINTCAL register.
25pub const VREF_CALIB_MV: u32 = 3300; 25pub const VREF_CALIB_MV: u32 = 3300;
26 26
27const VREF_CHANNEL: u8 = 0; 27impl super::SealedSpecialConverter<super::VrefInt> for crate::peripherals::ADC4 {
28const VCORE_CHANNEL: u8 = 12; 28 const CHANNEL: u8 = 0;
29const TEMP_CHANNEL: u8 = 13;
30const VBAT_CHANNEL: u8 = 14;
31const DAC_CHANNEL: u8 = 21;
32
33// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs
34/// Internal voltage reference channel.
35pub struct VrefInt;
36impl<T: Instance> AdcChannel<T> for VrefInt {}
37impl<T: Instance> SealedAdcChannel<T> for VrefInt {
38 fn channel(&self) -> u8 {
39 VREF_CHANNEL
40 }
41} 29}
42 30
43/// Internal temperature channel. 31impl super::SealedSpecialConverter<super::Temperature> for crate::peripherals::ADC4 {
44pub struct Temperature; 32 const CHANNEL: u8 = 13;
45impl<T: Instance> AdcChannel<T> for Temperature {}
46impl<T: Instance> SealedAdcChannel<T> for Temperature {
47 fn channel(&self) -> u8 {
48 TEMP_CHANNEL
49 }
50} 33}
51 34
52/// Internal battery voltage channel. 35impl super::SealedSpecialConverter<super::Vcore> for crate::peripherals::ADC4 {
53pub struct Vbat; 36 const CHANNEL: u8 = 12;
54impl<T: Instance> AdcChannel<T> for Vbat {}
55impl<T: Instance> SealedAdcChannel<T> for Vbat {
56 fn channel(&self) -> u8 {
57 VBAT_CHANNEL
58 }
59} 37}
60 38
61/// Internal DAC channel. 39impl super::SealedSpecialConverter<super::Vbat> for crate::peripherals::ADC4 {
62pub struct Dac; 40 const CHANNEL: u8 = 14;
63impl<T: Instance> AdcChannel<T> for Dac {}
64impl<T: Instance> SealedAdcChannel<T> for Dac {
65 fn channel(&self) -> u8 {
66 DAC_CHANNEL
67 }
68} 41}
69 42
70/// Internal Vcore channel. 43impl super::SealedSpecialConverter<super::Dac> for crate::peripherals::ADC4 {
71pub struct Vcore; 44 const CHANNEL: u8 = 21;
72impl<T: Instance> AdcChannel<T> for Vcore {}
73impl<T: Instance> SealedAdcChannel<T> for Vcore {
74 fn channel(&self) -> u8 {
75 VCORE_CHANNEL
76 }
77} 45}
78 46
79#[derive(Copy, Clone)] 47#[derive(Copy, Clone)]
@@ -108,123 +76,145 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 {
108 } 76 }
109} 77}
110 78
111// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 79fn from_ker_ck(frequency: Hertz) -> Presc {
112// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. 80 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
113#[allow(unused)] 81 match raw_prescaler {
114enum Prescaler { 82 0 => Presc::DIV1,
115 NotDivided, 83 1 => Presc::DIV2,
116 DividedBy2, 84 2..=3 => Presc::DIV4,
117 DividedBy4, 85 4..=5 => Presc::DIV6,
118 DividedBy6, 86 6..=7 => Presc::DIV8,
119 DividedBy8, 87 8..=9 => Presc::DIV10,
120 DividedBy10, 88 10..=11 => Presc::DIV12,
121 DividedBy12, 89 _ => unimplemented!(),
122 DividedBy16, 90 }
123 DividedBy32,
124 DividedBy64,
125 DividedBy128,
126 DividedBy256,
127} 91}
128 92
129impl Prescaler { 93impl AdcRegs for crate::pac::adc::Adc4 {
130 fn from_ker_ck(frequency: Hertz) -> Self { 94 fn data(&self) -> *mut u16 {
131 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 95 crate::pac::adc::Adc4::dr(*self).as_ptr() as *mut u16
132 match raw_prescaler { 96 }
133 0 => Self::NotDivided, 97
134 1 => Self::DividedBy2, 98 fn enable(&self) {
135 2..=3 => Self::DividedBy4, 99 if !self.cr().read().aden() || !self.isr().read().adrdy() {
136 4..=5 => Self::DividedBy6, 100 self.isr().write(|w| w.set_adrdy(true));
137 6..=7 => Self::DividedBy8, 101 self.cr().modify(|w| w.set_aden(true));
138 8..=9 => Self::DividedBy10, 102 while !self.isr().read().adrdy() {}
139 10..=11 => Self::DividedBy12,
140 _ => unimplemented!(),
141 } 103 }
142 } 104 }
143 105
144 fn divisor(&self) -> u32 { 106 fn start(&self) {
145 match self { 107 // Start conversion
146 Prescaler::NotDivided => 1, 108 self.cr().modify(|reg| {
147 Prescaler::DividedBy2 => 2, 109 reg.set_adstart(true);
148 Prescaler::DividedBy4 => 4, 110 });
149 Prescaler::DividedBy6 => 6, 111 }
150 Prescaler::DividedBy8 => 8, 112
151 Prescaler::DividedBy10 => 10, 113 fn stop(&self) {
152 Prescaler::DividedBy12 => 12, 114 let cr = self.cr().read();
153 Prescaler::DividedBy16 => 16, 115 if cr.adstart() {
154 Prescaler::DividedBy32 => 32, 116 self.cr().modify(|w| w.set_adstp(true));
155 Prescaler::DividedBy64 => 64, 117 while self.cr().read().adstart() {}
156 Prescaler::DividedBy128 => 128, 118 }
157 Prescaler::DividedBy256 => 256, 119
120 if cr.aden() || cr.adstart() {
121 self.cr().modify(|w| w.set_addis(true));
122 while self.cr().read().aden() {}
158 } 123 }
124
125 // Reset configuration.
126 self.cfgr1().modify(|reg| {
127 reg.set_dmaen(false);
128 });
159 } 129 }
160 130
161 fn presc(&self) -> Presc { 131 fn configure_dma(&self, conversion_mode: ConversionMode) {
162 match self { 132 match conversion_mode {
163 Prescaler::NotDivided => Presc::DIV1, 133 ConversionMode::Singular => {
164 Prescaler::DividedBy2 => Presc::DIV2, 134 self.isr().modify(|reg| {
165 Prescaler::DividedBy4 => Presc::DIV4, 135 reg.set_ovr(true);
166 Prescaler::DividedBy6 => Presc::DIV6, 136 reg.set_eos(true);
167 Prescaler::DividedBy8 => Presc::DIV8, 137 reg.set_eoc(true);
168 Prescaler::DividedBy10 => Presc::DIV10, 138 });
169 Prescaler::DividedBy12 => Presc::DIV12, 139
170 Prescaler::DividedBy16 => Presc::DIV16, 140 self.cfgr1().modify(|reg| {
171 Prescaler::DividedBy32 => Presc::DIV32, 141 reg.set_dmaen(true);
172 Prescaler::DividedBy64 => Presc::DIV64, 142 reg.set_dmacfg(Dmacfg::ONE_SHOT);
173 Prescaler::DividedBy128 => Presc::DIV128, 143 #[cfg(stm32u5)]
174 Prescaler::DividedBy256 => Presc::DIV256, 144 reg.set_chselrmod(false);
145 #[cfg(stm32wba)]
146 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
147 });
148 }
149 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
150 _ => unreachable!(),
175 } 151 }
176 } 152 }
177}
178 153
179pub trait SealedInstance { 154 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), SampleTime)>) {
180 #[allow(unused)] 155 let mut prev_channel: i16 = -1;
181 fn regs() -> crate::pac::adc::Adc4; 156 #[cfg(stm32wba)]
182} 157 self.chselr().write_value(Chselr(0_u32));
158 #[cfg(stm32u5)]
159 self.chselrmod0().write_value(Chselr(0_u32));
160 for (_i, ((channel, _), sample_time)) in sequence.enumerate() {
161 self.smpr().modify(|w| {
162 w.set_smp(_i, sample_time);
163 });
183 164
184pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { 165 let channel_num = channel;
185 type Interrupt: crate::interrupt::typelevel::Interrupt; 166 if channel_num as i16 <= prev_channel {
186} 167 return;
168 };
169 prev_channel = channel_num as i16;
187 170
188pub struct Adc4<'d, T: Instance> { 171 #[cfg(stm32wba)]
189 #[allow(unused)] 172 self.chselr().modify(|w| {
190 adc: crate::Peri<'d, T>, 173 w.set_chsel0(channel as usize, true);
191} 174 });
175 #[cfg(stm32u5)]
176 self.chselrmod0().modify(|w| {
177 w.set_chsel(channel as usize, true);
178 });
179 }
180 }
192 181
193#[derive(Copy, Clone, Debug)] 182 fn convert(&self) {
194pub enum Adc4Error { 183 // Reset interrupts
195 InvalidSequence, 184 self.isr().modify(|reg| {
196 DMAError, 185 reg.set_eos(true);
186 reg.set_eoc(true);
187 });
188
189 // Start conversion
190 self.cr().modify(|reg| {
191 reg.set_adstart(true);
192 });
193
194 while !self.isr().read().eos() {
195 // spin
196 }
197 }
197} 198}
198 199
199impl<'d, T: Instance> Adc4<'d, T> { 200impl<'d, T: Instance<Regs = crate::pac::adc::Adc4>> super::Adc<'d, T> {
200 /// Create a new ADC driver. 201 /// Create a new ADC driver.
201 pub fn new(adc: Peri<'d, T>) -> Self { 202 pub fn new_adc4(adc: Peri<'d, T>) -> Self {
202 rcc::enable_and_reset::<T>(); 203 rcc::enable_and_reset::<T>();
203 let prescaler = Prescaler::from_ker_ck(T::frequency()); 204 let prescaler = from_ker_ck(T::frequency());
204 205
205 T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 206 T::regs().ccr().modify(|w| w.set_presc(prescaler));
206 207
207 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 208 let frequency = T::frequency() / prescaler;
208 info!("ADC4 frequency set to {}", frequency); 209 info!("ADC4 frequency set to {}", frequency);
209 210
210 if frequency > MAX_ADC_CLK_FREQ { 211 if frequency > MAX_ADC_CLK_FREQ {
211 panic!("Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 212 panic!(
213 "Maximal allowed frequency for ADC4 is {} MHz and it varies with different packages, refer to ST docs for more information.",
214 MAX_ADC_CLK_FREQ.0 / 1_000_000
215 );
212 } 216 }
213 217
214 let mut s = Self { adc };
215
216 s.power_up();
217
218 s.calibrate();
219 blocking_delay_us(1);
220
221 s.enable();
222 s.configure();
223
224 s
225 }
226
227 fn power_up(&mut self) {
228 T::regs().isr().modify(|w| { 218 T::regs().isr().modify(|w| {
229 w.set_ldordy(true); 219 w.set_ldordy(true);
230 }); 220 });
@@ -236,22 +226,15 @@ impl<'d, T: Instance> Adc4<'d, T> {
236 T::regs().isr().modify(|w| { 226 T::regs().isr().modify(|w| {
237 w.set_ldordy(true); 227 w.set_ldordy(true);
238 }); 228 });
239 }
240 229
241 fn calibrate(&mut self) {
242 T::regs().cr().modify(|w| w.set_adcal(true)); 230 T::regs().cr().modify(|w| w.set_adcal(true));
243 while T::regs().cr().read().adcal() {} 231 while T::regs().cr().read().adcal() {}
244 T::regs().isr().modify(|w| w.set_eocal(true)); 232 T::regs().isr().modify(|w| w.set_eocal(true));
245 }
246 233
247 fn enable(&mut self) { 234 blocking_delay_us(1);
248 T::regs().isr().write(|w| w.set_adrdy(true)); 235
249 T::regs().cr().modify(|w| w.set_aden(true)); 236 T::regs().enable();
250 while !T::regs().isr().read().adrdy() {}
251 T::regs().isr().write(|w| w.set_adrdy(true));
252 }
253 237
254 fn configure(&mut self) {
255 // single conversion mode, software trigger 238 // single conversion mode, software trigger
256 T::regs().cfgr1().modify(|w| { 239 T::regs().cfgr1().modify(|w| {
257 #[cfg(stm32u5)] 240 #[cfg(stm32u5)]
@@ -277,73 +260,63 @@ impl<'d, T: Instance> Adc4<'d, T> {
277 w.set_smpsel(i, Smpsel::SMP1); 260 w.set_smpsel(i, Smpsel::SMP1);
278 } 261 }
279 }); 262 });
263
264 Self { adc }
280 } 265 }
281 266
282 /// Enable reading the voltage reference internal channel. 267 /// Enable reading the voltage reference internal channel.
283 pub fn enable_vrefint(&self) -> VrefInt { 268 pub fn enable_vrefint_adc4(&self) -> super::VrefInt {
284 T::regs().ccr().modify(|w| { 269 T::regs().ccr().modify(|w| {
285 w.set_vrefen(true); 270 w.set_vrefen(true);
286 }); 271 });
287 272
288 VrefInt {} 273 super::VrefInt {}
289 } 274 }
290 275
291 /// Enable reading the temperature internal channel. 276 /// Enable reading the temperature internal channel.
292 pub fn enable_temperature(&self) -> Temperature { 277 pub fn enable_temperature_adc4(&self) -> super::Temperature {
293 T::regs().ccr().modify(|w| { 278 T::regs().ccr().modify(|w| {
294 w.set_vsensesel(true); 279 w.set_vsensesel(true);
295 }); 280 });
296 281
297 Temperature {} 282 super::Temperature {}
298 } 283 }
299 284
300 /// Enable reading the vbat internal channel. 285 /// Enable reading the vbat internal channel.
301 #[cfg(stm32u5)] 286 #[cfg(stm32u5)]
302 pub fn enable_vbat(&self) -> Vbat { 287 pub fn enable_vbat_adc4(&self) -> super::Vbat {
303 T::regs().ccr().modify(|w| { 288 T::regs().ccr().modify(|w| {
304 w.set_vbaten(true); 289 w.set_vbaten(true);
305 }); 290 });
306 291
307 Vbat {} 292 super::Vbat {}
308 } 293 }
309 294
310 /// Enable reading the vbat internal channel. 295 /// Enable reading the vbat internal channel.
311 pub fn enable_vcore(&self) -> Vcore { 296 pub fn enable_vcore_adc4(&self) -> super::Vcore {
312 Vcore {} 297 super::Vcore {}
313 } 298 }
314 299
315 /// Enable reading the vbat internal channel. 300 /// Enable reading the vbat internal channel.
316 #[cfg(stm32u5)] 301 #[cfg(stm32u5)]
317 pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { 302 pub fn enable_dac_channel_adc4(&self, dac: DacChannel) -> super::Dac {
318 let mux; 303 let mux;
319 match dac { 304 match dac {
320 DacChannel::OUT1 => mux = false, 305 DacChannel::OUT1 => mux = false,
321 DacChannel::OUT2 => mux = true, 306 DacChannel::OUT2 => mux = true,
322 } 307 }
323 T::regs().or().modify(|w| w.set_chn21sel(mux)); 308 T::regs().or().modify(|w| w.set_chn21sel(mux));
324 Dac {} 309 super::Dac {}
325 }
326
327 /// Set the ADC sample time.
328 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
329 T::regs().smpr().modify(|w| {
330 w.set_smp(0, sample_time);
331 });
332 }
333
334 /// Get the ADC sample time.
335 pub fn sample_time(&self) -> SampleTime {
336 T::regs().smpr().read().smp(0)
337 } 310 }
338 311
339 /// Set the ADC resolution. 312 /// Set the ADC resolution.
340 pub fn set_resolution(&mut self, resolution: Resolution) { 313 pub fn set_resolution_adc4(&mut self, resolution: Resolution) {
341 T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); 314 T::regs().cfgr1().modify(|w| w.set_res(resolution.into()));
342 } 315 }
343 316
344 /// Set hardware averaging. 317 /// Set hardware averaging.
345 #[cfg(stm32u5)] 318 #[cfg(stm32u5)]
346 pub fn set_averaging(&mut self, averaging: Averaging) { 319 pub fn set_averaging_adc4(&mut self, averaging: Averaging) {
347 let (enable, samples, right_shift) = match averaging { 320 let (enable, samples, right_shift) = match averaging {
348 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0), 321 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, 0),
349 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1), 322 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, 1),
@@ -363,7 +336,7 @@ impl<'d, T: Instance> Adc4<'d, T> {
363 }) 336 })
364 } 337 }
365 #[cfg(stm32wba)] 338 #[cfg(stm32wba)]
366 pub fn set_averaging(&mut self, averaging: Averaging) { 339 pub fn set_averaging_adc4(&mut self, averaging: Averaging) {
367 let (enable, samples, right_shift) = match averaging { 340 let (enable, samples, right_shift) = match averaging {
368 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0), 341 Averaging::Disabled => (false, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT0),
369 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1), 342 Averaging::Samples2 => (true, OversamplingRatio::OVERSAMPLE2X, Ovss::SHIFT1),
@@ -382,164 +355,4 @@ impl<'d, T: Instance> Adc4<'d, T> {
382 w.set_ovse(enable) 355 w.set_ovse(enable)
383 }) 356 })
384 } 357 }
385
386 /// Read an ADC channel.
387 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
388 channel.setup();
389
390 // Select channel
391 #[cfg(stm32wba)]
392 {
393 T::regs().chselr().write_value(Chselr(0_u32));
394 T::regs().chselr().modify(|w| {
395 w.set_chsel0(channel.channel() as usize, true);
396 });
397 }
398 #[cfg(stm32u5)]
399 {
400 T::regs().chselrmod0().write_value(Chselr(0_u32));
401 T::regs().chselrmod0().modify(|w| {
402 w.set_chsel(channel.channel() as usize, true);
403 });
404 }
405
406 // Reset interrupts
407 T::regs().isr().modify(|reg| {
408 reg.set_eos(true);
409 reg.set_eoc(true);
410 });
411
412 // Start conversion
413 T::regs().cr().modify(|reg| {
414 reg.set_adstart(true);
415 });
416
417 while !T::regs().isr().read().eos() {
418 // spin
419 }
420
421 T::regs().dr().read().0 as u16
422 }
423
424 /// Read one or multiple ADC channels using DMA.
425 ///
426 /// `sequence` iterator and `readings` must have the same length.
427 /// The channels in `sequence` must be in ascending order.
428 ///
429 /// Example
430 /// ```rust,ignore
431 /// use embassy_stm32::adc::adc4;
432 /// use embassy_stm32::adc::AdcChannel;
433 ///
434 /// let mut adc4 = adc4::Adc4::new(p.ADC4);
435 /// let mut adc4_pin1 = p.PC1;
436 /// let mut adc4_pin2 = p.PC0;
437 /// let mut.into()d41 = adc4_pin1.into();
438 /// let mut.into()d42 = adc4_pin2.into();
439 /// let mut measurements = [0u16; 2];
440 /// // not that the channels must be in ascending order
441 /// adc4.read(
442 /// &mut p.GPDMA1_CH1,
443 /// [
444 /// &mut.into()d42,
445 /// &mut.into()d41,
446 /// ]
447 /// .into_iter(),
448 /// &mut measurements,
449 /// ).await.unwrap();
450 /// ```
451 pub async fn read(
452 &mut self,
453 rx_dma: Peri<'_, impl RxDma4<T>>,
454 sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
455 readings: &mut [u16],
456 ) -> Result<(), Adc4Error> {
457 assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty");
458 assert!(
459 sequence.len() == readings.len(),
460 "Sequence length must be equal to readings length"
461 );
462
463 // Ensure no conversions are ongoing
464 Self::cancel_conversions();
465
466 T::regs().isr().modify(|reg| {
467 reg.set_ovr(true);
468 reg.set_eos(true);
469 reg.set_eoc(true);
470 });
471
472 T::regs().cfgr1().modify(|reg| {
473 reg.set_dmaen(true);
474 reg.set_dmacfg(Dmacfg::ONE_SHOT);
475 #[cfg(stm32u5)]
476 reg.set_chselrmod(false);
477 #[cfg(stm32wba)]
478 reg.set_chselrmod(Chselrmod::ENABLE_INPUT)
479 });
480
481 // Verify and activate sequence
482 let mut prev_channel: i16 = -1;
483 #[cfg(stm32wba)]
484 T::regs().chselr().write_value(Chselr(0_u32));
485 #[cfg(stm32u5)]
486 T::regs().chselrmod0().write_value(Chselr(0_u32));
487 for channel in sequence {
488 let channel_num = channel.channel;
489 if channel_num as i16 <= prev_channel {
490 return Err(Adc4Error::InvalidSequence);
491 };
492 prev_channel = channel_num as i16;
493
494 #[cfg(stm32wba)]
495 T::regs().chselr().modify(|w| {
496 w.set_chsel0(channel.channel as usize, true);
497 });
498 #[cfg(stm32u5)]
499 T::regs().chselrmod0().modify(|w| {
500 w.set_chsel(channel.channel as usize, true);
501 });
502 }
503
504 let request = rx_dma.request();
505 let transfer = unsafe {
506 Transfer::new_read(
507 rx_dma,
508 request,
509 T::regs().dr().as_ptr() as *mut u16,
510 readings,
511 Default::default(),
512 )
513 };
514
515 // Start conversion
516 T::regs().cr().modify(|reg| {
517 reg.set_adstart(true);
518 });
519
520 transfer.await;
521
522 // Ensure conversions are finished.
523 Self::cancel_conversions();
524
525 // Reset configuration.
526 T::regs().cfgr1().modify(|reg| {
527 reg.set_dmaen(false);
528 });
529
530 if T::regs().isr().read().ovr() {
531 Err(Adc4Error::DMAError)
532 } else {
533 Ok(())
534 }
535 }
536
537 fn cancel_conversions() {
538 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
539 T::regs().cr().modify(|reg| {
540 reg.set_adstp(true);
541 });
542 while T::regs().cr().read().adstart() {}
543 }
544 }
545} 358}