esp_hal/analog/adc/
riscv.rs

1use core::marker::PhantomData;
2
3cfg_if::cfg_if! {
4    if #[cfg(esp32c6)] {
5        use Interrupt::APB_SARADC as InterruptSource;
6    } else {
7        use Interrupt::APB_ADC as InterruptSource;
8    }
9}
10
11#[cfg(not(esp32h2))]
12pub use self::calibration::*;
13use super::{AdcCalSource, AdcConfig, Attenuation};
14#[cfg(any(esp32c6, esp32h2))]
15use crate::clock::clocks_ll::regi2c_write_mask;
16#[cfg(any(esp32c2, esp32c3, esp32c6))]
17use crate::efuse::Efuse;
18use crate::{
19    analog::adc::asynch::AdcFuture,
20    interrupt::{InterruptConfigurable, InterruptHandler},
21    peripheral::PeripheralRef,
22    peripherals::{Interrupt, APB_SARADC},
23    system::{GenericPeripheralGuard, Peripheral},
24    Async,
25    Blocking,
26};
27
28mod calibration;
29
30// polyfill for c2 and c3
31#[cfg(any(esp32c2, esp32c3))]
32#[inline(always)]
33fn regi2c_write_mask(block: u8, host_id: u8, reg_add: u8, msb: u8, lsb: u8, data: u8) {
34    unsafe {
35        crate::rom::rom_i2c_writeReg_Mask(
36            block as _,
37            host_id as _,
38            reg_add as _,
39            msb as _,
40            lsb as _,
41            data as _,
42        );
43    }
44}
45
46// Constants taken from:
47// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32c2/include/soc/regi2c_saradc.h
48// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32c3/include/soc/regi2c_saradc.h
49// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32c6/include/soc/regi2c_saradc.h
50// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32h2/include/soc/regi2c_saradc.h
51// https://github.com/espressif/esp-idf/blob/903af13e8/components/soc/esp32h4/include/soc/regi2c_saradc.h
52cfg_if::cfg_if! {
53    if #[cfg(adc1)] {
54        const I2C_SAR_ADC: u8 = 0x69;
55        const I2C_SAR_ADC_HOSTID: u8 = 0;
56
57        const ADC_VAL_MASK: u16 = 0xfff;
58        const ADC_CAL_CNT_MAX: u16 = 32;
59        const ADC_CAL_CHANNEL: u16 = 15;
60
61        const ADC_SAR1_ENCAL_GND_ADDR: u8 = 0x7;
62        const ADC_SAR1_ENCAL_GND_ADDR_MSB: u8 = 5;
63        const ADC_SAR1_ENCAL_GND_ADDR_LSB: u8 = 5;
64
65        const ADC_SAR1_INITIAL_CODE_HIGH_ADDR: u8 = 0x1;
66        const ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB: u8 = 0x3;
67        const ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB: u8 = 0x0;
68
69        const ADC_SAR1_INITIAL_CODE_LOW_ADDR: u8 = 0x0;
70        const ADC_SAR1_INITIAL_CODE_LOW_ADDR_MSB: u8 = 0x7;
71        const ADC_SAR1_INITIAL_CODE_LOW_ADDR_LSB: u8 = 0x0;
72
73        const ADC_SAR1_DREF_ADDR: u8 = 0x2;
74        const ADC_SAR1_DREF_ADDR_MSB: u8 = 0x6;
75        const ADC_SAR1_DREF_ADDR_LSB: u8 = 0x4;
76
77        const ADC_SARADC1_ENCAL_REF_ADDR: u8 = 0x7;
78        const ADC_SARADC1_ENCAL_REF_ADDR_MSB: u8 = 4;
79        const ADC_SARADC1_ENCAL_REF_ADDR_LSB: u8 = 4;
80    }
81}
82
83cfg_if::cfg_if! {
84    if #[cfg(adc2)] {
85        const ADC_SAR2_ENCAL_GND_ADDR: u8 = 0x7;
86        const ADC_SAR2_ENCAL_GND_ADDR_MSB: u8 = 7;
87        const ADC_SAR2_ENCAL_GND_ADDR_LSB: u8 = 7;
88
89        const ADC_SAR2_INITIAL_CODE_HIGH_ADDR: u8 = 0x4;
90        const ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB: u8 = 0x3;
91        const ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB: u8 = 0x0;
92
93        const ADC_SAR2_INITIAL_CODE_LOW_ADDR: u8 = 0x3;
94        const ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB: u8 = 0x7;
95        const ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB: u8 = 0x0;
96
97        const ADC_SAR2_DREF_ADDR: u8 = 0x5;
98        const ADC_SAR2_DREF_ADDR_MSB: u8 = 0x6;
99        const ADC_SAR2_DREF_ADDR_LSB: u8 = 0x4;
100
101        const ADC_SARADC2_ENCAL_REF_ADDR: u8 = 0x7;
102        const ADC_SARADC2_ENCAL_REF_ADDR_MSB: u8 = 6;
103        const ADC_SARADC2_ENCAL_REF_ADDR_LSB: u8 = 6;
104    }
105}
106
107// The number of analog IO pins, and in turn the number of attentuations,
108// depends on which chip is being used
109cfg_if::cfg_if! {
110    if #[cfg(esp32c6)] {
111        pub(super) const NUM_ATTENS: usize = 7;
112    } else {
113        pub(super) const NUM_ATTENS: usize = 5;
114    }
115}
116
117/// The sampling/readout resolution of the ADC.
118#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
119#[cfg_attr(feature = "defmt", derive(defmt::Format))]
120#[allow(clippy::enum_variant_names, reason = "peripheral is unstable")]
121pub enum Resolution {
122    /// 12-bit resolution
123    #[default]
124    Resolution12Bit,
125}
126
127impl<ADCI> AdcConfig<ADCI>
128where
129    ADCI: RegisterAccess,
130{
131    /// Calibrate ADC with specified attenuation and voltage source
132    pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16
133    where
134        ADCI: super::CalibrationAccess,
135    {
136        let mut adc_max: u16 = 0;
137        let mut adc_min: u16 = u16::MAX;
138        let mut adc_sum: u32 = 0;
139
140        ADCI::enable_vdef(true);
141
142        // Start sampling
143        ADCI::config_onetime_sample(ADC_CAL_CHANNEL as u8, atten as u8);
144
145        // Connect calibration source
146        ADCI::connect_cal(source, true);
147
148        for _ in 0..ADC_CAL_CNT_MAX {
149            ADCI::set_init_code(0);
150
151            // Trigger ADC sampling
152            ADCI::start_onetime_sample();
153
154            // Wait until ADC1 sampling is done
155            while !ADCI::is_done() {}
156
157            let adc = ADCI::read_data() & ADC_VAL_MASK;
158
159            ADCI::reset();
160
161            adc_sum += adc as u32;
162            adc_max = adc.max(adc_max);
163            adc_min = adc.min(adc_min);
164        }
165
166        let cal_val = (adc_sum - adc_max as u32 - adc_min as u32) as u16 / (ADC_CAL_CNT_MAX - 2);
167
168        // Disconnect calibration source
169        ADCI::connect_cal(source, false);
170
171        cal_val
172    }
173}
174
175#[doc(hidden)]
176pub trait RegisterAccess {
177    /// Configure onetime sampling parameters
178    fn config_onetime_sample(channel: u8, attenuation: u8);
179
180    /// Start onetime sampling
181    fn start_onetime_sample();
182
183    /// Check if sampling is done
184    fn is_done() -> bool;
185
186    /// Read sample data
187    fn read_data() -> u16;
188
189    /// Reset flags
190    fn reset();
191
192    /// Set calibration parameter to ADC hardware
193    fn set_init_code(data: u16);
194}
195
196#[cfg(adc1)]
197impl RegisterAccess for crate::peripherals::ADC1 {
198    fn config_onetime_sample(channel: u8, attenuation: u8) {
199        APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
200            w.saradc1_onetime_sample().set_bit();
201            w.onetime_channel().bits(channel);
202            w.onetime_atten().bits(attenuation)
203        });
204    }
205
206    fn start_onetime_sample() {
207        APB_SARADC::regs()
208            .onetime_sample()
209            .modify(|_, w| w.onetime_start().set_bit());
210    }
211
212    fn is_done() -> bool {
213        APB_SARADC::regs().int_raw().read().adc1_done().bit()
214    }
215
216    fn read_data() -> u16 {
217        APB_SARADC::regs()
218            .sar1data_status()
219            .read()
220            .saradc1_data()
221            .bits() as u16
222            & 0xfff
223    }
224
225    fn reset() {
226        // Clear ADC1 sampling done interrupt bit
227        APB_SARADC::regs()
228            .int_clr()
229            .write(|w| w.adc1_done().clear_bit_by_one());
230
231        // Disable ADC sampling
232        APB_SARADC::regs()
233            .onetime_sample()
234            .modify(|_, w| w.onetime_start().clear_bit());
235    }
236
237    fn set_init_code(data: u16) {
238        let [msb, lsb] = data.to_be_bytes();
239
240        regi2c_write_mask(
241            I2C_SAR_ADC,
242            I2C_SAR_ADC_HOSTID,
243            ADC_SAR1_INITIAL_CODE_HIGH_ADDR,
244            ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB,
245            ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB,
246            msb as _,
247        );
248        regi2c_write_mask(
249            I2C_SAR_ADC,
250            I2C_SAR_ADC_HOSTID,
251            ADC_SAR1_INITIAL_CODE_LOW_ADDR,
252            ADC_SAR1_INITIAL_CODE_LOW_ADDR_MSB,
253            ADC_SAR1_INITIAL_CODE_LOW_ADDR_LSB,
254            lsb as _,
255        );
256    }
257}
258
259#[cfg(adc1)]
260impl super::CalibrationAccess for crate::peripherals::ADC1 {
261    const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
262    const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
263    const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
264
265    fn enable_vdef(enable: bool) {
266        let value = enable as _;
267        regi2c_write_mask(
268            I2C_SAR_ADC,
269            I2C_SAR_ADC_HOSTID,
270            ADC_SAR1_DREF_ADDR,
271            ADC_SAR1_DREF_ADDR_MSB,
272            ADC_SAR1_DREF_ADDR_LSB,
273            value,
274        );
275    }
276
277    fn connect_cal(source: AdcCalSource, enable: bool) {
278        let value = enable as _;
279        match source {
280            AdcCalSource::Gnd => regi2c_write_mask(
281                I2C_SAR_ADC,
282                I2C_SAR_ADC_HOSTID,
283                ADC_SAR1_ENCAL_GND_ADDR,
284                ADC_SAR1_ENCAL_GND_ADDR_MSB,
285                ADC_SAR1_ENCAL_GND_ADDR_LSB,
286                value,
287            ),
288            AdcCalSource::Ref => regi2c_write_mask(
289                I2C_SAR_ADC,
290                I2C_SAR_ADC_HOSTID,
291                ADC_SARADC1_ENCAL_REF_ADDR,
292                ADC_SARADC1_ENCAL_REF_ADDR_MSB,
293                ADC_SARADC1_ENCAL_REF_ADDR_LSB,
294                value,
295            ),
296        }
297    }
298}
299
300#[cfg(adc2)]
301impl RegisterAccess for crate::peripherals::ADC2 {
302    fn config_onetime_sample(channel: u8, attenuation: u8) {
303        APB_SARADC::regs().onetime_sample().modify(|_, w| unsafe {
304            w.saradc2_onetime_sample().set_bit();
305            w.onetime_channel().bits(channel);
306            w.onetime_atten().bits(attenuation)
307        });
308    }
309
310    fn start_onetime_sample() {
311        APB_SARADC::regs()
312            .onetime_sample()
313            .modify(|_, w| w.onetime_start().set_bit());
314    }
315
316    fn is_done() -> bool {
317        APB_SARADC::regs().int_raw().read().adc2_done().bit()
318    }
319
320    fn read_data() -> u16 {
321        APB_SARADC::regs()
322            .sar2data_status()
323            .read()
324            .saradc2_data()
325            .bits() as u16
326            & 0xfff
327    }
328
329    fn reset() {
330        APB_SARADC::regs()
331            .int_clr()
332            .write(|w| w.adc2_done().clear_bit_by_one());
333
334        APB_SARADC::regs()
335            .onetime_sample()
336            .modify(|_, w| w.onetime_start().clear_bit());
337    }
338
339    fn set_init_code(data: u16) {
340        let [msb, lsb] = data.to_be_bytes();
341
342        regi2c_write_mask(
343            I2C_SAR_ADC,
344            I2C_SAR_ADC_HOSTID,
345            ADC_SAR2_INITIAL_CODE_HIGH_ADDR,
346            ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB,
347            ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB,
348            msb as _,
349        );
350        regi2c_write_mask(
351            I2C_SAR_ADC,
352            I2C_SAR_ADC_HOSTID,
353            ADC_SAR2_INITIAL_CODE_LOW_ADDR,
354            ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB,
355            ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB,
356            lsb as _,
357        );
358    }
359}
360
361#[cfg(adc2)]
362impl super::CalibrationAccess for crate::peripherals::ADC2 {
363    const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
364    const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
365    const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
366
367    fn enable_vdef(enable: bool) {
368        let value = enable as _;
369        regi2c_write_mask(
370            I2C_SAR_ADC,
371            I2C_SAR_ADC_HOSTID,
372            ADC_SAR2_DREF_ADDR,
373            ADC_SAR2_DREF_ADDR_MSB,
374            ADC_SAR2_DREF_ADDR_LSB,
375            value,
376        );
377    }
378
379    fn connect_cal(source: AdcCalSource, enable: bool) {
380        let value = enable as _;
381        match source {
382            AdcCalSource::Gnd => regi2c_write_mask(
383                I2C_SAR_ADC,
384                I2C_SAR_ADC_HOSTID,
385                ADC_SAR2_ENCAL_GND_ADDR,
386                ADC_SAR2_ENCAL_GND_ADDR_MSB,
387                ADC_SAR2_ENCAL_GND_ADDR_LSB,
388                value,
389            ),
390            AdcCalSource::Ref => regi2c_write_mask(
391                I2C_SAR_ADC,
392                I2C_SAR_ADC_HOSTID,
393                ADC_SARADC2_ENCAL_REF_ADDR,
394                ADC_SARADC2_ENCAL_REF_ADDR_MSB,
395                ADC_SARADC2_ENCAL_REF_ADDR_LSB,
396                value,
397            ),
398        }
399    }
400}
401
402/// Analog-to-Digital Converter peripheral driver.
403pub struct Adc<'d, ADCI, Dm: crate::DriverMode> {
404    _adc: PeripheralRef<'d, ADCI>,
405    attenuations: [Option<Attenuation>; NUM_ATTENS],
406    active_channel: Option<u8>,
407    _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
408    _phantom: PhantomData<Dm>,
409}
410
411impl<'d, ADCI> Adc<'d, ADCI, Blocking>
412where
413    ADCI: RegisterAccess + 'd,
414{
415    /// Configure a given ADC instance using the provided configuration, and
416    /// initialize the ADC for use
417    pub fn new(
418        adc_instance: impl crate::peripheral::Peripheral<P = ADCI> + 'd,
419        config: AdcConfig<ADCI>,
420    ) -> Self {
421        let guard = GenericPeripheralGuard::new();
422
423        APB_SARADC::regs().ctrl().modify(|_, w| unsafe {
424            w.start_force().set_bit();
425            w.start().set_bit();
426            w.sar_clk_gated().set_bit();
427            w.xpd_sar_force().bits(0b11)
428        });
429
430        Adc {
431            _adc: adc_instance.into_ref(),
432            attenuations: config.attenuations,
433            active_channel: None,
434            _guard: guard,
435            _phantom: PhantomData,
436        }
437    }
438
439    /// Reconfigures the ADC driver to operate in asynchronous mode.
440    pub fn into_async(mut self) -> Adc<'d, ADCI, Async> {
441        asynch::acquire_async_adc();
442        self.set_interrupt_handler(asynch::adc_interrupt_handler);
443
444        // Reset interrupt flags and disable oneshot reading to normalize state before
445        // entering async mode, otherwise there can be '0' readings, happening initially
446        // using ADC2
447        ADCI::reset();
448
449        Adc {
450            _adc: self._adc,
451            attenuations: self.attenuations,
452            active_channel: self.active_channel,
453            _guard: self._guard,
454            _phantom: PhantomData,
455        }
456    }
457
458    /// Request that the ADC begin a conversion on the specified pin
459    ///
460    /// This method takes an [AdcPin](super::AdcPin) reference, as it is
461    /// expected that the ADC will be able to sample whatever channel
462    /// underlies the pin.
463    pub fn read_oneshot<PIN, CS>(
464        &mut self,
465        pin: &mut super::AdcPin<PIN, ADCI, CS>,
466    ) -> nb::Result<u16, ()>
467    where
468        PIN: super::AdcChannel,
469        CS: super::AdcCalScheme<ADCI>,
470    {
471        if self.attenuations[PIN::CHANNEL as usize].is_none() {
472            panic!("Channel {} is not configured reading!", PIN::CHANNEL);
473        }
474
475        if let Some(active_channel) = self.active_channel {
476            // There is conversion in progress:
477            // - if it's for a different channel try again later
478            // - if it's for the given channel, go ahead and check progress
479            if active_channel != PIN::CHANNEL {
480                return Err(nb::Error::WouldBlock);
481            }
482        } else {
483            // If no conversions are in progress, start a new one for given channel
484            self.active_channel = Some(PIN::CHANNEL);
485
486            // Set ADC unit calibration according used scheme for pin
487            ADCI::set_init_code(pin.cal_scheme.adc_cal());
488
489            let channel = self.active_channel.unwrap();
490            let attenuation = self.attenuations[channel as usize].unwrap() as u8;
491            ADCI::config_onetime_sample(channel, attenuation);
492            ADCI::start_onetime_sample();
493
494            // see https://github.com/espressif/esp-idf/blob/b4268c874a4cf8fcf7c0c4153cffb76ad2ddda4e/components/hal/adc_oneshot_hal.c#L105-L107
495            // the delay might be a bit generous but longer delay seem to not cause problems
496            #[cfg(esp32c6)]
497            {
498                crate::rom::ets_delay_us(40);
499                ADCI::start_onetime_sample();
500            }
501        }
502
503        // Wait for ADC to finish conversion
504        let conversion_finished = ADCI::is_done();
505        if !conversion_finished {
506            return Err(nb::Error::WouldBlock);
507        }
508
509        // Get converted value
510        let converted_value = ADCI::read_data();
511        ADCI::reset();
512
513        // Postprocess converted value according to calibration scheme used for pin
514        let converted_value = pin.cal_scheme.adc_val(converted_value);
515
516        // There is a hardware limitation. If the APB clock frequency is high, the step
517        // of this reg signal: ``onetime_start`` may not be captured by the
518        // ADC digital controller (when its clock frequency is too slow). A rough
519        // estimate for this step should be at least 3 ADC digital controller
520        // clock cycle.
521        //
522        // This limitation will be removed in hardware future versions.
523        // We reset ``onetime_start`` in `reset` and assume enough time has passed until
524        // the next sample is requested.
525
526        // Mark that no conversions are currently in progress
527        self.active_channel = None;
528
529        Ok(converted_value)
530    }
531}
532
533impl<ADCI> crate::private::Sealed for Adc<'_, ADCI, Blocking> {}
534
535impl<ADCI> InterruptConfigurable for Adc<'_, ADCI, Blocking> {
536    fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
537        for core in crate::system::Cpu::other() {
538            crate::interrupt::disable(core, InterruptSource);
539        }
540        unsafe { crate::interrupt::bind_interrupt(InterruptSource, handler.handler()) };
541        unwrap!(crate::interrupt::enable(
542            InterruptSource,
543            handler.priority()
544        ));
545    }
546}
547
548#[cfg(all(adc1, not(esp32h2)))]
549impl super::AdcCalEfuse for crate::peripherals::ADC1 {
550    fn init_code(atten: Attenuation) -> Option<u16> {
551        Efuse::rtc_calib_init_code(1, atten)
552    }
553
554    fn cal_mv(atten: Attenuation) -> u16 {
555        Efuse::rtc_calib_cal_mv(1, atten)
556    }
557
558    fn cal_code(atten: Attenuation) -> Option<u16> {
559        Efuse::rtc_calib_cal_code(1, atten)
560    }
561}
562
563#[cfg(adc2)]
564impl super::AdcCalEfuse for crate::peripherals::ADC2 {
565    fn init_code(atten: Attenuation) -> Option<u16> {
566        Efuse::rtc_calib_init_code(2, atten)
567    }
568
569    fn cal_mv(atten: Attenuation) -> u16 {
570        Efuse::rtc_calib_cal_mv(2, atten)
571    }
572
573    fn cal_code(atten: Attenuation) -> Option<u16> {
574        Efuse::rtc_calib_cal_code(2, atten)
575    }
576}
577
578#[cfg(esp32c2)]
579mod adc_implementation {
580    crate::analog::adc::impl_adc_interface! {
581        ADC1 [
582            (GpioPin<0>, 0),
583            (GpioPin<1>, 1),
584            (GpioPin<2>, 2),
585            (GpioPin<3>, 3),
586            (GpioPin<4>, 4),
587        ]
588    }
589}
590
591#[cfg(esp32c3)]
592mod adc_implementation {
593    crate::analog::adc::impl_adc_interface! {
594        ADC1 [
595            (GpioPin<0>, 0),
596            (GpioPin<1>, 1),
597            (GpioPin<2>, 2),
598            (GpioPin<3>, 3),
599            (GpioPin<4>, 4),
600        ]
601    }
602
603    crate::analog::adc::impl_adc_interface! {
604        ADC2 [
605            (GpioPin<5>, 0),
606        ]
607    }
608}
609
610#[cfg(esp32c6)]
611mod adc_implementation {
612    crate::analog::adc::impl_adc_interface! {
613        ADC1 [
614            (GpioPin<0>, 0),
615            (GpioPin<1>, 1),
616            (GpioPin<2>, 2),
617            (GpioPin<3>, 3),
618            (GpioPin<4>, 4),
619            (GpioPin<5>, 5),
620            (GpioPin<6>, 6),
621        ]
622    }
623}
624
625#[cfg(esp32h2)]
626mod adc_implementation {
627    crate::analog::adc::impl_adc_interface! {
628        ADC1 [
629            (GpioPin<1>, 0),
630            (GpioPin<2>, 1),
631            (GpioPin<3>, 2),
632            (GpioPin<4>, 3),
633            (GpioPin<5>, 4),
634        ]
635    }
636}
637
638impl<'d, ADCI> Adc<'d, ADCI, Async>
639where
640    ADCI: RegisterAccess + 'd,
641{
642    /// Create a new instance in [crate::Blocking] mode.
643    pub fn into_blocking(self) -> Adc<'d, ADCI, Blocking> {
644        if asynch::release_async_adc() {
645            // Disable ADC interrupt on all cores if the last async ADC instance is disabled
646            for cpu in crate::system::Cpu::all() {
647                crate::interrupt::disable(cpu, InterruptSource);
648            }
649        }
650        Adc {
651            _adc: self._adc,
652            attenuations: self.attenuations,
653            active_channel: self.active_channel,
654            _guard: self._guard,
655            _phantom: PhantomData,
656        }
657    }
658
659    /// Request that the ADC begin a conversion on the specified pin
660    ///
661    /// This method takes an [AdcPin](super::AdcPin) reference, as it is
662    /// expected that the ADC will be able to sample whatever channel
663    /// underlies the pin.
664    pub async fn read_oneshot<PIN, CS>(&mut self, pin: &mut super::AdcPin<PIN, ADCI, CS>) -> u16
665    where
666        ADCI: asynch::AsyncAccess,
667        PIN: super::AdcChannel,
668        CS: super::AdcCalScheme<ADCI>,
669    {
670        let channel = PIN::CHANNEL;
671        if self.attenuations[channel as usize].is_none() {
672            panic!("Channel {} is not configured reading!", channel);
673        }
674
675        // Set ADC unit calibration according used scheme for pin
676        ADCI::set_init_code(pin.cal_scheme.adc_cal());
677
678        let attenuation = self.attenuations[channel as usize].unwrap() as u8;
679        ADCI::config_onetime_sample(channel, attenuation);
680        ADCI::start_onetime_sample();
681
682        // Wait for ADC to finish conversion and get value
683        let adc_ready_future = AdcFuture::new(self);
684        adc_ready_future.await;
685        let converted_value = ADCI::read_data();
686
687        // There is a hardware limitation. If the APB clock frequency is high, the step
688        // of this reg signal: ``onetime_start`` may not be captured by the
689        // ADC digital controller (when its clock frequency is too slow). A rough
690        // estimate for this step should be at least 3 ADC digital controller
691        // clock cycle.
692        //
693        // This limitation will be removed in hardware future versions.
694        // We reset ``onetime_start`` in `reset` and assume enough time has passed until
695        // the next sample is requested.
696
697        ADCI::reset();
698
699        // Postprocess converted value according to calibration scheme used for pin
700        pin.cal_scheme.adc_val(converted_value)
701    }
702}
703
704/// Async functionality
705pub(crate) mod asynch {
706    use core::{
707        marker::PhantomData,
708        pin::Pin,
709        task::{Context, Poll},
710    };
711
712    // We only have to count on devices that have multiple ADCs sharing the same interrupt
713    #[cfg(all(adc1, adc2))]
714    use portable_atomic::{AtomicU32, Ordering};
715    use procmacros::handler;
716
717    use crate::{asynch::AtomicWaker, peripherals::APB_SARADC, Async};
718
719    #[cfg(all(adc1, adc2))]
720    static ASYNC_ADC_COUNT: AtomicU32 = AtomicU32::new(0);
721
722    pub(super) fn acquire_async_adc() {
723        #[cfg(all(adc1, adc2))]
724        ASYNC_ADC_COUNT.fetch_add(1, Ordering::Relaxed);
725    }
726
727    pub(super) fn release_async_adc() -> bool {
728        cfg_if::cfg_if! {
729            if #[cfg(all(adc1, adc2))] {
730                ASYNC_ADC_COUNT.fetch_sub(1, Ordering::Relaxed) == 1
731            } else {
732                true
733            }
734        }
735    }
736
737    #[handler]
738    pub(crate) fn adc_interrupt_handler() {
739        let saradc = APB_SARADC::regs();
740        let interrupt_status = saradc.int_st().read();
741
742        #[cfg(adc1)]
743        if interrupt_status.adc1_done().bit_is_set() {
744            handle_async(crate::peripherals::ADC1)
745        }
746
747        #[cfg(adc2)]
748        if interrupt_status.adc2_done().bit_is_set() {
749            handle_async(crate::peripherals::ADC2)
750        }
751    }
752
753    fn handle_async<ADCI: AsyncAccess>(_instance: ADCI) {
754        ADCI::waker().wake();
755        ADCI::disable_interrupt();
756    }
757
758    #[doc(hidden)]
759    pub trait AsyncAccess {
760        /// Enable the ADC interrupt
761        fn enable_interrupt();
762
763        /// Disable the ADC interrupt
764        fn disable_interrupt();
765
766        /// Clear the ADC interrupt
767        fn clear_interrupt();
768
769        /// Obtain the waker for the ADC interrupt
770        fn waker() -> &'static AtomicWaker;
771    }
772
773    #[cfg(adc1)]
774    impl AsyncAccess for crate::peripherals::ADC1 {
775        fn enable_interrupt() {
776            APB_SARADC::regs()
777                .int_ena()
778                .modify(|_, w| w.adc1_done().set_bit());
779        }
780
781        fn disable_interrupt() {
782            APB_SARADC::regs()
783                .int_ena()
784                .modify(|_, w| w.adc1_done().clear_bit());
785        }
786
787        fn clear_interrupt() {
788            APB_SARADC::regs()
789                .int_clr()
790                .write(|w| w.adc1_done().clear_bit_by_one());
791        }
792
793        fn waker() -> &'static AtomicWaker {
794            static WAKER: AtomicWaker = AtomicWaker::new();
795
796            &WAKER
797        }
798    }
799
800    #[cfg(adc2)]
801    impl AsyncAccess for crate::peripherals::ADC2 {
802        fn enable_interrupt() {
803            APB_SARADC::regs()
804                .int_ena()
805                .modify(|_, w| w.adc2_done().set_bit());
806        }
807
808        fn disable_interrupt() {
809            APB_SARADC::regs()
810                .int_ena()
811                .modify(|_, w| w.adc2_done().clear_bit());
812        }
813
814        fn clear_interrupt() {
815            APB_SARADC::regs()
816                .int_clr()
817                .write(|w| w.adc2_done().clear_bit_by_one());
818        }
819
820        fn waker() -> &'static AtomicWaker {
821            static WAKER: AtomicWaker = AtomicWaker::new();
822
823            &WAKER
824        }
825    }
826
827    #[must_use = "futures do nothing unless you `.await` or poll them"]
828    pub(crate) struct AdcFuture<ADCI: AsyncAccess> {
829        phantom: PhantomData<ADCI>,
830    }
831
832    impl<ADCI: AsyncAccess> AdcFuture<ADCI> {
833        pub fn new(_self: &super::Adc<'_, ADCI, Async>) -> Self {
834            Self {
835                phantom: PhantomData,
836            }
837        }
838    }
839
840    impl<ADCI: AsyncAccess + super::RegisterAccess> core::future::Future for AdcFuture<ADCI> {
841        type Output = ();
842
843        fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
844            if ADCI::is_done() {
845                ADCI::clear_interrupt();
846                Poll::Ready(())
847            } else {
848                ADCI::waker().register(cx.waker());
849                ADCI::enable_interrupt();
850                Poll::Pending
851            }
852        }
853    }
854
855    impl<ADCI: AsyncAccess> Drop for AdcFuture<ADCI> {
856        fn drop(&mut self) {
857            ADCI::disable_interrupt();
858        }
859    }
860}