1 | #[allow (unused)] |
2 | use pac::adc::vals::{Adc4Dmacfg, Adc4Exten, Adc4OversamplingRatio}; |
3 | |
4 | use super::{blocking_delay_us, AdcChannel, AnyAdcChannel, RxDma4, SealedAdcChannel}; |
5 | use crate::dma::Transfer; |
6 | pub use crate::pac::adc::regs::Adc4Chselrmod0; |
7 | pub use crate::pac::adc::vals::{Adc4Presc as Presc, Adc4Res as Resolution, Adc4SampleTime as SampleTime}; |
8 | use crate::time::Hertz; |
9 | use crate::{pac, rcc, Peripheral}; |
10 | |
11 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(megahertz:55); |
12 | |
13 | /// Default VREF voltage used for sample conversion to millivolts. |
14 | pub const VREF_DEFAULT_MV: u32 = 3300; |
15 | /// VREF voltage used for factory calibration of VREFINTCAL register. |
16 | pub const VREF_CALIB_MV: u32 = 3300; |
17 | |
18 | const VREF_CHANNEL: u8 = 0; |
19 | const VCORE_CHANNEL: u8 = 12; |
20 | const TEMP_CHANNEL: u8 = 13; |
21 | const VBAT_CHANNEL: u8 = 14; |
22 | const DAC_CHANNEL: u8 = 21; |
23 | |
24 | // 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 |
25 | /// Internal voltage reference channel. |
26 | pub struct VrefInt; |
27 | impl<T: Instance> AdcChannel<T> for VrefInt {} |
28 | impl<T: Instance> SealedAdcChannel<T> for VrefInt { |
29 | fn channel(&self) -> u8 { |
30 | VREF_CHANNEL |
31 | } |
32 | } |
33 | |
34 | /// Internal temperature channel. |
35 | pub struct Temperature; |
36 | impl<T: Instance> AdcChannel<T> for Temperature {} |
37 | impl<T: Instance> SealedAdcChannel<T> for Temperature { |
38 | fn channel(&self) -> u8 { |
39 | TEMP_CHANNEL |
40 | } |
41 | } |
42 | |
43 | /// Internal battery voltage channel. |
44 | pub struct Vbat; |
45 | impl<T: Instance> AdcChannel<T> for Vbat {} |
46 | impl<T: Instance> SealedAdcChannel<T> for Vbat { |
47 | fn channel(&self) -> u8 { |
48 | VBAT_CHANNEL |
49 | } |
50 | } |
51 | |
52 | /// Internal DAC channel. |
53 | pub struct Dac; |
54 | impl<T: Instance> AdcChannel<T> for Dac {} |
55 | impl<T: Instance> SealedAdcChannel<T> for Dac { |
56 | fn channel(&self) -> u8 { |
57 | DAC_CHANNEL |
58 | } |
59 | } |
60 | |
61 | /// Internal Vcore channel. |
62 | pub struct Vcore; |
63 | impl<T: Instance> AdcChannel<T> for Vcore {} |
64 | impl<T: Instance> SealedAdcChannel<T> for Vcore { |
65 | fn channel(&self) -> u8 { |
66 | VCORE_CHANNEL |
67 | } |
68 | } |
69 | |
70 | pub enum DacChannel { |
71 | OUT1, |
72 | OUT2, |
73 | } |
74 | |
75 | /// Number of samples used for averaging. |
76 | pub enum Averaging { |
77 | Disabled, |
78 | Samples2, |
79 | Samples4, |
80 | Samples8, |
81 | Samples16, |
82 | Samples32, |
83 | Samples64, |
84 | Samples128, |
85 | Samples256, |
86 | } |
87 | |
88 | pub const fn resolution_to_max_count(res: Resolution) -> u32 { |
89 | match res { |
90 | Resolution::BITS12 => (1 << 12) - 1, |
91 | Resolution::BITS10 => (1 << 10) - 1, |
92 | Resolution::BITS8 => (1 << 8) - 1, |
93 | Resolution::BITS6 => (1 << 6) - 1, |
94 | #[allow (unreachable_patterns)] |
95 | _ => core::unreachable!(), |
96 | } |
97 | } |
98 | |
99 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, |
100 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. |
101 | #[allow (unused)] |
102 | enum Prescaler { |
103 | NotDivided, |
104 | DividedBy2, |
105 | DividedBy4, |
106 | DividedBy6, |
107 | DividedBy8, |
108 | DividedBy10, |
109 | DividedBy12, |
110 | DividedBy16, |
111 | DividedBy32, |
112 | DividedBy64, |
113 | DividedBy128, |
114 | DividedBy256, |
115 | } |
116 | |
117 | impl Prescaler { |
118 | fn from_ker_ck(frequency: Hertz) -> Self { |
119 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
120 | match raw_prescaler { |
121 | 0 => Self::NotDivided, |
122 | 1 => Self::DividedBy2, |
123 | 2..=3 => Self::DividedBy4, |
124 | 4..=5 => Self::DividedBy6, |
125 | 6..=7 => Self::DividedBy8, |
126 | 8..=9 => Self::DividedBy10, |
127 | 10..=11 => Self::DividedBy12, |
128 | _ => unimplemented!(), |
129 | } |
130 | } |
131 | |
132 | fn divisor(&self) -> u32 { |
133 | match self { |
134 | Prescaler::NotDivided => 1, |
135 | Prescaler::DividedBy2 => 2, |
136 | Prescaler::DividedBy4 => 4, |
137 | Prescaler::DividedBy6 => 6, |
138 | Prescaler::DividedBy8 => 8, |
139 | Prescaler::DividedBy10 => 10, |
140 | Prescaler::DividedBy12 => 12, |
141 | Prescaler::DividedBy16 => 16, |
142 | Prescaler::DividedBy32 => 32, |
143 | Prescaler::DividedBy64 => 64, |
144 | Prescaler::DividedBy128 => 128, |
145 | Prescaler::DividedBy256 => 256, |
146 | } |
147 | } |
148 | |
149 | fn presc(&self) -> Presc { |
150 | match self { |
151 | Prescaler::NotDivided => Presc::DIV1, |
152 | Prescaler::DividedBy2 => Presc::DIV2, |
153 | Prescaler::DividedBy4 => Presc::DIV4, |
154 | Prescaler::DividedBy6 => Presc::DIV6, |
155 | Prescaler::DividedBy8 => Presc::DIV8, |
156 | Prescaler::DividedBy10 => Presc::DIV10, |
157 | Prescaler::DividedBy12 => Presc::DIV12, |
158 | Prescaler::DividedBy16 => Presc::DIV16, |
159 | Prescaler::DividedBy32 => Presc::DIV32, |
160 | Prescaler::DividedBy64 => Presc::DIV64, |
161 | Prescaler::DividedBy128 => Presc::DIV128, |
162 | Prescaler::DividedBy256 => Presc::DIV256, |
163 | } |
164 | } |
165 | } |
166 | |
167 | pub trait SealedInstance { |
168 | #[allow (unused)] |
169 | fn regs() -> crate::pac::adc::Adc4; |
170 | } |
171 | |
172 | pub trait Instance: SealedInstance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral { |
173 | type Interrupt: crate::interrupt::typelevel::Interrupt; |
174 | } |
175 | |
176 | pub struct Adc4<'d, T: Instance> { |
177 | #[allow (unused)] |
178 | adc: crate::PeripheralRef<'d, T>, |
179 | } |
180 | |
181 | #[derive (Debug)] |
182 | pub enum Adc4Error { |
183 | InvalidSequence, |
184 | DMAError, |
185 | } |
186 | |
187 | impl<'d, T: Instance> Adc4<'d, T> { |
188 | /// Create a new ADC driver. |
189 | pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { |
190 | embassy_hal_internal::into_ref!(adc); |
191 | rcc::enable_and_reset::<T>(); |
192 | let prescaler = Prescaler::from_ker_ck(T::frequency()); |
193 | |
194 | T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); |
195 | |
196 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); |
197 | info!("ADC4 frequency set to {} Hz" , frequency.0); |
198 | |
199 | if frequency > MAX_ADC_CLK_FREQ { |
200 | 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 ); |
201 | } |
202 | |
203 | let mut s = Self { adc }; |
204 | |
205 | s.power_up(); |
206 | |
207 | s.calibrate(); |
208 | blocking_delay_us(1); |
209 | |
210 | s.enable(); |
211 | s.configure(); |
212 | |
213 | s |
214 | } |
215 | |
216 | fn power_up(&mut self) { |
217 | T::regs().isr().modify(|w| { |
218 | w.set_ldordy(true); |
219 | }); |
220 | T::regs().cr().modify(|w| { |
221 | w.set_advregen(true); |
222 | }); |
223 | while !T::regs().isr().read().ldordy() {} |
224 | |
225 | T::regs().isr().modify(|w| { |
226 | w.set_ldordy(true); |
227 | }); |
228 | } |
229 | |
230 | fn calibrate(&mut self) { |
231 | T::regs().cr().modify(|w| w.set_adcal(true)); |
232 | while T::regs().cr().read().adcal() {} |
233 | T::regs().isr().modify(|w| w.set_eocal(true)); |
234 | } |
235 | |
236 | fn enable(&mut self) { |
237 | T::regs().isr().write(|w| w.set_adrdy(true)); |
238 | T::regs().cr().modify(|w| w.set_aden(true)); |
239 | while !T::regs().isr().read().adrdy() {} |
240 | T::regs().isr().write(|w| w.set_adrdy(true)); |
241 | } |
242 | |
243 | fn configure(&mut self) { |
244 | // single conversion mode, software trigger |
245 | T::regs().cfgr1().modify(|w| { |
246 | w.set_cont(false); |
247 | w.set_discen(false); |
248 | w.set_exten(Adc4Exten::DISABLED); |
249 | w.set_chselrmod(false); |
250 | }); |
251 | |
252 | // only use one channel at the moment |
253 | T::regs().smpr().modify(|w| { |
254 | for i in 0..24 { |
255 | w.set_smpsel(i, false); |
256 | } |
257 | }); |
258 | } |
259 | |
260 | /// Enable reading the voltage reference internal channel. |
261 | pub fn enable_vrefint(&self) -> VrefInt { |
262 | T::regs().ccr().modify(|w| { |
263 | w.set_vrefen(true); |
264 | }); |
265 | |
266 | VrefInt {} |
267 | } |
268 | |
269 | /// Enable reading the temperature internal channel. |
270 | pub fn enable_temperature(&self) -> Temperature { |
271 | T::regs().ccr().modify(|w| { |
272 | w.set_vsensesel(true); |
273 | }); |
274 | |
275 | Temperature {} |
276 | } |
277 | |
278 | /// Enable reading the vbat internal channel. |
279 | pub fn enable_vbat(&self) -> Vbat { |
280 | T::regs().ccr().modify(|w| { |
281 | w.set_vbaten(true); |
282 | }); |
283 | |
284 | Vbat {} |
285 | } |
286 | |
287 | /// Enable reading the vbat internal channel. |
288 | pub fn enable_vcore(&self) -> Vcore { |
289 | Vcore {} |
290 | } |
291 | |
292 | /// Enable reading the vbat internal channel. |
293 | pub fn enable_dac_channel(&self, dac: DacChannel) -> Dac { |
294 | let mux; |
295 | match dac { |
296 | DacChannel::OUT1 => mux = false, |
297 | DacChannel::OUT2 => mux = true, |
298 | } |
299 | T::regs().or().modify(|w| w.set_chn21sel(mux)); |
300 | Dac {} |
301 | } |
302 | |
303 | /// Set the ADC sample time. |
304 | pub fn set_sample_time(&mut self, sample_time: SampleTime) { |
305 | T::regs().smpr().modify(|w| { |
306 | w.set_smp(0, sample_time); |
307 | }); |
308 | } |
309 | |
310 | /// Get the ADC sample time. |
311 | pub fn sample_time(&self) -> SampleTime { |
312 | T::regs().smpr().read().smp(0) |
313 | } |
314 | |
315 | /// Set the ADC resolution. |
316 | pub fn set_resolution(&mut self, resolution: Resolution) { |
317 | T::regs().cfgr1().modify(|w| w.set_res(resolution.into())); |
318 | } |
319 | |
320 | /// Set hardware averaging. |
321 | pub fn set_averaging(&mut self, averaging: Averaging) { |
322 | let (enable, samples, right_shift) = match averaging { |
323 | Averaging::Disabled => (false, Adc4OversamplingRatio::OVERSAMPLE2X, 0), |
324 | Averaging::Samples2 => (true, Adc4OversamplingRatio::OVERSAMPLE2X, 1), |
325 | Averaging::Samples4 => (true, Adc4OversamplingRatio::OVERSAMPLE4X, 2), |
326 | Averaging::Samples8 => (true, Adc4OversamplingRatio::OVERSAMPLE8X, 3), |
327 | Averaging::Samples16 => (true, Adc4OversamplingRatio::OVERSAMPLE16X, 4), |
328 | Averaging::Samples32 => (true, Adc4OversamplingRatio::OVERSAMPLE32X, 5), |
329 | Averaging::Samples64 => (true, Adc4OversamplingRatio::OVERSAMPLE64X, 6), |
330 | Averaging::Samples128 => (true, Adc4OversamplingRatio::OVERSAMPLE128X, 7), |
331 | Averaging::Samples256 => (true, Adc4OversamplingRatio::OVERSAMPLE256X, 8), |
332 | }; |
333 | |
334 | T::regs().cfgr2().modify(|w| { |
335 | w.set_ovsr(samples); |
336 | w.set_ovss(right_shift); |
337 | w.set_ovse(enable) |
338 | }) |
339 | } |
340 | |
341 | /// Read an ADC channel. |
342 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>) -> u16 { |
343 | channel.setup(); |
344 | |
345 | // Select channel |
346 | T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); |
347 | T::regs().chselrmod0().modify(|w| { |
348 | w.set_chsel(channel.channel() as usize, true); |
349 | }); |
350 | |
351 | // Reset interrupts |
352 | T::regs().isr().modify(|reg| { |
353 | reg.set_eos(true); |
354 | reg.set_eoc(true); |
355 | }); |
356 | |
357 | // Start conversion |
358 | T::regs().cr().modify(|reg| { |
359 | reg.set_adstart(true); |
360 | }); |
361 | |
362 | while !T::regs().isr().read().eos() { |
363 | // spin |
364 | } |
365 | |
366 | T::regs().dr().read().0 as u16 |
367 | } |
368 | |
369 | /// Read one or multiple ADC channels using DMA. |
370 | /// |
371 | /// `sequence` iterator and `readings` must have the same length. |
372 | /// The channels in `sequence` must be in ascending order. |
373 | /// |
374 | /// Example |
375 | /// ```rust,ignore |
376 | /// use embassy_stm32::adc::adc4; |
377 | /// use embassy_stm32::adc::AdcChannel; |
378 | /// |
379 | /// let mut adc4 = adc4::Adc4::new(p.ADC4); |
380 | /// let mut adc4_pin1 = p.PC1; |
381 | /// let mut adc4_pin2 = p.PC0; |
382 | /// let mut degraded41 = adc4_pin1.degrade_adc(); |
383 | /// let mut degraded42 = adc4_pin2.degrade_adc(); |
384 | /// let mut measurements = [0u16; 2]; |
385 | /// // not that the channels must be in ascending order |
386 | /// adc4.read( |
387 | /// &mut p.GPDMA1_CH1, |
388 | /// [ |
389 | /// &mut degraded42, |
390 | /// &mut degraded41, |
391 | /// ] |
392 | /// .into_iter(), |
393 | /// &mut measurements, |
394 | /// ).await.unwrap(); |
395 | /// ``` |
396 | pub async fn read( |
397 | &mut self, |
398 | rx_dma: &mut impl RxDma4<T>, |
399 | sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>, |
400 | readings: &mut [u16], |
401 | ) -> Result<(), Adc4Error> { |
402 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty" ); |
403 | assert!( |
404 | sequence.len() == readings.len(), |
405 | "Sequence length must be equal to readings length" |
406 | ); |
407 | |
408 | // Ensure no conversions are ongoing |
409 | Self::cancel_conversions(); |
410 | |
411 | T::regs().isr().modify(|reg| { |
412 | reg.set_ovr(true); |
413 | reg.set_eos(true); |
414 | reg.set_eoc(true); |
415 | }); |
416 | |
417 | T::regs().cfgr1().modify(|reg| { |
418 | reg.set_dmaen(true); |
419 | reg.set_dmacfg(Adc4Dmacfg::ONE_SHOT); |
420 | reg.set_chselrmod(false); |
421 | }); |
422 | |
423 | // Verify and activate sequence |
424 | let mut prev_channel: i16 = -1; |
425 | T::regs().chselrmod0().write_value(Adc4Chselrmod0(0_u32)); |
426 | for channel in sequence { |
427 | let channel_num = channel.channel; |
428 | if channel_num as i16 <= prev_channel { |
429 | return Err(Adc4Error::InvalidSequence); |
430 | }; |
431 | prev_channel = channel_num as i16; |
432 | |
433 | T::regs().chselrmod0().modify(|w| { |
434 | w.set_chsel(channel.channel as usize, true); |
435 | }); |
436 | } |
437 | |
438 | let request = rx_dma.request(); |
439 | let transfer = unsafe { |
440 | Transfer::new_read( |
441 | rx_dma, |
442 | request, |
443 | T::regs().dr().as_ptr() as *mut u16, |
444 | readings, |
445 | Default::default(), |
446 | ) |
447 | }; |
448 | |
449 | // Start conversion |
450 | T::regs().cr().modify(|reg| { |
451 | reg.set_adstart(true); |
452 | }); |
453 | |
454 | transfer.await; |
455 | |
456 | // Ensure conversions are finished. |
457 | Self::cancel_conversions(); |
458 | |
459 | // Reset configuration. |
460 | T::regs().cfgr1().modify(|reg| { |
461 | reg.set_dmaen(false); |
462 | }); |
463 | |
464 | if T::regs().isr().read().ovr() { |
465 | Err(Adc4Error::DMAError) |
466 | } else { |
467 | Ok(()) |
468 | } |
469 | } |
470 | |
471 | fn cancel_conversions() { |
472 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { |
473 | T::regs().cr().modify(|reg| { |
474 | reg.set_adstp(true); |
475 | }); |
476 | while T::regs().cr().read().adstart() {} |
477 | } |
478 | } |
479 | } |
480 | |