refactor(adc_calib): Simplify 2nd step coefficient calculation

- remove unnecessary variables and calculations
- improve readability of code
This commit is contained in:
laokaiyao 2023-06-26 11:52:25 +08:00
parent 5354759735
commit edc1abc8ea
9 changed files with 82 additions and 51 deletions

View File

@ -65,10 +65,14 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a
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)
{
assert((version >= ESP_EFUSE_ADC_CALIB_VER_MIN) &&
(version <= ESP_EFUSE_ADC_CALIB_VER_MAX));
assert(atten <= ADC_ATTEN_DB_11);
(void) adc_unit;
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;
}
if (atten == ADC_ATTEN_DB_2_5 || atten == ADC_ATTEN_DB_6) {
/**

View File

@ -34,8 +34,7 @@ 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)
{
assert((version >= ESP_EFUSE_ADC_CALIB_VER_MIN) &&
(version <= ESP_EFUSE_ADC_CALIB_VER_MAX));
/* Version validation should be guaranteed in the caller */
assert(atten >=0 && atten < 4);
(void) adc_unit;
@ -60,8 +59,7 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a
int esp_efuse_rtc_calib_get_chan_compens(int version, uint32_t adc_unit, uint32_t adc_channel, int atten)
{
assert((version >= ESP_EFUSE_ADC_CALIB_VER_MIN) &&
(version <= ESP_EFUSE_ADC_CALIB_VER_MAX));
/* Version validation should be guaranteed in the caller */
assert(atten < 4);
assert(adc_channel < SOC_ADC_CHANNEL_NUM(adc_unit));

View File

@ -63,9 +63,13 @@ uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int a
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)
{
assert((version >= ESP_EFUSE_ADC_CALIB_VER_MIN) &&
(version <= ESP_EFUSE_ADC_CALIB_VER_MAX));
assert(atten < 4);
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(adc_unit <= ADC_UNIT_2);
int efuse_vol_bits = 0;

View File

@ -59,7 +59,7 @@ typedef struct {
/* ----------------------- Characterization Functions ----------------------- */
static void get_first_step_reference_point(int version_num, adc_unit_t unit_id, adc_atten_t atten, adc_calib_info_t *calib_info);
static void calc_first_step_coefficients(const adc_calib_info_t *parsed_data, cali_chars_curve_fitting_t *chars);
static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step_t *param, adc_atten_t atten);
static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step_t *param);
static esp_err_t check_valid(const adc_cali_curve_fitting_config_t *config);
/* ------------------------ Interface Functions --------------------------- */
@ -140,7 +140,7 @@ static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage)
#endif // SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED
uint64_t v_cali_1 = (uint64_t)raw * ctx->chars_first_step.coeff_a / coeff_a_scaling + ctx->chars_first_step.coeff_b;
int32_t error = get_reading_error(v_cali_1, &(ctx->chars_second_step), ctx->atten);
int32_t error = get_reading_error(v_cali_1, &(ctx->chars_second_step));
*voltage = (int32_t)v_cali_1 - error;
@ -179,9 +179,9 @@ static void calc_first_step_coefficients(const adc_calib_info_t *parsed_data, ca
}
static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step_t *param, adc_atten_t atten)
static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step_t *param)
{
if (v_cali_1 == 0) {
if (v_cali_1 == 0 || param->term_num == 0) {
return 0;
}
@ -193,19 +193,23 @@ static int32_t get_reading_error(uint64_t v_cali_1, const cali_chars_second_step
memset(variable, 0, term_num * sizeof(uint64_t));
memset(term, 0, term_num * sizeof(uint64_t));
/**
* The scheme formula is:
* error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + ... + (Kn * X^n);
*/
variable[0] = 1;
coeff = (*param->coeff)[atten][0][0];
term[0] = variable[0] * coeff / (*param->coeff)[atten][0][1];
error = (int32_t)term[0] * (*param->sign)[atten][0];
coeff = (param->coeff)[0][0];
term[0] = variable[0] * coeff / (param->coeff)[0][1];
error = (int32_t)term[0] * (param->sign)[0];
for (int i = 1; i < term_num; i++) {
variable[i] = variable[i - 1] * v_cali_1;
coeff = (*param->coeff)[atten][i][0];
coeff = (param->coeff)[i][0];
term[i] = variable[i] * coeff;
ESP_LOGV(TAG, "big coef is %llu, big term%d is %llu, coef_id is %d", coeff, i, term[i], i);
term[i] = term[i] / (*param->coeff)[atten][i][1];
error += (int32_t)term[i] * (*param->sign)[atten][i];
term[i] = term[i] / (param->coeff)[i][1];
error += (int32_t)term[i] * (param->sign)[i];
ESP_LOGV(TAG, "term%d is %llu, error is %"PRId32, i, term[i], error);
}

View File

@ -12,13 +12,10 @@
extern "C" {
#endif
#define COEFF_GROUP_NUM 4
#define TERM_MAX 5
typedef struct {
uint8_t term_num; ///< Term number of the algorithm formula
const uint64_t (*coeff)[COEFF_GROUP_NUM][TERM_MAX][2]; ///< Coeff of each term. See `adc_error_coef_atten` for details (and the magic number 2)
const int32_t (*sign)[COEFF_GROUP_NUM][TERM_MAX]; ///< Sign of each term
const uint64_t (*coeff)[2]; ///< Coeff of each term. See `adc_error_coef_atten` for details (and the magic number 2)
const int32_t (*sign); ///< Sign of each term
} cali_chars_second_step_t;
/**

View File

@ -7,6 +7,9 @@
#include <stdint.h>
#include "../curve_fitting_coefficients.h"
#define COEFF_GROUP_NUM 4
#define TERM_MAX 5
/**
* @note Error Calculation
* Coefficients for calculating the reading voltage error.
@ -41,6 +44,6 @@ void curve_fitting_get_second_step_coeff(const adc_cali_curve_fitting_config_t *
ctx->term_num = (config->atten == 3) ? 5 : 3;
// On esp32c3, ADC1 and ADC2 share the second step coefficients
// And if the target only has 1 ADC peripheral, just use the ADC1 directly
ctx->coeff = &adc1_error_coef_atten;
ctx->sign = &adc1_error_sign;
ctx->coeff = adc1_error_coef_atten[config->atten];
ctx->sign = adc1_error_sign[config->atten];
}

View File

@ -10,6 +10,8 @@
#include "../curve_fitting_coefficients.h"
#define COEFF_VERSION_NUM 2 // Currently C6 has two versions of curve calibration schemes
#define COEFF_GROUP_NUM 4
#define TERM_MAX 3
/**
* @note Error Calculation
@ -26,17 +28,17 @@
const static uint64_t adc1_error_coef_atten[COEFF_VERSION_NUM][COEFF_GROUP_NUM][TERM_MAX][2] = {
/* Coefficients of calibration version 1 */
{
{{487166399931449, 1e15}, {6436483033201, 1e16}, {30410131806, 1e16}, {0, 0}, {0, 0}}, //atten0
{{8665498165817785, 1e16}, {15239070452946, 1e16}, {13818878844, 1e16}, {0, 0}, {0, 0}}, //atten1
{{12277821756674387, 1e16}, {22275554717885, 1e16}, {5924302667, 1e16}, {0, 0}, {0, 0}}, //atten2
{{3801417550380255, 1e16}, {6020352420772, 1e16}, {12442478488, 1e16}, {0, 0}, {0, 0}}, //atten3
{{487166399931449, 1e15}, {6436483033201, 1e16}, {30410131806, 1e16}}, //atten0
{{8665498165817785, 1e16}, {15239070452946, 1e16}, {13818878844, 1e16}}, //atten1
{{12277821756674387, 1e16}, {22275554717885, 1e16}, {5924302667, 1e16}}, //atten2
{{3801417550380255, 1e16}, {6020352420772, 1e16}, {12442478488, 1e16}}, //atten3
},
/* Coefficients of calibration version 2 */
{
{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, //atten0
{{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, //atten1
{{12217864764388775, 1e16}, {1954123107752, 1e16}, {6409679727, 1e16}, {0, 0}, {0, 0}}, //atten2
{{3915910437042445 , 1e16}, {31536470857564, 1e16}, {12493873014, 1e16}, {0, 0}, {0, 0}}, //atten3
{{0, 0}, {0, 0}, {0, 0}}, //atten0
{{0, 0}, {0, 0}, {0, 0}}, //atten1
{{12217864764388775, 1e16}, {1954123107752, 1e16}, {6409679727, 1e16}}, //atten2
{{3915910437042445 , 1e16}, {31536470857564, 1e16}, {12493873014, 1e16}}, //atten3
},
};
@ -46,17 +48,17 @@ const static uint64_t adc1_error_coef_atten[COEFF_VERSION_NUM][COEFF_GROUP_NUM][
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
{-1, 1, 1}, //atten0
{-1, 1, 1}, //atten1
{-1, 1, 1}, //atten2
{-1, -1, 1}, //atten3
},
/* Coefficient sign of calibration version 2 */
{
{ 0, 0, 0, 0, 0}, //atten0
{ 0, 0, 0, 0, 0}, //atten1
{-1, -1, 1, 0, 0}, //atten2
{-1, -1, 1, 0, 0}, //atten3
{ 0, 0, 0}, //atten0
{ 0, 0, 0}, //atten1
{-1, -1, 1}, //atten2
{-1, -1, 1}, //atten3
},
};
@ -66,8 +68,13 @@ void curve_fitting_get_second_step_coeff(const adc_cali_curve_fitting_config_t *
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;
printf("ver %lu index %lu\n", adc_calib_ver, VER2IDX(adc_calib_ver));
ctx->coeff = &adc1_error_coef_atten[VER2IDX(adc_calib_ver)];
ctx->sign = &adc1_error_sign[VER2IDX(adc_calib_ver)];
if (adc_calib_ver == ESP_EFUSE_ADC_CALIB_VER2 && config->atten < 2) {
ctx->term_num = 0;
ctx->coeff = NULL;
ctx->sign = NULL;
} else {
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];
}
}

View File

@ -5,8 +5,12 @@
*/
#include <stdint.h>
#include "hal/adc_types.h"
#include "../curve_fitting_coefficients.h"
#define COEFF_GROUP_NUM 4
#define TERM_MAX 5
/**
* @note Error Calculation
* Coefficients for calculating the reading voltage error.
@ -50,6 +54,10 @@ const static int32_t adc2_error_sign[COEFF_GROUP_NUM][TERM_MAX] = {
void curve_fitting_get_second_step_coeff(const adc_cali_curve_fitting_config_t *config, cali_chars_second_step_t *ctx)
{
ctx->term_num = (config->atten == 3) ? 5 : 3;
ctx->coeff = (config->unit_id == ADC_UNIT_1) ? &adc1_error_coef_atten : &adc2_error_coef_atten;
ctx->sign = (config->unit_id == ADC_UNIT_1) ? &adc1_error_sign : &adc2_error_sign;
ctx->coeff = config->unit_id == ADC_UNIT_1 ?
adc1_error_coef_atten[config->atten] :
adc2_error_coef_atten[config->atten];
ctx->sign = config->unit_id == ADC_UNIT_1 ?
adc1_error_sign[config->atten] :
adc2_error_sign[config->atten];
}

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -70,6 +70,7 @@ void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten)
if ((version >= ESP_EFUSE_ADC_CALIB_VER_MIN) &&
(version <= ESP_EFUSE_ADC_CALIB_VER_MAX)) {
// Guarantee the calibration version before calling efuse function
init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten);
}
#if SOC_ADC_SELF_HW_CALI_SUPPORTED
@ -103,7 +104,12 @@ static int s_adc_cali_chan_compens[SOC_ADC_MAX_CHANNEL_NUM][SOC_ADC_ATTEN_NUM] =
void adc_load_hw_calibration_chan_compens(adc_unit_t adc_n, adc_channel_t chan, adc_atten_t atten)
{
int version = esp_efuse_rtc_calib_get_ver();
s_adc_cali_chan_compens[chan][atten] = esp_efuse_rtc_calib_get_chan_compens(version, adc_n, chan, atten);
if ((version >= ESP_EFUSE_ADC_CALIB_VER_MIN) &&
(version <= ESP_EFUSE_ADC_CALIB_VER_MAX)) {
// Guarantee the calibration version before calling efuse function
s_adc_cali_chan_compens[chan][atten] = esp_efuse_rtc_calib_get_chan_compens(version, adc_n, chan, atten);
}
// No warning when version doesn't match because should has warned in adc_calc_hw_calibration_code
}
int IRAM_ATTR adc_get_hw_calibration_chan_compens(adc_unit_t adc_n, adc_channel_t chan, adc_atten_t atten)