Skip to main content

esp_idf_hal/
adc.rs

1//! Analog to Digital Converter peripheral control.
2
3use core::marker::PhantomData;
4
5use esp_idf_sys::*;
6
7#[cfg(all(
8    not(esp_idf_version_major = "4"),
9    not(esp32c2),
10    esp_idf_comp_esp_adc_enabled
11))]
12#[allow(deprecated)]
13pub use continuous::{
14    config as cont_config, config::Config as AdcContConfig, AdcChannels, AdcChannelsArray,
15    AdcDriver as AdcContDriver, AdcMeasurement, Atten11dB, Atten12dB, Atten2p5dB, Atten6dB,
16    AttenNone, Attenuated, ChainedAdcChannels, EmptyAdcChannels,
17};
18
19#[cfg(any(
20    all(feature = "adc-oneshot-legacy", esp_idf_version_major = "5"),
21    esp_idf_version_major = "4"
22))]
23pub use oneshot_legacy::*;
24
25/// A trait designating the ADC Unit
26///
27/// An associated type provided by ADC peripherals
28pub trait AdcUnit: 'static {
29    /// Return the ESP-IDF ADC unit identifier.
30    fn unit() -> adc_unit_t;
31}
32
33macro_rules! impl_adcu {
34    ($adcu:ident: $unit:expr) => {
35        pub struct $adcu;
36
37        impl AdcUnit for $adcu {
38            fn unit() -> adc_unit_t {
39                $unit
40            }
41        }
42    };
43}
44
45impl_adcu!(ADCU1: adc_unit_t_ADC_UNIT_1);
46#[cfg(any(esp32, esp32s2, esp32s3, esp32c3, esp32p4))]
47impl_adcu!(ADCU2: adc_unit_t_ADC_UNIT_2);
48
49/// A trait designating the ADC channel
50///
51/// An associated type provided by ADC pins
52pub trait AdcChannel: 'static {
53    /// The ADC unit this channel is associated with.
54    type AdcUnit: AdcUnit;
55
56    /// Return the ESP-IDF ADC unit identifier.
57    fn unit() -> adc_unit_t {
58        Self::AdcUnit::unit()
59    }
60
61    /// Return the ESP-IDF ADC channel identifier.
62    fn channel() -> adc_channel_t;
63}
64
65macro_rules! impl_adcch {
66    ($adcch:ident: $unit:expr) => {
67        pub struct $adcch<U: AdcUnit>(PhantomData<U>);
68
69        impl<U: AdcUnit> AdcChannel for $adcch<U> {
70            type AdcUnit = U;
71
72            fn channel() -> adc_channel_t {
73                $unit
74            }
75        }
76    };
77}
78
79impl_adcch!(ADCCH0: adc_channel_t_ADC_CHANNEL_0);
80impl_adcch!(ADCCH1: adc_channel_t_ADC_CHANNEL_1);
81impl_adcch!(ADCCH2: adc_channel_t_ADC_CHANNEL_2);
82impl_adcch!(ADCCH3: adc_channel_t_ADC_CHANNEL_3);
83impl_adcch!(ADCCH4: adc_channel_t_ADC_CHANNEL_4);
84impl_adcch!(ADCCH5: adc_channel_t_ADC_CHANNEL_5);
85impl_adcch!(ADCCH6: adc_channel_t_ADC_CHANNEL_6);
86impl_adcch!(ADCCH7: adc_channel_t_ADC_CHANNEL_7);
87impl_adcch!(ADCCH8: adc_channel_t_ADC_CHANNEL_8);
88impl_adcch!(ADCCH9: adc_channel_t_ADC_CHANNEL_9);
89
90/// A trait for ADC peripherals
91pub trait Adc: Send {
92    /// The ADC unit this peripheral is associated with.
93    type AdcUnit: AdcUnit;
94
95    /// Return the ESP-IDF ADC unit identifier.
96    fn unit() -> adc_unit_t {
97        Self::AdcUnit::unit()
98    }
99}
100
101// NOTE: Will be changed to an enum once C-style enums are usable as const generics
102pub mod attenuation {
103    pub use esp_idf_sys::{
104        adc_atten_t, adc_atten_t_ADC_ATTEN_DB_0, adc_atten_t_ADC_ATTEN_DB_2_5,
105        adc_atten_t_ADC_ATTEN_DB_6,
106    };
107
108    #[cfg(esp_idf_version_at_least_6_0_0)]
109    pub use esp_idf_sys::adc_atten_t_ADC_ATTEN_DB_12;
110    #[cfg(esp_idf_version_at_least_6_0_0)]
111    #[allow(non_upper_case_globals)]
112    pub const adc_atten_t_ADC_ATTEN_DB_11: adc_atten_t = adc_atten_t_ADC_ATTEN_DB_12;
113
114    #[cfg(not(esp_idf_version_at_least_6_0_0))]
115    pub use esp_idf_sys::adc_atten_t_ADC_ATTEN_DB_11;
116    #[cfg(not(esp_idf_version_at_least_6_0_0))]
117    #[allow(non_upper_case_globals)]
118    pub const adc_atten_t_ADC_ATTEN_DB_12: adc_atten_t = adc_atten_t_ADC_ATTEN_DB_11;
119
120    pub const NONE: adc_atten_t = adc_atten_t_ADC_ATTEN_DB_0;
121    pub const DB_2_5: adc_atten_t = adc_atten_t_ADC_ATTEN_DB_2_5;
122    pub const DB_6: adc_atten_t = adc_atten_t_ADC_ATTEN_DB_6;
123    #[deprecated(since = "0.45.3", note = "Use `DB_12` instead")]
124    pub const DB_11: adc_atten_t = adc_atten_t_ADC_ATTEN_DB_11;
125    pub const DB_12: adc_atten_t = adc_atten_t_ADC_ATTEN_DB_12;
126}
127
128/// The sampling/readout resolution of the ADC
129#[derive(Debug, PartialEq, Eq, Clone, Copy)]
130pub enum Resolution {
131    #[cfg(esp32)]
132    Resolution9Bit,
133    #[cfg(esp32)]
134    Resolution10Bit,
135    #[cfg(esp32)]
136    Resolution11Bit,
137    #[cfg(any(
138        esp32, esp32c3, esp32s3, esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61, esp32p4
139    ))]
140    Resolution12Bit,
141    #[cfg(esp32s2)]
142    Resolution13Bit,
143}
144
145impl Resolution {
146    #[cfg(not(esp32s2))]
147    pub const fn new() -> Self {
148        Self::Resolution12Bit
149    }
150
151    #[cfg(esp32s2)]
152    pub const fn new() -> Self {
153        Self::Resolution13Bit
154    }
155}
156
157impl Default for Resolution {
158    fn default() -> Self {
159        Self::new()
160    }
161}
162
163#[cfg(esp_idf_version_at_least_6_0_0)]
164impl From<Resolution> for adc_bitwidth_t {
165    fn from(resolution: Resolution) -> Self {
166        match resolution {
167            #[cfg(esp32)]
168            Resolution::Resolution9Bit => adc_bitwidth_t_ADC_BITWIDTH_9,
169            #[cfg(esp32)]
170            Resolution::Resolution10Bit => adc_bitwidth_t_ADC_BITWIDTH_10,
171            #[cfg(esp32)]
172            Resolution::Resolution11Bit => adc_bitwidth_t_ADC_BITWIDTH_11,
173            #[cfg(any(
174                esp32, esp32s3, esp32c3, esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61,
175                esp32p4
176            ))]
177            Resolution::Resolution12Bit => adc_bitwidth_t_ADC_BITWIDTH_12,
178            #[cfg(esp32s2)]
179            Resolution::Resolution13Bit => adc_bitwidth_t_ADC_BITWIDTH_13,
180        }
181    }
182}
183
184#[cfg(not(esp_idf_version_at_least_6_0_0))]
185impl From<Resolution> for adc_bits_width_t {
186    fn from(resolution: Resolution) -> Self {
187        match resolution {
188            #[cfg(esp32)]
189            Resolution::Resolution9Bit => adc_bits_width_t_ADC_WIDTH_BIT_9,
190            #[cfg(esp32)]
191            Resolution::Resolution10Bit => adc_bits_width_t_ADC_WIDTH_BIT_10,
192            #[cfg(esp32)]
193            Resolution::Resolution11Bit => adc_bits_width_t_ADC_WIDTH_BIT_11,
194            #[cfg(any(
195                esp32, esp32s3, esp32c3, esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61,
196                esp32p4
197            ))]
198            Resolution::Resolution12Bit => adc_bits_width_t_ADC_WIDTH_BIT_12,
199            #[cfg(esp32s2)]
200            Resolution::Resolution13Bit => adc_bits_width_t_ADC_WIDTH_BIT_13,
201        }
202    }
203}
204
205#[cfg(any(
206    all(feature = "adc-oneshot-legacy", esp_idf_version_major = "5"),
207    esp_idf_version_major = "4"
208))]
209mod oneshot_legacy {
210    use core::marker::PhantomData;
211
212    use esp_idf_sys::*;
213
214    use crate::{
215        adc::{AdcChannel, AdcUnit},
216        gpio::ADCPin,
217    };
218
219    use super::{to_nb_err, Adc, DirectConverter};
220
221    pub type AdcConfig = config::Config;
222
223    /// ADC configuration
224    pub mod config {
225        pub use crate::adc::Resolution;
226
227        #[derive(Debug, Copy, Clone, Default)]
228        pub struct Config {
229            pub resolution: Resolution,
230            #[cfg(any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled))]
231            pub calibration: bool,
232        }
233
234        impl Config {
235            pub fn new() -> Self {
236                Default::default()
237            }
238
239            #[must_use]
240            pub fn resolution(mut self, resolution: Resolution) -> Self {
241                self.resolution = resolution;
242                self
243            }
244
245            #[cfg(any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled))]
246            #[must_use]
247            pub fn calibration(mut self, calibration: bool) -> Self {
248                self.calibration = calibration;
249                self
250            }
251        }
252    }
253
254    pub struct AdcChannelDriver<'d, const A: adc_atten_t, C: AdcChannel> {
255        _channel: PhantomData<C>,
256        _t: PhantomData<&'d mut ()>,
257    }
258
259    impl<'d, const A: adc_atten_t, C: AdcChannel> AdcChannelDriver<'d, A, C>
260    where
261        C: AdcChannel,
262    {
263        pub fn new(pin: impl ADCPin<AdcChannel = C> + 'd) -> Result<Self, EspError> {
264            unsafe {
265                crate::gpio::rtc_reset_pin(pin.pin() as _)?;
266            }
267
268            if C::unit() == adc_unit_t_ADC_UNIT_1 {
269                esp!(unsafe { adc1_config_channel_atten(C::channel(), A) })?;
270            } else {
271                #[cfg(not(any(esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61, esp32p4)))]
272                esp!(unsafe { adc2_config_channel_atten(C::channel(), A) })?;
273
274                #[cfg(any(esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61, esp32p4))]
275                unreachable!();
276            }
277
278            Ok(Self {
279                _channel: PhantomData,
280                _t: PhantomData,
281            })
282        }
283    }
284
285    impl<const A: adc_atten_t, C: AdcChannel> embedded_hal_0_2::adc::Channel<C::AdcUnit>
286        for AdcChannelDriver<'_, A, C>
287    {
288        type ID = (adc_channel_t, adc_atten_t);
289
290        fn channel() -> Self::ID {
291            (C::channel(), A)
292        }
293    }
294
295    pub struct AdcDriver<'d, ADCU: AdcUnit> {
296        #[allow(dead_code)]
297        resolution: config::Resolution,
298        #[cfg(all(
299            any(esp32, esp32s2, esp32s3, esp32c3),
300            any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
301        ))]
302        cal_characteristics: Option<
303            [Option<esp_adc_cal_characteristics_t>; adc_atten_t_ADC_ATTEN_DB_11 as usize + 1],
304        >,
305        _unit: PhantomData<ADCU>,
306        _t: PhantomData<&'d mut ()>,
307    }
308
309    unsafe impl<ADCU: AdcUnit> Send for AdcDriver<'_, ADCU> {}
310
311    impl<'d, ADCU: AdcUnit> AdcDriver<'d, ADCU> {
312        #[cfg(all(
313            esp32,
314            any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
315        ))]
316        const CALIBRATION_SCHEME: esp_adc_cal_value_t =
317            esp_adc_cal_value_t_ESP_ADC_CAL_VAL_EFUSE_VREF;
318
319        #[cfg(all(
320            any(esp32c3, esp32s2),
321            any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
322        ))]
323        const CALIBRATION_SCHEME: esp_adc_cal_value_t =
324            esp_adc_cal_value_t_ESP_ADC_CAL_VAL_EFUSE_TP;
325
326        #[cfg(all(
327            esp32s3,
328            any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
329        ))]
330        const CALIBRATION_SCHEME: esp_adc_cal_value_t =
331            esp_adc_cal_value_t_ESP_ADC_CAL_VAL_EFUSE_TP_FIT;
332
333        pub fn new<ADC: Adc<AdcUnit = ADCU> + 'd>(
334            _adc: ADC,
335            config: &config::Config,
336        ) -> Result<Self, EspError> {
337            #[cfg(all(
338                any(esp32, esp32s2, esp32s3, esp32c3),
339                any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
340            ))]
341            if config.calibration {
342                esp!(unsafe { esp_adc_cal_check_efuse(Self::CALIBRATION_SCHEME) })?;
343            }
344
345            if ADC::unit() == adc_unit_t_ADC_UNIT_1 {
346                esp!(unsafe { adc1_config_width(config.resolution.into()) })?;
347            }
348
349            Ok(Self {
350                resolution: config.resolution,
351                #[cfg(all(
352                    any(esp32, esp32s2, esp32s3, esp32c3),
353                    any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
354                ))]
355                cal_characteristics: if config.calibration {
356                    Some(Default::default())
357                } else {
358                    None
359                },
360                _unit: PhantomData,
361                _t: PhantomData,
362            })
363        }
364
365        #[inline(always)]
366        pub fn read<const A: adc_atten_t, C: AdcChannel<AdcUnit = ADCU>>(
367            &mut self,
368            _pin: &mut AdcChannelDriver<'_, A, C>,
369        ) -> Result<u16, EspError> {
370            self.read_internal(C::unit(), C::channel(), A)
371        }
372
373        #[inline(always)]
374        pub fn read_raw<const A: adc_atten_t, C: AdcChannel<AdcUnit = ADCU>>(
375            &mut self,
376            _pin: &mut AdcChannelDriver<'_, A, C>,
377        ) -> Result<u16, EspError> {
378            self.read_internal_raw(C::unit(), C::channel())
379        }
380
381        #[inline(always)]
382        fn read_internal(
383            &mut self,
384            unit: adc_unit_t,
385            channel: adc_channel_t,
386            atten: adc_atten_t,
387        ) -> Result<u16, EspError> {
388            let measurement = self.read_internal_raw(unit, channel)?;
389            self.raw_to_voltage(measurement, atten)
390        }
391
392        #[inline(always)]
393        fn read_internal_raw(
394            &mut self,
395            unit: adc_unit_t,
396            channel: adc_channel_t,
397        ) -> Result<u16, EspError> {
398            if unit == adc_unit_t_ADC_UNIT_1 {
399                Ok(unsafe { adc1_get_raw(channel) } as _)
400            } else {
401                #[cfg(not(any(esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61, esp32p4)))]
402                {
403                    let mut measurement = 0;
404                    esp!(unsafe {
405                        adc2_get_raw(channel, self.resolution.into(), &mut measurement)
406                    })?;
407
408                    Ok(measurement as _)
409                }
410
411                #[cfg(any(esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61, esp32p4))]
412                unreachable!();
413            }
414        }
415
416        #[inline(always)]
417        fn raw_to_voltage(
418            &mut self,
419            measurement: u16,
420            attenuation: adc_atten_t,
421        ) -> Result<u16, EspError> {
422            #[cfg(all(
423                any(esp32, esp32s2, esp32s3, esp32c3),
424                any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
425            ))]
426            let mv = if let Some(cal) = self.get_cal_characteristics(attenuation)? {
427                unsafe { esp_adc_cal_raw_to_voltage(measurement as u32, &cal) as u16 }
428            } else {
429                DirectConverter(attenuation).raw_to_mv(measurement)
430            };
431
432            #[cfg(not(all(
433                any(esp32, esp32s2, esp32s3, esp32c3),
434                any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
435            )))]
436            let mv = DirectConverter(attenuation).raw_to_mv(measurement);
437
438            Ok(mv)
439        }
440
441        #[cfg(all(
442            any(esp32, esp32s2, esp32s3, esp32c3),
443            any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled)
444        ))]
445        fn get_cal_characteristics(
446            &mut self,
447            attenuation: adc_atten_t,
448        ) -> Result<Option<esp_adc_cal_characteristics_t>, EspError> {
449            if let Some(characteristics) = &mut self.cal_characteristics {
450                if let Some(cal) = characteristics[attenuation as usize] {
451                    Ok(Some(cal))
452                } else {
453                    esp!(unsafe { esp_adc_cal_check_efuse(Self::CALIBRATION_SCHEME) })?;
454
455                    let mut cal: esp_adc_cal_characteristics_t = Default::default();
456                    unsafe {
457                        esp_adc_cal_characterize(
458                            ADCU::unit(),
459                            attenuation,
460                            self.resolution.into(),
461                            0,
462                            &mut cal,
463                        )
464                    };
465
466                    characteristics[attenuation as usize] = Some(cal);
467
468                    Ok(Some(cal))
469                }
470            } else {
471                Ok(None)
472            }
473        }
474    }
475
476    impl<'c, const A: adc_atten_t, C>
477        embedded_hal_0_2::adc::OneShot<C::AdcUnit, u16, AdcChannelDriver<'c, A, C>>
478        for AdcDriver<'_, C::AdcUnit>
479    where
480        C: AdcChannel,
481    {
482        type Error = EspError;
483
484        fn read(&mut self, _pin: &mut AdcChannelDriver<'c, A, C>) -> nb::Result<u16, Self::Error> {
485            self.read_internal(C::unit(), C::channel(), A)
486                .map_err(to_nb_err)
487        }
488    }
489}
490
491fn to_nb_err(err: EspError) -> nb::Error<EspError> {
492    if err.code() == ESP_ERR_INVALID_STATE {
493        nb::Error::WouldBlock
494    } else {
495        nb::Error::Other(err)
496    }
497}
498
499macro_rules! impl_adc {
500    ($adc:ident: $unit:ident) => {
501        crate::impl_peripheral!($adc);
502
503        impl Adc for $adc<'_> {
504            type AdcUnit = $unit;
505        }
506    };
507}
508
509impl_adc!(ADC1: ADCU1);
510#[cfg(not(any(esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61)))] // TODO: Check for esp32c5
511impl_adc!(ADC2: ADCU2);
512
513/// Converts a raw reading to mV without using calibration
514struct DirectConverter(adc_atten_t);
515
516impl DirectConverter {
517    #[cfg(not(esp32s2))]
518    const MAX_READING: u32 = 4095;
519
520    #[cfg(esp32s2)]
521    const MAX_READING: u32 = 8191;
522
523    fn raw_to_mv(&self, raw: u16) -> u16 {
524        (raw as u32 * self.get_max_mv() as u32 / Self::MAX_READING) as u16
525    }
526
527    #[inline(always)]
528    #[allow(non_upper_case_globals)]
529    fn get_max_mv(&self) -> u16 {
530        let attenuation = self.0;
531
532        #[cfg(esp32)]
533        let mv = match attenuation {
534            attenuation::NONE => 950,
535            attenuation::DB_2_5 => 1250,
536            attenuation::DB_6 => 1750,
537            attenuation::DB_12 => 2450,
538            other => panic!("Unknown attenuation: {other}"),
539        };
540
541        #[cfg(any(
542            esp32c3, esp32s2, esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61, esp32p4
543        ))]
544        let mv = match attenuation {
545            attenuation::NONE => 750,
546            attenuation::DB_2_5 => 1050,
547            attenuation::DB_6 => 1300,
548            attenuation::DB_12 => 2500,
549            other => panic!("Unknown attenuation: {other}"),
550        };
551
552        #[cfg(esp32s3)]
553        let mv = match attenuation {
554            attenuation::NONE => 950,
555            attenuation::DB_2_5 => 1250,
556            attenuation::DB_6 => 1750,
557            attenuation::DB_12 => 3100,
558            other => panic!("Unknown attenuation: {other}"),
559        };
560
561        mv
562    }
563}
564
565/// One-shot ADC module
566/// Example: reading a value form a pin and printing it on the terminal
567/// ```
568/// use std::thread;
569/// use std::time::Duration;
570///
571/// fn main() -> anyhow::Result<()> {
572///     use esp_idf_hal::adc::attenuation::DB_12;
573///     use esp_idf_hal::adc::oneshot::config::AdcChannelConfig;
574///     use esp_idf_hal::adc::oneshot::*;
575///     use esp_idf_hal::peripherals::Peripherals;
576///
577///     let peripherals = Peripherals::take()?;
578///     let adc = AdcDriver::new(peripherals.adc1)?;
579///
580///     /// configuring pin to analog read, you can regulate the adc input voltage range depending on your need
581///     /// for this example we use the attenuation of 11db which sets the input voltage range to around 0-3.6V
582///     let config = AdcChannelConfig {
583///         attenuation: DB_12,
584///         ..Default::default()
585///     };
586///     let mut adc_pin = AdcChannelDriver::new(&adc, peripherals.pins.gpio2, &config)?;
587///
588///     loop {
589///         /// you can change the sleep duration depending on how often you want to sample
590///         thread::sleep(Duration::from_millis(100));
591///         println!("ADC value: {}", adc.read(&mut adc_pin)?);
592///     }
593/// }
594/// ```
595#[cfg(all(
596    not(all(feature = "adc-oneshot-legacy", esp_idf_version_major = "5")),
597    not(esp_idf_version_major = "4"),
598    esp_idf_comp_esp_adc_enabled
599))]
600pub mod oneshot {
601    use core::borrow::Borrow;
602    use core::marker::PhantomData;
603
604    use esp_idf_sys::*;
605
606    use crate::adc::to_nb_err;
607    use crate::adc::AdcChannel;
608    use crate::gpio::ADCPin;
609
610    use super::attenuation::adc_atten_t;
611    use super::Adc;
612    use super::AdcUnit;
613    use super::DirectConverter;
614
615    pub mod config {
616        use super::adc_atten_t;
617
618        pub use crate::adc::Resolution;
619
620        #[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
621        pub enum Calibration {
622            #[default]
623            None,
624            #[cfg(all(
625                any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
626                any(
627                    esp32c3,
628                    all(
629                        esp32c6,
630                        not(all(esp_idf_version_major = "5", esp_idf_version_minor = "0")),
631                        not(esp_idf_version_full = "5.1.0")
632                    ),
633                    esp32s3,
634                )
635            ))]
636            Curve,
637            #[cfg(all(
638                any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
639                any(esp32, esp32c2, esp32s2)
640            ))]
641            Line,
642        }
643
644        #[derive(Debug, Copy, Clone, Default)]
645        pub struct AdcChannelConfig {
646            pub attenuation: adc_atten_t,
647            pub resolution: Resolution,
648            pub calibration: Calibration,
649        }
650
651        impl AdcChannelConfig {
652            pub const fn new() -> Self {
653                Self {
654                    attenuation: crate::adc::attenuation::NONE,
655                    resolution: Resolution::new(),
656                    calibration: Calibration::None,
657                }
658            }
659        }
660    }
661
662    /// Converts a raw reading to mV with or without calibration
663    enum Converter {
664        NoCalibration(adc_atten_t),
665        #[cfg(all(
666            any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
667            any(
668                esp32c3,
669                all(
670                    esp32c6,
671                    not(all(esp_idf_version_major = "5", esp_idf_version_minor = "0")),
672                    not(esp_idf_version_full = "5.1.0")
673                ),
674                esp32s3,
675            )
676        ))]
677        CurveFittingCalibration(adc_cali_handle_t),
678        #[cfg(all(
679            any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
680            any(esp32, esp32c2, esp32s2)
681        ))]
682        LineFittingCalibration(adc_cali_handle_t),
683    }
684
685    impl Converter {
686        #[allow(unused_variables)]
687        fn create(
688            unit: adc_unit_t,
689            chan: adc_channel_t,
690            atten: adc_atten_t,
691            #[cfg(esp_idf_version_at_least_6_0_0)] bitwidth: adc_bitwidth_t,
692            #[cfg(not(esp_idf_version_at_least_6_0_0))] bitwidth: adc_bits_width_t,
693            calibration: config::Calibration,
694        ) -> Result<Self, EspError> {
695            match calibration {
696                config::Calibration::None => Ok(Self::NoCalibration(atten)),
697                #[cfg(all(
698                    any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
699                    any(
700                        esp32c3,
701                        all(
702                            esp32c6,
703                            not(all(esp_idf_version_major = "5", esp_idf_version_minor = "0")),
704                            not(esp_idf_version_full = "5.1.0")
705                        ),
706                        esp32s3,
707                    )
708                ))]
709                config::Calibration::Curve => {
710                    // it would be nice if esp-idf-sys could export some cfg values to replicate these two defines
711                    // from esp-idf:
712                    // ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
713                    // ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
714                    // then we wouuld not need the ugliness for the esp32c6
715                    let cal_config = adc_cali_curve_fitting_config_t {
716                        unit_id: unit,
717                        #[cfg(esp_idf_version_at_least_5_1_1)]
718                        chan,
719                        atten,
720                        bitwidth,
721                    };
722                    let mut cal_handle: adc_cali_handle_t = core::ptr::null_mut();
723                    esp!(unsafe {
724                        esp_idf_sys::adc_cali_create_scheme_curve_fitting(
725                            &cal_config,
726                            &mut cal_handle,
727                        )
728                    })?;
729
730                    Ok(Self::CurveFittingCalibration(cal_handle))
731                }
732                #[cfg(all(
733                    any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
734                    any(esp32, esp32c2, esp32s2)
735                ))]
736                config::Calibration::Line => {
737                    // esp32 has an additional field that the exanple defaults
738                    // to using fuse values for vref. Maybe we should expose
739                    // this as a config option?
740                    #[allow(clippy::needless_update)]
741                    let cal_config = adc_cali_line_fitting_config_t {
742                        unit_id: unit,
743                        atten,
744                        bitwidth,
745                        ..Default::default()
746                    };
747                    let mut cal_handle: adc_cali_handle_t = core::ptr::null_mut();
748                    esp!(unsafe {
749                        esp_idf_sys::adc_cali_create_scheme_line_fitting(
750                            &cal_config,
751                            &mut cal_handle,
752                        )
753                    })?;
754
755                    Ok(Self::LineFittingCalibration(cal_handle))
756                }
757            }
758        }
759
760        fn raw_to_mv(&self, raw: u16) -> Result<u16, EspError> {
761            match self {
762                Self::NoCalibration(atten) => Ok(DirectConverter(*atten).raw_to_mv(raw)),
763                #[cfg(all(
764                    any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
765                    any(
766                        esp32c3,
767                        all(
768                            esp32c6,
769                            not(all(esp_idf_version_major = "5", esp_idf_version_minor = "0")),
770                            not(esp_idf_version_full = "5.1.0")
771                        ),
772                        esp32s3,
773                    )
774                ))]
775                Self::CurveFittingCalibration(handle) => {
776                    let mut mv = 0i32;
777                    esp!(unsafe { adc_cali_raw_to_voltage(*handle, raw as i32, &mut mv) })?;
778
779                    Ok(mv as u16)
780                }
781                #[cfg(all(
782                    any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
783                    any(esp32, esp32c2, esp32s2)
784                ))]
785                Self::LineFittingCalibration(handle) => {
786                    let mut mv = 0i32;
787                    esp!(unsafe { adc_cali_raw_to_voltage(*handle, raw as i32, &mut mv) })?;
788
789                    Ok(mv as u16)
790                }
791            }
792        }
793    }
794
795    impl Drop for Converter {
796        fn drop(&mut self) {
797            match self {
798                Self::NoCalibration(_) => (),
799                #[cfg(all(
800                    any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
801                    any(
802                        esp32c3,
803                        all(
804                            esp32c6,
805                            not(all(esp_idf_version_major = "5", esp_idf_version_minor = "0")),
806                            not(esp_idf_version_full = "5.1.0")
807                        ),
808                        esp32s3,
809                    )
810                ))]
811                Self::CurveFittingCalibration(handle) => {
812                    esp!(unsafe { esp_idf_sys::adc_cali_delete_scheme_curve_fitting(*handle) })
813                        .unwrap()
814                }
815                #[cfg(all(
816                    any(esp_idf_comp_esp_adc_cal_enabled, esp_idf_comp_esp_adc_enabled),
817                    any(esp32, esp32c2, esp32s2)
818                ))]
819                Self::LineFittingCalibration(handle) => {
820                    esp!(unsafe { esp_idf_sys::adc_cali_delete_scheme_line_fitting(*handle) })
821                        .unwrap()
822                }
823            }
824        }
825    }
826
827    pub struct AdcChannelDriver<'d, C, M>
828    where
829        C: AdcChannel,
830        M: Borrow<AdcDriver<'d, C::AdcUnit>>,
831    {
832        adc: M,
833        _channel: PhantomData<C>,
834        converter: Converter,
835        _t: PhantomData<&'d mut ()>,
836    }
837
838    impl<'d, C, M> AdcChannelDriver<'d, C, M>
839    where
840        C: AdcChannel,
841        M: Borrow<AdcDriver<'d, C::AdcUnit>>,
842    {
843        pub fn new(
844            adc: M,
845            pin: impl ADCPin<AdcChannel = C> + 'd,
846            config: &config::AdcChannelConfig,
847        ) -> Result<Self, EspError> {
848            unsafe {
849                crate::gpio::rtc_reset_pin(pin.pin() as _)?;
850            }
851
852            let chan_config = adc_oneshot_chan_cfg_t {
853                atten: config.attenuation,
854                bitwidth: config.resolution.into(),
855            };
856
857            let converter = Converter::create(
858                C::unit(),
859                C::channel(),
860                config.attenuation,
861                config.resolution.into(),
862                config.calibration,
863            )?;
864
865            unsafe {
866                esp!(adc_oneshot_config_channel(
867                    adc.borrow().handle,
868                    C::channel(),
869                    &chan_config
870                ))?
871            };
872
873            Ok(Self {
874                adc,
875                _channel: PhantomData,
876                converter,
877                _t: PhantomData,
878            })
879        }
880
881        #[inline(always)]
882        pub fn read(&mut self) -> Result<u16, EspError> {
883            let raw = self.read_raw()?;
884            self.raw_to_mv(raw)
885        }
886
887        #[inline(always)]
888        pub fn read_raw(&mut self) -> Result<u16, EspError> {
889            let channel = C::channel();
890            self.adc.borrow().read_raw_internal(channel)
891        }
892
893        #[inline(always)]
894        pub fn raw_to_mv(&self, raw: u16) -> Result<u16, EspError> {
895            self.converter.raw_to_mv(raw)
896        }
897    }
898
899    impl<'d, C, M> embedded_hal_0_2::adc::Channel<C::AdcUnit> for AdcChannelDriver<'d, C, M>
900    where
901        C: AdcChannel,
902        M: Borrow<AdcDriver<'d, C::AdcUnit>>,
903    {
904        type ID = adc_channel_t;
905
906        fn channel() -> Self::ID {
907            C::channel()
908        }
909    }
910
911    unsafe impl<'d, C, M> Send for AdcChannelDriver<'d, C, M>
912    where
913        C: AdcChannel,
914        M: Borrow<AdcDriver<'d, C::AdcUnit>>,
915    {
916    }
917
918    pub struct AdcDriver<'d, U> {
919        handle: adc_oneshot_unit_handle_t,
920        _unit: PhantomData<U>,
921        _t: PhantomData<&'d mut ()>,
922    }
923
924    impl<'d, U> AdcDriver<'d, U>
925    where
926        U: AdcUnit + 'd,
927    {
928        pub fn new<ADC: Adc<AdcUnit = U> + 'd>(_adc: ADC) -> Result<Self, EspError> {
929            let config = adc_oneshot_unit_init_cfg_t {
930                unit_id: ADC::unit(),
931                ..Default::default()
932            };
933            let mut handle: adc_oneshot_unit_handle_t = core::ptr::null_mut();
934            unsafe { esp!(adc_oneshot_new_unit(&config, &mut handle))? };
935            Ok(Self {
936                handle,
937                _unit: PhantomData,
938                _t: PhantomData,
939            })
940        }
941
942        #[inline(always)]
943        pub fn read<C, M>(&self, channel: &mut AdcChannelDriver<'d, C, M>) -> Result<u16, EspError>
944        where
945            C: AdcChannel<AdcUnit = U>,
946            M: Borrow<AdcDriver<'d, U>>,
947        {
948            let raw = self.read_raw(channel)?;
949            self.raw_to_mv(channel, raw)
950        }
951
952        #[inline(always)]
953        pub fn read_raw<C, M>(
954            &self,
955            _channel: &mut AdcChannelDriver<'d, C, M>,
956        ) -> Result<u16, EspError>
957        where
958            C: AdcChannel<AdcUnit = U>,
959            M: Borrow<AdcDriver<'d, U>>,
960        {
961            self.read_raw_internal(C::channel())
962        }
963
964        #[inline(always)]
965        fn read_raw_internal(&self, channel: adc_channel_t) -> Result<u16, EspError> {
966            let mut measurement = 0;
967            unsafe { esp!(adc_oneshot_read(self.handle, channel, &mut measurement)) }?;
968            Ok(measurement as u16)
969        }
970
971        #[inline(always)]
972        pub fn raw_to_mv<C, M>(
973            &self,
974            channel: &AdcChannelDriver<'d, C, M>,
975            raw: u16,
976        ) -> Result<u16, EspError>
977        where
978            C: AdcChannel<AdcUnit = U>,
979            M: Borrow<AdcDriver<'d, U>>,
980        {
981            channel.converter.raw_to_mv(raw)
982        }
983    }
984
985    impl<U> Drop for AdcDriver<'_, U> {
986        fn drop(&mut self) {
987            unsafe { esp!(adc_oneshot_del_unit(self.handle)) }.unwrap();
988        }
989    }
990
991    impl<'d, C, M> embedded_hal_0_2::adc::OneShot<C::AdcUnit, u16, AdcChannelDriver<'d, C, M>>
992        for AdcDriver<'d, C::AdcUnit>
993    where
994        C: AdcChannel,
995        M: Borrow<AdcDriver<'d, C::AdcUnit>>,
996    {
997        type Error = EspError;
998
999        fn read(&mut self, pin: &mut AdcChannelDriver<'d, C, M>) -> nb::Result<u16, Self::Error> {
1000            AdcDriver::read(self, pin).map_err(to_nb_err)
1001        }
1002    }
1003
1004    unsafe impl<U: AdcUnit> Send for AdcDriver<'_, U> {}
1005    unsafe impl<U: AdcUnit> Sync for AdcDriver<'_, U> {}
1006}
1007
1008/// Continuous ADC module
1009/// Example: continuously reading value from a pin
1010/// ```
1011/// use ::log::{info, debug};
1012///
1013/// fn main() -> anyhow::Result<()> {
1014///     use esp_idf_svc::hal::adc::{AdcContConfig, AdcContDriver, AdcMeasurement, Attenuated};
1015///     use esp_idf_svc::hal::modem::Modem;
1016///     use esp_idf_svc::hal::peripherals::Peripherals;
1017///     use esp_idf_svc::sys::EspError;
1018///
1019///     esp_idf_svc::sys::link_patches();
1020///     esp_idf_svc::log::EspLogger::initialize_default();
1021///
1022///     let peripherals = Peripherals::take()?;
1023///     let config = AdcContConfig::default();
1024///
1025///     let adc_1_channel_0 = Attenuated::db12(peripherals.pins.gpio0);
1026///     let mut adc = AdcContDriver::new(peripherals.adc1, &config, adc_1_channel_0)?;
1027///
1028///     adc.start()?;
1029///
1030///     /// Default to just read 100 measurements per each read
1031///     let mut samples = [AdcMeasurement::default(); 100];
1032///
1033///     loop {
1034///         if let Ok(num_read) = adc.read(&mut samples, 10) {
1035///             debug!("Read {} measurement.", num_read);
1036///             for index in 0..num_read {
1037///                 debug!("{}", samples[index].data());
1038///             }
1039///         }
1040///     }
1041/// }
1042/// ```
1043#[cfg(all(
1044    not(esp_idf_version_major = "4"),
1045    not(esp32c2),
1046    esp_idf_comp_esp_adc_enabled
1047))]
1048pub mod continuous {
1049    use core::ffi::c_void;
1050    use core::fmt::{self, Debug, Display};
1051    use core::marker::PhantomData;
1052
1053    use esp_idf_sys::*;
1054
1055    use crate::adc::AdcChannel;
1056    use crate::delay::{self, TickType};
1057    use crate::gpio::ADCPin;
1058    use crate::interrupt::asynch::HalIsrNotification;
1059    use crate::io::EspIOError;
1060
1061    use super::{attenuation, Adc, AdcUnit};
1062
1063    /// Set ADC attenuation level
1064    /// Example: let pin = Attenuated::db12(peripherals.pins.gpio0);
1065    pub struct Attenuated<const A: adc_atten_t, T>(T);
1066
1067    impl<T> Attenuated<{ attenuation::NONE }, T> {
1068        pub const fn none(t: T) -> Self {
1069            Self(t)
1070        }
1071    }
1072
1073    impl<T> Attenuated<{ attenuation::DB_2_5 }, T> {
1074        pub const fn db2_5(t: T) -> Self {
1075            Self(t)
1076        }
1077    }
1078
1079    impl<T> Attenuated<{ attenuation::DB_6 }, T> {
1080        pub const fn db6(t: T) -> Self {
1081            Self(t)
1082        }
1083    }
1084
1085    #[allow(deprecated)]
1086    impl<T> Attenuated<{ attenuation::DB_11 }, T> {
1087        #[cfg_attr(
1088            not(esp_idf_version_major = "4"),
1089            deprecated(since = "0.45.3", note = "Use `Attenuated::db12` instead")
1090        )]
1091        pub const fn db11(t: T) -> Self {
1092            Self(t)
1093        }
1094    }
1095
1096    #[cfg(not(esp_idf_version_major = "4"))]
1097    impl<T> Attenuated<{ attenuation::DB_12 }, T> {
1098        pub const fn db12(t: T) -> Self {
1099            Self(t)
1100        }
1101    }
1102
1103    impl<const A: adc_atten_t, T> Attenuated<A, T> {
1104        pub fn atten(channel: (adc_channel_t, adc_atten_t)) -> (adc_channel_t, adc_atten_t) {
1105            (channel.0, A)
1106        }
1107    }
1108
1109    pub type AttenNone<T> = Attenuated<{ attenuation::NONE }, T>;
1110    pub type Atten2p5dB<T> = Attenuated<{ attenuation::DB_2_5 }, T>;
1111    pub type Atten6dB<T> = Attenuated<{ attenuation::DB_6 }, T>;
1112    #[deprecated(since = "0.45.3", note = "Use `Atten12dB` instead")]
1113    #[allow(deprecated)]
1114    pub type Atten11dB<T> = Attenuated<{ attenuation::DB_11 }, T>;
1115    pub type Atten12dB<T> = Attenuated<{ attenuation::DB_12 }, T>;
1116
1117    pub trait AdcChannels {
1118        type AdcUnit: AdcUnit;
1119
1120        type Iterator<'a>: Iterator<Item = (adc_channel_t, adc_atten_t)>
1121        where
1122            Self: 'a;
1123
1124        fn iter(&self) -> Self::Iterator<'_>;
1125    }
1126
1127    impl<P> AdcChannels for P
1128    where
1129        P: ADCPin,
1130    {
1131        type AdcUnit = <P::AdcChannel as AdcChannel>::AdcUnit;
1132
1133        type Iterator<'a>
1134            = core::iter::Once<(adc_channel_t, adc_atten_t)>
1135        where
1136            Self: 'a;
1137
1138        fn iter(&self) -> Self::Iterator<'_> {
1139            core::iter::once((P::AdcChannel::channel(), attenuation::NONE))
1140        }
1141    }
1142
1143    impl<const A: adc_atten_t, C> AdcChannels for Attenuated<A, C>
1144    where
1145        C: AdcChannels,
1146    {
1147        type AdcUnit = C::AdcUnit;
1148
1149        type Iterator<'a>
1150            = core::iter::Map<
1151            C::Iterator<'a>,
1152            fn((adc_channel_t, adc_atten_t)) -> (adc_channel_t, adc_atten_t),
1153        >
1154        where
1155            Self: 'a;
1156
1157        fn iter(&self) -> Self::Iterator<'_> {
1158            self.0.iter().map(Attenuated::<A, C>::atten)
1159        }
1160    }
1161
1162    pub struct AdcChannelsArray<C, const N: usize>(pub [C; N]);
1163
1164    impl<C, const N: usize> AdcChannels for AdcChannelsArray<C, N>
1165    where
1166        C: AdcChannels,
1167    {
1168        type AdcUnit = C::AdcUnit;
1169
1170        type Iterator<'a>
1171            = core::iter::FlatMap<
1172            core::slice::Iter<'a, C>,
1173            <C as AdcChannels>::Iterator<'a>,
1174            fn(&'a C) -> C::Iterator<'a>,
1175        >
1176        where
1177            Self: 'a;
1178
1179        fn iter(&self) -> Self::Iterator<'_> {
1180            self.0.iter().flat_map(AdcChannels::iter)
1181        }
1182    }
1183
1184    pub struct EmptyAdcChannels<A>(PhantomData<A>);
1185
1186    impl<A> EmptyAdcChannels<A> {
1187        pub fn chain<O>(other: O) -> ChainedAdcChannels<Self, O>
1188        where
1189            A: Adc,
1190            O: AdcChannels<AdcUnit = A>,
1191        {
1192            ChainedAdcChannels {
1193                first: Self(PhantomData),
1194                second: other,
1195            }
1196        }
1197    }
1198
1199    impl<A> AdcChannels for EmptyAdcChannels<A>
1200    where
1201        A: AdcUnit,
1202    {
1203        type AdcUnit = A;
1204
1205        type Iterator<'a>
1206            = core::iter::Empty<(adc_channel_t, adc_atten_t)>
1207        where
1208            Self: 'a;
1209
1210        fn iter(&self) -> Self::Iterator<'_> {
1211            core::iter::empty()
1212        }
1213    }
1214
1215    pub struct ChainedAdcChannels<F, S> {
1216        first: F,
1217        second: S,
1218    }
1219
1220    impl<F, S> ChainedAdcChannels<F, S> {
1221        pub fn chain<O>(self, other: O) -> ChainedAdcChannels<Self, O>
1222        where
1223            F: AdcChannels,
1224            S: AdcChannels<AdcUnit = F::AdcUnit>,
1225            O: AdcChannels<AdcUnit = F::AdcUnit>,
1226        {
1227            ChainedAdcChannels {
1228                first: self,
1229                second: other,
1230            }
1231        }
1232    }
1233
1234    impl<F, S> AdcChannels for ChainedAdcChannels<F, S>
1235    where
1236        F: AdcChannels,
1237        S: AdcChannels<AdcUnit = F::AdcUnit>,
1238    {
1239        type AdcUnit = F::AdcUnit;
1240
1241        type Iterator<'a>
1242            = core::iter::Chain<F::Iterator<'a>, S::Iterator<'a>>
1243        where
1244            Self: 'a;
1245
1246        fn iter(&self) -> Self::Iterator<'_> {
1247            self.first.iter().chain(self.second.iter())
1248        }
1249    }
1250
1251    #[derive(Copy, Clone)]
1252    #[repr(transparent)]
1253    pub struct AdcMeasurement(adc_digi_output_data_t);
1254
1255    impl Default for AdcMeasurement {
1256        fn default() -> Self {
1257            Self::new()
1258        }
1259    }
1260
1261    impl AdcMeasurement {
1262        pub const INIT: Self = AdcMeasurement(unsafe {
1263            core::mem::transmute::<
1264                [u8; core::mem::size_of::<adc_digi_output_data_t>()],
1265                adc_digi_output_data_t,
1266            >([0u8; core::mem::size_of::<adc_digi_output_data_t>()])
1267        });
1268
1269        pub const fn new() -> Self {
1270            Self::INIT
1271        }
1272
1273        #[cfg(any(esp32, esp32s2))]
1274        pub fn data(&self) -> u16 {
1275            unsafe { self.0.__bindgen_anon_1.type1.data() as _ }
1276        }
1277
1278        #[cfg(any(esp32, esp32s2))]
1279        pub fn channel(&self) -> adc_channel_t {
1280            unsafe { self.0.__bindgen_anon_1.type1.channel() as _ }
1281        }
1282
1283        #[cfg(not(any(esp32, esp32s2)))]
1284        pub fn data(&self) -> u16 {
1285            unsafe { self.0.__bindgen_anon_1.type2.data() as _ }
1286        }
1287
1288        #[cfg(not(any(esp32, esp32s2)))]
1289        pub fn channel(&self) -> adc_channel_t {
1290            unsafe { self.0.__bindgen_anon_1.type2.channel() as _ }
1291        }
1292
1293        #[cfg(not(any(esp32, esp32s2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61)))]
1294        pub fn unit(&self) -> adc_unit_t {
1295            unsafe { self.0.__bindgen_anon_1.type2.unit() as _ }
1296        }
1297
1298        #[cfg(any(esp32, esp32s2))]
1299        pub fn nullify(&mut self) {
1300            self.0.__bindgen_anon_1.val = self.data();
1301        }
1302
1303        #[cfg(not(any(esp32, esp32s2)))]
1304        pub fn nullify(&mut self) {
1305            self.0.__bindgen_anon_1.val = self.data() as _;
1306        }
1307
1308        #[cfg(any(esp32, esp32s2))]
1309        pub fn as_pcm16(data: &mut [AdcMeasurement]) -> &mut [u16] {
1310            for measurement in data.iter_mut() {
1311                measurement.nullify();
1312            }
1313
1314            unsafe { core::slice::from_raw_parts_mut(data.as_mut_ptr() as *mut _, data.len()) }
1315        }
1316
1317        #[cfg(not(any(esp32, esp32s2)))]
1318        pub fn as_pcm32(data: &mut [AdcMeasurement]) -> &mut [u32] {
1319            for measurement in data.iter_mut() {
1320                measurement.nullify();
1321            }
1322
1323            unsafe { core::slice::from_raw_parts_mut(data.as_mut_ptr() as *mut _, data.len()) }
1324        }
1325    }
1326
1327    impl Display for AdcMeasurement {
1328        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1329            write!(
1330                f,
1331                "ADC Reading {{channel={}, data={}}}",
1332                self.channel(),
1333                self.data()
1334            )
1335        }
1336    }
1337
1338    impl Debug for AdcMeasurement {
1339        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1340            write!(
1341                f,
1342                "AdcMeasurement {{channel: {}, data: {}}}",
1343                self.channel(),
1344                self.data()
1345            )
1346        }
1347    }
1348
1349    pub mod config {
1350        use crate::units::*;
1351
1352        /// ADC continuous mode driver configurations.
1353        /// The default configuration is:
1354        /// * [`sample_freq`][Config::sample_freq]: 2000 Hz
1355        /// * [`frame_measurements`][Config::frame_measurements]: 100
1356        /// * [`frames_count`][Config::frames_count]: 10
1357        #[derive(Debug, Copy, Clone)]
1358        pub struct Config {
1359            pub sample_freq: Hertz,
1360            pub frame_measurements: usize,
1361            pub frames_count: usize,
1362        }
1363
1364        impl Config {
1365            pub const fn new() -> Self {
1366                Self {
1367                    sample_freq: Hertz(20000),
1368                    frame_measurements: 100,
1369                    frames_count: 10,
1370                }
1371            }
1372
1373            #[must_use]
1374            pub fn sample_freq(mut self, sample_freq: Hertz) -> Self {
1375                self.sample_freq = sample_freq;
1376                self
1377            }
1378
1379            #[must_use]
1380            pub fn frame_measurements(mut self, frame_measurements: usize) -> Self {
1381                self.frame_measurements = frame_measurements;
1382                self
1383            }
1384
1385            #[must_use]
1386            pub fn frames_count(mut self, frames_count: usize) -> Self {
1387                self.frames_count = frames_count;
1388                self
1389            }
1390        }
1391
1392        impl Default for Config {
1393            fn default() -> Self {
1394                Self::new()
1395            }
1396        }
1397    }
1398
1399    pub struct AdcDriver<'d> {
1400        handle: adc_continuous_handle_t,
1401        adc: u8,
1402        _ref: PhantomData<&'d ()>,
1403    }
1404
1405    impl<'d> AdcDriver<'d> {
1406        /// Initialize ADC continuous driver with configuration and channels.
1407        #[cfg(esp32)]
1408        pub fn new(
1409            adc: super::ADC1<'d>,
1410            _i2s: crate::i2s::I2S0<'d>,
1411            config: &config::Config,
1412            channels: impl AdcChannels<AdcUnit = super::ADCU1> + 'd,
1413        ) -> Result<Self, EspError> {
1414            Self::internal_new(adc, config, channels)
1415        }
1416
1417        /// Initialize ADC continuous driver with configuration and channels
1418        #[cfg(esp32s2)]
1419        pub fn new(
1420            adc: super::ADC1<'d>,
1421            _spi: crate::spi::SPI3<'d>,
1422            config: &config::Config,
1423            channels: impl AdcChannels<AdcUnit = super::ADCU1> + 'd,
1424        ) -> Result<Self, EspError> {
1425            Self::internal_new(adc, config, channels)
1426        }
1427
1428        /// Initialize ADC continuous driver with configuration and channels.
1429        #[cfg(not(any(esp32, esp32s2)))]
1430        pub fn new<A: Adc + 'd>(
1431            adc: A,
1432            config: &config::Config,
1433            channels: impl AdcChannels<AdcUnit = A::AdcUnit> + 'd,
1434        ) -> Result<Self, EspError> {
1435            Self::internal_new(adc, config, channels)
1436        }
1437
1438        fn internal_new<A: Adc + 'd>(
1439            _adc: A,
1440            config: &config::Config,
1441            channels: impl AdcChannels<AdcUnit = A::AdcUnit> + 'd,
1442        ) -> Result<Self, EspError> {
1443            let mut patterns = [adc_digi_pattern_config_t::default(); 32];
1444
1445            for (index, (channel, atten)) in channels.iter().enumerate() {
1446                if index >= patterns.len() {
1447                    return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
1448                }
1449
1450                patterns[index].atten = atten as _;
1451                patterns[index].channel = channel as _;
1452                patterns[index].unit = A::unit() as _;
1453                patterns[index].bit_width = 12; // For now only 12 bits is supported
1454            }
1455
1456            let mut handle: adc_continuous_handle_t = core::ptr::null_mut();
1457
1458            #[allow(clippy::needless_update)]
1459            esp!(unsafe {
1460                adc_continuous_new_handle(
1461                    &adc_continuous_handle_cfg_t {
1462                        max_store_buf_size: SOC_ADC_DIGI_DATA_BYTES_PER_CONV
1463                            * (config.frame_measurements as u32)
1464                            * (config.frames_count as u32),
1465                        conv_frame_size: SOC_ADC_DIGI_DATA_BYTES_PER_CONV
1466                            * (config.frame_measurements as u32),
1467                        ..Default::default()
1468                    },
1469                    &mut handle,
1470                )
1471            })?;
1472
1473            let conv_mode = if A::unit() == 0 {
1474                adc_digi_convert_mode_t_ADC_CONV_SINGLE_UNIT_1
1475            } else {
1476                adc_digi_convert_mode_t_ADC_CONV_SINGLE_UNIT_2
1477            };
1478
1479            #[cfg(any(esp32, esp32s2))]
1480            let format = adc_digi_output_format_t_ADC_DIGI_OUTPUT_FORMAT_TYPE1;
1481
1482            #[cfg(not(any(esp32, esp32s2)))]
1483            let format = adc_digi_output_format_t_ADC_DIGI_OUTPUT_FORMAT_TYPE2;
1484
1485            esp!(unsafe {
1486                adc_continuous_config(
1487                    handle,
1488                    &adc_continuous_config_t {
1489                        pattern_num: channels.iter().count() as _,
1490                        adc_pattern: &patterns as *const _ as *mut _,
1491                        sample_freq_hz: config.sample_freq.into(),
1492                        conv_mode,
1493                        format,
1494                    },
1495                )
1496            })?;
1497
1498            #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1499            {
1500                esp!(unsafe {
1501                    adc_continuous_register_event_callbacks(
1502                        handle,
1503                        &adc_continuous_evt_cbs_t {
1504                            on_conv_done: Some(Self::handle_isr),
1505                            on_pool_ovf: Some(Self::handle_isr),
1506                        },
1507                        &NOTIFIER[A::unit() as usize] as *const _ as *mut _,
1508                    )
1509                })?;
1510            }
1511
1512            Ok(Self {
1513                handle,
1514                adc: A::unit() as _,
1515                _ref: PhantomData,
1516            })
1517        }
1518
1519        /// Get the ADC driver handle.
1520        pub fn handle(&self) -> adc_continuous_handle_t {
1521            self.handle
1522        }
1523
1524        // Get the ADC unit. ADC1 or ADC2.
1525        pub fn unit(&self) -> adc_unit_t {
1526            self.adc as _
1527        }
1528
1529        /// Start the ADC under continuous mode and generate results.
1530        pub fn start(&mut self) -> Result<(), EspError> {
1531            esp!(unsafe { adc_continuous_start(self.handle) })
1532        }
1533
1534        /// Stop the ADC.
1535        pub fn stop(&mut self) -> Result<(), EspError> {
1536            esp!(unsafe { adc_continuous_stop(self.handle) })
1537        }
1538
1539        /// Read `AdcMeasurements` in continuous mode.
1540        pub fn read(
1541            &mut self,
1542            buf: &mut [AdcMeasurement],
1543            timeout: TickType_t,
1544        ) -> Result<usize, EspError> {
1545            let mut read: u32 = 0;
1546
1547            esp!(unsafe {
1548                adc_continuous_read(
1549                    self.handle,
1550                    buf.as_mut_ptr() as *mut _,
1551                    core::mem::size_of_val(buf) as _,
1552                    &mut read,
1553                    TickType(timeout).as_millis_u32(),
1554                )
1555            })?;
1556
1557            Ok(read as usize / core::mem::size_of::<AdcMeasurement>())
1558        }
1559
1560        /// Read bytes in continuous mode.
1561        pub fn read_bytes(
1562            &mut self,
1563            buf: &mut [u8],
1564            timeout: TickType_t,
1565        ) -> Result<usize, EspError> {
1566            let mut read: u32 = 0;
1567
1568            esp!(unsafe {
1569                adc_continuous_read(
1570                    self.handle,
1571                    buf.as_mut_ptr() as *mut _,
1572                    core::mem::size_of_val(buf) as _,
1573                    &mut read,
1574                    TickType(timeout).as_millis_u32(),
1575                )
1576            })?;
1577
1578            Ok(read as usize)
1579        }
1580
1581        #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1582        pub async fn read_async(&mut self, buf: &mut [AdcMeasurement]) -> Result<usize, EspError> {
1583            loop {
1584                match self.read(buf, delay::NON_BLOCK) {
1585                    Ok(len) if len > 0 => return Ok(len),
1586                    Err(e) if e.code() != ESP_ERR_TIMEOUT => return Err(e),
1587                    _ => {
1588                        NOTIFIER[self.adc as usize].wait().await;
1589                    }
1590                }
1591            }
1592        }
1593
1594        #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1595        pub async fn read_bytes_async(&mut self, buf: &mut [u8]) -> Result<usize, EspError> {
1596            loop {
1597                match self.read_bytes(buf, delay::NON_BLOCK) {
1598                    Ok(len) if len > 0 => return Ok(len),
1599                    Err(e) if e.code() != ESP_ERR_TIMEOUT => return Err(e),
1600                    _ => {
1601                        NOTIFIER[self.adc as usize].wait().await;
1602                    }
1603                }
1604            }
1605        }
1606
1607        #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1608        extern "C" fn handle_isr(
1609            _handle: adc_continuous_handle_t,
1610            _data: *const adc_continuous_evt_data_t,
1611            user_data: *mut c_void,
1612        ) -> bool {
1613            let notifier: &HalIsrNotification =
1614                unsafe { (user_data as *const HalIsrNotification).as_ref() }.unwrap();
1615
1616            notifier.notify_lsb()
1617        }
1618    }
1619
1620    impl Drop for AdcDriver<'_> {
1621        fn drop(&mut self) {
1622            let _ = self.stop();
1623
1624            #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1625            {
1626                esp!(unsafe {
1627                    adc_continuous_register_event_callbacks(
1628                        self.handle,
1629                        &adc_continuous_evt_cbs_t {
1630                            on_conv_done: None,
1631                            on_pool_ovf: None,
1632                        },
1633                        core::ptr::null_mut(),
1634                    )
1635                })
1636                .unwrap();
1637            }
1638
1639            esp!(unsafe { adc_continuous_deinit(self.handle) }).unwrap();
1640
1641            #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1642            NOTIFIER[self.adc as usize].reset();
1643        }
1644    }
1645
1646    unsafe impl Send for AdcDriver<'_> {}
1647
1648    impl embedded_io::ErrorType for AdcDriver<'_> {
1649        type Error = EspIOError;
1650    }
1651
1652    impl embedded_io::Read for AdcDriver<'_> {
1653        fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
1654            self.read_bytes(buf, delay::BLOCK).map_err(EspIOError)
1655        }
1656    }
1657
1658    #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1659    impl embedded_io_async::Read for AdcDriver<'_> {
1660        async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
1661            self.read_bytes_async(buf).await.map_err(EspIOError)
1662        }
1663    }
1664
1665    #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1666    #[cfg(any(esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61, esp32p4))] // TODO: Check for esp32c5 and esp32p4
1667    static NOTIFIER: [HalIsrNotification; 1] = [HalIsrNotification::new()];
1668
1669    #[cfg(not(esp_idf_adc_continuous_isr_iram_safe))]
1670    #[cfg(not(any(esp32c2, esp32h2, esp32h4, esp32c5, esp32c6, esp32c61, esp32p4)))] // TODO: Check for esp32c5 and esp32p4
1671    static NOTIFIER: [HalIsrNotification; 2] =
1672        [HalIsrNotification::new(), HalIsrNotification::new()];
1673}