diff --git a/esp-hal/src/analog/adc/calibration/line.rs b/esp-hal/src/analog/adc/calibration/line.rs index 792a0ed14f5..2f4fb44ca7a 100644 --- a/esp-hal/src/analog/adc/calibration/line.rs +++ b/esp-hal/src/analog/adc/calibration/line.rs @@ -45,6 +45,9 @@ pub struct AdcCalLine { /// number with 16 fractional bits. gain: u32, + #[cfg(esp32s2)] + offset: i32, + _phantom: PhantomData, } @@ -63,7 +66,7 @@ where .map(|code| (code, ADCI::cal_mv(atten))) .unwrap_or_else(|| { // As a fallback try to calibrate using reference voltage source. - // This method is not too good because actual reference voltage may varies + // This method is not too good because actual reference voltage varies // in range 1000..=1200 mV and this value currently cannot be read from efuse. ( AdcConfig::::adc_calibrate(atten, AdcCalSource::Ref), @@ -82,6 +85,8 @@ where Self { basic, gain, + #[cfg(esp32s2)] + offset: ADCI::coeff_b(atten).unwrap_or(0), _phantom: PhantomData, } } @@ -93,12 +98,17 @@ where fn adc_val(&self, val: u16) -> u16 { let val = self.basic.adc_val(val); - (val as u32 * self.gain / GAIN_SCALE) as u16 + let transformed = val as u32 * self.gain / GAIN_SCALE; + + #[cfg(esp32s2)] + let transformed = { i32::max(transformed as i32 + self.offset, 0) }; + + transformed as u16 } } -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3))] impl AdcHasLineCal for crate::peripherals::ADC1<'_> {} -#[cfg(any(esp32c3, esp32s3))] +#[cfg(any(esp32c3, esp32s2, esp32s3))] impl AdcHasLineCal for crate::peripherals::ADC2<'_> {} diff --git a/esp-hal/src/analog/adc/calibration/mod.rs b/esp-hal/src/analog/adc/calibration/mod.rs index 1dde6b10a34..7a01c12c637 100644 --- a/esp-hal/src/analog/adc/calibration/mod.rs +++ b/esp-hal/src/analog/adc/calibration/mod.rs @@ -1,13 +1,13 @@ -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3))] pub use self::basic::AdcCalBasic; #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] pub use self::curve::{AdcCalCurve, AdcHasCurveCal}; -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3))] pub use self::line::{AdcCalLine, AdcHasLineCal}; -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3))] mod basic; #[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))] mod curve; -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s3))] +#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2, esp32s2, esp32s3))] mod line; diff --git a/esp-hal/src/analog/adc/mod.rs b/esp-hal/src/analog/adc/mod.rs index c64a7cf3cc4..2a68e9c4b82 100644 --- a/esp-hal/src/analog/adc/mod.rs +++ b/esp-hal/src/analog/adc/mod.rs @@ -225,7 +225,7 @@ impl AdcCalScheme for () { } /// A helper trait to get access to ADC calibration efuses. -#[cfg(not(any(esp32, esp32s2)))] +#[cfg(not(any(esp32, esp32h2)))] trait AdcCalEfuse { /// Get ADC calibration init code /// @@ -241,6 +241,11 @@ trait AdcCalEfuse { /// /// Returns digital value for reference voltage for a given attenuation fn cal_code(atten: Attenuation) -> Option; + + #[cfg(esp32s2)] + /// Get the coeff_b from efuse. + /// Use in the equation: millivolts = coeff_a*adc + coeff_b + fn coeff_b(atten: Attenuation) -> Option; } macro_rules! impl_adc_interface { diff --git a/esp-hal/src/analog/adc/xtensa.rs b/esp-hal/src/analog/adc/xtensa.rs index 2b49a7316bd..304b572b53d 100644 --- a/esp-hal/src/analog/adc/xtensa.rs +++ b/esp-hal/src/analog/adc/xtensa.rs @@ -1,9 +1,9 @@ use core::marker::PhantomData; -#[cfg(esp32s3)] +#[cfg(any(esp32s2, esp32s3))] pub use self::calibration::*; use super::{AdcCalScheme, AdcCalSource, AdcChannel, AdcConfig, AdcPin, Attenuation}; -#[cfg(esp32s3)] +#[cfg(any(esp32s2, esp32s3))] use crate::efuse::Efuse; use crate::{ peripherals::{APB_SARADC, SENS}, @@ -16,10 +16,10 @@ mod calibration; pub(super) const NUM_ATTENS: usize = 10; cfg_if::cfg_if! { - if #[cfg(esp32s3)] { + if #[cfg(any(esp32s2, esp32s3))] { const ADC_VAL_MASK: u16 = 0xfff; const ADC_CAL_CNT_MAX: u16 = 32; - const ADC_CAL_CHANNEL: u16 = 15; + const ADC_CAL_CHANNEL: u16 = 0; } } @@ -61,7 +61,7 @@ where // Trigger ADC sampling ADCI::start_sample(); - // Wait until ADC1 sampling is done + // Wait until ADCI sampling is done while !ADCI::is_done() {} let adc = ADCI::read_data() & ADCI::ADC_VAL_MASK; @@ -193,14 +193,16 @@ impl RegisterAccess for crate::peripherals::ADC1<'_> { } } -#[cfg(esp32s3)] +#[cfg(any(esp32s2, esp32s3))] impl super::CalibrationAccess for crate::peripherals::ADC1<'_> { const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX; const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL; const ADC_VAL_MASK: u16 = ADC_VAL_MASK; fn enable_vdef(enable: bool) { - regi2c::ADC_SAR1_DREF.write_field(enable as u8); + // For enable value 4, see + // For disable value 1, see + regi2c::ADC_SAR1_DREF.write_field(if enable { 4 } else { 1 }); } fn connect_cal(source: AdcCalSource, enable: bool) { @@ -296,14 +298,14 @@ impl RegisterAccess for crate::peripherals::ADC2<'_> { } } -#[cfg(esp32s3)] +#[cfg(any(esp32s2, esp32s3))] impl super::CalibrationAccess for crate::peripherals::ADC2<'_> { const ADC_CAL_CNT_MAX: u16 = ADC_CAL_CNT_MAX; const ADC_CAL_CHANNEL: u16 = ADC_CAL_CHANNEL; const ADC_VAL_MASK: u16 = ADC_VAL_MASK; fn enable_vdef(enable: bool) { - regi2c::ADC_SAR2_DREF.write_field(enable as u8); + regi2c::ADC_SAR2_DREF.write_field(if enable { 4 } else { 1 }); } fn connect_cal(source: AdcCalSource, enable: bool) { @@ -395,6 +397,8 @@ where .sar_amp_ctrl2() .modify(|_, w| unsafe { w.sar_amp_wait3().bits(1) }); + // TODO: ADC2 arbiter: https://github.com/espressif/esp-idf/blob/84df38aab927d50f7ee22d34516d7263f3e96068/components/hal/adc_oneshot_hal.c#L92 + Adc { _adc: adc_instance, active_channel: None, @@ -489,7 +493,7 @@ where } } -#[cfg(esp32s3)] +#[cfg(any(esp32s2, esp32s3))] impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> { fn init_code(atten: Attenuation) -> Option { Efuse::rtc_calib_init_code(1, atten) @@ -502,9 +506,13 @@ impl super::AdcCalEfuse for crate::peripherals::ADC1<'_> { fn cal_code(atten: Attenuation) -> Option { Efuse::rtc_calib_cal_code(1, atten) } + + fn coeff_b(atten: Attenuation) -> Option { + Efuse::rtc_calib_coeff_b(1, atten) + } } -#[cfg(esp32s3)] +#[cfg(any(esp32s2, esp32s3))] impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> { fn init_code(atten: Attenuation) -> Option { Efuse::rtc_calib_init_code(2, atten) @@ -517,6 +525,9 @@ impl super::AdcCalEfuse for crate::peripherals::ADC2<'_> { fn cal_code(atten: Attenuation) -> Option { Efuse::rtc_calib_cal_code(2, atten) } + fn coeff_b(atten: Attenuation) -> Option { + Efuse::rtc_calib_coeff_b(2, atten) + } } mod adc_implementation { diff --git a/esp-hal/src/soc/esp32s2/efuse/adc_raw_map.rs b/esp-hal/src/soc/esp32s2/efuse/adc_raw_map.rs new file mode 100644 index 00000000000..bc66bdaac9e --- /dev/null +++ b/esp-hal/src/soc/esp32s2/efuse/adc_raw_map.rs @@ -0,0 +1,425 @@ +// https://github.com/espressif/esp-idf/blob/a45d713b03fd96d8805d1cc116f02a4415b360c7/components/efuse/esp32s2/include/esp_efuse_rtc_table.h#L31C1-L65C34 +// These are the tags. Either use them directly or use +// esp_efuse_rtc_table_get_tag to calculate the corresponding tag. + +#![allow(unused)] +use super::{EfuseBlock, EfuseField}; + +pub const TAG_RTCCALIB_V1IDX_A10L: usize = 1; +pub const TAG_RTCCALIB_V1IDX_A11L: usize = 2; +pub const TAG_RTCCALIB_V1IDX_A12L: usize = 3; +pub const TAG_RTCCALIB_V1IDX_A13L: usize = 4; +pub const TAG_RTCCALIB_V1IDX_A20L: usize = 5; +pub const TAG_RTCCALIB_V1IDX_A21L: usize = 6; +pub const TAG_RTCCALIB_V1IDX_A22L: usize = 7; +pub const TAG_RTCCALIB_V1IDX_A23L: usize = 8; +pub const TAG_RTCCALIB_V1IDX_A10H: usize = 9; +pub const TAG_RTCCALIB_V1IDX_A11H: usize = 10; +pub const TAG_RTCCALIB_V1IDX_A12H: usize = 11; +pub const TAG_RTCCALIB_V1IDX_A13H: usize = 12; +pub const TAG_RTCCALIB_V1IDX_A20H: usize = 13; +pub const TAG_RTCCALIB_V1IDX_A21H: usize = 14; +pub const TAG_RTCCALIB_V1IDX_A22H: usize = 15; +pub const TAG_RTCCALIB_V1IDX_A23H: usize = 16; +pub const TAG_RTCCALIB_V2IDX_A10H: usize = 17; +pub const TAG_RTCCALIB_V2IDX_A11H: usize = 18; +pub const TAG_RTCCALIB_V2IDX_A12H: usize = 19; +pub const TAG_RTCCALIB_V2IDX_A13H: usize = 20; +pub const TAG_RTCCALIB_V2IDX_A20H: usize = 21; +pub const TAG_RTCCALIB_V2IDX_A21H: usize = 22; +pub const TAG_RTCCALIB_V2IDX_A22H: usize = 23; +pub const TAG_RTCCALIB_V2IDX_A23H: usize = 24; +pub const TAG_RTCCALIB_V2IDX_A10I: usize = 25; +pub const TAG_RTCCALIB_V2IDX_A11I: usize = 26; +pub const TAG_RTCCALIB_V2IDX_A12I: usize = 27; +pub const TAG_RTCCALIB_V2IDX_A13I: usize = 28; +pub const TAG_RTCCALIB_V2IDX_A20I: usize = 29; +pub const TAG_RTCCALIB_V2IDX_A21I: usize = 30; +pub const TAG_RTCCALIB_V2IDX_A22I: usize = 31; +pub const TAG_RTCCALIB_V2IDX_A23I: usize = 32; +pub const TAG_RTCCALIB_IDX_TMPSENSOR: usize = 33; + +/// See +pub struct MapInfo { + pub field: EfuseField, + pub multiplier: i32, + pub base: i32, + pub dependency: usize, +} + +pub const RAW_MAP: [MapInfo; 34] = [ + MapInfo { + field: EfuseField { + block: EfuseBlock::Block0, + word: 0, + bit_start: 0, + bit_count: 0, + }, + multiplier: 0, + base: 0, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 208, + bit_count: 6, + }, + multiplier: 4, + base: 2231, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 214, + bit_count: 6, + }, + multiplier: 4, + base: 1643, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 220, + bit_count: 6, + }, + multiplier: 4, + base: 1290, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 226, + bit_count: 6, + }, + multiplier: 4, + base: 701, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 232, + bit_count: 6, + }, + multiplier: 4, + base: 2305, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 238, + bit_count: 6, + }, + multiplier: 4, + base: 1693, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 244, + bit_count: 6, + }, + multiplier: 4, + base: 1343, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 250, + bit_count: 6, + }, + multiplier: 4, + base: 723, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 144, + bit_count: 8, + }, + multiplier: 4, + base: 5775, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 152, + bit_count: 8, + }, + multiplier: 4, + base: 5693, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 160, + bit_count: 8, + }, + multiplier: 4, + base: 5723, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 168, + bit_count: 8, + }, + multiplier: 4, + base: 6209, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 176, + bit_count: 8, + }, + multiplier: 4, + base: 5817, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 184, + bit_count: 8, + }, + multiplier: 4, + base: 5703, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 192, + bit_count: 8, + }, + multiplier: 4, + base: 5731, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 200, + bit_count: 8, + }, + multiplier: 4, + base: 6157, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 197, + bit_count: 6, + }, + multiplier: 2, + base: 169, + dependency: TAG_RTCCALIB_V2IDX_A12H, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 203, + bit_count: 6, + }, + multiplier: 2, + base: -26, + dependency: TAG_RTCCALIB_V2IDX_A12H, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 209, + bit_count: 9, + }, + multiplier: 2, + base: 126, + dependency: TAG_RTCCALIB_V2IDX_A21H, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 218, + bit_count: 7, + }, + multiplier: 2, + base: 387, + dependency: TAG_RTCCALIB_V2IDX_A12H, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 225, + bit_count: 7, + }, + multiplier: 2, + base: 177, + dependency: TAG_RTCCALIB_V2IDX_A21H, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 232, + bit_count: 10, + }, + multiplier: 2, + base: 5815, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 242, + bit_count: 7, + }, + multiplier: 2, + base: 27, + dependency: TAG_RTCCALIB_V2IDX_A21H, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 249, + bit_count: 7, + }, + multiplier: 2, + base: 410, + dependency: TAG_RTCCALIB_V2IDX_A21H, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 147, + bit_count: 8, + }, + multiplier: 2, + base: 1519, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 155, + bit_count: 6, + }, + multiplier: 2, + base: 88, + dependency: TAG_RTCCALIB_V2IDX_A10I, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 161, + bit_count: 5, + }, + multiplier: 2, + base: 8, + dependency: TAG_RTCCALIB_V2IDX_A11I, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 166, + bit_count: 6, + }, + multiplier: 2, + base: 70, + dependency: TAG_RTCCALIB_V2IDX_A12I, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 172, + bit_count: 8, + }, + multiplier: 2, + base: 1677, + dependency: 0, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 180, + bit_count: 6, + }, + multiplier: 2, + base: 23, + dependency: TAG_RTCCALIB_V2IDX_A20I, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 186, + bit_count: 5, + }, + multiplier: 2, + base: 6, + dependency: TAG_RTCCALIB_V2IDX_A21I, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 191, + bit_count: 6, + }, + multiplier: 2, + base: 13, + dependency: TAG_RTCCALIB_V2IDX_A22I, + }, + MapInfo { + field: EfuseField { + block: EfuseBlock::Block2, + word: 0, + bit_start: 135, + bit_count: 9, + }, + multiplier: 1, + base: 0, + dependency: 0, + }, +]; diff --git a/esp-hal/src/soc/esp32s2/efuse/mod.rs b/esp-hal/src/soc/esp32s2/efuse/mod.rs index 12e5a093411..cd7be8f26d1 100644 --- a/esp-hal/src/soc/esp32s2/efuse/mod.rs +++ b/esp-hal/src/soc/esp32s2/efuse/mod.rs @@ -43,14 +43,37 @@ //! # {after_snippet} //! ``` +use self::adc_raw_map::*; pub use self::fields::*; -use crate::{peripherals::EFUSE, soc::efuse_field::EfuseField}; +use crate::{analog::adc::Attenuation, peripherals::EFUSE, soc::efuse_field::EfuseField}; +mod adc_raw_map; mod fields; /// A struct representing the eFuse functionality of the chip. pub struct Efuse; +enum RtcCalibParam { + V1VLow, + V1VHigh, + V2VInit, + V2VHigh, +} + +impl Into for RtcCalibParam { + fn into(self) -> usize { + match self { + RtcCalibParam::V1VLow => 0, + RtcCalibParam::V1VHigh => 1, + RtcCalibParam::V2VInit => 1, + RtcCalibParam::V2VHigh => 0, + } + } +} + +const RTC_CALIB_V_HIGH: [i32; 4] = [600, 800, 1000, 2000]; +const RTC_CALIB_V_LOW: i32 = 250; + impl Efuse { /// Get status of SPI boot encryption. pub fn flash_encryption() -> bool { @@ -63,6 +86,200 @@ impl Efuse { pub fn rwdt_multiplier() -> u8 { Self::read_field_le::(WDT_DELAY_SEL) } + + /// Get efuse block version + /// + /// see + pub fn block_version() -> (u8, u8) { + // See + ( + Self::read_field_le::(BLK_VERSION_MAJOR), + Self::read_field_le::(BLK_VERSION_MINOR), + ) + } + + /// See + pub fn adc_cal_check_efuse() -> bool { + let (_, calib_version) = Self::block_version(); + let encoding_version = calib_version; + + encoding_version == 1 || encoding_version == 2 + } + + /// See + fn rtc_table_get_tag( + version: u8, + unit: u8, + atten: Attenuation, + tag: RtcCalibParam, + ) -> Option { + if unit >= 2 { + return None; + } + + use RtcCalibParam::*; + let param_offset = match (version, tag) { + (1, V1VLow) => TAG_RTCCALIB_V1IDX_A10L, + (1, V1VHigh) => TAG_RTCCALIB_V1IDX_A10H, + (2, V2VInit) => TAG_RTCCALIB_V2IDX_A10I, + (2, V2VHigh) => TAG_RTCCALIB_V2IDX_A10H, + _ => return None, + }; + + const RTCCALIB_ATTENCOUNT: usize = 4; + Some(param_offset + (unit as usize) * RTCCALIB_ATTENCOUNT + (atten as usize)) + } + + fn rtc_table_get_raw_efuse_value(tag: usize) -> i32 { + if tag == 0 || tag >= RAW_MAP.len() { + return 0; + } + fn signed_bit_to_int(number: u32, length: u32) -> i32 { + if number >> (length - 1) != 0 { + -((number ^ (1 << (length - 1))) as i32) + } else { + number as i32 + } + } + let info = &RAW_MAP[tag]; + let val = Self::read_field_le(info.field); + signed_bit_to_int(val, info.field.bit_count) + } + + /// See + pub fn rtc_table_get_parsed_efuse_value(tag: usize) -> i32 { + if tag == 0 || tag >= RAW_MAP.len() { + return 0; + } + + let info = &RAW_MAP[tag]; + let efuse_val = Self::rtc_table_get_raw_efuse_value(tag) * info.multiplier; + efuse_val + info.base + Self::rtc_table_get_parsed_efuse_value(info.dependency) + } + + /// Calculates the coeff_b from the calculate_characterization_coefficient + pub fn rtc_calib_coeff_b(adcn: usize, atten: Attenuation) -> Option { + if adcn > 2 || adcn == 0 { + return None; + } + let unit = (adcn - 1) as u8; + let (_, calib_version) = Self::block_version(); + let version_number = calib_version; + + match version_number { + 1 => { + let low = Self::rtc_table_get_parsed_efuse_value(Self::rtc_table_get_tag( + version_number, + unit, + atten, + RtcCalibParam::V1VLow, + )?); + let high = Self::rtc_table_get_parsed_efuse_value(Self::rtc_table_get_tag( + version_number, + unit, + atten, + RtcCalibParam::V1VHigh, + )?); + + let vhigh = RTC_CALIB_V_HIGH[atten as usize]; + let vlow = RTC_CALIB_V_LOW; + let dx = high - low; + Some((vlow * high - vhigh * low) / dx) + } + 2 => Some(0), + _ => None, + } + } + /// The value to pass to set_init_code. Only present in version 2 of the + /// efuse. + pub fn rtc_calib_init_code(adcn: usize, atten: Attenuation) -> Option { + if adcn > 2 || adcn == 0 { + return None; + } + let unit = (adcn - 1) as u8; + let (_, calib_version) = Self::block_version(); + let version_number = calib_version; + + if version_number == 2 { + let icode = Self::rtc_table_get_parsed_efuse_value(Self::rtc_table_get_tag( + version_number, + unit, + atten, + RtcCalibParam::V2VInit, + )?); + Some(icode as u16) + } else { + None + } + } + + /// Return the calibration voltage in mV. It's only used as dy in the + /// slope calculation of the AdcCalLine::new_cal calibration. Correct it + /// to be ready for this calculation. + pub fn rtc_calib_cal_mv(adcn: usize, atten: Attenuation) -> u16 { + if adcn > 2 || adcn == 0 { + return 0; + } + let _unit = (adcn - 1) as u8; + + let index = atten as usize; + if index >= RTC_CALIB_V_HIGH.len() { + return 0; + } + + let (_, calib_version) = Self::block_version(); + let version_number = calib_version; + + // Note: ... - ..._V_LOW because it's used as dy to calculate the slope in + // AdcCalLine::new_cal + (match version_number { + 1 => RTC_CALIB_V_HIGH[index] - RTC_CALIB_V_LOW, + _ => RTC_CALIB_V_HIGH[index], + }) as u16 + } + + /// Return the calibration adc value. It's only used as dx in the + /// slope calculation of the AdcCalLine::new_cal calibration. Correct it + /// to be ready for this calculation. + pub fn rtc_calib_cal_code(adcn: usize, atten: Attenuation) -> Option { + if adcn > 2 || adcn == 0 { + return None; + } + let unit = (adcn - 1) as u8; + let (_, calib_version) = Self::block_version(); + let version_number = calib_version; + + match version_number { + 1 => { + let low = Self::rtc_table_get_parsed_efuse_value(Self::rtc_table_get_tag( + version_number, + unit, + atten, + RtcCalibParam::V1VLow, + )?); + let high = Self::rtc_table_get_parsed_efuse_value(Self::rtc_table_get_tag( + version_number, + unit, + atten, + RtcCalibParam::V1VHigh, + )?); + // Note: Not just high, but dx, because its purpose is in AdcCalLine::new_cal to + // compute the slope + let dx = high - low; + Some(dx as u16) + } + 2 => { + let high = Self::rtc_table_get_parsed_efuse_value(Self::rtc_table_get_tag( + version_number, + unit, + atten, + RtcCalibParam::V2VHigh, + )?); + Some(high as u16) + } + _ => None, + } + } } #[derive(Debug, Clone, Copy, strum::FromRepr)]