adc: upgrade adc calibration algorithm to version 2 on c3

This commit is contained in:
Armando
2022-01-20 20:34:37 +08:00
parent 22e741a281
commit bcb8d87108
7 changed files with 149 additions and 12 deletions

View File

@@ -1,7 +1,7 @@
idf_build_get_property(target IDF_TARGET)
set(srcs "esp_adc_cal_common.c")
set(src_target "esp_adc_cal_${target}.c")
set(src_target "${target}/esp_adc_cal.c")
if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${src_target}")
list(APPEND srcs ${src_target})
endif()

View File

@@ -14,6 +14,7 @@
#include "hal/adc_ll.h"
#include "esp32c3/esp_efuse_rtc_calib.h"
#include "esp_adc_cal.h"
#include "../esp_adc_cal_internal.h"
#define ADC_CALIB_CHECK(cond, err_msg, ret) do {\
@@ -28,10 +29,40 @@ const static char LOG_TAG[] = "adc_calib";
/* ------------------------ Characterization Constants ---------------------- */
// coeff_a and coeff_b are actually floats
// they are scaled to put them into uint32_t so that the headers do not have to be changed
// coeff_a is actually a float number
// it is scaled to put them into uint32_t so that the headers do not have to be changed
static const int coeff_a_scaling = 65536;
static const int coeff_b_scaling = 1024;
/**
* @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 coeffcients are recorded as Absolute Value
* @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
* @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered.
* @note ADC1 and ADC2 use same coeffients
*/
const static uint64_t adc_error_coef_atten[4][5][2] = {
{{225966470500043, 1e15}, {7265418501948, 1e16}, {109410402681, 1e16}, {0, 0}, {0, 0}}, //atten0
{{4229623392600516, 1e16}, {731527490903, 1e16}, {88166562521, 1e16}, {0, 0}, {0, 0}}, //atten1
{{1017859239236435, 1e15}, {97159265299153, 1e16}, {149794028038, 1e16}, {0, 0}, {0, 0}}, //atten2
{{14912262772850453, 1e16}, {228549975564099, 1e16}, {356391935717, 1e16}, {179964582, 1e16}, {42046, 1e16}} //atten3
};
/**
* Term sign
* @note ADC1 and ADC2 use same coeffients
*/
const static int32_t adc_error_sign[4][5] = {
{-1, -1, 1, 0, 0}, //atten0
{ 1, -1, 1, 0, 0}, //atten1
{-1, -1, 1, 0, 0}, //atten2
{-1, -1, 1, -1, 1} //atten3
};
/* -------------------- Characterization Helper Data Types ------------------ */
typedef struct {
uint32_t voltage;
@@ -45,9 +76,9 @@ typedef struct {
union {
adc_calib_data_ver1 ver1;
} efuse_data;
} adc_calib_parsed_info;
} adc_calib_parsed_info_t;
static esp_err_t prepare_calib_data_for(int version_num, adc_unit_t adc_num, adc_atten_t atten, adc_calib_parsed_info *parsed_data_storage)
static esp_err_t prepare_calib_data_for(int version_num, adc_unit_t adc_num, adc_atten_t atten, adc_calib_parsed_info_t *parsed_data_storage)
{
assert(version_num == 1);
esp_err_t ret;
@@ -71,7 +102,7 @@ static esp_err_t prepare_calib_data_for(int version_num, adc_unit_t adc_num, adc
* Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
* with the previously done measurement when the chip was manufactured.
*/
static void calculate_characterization_coefficients(const adc_calib_parsed_info *parsed_data, esp_adc_cal_characteristics_t *chars)
static void calculate_characterization_coefficients(const adc_calib_parsed_info_t *parsed_data, esp_adc_cal_characteristics_t *chars)
{
ESP_LOGD(LOG_TAG, "Calib V1, Cal Voltage = %d, Digi out = %d\n", parsed_data->efuse_data.ver1.voltage, parsed_data->efuse_data.ver1.digi);
@@ -100,7 +131,7 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
esp_adc_cal_characteristics_t *chars)
{
esp_err_t ret;
adc_calib_parsed_info efuse_parsed_data = {0};
adc_calib_parsed_info_t efuse_parsed_data = {0};
// Check parameters
ADC_CALIB_CHECK(adc_num == ADC_UNIT_1 || adc_num == ADC_UNIT_2, "Invalid unit num", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
ADC_CALIB_CHECK(chars != NULL, "Invalid characteristic", ESP_ADC_CAL_VAL_NOT_SUPPORTED);
@@ -132,7 +163,17 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
ADC_CALIB_CHECK(chars != NULL, "No characteristic input.", ESP_ERR_INVALID_ARG);
assert(chars != NULL);
return adc_reading * chars->coeff_a / coeff_a_scaling + chars->coeff_b / coeff_b_scaling;
int32_t error = 0;
uint64_t v_cali_1 = adc_reading * chars->coeff_a / coeff_a_scaling;
esp_adc_error_calc_param_t param = {
.v_cali_input = v_cali_1,
.term_num = (chars->atten == 3) ? 5 : 3,
.coeff = &adc_error_coef_atten,
.sign = &adc_error_sign,
};
error = esp_adc_cal_get_reading_error(&param, chars->atten);
return (int32_t)v_cali_1 - error;
}

View File

@@ -170,7 +170,6 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
esp_adc_cal_characteristics_t *chars)
{
bool res;
bool res __attribute__((unused));
adc_calib_parsed_info efuse_parsed_data = {0};
// Check parameters
assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2));

View File

@@ -12,6 +12,7 @@
#include "driver/adc.h"
#include "hal/adc_types.h"
#include "esp_adc_cal.h"
#include "esp_adc_cal_internal.h"
#define ADC_CAL_CHECK(cond, ret) ({ \
if(!(cond)){ \
@@ -44,3 +45,49 @@ esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel,
}
return ret;
}
#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
/*------------------------------------------------------------------------------
* Private API
*----------------------------------------------------------------------------*/
int32_t esp_adc_cal_get_reading_error(const esp_adc_error_calc_param_t *param, uint8_t atten)
{
if (param->v_cali_input == 0) {
return 0;
}
uint64_t v_cali_1 = param->v_cali_input;
uint8_t term_num = param->term_num;
int32_t error = 0;
uint64_t coeff = 0;
uint64_t variable[term_num];
uint64_t term[term_num];
memset(variable, 0, term_num * sizeof(uint64_t));
memset(term, 0, term_num * sizeof(uint64_t));
/**
* For atten0 ~ 2:
* error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2);
*
* For atten3:
* error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
*/
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];
for (int i = 1; i < term_num; i++) {
variable[i] = variable[i-1] * v_cali_1;
coeff = (*param->coeff)[atten][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];
ESP_LOGV(TAG, "term%d is %llu, error is %d", i, term[i], error);
}
return error;
}
#endif //#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED

View File

@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#define ESP_ADC_CAL_CURVE_FITTING_SUPPORTED 1
#define COEFF_GROUP_NUM 4
#define TERM_MAX 5
#endif
#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
/**
* Calculation parameters used for curve fitting calibration algorithm error
*
* @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
* Where X is the `v_cali_input`.
*/
typedef struct {
uint64_t v_cali_input; //Input to calculate the error
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
} esp_adc_error_calc_param_t;
/**
* Calculate the curve fitting error
*
* @param param see `esp_adc_error_calc_param_t`
* @param atten ADC attenuation
*/
int32_t esp_adc_cal_get_reading_error(const esp_adc_error_calc_param_t *param, uint8_t atten);
#endif //#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/