aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-13 12:02:38 -0600
committerxoviat <[email protected]>2025-11-13 12:02:38 -0600
commit32408f4a031dff11c1c3c8c4aeb2044f1a7e8f42 (patch)
tree83db411fc79c4f544f77a84973370bfd6f7ada2a
parenta8de2ccb8c0721284281715ce6eda28271db3950 (diff)
adc: extract c0
-rw-r--r--embassy-stm32/src/adc/c0.rs488
-rw-r--r--embassy-stm32/src/adc/mod.rs53
-rw-r--r--examples/stm32c0/src/bin/adc.rs18
3 files changed, 214 insertions, 345 deletions
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index 8992d6e6e..983e7c10d 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -1,12 +1,10 @@
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::Scandir;
5 5
6use super::{ 6use super::{Adc, Instance, Resolution, blocking_delay_us};
7 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, 7use crate::adc::{AnyInstance, ConversionMode};
8};
9use crate::dma::Transfer;
10use crate::time::Hertz; 8use crate::time::Hertz;
11use crate::{Peri, pac, rcc}; 9use crate::{Peri, pac, rcc};
12 10
@@ -32,104 +30,184 @@ impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
32 const CHANNEL: u8 = 9; 30 const CHANNEL: u8 = 9;
33} 31}
34 32
35#[derive(Copy, Clone, Debug)] 33fn from_ker_ck(frequency: Hertz) -> Presc {
36pub enum Prescaler { 34 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0;
37 NotDivided, 35 match raw_prescaler {
38 DividedBy2, 36 0 => Presc::DIV1,
39 DividedBy4, 37 1 => Presc::DIV2,
40 DividedBy6, 38 2..=3 => Presc::DIV4,
41 DividedBy8, 39 4..=5 => Presc::DIV6,
42 DividedBy10, 40 6..=7 => Presc::DIV8,
43 DividedBy12, 41 8..=9 => Presc::DIV10,
44 DividedBy16, 42 10..=11 => Presc::DIV12,
45 DividedBy32, 43 _ => unimplemented!(),
46 DividedBy64, 44 }
47 DividedBy128,
48 DividedBy256,
49} 45}
50 46
51impl Prescaler { 47impl<T: Instance> super::SealedAnyInstance for T {
52 fn from_ker_ck(frequency: Hertz) -> Self { 48 fn dr() -> *mut u16 {
53 let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; 49 T::regs().dr().as_ptr() as *mut u16
54 match raw_prescaler {
55 0 => Self::NotDivided,
56 1 => Self::DividedBy2,
57 2..=3 => Self::DividedBy4,
58 4..=5 => Self::DividedBy6,
59 6..=7 => Self::DividedBy8,
60 8..=9 => Self::DividedBy10,
61 10..=11 => Self::DividedBy12,
62 _ => unimplemented!(),
63 }
64 } 50 }
65 51
66 #[allow(unused)] 52 fn enable() {
67 fn divisor(&self) -> u32 { 53 T::regs().isr().modify(|w| w.set_adrdy(true));
68 match self { 54 T::regs().cr().modify(|w| w.set_aden(true));
69 Prescaler::NotDivided => 1, 55 // ADRDY is "ADC ready". Wait until it will be True.
70 Prescaler::DividedBy2 => 2, 56 while !T::regs().isr().read().adrdy() {}
71 Prescaler::DividedBy4 => 4, 57 }
72 Prescaler::DividedBy6 => 6, 58
73 Prescaler::DividedBy8 => 8, 59 fn start() {
74 Prescaler::DividedBy10 => 10, 60 // Start conversion
75 Prescaler::DividedBy12 => 12, 61 T::regs().cr().modify(|reg| {
76 Prescaler::DividedBy16 => 16, 62 reg.set_adstart(true);
77 Prescaler::DividedBy32 => 32, 63 });
78 Prescaler::DividedBy64 => 64, 64 }
79 Prescaler::DividedBy128 => 128, 65
80 Prescaler::DividedBy256 => 256, 66 fn stop() {
67 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
68 T::regs().cr().modify(|reg| {
69 reg.set_adstp(Adstp::STOP);
70 });
71 while T::regs().cr().read().adstart() {}
81 } 72 }
73
74 // Reset configuration.
75 T::regs().cfgr1().modify(|reg| {
76 reg.set_cont(false);
77 reg.set_dmacfg(Dmacfg::from_bits(0));
78 reg.set_dmaen(false);
79 });
82 } 80 }
83 81
84 fn presc(&self) -> Presc { 82 fn configure_dma(conversion_mode: super::ConversionMode) {
85 match self { 83 match conversion_mode {
86 Prescaler::NotDivided => Presc::DIV1, 84 ConversionMode::Singular => {
87 Prescaler::DividedBy2 => Presc::DIV2, 85 // Enable overrun control, so no new DMA requests will be generated until
88 Prescaler::DividedBy4 => Presc::DIV4, 86 // previous DR values is read.
89 Prescaler::DividedBy6 => Presc::DIV6, 87 T::regs().isr().modify(|reg| {
90 Prescaler::DividedBy8 => Presc::DIV8, 88 reg.set_ovr(true);
91 Prescaler::DividedBy10 => Presc::DIV10, 89 });
92 Prescaler::DividedBy12 => Presc::DIV12, 90
93 Prescaler::DividedBy16 => Presc::DIV16, 91 // Set continuous mode with oneshot dma.
94 Prescaler::DividedBy32 => Presc::DIV32, 92 T::regs().cfgr1().modify(|reg| {
95 Prescaler::DividedBy64 => Presc::DIV64, 93 reg.set_discen(false);
96 Prescaler::DividedBy128 => Presc::DIV128, 94 reg.set_cont(true);
97 Prescaler::DividedBy256 => Presc::DIV256, 95 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
96 reg.set_dmaen(true);
97 reg.set_ovrmod(Ovrmod::PRESERVE);
98 });
99 }
98 } 100 }
99 } 101 }
100}
101 102
102#[cfg(feature = "defmt")] 103 fn configure_sequence(mut sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool) {
103impl<'a> defmt::Format for Prescaler { 104 T::regs().cfgr1().modify(|reg| {
104 fn format(&self, fmt: defmt::Formatter) { 105 reg.set_chselrmod(!blocking);
105 match self { 106 reg.set_align(Align::RIGHT);
106 Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), 107 });
107 Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), 108
108 Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), 109 assert!(!blocking || sequence.len() == 1, "Sequence len must be 1 for blocking.");
109 Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), 110 if blocking {
110 Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), 111 let ((ch, _), sample_time) = sequence.next().unwrap();
111 Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), 112 // Set all channels to use SMP1 field as source.
112 Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), 113 T::regs().smpr().modify(|w| {
113 Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), 114 w.smpsel(0);
114 Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), 115 w.set_smp1(sample_time);
115 Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), 116 });
116 Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), 117
117 Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), 118 // write() because we want all other bits to be set to 0.
119 T::regs().chselr().write(|w| w.set_chsel(ch.into(), true));
120 } else {
121 let mut hw_channel_selection: u32 = 0;
122 let mut is_ordered_up = true;
123 let mut is_ordered_down = true;
124 let mut needs_hw = false;
125
126 assert!(
127 sequence.len() <= CHSELR_SQ_SIZE,
128 "Sequence read set cannot be more than {} in size.",
129 CHSELR_SQ_SIZE
130 );
131 let mut last_sq_set: usize = 0;
132 let mut last_channel: u8 = 0;
133 T::regs().chselr_sq().write(|w| {
134 for (i, ((channel, _), _sample_time)) in sequence.enumerate() {
135 needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL;
136 last_sq_set = i;
137 is_ordered_up = is_ordered_up && channel > last_channel;
138 is_ordered_down = is_ordered_down && channel < last_channel;
139 hw_channel_selection += 1 << channel;
140 last_channel = channel;
141
142 if !needs_hw {
143 w.set_sq(i, channel);
144 }
145 }
146
147 assert!(
148 !needs_hw || is_ordered_up || is_ordered_down,
149 "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.",
150 CHSELR_SQ_MAX_CHANNEL
151 );
152
153 if needs_hw {
154 assert!(
155 hw_channel_selection != 0,
156 "Some bits in `hw_channel_selection` shall be set."
157 );
158 assert!(
159 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
160 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
161 NUM_HW_CHANNELS
162 );
163
164 T::regs().cfgr1().modify(|reg| {
165 reg.set_chselrmod(false);
166 reg.set_scandir(if is_ordered_up { Scandir::UP} else { Scandir::BACK });
167 });
168
169 // Set required channels for multi-convert.
170 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
171 } else {
172 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
173 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
174 }
175 }
176 });
118 } 177 }
178
179 // Trigger and wait for the channel selection procedure to complete.
180 T::regs().isr().modify(|w| w.set_ccrdy(false));
181 while !T::regs().isr().read().ccrdy() {}
182 }
183
184 fn convert() -> u16 {
185 // Set single conversion mode.
186 T::regs().cfgr1().modify(|w| w.set_cont(false));
187
188 // Start conversion
189 T::regs().cr().modify(|reg| {
190 reg.set_adstart(true);
191 });
192
193 // Waiting for End Of Conversion (EOC).
194 while !T::regs().isr().read().eoc() {}
195
196 T::regs().dr().read().data() as u16
119 } 197 }
120} 198}
121 199
122impl<'d, T: Instance> Adc<'d, T> { 200impl<'d, T: AnyInstance> Adc<'d, T> {
123 /// Create a new ADC driver. 201 /// Create a new ADC driver.
124 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { 202 pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self {
125 rcc::enable_and_reset::<T>(); 203 rcc::enable_and_reset::<T>();
126 204
127 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); 205 T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK));
128 206
129 let prescaler = Prescaler::from_ker_ck(T::frequency()); 207 let prescaler = from_ker_ck(T::frequency());
130 T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 208 T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
131 209
132 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 210 let frequency = T::frequency() / prescaler;
133 debug!("ADC frequency set to {}", frequency); 211 debug!("ADC frequency set to {}", frequency);
134 212
135 if frequency > MAX_ADC_CLK_FREQ { 213 if frequency > MAX_ADC_CLK_FREQ {
@@ -139,22 +217,6 @@ impl<'d, T: Instance> Adc<'d, T> {
139 ); 217 );
140 } 218 }
141 219
142 let mut s = Self { adc };
143
144 s.power_up();
145
146 s.set_resolution(resolution);
147
148 s.calibrate();
149
150 s.enable();
151
152 s.configure_default();
153
154 s
155 }
156
157 fn power_up(&mut self) {
158 T::regs().cr().modify(|reg| { 220 T::regs().cr().modify(|reg| {
159 reg.set_advregen(true); 221 reg.set_advregen(true);
160 }); 222 });
@@ -162,9 +224,9 @@ impl<'d, T: Instance> Adc<'d, T> {
162 // "The software must wait for the ADC voltage regulator startup time." 224 // "The software must wait for the ADC voltage regulator startup time."
163 // See datasheet for the value. 225 // See datasheet for the value.
164 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); 226 blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1);
165 }
166 227
167 fn calibrate(&mut self) { 228 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
229
168 // We have to make sure AUTOFF is OFF, but keep its value after calibration. 230 // We have to make sure AUTOFF is OFF, but keep its value after calibration.
169 let autoff_value = T::regs().cfgr1().read().autoff(); 231 let autoff_value = T::regs().cfgr1().read().autoff();
170 T::regs().cfgr1().modify(|w| w.set_autoff(false)); 232 T::regs().cfgr1().modify(|w| w.set_autoff(false));
@@ -178,22 +240,17 @@ impl<'d, T: Instance> Adc<'d, T> {
178 debug!("ADC calibration value: {}.", T::regs().dr().read().data()); 240 debug!("ADC calibration value: {}.", T::regs().dr().read().data());
179 241
180 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); 242 T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value));
181 }
182 243
183 fn enable(&mut self) { 244 T::enable();
184 T::regs().isr().modify(|w| w.set_adrdy(true));
185 T::regs().cr().modify(|w| w.set_aden(true));
186 // ADRDY is "ADC ready". Wait until it will be True.
187 while !T::regs().isr().read().adrdy() {}
188 }
189 245
190 fn configure_default(&mut self) {
191 // single conversion mode, software trigger 246 // single conversion mode, software trigger
192 T::regs().cfgr1().modify(|w| { 247 T::regs().cfgr1().modify(|w| {
193 w.set_cont(false); 248 w.set_cont(false);
194 w.set_exten(Exten::DISABLED); 249 w.set_exten(Exten::DISABLED);
195 w.set_align(Align::RIGHT); 250 w.set_align(Align::RIGHT);
196 }); 251 });
252
253 Self { adc }
197 } 254 }
198 255
199 /// Enable reading the voltage reference internal channel. 256 /// Enable reading the voltage reference internal channel.
@@ -214,219 +271,4 @@ impl<'d, T: Instance> Adc<'d, T> {
214 271
215 super::Temperature {} 272 super::Temperature {}
216 } 273 }
217
218 /// Set the ADC sample time.
219 /// Shall only be called when ADC is not converting.
220 pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) {
221 // Set all channels to use SMP1 field as source.
222 T::regs().smpr().modify(|w| {
223 w.smpsel(0);
224 w.set_smp1(sample_time);
225 });
226 }
227
228 /// Set the ADC resolution.
229 pub fn set_resolution(&mut self, resolution: Resolution) {
230 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
231 }
232
233 /// Perform a single conversion.
234 fn convert(&mut self) -> u16 {
235 // Set single conversion mode.
236 T::regs().cfgr1().modify(|w| w.set_cont(false));
237
238 // Start conversion
239 T::regs().cr().modify(|reg| {
240 reg.set_adstart(true);
241 });
242
243 // Waiting for End Of Conversion (EOC).
244 while !T::regs().isr().read().eoc() {}
245
246 T::regs().dr().read().data() as u16
247 }
248
249 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 {
250 self.set_sample_time_all_channels(sample_time);
251
252 Self::configure_channel(channel);
253 T::regs().cfgr1().write(|reg| {
254 reg.set_chselrmod(false);
255 reg.set_align(Align::RIGHT);
256 });
257 self.convert()
258 }
259
260 fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) {
261 assert!(
262 channel_sequence.len() <= CHSELR_SQ_SIZE,
263 "Seqenced read set cannot be more than {} in size.",
264 CHSELR_SQ_SIZE
265 );
266 let mut last_sq_set: usize = 0;
267 T::regs().chselr_sq().write(|w| {
268 for (i, channel) in channel_sequence.enumerate() {
269 assert!(
270 channel.channel() <= CHSELR_SQ_MAX_CHANNEL,
271 "Sequencer only support HW channels smaller than {}.",
272 CHSELR_SQ_MAX_CHANNEL
273 );
274 w.set_sq(i, channel.channel());
275 last_sq_set = i;
276 }
277
278 for i in (last_sq_set + 1)..CHSELR_SQ_SIZE {
279 w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER);
280 }
281 });
282
283 Self::apply_channel_conf()
284 }
285
286 async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) {
287 // Enable overrun control, so no new DMA requests will be generated until
288 // previous DR values is read.
289 T::regs().isr().modify(|reg| {
290 reg.set_ovr(true);
291 });
292
293 // Set continuous mode with oneshot dma.
294 T::regs().cfgr1().modify(|reg| {
295 reg.set_discen(false);
296 reg.set_cont(true);
297 reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT);
298 reg.set_dmaen(true);
299 reg.set_ovrmod(Ovrmod::PRESERVE);
300 });
301
302 let request = rx_dma.request();
303 let transfer = unsafe {
304 Transfer::new_read(
305 rx_dma,
306 request,
307 T::regs().dr().as_ptr() as *mut u16,
308 readings,
309 Default::default(),
310 )
311 };
312
313 // Start conversion.
314 T::regs().cr().modify(|reg| {
315 reg.set_adstart(true);
316 });
317
318 // Wait for conversion sequence to finish.
319 transfer.await;
320
321 // Ensure conversions are finished.
322 Self::cancel_conversions();
323
324 // Reset configuration.
325 T::regs().cfgr1().modify(|reg| {
326 reg.set_cont(false);
327 reg.set_dmacfg(Dmacfg::from_bits(0));
328 reg.set_dmaen(false);
329 });
330 }
331
332 /// Read one or multiple ADC channels using DMA in hardware order.
333 /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting.
334 /// Readings won't be in the same order as in the `set`!
335 ///
336 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
337 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
338 /// TODO(chudsaviet): externalize generic code and merge with read().
339 pub async fn read_in_hw_order(
340 &mut self,
341 rx_dma: Peri<'_, impl RxDma<T>>,
342 hw_channel_selection: u32,
343 scandir: Scandir,
344 readings: &mut [u16],
345 ) {
346 assert!(
347 hw_channel_selection != 0,
348 "Some bits in `hw_channel_selection` shall be set."
349 );
350 assert!(
351 (hw_channel_selection >> NUM_HW_CHANNELS) == 0,
352 "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.",
353 NUM_HW_CHANNELS
354 );
355 // To check for correct readings slice size, we shall solve Hamming weight problem,
356 // which is either slow or memory consuming.
357 // Since we have limited resources, we don't do it here.
358 // Not doing this have a great potential for a bug through.
359
360 // Ensure no conversions are ongoing.
361 Self::cancel_conversions();
362
363 T::regs().cfgr1().modify(|reg| {
364 reg.set_chselrmod(false);
365 reg.set_scandir(scandir);
366 reg.set_align(Align::RIGHT);
367 });
368
369 // Set required channels for multi-convert.
370 unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) }
371
372 Self::apply_channel_conf();
373
374 self.dma_convert(rx_dma, readings).await
375 }
376
377 // Read ADC channels in specified order using DMA (CHSELRMOD = 1).
378 // In STM32C0, only lower 14 ADC channels can be read this way.
379 // For other channels, use `read_in_hw_order()` or blocking read.
380 pub async fn read(
381 &mut self,
382 rx_dma: Peri<'_, impl RxDma<T>>,
383 channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>,
384 readings: &mut [u16],
385 ) {
386 assert!(
387 channel_sequence.len() != 0,
388 "Asynchronous read channel sequence cannot be empty."
389 );
390 assert!(
391 channel_sequence.len() == readings.len(),
392 "Channel sequence length must be equal to readings length."
393 );
394
395 // Ensure no conversions are ongoing.
396 Self::cancel_conversions();
397
398 T::regs().cfgr1().modify(|reg| {
399 reg.set_chselrmod(true);
400 reg.set_align(Align::RIGHT);
401 });
402
403 Self::setup_channel_sequencer(channel_sequence);
404
405 self.dma_convert(rx_dma, readings).await
406 }
407
408 fn configure_channel(channel: &mut impl AdcChannel<T>) {
409 channel.setup();
410 // write() because we want all other bits to be set to 0.
411 T::regs()
412 .chselr()
413 .write(|w| w.set_chsel(channel.channel().into(), true));
414
415 Self::apply_channel_conf();
416 }
417
418 fn apply_channel_conf() {
419 // Trigger and wait for the channel selection procedure to complete.
420 T::regs().isr().modify(|w| w.set_ccrdy(false));
421 while !T::regs().isr().read().ccrdy() {}
422 }
423
424 fn cancel_conversions() {
425 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
426 T::regs().cr().modify(|reg| {
427 reg.set_adstp(Adstp::STOP);
428 });
429 while T::regs().cr().read().adstart() {}
430 }
431 }
432} 274}
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index fd5b94224..549f2f5a5 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -88,30 +88,37 @@ pub(crate) trait SealedAdcChannel<T> {
88} 88}
89 89
90// Temporary patch for ADCs that have not implemented the standard iface yet 90// Temporary patch for ADCs that have not implemented the standard iface yet
91#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1, adc_c0))] 91#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))]
92trait_set::trait_set! { 92trait_set::trait_set! {
93 pub trait AnyInstance = Instance; 93 pub trait AnyInstance = Instance;
94} 94}
95 95
96#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 96#[cfg(any(
97 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
98))]
97pub trait BasicAnyInstance { 99pub trait BasicAnyInstance {
98 type SampleTime; 100 type SampleTime;
99} 101}
100 102
101#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 103#[cfg(any(
104 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
105))]
102pub(self) trait SealedAnyInstance: BasicAnyInstance { 106pub(self) trait SealedAnyInstance: BasicAnyInstance {
103 fn enable(); 107 fn enable();
104 fn start(); 108 fn start();
105 fn stop(); 109 fn stop();
106 fn convert() -> u16; 110 fn convert() -> u16;
107 fn configure_dma(conversion_mode: ConversionMode); 111 fn configure_dma(conversion_mode: ConversionMode);
112 #[cfg(not(adc_c0))]
108 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); 113 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>);
114 #[cfg(adc_c0)]
115 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool);
109 #[allow(dead_code)] 116 #[allow(dead_code)]
110 fn dr() -> *mut u16; 117 fn dr() -> *mut u16;
111} 118}
112 119
113// On chips without ADC4, AnyInstance is an Instance 120// On chips without ADC4, AnyInstance is an Instance
114#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4))] 121#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))]
115#[allow(private_bounds)] 122#[allow(private_bounds)]
116pub trait AnyInstance: SealedAnyInstance + Instance {} 123pub trait AnyInstance: SealedAnyInstance + Instance {}
117 124
@@ -121,12 +128,16 @@ pub trait AnyInstance: SealedAnyInstance + Instance {}
121pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} 128pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {}
122 129
123// Implement AnyInstance automatically for SealedAnyInstance 130// Implement AnyInstance automatically for SealedAnyInstance
124#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 131#[cfg(any(
132 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
133))]
125impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { 134impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T {
126 type SampleTime = SampleTime; 135 type SampleTime = SampleTime;
127} 136}
128 137
129#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 138#[cfg(any(
139 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
140))]
130impl<T: SealedAnyInstance + Instance> AnyInstance for T {} 141impl<T: SealedAnyInstance + Instance> AnyInstance for T {}
131 142
132/// Performs a busy-wait delay for a specified number of microseconds. 143/// Performs a busy-wait delay for a specified number of microseconds.
@@ -167,10 +178,12 @@ pub enum Averaging {
167 Samples1024, 178 Samples1024,
168} 179}
169 180
170#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 181#[cfg(any(
182 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0
183))]
171pub(crate) enum ConversionMode { 184pub(crate) enum ConversionMode {
172 // Should match the cfg on "read" below 185 // Should match the cfg on "read" below
173 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 186 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
174 Singular, 187 Singular,
175 // Should match the cfg on "into_ring_buffered" below 188 // Should match the cfg on "into_ring_buffered" below
176 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] 189 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
@@ -190,7 +203,9 @@ pub enum RegularConversionMode {
190} 203}
191 204
192impl<'d, T: AnyInstance> Adc<'d, T> { 205impl<'d, T: AnyInstance> Adc<'d, T> {
193 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba))] 206 #[cfg(any(
207 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0
208 ))]
194 /// Read an ADC pin. 209 /// Read an ADC pin.
195 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { 210 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 {
196 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 211 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
@@ -198,12 +213,18 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
198 213
199 #[cfg(not(adc_v4))] 214 #[cfg(not(adc_v4))]
200 T::enable(); 215 T::enable();
216 #[cfg(not(adc_c0))]
201 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); 217 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
218 #[cfg(adc_c0)]
219 T::configure_sequence(
220 [((channel.channel(), channel.is_differential()), sample_time)].into_iter(),
221 true,
222 );
202 223
203 T::convert() 224 T::convert()
204 } 225 }
205 226
206 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 227 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
207 /// Read one or multiple ADC regular channels using DMA. 228 /// Read one or multiple ADC regular channels using DMA.
208 /// 229 ///
209 /// `sequence` iterator and `readings` must have the same length. 230 /// `sequence` iterator and `readings` must have the same length.
@@ -232,6 +253,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
232 /// 253 ///
233 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use 254 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
234 /// `into_ring_buffered`, `into_ring_buffered_and_injected` 255 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
256 ///
257 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
258 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
259 ///
260 /// In addtion, on STM320, this method will panic if the channels are not passed in order
235 pub async fn read( 261 pub async fn read(
236 &mut self, 262 &mut self,
237 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, 263 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
@@ -252,8 +278,15 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
252 T::stop(); 278 T::stop();
253 T::enable(); 279 T::enable();
254 280
281 #[cfg(not(adc_c0))]
282 T::configure_sequence(
283 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
284 );
285
286 #[cfg(adc_c0)]
255 T::configure_sequence( 287 T::configure_sequence(
256 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), 288 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
289 false,
257 ); 290 );
258 291
259 T::configure_dma(ConversionMode::Singular); 292 T::configure_dma(ConversionMode::Singular);
diff --git a/examples/stm32c0/src/bin/adc.rs b/examples/stm32c0/src/bin/adc.rs
index b52c9e7f8..ad597b63c 100644
--- a/examples/stm32c0/src/bin/adc.rs
+++ b/examples/stm32c0/src/bin/adc.rs
@@ -3,7 +3,6 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::vals::Scandir;
7use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime}; 6use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime};
8use embassy_stm32::peripherals::ADC1; 7use embassy_stm32::peripherals::ADC1;
9use embassy_time::Timer; 8use embassy_time::Timer;
@@ -35,8 +34,12 @@ async fn main(_spawner: Spawner) {
35 blocking_vref, blocking_temp, blocing_pin0 34 blocking_vref, blocking_temp, blocing_pin0
36 ); 35 );
37 36
38 let channels_seqence: [&mut AnyAdcChannel<ADC1>; 3] = [&mut vref, &mut temp, &mut pin0]; 37 let channels_sequence: [(&mut AnyAdcChannel<ADC1>, SampleTime); 3] = [
39 adc.read(dma.reborrow(), channels_seqence.into_iter(), &mut read_buffer) 38 (&mut vref, SampleTime::CYCLES12_5),
39 (&mut temp, SampleTime::CYCLES12_5),
40 (&mut pin0, SampleTime::CYCLES12_5),
41 ];
42 adc.read(dma.reborrow(), channels_sequence.into_iter(), &mut read_buffer)
40 .await; 43 .await;
41 // Values are ordered according to hardware ADC channel number! 44 // Values are ordered according to hardware ADC channel number!
42 info!( 45 info!(
@@ -44,15 +47,6 @@ async fn main(_spawner: Spawner) {
44 read_buffer[0], read_buffer[1], read_buffer[2] 47 read_buffer[0], read_buffer[1], read_buffer[2]
45 ); 48 );
46 49
47 let hw_channel_selection: u32 =
48 (1 << temp.get_hw_channel()) + (1 << vref.get_hw_channel()) + (1 << pin0.get_hw_channel());
49 adc.read_in_hw_order(dma.reborrow(), hw_channel_selection, Scandir::UP, &mut read_buffer)
50 .await;
51 info!(
52 "DMA ADC read in hardware order: vref = {}, temp = {}, pin0 = {}.",
53 read_buffer[2], read_buffer[1], read_buffer[0]
54 );
55
56 Timer::after_millis(2000).await; 50 Timer::after_millis(2000).await;
57 } 51 }
58} 52}