Skip to main content

esp_hal/efuse/esp32c6/
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 we are interested in the efuse calibration data for
9#[instability::unstable]
10pub enum AdcCalibUnit {
11    /// Select efuse calibration data for ADC1
12    ADC1,
13    /// Select efuse calibration data for ADC2
14    ADC2,
15}
16
17/// Get status of SPI boot encryption.
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/// Get 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/// Get 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/esp32c6/include/hal/efuse_ll.h#L65-L73>
37    // <https://github.com/espressif/esp-idf/blob/903af13e8/components/efuse/esp32c6/esp_efuse_table.csv#L156>
38    (
39        super::read_field_le::<u8>(BLK_VERSION_MAJOR),
40        super::read_field_le::<u8>(BLK_VERSION_MINOR),
41    )
42}
43
44/// Get a signed value from the raw data from eFuse.
45///
46/// `sign_bit` is the index of the sign bit, starting from 0.
47fn get_signed_val(data: u32, sign_bit: u32) -> i32 {
48    let sign_mask = 1u32 << sign_bit;
49    if data & sign_mask != 0 {
50        -((data & !sign_mask) as i32)
51    } else {
52        data as i32
53    }
54}
55
56/// Get version of RTC calibration block
57///
58/// See <https://github.com/espressif/esp-idf/blob/027613140/components/efuse/esp32c6/esp_efuse_rtc_calib.c#L20>
59#[instability::unstable]
60pub fn rtc_calib_version() -> u8 {
61    let (_major, minor) = block_version();
62    if minor == 1 {
63        1
64    } else if minor >= 2 {
65        2
66    } else {
67        0
68    }
69}
70
71/// Get ADC initial code for specified attenuation from efuse
72///
73/// See <https://github.com/espressif/esp-idf/blob/027613140/components/efuse/esp32c6/esp_efuse_rtc_calib.c#L35>
74#[instability::unstable]
75pub fn rtc_calib_init_code(_unit: AdcCalibUnit, atten: Attenuation) -> Option<u16> {
76    let version = rtc_calib_version();
77
78    if !(1..=2).contains(&version) {
79        return None;
80    }
81
82    // See <https://github.com/espressif/esp-idf/blob/027613140/components/efuse/esp32c6/esp_efuse_table.csv#L178-L181>
83    let init_code: u16 = super::read_field_le(match atten {
84        Attenuation::_0dB => ADC1_INIT_CODE_ATTEN0,
85        Attenuation::_2p5dB => ADC1_INIT_CODE_ATTEN1,
86        Attenuation::_6dB => ADC1_INIT_CODE_ATTEN2,
87        Attenuation::_11dB => ADC1_INIT_CODE_ATTEN3,
88    });
89
90    Some(init_code + 1600)
91}
92
93/// Get the channel specific calibration compensation
94///
95/// See <https://github.com/espressif/esp-idf/blob/027613140/components/efuse/esp32c6/esp_efuse_rtc_calib.c#L60>
96#[instability::unstable]
97pub fn rtc_calib_get_chan_compens(
98    _unit: AdcCalibUnit,
99    channel: u8,
100    atten: Attenuation,
101) -> Option<i32> {
102    let chan_diff: u32 = super::read_field_le(match channel {
103        0 => ADC1_INIT_CODE_ATTEN0_CH0,
104        1 => ADC1_INIT_CODE_ATTEN0_CH1,
105        2 => ADC1_INIT_CODE_ATTEN0_CH2,
106        3 => ADC1_INIT_CODE_ATTEN0_CH3,
107        4 => ADC1_INIT_CODE_ATTEN0_CH4,
108        5 => ADC1_INIT_CODE_ATTEN0_CH5,
109        _ => ADC1_INIT_CODE_ATTEN0_CH6,
110    });
111
112    Some(get_signed_val(chan_diff, 3) * (4 - atten as i32))
113}
114
115/// Get ADC reference point voltage for specified attenuation in millivolts
116///
117/// See <https://github.com/espressif/esp-idf/blob/027613140/components/efuse/esp32c6/esp_efuse_rtc_calib.c#L98>
118#[instability::unstable]
119pub fn rtc_calib_cal_mv(_unit: AdcCalibUnit, atten: Attenuation) -> u16 {
120    let version = rtc_calib_version();
121    let input_vout_mv = match version {
122        2 => [750, 1000, 1500, 2800],
123        _ => [400, 550, 750, 1370],
124    };
125
126    input_vout_mv[atten as usize]
127}
128
129/// Get ADC reference point digital code for specified attenuation
130///
131/// See <https://github.com/espressif/esp-idf/blob/027613140/components/efuse/esp32c6/esp_efuse_rtc_calib.c#L98>
132#[instability::unstable]
133pub fn rtc_calib_cal_code(_unit: AdcCalibUnit, atten: Attenuation) -> Option<u16> {
134    let version = rtc_calib_version();
135
136    if !(1..=2).contains(&version) {
137        return None;
138    }
139
140    // See <https://github.com/espressif/esp-idf/blob/027613140/components/efuse/esp32c6/esp_efuse_table.csv#L182-L185>
141    let cal_vol: u16 = super::read_field_le(match atten {
142        Attenuation::_0dB => ADC1_CAL_VOL_ATTEN0,
143        Attenuation::_2p5dB => ADC1_CAL_VOL_ATTEN1,
144        Attenuation::_6dB => ADC1_CAL_VOL_ATTEN2,
145        Attenuation::_11dB => ADC1_CAL_VOL_ATTEN3,
146    });
147
148    let chk_offset = if version == 1 {
149        1500
150    } else if atten == Attenuation::_6dB {
151        2900
152    } else {
153        2850
154    };
155
156    Some((chk_offset + get_signed_val(cal_vol as u32, 9)) as u16)
157}
158
159/// Returns the major hardware revision
160#[instability::unstable]
161pub fn major_chip_version() -> u8 {
162    super::read_field_le(WAFER_VERSION_MAJOR)
163}
164
165/// Returns the minor hardware revision
166#[instability::unstable]
167pub fn minor_chip_version() -> u8 {
168    super::read_field_le(WAFER_VERSION_MINOR)
169}
170
171#[derive(Debug, Clone, Copy, strum::FromRepr)]
172#[repr(u32)]
173pub(crate) enum EfuseBlock {
174    Block0,
175    Block1,
176    Block2,
177    Block3,
178    Block4,
179    Block5,
180    Block6,
181    Block7,
182    Block8,
183    Block9,
184    Block10,
185}
186
187impl EfuseBlock {
188    pub(crate) fn address(self) -> *const u32 {
189        let efuse = EFUSE::regs();
190        match self {
191            Self::Block0 => efuse.rd_wr_dis().as_ptr(),
192            Self::Block1 => efuse.rd_mac_spi_sys_0().as_ptr(),
193            Self::Block2 => efuse.rd_sys_part1_data0().as_ptr(),
194            Self::Block3 => efuse.rd_usr_data0().as_ptr(),
195            Self::Block4 => efuse.rd_key0_data0().as_ptr(),
196            Self::Block5 => efuse.rd_key1_data0().as_ptr(),
197            Self::Block6 => efuse.rd_key2_data0().as_ptr(),
198            Self::Block7 => efuse.rd_key3_data0().as_ptr(),
199            Self::Block8 => efuse.rd_key4_data0().as_ptr(),
200            Self::Block9 => efuse.rd_key5_data0().as_ptr(),
201            Self::Block10 => efuse.rd_sys_part2_data0().as_ptr(),
202        }
203    }
204}