Skip to content

Commit

Permalink
Merge branch 'feature/support_adc_calibration_on_h2_v5.2' into 'relea…
Browse files Browse the repository at this point in the history
…se/v5.2'

adc_cali: supported adc calibration v1 on ESP32H2 (v5.2)

See merge request espressif/esp-idf!26962
  • Loading branch information
jack0c committed Nov 9, 2023
2 parents e0286e2 + 1b07551 commit 4331ae7
Show file tree
Hide file tree
Showing 15 changed files with 260 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@
#define ADC_TEST_HIGH_VAL 3350
#define ADC_TEST_HIGH_THRESH 200

#elif CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-6216
#define ADC_TEST_LOW_VAL 2144
#define ADC_TEST_LOW_THRESH 200
#elif CONFIG_IDF_TARGET_ESP32H2
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 17

#define ADC_TEST_HIGH_VAL 4081
#define ADC_TEST_HIGH_VAL 3390
#define ADC_TEST_HIGH_THRESH 200

#endif
Expand Down
2 changes: 1 addition & 1 deletion components/efuse/esp32c6/include/esp_efuse_rtc_calib.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extern "C" {
#define ESP_EFUSE_ADC_CALIB_VER2 2
#define ESP_EFUSE_ADC_CALIB_VER_MIN ESP_EFUSE_ADC_CALIB_VER1
#define ESP_EFUSE_ADC_CALIB_VER_MAX ESP_EFUSE_ADC_CALIB_VER2
#define VER2IDX(ver) (ver - 1) // Version number to index number of the array
#define VER2IDX(ver) ((ver) - 1) // Version number to index number of the array
/**
* @brief Get the RTC calibration efuse version
*
Expand Down
114 changes: 114 additions & 0 deletions components/efuse/esp32h2/esp_efuse_rtc_calib.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,120 @@
#include <esp_bit_defs.h>
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_efuse_rtc_calib.h"
#include "hal/efuse_hal.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)
{
uint32_t cali_version = 0;
uint32_t blk_ver = efuse_hal_blk_version();
if (blk_ver >= 2) {
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)
{
/* Version validation should be guaranteed in the caller */
assert(atten >=0 && atten < 4);
(void) adc_unit;

const esp_efuse_desc_t** init_code_efuse;
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;
}

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 + 1600; // version 1 logic
}

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;
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;
default:
chan_diff_efuse = ESP_EFUSE_ADC1_CH4_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_cal_voltage(int version, uint32_t adc_unit, int atten, uint32_t* out_digi, uint32_t* out_vol_mv)
{
(void) adc_unit;
const esp_efuse_desc_t** cal_vol_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 uint32_t input_vout_mv[1][4] = {
{750, 1000, 1500, 2800}, // 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_efuse[atten][0]->bit_count == 10);

uint32_t cal_vol = 0;
esp_err_t ret = esp_efuse_read_field_blob(cal_vol_efuse[atten], &cal_vol, cal_vol_efuse[atten][0]->bit_count);
if (ret != ESP_OK) {
return ret;
}
uint32_t chk_offset = (atten == 2) ? 2970 : 2900;
*out_digi = chk_offset + RTC_CALIB_GET_SIGNED_VAL(cal_vol, 9);
*out_vol_mv = input_vout_mv[VER2IDX(version)][atten];
return ESP_OK;
}

esp_err_t esp_efuse_rtc_calib_get_tsens_val(float* tsens_cal)
{
Expand Down
22 changes: 17 additions & 5 deletions components/efuse/esp32h2/include/esp_efuse_rtc_calib.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -12,9 +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_VER_MIN ESP_EFUSE_ADC_CALIB_VER
#define ESP_EFUSE_ADC_CALIB_VER_MAX ESP_EFUSE_ADC_CALIB_VER
#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
Expand All @@ -33,18 +34,29 @@ 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.
*
* @param version Version of the stored efuse
* @param adc_unit ADC unit (not used on ESP32H2, for compatibility)
* @param atten Attenuation to use
* @param out_digi Output buffer of the digits
* @param out_vol_mv Output of the voltage, in mV
* @return
* - 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.
Expand Down
61 changes: 61 additions & 0 deletions components/esp_adc/esp32h2/curve_fitting_coefficients.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <stdio.h>
#include <stdint.h>
#include "esp_efuse_rtc_calib.h"
#include "../curve_fitting_coefficients.h"

#define COEFF_VERSION_NUM 1 // Currently H2 has one versions of curve calibration schemes
#define COEFF_GROUP_NUM 4
#define TERM_MAX 3

/**
* @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 ~ 2, error = (K0 * X^0) + (K1 * X^1)
* @note For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2)
* @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 */
{
{{5081991760658888, 1e16}, {7858995318513, 1e19}, {0, 1}}, //atten0
{{8359230818901277, 1e16}, {9025419089179, 1e19}, {0, 1}}, //atten1
{{1165668771581976, 1e15}, {8294679249061, 1e19}, {0, 1}}, //atten2
{{3637329628677273, 1e16}, {19607259738935, 1e18}, {7871689227, 1e16}}, //atten3
},
};

/**
* Term sign
*/
const static int32_t adc1_error_sign[COEFF_VERSION_NUM][COEFF_GROUP_NUM][TERM_MAX] = {
/* Coefficient sign of calibration version 1 */
{
{-1, 1, 1}, //atten0
{-1, 1, 1}, //atten1
{-1, 1, 1}, //atten2
{-1, -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 = 3;
ctx->coeff = adc1_error_coef_atten[VER2IDX(adc_calib_ver)][config->atten];
ctx->sign = adc1_error_sign[VER2IDX(adc_calib_ver)][config->atten];
}
2 changes: 1 addition & 1 deletion components/esp_adc/esp32h2/include/adc_cali_schemes.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
* @brief Supported calibration schemes
*/

//Now no scheme supported
#define ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED 1
10 changes: 5 additions & 5 deletions components/esp_adc/test_apps/adc/main/test_common_adc.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand Down Expand Up @@ -79,11 +79,11 @@ extern "C" {
#define ADC_TEST_HIGH_VAL_DMA 4081
#define ADC_TEST_HIGH_THRESH 200

#elif CONFIG_IDF_TARGET_ESP32H2 // TODO: IDF-6216
#define ADC_TEST_LOW_VAL 2144
#define ADC_TEST_LOW_THRESH 200
#elif CONFIG_IDF_TARGET_ESP32H2
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 17

#define ADC_TEST_HIGH_VAL 4081
#define ADC_TEST_HIGH_VAL 3390
#define ADC_TEST_HIGH_VAL_DMA 4081
#define ADC_TEST_HIGH_THRESH 200
#endif
Expand Down
31 changes: 31 additions & 0 deletions components/hal/esp32h2/include/hal/adc_ll.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,37 @@ static inline void adc_ll_calibration_init(adc_unit_t adc_n)
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 1);
}

/**
* 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)
{
HAL_ASSERT(adc_n == ADC_UNIT_1);
/* Enable/disable internal connect GND (for calibration). */
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);
}
}

/**
* Resume register status after calibration.
*
* @param adc_n ADC index number.
*/
static inline void adc_ll_calibration_finish(adc_unit_t adc_n)
{
HAL_ASSERT(adc_n == ADC_UNIT_1);
REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0);
}

/**
* Set the calibration result to ADC.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@
#define IDF_PERFORMANCE_MAX_CYCLES_PER_DIV 70
#define IDF_PERFORMANCE_MAX_CYCLES_PER_SQRT 140

//TODO: IDF-6216
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_NO_FILTER 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_2 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_4 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_8 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_16 10
#define IDF_PERFORMANCE_MAX_ADC_CONTINUOUS_STD_ATTEN3_FILTER_64 10
#define IDF_PERFORMANCE_MAX_ADC_ONESHOT_STD_ATTEN3 10
10 changes: 9 additions & 1 deletion components/soc/esp32h2/include/soc/Kconfig.soc_caps.in
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,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_TEMPERATURE_SHARE_INTR
bool
Expand Down
4 changes: 4 additions & 0 deletions components/soc/esp32h2/include/soc/regi2c_saradc.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,7 @@
#define I2C_SARADC_SAR2_INIT_CODE_MSB 4
#define I2C_SARADC_SAR2_INIT_CODE_MSB_MSB 3
#define I2C_SARADC_SAR2_INIT_CODE_MSB_LSB 0

#define ADC_SAR1_ENCAL_GND_ADDR 0x8
#define ADC_SAR1_ENCAL_GND_ADDR_MSB 0x1
#define ADC_SAR1_ENCAL_GND_ADDR_LSB 0x1
4 changes: 3 additions & 1 deletion components/soc/esp32h2/include/soc/soc_caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,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 */

/*!< Interrupt */
#define SOC_ADC_TEMPERATURE_SHARE_INTR (1)
Expand Down
1 change: 0 additions & 1 deletion docs/docs_not_updated/esp32h2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ api-guides/dfu
api-guides/index
api-reference/peripherals/spi_features
api-reference/peripherals/sdio_slave
api-reference/peripherals/adc_calibration
api-reference/peripherals/dedic_gpio
api-reference/peripherals/sd_pullup_requirements
api-reference/peripherals/index
Expand Down
Loading

0 comments on commit 4331ae7

Please sign in to comment.