1 | #[cfg (not(stm32u5))] |
2 | use pac::adc::vals::{Adcaldif, Boost}; |
3 | #[allow (unused)] |
4 | use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; |
5 | use pac::adccommon::vals::Presc; |
6 | |
7 | use super::{ |
8 | blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, |
9 | }; |
10 | use crate::dma::Transfer; |
11 | use crate::time::Hertz; |
12 | use crate::{pac, rcc, Peripheral}; |
13 | |
14 | /// Default VREF voltage used for sample conversion to millivolts. |
15 | pub const VREF_DEFAULT_MV: u32 = 3300; |
16 | /// VREF voltage used for factory calibration of VREFINTCAL register. |
17 | pub const VREF_CALIB_MV: u32 = 3300; |
18 | |
19 | /// Max single ADC operation clock frequency |
20 | #[cfg (stm32g4)] |
21 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); |
22 | #[cfg (stm32h7)] |
23 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); |
24 | #[cfg (stm32u5)] |
25 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(megahertz:55); |
26 | |
27 | #[cfg (stm32g4)] |
28 | const VREF_CHANNEL: u8 = 18; |
29 | #[cfg (stm32g4)] |
30 | const TEMP_CHANNEL: u8 = 16; |
31 | |
32 | #[cfg (stm32h7)] |
33 | const VREF_CHANNEL: u8 = 19; |
34 | #[cfg (stm32h7)] |
35 | const TEMP_CHANNEL: u8 = 18; |
36 | |
37 | // TODO this should be 14 for H7a/b/35 |
38 | #[cfg (not(stm32u5))] |
39 | const VBAT_CHANNEL: u8 = 17; |
40 | |
41 | #[cfg (stm32u5)] |
42 | const VREF_CHANNEL: u8 = 0; |
43 | #[cfg (stm32u5)] |
44 | const TEMP_CHANNEL: u8 = 19; |
45 | #[cfg (stm32u5)] |
46 | const VBAT_CHANNEL: u8 = 18; |
47 | |
48 | // 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 |
49 | /// Internal voltage reference channel. |
50 | pub struct VrefInt; |
51 | impl<T: Instance> AdcChannel<T> for VrefInt {} |
52 | impl<T: Instance> SealedAdcChannel<T> for VrefInt { |
53 | fn channel(&self) -> u8 { |
54 | VREF_CHANNEL |
55 | } |
56 | } |
57 | |
58 | /// Internal temperature channel. |
59 | pub struct Temperature; |
60 | impl<T: Instance> AdcChannel<T> for Temperature {} |
61 | impl<T: Instance> SealedAdcChannel<T> for Temperature { |
62 | fn channel(&self) -> u8 { |
63 | TEMP_CHANNEL |
64 | } |
65 | } |
66 | |
67 | /// Internal battery voltage channel. |
68 | pub struct Vbat; |
69 | impl<T: Instance> AdcChannel<T> for Vbat {} |
70 | impl<T: Instance> SealedAdcChannel<T> for Vbat { |
71 | fn channel(&self) -> u8 { |
72 | VBAT_CHANNEL |
73 | } |
74 | } |
75 | |
76 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, |
77 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. |
78 | #[allow (unused)] |
79 | enum Prescaler { |
80 | NotDivided, |
81 | DividedBy2, |
82 | DividedBy4, |
83 | DividedBy6, |
84 | DividedBy8, |
85 | DividedBy10, |
86 | DividedBy12, |
87 | DividedBy16, |
88 | DividedBy32, |
89 | DividedBy64, |
90 | DividedBy128, |
91 | DividedBy256, |
92 | } |
93 | |
94 | impl Prescaler { |
95 | fn from_ker_ck(frequency: Hertz) -> Self { |
96 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
97 | match raw_prescaler { |
98 | 0 => Self::NotDivided, |
99 | 1 => Self::DividedBy2, |
100 | 2..=3 => Self::DividedBy4, |
101 | 4..=5 => Self::DividedBy6, |
102 | 6..=7 => Self::DividedBy8, |
103 | 8..=9 => Self::DividedBy10, |
104 | 10..=11 => Self::DividedBy12, |
105 | _ => unimplemented!(), |
106 | } |
107 | } |
108 | |
109 | fn divisor(&self) -> u32 { |
110 | match self { |
111 | Prescaler::NotDivided => 1, |
112 | Prescaler::DividedBy2 => 2, |
113 | Prescaler::DividedBy4 => 4, |
114 | Prescaler::DividedBy6 => 6, |
115 | Prescaler::DividedBy8 => 8, |
116 | Prescaler::DividedBy10 => 10, |
117 | Prescaler::DividedBy12 => 12, |
118 | Prescaler::DividedBy16 => 16, |
119 | Prescaler::DividedBy32 => 32, |
120 | Prescaler::DividedBy64 => 64, |
121 | Prescaler::DividedBy128 => 128, |
122 | Prescaler::DividedBy256 => 256, |
123 | } |
124 | } |
125 | |
126 | fn presc(&self) -> Presc { |
127 | match self { |
128 | Prescaler::NotDivided => Presc::DIV1, |
129 | Prescaler::DividedBy2 => Presc::DIV2, |
130 | Prescaler::DividedBy4 => Presc::DIV4, |
131 | Prescaler::DividedBy6 => Presc::DIV6, |
132 | Prescaler::DividedBy8 => Presc::DIV8, |
133 | Prescaler::DividedBy10 => Presc::DIV10, |
134 | Prescaler::DividedBy12 => Presc::DIV12, |
135 | Prescaler::DividedBy16 => Presc::DIV16, |
136 | Prescaler::DividedBy32 => Presc::DIV32, |
137 | Prescaler::DividedBy64 => Presc::DIV64, |
138 | Prescaler::DividedBy128 => Presc::DIV128, |
139 | Prescaler::DividedBy256 => Presc::DIV256, |
140 | } |
141 | } |
142 | } |
143 | |
144 | /// Number of samples used for averaging. |
145 | pub enum Averaging { |
146 | Disabled, |
147 | Samples2, |
148 | Samples4, |
149 | Samples8, |
150 | Samples16, |
151 | Samples32, |
152 | Samples64, |
153 | Samples128, |
154 | Samples256, |
155 | Samples512, |
156 | Samples1024, |
157 | } |
158 | |
159 | impl<'d, T: Instance> Adc<'d, T> { |
160 | /// Create a new ADC driver. |
161 | pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { |
162 | embassy_hal_internal::into_ref!(adc); |
163 | rcc::enable_and_reset::<T>(); |
164 | |
165 | let prescaler = Prescaler::from_ker_ck(T::frequency()); |
166 | |
167 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); |
168 | |
169 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); |
170 | info!("ADC frequency set to {} Hz" , frequency.0); |
171 | |
172 | if frequency > MAX_ADC_CLK_FREQ { |
173 | 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 ); |
174 | } |
175 | |
176 | #[cfg (stm32h7)] |
177 | { |
178 | let boost = if frequency < Hertz::khz(6_250) { |
179 | Boost::LT6_25 |
180 | } else if frequency < Hertz::khz(12_500) { |
181 | Boost::LT12_5 |
182 | } else if frequency < Hertz::mhz(25) { |
183 | Boost::LT25 |
184 | } else { |
185 | Boost::LT50 |
186 | }; |
187 | T::regs().cr().modify(|w| w.set_boost(boost)); |
188 | } |
189 | let mut s = Self { |
190 | adc, |
191 | sample_time: SampleTime::from_bits(0), |
192 | }; |
193 | s.power_up(); |
194 | s.configure_differential_inputs(); |
195 | |
196 | s.calibrate(); |
197 | blocking_delay_us(1); |
198 | |
199 | s.enable(); |
200 | s.configure(); |
201 | |
202 | s |
203 | } |
204 | |
205 | fn power_up(&mut self) { |
206 | T::regs().cr().modify(|reg| { |
207 | reg.set_deeppwd(false); |
208 | reg.set_advregen(true); |
209 | }); |
210 | |
211 | blocking_delay_us(10); |
212 | } |
213 | |
214 | fn configure_differential_inputs(&mut self) { |
215 | T::regs().difsel().modify(|w| { |
216 | for n in 0..20 { |
217 | w.set_difsel(n, Difsel::SINGLE_ENDED); |
218 | } |
219 | }); |
220 | } |
221 | |
222 | fn calibrate(&mut self) { |
223 | T::regs().cr().modify(|w| { |
224 | #[cfg (not(adc_u5))] |
225 | w.set_adcaldif(Adcaldif::SINGLE_ENDED); |
226 | w.set_adcallin(true); |
227 | }); |
228 | |
229 | T::regs().cr().modify(|w| w.set_adcal(true)); |
230 | |
231 | while T::regs().cr().read().adcal() {} |
232 | } |
233 | |
234 | fn enable(&mut self) { |
235 | T::regs().isr().write(|w| w.set_adrdy(true)); |
236 | T::regs().cr().modify(|w| w.set_aden(true)); |
237 | while !T::regs().isr().read().adrdy() {} |
238 | T::regs().isr().write(|w| w.set_adrdy(true)); |
239 | } |
240 | |
241 | fn configure(&mut self) { |
242 | // single conversion mode, software trigger |
243 | T::regs().cfgr().modify(|w| { |
244 | w.set_cont(false); |
245 | w.set_exten(Exten::DISABLED); |
246 | }); |
247 | } |
248 | |
249 | /// Enable reading the voltage reference internal channel. |
250 | pub fn enable_vrefint(&self) -> VrefInt { |
251 | T::common_regs().ccr().modify(|reg| { |
252 | reg.set_vrefen(true); |
253 | }); |
254 | |
255 | VrefInt {} |
256 | } |
257 | |
258 | /// Enable reading the temperature internal channel. |
259 | pub fn enable_temperature(&self) -> Temperature { |
260 | T::common_regs().ccr().modify(|reg| { |
261 | reg.set_vsenseen(true); |
262 | }); |
263 | |
264 | Temperature {} |
265 | } |
266 | |
267 | /// Enable reading the vbat internal channel. |
268 | pub fn enable_vbat(&self) -> Vbat { |
269 | T::common_regs().ccr().modify(|reg| { |
270 | reg.set_vbaten(true); |
271 | }); |
272 | |
273 | Vbat {} |
274 | } |
275 | |
276 | /// Set the ADC sample time. |
277 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { |
278 | self.sample_time = sample_time; |
279 | } |
280 | |
281 | /// Get the ADC sample time. |
282 | pub fn sample_time(&self) -> SampleTime { |
283 | self.sample_time |
284 | } |
285 | |
286 | /// Set the ADC resolution. |
287 | pub fn set_resolution(&mut self, resolution: Resolution) { |
288 | T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); |
289 | } |
290 | |
291 | /// Set hardware averaging. |
292 | pub fn set_averaging(&mut self, averaging: Averaging) { |
293 | let (enable, samples, right_shift) = match averaging { |
294 | Averaging::Disabled => (false, 0, 0), |
295 | Averaging::Samples2 => (true, 1, 1), |
296 | Averaging::Samples4 => (true, 3, 2), |
297 | Averaging::Samples8 => (true, 7, 3), |
298 | Averaging::Samples16 => (true, 15, 4), |
299 | Averaging::Samples32 => (true, 31, 5), |
300 | Averaging::Samples64 => (true, 63, 6), |
301 | Averaging::Samples128 => (true, 127, 7), |
302 | Averaging::Samples256 => (true, 255, 8), |
303 | Averaging::Samples512 => (true, 511, 9), |
304 | Averaging::Samples1024 => (true, 1023, 10), |
305 | }; |
306 | |
307 | T::regs().cfgr2().modify(|reg| { |
308 | reg.set_rovse(enable); |
309 | reg.set_osvr(samples); |
310 | reg.set_ovss(right_shift); |
311 | }) |
312 | } |
313 | |
314 | /// Perform a single conversion. |
315 | fn convert(&mut self) -> u16 { |
316 | T::regs().isr().modify(|reg| { |
317 | reg.set_eos(true); |
318 | reg.set_eoc(true); |
319 | }); |
320 | |
321 | // Start conversion |
322 | T::regs().cr().modify(|reg| { |
323 | reg.set_adstart(true); |
324 | }); |
325 | |
326 | while !T::regs().isr().read().eos() { |
327 | // spin |
328 | } |
329 | |
330 | T::regs().dr().read().0 as u16 |
331 | } |
332 | |
333 | /// Read an ADC channel. |
334 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { |
335 | self.read_channel(channel) |
336 | } |
337 | |
338 | /// Read one or multiple ADC channels using DMA. |
339 | /// |
340 | /// `sequence` iterator and `readings` must have the same length. |
341 | /// |
342 | /// Example |
343 | /// ```rust,ignore |
344 | /// use embassy_stm32::adc::{Adc, AdcChannel} |
345 | /// |
346 | /// let mut adc = Adc::new(p.ADC1); |
347 | /// let mut adc_pin0 = p.PA0.degrade_adc(); |
348 | /// let mut adc_pin2 = p.PA2.degrade_adc(); |
349 | /// let mut measurements = [0u16; 2]; |
350 | /// |
351 | /// adc.read_async( |
352 | /// p.DMA2_CH0, |
353 | /// [ |
354 | /// (&mut *adc_pin0, SampleTime::CYCLES112), |
355 | /// (&mut *adc_pin2, SampleTime::CYCLES112), |
356 | /// ] |
357 | /// .into_iter(), |
358 | /// &mut measurements, |
359 | /// ) |
360 | /// .await; |
361 | /// defmt::info!("measurements: {}" , measurements); |
362 | /// ``` |
363 | pub async fn read( |
364 | &mut self, |
365 | rx_dma: &mut impl RxDma<T>, |
366 | sequence: impl ExactSizeIterator<Item = (&mut AnyAdcChannel<T>, SampleTime)>, |
367 | readings: &mut [u16], |
368 | ) { |
369 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty" ); |
370 | assert!( |
371 | sequence.len() == readings.len(), |
372 | "Sequence length must be equal to readings length" |
373 | ); |
374 | assert!( |
375 | sequence.len() <= 16, |
376 | "Asynchronous read sequence cannot be more than 16 in length" |
377 | ); |
378 | |
379 | // Ensure no conversions are ongoing |
380 | Self::cancel_conversions(); |
381 | |
382 | // Set sequence length |
383 | T::regs().sqr1().modify(|w| { |
384 | w.set_l(sequence.len() as u8 - 1); |
385 | }); |
386 | |
387 | // Configure channels and ranks |
388 | for (i, (channel, sample_time)) in sequence.enumerate() { |
389 | Self::configure_channel(channel, sample_time); |
390 | match i { |
391 | 0..=3 => { |
392 | T::regs().sqr1().modify(|w| { |
393 | w.set_sq(i, channel.channel()); |
394 | }); |
395 | } |
396 | 4..=8 => { |
397 | T::regs().sqr2().modify(|w| { |
398 | w.set_sq(i - 4, channel.channel()); |
399 | }); |
400 | } |
401 | 9..=13 => { |
402 | T::regs().sqr3().modify(|w| { |
403 | w.set_sq(i - 9, channel.channel()); |
404 | }); |
405 | } |
406 | 14..=15 => { |
407 | T::regs().sqr4().modify(|w| { |
408 | w.set_sq(i - 14, channel.channel()); |
409 | }); |
410 | } |
411 | _ => unreachable!(), |
412 | } |
413 | } |
414 | |
415 | // Set continuous mode with oneshot dma. |
416 | // Clear overrun flag before starting transfer. |
417 | |
418 | T::regs().isr().modify(|reg| { |
419 | reg.set_ovr(true); |
420 | }); |
421 | T::regs().cfgr().modify(|reg| { |
422 | reg.set_cont(true); |
423 | reg.set_dmngt(Dmngt::DMA_ONE_SHOT); |
424 | }); |
425 | |
426 | let request = rx_dma.request(); |
427 | let transfer = unsafe { |
428 | Transfer::new_read( |
429 | rx_dma, |
430 | request, |
431 | T::regs().dr().as_ptr() as *mut u16, |
432 | readings, |
433 | Default::default(), |
434 | ) |
435 | }; |
436 | |
437 | // Start conversion |
438 | T::regs().cr().modify(|reg| { |
439 | reg.set_adstart(true); |
440 | }); |
441 | |
442 | // Wait for conversion sequence to finish. |
443 | transfer.await; |
444 | |
445 | // Ensure conversions are finished. |
446 | Self::cancel_conversions(); |
447 | |
448 | // Reset configuration. |
449 | T::regs().cfgr().modify(|reg| { |
450 | reg.set_cont(false); |
451 | reg.set_dmngt(Dmngt::from_bits(0)); |
452 | }); |
453 | } |
454 | |
455 | fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { |
456 | channel.setup(); |
457 | |
458 | let channel = channel.channel(); |
459 | |
460 | Self::set_channel_sample_time(channel, sample_time); |
461 | |
462 | #[cfg (any(stm32h7, stm32u5))] |
463 | { |
464 | T::regs().cfgr2().modify(|w| w.set_lshift(0)); |
465 | T::regs() |
466 | .pcsel() |
467 | .modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); |
468 | } |
469 | } |
470 | |
471 | fn read_channel(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { |
472 | Self::configure_channel(channel, self.sample_time); |
473 | |
474 | T::regs().sqr1().modify(|reg| { |
475 | reg.set_sq(0, channel.channel()); |
476 | reg.set_l(0); |
477 | }); |
478 | |
479 | self.convert() |
480 | } |
481 | |
482 | fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { |
483 | let sample_time = sample_time.into(); |
484 | if ch <= 9 { |
485 | T::regs().smpr(0).modify(|reg| reg.set_smp(ch as _, sample_time)); |
486 | } else { |
487 | T::regs().smpr(1).modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); |
488 | } |
489 | } |
490 | |
491 | fn cancel_conversions() { |
492 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { |
493 | T::regs().cr().modify(|reg| { |
494 | reg.set_adstp(Adstp::STOP); |
495 | }); |
496 | while T::regs().cr().read().adstart() {} |
497 | } |
498 | } |
499 | } |
500 | |