esp_hal/analog/adc/
xtensa.rs

1use core::marker::PhantomData;
2
3#[cfg(esp32s3)]
4pub use self::calibration::*;
5use super::{AdcCalScheme, AdcCalSource, AdcChannel, AdcConfig, AdcPin, Attenuation};
6#[cfg(esp32s3)]
7use crate::efuse::Efuse;
8use crate::{
9    peripherals::{APB_SARADC, SENS},
10    soc::regi2c,
11    system::{GenericPeripheralGuard, Peripheral},
12};
13
14mod calibration;
15
16pub(super) const NUM_ATTENS: usize = 10;
17
18cfg_if::cfg_if! {
19    if #[cfg(esp32s3)] {
20        const ADC_VAL_MASK: u16 = 0xfff;
21        const ADC_CAL_CNT_MAX: u16 = 32;
22        const ADC_CAL_CHANNEL: u16 = 15;
23    }
24}
25
26/// The sampling/readout resolution of the ADC.
27#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
28#[cfg_attr(feature = "defmt", derive(defmt::Format))]
29#[allow(clippy::enum_variant_names, reason = "peripheral is unstable")]
30pub enum Resolution {
31    /// 13-bit resolution
32    #[default]
33    Resolution13Bit,
34}
35
36impl<ADCI> AdcConfig<ADCI>
37where
38    ADCI: RegisterAccess,
39{
40    /// Calibrate ADC with specified attenuation and voltage source
41    pub fn adc_calibrate(atten: Attenuation, source: AdcCalSource) -> u16
42    where
43        ADCI: super::CalibrationAccess,
44    {
45        let mut adc_max: u16 = 0;
46        let mut adc_min: u16 = u16::MAX;
47        let mut adc_sum: u32 = 0;
48
49        ADCI::enable_vdef(true);
50
51        // Start sampling
52        ADCI::set_en_pad(ADCI::ADC_CAL_CHANNEL as u8);
53        ADCI::set_attenuation(ADCI::ADC_CAL_CHANNEL as usize, atten as u8);
54
55        // Connect calibration source
56        ADCI::connect_cal(source, true);
57
58        ADCI::set_init_code(0);
59
60        for _ in 0..ADCI::ADC_CAL_CNT_MAX {
61            // Trigger ADC sampling
62            ADCI::start_sample();
63
64            // Wait until ADC1 sampling is done
65            while !ADCI::is_done() {}
66
67            let adc = ADCI::read_data() & ADCI::ADC_VAL_MASK;
68
69            ADCI::reset();
70
71            adc_sum += adc as u32;
72            adc_max = adc.max(adc_max);
73            adc_min = adc.min(adc_min);
74        }
75
76        let cal_val =
77            (adc_sum - adc_max as u32 - adc_min as u32) as u16 / (ADCI::ADC_CAL_CNT_MAX - 2);
78
79        // Disconnect calibration source
80        ADCI::connect_cal(source, false);
81
82        cal_val
83    }
84}
85
86#[doc(hidden)]
87pub trait RegisterAccess {
88    fn set_attenuation(channel: usize, attenuation: u8);
89
90    fn clear_dig_force();
91
92    fn set_start_force();
93
94    fn set_en_pad_force();
95
96    fn set_en_pad(channel: u8);
97
98    fn clear_start_sample();
99
100    fn start_sample();
101
102    /// Check if sampling is done
103    fn is_done() -> bool;
104
105    /// Read sample data
106    fn read_data() -> u16;
107
108    /// Set calibration parameter to ADC hardware
109    fn set_init_code(data: u16);
110
111    /// Reset flags
112    fn reset();
113}
114
115impl RegisterAccess for crate::peripherals::ADC1<'_> {
116    fn set_attenuation(channel: usize, attenuation: u8) {
117        SENS::regs().sar_atten1().modify(|r, w| {
118            let new_value = (r.bits() & !(0b11 << (channel * 2)))
119                | (((attenuation & 0b11) as u32) << (channel * 2));
120
121            unsafe { w.sar1_atten().bits(new_value) }
122        });
123    }
124
125    fn clear_dig_force() {
126        SENS::regs()
127            .sar_meas1_mux()
128            .modify(|_, w| w.sar1_dig_force().clear_bit());
129    }
130
131    fn set_start_force() {
132        SENS::regs()
133            .sar_meas1_ctrl2()
134            .modify(|_, w| w.meas1_start_force().set_bit());
135    }
136
137    fn set_en_pad_force() {
138        SENS::regs()
139            .sar_meas1_ctrl2()
140            .modify(|_, w| w.sar1_en_pad_force().set_bit());
141    }
142
143    fn set_en_pad(channel: u8) {
144        SENS::regs()
145            .sar_meas1_ctrl2()
146            .modify(|_, w| unsafe { w.sar1_en_pad().bits(1 << channel) });
147    }
148
149    fn clear_start_sample() {
150        SENS::regs()
151            .sar_meas1_ctrl2()
152            .modify(|_, w| w.meas1_start_sar().clear_bit());
153    }
154
155    fn start_sample() {
156        SENS::regs()
157            .sar_meas1_ctrl2()
158            .modify(|_, w| w.meas1_start_sar().set_bit());
159    }
160
161    fn is_done() -> bool {
162        SENS::regs()
163            .sar_meas1_ctrl2()
164            .read()
165            .meas1_done_sar()
166            .bit_is_set()
167    }
168
169    fn read_data() -> u16 {
170        SENS::regs()
171            .sar_meas1_ctrl2()
172            .read()
173            .meas1_data_sar()
174            .bits()
175    }
176
177    fn set_init_code(data: u16) {
178        let [msb, lsb] = data.to_be_bytes();
179
180        regi2c::ADC_SAR1_INITIAL_CODE_HIGH.write_field(msb);
181        regi2c::ADC_SAR1_INITIAL_CODE_LOW.write_field(lsb);
182    }
183
184    fn reset() {
185        let adc = APB_SARADC::regs();
186        let sensors = SENS::regs();
187
188        adc.int_clr().write(|w| w.adc1_done().clear_bit_by_one());
189
190        sensors
191            .sar_meas1_ctrl2()
192            .modify(|_, w| w.meas1_start_sar().clear_bit());
193    }
194}
195
196#[cfg(esp32s3)]
197impl super::CalibrationAccess for crate::peripherals::ADC1<'_> {
198    const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
199    const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
200    const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
201
202    fn enable_vdef(enable: bool) {
203        regi2c::ADC_SAR1_DREF.write_field(enable as u8);
204    }
205
206    fn connect_cal(source: AdcCalSource, enable: bool) {
207        match source {
208            AdcCalSource::Gnd => regi2c::ADC_SAR1_ENCAL_GND.write_field(enable as u8),
209            AdcCalSource::Ref => regi2c::ADC_SAR1_ENCAL_REF.write_field(enable as u8),
210        }
211    }
212}
213
214impl RegisterAccess for crate::peripherals::ADC2<'_> {
215    fn set_attenuation(channel: usize, attenuation: u8) {
216        SENS::regs().sar_atten2().modify(|r, w| {
217            let new_value = (r.bits() & !(0b11 << (channel * 2)))
218                | (((attenuation & 0b11) as u32) << (channel * 2));
219
220            unsafe { w.sar2_atten().bits(new_value) }
221        });
222    }
223
224    fn clear_dig_force() {
225        SENS::regs()
226            .sar_meas2_mux()
227            .modify(|_, w| w.sar2_rtc_force().set_bit());
228
229        APB_SARADC::regs()
230            .arb_ctrl()
231            .modify(|_, w| w.rtc_force().set_bit());
232    }
233
234    fn set_start_force() {
235        SENS::regs()
236            .sar_meas2_ctrl2()
237            .modify(|_, w| w.meas2_start_force().set_bit());
238    }
239
240    fn set_en_pad_force() {
241        SENS::regs()
242            .sar_meas2_ctrl2()
243            .modify(|_, w| w.sar2_en_pad_force().set_bit());
244    }
245
246    fn set_en_pad(channel: u8) {
247        SENS::regs()
248            .sar_meas2_ctrl2()
249            .modify(|_, w| unsafe { w.sar2_en_pad().bits(1 << channel) });
250    }
251
252    fn clear_start_sample() {
253        SENS::regs()
254            .sar_meas2_ctrl2()
255            .modify(|_, w| w.meas2_start_sar().clear_bit());
256    }
257
258    fn start_sample() {
259        SENS::regs()
260            .sar_meas2_ctrl2()
261            .modify(|_, w| w.meas2_start_sar().set_bit());
262    }
263
264    fn is_done() -> bool {
265        SENS::regs()
266            .sar_meas2_ctrl2()
267            .read()
268            .meas2_done_sar()
269            .bit_is_set()
270    }
271
272    fn read_data() -> u16 {
273        SENS::regs()
274            .sar_meas2_ctrl2()
275            .read()
276            .meas2_data_sar()
277            .bits()
278    }
279
280    fn set_init_code(data: u16) {
281        let [msb, lsb] = data.to_be_bytes();
282
283        regi2c::ADC_SAR2_INITIAL_CODE_HIGH.write_field(msb);
284        regi2c::ADC_SAR2_INITIAL_CODE_LOW.write_field(lsb);
285    }
286
287    fn reset() {
288        let adc = APB_SARADC::regs();
289        let sensors = SENS::regs();
290
291        adc.int_clr().write(|w| w.adc2_done().clear_bit_by_one());
292
293        sensors
294            .sar_meas2_ctrl2()
295            .modify(|_, w| w.meas2_start_sar().clear_bit());
296    }
297}
298
299#[cfg(esp32s3)]
300impl super::CalibrationAccess for crate::peripherals::ADC2<'_> {
301    const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX;
302    const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL;
303    const ADC_VAL_MASK: u16 = ADC_VAL_MASK;
304
305    fn enable_vdef(enable: bool) {
306        regi2c::ADC_SAR2_DREF.write_field(enable as u8);
307    }
308
309    fn connect_cal(source: AdcCalSource, enable: bool) {
310        match source {
311            AdcCalSource::Gnd => regi2c::ADC_SAR2_ENCAL_GND.write_field(enable as u8),
312            AdcCalSource::Ref => regi2c::ADC_SAR2_ENCAL_REF.write_field(enable as u8),
313        }
314    }
315}
316
317/// Analog-to-Digital Converter peripheral driver.
318pub struct Adc<'d, ADC, Dm: crate::DriverMode> {
319    _adc: ADC,
320    active_channel: Option<u8>,
321    last_init_code: u16,
322    _guard: GenericPeripheralGuard<{ Peripheral::ApbSarAdc as u8 }>,
323    _phantom: PhantomData<(Dm, &'d mut ())>,
324}
325
326impl<'d, ADCI> Adc<'d, ADCI, crate::Blocking>
327where
328    ADCI: RegisterAccess + 'd,
329{
330    /// Configure a given ADC instance using the provided configuration, and
331    /// initialize the ADC for use
332    pub fn new(adc_instance: ADCI, config: AdcConfig<ADCI>) -> Self {
333        let guard = GenericPeripheralGuard::new();
334        let sensors = SENS::regs();
335
336        // Set attenuation for pins
337        let attenuations = config.attenuations;
338
339        for (channel, attenuation) in attenuations.iter().enumerate() {
340            if let Some(attenuation) = attenuation {
341                ADCI::set_attenuation(channel, *attenuation as u8);
342            }
343        }
344
345        // Set controller to RTC
346        ADCI::clear_dig_force();
347        ADCI::set_start_force();
348        ADCI::set_en_pad_force();
349        sensors
350            .sar_hall_ctrl()
351            .modify(|_, w| w.xpd_hall_force().set_bit());
352        sensors
353            .sar_hall_ctrl()
354            .modify(|_, w| w.hall_phase_force().set_bit());
355
356        // Set power to SW power on
357        #[cfg(esp32s2)]
358        sensors
359            .sar_meas1_ctrl1()
360            .modify(|_, w| w.rtc_saradc_clkgate_en().set_bit());
361
362        #[cfg(esp32s3)]
363        sensors
364            .sar_peri_clk_gate_conf()
365            .modify(|_, w| w.saradc_clk_en().set_bit());
366
367        sensors
368            .sar_power_xpd_sar()
369            .modify(|_, w| w.sarclk_en().set_bit());
370
371        sensors
372            .sar_power_xpd_sar()
373            .modify(|_, w| unsafe { w.force_xpd_sar().bits(0b11) });
374
375        // disable AMP
376        sensors
377            .sar_meas1_ctrl1()
378            .modify(|_, w| unsafe { w.force_xpd_amp().bits(0b11) });
379        sensors
380            .sar_amp_ctrl3()
381            .modify(|_, w| unsafe { w.amp_rst_fb_fsm().bits(0) });
382        sensors
383            .sar_amp_ctrl3()
384            .modify(|_, w| unsafe { w.amp_short_ref_fsm().bits(0) });
385        sensors
386            .sar_amp_ctrl3()
387            .modify(|_, w| unsafe { w.amp_short_ref_gnd_fsm().bits(0) });
388        sensors
389            .sar_amp_ctrl1()
390            .modify(|_, w| unsafe { w.sar_amp_wait1().bits(1) });
391        sensors
392            .sar_amp_ctrl1()
393            .modify(|_, w| unsafe { w.sar_amp_wait2().bits(1) });
394        sensors
395            .sar_amp_ctrl2()
396            .modify(|_, w| unsafe { w.sar_amp_wait3().bits(1) });
397
398        Adc {
399            _adc: adc_instance,
400            active_channel: None,
401            last_init_code: 0,
402            _guard: guard,
403            _phantom: PhantomData,
404        }
405    }
406
407    /// Start and wait for a conversion on the specified pin and return the
408    /// result
409    pub fn read_blocking<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCI, CS>) -> u16
410    where
411        PIN: AdcChannel,
412        CS: AdcCalScheme<ADCI>,
413    {
414        self.start_sample(pin);
415
416        // Wait for ADC to finish conversion
417        while !ADCI::is_done() {}
418
419        // Get converted value
420        let converted_value = ADCI::read_data();
421        ADCI::reset();
422
423        // Postprocess converted value according to calibration scheme used for pin
424        pin.cal_scheme.adc_val(converted_value)
425    }
426
427    /// Request that the ADC begin a conversion on the specified pin
428    ///
429    /// This method takes an [AdcPin](super::AdcPin) reference, as it is
430    /// expected that the ADC will be able to sample whatever channel
431    /// underlies the pin.
432    pub fn read_oneshot<PIN, CS>(
433        &mut self,
434        pin: &mut super::AdcPin<PIN, ADCI, CS>,
435    ) -> nb::Result<u16, ()>
436    where
437        PIN: super::AdcChannel,
438        CS: super::AdcCalScheme<ADCI>,
439    {
440        if let Some(active_channel) = self.active_channel {
441            // There is conversion in progress:
442            // - if it's for a different channel try again later
443            // - if it's for the given channel, go ahead and check progress
444            if active_channel != PIN::CHANNEL {
445                return Err(nb::Error::WouldBlock);
446            }
447        } else {
448            // If no conversions are in progress, start a new one for given channel
449            self.active_channel = Some(PIN::CHANNEL);
450
451            self.start_sample(pin);
452        }
453
454        // Wait for ADC to finish conversion
455        let conversion_finished = ADCI::is_done();
456        if !conversion_finished {
457            return Err(nb::Error::WouldBlock);
458        }
459
460        // Get converted value
461        let converted_value = ADCI::read_data();
462        ADCI::reset();
463
464        // Postprocess converted value according to calibration scheme used for pin
465        let converted_value = pin.cal_scheme.adc_val(converted_value);
466
467        // Mark that no conversions are currently in progress
468        self.active_channel = None;
469
470        Ok(converted_value)
471    }
472
473    fn start_sample<PIN, CS>(&mut self, pin: &mut AdcPin<PIN, ADCI, CS>)
474    where
475        PIN: AdcChannel,
476        CS: AdcCalScheme<ADCI>,
477    {
478        // Set ADC unit calibration according used scheme for pin
479        let init_code = pin.cal_scheme.adc_cal();
480        if self.last_init_code != init_code {
481            ADCI::set_init_code(init_code);
482            self.last_init_code = init_code;
483        }
484
485        ADCI::set_en_pad(PIN::CHANNEL);
486
487        ADCI::clear_start_sample();
488        ADCI::start_sample();
489    }
490}
491
492#[cfg(esp32s3)]
493impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> {
494    fn init_code(atten: Attenuation) -> Option<u16> {
495        Efuse::rtc_calib_init_code(1, atten)
496    }
497
498    fn cal_mv(atten: Attenuation) -> u16 {
499        Efuse::rtc_calib_cal_mv(1, atten)
500    }
501
502    fn cal_code(atten: Attenuation) -> Option<u16> {
503        Efuse::rtc_calib_cal_code(1, atten)
504    }
505}
506
507#[cfg(esp32s3)]
508impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> {
509    fn init_code(atten: Attenuation) -> Option<u16> {
510        Efuse::rtc_calib_init_code(2, atten)
511    }
512
513    fn cal_mv(atten: Attenuation) -> u16 {
514        Efuse::rtc_calib_cal_mv(2, atten)
515    }
516
517    fn cal_code(atten: Attenuation) -> Option<u16> {
518        Efuse::rtc_calib_cal_code(2, atten)
519    }
520}
521
522mod adc_implementation {
523    crate::analog::adc::impl_adc_interface! {
524        ADC1 [
525            (GPIO1<'_>,  0),
526            (GPIO2<'_>,  1),
527            (GPIO3<'_>,  2),
528            (GPIO4<'_>,  3),
529            (GPIO5<'_>,  4),
530            (GPIO6<'_>,  5),
531            (GPIO7<'_>,  6),
532            (GPIO8<'_>,  7),
533            (GPIO9<'_>,  8),
534            (GPIO10<'_>, 9),
535        ]
536    }
537
538    crate::analog::adc::impl_adc_interface! {
539        ADC2 [
540            (GPIO11<'_>, 0),
541            (GPIO12<'_>, 1),
542            (GPIO13<'_>, 2),
543            (GPIO14<'_>, 3),
544            (GPIO15<'_>, 4),
545            (GPIO16<'_>, 5),
546            (GPIO17<'_>, 6),
547            (GPIO18<'_>, 7),
548            (GPIO19<'_>, 8),
549            (GPIO20<'_>, 9),
550        ]
551    }
552}