aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/adc/c0.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/adc/c0.rs')
-rw-r--r--embassy-stm32/src/adc/c0.rs535
1 files changed, 161 insertions, 374 deletions
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index f2837a8f1..2f0f326af 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -1,14 +1,12 @@
1use pac::adc::vals::Scandir;
2#[allow(unused)] 1#[allow(unused)]
3use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; 2use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr};
4use pac::adccommon::vals::Presc; 3use pac::adccommon::vals::Presc;
4use stm32_metapac::adc::vals::{SampleTime, Scandir};
5 5
6use super::{ 6use super::{Adc, Instance, Resolution, blocking_delay_us};
7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 7use crate::adc::{AdcRegs, ConversionMode};
8};
9use crate::dma::Transfer;
10use crate::time::Hertz; 8use crate::time::Hertz;
11use crate::{pac, rcc, Peri}; 9use crate::{Peri, pac, rcc};
12 10
13/// Default VREF voltage used for sample conversion to millivolts. 11/// Default VREF voltage used for sample conversion to millivolts.
14pub const VREF_DEFAULT_MV: u32 = 3300; 12pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -19,189 +17,198 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(25);
19 17
20const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20; 18const TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US: u32 = 20;
21 19
22const TEMP_CHANNEL: u8 = 9;
23const VREF_CHANNEL: u8 = 10;
24
25const NUM_HW_CHANNELS: u8 = 22;
26const CHSELR_SQ_SIZE: usize = 8; 20const CHSELR_SQ_SIZE: usize = 8;
27const CHSELR_SQ_MAX_CHANNEL: u8 = 14; 21const CHSELR_SQ_MAX_CHANNEL: u8 = 14;
28const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111; 22const CHSELR_SQ_SEQUENCE_END_MARKER: u8 = 0b1111;
29 23
30// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, 24impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
31// this currently cannot be modeled with stm32-data, 25 const CHANNEL: u8 = 10;
32// so these are available from the software on all ADCs.
33/// Internal voltage reference channel.
34pub struct VrefInt;
35impl<T: Instance> AdcChannel<T> for VrefInt {}
36impl<T: Instance> SealedAdcChannel<T> for VrefInt {
37 fn channel(&self) -> u8 {
38 VREF_CHANNEL
39 }
40} 26}
41 27
42/// Internal temperature channel. 28impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
43pub struct Temperature; 29 const CHANNEL: u8 = 9;
44impl<T: Instance> AdcChannel<T> for Temperature {}
45impl<T: Instance> SealedAdcChannel<T> for Temperature {
46 fn channel(&self) -> u8 {
47 TEMP_CHANNEL
48 }
49} 30}
50 31
51#[derive(Copy, Clone, Debug)] 32fn from_ker_ck(frequency: Hertz) -> Presc {
52pub enum Prescaler { 33 let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
53 NotDivided, 34 match raw_prescaler {
54 DividedBy2, 35 0 => Presc::DIV1,
55 DividedBy4, 36 1 => Presc::DIV2,
56 DividedBy6, 37 2..=3 => Presc::DIV4,
57 DividedBy8, 38 4..=5 => Presc::DIV6,
58 DividedBy10, 39 6..=7 => Presc::DIV8,
59 DividedBy12, 40 8..=9 => Presc::DIV10,
60 DividedBy16, 41 10..=11 => Presc::DIV12,
61 DividedBy32, 42 _ => unimplemented!(),
62 DividedBy64, 43 }
63 DividedBy128,
64 DividedBy256,
65} 44}
66 45
67impl Prescaler { 46impl AdcRegs for crate::pac::adc::Adc {
68 fn from_ker_ck(frequency: Hertz) -> Self { 47 fn data(&self) -> *mut u16 {
69 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 48 crate::pac::adc::Adc::dr(*self).as_ptr() as *mut u16
70 match raw_prescaler {
71 0 => Self::NotDivided,
72 1 => Self::DividedBy2,
73 2..=3 => Self::DividedBy4,
74 4..=5 => Self::DividedBy6,
75 6..=7 => Self::DividedBy8,
76 8..=9 => Self::DividedBy10,
77 10..=11 => Self::DividedBy12,
78 _ => unimplemented!(),
79 }
80 } 49 }
81 50
82 #[allow(unused)] 51 fn enable(&self) {
83 fn divisor(&self) -> u32 { 52 self.isr().modify(|w| w.set_adrdy(true));
84 match self { 53 self.cr().modify(|w| w.set_aden(true));
85 Prescaler::NotDivided => 1, 54 // ADRDY is "ADC ready". Wait until it will be True.
86 Prescaler::DividedBy2 => 2, 55 while !self.isr().read().adrdy() {}
87 Prescaler::DividedBy4 => 4, 56 }
88 Prescaler::DividedBy6 => 6, 57
89 Prescaler::DividedBy8 => 8, 58 fn start(&self) {
90 Prescaler::DividedBy10 => 10, 59 // Start conversion
91 Prescaler::DividedBy12 => 12, 60 self.cr().modify(|reg| {
92 Prescaler::DividedBy16 => 16, 61 reg.set_adstart(true);
93 Prescaler::DividedBy32 => 32, 62 });
94 Prescaler::DividedBy64 => 64,
95 Prescaler::DividedBy128 => 128,
96 Prescaler::DividedBy256 => 256,
97 }
98 } 63 }
99 64
100 fn presc(&self) -> Presc { 65 fn stop(&self) {
101 match self { 66 if self.cr().read().adstart() && !self.cr().read().addis() {
102 Prescaler::NotDivided => Presc::DIV1, 67 self.cr().modify(|reg| {
103 Prescaler::DividedBy2 => Presc::DIV2, 68 reg.set_adstp(Adstp::STOP);
104 Prescaler::DividedBy4 => Presc::DIV4, 69 });
105 Prescaler::DividedBy6 => Presc::DIV6, 70 while self.cr().read().adstart() {}
106 Prescaler::DividedBy8 => Presc::DIV8,
107 Prescaler::DividedBy10 => Presc::DIV10,
108 Prescaler::DividedBy12 => Presc::DIV12,
109 Prescaler::DividedBy16 => Presc::DIV16,
110 Prescaler::DividedBy32 => Presc::DIV32,
111 Prescaler::DividedBy64 => Presc::DIV64,
112 Prescaler::DividedBy128 => Presc::DIV128,
113 Prescaler::DividedBy256 => Presc::DIV256,
114 } 71 }
72
73 // Reset configuration.
74 self.cfgr1().modify(|reg| {
75 reg.set_cont(false);
76 reg.set_dmacfg(Dmacfg::from_bits(0));
77 reg.set_dmaen(false);
78 });
115 } 79 }
116}
117 80
118#[cfg(feature = "defmt")] 81 fn configure_dma(&self, conversion_mode: super::ConversionMode) {
119impl<'a> defmt::Format for Prescaler { 82 match conversion_mode {
120 fn format(&self, fmt: defmt::Formatter) { 83 ConversionMode::Singular => {
121 match self { 84 // Enable overrun control, so no new DMA requests will be generated until
122 Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), 85 // previous DR values is read.
123 Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), 86 self.isr().modify(|reg| {
124 Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), 87 reg.set_ovr(true);
125 Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), 88 });
126 Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), 89
127 Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), 90 // Set continuous mode with oneshot dma.
128 Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), 91 self.cfgr1().modify(|reg| {
129 Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), 92 reg.set_discen(false);
130 Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), 93 reg.set_cont(true);
131 Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), 94 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
132 Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), 95 reg.set_dmaen(true);
133 Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), 96 reg.set_ovrmod(Ovrmod::PRESERVE);
97 });
98 }
134 } 99 }
135 } 100 }
136}
137 101
138/// Number of samples used for averaging. 102 fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>) {
139/// TODO: Implement hardware averaging setting. 103 let mut needs_hw = sequence.len() == 1 || sequence.len() > CHSELR_SQ_SIZE;
140#[allow(unused)] 104 let mut is_ordered_up = true;
141#[derive(Copy, Clone, Debug)] 105 let mut is_ordered_down = true;
142#[cfg_attr(feature = "defmt", derive(defmt::Format))]
143pub enum Averaging {
144 Disabled,
145 Samples2,
146 Samples4,
147 Samples8,
148 Samples16,
149 Samples32,
150 Samples64,
151 Samples128,
152 Samples256,
153 Samples512,
154 Samples1024,
155}
156 106
157impl<'d, T: Instance> Adc<'d, T> { 107 let sequence_len = sequence.len();
158 /// Create a new ADC driver. 108 let mut hw_channel_selection: u32 = 0;
159 pub fn new(adc: Peri<'d, T>, sample_time: SampleTime, resolution: Resolution) -> Self { 109 let mut last_channel: u8 = 0;
160 rcc::enable_and_reset::<T>(); 110 let mut sample_time: Self::SampleTime = SampleTime::CYCLES2_5;
161 111
162 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); 112 self.chselr_sq().write(|w| {
113 for (i, ((channel, _), _sample_time)) in sequence.enumerate() {
114 assert!(
115 sample_time == _sample_time || i == 0,
116 "C0 only supports one sample time for the sequence."
117 );
163 118
164 let prescaler = Prescaler::from_ker_ck(T::frequency()); 119 sample_time = _sample_time;
165 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 120 needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL;
121 is_ordered_up = is_ordered_up && (channel > last_channel || i == 0);
122 is_ordered_down = is_ordered_down && (channel < last_channel || i == 0);
123 hw_channel_selection += 1 << channel;
124 last_channel = channel;
166 125
167 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 126 if !needs_hw {
168 debug!("ADC frequency set to {}", frequency); 127 w.set_sq(i, channel);
128 }
129 }
169 130
170 if frequency > MAX_ADC_CLK_FREQ { 131 for i in sequence_len..CHSELR_SQ_SIZE {
171 panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); 132 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
133 }
134 });
135
136 if needs_hw {
137 assert!(
138 sequence_len <= CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down,
139 "Sequencer is required because of unordered channels, but read set cannot be more than {} in size.",
140 CHSELR_SQ_SIZE
141 );
142 assert!(
143 sequence_len > CHSELR_SQ_SIZE || is_ordered_up || is_ordered_down,
144 "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.",
145 CHSELR_SQ_MAX_CHANNEL
146 );
147
148 // Set required channels for multi-convert.
149 unsafe { (self.chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
172 } 150 }
173 151
174 let mut s = Self { 152 self.smpr().modify(|w| {
175 adc, 153 w.smpsel(0);
176 sample_time: SampleTime::from_bits(0), 154 w.set_smp1(sample_time);
177 }; 155 });
178 156
179 s.power_up(); 157 self.cfgr1().modify(|reg| {
158 reg.set_chselrmod(!needs_hw);
159 reg.set_align(Align::RIGHT);
160 reg.set_scandir(if is_ordered_up { Scandir::UP } else { Scandir::BACK });
161 });
180 162
181 s.set_resolution(resolution); 163 // Trigger and wait for the channel selection procedure to complete.
164 self.isr().modify(|w| w.set_ccrdy(false));
165 while !self.isr().read().ccrdy() {}
166 }
182 167
183 s.calibrate(); 168 fn convert(&self) {
169 // Set single conversion mode.
170 self.cfgr1().modify(|w| w.set_cont(false));
184 171
185 s.enable(); 172 // Start conversion
173 self.cr().modify(|reg| {
174 reg.set_adstart(true);
175 });
186 176
187 s.configure_default(); 177 // Waiting for End Of Conversion (EOC).
178 while !self.isr().read().eoc() {}
179 }
180}
188 181
189 s.set_sample_time_all_channels(sample_time); 182impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
183 /// Create a new ADC driver.
184 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self {
185 rcc::enable_and_reset::<T>();
190 186
191 s 187 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
192 } 188
189 let prescaler = from_ker_ck(T::frequency());
190 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
191
192 let frequency = T::frequency() / prescaler;
193 debug!("ADC frequency set to {}", frequency);
194
195 if frequency > MAX_ADC_CLK_FREQ {
196 panic!(
197 "Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.",
198 MAX_ADC_CLK_FREQ.0 / 1_000_000
199 );
200 }
193 201
194 fn power_up(&mut self) {
195 T::regs().cr().modify(|reg| { 202 T::regs().cr().modify(|reg| {
196 reg.set_advregen(true); 203 reg.set_advregen(true);
197 }); 204 });
198 205
199 // "The software must wait for the ADC voltage regulator startup time." 206 // "The software must wait for the ADC voltage regulator startup time."
200 // See datasheet for the value. 207 // See datasheet for the value.
201 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); 208 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US as u64 + 1);
202 } 209
210 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
203 211
204 fn calibrate(&mut self) {
205 // We have to make sure AUTOFF is OFF, but keep its value after calibration. 212 // We have to make sure AUTOFF is OFF, but keep its value after calibration.
206 let autoff_value = T::regs().cfgr1().read().autoff(); 213 let autoff_value = T::regs().cfgr1().read().autoff();
207 T::regs().cfgr1().modify(|w| w.set_autoff(false)); 214 T::regs().cfgr1().modify(|w| w.set_autoff(false));
@@ -215,255 +222,35 @@ impl<'d, T: Instance> Adc<'d, T> {
215 debug!("ADC calibration value: {}.", T::regs().dr().read().data()); 222 debug!("ADC calibration value: {}.", T::regs().dr().read().data());
216 223
217 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); 224 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value));
218 }
219 225
220 fn enable(&mut self) { 226 T::regs().enable();
221 T::regs().isr().modify(|w| w.set_adrdy(true));
222 T::regs().cr().modify(|w| w.set_aden(true));
223 // ADRDY is "ADC ready". Wait until it will be True.
224 while !T::regs().isr().read().adrdy() {}
225 }
226 227
227 fn configure_default(&mut self) {
228 // single conversion mode, software trigger 228 // single conversion mode, software trigger
229 T::regs().cfgr1().modify(|w| { 229 T::regs().cfgr1().modify(|w| {
230 w.set_cont(false); 230 w.set_cont(false);
231 w.set_exten(Exten::DISABLED); 231 w.set_exten(Exten::DISABLED);
232 w.set_align(Align::RIGHT); 232 w.set_align(Align::RIGHT);
233 }); 233 });
234
235 Self { adc }
234 } 236 }
235 237
236 /// Enable reading the voltage reference internal channel. 238 /// Enable reading the voltage reference internal channel.
237 pub fn enable_vrefint(&self) -> VrefInt { 239 pub fn enable_vrefint(&self) -> super::VrefInt {
238 T::common_regs().ccr().modify(|reg| { 240 T::common_regs().ccr().modify(|reg| {
239 reg.set_vrefen(true); 241 reg.set_vrefen(true);
240 }); 242 });
241 243
242 VrefInt {} 244 super::VrefInt {}
243 } 245 }
244 246
245 /// Enable reading the temperature internal channel. 247 /// Enable reading the temperature internal channel.
246 pub fn enable_temperature(&self) -> Temperature { 248 pub fn enable_temperature(&self) -> super::Temperature {
247 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!"); 249 debug!("Ensure that sample time is set to more than temperature sensor T_start from the datasheet!");
248 T::common_regs().ccr().modify(|reg| { 250 T::common_regs().ccr().modify(|reg| {
249 reg.set_tsen(true); 251 reg.set_tsen(true);
250 }); 252 });
251 253
252 Temperature {} 254 super::Temperature {}
253 }
254
255 /// Set the ADC sample time.
256 /// Shall only be called when ADC is not converting.
257 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
258 self.sample_time = sample_time;
259
260 // Set all channels to use SMP1 field as source.
261 T::regs().smpr().modify(|w| {
262 w.smpsel(0);
263 w.set_smp1(sample_time);
264 });
265 }
266
267 /// Set the ADC resolution.
268 pub fn set_resolution(&mut self, resolution: Resolution) {
269 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
270 }
271
272 /// Perform a single conversion.
273 fn convert(&mut self) -> u16 {
274 // Set single conversion mode.
275 T::regs().cfgr1().modify(|w| w.set_cont(false));
276
277 // Start conversion
278 T::regs().cr().modify(|reg| {
279 reg.set_adstart(true);
280 });
281
282 // Waiting for End Of Conversion (EOC).
283 while !T::regs().isr().read().eoc() {}
284
285 T::regs().dr().read().data() as u16
286 }
287
288 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 {
289 Self::configure_channel(channel);
290 T::regs().cfgr1().write(|reg| {
291 reg.set_chselrmod(false);
292 reg.set_align(Align::RIGHT);
293 });
294 self.convert()
295 }
296
297 fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) {
298 assert!(
299 channel_sequence.len() <= CHSELR_SQ_SIZE,
300 "Seqenced read set cannot be more than {} in size.",
301 CHSELR_SQ_SIZE
302 );
303 let mut last_sq_set: usize = 0;
304 T::regs().chselr_sq().write(|w| {
305 for (i, channel) in channel_sequence.enumerate() {
306 assert!(
307 channel.channel() <= CHSELR_SQ_MAX_CHANNEL,
308 "Sequencer only support HW channels smaller than {}.",
309 CHSELR_SQ_MAX_CHANNEL
310 );
311 w.set_sq(i, channel.channel());
312 last_sq_set = i;
313 }
314
315 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
316 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
317 }
318 });
319
320 Self::apply_channel_conf()
321 }
322
323 async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) {
324 // Enable overrun control, so no new DMA requests will be generated until
325 // previous DR values is read.
326 T::regs().isr().modify(|reg| {
327 reg.set_ovr(true);
328 });
329
330 // Set continuous mode with oneshot dma.
331 T::regs().cfgr1().modify(|reg| {
332 reg.set_discen(false);
333 reg.set_cont(true);
334 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
335 reg.set_dmaen(true);
336 reg.set_ovrmod(Ovrmod::PRESERVE);
337 });
338
339 let request = rx_dma.request();
340 let transfer = unsafe {
341 Transfer::new_read(
342 rx_dma,
343 request,
344 T::regs().dr().as_ptr() as *mut u16,
345 readings,
346 Default::default(),
347 )
348 };
349
350 // Start conversion.
351 T::regs().cr().modify(|reg| {
352 reg.set_adstart(true);
353 });
354
355 // Wait for conversion sequence to finish.
356 transfer.await;
357
358 // Ensure conversions are finished.
359 Self::cancel_conversions();
360
361 // Reset configuration.
362 T::regs().cfgr1().modify(|reg| {
363 reg.set_cont(false);
364 reg.set_dmacfg(Dmacfg::from_bits(0));
365 reg.set_dmaen(false);
366 });
367 }
368
369 /// Read one or multiple ADC channels using DMA in hardware order.
370 /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting.
371 /// Readings won't be in the same order as in the `set`!
372 ///
373 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
374 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
375 /// TODO(chudsaviet): externalize generic code and merge with read().
376 pub async fn read_in_hw_order(
377 &mut self,
378 rx_dma: Peri<'_, impl RxDma<T>>,
379 hw_channel_selection: u32,
380 scandir: Scandir,
381 readings: &mut [u16],
382 ) {
383 assert!(
384 hw_channel_selection != 0,
385 "Some bits in `hw_channel_selection` shall be set."
386 );
387 assert!(
388 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
389 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
390 NUM_HW_CHANNELS
391 );
392 // To check for correct readings slice size, we shall solve Hamming weight problem,
393 // which is either slow or memory consuming.
394 // Since we have limited resources, we don't do it here.
395 // Not doing this have a great potential for a bug through.
396
397 // Ensure no conversions are ongoing.
398 Self::cancel_conversions();
399
400 T::regs().cfgr1().modify(|reg| {
401 reg.set_chselrmod(false);
402 reg.set_scandir(scandir);
403 reg.set_align(Align::RIGHT);
404 });
405
406 // Set required channels for multi-convert.
407 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
408
409 Self::apply_channel_conf();
410
411 self.dma_convert(rx_dma, readings).await
412 }
413
414 // Read ADC channels in specified order using DMA (CHSELRMOD = 1).
415 // In STM32C0, only lower 14 ADC channels can be read this way.
416 // For other channels, use `read_in_hw_order()` or blocking read.
417 pub async fn read(
418 &mut self,
419 rx_dma: Peri<'_, impl RxDma<T>>,
420 channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
421 readings: &mut [u16],
422 ) {
423 assert!(
424 channel_sequence.len() != 0,
425 "Asynchronous read channel sequence cannot be empty."
426 );
427 assert!(
428 channel_sequence.len() == readings.len(),
429 "Channel sequence length must be equal to readings length."
430 );
431
432 // Ensure no conversions are ongoing.
433 Self::cancel_conversions();
434
435 T::regs().cfgr1().modify(|reg| {
436 reg.set_chselrmod(true);
437 reg.set_align(Align::RIGHT);
438 });
439
440 Self::setup_channel_sequencer(channel_sequence);
441
442 self.dma_convert(rx_dma, readings).await
443 }
444
445 fn configure_channel(channel: &mut impl AdcChannel<T>) {
446 channel.setup();
447 // write() because we want all other bits to be set to 0.
448 T::regs()
449 .chselr()
450 .write(|w| w.set_chsel(channel.channel().into(), true));
451
452 Self::apply_channel_conf();
453 }
454
455 fn apply_channel_conf() {
456 // Trigger and wait for the channel selection procedure to complete.
457 T::regs().isr().modify(|w| w.set_ccrdy(false));
458 while !T::regs().isr().read().ccrdy() {}
459 }
460
461 fn cancel_conversions() {
462 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
463 T::regs().cr().modify(|reg| {
464 reg.set_adstp(Adstp::STOP);
465 });
466 while T::regs().cr().read().adstart() {}
467 }
468 } 255 }
469} 256}