1use core::ptr;
3
4use crate::gpio::*;
5use crate::rcc::{Enable, Rcc};
6use crate::stm32::ADC;
7use hal::adc::{Channel, OneShot};
8
9#[derive(Eq, PartialEq)]
11pub enum Align {
12 Right,
17 Left,
23}
24
25#[derive(Copy, Clone, PartialEq, Eq)]
27pub enum Precision {
28 B_12 = 0b00,
30 B_10 = 0b01,
32 B_8 = 0b10,
34 B_6 = 0b11,
36}
37
38#[derive(Copy, Clone, PartialEq, Eq)]
40pub enum SampleTime {
41 T_2 = 0b000,
42 T_4 = 0b001,
43 T_8 = 0b010,
44 T_12 = 0b011,
45 T_20 = 0b100,
46 T_40 = 0b101,
47 T_80 = 0b110,
48 T_160 = 0b111,
49}
50
51#[derive(Copy, Clone, PartialEq, Eq)]
53pub enum OversamplingRatio {
54 X_2 = 0b000,
55 X_4 = 0b001,
56 X_8 = 0b010,
57 X_16 = 0b011,
58 X_32 = 0b100,
59 X_64 = 0b101,
60 X_128 = 0b110,
61 X_256 = 0b111,
62}
63
64#[derive(Clone, Copy, PartialEq, Eq, Debug)]
65pub enum ClockSource {
66 Pclk(PclkDiv),
67 Async(AsyncClockDiv),
68}
69
70#[derive(Clone, Copy, PartialEq, Eq, Debug)]
71pub enum PclkDiv {
72 PclkD1 = 3,
73 PclkD2 = 1,
74 PclkD4 = 2,
75}
76
77#[derive(Clone, Copy, PartialEq, Eq, Debug)]
78pub enum AsyncClockDiv {
79 AsyncD1 = 0,
80 AsyncD2 = 1,
81 AsyncD4 = 2,
82 AsyncD8 = 3,
83 AsyncD16 = 4,
84 AsyncD32 = 5,
85 AsyncD64 = 6,
86 AsyncD128 = 7,
87 AsyncD256 = 8,
88}
89
90#[derive(Copy, Clone, PartialEq, Eq)]
92pub enum InjTrigSource {
93 TRG_0 = 0b000, TRG_1 = 0b001, TRG_2 = 0b010, TRG_3 = 0b011, TRG_4 = 0b100, TRG_5 = 0b101, TRG_6 = 0b110, TRG_7 = 0b111, }
102
103pub struct Adc {
105 rb: ADC,
106 sample_time: SampleTime,
107 align: Align,
108 precision: Precision,
109 vref_cache: Option<u16>,
110}
111
112#[derive(Clone, Copy, PartialEq, Eq, Debug)]
114pub struct CalibrationFactor(pub u8);
115
116impl Adc {
117 pub fn new(adc: ADC, rcc: &mut Rcc) -> Self {
118 ADC::enable(rcc);
120
121 adc.cr.modify(|_, w| w.advregen().set_bit());
122
123 Self {
124 rb: adc,
125 sample_time: SampleTime::T_2,
126 align: Align::Right,
127 precision: Precision::B_12,
128 vref_cache: None,
129 }
130 }
131
132 pub fn set_clock_source(&mut self, clock_source: ClockSource) {
134 match clock_source {
135 ClockSource::Pclk(div) => self
136 .rb
137 .cfgr2
138 .modify(|_, w| unsafe { w.ckmode().bits(div as u8) }),
139 ClockSource::Async(div) => {
140 self.rb.cfgr2.modify(|_, w| unsafe { w.ckmode().bits(0) });
141 self.rb
142 .ccr
143 .modify(|_, w| unsafe { w.presc().bits(div as u8) });
144 }
145 }
146 }
147
148 pub fn calibrate(&mut self) {
155 self.rb.cr.modify(|_, w| w.adcal().set_bit());
156 while self.rb.cr.read().adcal().bit_is_set() {}
157 }
158
159 pub fn get_calibration(&self) -> CalibrationFactor {
169 CalibrationFactor(self.rb.calfact.read().calfact().bits())
170 }
171
172 pub fn set_calibration(&mut self, calfact: CalibrationFactor) {
178 self.rb
179 .calfact
180 .write(|w| unsafe { w.calfact().bits(calfact.0) });
181 }
182
183 pub fn set_sample_time(&mut self, t_samp: SampleTime) {
185 self.sample_time = t_samp;
186 }
187
188 pub fn set_align(&mut self, align: Align) {
190 self.align = align;
191 }
192
193 pub fn set_precision(&mut self, precision: Precision) {
195 self.precision = precision;
196 }
197
198 pub fn set_oversampling_shift(&mut self, nrbits: u8) {
200 self.rb
201 .cfgr2
202 .modify(|_, w| unsafe { w.ovss().bits(nrbits) });
203 }
204
205 pub fn set_oversampling_ratio(&mut self, ratio: OversamplingRatio) {
207 self.rb
208 .cfgr2
209 .modify(|_, w| unsafe { w.ovsr().bits(ratio as u8) });
210 }
211
212 pub fn oversampling_enable(&mut self, enable: bool) {
213 self.rb.cfgr2.modify(|_, w| w.ovse().bit(enable));
214 }
215
216 pub fn start_injected(&mut self) {
217 self.rb.cr.modify(|_, w| w.adstart().set_bit());
218 self.rb.ier.modify(|_, w| w.eocie().set_bit()); }
222
223 pub fn stop_injected(&mut self) {
224 self.rb.ier.modify(|_, w| w.eocie().clear_bit()); }
230
231 pub fn read_vref(&mut self) -> nb::Result<u16, ()> {
237 let mut vref = VRef::new();
238 let vref_val: u32 = if vref.enabled(self) {
239 self.read(&mut vref)?
240 } else {
241 vref.enable(self);
242 let vref_val = self.read(&mut vref)?;
243 vref.disable(self);
244 vref_val
245 };
246
247 let vref_cal: u32 = unsafe {
248 ptr::read_volatile(0x1FFF_75AA as *const u16) as u32
250 };
251
252 let vref = (vref_cal * 3_000_u32 / vref_val) as u16;
255 self.vref_cache = Some(vref);
256 Ok(vref)
257 }
258
259 pub fn get_vref_cached(&mut self) -> nb::Result<u16, ()> {
263 if let Some(vref) = self.vref_cache {
264 Ok(vref)
265 } else {
266 self.read_vref()
267 }
268 }
269
270 pub fn read_voltage<PIN: Channel<Adc, ID = u8>>(
271 &mut self,
272 pin: &mut PIN,
273 ) -> nb::Result<u16, ()> {
274 let vref = self.get_vref_cached()?;
275
276 self.read(pin).map(|raw: u32| {
277 let adc_mv = (vref as u32 * raw) >> 12;
278 adc_mv as u16
279 })
280 }
281
282 pub fn read_temperature(&mut self) -> nb::Result<i16, ()> {
283 let mut vtemp = VTemp::new();
284 let vtemp_voltage: u16 = if vtemp.enabled(self) {
285 self.read_voltage(&mut vtemp)?
286 } else {
287 vtemp.enable(self);
288 let vtemp_voltage = self.read_voltage(&mut vtemp)?;
289 vtemp.disable(self);
290 vtemp_voltage
291 };
292
293 let ts_cal1: u32 = unsafe {
294 ptr::read_volatile(0x1FFF_75A8 as *const u16) as u32
297 };
298
299 let v30 = (3000_u32 * ts_cal1) >> 12; let t = 30 + (vtemp_voltage as i32 - v30 as i32) * 10 / 25;
302
303 Ok(t as i16)
304 }
305
306 pub fn release(self) -> ADC {
307 self.rb
308 }
309
310 fn power_up(&mut self) {
311 self.rb.isr.modify(|_, w| w.adrdy().set_bit());
312 self.rb.cr.modify(|_, w| w.aden().set_bit());
313 while self.rb.isr.read().adrdy().bit_is_clear() {}
314 }
315
316 fn power_down(&mut self) {
317 self.rb.cr.modify(|_, w| w.addis().set_bit());
318 self.rb.isr.modify(|_, w| w.adrdy().set_bit());
319 while self.rb.cr.read().aden().bit_is_set() {}
320 }
321}
322
323pub trait AdcExt {
324 fn constrain(self, rcc: &mut Rcc) -> Adc;
325}
326
327impl AdcExt for ADC {
328 fn constrain(self, rcc: &mut Rcc) -> Adc {
329 Adc::new(self, rcc)
330 }
331}
332
333pub trait InjectMode<ADC, Pin: Channel<ADC>> {
334 type Error;
336 fn prepare_injected(&mut self, _pin: &mut Pin, triger_source: InjTrigSource);
337}
338
339impl<PIN> InjectMode<Adc, PIN> for Adc
340where
341 PIN: Channel<Adc, ID = u8>,
343{
344 type Error = ();
345
346 fn prepare_injected(&mut self, _pin: &mut PIN, triger_source: InjTrigSource) {
347 self.rb
348 .cfgr1
349 .modify(|_, w| unsafe { w.exten().bits(1).extsel().bits(triger_source as u8) });
350
351 self.rb.cfgr1.modify(|_, w| unsafe {
352 w.res() .bits(self.precision as u8)
354 .align() .bit(self.align == Align::Left)
356 });
357
358 self.power_up();
359
360 self.rb
361 .smpr .modify(|_, w| unsafe { w.smp1().bits(self.sample_time as u8) });
363
364 self.rb
365 .chselr() .modify(|_, w| unsafe { w.chsel().bits(1 << PIN::channel()) });
367 }
368}
369
370pub trait DmaMode<ADC> {
371 type Error;
373 fn dma_enable(&mut self, enable: bool);
374 fn dma_circualr_mode(&mut self, enable: bool);
375}
376
377impl DmaMode<Adc> for Adc {
378 type Error = ();
379
380 fn dma_enable(&mut self, enable: bool) {
381 if enable {
382 self.rb.cfgr1.modify(|_, w| w.dmaen().set_bit()); } else {
384 self.rb.cfgr1.modify(|_, w| w.dmaen().clear_bit()); }
386 }
387
388 fn dma_circualr_mode(&mut self, enable: bool) {
389 if enable {
390 self.rb.cfgr1.modify(|_, w| w.dmacfg().set_bit()); } else {
392 self.rb.cfgr1.modify(|_, w| w.dmacfg().clear_bit()); }
394 }
395}
396
397impl<WORD, PIN> OneShot<Adc, WORD, PIN> for Adc
398where
399 WORD: From<u16>,
400 PIN: Channel<Adc, ID = u8>,
401{
402 type Error = ();
403
404 fn read(&mut self, _pin: &mut PIN) -> nb::Result<WORD, Self::Error> {
405 self.power_up();
406 self.rb.cfgr1.modify(|_, w| unsafe {
407 w.res()
408 .bits(self.precision as u8)
409 .align()
410 .bit(self.align == Align::Left)
411 });
412
413 self.rb
414 .smpr
415 .modify(|_, w| unsafe { w.smp1().bits(self.sample_time as u8) });
416
417 self.rb
418 .chselr()
419 .modify(|_, w| unsafe { w.chsel().bits(1 << PIN::channel()) });
420
421 self.rb.isr.modify(|_, w| w.eos().set_bit());
422 self.rb.cr.modify(|_, w| w.adstart().set_bit());
423 while self.rb.isr.read().eos().bit_is_clear() {}
424
425 let res = self.rb.dr.read().bits() as u16;
426 let val = if self.align == Align::Left && self.precision == Precision::B_6 {
427 res << 8
428 } else {
429 res
430 };
431
432 self.power_down();
433 Ok(val.into())
434 }
435}
436
437macro_rules! int_adc {
438 ($($Chan:ident: ($chan:expr, $en:ident)),+ $(,)*) => {
439 $(
440 pub struct $Chan;
441
442 impl $Chan {
443 pub fn new() -> Self {
444 Self {}
445 }
446
447 pub fn enable(&mut self, adc: &mut Adc) {
448 adc.rb.ccr.modify(|_, w| w.$en().set_bit());
449 }
450
451 pub fn disable(&mut self, adc: &mut Adc) {
452 adc.rb.ccr.modify(|_, w| w.$en().clear_bit());
453 }
454
455 pub fn enabled(&self, adc: &Adc) -> bool {
456 adc.rb.ccr.read().$en().bit_is_set()
457 }
458 }
459
460 impl Default for $Chan {
461 fn default() -> $Chan {
462 $Chan::new()
463 }
464 }
465
466 impl Channel<Adc> for $Chan {
467 type ID = u8;
468
469 fn channel() -> u8 {
470 $chan
471 }
472 }
473 )+
474 };
475}
476
477int_adc! {
478 VTemp: (12, tsen),
479 VRef: (13, vrefen),
480 VBat: (14, vbaten),
481}
482
483macro_rules! adc_pin {
484 ($($Chan:ty: ($pin:ty, $chan:expr)),+ $(,)*) => {
485 $(
486 impl Channel<Adc> for $pin {
487 type ID = u8;
488
489 fn channel() -> u8 { $chan }
490 }
491 )+
492 };
493}
494
495adc_pin! {
496 Channel0: (gpioa::PA0<Analog>, 0u8),
497 Channel1: (gpioa::PA1<Analog>, 1u8),
498 Channel2: (gpioa::PA2<Analog>, 2u8),
499 Channel3: (gpioa::PA3<Analog>, 3u8),
500 Channel4: (gpioa::PA4<Analog>, 4u8),
501 Channel5: (gpioa::PA5<Analog>, 5u8),
502 Channel6: (gpioa::PA6<Analog>, 6u8),
503 Channel7: (gpioa::PA7<Analog>, 7u8),
504 Channel8: (gpiob::PB0<Analog>, 8u8),
505 Channel9: (gpiob::PB1<Analog>, 9u8),
506 Channel10: (gpiob::PB2<Analog>, 10u8),
507 Channel11: (gpiob::PB10<Analog>, 11u8),
508 Channel15: (gpiob::PB11<Analog>, 15u8),
509 Channel16: (gpiob::PB12<Analog>, 16u8),
510}
511
512#[cfg(any(feature = "stm32g030", feature = "stm32g031", feature = "stm32g041",))]
513adc_pin! {
514 Channel11: (gpiob::PB7<Analog>, 11u8),
515 Channel15: (gpioa::PA11<Analog>, 15u8),
516 Channel16: (gpioa::PA12<Analog>, 16u8),
517 Channel17: (gpioa::PA13<Analog>, 17u8),
518 Channel18: (gpioa::PA14<Analog>, 18u8),
519}
520
521#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081",))]
522adc_pin! {
523 Channel17: (gpioc::PC4<Analog>, 17u8),
524 Channel18: (gpioc::PC5<Analog>, 18u8),
525}