stm32l4xx_hal/
adc.rs

1//! # Analog to Digital converter
2
3use core::{
4    convert::Infallible,
5    ops::DerefMut,
6    sync::atomic::{self, Ordering},
7};
8
9use crate::{
10    dma::{dma1, Event as DMAEvent, RxDma, Transfer, TransferPayload, W},
11    dmamux::{DmaInput, DmaMux},
12    gpio::{self, Analog},
13    hal::{
14        adc::{Channel as EmbeddedHalChannel, OneShot},
15        blocking::delay::DelayUs,
16    },
17    pac,
18    rcc::{Enable, Reset, AHB2, CCIPR},
19    signature::{VrefCal, VtempCalHigh, VtempCalLow, VDDA_CALIB_MV},
20};
21
22use pac::{ADC1, ADC_COMMON};
23use stable_deref_trait::StableDeref;
24
25/// Vref internal signal, used for calibration
26pub struct Vref;
27
28/// Vbat internal signal, used for monitoring the battery
29pub struct Vbat;
30
31/// Core temperature internal signal
32pub struct Temperature;
33
34/// Analog to Digital converter interface
35pub struct ADC {
36    pub(crate) adc: ADC1,
37    common: ADC_COMMON,
38    resolution: Resolution,
39    sample_time: SampleTime,
40    calibrated_vdda: u32,
41}
42
43#[derive(Copy, Clone, PartialEq)]
44pub enum DmaMode {
45    Disabled = 0,
46    Oneshot = 1,
47    // FIXME: Figure out how to get circular DMA to function properly (requires circbuffer?)
48    // Circular = 2,
49}
50
51#[derive(PartialEq, PartialOrd, Clone, Copy)]
52pub enum Sequence {
53    One = 0,
54    Two = 1,
55    Three = 2,
56    Four = 3,
57    Five = 4,
58    Six = 5,
59    Seven = 6,
60    Eight = 7,
61    Nine = 8,
62    Ten = 9,
63    Eleven = 10,
64    Twelve = 11,
65    Thirteen = 12,
66    Fourteen = 13,
67    Fifteen = 14,
68    Sixteen = 15,
69}
70
71impl From<u8> for Sequence {
72    fn from(bits: u8) -> Self {
73        match bits {
74            0 => Sequence::One,
75            1 => Sequence::Two,
76            2 => Sequence::Three,
77            3 => Sequence::Four,
78            4 => Sequence::Five,
79            5 => Sequence::Six,
80            6 => Sequence::Seven,
81            7 => Sequence::Eight,
82            8 => Sequence::Nine,
83            9 => Sequence::Ten,
84            10 => Sequence::Eleven,
85            11 => Sequence::Twelve,
86            12 => Sequence::Thirteen,
87            13 => Sequence::Fourteen,
88            14 => Sequence::Fifteen,
89            15 => Sequence::Sixteen,
90            _ => unimplemented!(),
91        }
92    }
93}
94
95impl Into<u8> for Sequence {
96    fn into(self) -> u8 {
97        match self {
98            Sequence::One => 0,
99            Sequence::Two => 1,
100            Sequence::Three => 2,
101            Sequence::Four => 3,
102            Sequence::Five => 4,
103            Sequence::Six => 5,
104            Sequence::Seven => 6,
105            Sequence::Eight => 7,
106            Sequence::Nine => 8,
107            Sequence::Ten => 9,
108            Sequence::Eleven => 10,
109            Sequence::Twelve => 11,
110            Sequence::Thirteen => 12,
111            Sequence::Fourteen => 13,
112            Sequence::Fifteen => 14,
113            Sequence::Sixteen => 15,
114        }
115    }
116}
117
118#[derive(PartialEq, PartialOrd, Clone, Copy)]
119pub enum Event {
120    EndOfRegularSequence,
121    EndOfRegularConversion,
122}
123
124impl ADC {
125    /// Initialize the ADC
126    pub fn new(
127        adc: ADC1,
128        common: ADC_COMMON,
129        ahb: &mut AHB2,
130        ccipr: &mut CCIPR,
131        delay: &mut impl DelayUs<u32>,
132    ) -> Self {
133        // Enable peripheral
134        ADC1::enable(ahb);
135
136        // Reset peripheral
137        ADC1::reset(ahb);
138
139        // Select system clock as ADC clock source
140        ccipr.ccipr().modify(|_, w| {
141            // This is sound, as `0b11` is a valid value for this field.
142            unsafe {
143                w.adcsel().bits(0b11);
144            }
145
146            w
147        });
148
149        // Initialize the ADC, according to the STM32L4xx Reference Manual,
150        // section 16.4.6.
151        adc.cr.write(|w| w.deeppwd().clear_bit()); // exit deep-power-down mode
152        adc.cr.modify(|_, w| w.advregen().set_bit()); // enable internal voltage regulator
153
154        // According to the STM32L4xx Reference Manual, section 16.4.6, we need
155        // to wait for T_ADCVREG_STUP after enabling the internal voltage
156        // regulator. For the STM32L433, this is 20 us. We choose 25 us to
157        // account for bad clocks.
158        delay.delay_us(25);
159
160        // Calibration procedure according to section 16.4.8.
161        adc.cr.modify(|_, w| {
162            w.adcal().set_bit(); // start calibration
163            w.adcaldif().clear_bit(); // single-ended mode
164
165            w
166        });
167
168        while adc.cr.read().adcal().bit_is_set() {}
169
170        // We need to wait 4 ADC clock after ADCAL goes low, 1 us is more than enough
171        delay.delay_us(1);
172
173        let mut s = Self {
174            adc,
175            common,
176            resolution: Resolution::default(),
177            sample_time: SampleTime::default(),
178            calibrated_vdda: VDDA_CALIB_MV,
179        };
180
181        // Temporarily enable Vref
182        let mut vref = s.enable_vref(delay);
183
184        s.calibrate(&mut vref);
185
186        s.common.ccr.modify(|_, w| w.vrefen().clear_bit());
187        s
188    }
189
190    /// Enable and get the `Vref`
191    pub fn enable_vref(&mut self, delay: &mut impl DelayUs<u32>) -> Vref {
192        self.common.ccr.modify(|_, w| w.vrefen().set_bit());
193
194        // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
195        // to stabilize the internal voltage reference, we wait a little more.
196        delay.delay_us(15);
197
198        Vref {}
199    }
200
201    /// Enable and get the `Temperature`
202    pub fn enable_temperature(&mut self, delay: &mut impl DelayUs<u32>) -> Temperature {
203        self.common.ccr.modify(|_, w| w.ch17sel().set_bit());
204
205        // FIXME: This note from the reference manual is currently not possible
206        // rm0351 section 18.4.32 pg580 (L47/L48/L49/L4A models)
207        // Note:
208        // The sensor has a startup time after waking from power-down mode before it can output VTS
209        // at the correct level. The ADC also has a startup time after power-on, so to minimize the
210        // delay, the ADEN and CH17SEL bits should be set at the same time.
211        //
212        // https://github.com/STMicroelectronics/STM32CubeL4/blob/master/Drivers/STM32L4xx_HAL_Driver/Inc/stm32l4xx_ll_adc.h#L1363
213        // 120us is used in the ST HAL code
214        delay.delay_us(150);
215
216        Temperature {}
217    }
218
219    /// Enable and get the `Vbat`
220    pub fn enable_vbat(&mut self) -> Vbat {
221        self.common.ccr.modify(|_, w| w.ch18sel().set_bit());
222
223        Vbat {}
224    }
225
226    /// Calculates the system VDDA by sampling the internal VREF channel and comparing
227    /// the result with the value stored at the factory. If the chip's VDDA is not stable, run
228    /// this before each ADC conversion.
229    pub fn calibrate(&mut self, vref: &mut Vref) {
230        let vref_cal = VrefCal::get().read();
231        let old_sample_time = self.sample_time;
232
233        // "Table 24. Embedded internal voltage reference" states that the sample time needs to be
234        // at a minimum 4 us. With 640.5 ADC cycles we have a minimum of 8 us at 80 MHz, leaving
235        // some headroom.
236        self.set_sample_time(SampleTime::Cycles640_5);
237
238        // This can't actually fail, it's just in a result to satisfy hal trait
239        let vref_samp = self.read(vref).unwrap();
240
241        self.set_sample_time(old_sample_time);
242
243        // Safety: DIV by 0 is possible if vref_samp is 0
244        self.calibrated_vdda = (VDDA_CALIB_MV * u32::from(vref_cal)) / u32::from(vref_samp);
245    }
246
247    /// Set the ADC resolution
248    pub fn set_resolution(&mut self, resolution: Resolution) {
249        self.resolution = resolution;
250    }
251
252    /// Set the sample time
253    pub fn set_sample_time(&mut self, sample_time: SampleTime) {
254        self.sample_time = sample_time;
255    }
256
257    /// Get the max value for the current resolution
258    pub fn get_max_value(&self) -> u16 {
259        match self.resolution {
260            Resolution::Bits12 => 4095,
261            Resolution::Bits10 => 1023,
262            Resolution::Bits8 => 255,
263            Resolution::Bits6 => 63,
264        }
265    }
266
267    /// Release the ADC peripheral
268    ///
269    /// Drops `ADC` and returns the `(pac::ADC, pad::ADC_COMMON)` that is was wrapping, giving the
270    /// user full access to the peripheral.
271    pub fn release(self) -> (ADC1, ADC_COMMON) {
272        (self.adc, self.common)
273    }
274
275    /// Convert a measurement to millivolts
276    pub fn to_millivolts(&self, sample: u16) -> u16 {
277        ((u32::from(sample) * self.calibrated_vdda) / self.resolution.to_max_count()) as u16
278    }
279
280    /// Convert a raw sample from the `Temperature` to deg C
281    pub fn to_degrees_centigrade(&self, sample: u16) -> f32 {
282        let sample = (u32::from(sample) * self.calibrated_vdda) / VDDA_CALIB_MV;
283        (VtempCalHigh::TEMP_DEGREES - VtempCalLow::TEMP_DEGREES) as f32
284            // as signed because RM0351 doesn't specify against this being an
285            // inverse relation (which would result in a negative differential)
286            / (VtempCalHigh::get().read() as i32 - VtempCalLow::get().read() as i32) as f32
287            // this can definitely be negative so must be done as a signed value
288            * (sample as i32 - VtempCalLow::get().read() as i32) as f32
289            // while it would make sense for this to be `VtempCalLow::TEMP_DEGREES` (which is 30*C),
290            // the RM specifically uses 30*C so this will too
291            + 30.0
292    }
293
294    // DMA channels:
295    //  ADC1: DMA2_3 with C2S 0000
296    //  ADC2: DMA2_4 with C2S 0000
297    //  ADC1: DMA1_1 with C1S 0000 (implemented)
298    //  ADC2: DMA1_2 with C1S 0000
299
300    pub fn get_data(&self) -> u16 {
301        // Sound, as bits 31:16 are reserved, read-only and 0 in ADC_DR
302        self.adc.dr.read().bits() as u16
303    }
304
305    /// Configure the channel for a specific step in the sequence.
306    ///
307    /// Automatically sets the sequence length to the farthes sequence
308    /// index that has been used so far. Use [`ADC::reset_sequence`] to
309    /// reset the sequence length.
310    pub fn configure_sequence<C>(
311        &mut self,
312        channel: &mut C,
313        sequence: Sequence,
314        sample_time: SampleTime,
315    ) where
316        C: Channel,
317    {
318        let channel_bits = C::channel();
319        channel.set_sample_time(&self.adc, sample_time);
320
321        unsafe {
322            // This is sound as channel() always returns a valid channel number
323            match sequence {
324                Sequence::One => self.adc.sqr1.modify(|_, w| w.sq1().bits(channel_bits)),
325                Sequence::Two => self.adc.sqr1.modify(|_, w| w.sq2().bits(channel_bits)),
326                Sequence::Three => self.adc.sqr1.modify(|_, w| w.sq3().bits(channel_bits)),
327                Sequence::Four => self.adc.sqr1.modify(|_, w| w.sq4().bits(channel_bits)),
328                Sequence::Five => self.adc.sqr2.modify(|_, w| w.sq5().bits(channel_bits)),
329                Sequence::Six => self.adc.sqr2.modify(|_, w| w.sq6().bits(channel_bits)),
330                Sequence::Seven => self.adc.sqr2.modify(|_, w| w.sq7().bits(channel_bits)),
331                Sequence::Eight => self.adc.sqr2.modify(|_, w| w.sq8().bits(channel_bits)),
332                Sequence::Nine => self.adc.sqr2.modify(|_, w| w.sq9().bits(channel_bits)),
333                Sequence::Ten => self.adc.sqr3.modify(|_, w| w.sq10().bits(channel_bits)),
334                Sequence::Eleven => self.adc.sqr3.modify(|_, w| w.sq11().bits(channel_bits)),
335                Sequence::Twelve => self.adc.sqr3.modify(|_, w| w.sq12().bits(channel_bits)),
336                Sequence::Thirteen => self.adc.sqr3.modify(|_, w| w.sq13().bits(channel_bits)),
337                Sequence::Fourteen => self.adc.sqr3.modify(|_, w| w.sq14().bits(channel_bits)),
338                Sequence::Fifteen => self.adc.sqr4.modify(|_, w| w.sq15().bits(channel_bits)),
339                Sequence::Sixteen => self.adc.sqr4.modify(|_, w| w.sq16().bits(channel_bits)),
340            }
341        }
342
343        // This will only ever extend the sequence, not shrink it.
344        let current_seql = self.get_sequence_length();
345        let next_seql: u8 = sequence.into();
346        if next_seql >= current_seql {
347            // Note: sequence length of 0 = 1 conversion
348            self.set_sequence_length(sequence.into());
349        }
350    }
351
352    /// Get the configured sequence length (= `actual sequence length - 1`)
353    pub(crate) fn get_sequence_length(&self) -> u8 {
354        self.adc.sqr1.read().l().bits()
355    }
356
357    /// Private: length must be `actual sequence length - 1`, so not API-friendly.
358    /// Use [`ADC::reset_sequence`] and [`ADC::configure_sequence`] instead
359    fn set_sequence_length(&mut self, length: u8) {
360        self.adc.sqr1.modify(|_, w| unsafe { w.l().bits(length) });
361    }
362
363    /// Reset the sequence length to 1
364    ///
365    /// Does *not* erase previously configured sequence settings, only
366    /// changes the sequence length
367    pub fn reset_sequence(&mut self) {
368        self.adc.sqr1.modify(|_, w| unsafe { w.l().bits(0b0000) })
369    }
370
371    pub fn has_completed_conversion(&self) -> bool {
372        self.adc.isr.read().eoc().bit_is_set()
373    }
374
375    pub fn has_completed_sequence(&self) -> bool {
376        self.adc.isr.read().eos().bit_is_set()
377    }
378
379    pub fn clear_end_flags(&mut self) {
380        // EOS and EOC are reset by setting them (See reference manual section 16.6.1)
381        self.adc
382            .isr
383            .modify(|_, w| w.eos().set_bit().eoc().set_bit());
384    }
385
386    pub fn start_conversion(&mut self) {
387        self.enable();
388        self.clear_end_flags();
389        self.adc.cr.modify(|_, w| w.adstart().set_bit());
390    }
391
392    pub fn is_converting(&self) -> bool {
393        self.adc.cr.read().adstart().bit_is_set()
394    }
395
396    pub fn listen(&mut self, event: Event) {
397        self.adc.ier.modify(|_, w| match event {
398            Event::EndOfRegularSequence => w.eosie().set_bit(),
399            Event::EndOfRegularConversion => w.eocie().set_bit(),
400        });
401    }
402
403    pub fn unlisten(&mut self, event: Event) {
404        self.adc.ier.modify(|_, w| match event {
405            Event::EndOfRegularSequence => w.eosie().clear_bit(),
406            Event::EndOfRegularConversion => w.eocie().clear_bit(),
407        });
408    }
409
410    pub fn enable(&mut self) {
411        if !self.is_enabled() {
412            // Make sure bits are off
413            while self.adc.cr.read().addis().bit_is_set() {}
414
415            // Clear ADRDY by setting it (See Reference Manual section 1.16.1)
416            self.adc.isr.modify(|_, w| w.adrdy().set_bit());
417            self.adc.cr.modify(|_, w| w.aden().set_bit());
418            while self.adc.isr.read().adrdy().bit_is_clear() {}
419
420            // Configure ADC
421            self.adc.cfgr.modify(|_, w| {
422                // This is sound, as all `Resolution` values are valid for this
423                // field.
424                unsafe { w.res().bits(self.resolution as u8) }
425            });
426        }
427    }
428
429    pub fn is_enabled(&self) -> bool {
430        self.adc.cr.read().aden().bit_is_set()
431    }
432
433    pub fn disable(&mut self) {
434        self.adc.cr.modify(|_, w| w.addis().set_bit());
435    }
436}
437
438impl<C> OneShot<ADC, u16, C> for ADC
439where
440    C: Channel,
441{
442    type Error = Infallible;
443
444    fn read(&mut self, channel: &mut C) -> nb::Result<u16, Self::Error> {
445        self.configure_sequence(channel, Sequence::One, self.sample_time);
446
447        self.start_conversion();
448        while !self.has_completed_sequence() {}
449
450        // Read ADC value first time and discard it, as per errata sheet.
451        // The errata states that if we do conversions slower than 1 kHz, the
452        // first read ADC value can be corrupted, so we discard it and measure again.
453        let _ = self.get_data();
454
455        self.start_conversion();
456        while !self.has_completed_sequence() {}
457
458        // Read ADC value
459        let val = self.get_data();
460
461        // Disable ADC
462        self.disable();
463
464        Ok(val)
465    }
466}
467
468impl TransferPayload for RxDma<ADC, dma1::C1> {
469    fn start(&mut self) {
470        self.channel.start();
471    }
472
473    fn stop(&mut self) {
474        self.channel.stop();
475    }
476}
477
478impl RxDma<ADC, dma1::C1> {
479    pub fn split(mut self) -> (ADC, dma1::C1) {
480        self.stop();
481        (self.payload, self.channel)
482    }
483}
484
485impl<BUFFER, const N: usize> Transfer<W, BUFFER, RxDma<ADC, dma1::C1>>
486where
487    BUFFER: Sized + StableDeref<Target = [u16; N]> + DerefMut + 'static,
488{
489    pub fn from_adc_dma(
490        dma: RxDma<ADC, dma1::C1>,
491        buffer: BUFFER,
492        dma_mode: DmaMode,
493        transfer_complete_interrupt: bool,
494    ) -> Self {
495        let (adc, channel) = dma.split();
496        Transfer::from_adc(adc, channel, buffer, dma_mode, transfer_complete_interrupt)
497    }
498
499    /// Initiate a new DMA transfer from an ADC.
500    ///
501    /// `dma_mode` indicates the desired mode for DMA.
502    ///
503    /// If `transfer_complete_interrupt` is true, the transfer
504    /// complete interrupt (= `DMA1_CH1`) will be enabled
505    pub fn from_adc(
506        mut adc: ADC,
507        mut channel: dma1::C1,
508        buffer: BUFFER,
509        dma_mode: DmaMode,
510        transfer_complete_interrupt: bool,
511    ) -> Self {
512        assert!(dma_mode != DmaMode::Disabled);
513
514        let (enable, circular) = match dma_mode {
515            DmaMode::Disabled => (false, false),
516            DmaMode::Oneshot => (true, false),
517        };
518
519        adc.adc
520            .cfgr
521            .modify(|_, w| w.dmaen().bit(enable).dmacfg().bit(circular));
522
523        channel.set_peripheral_address(&adc.adc.dr as *const _ as u32, false);
524
525        // SAFETY: since the length of BUFFER is known to be `N`, we are allowed
526        // to perform N transfers into said buffer
527        channel.set_memory_address(buffer.as_ptr() as u32, true);
528        channel.set_transfer_length(N as u16);
529
530        channel.set_request_line(DmaInput::Adc1).unwrap();
531
532        channel.ccr().modify(|_, w| unsafe {
533            w.mem2mem()
534                .clear_bit()
535                // 00: Low, 01: Medium, 10: High, 11: Very high
536                .pl()
537                .bits(0b01)
538                // 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved
539                .msize()
540                .bits(0b01)
541                // 00: 8-bits, 01: 16-bits, 10: 32-bits, 11: Reserved
542                .psize()
543                .bits(0b01)
544                // Peripheral -> Mem
545                .dir()
546                .clear_bit()
547                .circ()
548                .bit(circular)
549        });
550
551        if transfer_complete_interrupt {
552            channel.listen(DMAEvent::TransferComplete);
553        }
554
555        atomic::compiler_fence(Ordering::Release);
556
557        channel.start();
558        adc.start_conversion();
559
560        Transfer::w(
561            buffer,
562            RxDma {
563                channel,
564                payload: adc,
565            },
566        )
567    }
568}
569
570/// ADC resolution setting
571///
572/// The default setting is 12 bits.
573#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
574pub enum Resolution {
575    /// 12-bit resolution
576    Bits12 = 0b00,
577
578    /// 10-bit resolution
579    Bits10 = 0b01,
580
581    /// 8-bit resolution
582    Bits8 = 0b10,
583
584    /// 6-bit resolution
585    Bits6 = 0b11,
586}
587
588impl Default for Resolution {
589    fn default() -> Self {
590        Self::Bits12
591    }
592}
593
594impl Resolution {
595    fn to_max_count(&self) -> u32 {
596        match self {
597            Resolution::Bits12 => (1 << 12) - 1,
598            Resolution::Bits10 => (1 << 10) - 1,
599            Resolution::Bits8 => (1 << 8) - 1,
600            Resolution::Bits6 => (1 << 6) - 1,
601        }
602    }
603}
604
605/// ADC sample time
606///
607/// The default setting is 2.5 ADC clock cycles.
608#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
609pub enum SampleTime {
610    /// 2.5 ADC clock cycles
611    Cycles2_5 = 0b000,
612
613    /// 6.5 ADC clock cycles
614    Cycles6_5 = 0b001,
615
616    /// 12.5 ADC clock cycles
617    Cycles12_5 = 0b010,
618
619    /// 24.5 ADC clock cycles
620    Cycles24_5 = 0b011,
621
622    /// 47.5 ADC clock cycles
623    Cycles47_5 = 0b100,
624
625    /// 92.5 ADC clock cycles
626    Cycles92_5 = 0b101,
627
628    /// 247.5 ADC clock cycles
629    Cycles247_5 = 0b110,
630
631    /// 640.5 ADC clock cycles
632    Cycles640_5 = 0b111,
633}
634
635impl Default for SampleTime {
636    fn default() -> Self {
637        Self::Cycles2_5
638    }
639}
640
641/// Implemented for all types that represent ADC channels
642pub trait Channel: EmbeddedHalChannel<ADC, ID = u8> {
643    fn set_sample_time(&mut self, adc: &ADC1, sample_time: SampleTime);
644}
645
646macro_rules! adc_pins {
647    (
648        $(
649            $id:expr,
650            $pin:ty,
651            $smpr:ident,
652            $smp:ident;
653        )*
654    ) => {
655        $(
656            impl EmbeddedHalChannel<ADC> for $pin {
657                type ID = u8;
658
659                fn channel() -> Self::ID {
660                    $id
661                }
662            }
663
664            impl Channel for $pin {
665                fn set_sample_time(&mut self,
666                    adc: &ADC1,
667                    sample_time: SampleTime,
668                ) {
669                    adc.$smpr.modify(|_, w| {
670                        // This is sound, as all `SampleTime` values are valid
671                        // for this field.
672                        unsafe {
673                            w.$smp().bits(sample_time as u8)
674                        }
675                    })
676                }
677            }
678        )*
679    };
680}
681
682adc_pins!(
683    0,  Vref,              smpr1, smp0;
684    1,  gpio::PC0<Analog>, smpr1, smp1;
685    2,  gpio::PC1<Analog>, smpr1, smp2;
686    3,  gpio::PC2<Analog>, smpr1, smp3;
687    4,  gpio::PC3<Analog>, smpr1, smp4;
688    5,  gpio::PA0<Analog>, smpr1, smp5;
689    6,  gpio::PA1<Analog>, smpr1, smp6;
690    7,  gpio::PA2<Analog>, smpr1, smp7;
691    8,  gpio::PA3<Analog>, smpr1, smp8;
692    9,  gpio::PA4<Analog>, smpr1, smp9;
693    10, gpio::PA5<Analog>, smpr2, smp10;
694    11, gpio::PA6<Analog>, smpr2, smp11;
695    12, gpio::PA7<Analog>, smpr2, smp12;
696    13, gpio::PC4<Analog>, smpr2, smp13;
697    14, gpio::PC5<Analog>, smpr2, smp14;
698    15, gpio::PB0<Analog>, smpr2, smp15;
699    16, gpio::PB1<Analog>, smpr2, smp16;
700    17, Temperature,       smpr2, smp17;
701    18, Vbat,              smpr2, smp18;
702);