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