From 1b49a1674eb32f17d45fad2edab7e77af1ca55de Mon Sep 17 00:00:00 2001 From: gaoxu Date: Mon, 6 Jan 2025 11:04:29 +0800 Subject: [PATCH] feat(adc): support ADC calibration on ESP32P4 --- .../src/bootloader_random_esp32p4.c | 16 +- .../driver/test_apps/.build-test-rules.yml | 3 - .../legacy_adc_driver/main/test_legacy_adc.c | 8 +- .../legacy_adc_driver/pytest_legacy_adc.py | 1 + .../efuse/esp32p4/esp_efuse_rtc_calib.c | 190 ++++++++++++++++-- .../esp32p4/include/esp_efuse_rtc_calib.h | 19 +- .../esp32p4/curve_fitting_coefficients.c | 88 ++++++++ .../esp32p4/include/adc_cali_schemes.h | 2 +- .../test_apps/adc/main/test_common_adc.h | 8 +- components/hal/esp32p4/include/hal/adc_ll.h | 82 +++++++- .../esp32p4/include/soc/Kconfig.soc_caps.in | 10 +- .../soc/esp32p4/include/soc/regi2c_saradc.h | 92 ++++----- components/soc/esp32p4/include/soc/soc_caps.h | 4 +- 13 files changed, 433 insertions(+), 90 deletions(-) create mode 100644 components/esp_adc/esp32p4/curve_fitting_coefficients.c diff --git a/components/bootloader_support/src/bootloader_random_esp32p4.c b/components/bootloader_support/src/bootloader_random_esp32p4.c index 41d45061f9..5fdcb42bcb 100644 --- a/components/bootloader_support/src/bootloader_random_esp32p4.c +++ b/components/bootloader_support/src/bootloader_random_esp32p4.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -30,8 +30,8 @@ static void adc1_fix_initcode_set(uint32_t initcode_value) { uint32_t msb = initcode_value >> 8; uint32_t lsb = initcode_value & 0xff; - REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SAR_ADC_SAR1_INIT_CODE_MSB, msb); - REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SAR_ADC_SAR1_INIT_CODE_LSB, lsb); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_HIGH_ADDR, msb); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_LOW_ADDR, lsb); } //total 4 tables @@ -100,14 +100,8 @@ void bootloader_random_disable(void) // disable analog i2c master clock ANALOG_CLOCK_DISABLE(); - //TODO IDF-4714 - // disable timer - REG_CLR_BIT(ADC_CTRL2_REG, ADC_TIMER_EN); - // Write reset value of this register - REG_WRITE(ADC_SAR1_PATT_TAB1_REG, 0xFFFFFF); - // Revert ADC I2C configuration and initial voltage source setting - REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SAR_ADC_SAR1_INIT_CODE_MSB, 0); - REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SAR_ADC_SAR1_INIT_CODE_LSB, 0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_LOW_ADDR, 0); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_HIGH_ADDR, 0); REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SAR_ADC_ENT_VDD_GRP1, 0); REGI2C_WRITE_MASK(I2C_SAR_ADC, I2C_SAR_ADC_DTEST_VDD_GRP1, 0); diff --git a/components/driver/test_apps/.build-test-rules.yml b/components/driver/test_apps/.build-test-rules.yml index 5554901f8c..f638e5ed55 100644 --- a/components/driver/test_apps/.build-test-rules.yml +++ b/components/driver/test_apps/.build-test-rules.yml @@ -18,9 +18,6 @@ components/driver/test_apps/legacy_adc_driver: disable: - if: SOC_ADC_SUPPORTED != 1 disable_test: - - if: IDF_TARGET == "esp32p4" - temporary: true - reason: lack of runners, TODO IDF-9573 - if: IDF_TARGET == "esp32c61" temporary: true reason: lack of runners diff --git a/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c b/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c index 15f88e99b0..327fefa051 100644 --- a/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c +++ b/components/driver/test_apps/legacy_adc_driver/main/test_legacy_adc.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Unlicense OR CC0-1.0 */ @@ -69,10 +69,10 @@ #define ADC_TEST_HIGH_THRESH 200 #elif CONFIG_IDF_TARGET_ESP32P4 -#define ADC_TEST_LOW_VAL 2152 -#define ADC_TEST_LOW_THRESH 200 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 10 -#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_VAL 3360 #define ADC_TEST_HIGH_THRESH 200 #elif CONFIG_IDF_TARGET_ESP32C5 diff --git a/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py b/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py index b311f7b3a8..064d9449ab 100644 --- a/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py +++ b/components/driver/test_apps/legacy_adc_driver/pytest_legacy_adc.py @@ -11,6 +11,7 @@ from pytest_embedded import Dut @pytest.mark.esp32c6 @pytest.mark.esp32h2 @pytest.mark.esp32c5 +@pytest.mark.esp32p4 @pytest.mark.adc @pytest.mark.parametrize( 'config', diff --git a/components/efuse/esp32p4/esp_efuse_rtc_calib.c b/components/efuse/esp32p4/esp_efuse_rtc_calib.c index db583af99e..74a6687c37 100644 --- a/components/efuse/esp32p4/esp_efuse_rtc_calib.c +++ b/components/efuse/esp32p4/esp_efuse_rtc_calib.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,30 +8,190 @@ #include "esp_efuse.h" #include "esp_efuse_table.h" #include "esp_efuse_rtc_calib.h" +#include "hal/efuse_hal.h" +#include "hal/adc_types.h" + +/** + * @brief Get the signed value by the raw data that read from eFuse + * @param data The raw data that read from eFuse + * @param sign_bit The index of the sign bit, start from 0 + */ +#define RTC_CALIB_GET_SIGNED_VAL(data, sign_bit) ((data & BIT##sign_bit) ? -(int)(data & ~BIT##sign_bit) : (int)data) int esp_efuse_rtc_calib_get_ver(void) { - //TODO: IDF-7467, eFuses are not defined yet - return 0; + uint32_t cali_version = 0; + uint32_t blk_ver = efuse_hal_blk_version(); + if (blk_ver >= 1 && blk_ver < 100) { + cali_version = ESP_EFUSE_ADC_CALIB_VER1; + } else { + ESP_LOGW("eFuse", "calibration efuse version does not match, set default version to 0"); + } + + return cali_version; } uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten) { - //TODO: IDF-7467, check below, eFuses are not defined yet - (void) version; - (void) adc_unit; - (void) atten; - return 0; + /* Version validation should be guaranteed in the caller */ + assert(atten >=0 && atten < 4); + + const esp_efuse_desc_t** init_code_efuse; + if (adc_unit == 0) { + if (atten == 0) { + init_code_efuse = ESP_EFUSE_ADC1_AVE_INITCODE_ATTEN0; + } else if (atten == 1) { + init_code_efuse = ESP_EFUSE_ADC1_AVE_INITCODE_ATTEN1; + } else if (atten == 2) { + init_code_efuse = ESP_EFUSE_ADC1_AVE_INITCODE_ATTEN2; + } else { + init_code_efuse = ESP_EFUSE_ADC1_AVE_INITCODE_ATTEN3; + } + } else { + if (atten == 0) { + init_code_efuse = ESP_EFUSE_ADC2_AVE_INITCODE_ATTEN0; + } else if (atten == 1) { + init_code_efuse = ESP_EFUSE_ADC2_AVE_INITCODE_ATTEN1; + } else if (atten == 2) { + init_code_efuse = ESP_EFUSE_ADC2_AVE_INITCODE_ATTEN2; + } else { + init_code_efuse = ESP_EFUSE_ADC2_AVE_INITCODE_ATTEN3; + } + } + + int init_code_size = esp_efuse_get_field_size(init_code_efuse); + assert(init_code_size == 10); + + uint32_t init_code = 0; + ESP_ERROR_CHECK(esp_efuse_read_field_blob(init_code_efuse, &init_code, init_code_size)); + + return init_code + 1400; // version 1 logic } -esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, int atten, uint32_t* out_digi, uint32_t* out_vol_mv) +esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, uint32_t adc_unit, int atten, uint32_t* out_digi, uint32_t* out_vol_mv) { - //TODO: IDF-7467, check below, eFuses are not defined yet - (void) version; - (void) atten; - (void) out_digi; - (void) out_vol_mv; - return ESP_ERR_NOT_SUPPORTED; + const esp_efuse_desc_t** cal_vol_adc1_efuse[4] = { + ESP_EFUSE_ADC1_HI_DOUT_ATTEN0, + ESP_EFUSE_ADC1_HI_DOUT_ATTEN1, + ESP_EFUSE_ADC1_HI_DOUT_ATTEN2, + ESP_EFUSE_ADC1_HI_DOUT_ATTEN3, + }; + + const esp_efuse_desc_t** cal_vol_adc2_efuse[4] = { + ESP_EFUSE_ADC2_HI_DOUT_ATTEN0, + ESP_EFUSE_ADC2_HI_DOUT_ATTEN1, + ESP_EFUSE_ADC2_HI_DOUT_ATTEN2, + ESP_EFUSE_ADC2_HI_DOUT_ATTEN3, + }; + + + const uint32_t input_vout_mv[1][4] = { + {600, 800, 1200, 2300}, // Calibration V1 coefficients + }; + + if ((version < ESP_EFUSE_ADC_CALIB_VER_MIN) || + (version > ESP_EFUSE_ADC_CALIB_VER_MAX)) { + return ESP_ERR_INVALID_ARG; + } + if (atten >= 4 || atten < 0) { + return ESP_ERR_INVALID_ARG; + } + + assert(cal_vol_adc1_efuse[atten][0]->bit_count == 10); + assert(cal_vol_adc2_efuse[atten][0]->bit_count == 10); + + uint32_t cal_vol = 0; + esp_err_t ret = ESP_OK; + if (adc_unit == ADC_UNIT_1) { + ret = esp_efuse_read_field_blob(cal_vol_adc1_efuse[atten], &cal_vol, cal_vol_adc1_efuse[atten][0]->bit_count); + } else { + ret = esp_efuse_read_field_blob(cal_vol_adc2_efuse[atten], &cal_vol, cal_vol_adc2_efuse[atten][0]->bit_count); + } + + if (ret != ESP_OK) { + return ret; + } + uint32_t chk_offset; + if (atten == 0) { + chk_offset = 2300; + } else if (atten == 1) { + chk_offset = 2300; + } else if (atten == 2) { + chk_offset = 2350; + } else { + chk_offset = 2350; + } + + *out_digi = chk_offset + RTC_CALIB_GET_SIGNED_VAL(cal_vol, 9); + *out_vol_mv = input_vout_mv[VER2IDX(version)][atten]; + + return ESP_OK; +} + +int esp_efuse_rtc_calib_get_chan_compens(int version, uint32_t adc_unit, uint32_t adc_channel, int atten) +{ + /* Version validation should be guaranteed in the caller */ + assert(atten < 4); + assert(adc_channel < SOC_ADC_CHANNEL_NUM(adc_unit)); + + const esp_efuse_desc_t** chan_diff_efuse = NULL; + if (adc_unit == ADC_UNIT_1) { + switch (adc_channel) { + case 0: + chan_diff_efuse = ESP_EFUSE_ADC1_CH0_ATTEN0_INITCODE_DIFF; + break; + case 1: + chan_diff_efuse = ESP_EFUSE_ADC1_CH1_ATTEN0_INITCODE_DIFF; + break; + case 2: + chan_diff_efuse = ESP_EFUSE_ADC1_CH2_ATTEN0_INITCODE_DIFF; + break; + case 3: + chan_diff_efuse = ESP_EFUSE_ADC1_CH3_ATTEN0_INITCODE_DIFF; + break; + case 4: + chan_diff_efuse = ESP_EFUSE_ADC1_CH4_ATTEN0_INITCODE_DIFF; + break; + case 5: + chan_diff_efuse = ESP_EFUSE_ADC1_CH5_ATTEN0_INITCODE_DIFF; + break; + case 6: + chan_diff_efuse = ESP_EFUSE_ADC1_CH6_ATTEN0_INITCODE_DIFF; + break; + default: + chan_diff_efuse = ESP_EFUSE_ADC1_CH7_ATTEN0_INITCODE_DIFF; + break; + } + } else { + switch (adc_channel) { + case 0: + chan_diff_efuse = ESP_EFUSE_ADC2_CH0_ATTEN0_INITCODE_DIFF; + break; + case 1: + chan_diff_efuse = ESP_EFUSE_ADC2_CH1_ATTEN0_INITCODE_DIFF; + break; + case 2: + chan_diff_efuse = ESP_EFUSE_ADC2_CH2_ATTEN0_INITCODE_DIFF; + break; + case 3: + chan_diff_efuse = ESP_EFUSE_ADC2_CH3_ATTEN0_INITCODE_DIFF; + break; + case 4: + chan_diff_efuse = ESP_EFUSE_ADC2_CH4_ATTEN0_INITCODE_DIFF; + break; + default: + chan_diff_efuse = ESP_EFUSE_ADC2_CH5_ATTEN0_INITCODE_DIFF; + break; + } + } + + + int chan_diff_size = esp_efuse_get_field_size(chan_diff_efuse); + assert(chan_diff_size == 4); + uint32_t chan_diff = 0; + ESP_ERROR_CHECK(esp_efuse_read_field_blob(chan_diff_efuse, &chan_diff, chan_diff_size)); + + return RTC_CALIB_GET_SIGNED_VAL(chan_diff, 3) * (4 - atten); } esp_err_t esp_efuse_rtc_calib_get_tsens_val(float* tsens_cal) diff --git a/components/efuse/esp32p4/include/esp_efuse_rtc_calib.h b/components/efuse/esp32p4/include/esp_efuse_rtc_calib.h index 0a8f6e7c16..b3b9e5092c 100644 --- a/components/efuse/esp32p4/include/esp_efuse_rtc_calib.h +++ b/components/efuse/esp32p4/include/esp_efuse_rtc_calib.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,10 @@ extern "C" { #endif //This is the ADC calibration value version burnt in efuse -#define ESP_EFUSE_ADC_CALIB_VER 1 +#define ESP_EFUSE_ADC_CALIB_VER1 1 +#define ESP_EFUSE_ADC_CALIB_VER_MIN ESP_EFUSE_ADC_CALIB_VER1 +#define ESP_EFUSE_ADC_CALIB_VER_MAX ESP_EFUSE_ADC_CALIB_VER1 +#define VER2IDX(ver) ((ver) - 1) // Version number to index number of the array /** * @brief Get the RTC calibration efuse version @@ -31,6 +34,16 @@ int esp_efuse_rtc_calib_get_ver(void); */ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten); +/** + * @brief Get the channel specific calibration compensation + * + * @param version Version of the stored efuse + * @param adc_unit ADC unit. Not used, for compatibility. ESP32H2 only supports one ADC unit + * @param atten Attenuation of the init code + * @return The channel calibration compensation value + */ +int esp_efuse_rtc_calib_get_chan_compens(int version, uint32_t adc_unit, uint32_t adc_channel, int atten); + /** * @brief Get the calibration digits stored in the efuse, and the corresponding voltage. * @@ -42,7 +55,7 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a * - ESP_ERR_INVALID_ARG: If efuse version or attenuation is invalid * - ESP_OK: if success */ -esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, int atten, uint32_t* out_digi, uint32_t* out_vol_mv); +esp_err_t esp_efuse_rtc_calib_get_cal_voltage(int version, uint32_t adc_unit, int atten, uint32_t* out_digi, uint32_t* out_vol_mv); /** * @brief Get the temperature sensor calibration number delta_T stored in the efuse. diff --git a/components/esp_adc/esp32p4/curve_fitting_coefficients.c b/components/esp_adc/esp32p4/curve_fitting_coefficients.c new file mode 100644 index 0000000000..84144124bd --- /dev/null +++ b/components/esp_adc/esp32p4/curve_fitting_coefficients.c @@ -0,0 +1,88 @@ +/* + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "esp_efuse_rtc_calib.h" +#include "../curve_fitting_coefficients.h" + +#define COEFF_VERSION_NUM 1 // Currently P4 has one versions of curve calibration schemes +#define COEFF_GROUP_NUM 4 +#define TERM_MAX 2 + +/** + * @note Error Calculation + * Coefficients for calculating the reading voltage error. + * Four sets of coefficients for atten0 ~ atten3 respectively. + * + * For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient. + * + * @note {0,0} stands for unused item + * @note In case of the overflow, these coefficients are recorded as Absolute Value + * @note For atten0 ~ 3, error = (K0 * X^0) + (K1 * X^1) + * @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered. + */ +const static uint64_t adc1_error_coef_atten[COEFF_VERSION_NUM][COEFF_GROUP_NUM][TERM_MAX][2] = { + /* Coefficients of calibration version 1 */ + { + {{7170501832480995, 1e16}, {10598497992115, 1e16}}, //atten0 + {{9960085535084866, 1e16}, {15840076608145, 1e16}}, //atten1 + {{14711053224678996, 1e16}, {1594266424857, 1e17}}, //atten2 + {{28811493455181565, 1e16}, {10082311568625, 1e16}}, //atten3 + }, +}; + +const static uint64_t adc2_error_coef_atten[COEFF_VERSION_NUM][COEFF_GROUP_NUM][TERM_MAX][2] = { + /* Coefficients of calibration version 1 */ + { + {{4900967548489932, 1e16}, {5037402667913, 1e16}}, //atten0 + {{7296214814536025, 1e16}, {11021577596635, 1e16}}, //atten1 + {{10991620450220592, 1e16}, {11623930881896, 1e16}}, //atten2 + {{24421401024626730, 1e16}, {9458501263393, 1e16}}, //atten3 + }, +}; + +/** + * Term sign ADC1 + */ +const static int32_t adc1_error_sign[COEFF_VERSION_NUM][COEFF_GROUP_NUM][TERM_MAX] = { + /* Coefficient sign of calibration version 1 */ + { + {-1, 1}, //atten0 + {-1, 1}, //atten1 + {-1, 1}, //atten2 + {-1, 1}, //atten3 + }, +}; + +/** + * Term sign ADC2 + */ +const static int32_t adc2_error_sign[COEFF_VERSION_NUM][COEFF_GROUP_NUM][TERM_MAX] = { + /* Coefficient sign of calibration version 1 */ + { + {-1, 1}, //atten0 + {-1, 1}, //atten1 + {-1, 1}, //atten2 + {-1, 1}, //atten3 + }, +}; + +void curve_fitting_get_second_step_coeff(const adc_cali_curve_fitting_config_t *config, cali_chars_second_step_t *ctx) +{ + uint32_t adc_calib_ver = esp_efuse_rtc_calib_get_ver(); + assert((adc_calib_ver >= ESP_EFUSE_ADC_CALIB_VER_MIN) && + (adc_calib_ver <= ESP_EFUSE_ADC_CALIB_VER_MAX)); + + ctx->term_num = 2; + + ctx->coeff = config->unit_id == ADC_UNIT_1 ? + adc1_error_coef_atten[VER2IDX(adc_calib_ver)][config->atten] : + adc2_error_coef_atten[VER2IDX(adc_calib_ver)][config->atten]; + ctx->sign = config->unit_id == ADC_UNIT_1 ? + adc1_error_sign[VER2IDX(adc_calib_ver)][config->atten] : + adc2_error_sign[VER2IDX(adc_calib_ver)][config->atten]; +} diff --git a/components/esp_adc/esp32p4/include/adc_cali_schemes.h b/components/esp_adc/esp32p4/include/adc_cali_schemes.h index 16dc6be4f1..96067994e0 100644 --- a/components/esp_adc/esp32p4/include/adc_cali_schemes.h +++ b/components/esp_adc/esp32p4/include/adc_cali_schemes.h @@ -12,4 +12,4 @@ * @brief Supported calibration schemes */ -//Now no scheme supported +#define ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED 1 diff --git a/components/esp_adc/test_apps/adc/main/test_common_adc.h b/components/esp_adc/test_apps/adc/main/test_common_adc.h index ac6d07ca87..2bdfa9fe98 100644 --- a/components/esp_adc/test_apps/adc/main/test_common_adc.h +++ b/components/esp_adc/test_apps/adc/main/test_common_adc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -88,10 +88,10 @@ extern "C" { #define ADC_TEST_HIGH_THRESH 200 #elif CONFIG_IDF_TARGET_ESP32P4 -#define ADC_TEST_LOW_VAL 2152 -#define ADC_TEST_LOW_THRESH 200 +#define ADC_TEST_LOW_VAL 0 +#define ADC_TEST_LOW_THRESH 10 -#define ADC_TEST_HIGH_VAL 4095 +#define ADC_TEST_HIGH_VAL 3360 #define ADC_TEST_HIGH_VAL_DMA 4095 #define ADC_TEST_HIGH_THRESH 200 diff --git a/components/hal/esp32p4/include/hal/adc_ll.h b/components/hal/esp32p4/include/hal/adc_ll.h index b830826039..3b18c4d3f2 100644 --- a/components/hal/esp32p4/include/hal/adc_ll.h +++ b/components/hal/esp32p4/include/hal/adc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -651,6 +651,86 @@ static inline void adc_ll_set_controller(adc_unit_t adc_n, adc_ll_controller_t c } } +/*--------------------------------------------------------------- + Calibration +---------------------------------------------------------------*/ + +/** + * @brief Set common calibration configuration. Should be shared with other parts (PWDET). + */ +__attribute__((always_inline)) +static inline void adc_ll_calibration_init(adc_unit_t adc_n) +{ + if (adc_n == ADC_UNIT_1) { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 4); + } else { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 4); + } +} + +/** + * Configure the registers for ADC calibration. You need to call the ``adc_ll_calibration_finish`` interface to resume after calibration. + * + * @note Different ADC units and different attenuation options use different calibration data (initial data). + * + * @param adc_n ADC index number. + * @param internal_gnd true: Disconnect from the IO port and use the internal GND as the calibration voltage. + * false: Use IO external voltage as calibration voltage. + */ +static inline void adc_ll_calibration_prepare(adc_unit_t adc_n, bool internal_gnd) +{ + /* Enable/disable internal connect GND (for calibration). */ + if (adc_n == ADC_UNIT_1) { + if (internal_gnd) { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 1); + } else { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0); + } + } else { + if (internal_gnd) { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 1); + } else { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 0); + } + } +} + +/** + * Resume register status after calibration. + * + * @param adc_n ADC index number. + */ +static inline void adc_ll_calibration_finish(adc_unit_t adc_n) +{ + if (adc_n == ADC_UNIT_1) { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0); + } else { //adc_n == ADC_UNIT_2 + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 0); + } +} + +/** + * Set the calibration result to ADC. + * + * @note Different ADC units and different attenuation options use different calibration data (initial data). + * + * @param adc_n ADC index number. + */ +__attribute__((always_inline)) +static inline void adc_ll_set_calibration_param(adc_unit_t adc_n, uint32_t param) +{ + uint8_t msb = param >> 8; + uint8_t lsb = param & 0xFF; + + if (adc_n == ADC_UNIT_1) { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_HIGH_ADDR, msb); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_INITIAL_CODE_LOW_ADDR, lsb); + } else { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_HIGH_ADDR, msb); + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_INITIAL_CODE_LOW_ADDR, lsb); + } +} + /*--------------------------------------------------------------- Oneshot Read ---------------------------------------------------------------*/ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index cecb381910..a08866b643 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -429,7 +429,15 @@ config SOC_ADC_RTC_MAX_BITWIDTH config SOC_ADC_CALIBRATION_V1_SUPPORTED bool - default n + default y + +config SOC_ADC_SELF_HW_CALI_SUPPORTED + bool + default y + +config SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED + bool + default y config SOC_ADC_SHARED_POWER bool diff --git a/components/soc/esp32p4/include/soc/regi2c_saradc.h b/components/soc/esp32p4/include/soc/regi2c_saradc.h index 725992d692..fa8dd1004c 100644 --- a/components/soc/esp32p4/include/soc/regi2c_saradc.h +++ b/components/soc/esp32p4/include/soc/regi2c_saradc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,62 +18,62 @@ #define I2C_SAR_ADC 0X69 #define I2C_SAR_ADC_HOSTID 0 -#define I2C_SARADC_TSENS_DAC 0x6 -#define I2C_SARADC_TSENS_DAC_MSB 3 -#define I2C_SARADC_TSENS_DAC_LSB 0 +#define ADC_SAR1_INITIAL_CODE_LOW_ADDR 0x0 +#define ADC_SAR1_INITIAL_CODE_LOW_ADDR_MSB 0x7 +#define ADC_SAR1_INITIAL_CODE_LOW_ADDR_LSB 0x0 -#define I2C_SAR_ADC_SAR1_INIT_CODE_LSB 0 -#define I2C_SAR_ADC_SAR1_INIT_CODE_LSB_MSB 7 -#define I2C_SAR_ADC_SAR1_INIT_CODE_LSB_LSB 0 +#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR 0x1 +#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_MSB 0x3 +#define ADC_SAR1_INITIAL_CODE_HIGH_ADDR_LSB 0x0 -#define I2C_SAR_ADC_SAR1_INIT_CODE_MSB 1 -#define I2C_SAR_ADC_SAR1_INIT_CODE_MSB_MSB 3 -#define I2C_SAR_ADC_SAR1_INIT_CODE_MSB_LSB 0 +#define ADC_SAR1_SAMPLE_CYCLE_ADDR 0x2 +#define ADC_SAR1_SAMPLE_CYCLE_ADDR_MSB 0x2 +#define ADC_SAR1_SAMPLE_CYCLE_ADDR_LSB 0x0 -#define I2C_SAR_ADC_ENT_VDD_GRP1 9 -#define I2C_SAR_ADC_ENT_VDD_GRP1_MSB 4 -#define I2C_SAR_ADC_ENT_VDD_GRP1_LSB 4 +#define ADC_SAR1_DREF_ADDR 0x2 +#define ADC_SAR1_DREF_ADDR_MSB 0x6 +#define ADC_SAR1_DREF_ADDR_LSB 0x4 -#define I2C_SAR_ADC_DTEST_VDD_GRP1 9 -#define I2C_SAR_ADC_DTEST_VDD_GRP1_MSB 3 -#define I2C_SAR_ADC_DTEST_VDD_GRP1_LSB 0 +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR 0x3 +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB 0x7 +#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB 0x0 -#define ADC_SAR1_SAMPLE_CYCLE_ADDR 0x2 -#define ADC_SAR1_SAMPLE_CYCLE_ADDR_MSB 0x2 -#define ADC_SAR1_SAMPLE_CYCLE_ADDR_LSB 0x0 +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR 0x4 +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB 0x3 +#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB 0x0 -#define ADC_SAR1_DREF_ADDR 0x2 -#define ADC_SAR1_DREF_ADDR_MSB 0x6 -#define ADC_SAR1_DREF_ADDR_LSB 0x4 +#define ADC_SAR2_SAMPLE_CYCLE_ADDR 0x5 +#define ADC_SAR2_SAMPLE_CYCLE_ADDR_MSB 0x2 +#define ADC_SAR2_SAMPLE_CYCLE_ADDR_LSB 0x0 -#define ADC_SAR2_INITIAL_CODE_LOW_ADDR 0x3 -#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_MSB 0x7 -#define ADC_SAR2_INITIAL_CODE_LOW_ADDR_LSB 0x0 +#define ADC_SAR2_DREF_ADDR 0x5 +#define ADC_SAR2_DREF_ADDR_MSB 0x6 +#define ADC_SAR2_DREF_ADDR_LSB 0x4 -#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR 0x4 -#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_MSB 0x3 -#define ADC_SAR2_INITIAL_CODE_HIGH_ADDR_LSB 0x0 +#define I2C_SARADC_TSENS_DAC 0x6 +#define I2C_SARADC_TSENS_DAC_MSB 0x3 +#define I2C_SARADC_TSENS_DAC_LSB 0x0 -#define ADC_SAR2_SAMPLE_CYCLE_ADDR 0x5 -#define ADC_SAR2_SAMPLE_CYCLE_ADDR_MSB 0x2 -#define ADC_SAR2_SAMPLE_CYCLE_ADDR_LSB 0x0 +#define ADC_SAR1_ENCAL_REF_ADDR 0x7 +#define ADC_SAR1_ENCAL_REF_ADDR_MSB 0X4 +#define ADC_SAR1_ENCAL_REF_ADDR_LSB 0X4 -#define ADC_SAR2_DREF_ADDR 0x5 -#define ADC_SAR2_DREF_ADDR_MSB 0x6 -#define ADC_SAR2_DREF_ADDR_LSB 0x4 +#define ADC_SAR1_ENCAL_GND_ADDR 0x7 +#define ADC_SAR1_ENCAL_GND_ADDR_MSB 0x5 +#define ADC_SAR1_ENCAL_GND_ADDR_LSB 0x5 -#define ADC_SAR1_ENCAL_REF_ADDR 0x7 -#define ADC_SAR1_ENCAL_REF_ADDR_MSB 4 -#define ADC_SAR1_ENCAL_REF_ADDR_LSB 4 +#define ADC_SAR2_ENCAL_REF_ADDR 0x7 +#define ADC_SAR2_ENCAL_REF_ADDR_MSB 0x6 +#define ADC_SAR2_ENCAL_REF_ADDR_LSB 0x6 -#define ADC_SAR1_ENCAL_GND_ADDR 0x7 -#define ADC_SAR1_ENCAL_GND_ADDR_MSB 5 -#define ADC_SAR1_ENCAL_GND_ADDR_LSB 5 +#define ADC_SAR2_ENCAL_GND_ADDR 0x7 +#define ADC_SAR2_ENCAL_GND_ADDR_MSB 0x7 +#define ADC_SAR2_ENCAL_GND_ADDR_LSB 0x7 -#define ADC_SAR2_ENCAL_REF_ADDR 0x7 -#define ADC_SAR2_ENCAL_REF_ADDR_MSB 6 -#define ADC_SAR2_ENCAL_REF_ADDR_LSB 6 +#define I2C_SAR_ADC_DTEST_VDD_GRP1 0x9 +#define I2C_SAR_ADC_DTEST_VDD_GRP1_MSB 0x3 +#define I2C_SAR_ADC_DTEST_VDD_GRP1_LSB 0x0 -#define ADC_SAR2_ENCAL_GND_ADDR 0x7 -#define ADC_SAR2_ENCAL_GND_ADDR_MSB 7 -#define ADC_SAR2_ENCAL_GND_ADDR_LSB 7 +#define I2C_SAR_ADC_ENT_VDD_GRP1 0x9 +#define I2C_SAR_ADC_ENT_VDD_GRP1_MSB 0x4 +#define I2C_SAR_ADC_ENT_VDD_GRP1_LSB 0x4 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 5805f43ae8..bf0dfa7909 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -144,7 +144,9 @@ #define SOC_ADC_RTC_MAX_BITWIDTH (12) /*!< Calibration */ -#define SOC_ADC_CALIBRATION_V1_SUPPORTED (0) /*!< support HW offset calibration version 1*/ +#define SOC_ADC_CALIBRATION_V1_SUPPORTED (1) /*!< support HW offset calibration version 1*/ +#define SOC_ADC_SELF_HW_CALI_SUPPORTED (1) /*!< support HW offset self calibration */ +#define SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED (1) /*!< support channel compensation to the HW offset calibration */ /*!< ADC power control is shared by PWDET, TempSensor */ #define SOC_ADC_SHARED_POWER 1