stm32g0xx_hal/analog/
adc.rs

1//! # Analog to Digital converter
2use core::ptr;
3
4use crate::gpio::*;
5use crate::rcc::{Enable, Rcc};
6use crate::stm32::ADC;
7use hal::adc::{Channel, OneShot};
8
9/// ADC Result Alignment
10#[derive(Eq, PartialEq)]
11pub enum Align {
12    /// Right aligned results (least significant bits)
13    ///
14    /// Results in all precisions returning values from 0-(2^bits-1) in
15    /// steps of 1.
16    Right,
17    /// Left aligned results (most significant bits)
18    ///
19    /// Results in all precisions returning a value in the range 0-65535.
20    /// Depending on the precision the result will step by larger or smaller
21    /// amounts.
22    Left,
23}
24
25/// ADC Sampling Precision
26#[derive(Copy, Clone, PartialEq, Eq)]
27pub enum Precision {
28    /// 12 bit precision
29    B_12 = 0b00,
30    /// 10 bit precision
31    B_10 = 0b01,
32    /// 8 bit precision
33    B_8 = 0b10,
34    /// 6 bit precision
35    B_6 = 0b11,
36}
37
38/// ADC Sampling time
39#[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// ADC Oversampling ratio
52#[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/// ADC injected trigger source selection
91#[derive(Copy, Clone, PartialEq, Eq)]
92pub enum InjTrigSource {
93    TRG_0 = 0b000, // TIM1_TRGO2
94    TRG_1 = 0b001, // TIM1_CC4
95    TRG_2 = 0b010, // TIM2_TRGO
96    TRG_3 = 0b011, // TIM3_TRGO
97    TRG_4 = 0b100, // TIM15_TRGO
98    TRG_5 = 0b101, // TIM6_TRGO
99    TRG_6 = 0b110, // TIM4_TRGO
100    TRG_7 = 0b111, // EXTI11
101}
102
103/// Analog to Digital converter interface
104pub struct Adc {
105    rb: ADC,
106    sample_time: SampleTime,
107    align: Align,
108    precision: Precision,
109    vref_cache: Option<u16>,
110}
111
112/// Contains the calibration factors for the ADC which can be reused with [`Adc::set_calibration()`]
113#[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        // Enable ADC clocks
119        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    /// Sets ADC source
133    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    /// Runs the calibration routine on the ADC
149    ///
150    /// Wait for tADCVREG_SETUP (20us on STM32G071x8) after calling [`Self::new()`] before calibrating, to wait for the
151    /// ADC voltage regulator to stabilize.
152    ///
153    /// Do not call if an ADC reading is ongoing.
154    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    /// Returns the calibration factors used by the ADC
160    ///
161    /// The ADC does not have a factory-stored calibration, [`Self::calibrate()`] must be run before calling this
162    /// for the returned value to be useful.
163    ///
164    /// The ADC loses its calibration factors when Standby or Vbat mode is entered. Saving and restoring the calibration
165    /// factors can be used to recalibrate the ADC after waking up from sleep more quickly than re-running calibraiton.
166    /// Note that VDDA changes and to a lesser extent temperature changes affect the ADC operating conditions and
167    /// calibration should be run again for the best accuracy.
168    pub fn get_calibration(&self) -> CalibrationFactor {
169        CalibrationFactor(self.rb.calfact.read().calfact().bits())
170    }
171
172    /// Writes the calibration factors used by the ADC
173    ///
174    /// See [`Self::get_calibration()`].
175    ///
176    /// Do not call if an ADC reading is ongoing.
177    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    /// Set the Adc sampling time
184    pub fn set_sample_time(&mut self, t_samp: SampleTime) {
185        self.sample_time = t_samp;
186    }
187
188    /// Set the Adc result alignment
189    pub fn set_align(&mut self, align: Align) {
190        self.align = align;
191    }
192
193    /// Set the Adc precision
194    pub fn set_precision(&mut self, precision: Precision) {
195        self.precision = precision;
196    }
197
198    /// The nuber of bits, the oversampling result is shifted in bits at the end of oversampling
199    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    /// Oversampling of adc according to datasheet of stm32g0, when oversampling is enabled
206    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        // ADSTART bit is cleared to 0 bevor using this function
219        // enable self.rb.isr.eos() flag is set after each converstion
220        self.rb.ier.modify(|_, w| w.eocie().set_bit()); // end of sequence interupt enable
221    }
222
223    pub fn stop_injected(&mut self) {
224        // ?????? or is it reset after each conversion?
225        // ADSTART bit is cleared to 0 bevor using this function
226        // disable EOS interrupt
227        // maybe self.rb.cr.adstp().set_bit() must be performed before interrupt is disabled + wait abortion
228        self.rb.ier.modify(|_, w| w.eocie().clear_bit()); // end of sequence interupt disable
229    }
230
231    /// Read actual VREF voltage using the internal reference
232    ///
233    /// If oversampling is enabled, the return value is scaled down accordingly.
234    /// The product of the return value and any ADC reading always gives correct voltage in 4096ths of mV
235    /// regardless of oversampling and shift settings provided that these settings remain the same.
236    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            // DS12766 3.13.2
249            ptr::read_volatile(0x1FFF_75AA as *const u16) as u32
250        };
251
252        // RM0454 14.9 Calculating the actual VDDA voltage using the internal reference voltage
253        // V_DDA = 3 V x VREFINT_CAL / VREFINT_DATA
254        let vref = (vref_cal * 3_000_u32 / vref_val) as u16;
255        self.vref_cache = Some(vref);
256        Ok(vref)
257    }
258
259    /// Get VREF value using cached value if possible
260    ///
261    /// See `read_vref` for more details.
262    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            // DS12991 3.14.1
295            // at 3000 mV Vref+ and 30 degC
296            ptr::read_volatile(0x1FFF_75A8 as *const u16) as u32
297        };
298
299        let v30 = (3000_u32 * ts_cal1) >> 12; // mV
300                                              // 2.5 mV/degC
301        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    /// Error type returned by ADC methods
335    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    // WORD: From<u16>,
342    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() // set ADC resolution bits (ADEN must be =0)
353                .bits(self.precision as u8)
354                .align() // set alignment bit is  (ADSTART must be 0)
355                .bit(self.align == Align::Left)
356        });
357
358        self.power_up();
359
360        self.rb
361            .smpr // set sampling time set 1 (ADSTART must be 0)
362            .modify(|_, w| unsafe { w.smp1().bits(self.sample_time as u8) });
363
364        self.rb
365            .chselr() // set activ channel acording chapter 15.12.9 (ADC_CFGR1; CHSELRMOD=0)
366            .modify(|_, w| unsafe { w.chsel().bits(1 << PIN::channel()) });
367    }
368}
369
370pub trait DmaMode<ADC> {
371    /// Error type returned by ADC methods
372    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()); //  enable dma beeing called
383        } else {
384            self.rb.cfgr1.modify(|_, w| w.dmaen().clear_bit()); //  disable dma beeing called
385        }
386    }
387
388    fn dma_circualr_mode(&mut self, enable: bool) {
389        if enable {
390            self.rb.cfgr1.modify(|_, w| w.dmacfg().set_bit()); // activate circular mode
391        } else {
392            self.rb.cfgr1.modify(|_, w| w.dmacfg().clear_bit()); // disable circular mode
393        }
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}