stm32f4xx_hal/
adc.rs

1//! Analog to digital converter configuration.
2//!
3//! # Status
4//! Most options relating to regular conversions are implemented. One-shot and sequences of conversions
5//! have been tested and work as expected.
6//!
7//! GPIO to channel mapping should be correct for all supported F4 devices. The mappings were taken from
8//! CubeMX. The mappings are feature gated per 4xx device but there are actually sub variants for some
9//! devices and some pins may be missing on some variants. The implementation has been split up and commented
10//! to show which pins are available on certain device variants but currently the library doesn't enforce this.
11//! To fully support the right pins would require 10+ more features for the various variants.
12//! ## Todo
13//! * Injected conversions
14//! * Analog watchdog config
15//! * Discontinuous mode
16//! # Examples
17//! ## One-shot conversion
18//! ```
19//! use stm32f4xx_hal::{
20//!   gpio::gpioa,
21//!   adc::{
22//!     Adc,
23//!     config::{AdcConfig, SampleTime},
24//!   },
25//! };
26//!
27//! let mut adc = Adc::adc1(device.ADC1, true, AdcConfig::default());
28//! let pa3 = gpioa.pa3.into_analog();
29//! let sample = adc.convert(&pa3, SampleTime::Cycles_480);
30//! let millivolts = adc.sample_to_millivolts(sample);
31//! info!("pa3: {}mV", millivolts);
32//! ```
33//!
34//! ## Sequence conversion
35//! ```
36//! use stm32f4xx_hal::{
37//!   gpio::gpioa,
38//!   adc::{
39//!     Adc,
40//!     config::{AdcConfig, SampleTime, Sequence, Eoc, Scan, Clock},
41//!   },
42//! };
43//!
44//! let config = AdcConfig::default()
45//!     //We'll either need DMA or an interrupt per conversion to convert
46//!     //multiple values in a sequence
47//!     .end_of_conversion_interrupt(Eoc::Conversion)
48//!     //Scan mode is also required to convert a sequence
49//!     .scan(Scan::Enabled)
50//!     //And since we're looking for one interrupt per conversion the
51//!     //clock will need to be fairly slow to avoid overruns breaking
52//!     //the sequence. If you are running in debug mode and logging in
53//!     //the interrupt, good luck... try setting pclk2 really low.
54//!     //(Better yet use DMA)
55//!     .clock(Clock::Pclk2_div_8);
56//! let mut adc = Adc::adc1(device.ADC1, true, config);
57//! let pa0 = gpioa.pa0.into_analog();
58//! let pa3 = gpioa.pa3.into_analog();
59//! adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_112);
60//! adc.configure_channel(&pa3, Sequence::Two, SampleTime::Cycles_480);
61//! adc.configure_channel(&pa0, Sequence::Three, SampleTime::Cycles_112);
62//! adc.start_conversion();
63//! ```
64//!
65//! ## External trigger
66//!
67//! A common mistake on STM forums is enabling continuous mode but that causes it to start
68//! capturing on the first trigger and capture as fast as possible forever, regardless of
69//! future triggers. Continuous mode is disabled by default but I thought it was worth
70//! highlighting.
71//!
72//! Getting the timer config right to make sure it's sending the event the ADC is listening
73//! to can be a bit of a pain but the key fields are highlighted below. Try hooking a timer
74//! channel up to an external pin with an LED or oscilloscope attached to check it's really
75//! generating pulses if the ADC doesn't seem to be triggering.
76//! ```
77//! use stm32f4xx_hal::{
78//!   gpio::gpioa,
79//!   adc::{
80//!     Adc,
81//!     config::{AdcConfig, SampleTime, Sequence, Eoc, Scan, Clock},
82//!   },
83//! };
84//!
85//!  let config = AdcConfig::default()
86//!      //Set the trigger you want
87//!      .external_trigger(TriggerMode::RisingEdge, ExternalTrigger::Tim_1_cc_1);
88//!  let mut adc = Adc::adc1(device.ADC1, true, config);
89//!  let pa0 = gpioa.pa0.into_analog();
90//!  adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_112);
91//!  //Make sure it's enabled but don't start the conversion
92//!  adc.enable();
93//!
94//! //Configure the timer
95//! let mut tim = Timer::tim1(device.TIM1, 1.hz(), clocks);
96//! unsafe {
97//!     let tim = &(*TIM1::ptr());
98//!
99//!     //Channel 1
100//!     //Disable the channel before configuring it
101//!     tim.ccer().modify(|_, w| w.cc1e().clear_bit());
102//!
103//!     tim.ccmr1_output().modify(|_, w| w
104//!       //Preload enable for channel
105//!       .oc1pe().set_bit()
106//!
107//!       //Set mode for channel, the default mode is "frozen" which won't work
108//!       .oc1m().pwm_mode1()
109//!     );
110//!
111//!     //Set the duty cycle, 0 won't work in pwm mode but might be ok in
112//!     //toggle mode or match mode
113//!     let max_duty = tim.arr.read().arr().bits() as u16;
114//!     tim.ccr1.modify(|_, w| w.ccr().bits(max_duty / 2));
115//!
116//!     //Enable the channel
117//!     tim.ccer.modify(|_, w| w.cc1e().set_bit());
118//!
119//!     //Enable the TIM main Output
120//!     tim.bdtr.modify(|_, w| w.moe().set_bit());
121//! }
122//! ```
123
124#![deny(missing_docs)]
125
126/*
127    Currently unused but this is the formula for using temperature calibration:
128    Temperature in °C = (110-30) * (adc_sample - VtempCal30::get().read()) / (VtempCal110::get().read()-VtempCal30::get().read()) + 30
129*/
130
131use crate::dma::traits::{DMASet, PeriAddress, SafePeripheralRead};
132use crate::dma::PeripheralToMemory;
133use crate::rcc;
134use crate::{
135    gpio::{self, Analog},
136    pac::{self, RCC},
137    signature::VrefCal,
138    signature::VDDA_CALIB,
139};
140use core::fmt;
141use core::ops::Deref;
142
143pub mod config;
144mod f4;
145
146/// Vref internal signal, used for calibration
147pub struct Vref;
148
149/// Vbat internal signal, used for monitoring the battery (if used)
150pub struct Vbat;
151
152/// Core temperature internal signal
153pub struct Temperature;
154
155/// Marker trait for all ADC peripherals
156pub trait Instance:
157    crate::Sealed + Deref<Target = pac::adc1::RegisterBlock> + rcc::Enable + rcc::Reset
158{
159}
160
161#[doc(hidden)]
162pub trait Calibrate {
163    // Provide a stub implementation for ADCs that do not have a means of sampling VREF.
164    fn calibrate(&mut self) {}
165}
166
167impl Instance for pac::ADC1 {}
168#[cfg(feature = "adc2")]
169impl Instance for pac::ADC2 {}
170#[cfg(feature = "adc3")]
171impl Instance for pac::ADC3 {}
172
173/// Analog to Digital Converter
174#[derive(Clone, Copy)]
175pub struct Adc<ADC: Instance> {
176    /// Current config of the ADC, kept up to date by the various set methods
177    config: config::AdcConfig,
178    /// The adc peripheral
179    adc_reg: ADC,
180    /// VDDA in millivolts calculated from the factory calibration and vrefint
181    calibrated_vdda: u32,
182    /// Exclusive limit for the sample value possible for the configured resolution.
183    max_sample: u32,
184}
185impl<ADC: Instance> fmt::Debug for Adc<ADC> {
186    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187        write!(
188            f,
189            "Adc: {{ calibrated_vdda: {:?}, max_sample: {:?}, config: {:?}, ... }}",
190            self.calibrated_vdda, self.max_sample, self.config
191        )
192    }
193}
194
195// Note that only ADC1 supports measurement of VREF, VBAT, and the internal temperature sensor.
196impl Calibrate for Adc<pac::ADC1> {
197    /// Calculates the system VDDA by sampling the internal VREF channel and comparing
198    /// the result with the value stored at the factory.
199    fn calibrate(&mut self) {
200        self.enable();
201
202        let vref_en = self.temperature_and_vref_enabled();
203        if !vref_en {
204            self.enable_temperature_and_vref();
205        }
206
207        let vref_cal = VrefCal::get().read();
208        let vref_samp = self.read(&mut Vref).unwrap(); //This can't actually fail, it's just in a result to satisfy hal trait
209
210        self.calibrated_vdda = (VDDA_CALIB * u32::from(vref_cal)) / u32::from(vref_samp);
211        if !vref_en {
212            self.disable_temperature_and_vref();
213        }
214    }
215}
216
217impl Adc<pac::ADC1> {
218    /// Calibrate ADC
219    pub fn calibrate(&mut self) {
220        Calibrate::calibrate(self);
221    }
222
223    /// Enables the vbat internal channel
224    pub fn enable_vbat(&self) {
225        unsafe {
226            let common = &(*pac::ADC_COMMON::ptr());
227            common.ccr().modify(|_, w| w.vbate().set_bit());
228        }
229    }
230
231    /// Enables the vbat internal channel
232    pub fn disable_vbat(&self) {
233        unsafe {
234            let common = &(*pac::ADC_COMMON::ptr());
235            common.ccr().modify(|_, w| w.vbate().clear_bit());
236        }
237    }
238
239    /// Enables the temp and vref internal channels.
240    /// They can't work while vbat is also enabled so this method also disables vbat.
241    pub fn enable_temperature_and_vref(&mut self) {
242        //VBAT prevents TS and VREF from being sampled
243        self.disable_vbat();
244        unsafe {
245            let common = &(*pac::ADC_COMMON::ptr());
246            common.ccr().modify(|_, w| w.tsvrefe().set_bit());
247        }
248    }
249
250    /// Disables the temp and vref internal channels
251    pub fn disable_temperature_and_vref(&mut self) {
252        unsafe {
253            let common = &(*pac::ADC_COMMON::ptr());
254            common.ccr().modify(|_, w| w.tsvrefe().clear_bit());
255        }
256    }
257
258    /// Returns if the temp and vref internal channels are enabled
259    pub fn temperature_and_vref_enabled(&mut self) -> bool {
260        unsafe {
261            let common = &(*pac::ADC_COMMON::ptr());
262            common.ccr().read().tsvrefe().bit_is_set()
263        }
264    }
265}
266
267impl<ADC: Instance> SafePeripheralRead for Adc<ADC> {}
268
269impl<ADC: Instance> Adc<ADC>
270where
271    Self: Calibrate,
272{
273    /// Enables the ADC clock, resets the peripheral (optionally), runs calibration and applies the supplied config
274    /// # Arguments
275    /// * `reset` - should a reset be performed. This is provided because on some devices multiple ADCs share the same common reset
276    pub fn new(adc: ADC, reset: bool, config: config::AdcConfig, rcc: &mut RCC) -> Adc<ADC> {
277        // All ADCs share the same reset interface.
278
279        //Enable the clock
280        ADC::enable(rcc);
281
282        if reset {
283            //Reset the peripheral(s)
284            ADC::reset(rcc);
285        }
286
287        let mut s = Self {
288            config,
289            adc_reg: adc,
290            calibrated_vdda: VDDA_CALIB,
291            max_sample: 0,
292        };
293
294        //Probably unnecessary to disable the ADC in most cases but it shouldn't do any harm either
295        s.disable();
296        s.apply_config(config);
297
298        s.enable();
299        s.calibrate();
300
301        // If the user specified a VDDA, use that over the internally determined value.
302        if let Some(vdda) = s.config.vdda {
303            s.calibrated_vdda = vdda;
304        }
305
306        s
307    }
308}
309
310impl<ADC: Instance> Adc<ADC> {
311    /// Applies all fields in AdcConfig
312    pub fn apply_config(&mut self, config: config::AdcConfig) {
313        self.set_clock(config.clock);
314        self.set_resolution(config.resolution);
315        self.set_align(config.align);
316        self.set_scan(config.scan);
317        self.set_external_trigger(config.external_trigger);
318        self.set_continuous(config.continuous);
319        self.set_dma(config.dma);
320        self.set_end_of_conversion_interrupt(config.end_of_conversion_interrupt);
321        self.set_default_sample_time(config.default_sample_time);
322
323        if let Some(vdda) = config.vdda {
324            self.calibrated_vdda = vdda;
325        }
326    }
327
328    /// Returns if the adc is enabled
329    pub fn is_enabled(&self) -> bool {
330        self.adc_reg.cr2().read().adon().bit_is_set()
331    }
332
333    /// Enables the adc
334    pub fn enable(&mut self) {
335        self.adc_reg.cr2().modify(|_, w| w.adon().set_bit());
336    }
337
338    /// Disables the adc
339    /// # Note
340    /// The ADC in the f4 has few restrictions on what can be configured while the ADC
341    /// is enabled. If any bugs are found where some settings aren't "sticking" try disabling
342    /// the ADC before changing them. The reference manual for the chip I'm using only states
343    /// that the sequence registers are locked when they are being converted.
344    pub fn disable(&mut self) {
345        self.adc_reg.cr2().modify(|_, w| w.adon().clear_bit());
346    }
347
348    /// Starts conversion sequence. Waits for the hardware to indicate it's actually started.
349    pub fn start_conversion(&mut self) {
350        self.enable();
351        self.clear_end_of_conversion_flag();
352        //Start conversion
353        self.adc_reg.cr2().modify(|_, w| w.swstart().set_bit());
354
355        while !self.adc_reg.sr().read().strt().bit_is_set() {}
356    }
357
358    /// Sets the clock for the adc
359    pub fn set_clock(&mut self, clock: config::Clock) {
360        self.config.clock = clock;
361        unsafe {
362            let common = &(*pac::ADC_COMMON::ptr());
363            common.ccr().modify(|_, w| w.adcpre().bits(clock as _));
364        }
365    }
366
367    /// Sets the sampling resolution
368    pub fn set_resolution(&mut self, resolution: config::Resolution) {
369        self.max_sample = match resolution {
370            config::Resolution::Twelve => 1 << 12,
371            config::Resolution::Ten => 1 << 10,
372            config::Resolution::Eight => 1 << 8,
373            config::Resolution::Six => 1 << 6,
374        };
375        self.config.resolution = resolution;
376        self.adc_reg
377            .cr1()
378            .modify(|_, w| w.res().set(resolution as _));
379    }
380
381    /// Sets the DR register alignment to left or right
382    pub fn set_align(&mut self, align: config::Align) {
383        self.config.align = align;
384        self.adc_reg
385            .cr2()
386            .modify(|_, w| w.align().bit(align.into()));
387    }
388
389    /// Enables and disables scan mode
390    pub fn set_scan(&mut self, scan: config::Scan) {
391        self.config.scan = scan;
392        self.adc_reg.cr1().modify(|_, w| w.scan().bit(scan.into()));
393    }
394
395    /// Sets which external trigger to use and if it is disabled, rising, falling or both
396    pub fn set_external_trigger(
397        &mut self,
398        (edge, extsel): (config::TriggerMode, config::ExternalTrigger),
399    ) {
400        self.config.external_trigger = (edge, extsel);
401        self.adc_reg.cr2().modify(|_, w| {
402            unsafe {
403                w.extsel().bits(extsel as _);
404            }
405            w.exten().set(edge as _)
406        });
407    }
408
409    /// Enables and disables continuous mode
410    pub fn set_continuous(&mut self, continuous: config::Continuous) {
411        self.config.continuous = continuous;
412        self.adc_reg
413            .cr2()
414            .modify(|_, w| w.cont().bit(continuous.into()));
415    }
416
417    /// Sets DMA to disabled, single or continuous
418    pub fn set_dma(&mut self, dma: config::Dma) {
419        self.config.dma = dma;
420        let (dds, en) = match dma {
421            config::Dma::Disabled => (false, false),
422            config::Dma::Single => (false, true),
423            config::Dma::Continuous => (true, true),
424        };
425        self.adc_reg.cr2().modify(|_, w| {
426            //DDS stands for "DMA disable selection"
427            //0 means do one DMA then stop
428            //1 means keep sending DMA requests as long as DMA=1
429            w.dds().bit(dds);
430            w.dma().bit(en)
431        });
432    }
433
434    /// Sets if the end-of-conversion behaviour.
435    /// The end-of-conversion interrupt occur either per conversion or for the whole sequence.
436    pub fn set_end_of_conversion_interrupt(&mut self, eoc: config::Eoc) {
437        self.config.end_of_conversion_interrupt = eoc;
438        let (en, eocs) = match eoc {
439            config::Eoc::Disabled => (false, false),
440            config::Eoc::Conversion => (true, true),
441            config::Eoc::Sequence => (true, false),
442        };
443        self.adc_reg.cr1().modify(|_, w| w.eocie().bit(en));
444        self.adc_reg.cr2().modify(|_, w| w.eocs().bit(eocs));
445    }
446
447    /// Resets the end-of-conversion flag
448    pub fn clear_end_of_conversion_flag(&mut self) {
449        self.adc_reg.sr().modify(|_, w| w.eoc().clear_bit());
450    }
451
452    /// Sets the default sample time that is used for one-shot conversions.
453    /// [configure_channel](#method.configure_channel) and [start_conversion](#method.start_conversion) can be \
454    /// used for configurations where different sampling times are required per channel.
455    pub fn set_default_sample_time(&mut self, sample_time: config::SampleTime) {
456        self.config.default_sample_time = sample_time;
457    }
458
459    /// Returns the current sequence length. Primarily useful for configuring DMA.
460    pub fn sequence_length(&mut self) -> u8 {
461        self.adc_reg.sqr1().read().l().bits() + 1
462    }
463
464    /// Reset the sequence
465    pub fn reset_sequence(&mut self) {
466        //The reset state is One conversion selected
467        self.adc_reg
468            .sqr1()
469            .modify(|_, w| w.l().set(config::Sequence::One.into()));
470    }
471
472    /// Returns the address of the ADC data register. Primarily useful for configuring DMA.
473    pub fn data_register_address(&self) -> u32 {
474        self.adc_reg.dr().as_ptr() as u32
475    }
476
477    /// Configure a channel for sampling.
478    /// It will make sure the sequence is at least as long as the `sequence` provided.
479    /// # Arguments
480    /// * `channel` - channel to configure
481    /// * `sequence` - where in the sequence to sample the channel. Also called rank in some STM docs/code
482    /// * `sample_time` - how long to sample for. See datasheet and ref manual to work out how long you need
483    ///   to sample for at a given ADC clock frequency
484    pub fn configure_channel<CHANNEL>(
485        &mut self,
486        _channel: &CHANNEL,
487        sequence: config::Sequence,
488        sample_time: config::SampleTime,
489    ) where
490        CHANNEL: embedded_hal_02::adc::Channel<ADC, ID = u8>,
491    {
492        //Check the sequence is long enough
493        self.adc_reg.sqr1().modify(|r, w| {
494            let prev: config::Sequence = r.l().bits().into();
495            if prev < sequence {
496                w.l().set(sequence.into())
497            } else {
498                w
499            }
500        });
501
502        let channel = CHANNEL::channel();
503
504        //Set the channel in the right sequence field
505        use config::Sequence;
506        match sequence {
507            Sequence::One
508            | Sequence::Two
509            | Sequence::Three
510            | Sequence::Four
511            | Sequence::Five
512            | Sequence::Six => self
513                .adc_reg
514                .sqr3()
515                .modify(|_, w| unsafe { w.sq(sequence as u8).bits(channel) }),
516            Sequence::Seven
517            | Sequence::Eight
518            | Sequence::Nine
519            | Sequence::Ten
520            | Sequence::Eleven
521            | Sequence::Twelve => self
522                .adc_reg
523                .sqr2()
524                .modify(|_, w| unsafe { w.sq(sequence as u8 - 6).bits(channel) }),
525            _ => self
526                .adc_reg
527                .sqr1()
528                .modify(|_, w| unsafe { w.sq(sequence as u8 - 12).bits(channel) }),
529        };
530
531        //Set the sample time for the channel
532        let st = sample_time as u8;
533        match channel {
534            0..=9 => self
535                .adc_reg
536                .smpr2()
537                .modify(|_, w| unsafe { w.smp(channel).bits(st) }),
538            10..=18 => self
539                .adc_reg
540                .smpr1()
541                .modify(|_, w| unsafe { w.smp(channel - 10).bits(st) }),
542            _ => unimplemented!(),
543        };
544    }
545
546    /// Returns the current sample stored in the ADC data register
547    pub fn current_sample(&self) -> u16 {
548        self.adc_reg.dr().read().data().bits()
549    }
550
551    /// Converts a sample value to millivolts using calibrated VDDA and configured resolution.
552    /// Due to the ADC characteristics VDDA will never be reached as described in #362 and
553    /// [AN2834-How to get the best ADC accuracy in STM32 microcontrollers](https://www.st.com/resource/en/application_note/cd00211314-how-to-get-the-best-adc-accuracy-in-stm32-microcontrollers-stmicroelectronics.pdf) in section 3.1.2.
554    pub fn sample_to_millivolts(&self, sample: u16) -> u16 {
555        ((u32::from(sample) * self.calibrated_vdda) / self.max_sample) as u16
556    }
557
558    /// Make a converter for samples to millivolts
559    pub fn make_sample_to_millivolts(&self) -> impl Fn(u16) -> u16 {
560        let calibrated_vdda = self.calibrated_vdda;
561        let max_sample = self.max_sample;
562        move |sample| ((u32::from(sample) * calibrated_vdda) / max_sample) as u16
563    }
564
565    /// Returns the VDDA in millivolts calculated from the factory calibration and vrefint. Can be used to get calibration data from ADC1 and use it to configure ADCs that don't support calibration.
566    pub fn reference_voltage(&self) -> u32 {
567        self.calibrated_vdda
568    }
569
570    /// Block until the conversion is completed
571    /// # Panics
572    /// Will panic if there is no conversion started and the end-of-conversion bit is not set
573    pub fn wait_for_conversion_sequence(&self) {
574        if !self.adc_reg.sr().read().strt().bit_is_set()
575            && !self.adc_reg.sr().read().eoc().bit_is_set()
576        {
577            panic!("Waiting for end-of-conversion but no conversion started");
578        }
579        while !self.adc_reg.sr().read().eoc().bit_is_set() {}
580        //Clear the conversion started flag
581        self.adc_reg.sr().modify(|_, w| w.strt().clear_bit());
582    }
583
584    /// Synchronously convert a single sample
585    /// Note that it reconfigures the adc sequence and doesn't restore it
586    pub fn convert<PIN>(&mut self, pin: &PIN, sample_time: config::SampleTime) -> u16
587    where
588        PIN: embedded_hal_02::adc::Channel<ADC, ID = u8>,
589    {
590        self.adc_reg.cr2().modify(|_, w| {
591            //Disable dma
592            w.dma().clear_bit();
593            //Disable continuous mode
594            w.cont().clear_bit();
595            //Disable trigger
596            w.exten().set(config::TriggerMode::Disabled.into());
597            //EOC is set at the end of the sequence
598            w.eocs().clear_bit()
599        });
600        self.adc_reg.cr1().modify(|_, w| {
601            //Disable scan mode
602            w.scan().clear_bit();
603            //Disable end of conversion interrupt
604            w.eocie().clear_bit()
605        });
606
607        self.reset_sequence();
608        self.configure_channel(pin, config::Sequence::One, sample_time);
609        self.enable();
610        self.clear_end_of_conversion_flag();
611        self.start_conversion();
612
613        //Wait for the sequence to complete
614        self.wait_for_conversion_sequence();
615
616        let result = self.current_sample();
617
618        //Reset the config
619        self.apply_config(self.config);
620
621        result
622    }
623}
624
625impl<ADC: Instance> Adc<ADC> {
626    fn read<PIN>(&mut self, pin: &mut PIN) -> nb::Result<u16, ()>
627    where
628        PIN: embedded_hal_02::adc::Channel<ADC, ID = u8>,
629    {
630        let enabled = self.is_enabled();
631        if !enabled {
632            self.enable();
633        }
634
635        let sample = self.convert(pin, self.config.default_sample_time);
636
637        if !enabled {
638            self.disable();
639        }
640
641        Ok(sample)
642    }
643}
644
645impl<ADC: Instance, PIN> embedded_hal_02::adc::OneShot<ADC, u16, PIN> for Adc<ADC>
646where
647    PIN: embedded_hal_02::adc::Channel<ADC, ID = u8>,
648{
649    type Error = ();
650
651    fn read(&mut self, pin: &mut PIN) -> nb::Result<u16, Self::Error> {
652        self.read::<PIN>(pin)
653    }
654}
655
656unsafe impl<ADC: Instance> PeriAddress for Adc<ADC> {
657    #[inline(always)]
658    fn address(&self) -> u32 {
659        self.data_register_address()
660    }
661
662    type MemSize = u16;
663}
664
665unsafe impl<ADC: Instance, STREAM, const CHANNEL: u8> DMASet<STREAM, CHANNEL, PeripheralToMemory>
666    for Adc<ADC>
667where
668    ADC: DMASet<STREAM, CHANNEL, PeripheralToMemory>,
669{
670}
671
672macro_rules! adc_pins {
673    ($($pin:ty => ($adc:ident, $chan:expr)),+ $(,)*) => {
674        $(
675            impl embedded_hal_02::adc::Channel<pac::$adc> for $pin {
676                type ID = u8;
677                fn channel() -> u8 { $chan }
678            }
679        )+
680    };
681}
682use adc_pins;