Skip to main content

esp_hal/analog/adc/calibration/
basic.rs

1use core::marker::PhantomData;
2
3use crate::analog::adc::{AdcCalEfuse, AdcCalScheme, Attenuation, CalibrationAccess, Error};
4
5/// Basic ADC calibration scheme.
6///
7/// The zero-voltage bias (`Dout0`) is applied by the driver for every
8/// conversion, whether or not a calibration scheme is in use, because the
9/// hardware subtracts it before truncating the result.
10///
11/// What is left for this scheme is the per-channel correction to that bias,
12/// which only some chips characterize in eFuse. On the others this scheme
13/// returns readings unchanged.
14#[derive(Clone, Copy)]
15pub struct AdcCalBasic<ADCX> {
16    #[cfg(adc_channel_compensation)]
17    chan_compens: i32,
18
19    _phantom: PhantomData<ADCX>,
20}
21
22impl<ADCX> crate::private::Sealed for AdcCalBasic<ADCX> {}
23
24impl<ADCX> AdcCalScheme<ADCX> for AdcCalBasic<ADCX>
25where
26    ADCX: AdcCalEfuse + CalibrationAccess,
27{
28    fn new_cal(atten: Attenuation) -> Result<Self, Error> {
29        Self::new_cal_with_channel(atten, 0)
30    }
31
32    fn new_cal_with_channel(_atten: Attenuation, _channel: u8) -> Result<Self, Error> {
33        Ok(Self {
34            // A missing per-channel offset means the chip did not characterize this
35            // channel, so no correction applies. `channel` always comes from a valid
36            // ADC pin, and unburnt eFuses likewise mean zero correction.
37            #[cfg(adc_channel_compensation)]
38            chan_compens: ADCX::cal_chan_compens(_atten, _channel).unwrap_or(0),
39            _phantom: PhantomData,
40        })
41    }
42
43    #[cfg(adc_channel_compensation)]
44    fn adc_val(&self, val: u16) -> u16 {
45        (val as i32 - self.chan_compens).clamp(0, ADCX::ADC_VAL_MASK as i32) as u16
46    }
47}