Skip to content

Commit

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

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

See merge request espressif/esp-idf!26963
  • Loading branch information
suda-morris committed Nov 17, 2023
2 parents ddb6d22 + df46426 commit 1b3713f
Show file tree
Hide file tree
Showing 15 changed files with 257 additions and 36 deletions.
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
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
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
20 changes: 16 additions & 4 deletions components/efuse/esp32h2/include/esp_efuse_rtc_calib.h
Expand Up @@ -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
59 changes: 59 additions & 0 deletions components/esp_adc/esp32h2/curve_fitting_coefficients.c
@@ -0,0 +1,59 @@
/*
* 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

/**
* @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}, {0, 0}, {0, 0}}, //atten0
{{8359230818901277, 1e16}, {9025419089179, 1e19}, {0, 1}, {0, 0}, {0, 0}}, //atten1
{{1165668771581976, 1e15}, {8294679249061, 1e19}, {0, 1}, {0, 0}, {0, 0}}, //atten2
{{3637329628677273, 1e16}, {19607259738935, 1e18}, {7871689227, 1e16}, {0, 0}, {0, 0}}, //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, 0, 0}, //atten0
{-1, 1, 1, 0, 0}, //atten1
{-1, 1, 1, 0, 0}, //atten2
{-1, -1, 1, 0, 0}, //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)];
ctx->sign = &adc1_error_sign[VER2IDX(adc_calib_ver)];
}
2 changes: 1 addition & 1 deletion components/esp_adc/esp32h2/include/adc_cali_schemes.h
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
@@ -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
Expand Up @@ -543,6 +543,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
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
Expand Up @@ -281,7 +281,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
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
Expand Up @@ -114,7 +114,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
Expand Up @@ -6,7 +6,6 @@ api-guides/index
api-reference/peripherals/i2s
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

0 comments on commit 1b3713f

Please sign in to comment.