Skip to main content

esp_hal/efuse/esp32s3/
mod.rs

1use crate::{analog::adc::Attenuation, peripherals::EFUSE};
2
3#[cfg_attr(not(feature = "unstable"), allow(dead_code))]
4mod fields;
5#[instability::unstable]
6pub use fields::*;
7
8/// Selects which ADC the eFuse calibration data applies to.
9#[instability::unstable]
10pub enum AdcCalibUnit {
11    /// Selects efuse calibration data for ADC1.
12    ADC1,
13    /// Selects efuse calibration data for ADC2.
14    ADC2,
15}
16
17/// Returns whether SPI boot encryption is enabled.
18#[instability::unstable]
19pub fn flash_encryption() -> bool {
20    !super::read_field_le::<u8>(SPI_BOOT_CRYPT_CNT)
21        .count_ones()
22        .is_multiple_of(2)
23}
24
25/// Returns the multiplier for the timeout value of the RWDT STAGE 0 register.
26#[instability::unstable]
27pub fn rwdt_multiplier() -> u8 {
28    super::read_field_le::<u8>(WDT_DELAY_SEL)
29}
30
31/// Returns the eFuse block version.
32///
33/// see <https://github.com/espressif/esp-idf/blob/dc016f5987/components/hal/efuse_hal.c#L27-L30>
34#[instability::unstable]
35pub fn block_version() -> (u8, u8) {
36    // see <https://github.com/espressif/esp-idf/blob/dc016f5987/components/hal/esp32s3/include/hal/efuse_ll.h#L65-L73>
37    // <https://github.com/espressif/esp-idf/blob/903af13e8/components/efuse/esp32s3/esp_efuse_table.csv#L196>
38    (
39        super::read_field_le::<u8>(BLK_VERSION_MAJOR),
40        super::read_field_le::<u8>(BLK_VERSION_MINOR),
41    )
42}
43
44/// Returns the version of RTC calibration block.
45///
46/// see <https://github.com/espressif/esp-idf/blob/903af13e8/components/efuse/esp32s3/esp_efuse_rtc_calib.c#L15>
47#[instability::unstable]
48pub fn rtc_calib_version() -> u8 {
49    let (major, _minor) = block_version();
50
51    if major == 1 { 1 } else { 0 }
52}
53
54/// Returns the ADC initial code for specified attenuation from efuse.
55///
56/// see <https://github.com/espressif/esp-idf/blob/903af13e8/components/efuse/esp32s3/esp_efuse_rtc_calib.c#L28>
57#[instability::unstable]
58pub fn rtc_calib_init_code(unit: AdcCalibUnit, atten: Attenuation) -> Option<u16> {
59    let version = rtc_calib_version();
60
61    if version != 1 {
62        return None;
63    }
64
65    let adc_icode_diff: [u16; 4] = match unit {
66        AdcCalibUnit::ADC1 => [
67            super::read_field_le(ADC1_INIT_CODE_ATTEN0),
68            super::read_field_le(ADC1_INIT_CODE_ATTEN1),
69            super::read_field_le(ADC1_INIT_CODE_ATTEN2),
70            super::read_field_le(ADC1_INIT_CODE_ATTEN3),
71        ],
72        AdcCalibUnit::ADC2 => [
73            super::read_field_le(ADC2_INIT_CODE_ATTEN0),
74            super::read_field_le(ADC2_INIT_CODE_ATTEN1),
75            super::read_field_le(ADC2_INIT_CODE_ATTEN2),
76            super::read_field_le(ADC2_INIT_CODE_ATTEN3),
77        ],
78    };
79
80    // Version 1 logic for calculating ADC ICode based on EFUSE burnt value
81
82    let mut adc_icode = [0; 4];
83    match unit {
84        AdcCalibUnit::ADC1 => {
85            adc_icode[0] = adc_icode_diff[0] + 1850;
86            adc_icode[1] = adc_icode_diff[1] + adc_icode[0] + 90;
87            adc_icode[2] = adc_icode_diff[2] + adc_icode[1];
88            adc_icode[3] = adc_icode_diff[3] + adc_icode[2] + 70;
89        }
90        AdcCalibUnit::ADC2 => {
91            adc_icode[0] = adc_icode_diff[0] + 2020;
92            adc_icode[1] = adc_icode_diff[1] + adc_icode[0];
93            adc_icode[2] = adc_icode_diff[2] + adc_icode[1];
94            adc_icode[3] = adc_icode_diff[3] + adc_icode[2];
95        }
96    }
97
98    Some(
99        adc_icode[match atten {
100            Attenuation::_0dB => 0,
101            Attenuation::_2p5dB => 1,
102            Attenuation::_6dB => 2,
103            Attenuation::_11dB => 3,
104        }],
105    )
106}
107
108/// Returns the ADC reference point voltage for specified attenuation in millivolts.
109///
110/// see <https://github.com/espressif/esp-idf/blob/903af13e8/components/efuse/esp32s3/esp_efuse_rtc_calib.c#L63>
111#[instability::unstable]
112pub fn rtc_calib_cal_mv(_unit: AdcCalibUnit, _atten: Attenuation) -> u16 {
113    850
114}
115
116/// Returns the ADC reference point digital code for specified attenuation.
117///
118/// see <https://github.com/espressif/esp-idf/blob/903af13e8/components/efuse/esp32s3/esp_efuse_rtc_calib.c#L63>
119#[instability::unstable]
120pub fn rtc_calib_cal_code(unit: AdcCalibUnit, atten: Attenuation) -> Option<u16> {
121    let version = rtc_calib_version();
122
123    if version != 1 {
124        return None;
125    }
126
127    let adc_vol_diff: [u16; 8] = [
128        super::read_field_le(ADC1_CAL_VOL_ATTEN0),
129        super::read_field_le(ADC1_CAL_VOL_ATTEN1),
130        super::read_field_le(ADC1_CAL_VOL_ATTEN2),
131        super::read_field_le(ADC1_CAL_VOL_ATTEN3),
132        super::read_field_le(ADC2_CAL_VOL_ATTEN0),
133        super::read_field_le(ADC2_CAL_VOL_ATTEN1),
134        super::read_field_le(ADC2_CAL_VOL_ATTEN2),
135        super::read_field_le(ADC2_CAL_VOL_ATTEN3),
136    ];
137
138    let mut adc1_vol = [0; 4];
139    let mut adc2_vol = [0; 4];
140    adc1_vol[3] = adc_vol_diff[3] + 900;
141    adc1_vol[2] = adc_vol_diff[2] + adc1_vol[3] + 800;
142    adc1_vol[1] = adc_vol_diff[1] + adc1_vol[2] + 700;
143    adc1_vol[0] = adc_vol_diff[0] + adc1_vol[1] + 800;
144    adc2_vol[3] = adc1_vol[3] - adc_vol_diff[7] + 15;
145    adc2_vol[2] = adc1_vol[2] - adc_vol_diff[6] + 20;
146    adc2_vol[1] = adc1_vol[1] - adc_vol_diff[5] + 10;
147    adc2_vol[0] = adc1_vol[0] - adc_vol_diff[4] + 40;
148
149    let atten = match atten {
150        Attenuation::_0dB => 0,
151        Attenuation::_2p5dB => 1,
152        Attenuation::_6dB => 2,
153        Attenuation::_11dB => 3,
154    };
155
156    Some(match unit {
157        AdcCalibUnit::ADC1 => adc1_vol[atten],
158        AdcCalibUnit::ADC2 => adc2_vol[atten],
159    })
160}
161
162/// Returns the major hardware revision.
163#[instability::unstable]
164pub fn major_chip_version() -> u8 {
165    super::read_field_le(WAFER_VERSION_MAJOR)
166}
167
168/// Returns the minor hardware revision.
169#[instability::unstable]
170pub fn minor_chip_version() -> u8 {
171    super::read_field_le::<u8>(WAFER_VERSION_MINOR_HI) << 3
172        | super::read_field_le::<u8>(WAFER_VERSION_MINOR_LO)
173}
174
175#[derive(Debug, Clone, Copy, strum::FromRepr)]
176#[repr(u32)]
177pub(crate) enum EfuseBlock {
178    Block0,
179    Block1,
180    Block2,
181    Block3,
182    Block4,
183    Block5,
184    Block6,
185    Block7,
186    Block8,
187    Block9,
188    Block10,
189}
190
191impl EfuseBlock {
192    pub(crate) fn address(self) -> *const u32 {
193        let efuse = EFUSE::regs();
194        match self {
195            Self::Block0 => efuse.rd_wr_dis().as_ptr(),
196            Self::Block1 => efuse.rd_mac_spi_sys_0().as_ptr(),
197            Self::Block2 => efuse.rd_sys_part1_data0().as_ptr(),
198            Self::Block3 => efuse.rd_usr_data0().as_ptr(),
199            Self::Block4 => efuse.rd_key0_data0().as_ptr(),
200            Self::Block5 => efuse.rd_key1_data0().as_ptr(),
201            Self::Block6 => efuse.rd_key2_data0().as_ptr(),
202            Self::Block7 => efuse.rd_key3_data0().as_ptr(),
203            Self::Block8 => efuse.rd_key4_data0().as_ptr(),
204            Self::Block9 => efuse.rd_key5_data0().as_ptr(),
205            Self::Block10 => efuse.rd_sys_part2_data0().as_ptr(),
206        }
207    }
208}