diff --git a/components/esp_adc_cal/CMakeLists.txt b/components/esp_adc_cal/CMakeLists.txt index 1b4e93664b..2d1f824147 100644 --- a/components/esp_adc_cal/CMakeLists.txt +++ b/components/esp_adc_cal/CMakeLists.txt @@ -1,22 +1,12 @@ idf_build_get_property(target IDF_TARGET) -if(${target} STREQUAL "esp32") - idf_component_register(SRCS "esp_adc_cal_esp32.c" - INCLUDE_DIRS "include" - REQUIRES driver efuse) - -elseif(${target} STREQUAL "esp32s2") - idf_component_register(SRCS "esp_adc_cal_esp32s2.c" - INCLUDE_DIRS "include" - REQUIRES driver efuse) - -elseif(${target} STREQUAL "esp32c3") - idf_component_register(SRCS "esp_adc_cal_esp32c3.c" - INCLUDE_DIRS "include" - REQUIRES driver efuse) - -elseif(${target} STREQUAL "esp32s3") -idf_component_register(SRCS "esp_adc_cal_esp32s3.c" - INCLUDE_DIRS "include" - REQUIRES driver efuse) +set(srcs "esp_adc_cal_common.c") +set(src_target "${target}/esp_adc_cal.c") +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${src_target}") + list(APPEND srcs ${src_target}) endif() + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS include + REQUIRES driver + PRIV_REQUIRES efuse) diff --git a/components/esp_adc_cal/component.mk b/components/esp_adc_cal/component.mk index e85ba07e4d..99bda1cb26 100644 --- a/components/esp_adc_cal/component.mk +++ b/components/esp_adc_cal/component.mk @@ -2,5 +2,5 @@ # Component Makefile # +COMPONENT_SRCDIRS := . $(IDF_TARGET) COMPONENT_ADD_INCLUDEDIRS := include -COMPONENT_OBJEXCLUDE += esp_adc_cal_esp32s2.o esp_adc_cal_esp32c3.o esp_adc_cal_esp32h2.o esp_adc_cal_esp32s3.o diff --git a/components/esp_adc_cal/esp_adc_cal_esp32.c b/components/esp_adc_cal/esp32/esp_adc_cal.c similarity index 89% rename from components/esp_adc_cal/esp_adc_cal_esp32.c rename to components/esp_adc_cal/esp32/esp_adc_cal.c index 9c21e3ec33..187a35c3ed 100644 --- a/components/esp_adc_cal/esp_adc_cal_esp32.c +++ b/components/esp_adc_cal/esp32/esp_adc_cal.c @@ -1,16 +1,8 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include "esp_types.h" @@ -83,8 +75,6 @@ #define LUT_HIGH_THRESH (LUT_LOW_THRESH + LUT_ADC_STEP_SIZE) #define ADC_12_BIT_RES 4096 -const static char LOG_TAG[] = "ADC_CALI"; - /* ------------------------ Characterization Constants ---------------------- */ static const uint32_t adc1_tp_atten_scale[4] = {65504, 86975, 120389, 224310}; static const uint32_t adc2_tp_atten_scale[4] = {65467, 86861, 120416, 224708}; @@ -363,26 +353,3 @@ uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_char return calculate_voltage_linear(adc_reading, chars->coeff_a, chars->coeff_b); } } - -esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, - const esp_adc_cal_characteristics_t *chars, - uint32_t *voltage) -{ - //Check parameters - ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No characteristic input"); - ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No output buffer"); - - esp_err_t ret = ESP_OK; - int adc_reading; - if (chars->adc_num == ADC_UNIT_1) { - //Check channel is valid on ADC1 - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel"); - adc_reading = adc1_get_raw(channel); - } else { - //Check channel is valid on ADC2 - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel"); - ret = adc2_get_raw(channel, chars->bit_width, &adc_reading); - } - *voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars); - return ret; -} diff --git a/components/esp_adc_cal/esp_adc_cal_esp32c3.c b/components/esp_adc_cal/esp32c3/esp_adc_cal.c similarity index 57% rename from components/esp_adc_cal/esp_adc_cal_esp32c3.c rename to components/esp_adc_cal/esp32c3/esp_adc_cal.c index 7799e5cb1a..bf73affbec 100644 --- a/components/esp_adc_cal/esp_adc_cal_esp32c3.c +++ b/components/esp_adc_cal/esp32c3/esp_adc_cal.c @@ -1,16 +1,8 @@ -// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include @@ -23,16 +15,47 @@ #include "hal/adc_ll.h" #include "esp_efuse_rtc_calib.h" #include "esp_adc_cal.h" +#include "../esp_adc_cal_internal.h" -const static char LOG_TAG[] = "adc_calib"; +const static char LOG_TAG[] = "ADC_CALI"; /* ------------------------ 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; @@ -46,9 +69,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; @@ -72,7 +95,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); @@ -101,7 +124,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 ESP_RETURN_ON_FALSE(adc_num == ADC_UNIT_1 || adc_num == ADC_UNIT_2, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid unit num"); ESP_RETURN_ON_FALSE(chars != NULL, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Ivalid characteristic"); @@ -134,28 +157,16 @@ 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) { assert(chars != NULL); - return adc_reading * chars->coeff_a / coeff_a_scaling + chars->coeff_b / coeff_b_scaling; -} -esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, - const esp_adc_cal_characteristics_t *chars, - uint32_t *voltage) -{ - // Check parameters - ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No characteristic input"); - ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No output buffer"); + 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(¶m, chars->atten); - esp_err_t ret = ESP_OK; - int adc_reading; - if (chars->adc_num == ADC_UNIT_1) { - //Check if channel is valid on ADC1 - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel"); - adc_reading = adc1_get_raw(channel); - } else { - //Check if channel is valid on ADC2 - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel"); - ret = adc2_get_raw(channel, chars->bit_width, &adc_reading); - } - *voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars); - return ret; + return (int32_t)v_cali_1 - error; } diff --git a/components/esp_adc_cal/esp_adc_cal_esp32s2.c b/components/esp_adc_cal/esp32s2/esp_adc_cal.c similarity index 82% rename from components/esp_adc_cal/esp_adc_cal_esp32s2.c rename to components/esp_adc_cal/esp32s2/esp_adc_cal.c index 94b9682cdb..4de5b11eba 100644 --- a/components/esp_adc_cal/esp_adc_cal_esp32s2.c +++ b/components/esp_adc_cal/esp32s2/esp_adc_cal.c @@ -1,16 +1,8 @@ -// Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #include #include "esp_types.h" @@ -206,26 +198,3 @@ uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_char assert(chars != NULL); return adc_reading * chars->coeff_a / coeff_a_scaling + chars->coeff_b / coeff_b_scaling; } - -esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, - const esp_adc_cal_characteristics_t *chars, - uint32_t *voltage) -{ - // Check parameters - ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No characteristic input"); - ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No output buffer"); - - esp_err_t ret = ESP_OK; - int adc_reading; - if (chars->adc_num == ADC_UNIT_1) { - //Check if channel is valid on ADC1 - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel"); - adc_reading = adc1_get_raw(channel); - } else { - //Check if channel is valid on ADC2 - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel"); - ret = adc2_get_raw(channel, chars->bit_width, &adc_reading); - } - *voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars); - return ret; -} diff --git a/components/esp_adc_cal/esp_adc_cal_esp32s3.c b/components/esp_adc_cal/esp32s3/esp_adc_cal.c similarity index 53% rename from components/esp_adc_cal/esp_adc_cal_esp32s3.c rename to components/esp_adc_cal/esp32s3/esp_adc_cal.c index f7014fdf9f..46a5b8ad2d 100644 --- a/components/esp_adc_cal/esp_adc_cal_esp32s3.c +++ b/components/esp_adc_cal/esp32s3/esp_adc_cal.c @@ -15,6 +15,7 @@ #include "hal/adc_types.h" #include "esp_efuse_rtc_calib.h" #include "esp_adc_cal.h" +#include "../esp_adc_cal_internal.h" const static char LOG_TAG[] = "ADC_CALI"; @@ -33,33 +34,35 @@ static const int coeff_a_scaling = 1000000; * * @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 = a1 * X^2 + a2 * X + a3; For atten3, error = a1 * X^4 + a2 * X^3 + a3 * X^2 + a4 * X + a5; + * @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. */ -const static uint64_t adc_error_coef_atten[4][10][2] = { - {{9798249589, 1e15}, {50871540569528, 1e16}, {3, 1}, {0, 0}, {0, 0}, //ADC1 atten0 - {36615265189, 1e16}, {1353548869615, 1e16}, {3, 1}, {0, 0}, {0, 0}}, //ADC2 atten0 - - {{101379430548, 1e16}, {49393185868806, 1e16}, {3, 1}, {0, 0}, {0, 0}, //ADC1 atten1 - {118964995959, 1e16}, {66319894226185, 1e16}, {2, 1}, {0, 0}, {0, 0}}, //ADC2 atten1 - - {{208385525314, 1e16}, {147640181047414, 1e16}, {2, 1}, {0, 0}, {0, 0}, //ADC1 atten2 - {259011467956, 1e16}, {200996773954387, 1e16}, {1, 1}, {0, 0}, {0, 0}}, //ADC2 atten2 - - {{13515, 1e15}, {70769718, 1e15}, {1297891447611, 1e16}, {644334888647536, 1e16}, {1,1}, //ADC1 atten3 - {15038, 1e15}, {79672528, 1e15}, {1478791187119, 1e16}, {755717904943462, 1e16}, {1,1}} //ADC2 atten3 +const static uint64_t adc1_error_coef_atten[4][5][2] = { + {{27856531419538344, 1e16}, {50871540569528, 1e16}, {9798249589, 1e15}, {0, 0}, {0, 0}}, //ADC1 atten0 + {{29831022915028695, 1e16}, {49393185868806, 1e16}, {101379430548, 1e16}, {0, 0}, {0, 0}}, //ADC1 atten1 + {{23285545746296417, 1e16}, {147640181047414, 1e16}, {208385525314, 1e16}, {0, 0}, {0, 0}}, //ADC1 atten2 + {{644403418269478, 1e15}, {644334888647536, 1e16}, {1297891447611, 1e16}, {70769718, 1e15}, {13515, 1e15}} //ADC1 atten3 }; -const static int32_t adc_error_sign[4][10] = { - {1, -1, -1, 0, 0, //ADC1 atten0 - 1, 1, -1, 0, 0}, //ADC2 atten0 - - {1, -1, -1, 0, 0, //ADC1 atten1 - 1, -1, -1, 0, 0}, //ADC2 atten1 - - {1, -1, -1, 0, 0, //ADC1 atten2 - 1, -1, -1, 0, 0}, //ADC2 atten2 - - {1, -1, 1, -1, -1, //ADC1 atten3 - 1, -1, 1, -1, 1} //ADC2 atten3 +const static uint64_t adc2_error_coef_atten[4][5][2] = { + {{25668651654328927, 1e16}, {1353548869615, 1e16}, {36615265189, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten0 + {{23690184690298404, 1e16}, {66319894226185, 1e16}, {118964995959, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten1 + {{9452499397020617, 1e16}, {200996773954387, 1e16}, {259011467956, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten2 + {{12247719764336924,1e16}, {755717904943462, 1e16}, {1478791187119, 1e16}, {79672528, 1e15}, {15038, 1e15}} //ADC2 atten3 + }; +/** + * Term sign + */ +const static int32_t adc1_error_sign[4][5] = { + {-1, -1, 1, 0, 0}, //ADC1 atten0 + {-1, -1, 1, 0, 0}, //ADC1 atten1 + {-1, -1, 1, 0, 0}, //ADC1 atten2 + {-1, -1, 1, -1, 1} //ADC1 atten3 + }; +const static int32_t adc2_error_sign[4][5] = { + {-1, 1, 1, 0, 0}, //ADC2 atten0 + {-1, -1, 1, 0, 0}, //ADC2 atten1 + {-1, -1, 1, 0, 0}, //ADC2 atten2 + { 1, -1, 1, -1, 1} //ADC2 atten3 }; /* -------------------- Characterization Helper Data Types ------------------ */ @@ -151,47 +154,6 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num, return ESP_ADC_CAL_VAL_EFUSE_TP_FIT; } -static int32_t get_reading_error(uint64_t v_cali_1, uint8_t adc_num, uint8_t atten) -{ - if (v_cali_1 == 0) { - return 0; - } - - uint8_t term_max = (atten == 3) ? 5 : 3; - int32_t error = 0; - uint64_t coeff = 0; - uint64_t term[5] = {0}; - - /** - * For atten0 ~ 2: - * error = a1 * X^2 + a2 * X + a3; - * - * For atten3: - * error = a1 * X^4 + a2 * X^3 + a3 * X^2 + a4 * X + a5; - */ - - //Calculate all the power beforehand - term[term_max-1] = 1; - term[term_max-2] = v_cali_1; - for (int term_id = term_max - 3; term_id >= 0; term_id--) { - term[term_id] = term[term_id + 1] * v_cali_1; - } - - //Calculate each term - uint8_t coef_id_start = (adc_num == ADC_UNIT_1) ? 0 : 5; - for (int i = 0; i < term_max; i++) { - coeff = adc_error_coef_atten[atten][coef_id_start + i][0]; - term[i] = term[i] * coeff; - ESP_LOGV(LOG_TAG, "big coef is %llu, big term%d is %llu, coef_id is %d", coeff, i, term[i], coef_id_start + i); - - term[i] = term[i] / adc_error_coef_atten[atten][coef_id_start + i][1]; - error += (int32_t)term[i] * adc_error_sign[atten][i]; - ESP_LOGV(LOG_TAG, "term%d is %llu, error is %d", i, term[i], error); - } - - return error; -} - uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars) { assert(chars != NULL); @@ -209,29 +171,16 @@ uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_char v_cali_1 = v_cali_1 / coeff_a_scaling; ESP_LOGV(LOG_TAG, "v_cali_1 is %llu", v_cali_1); - error = get_reading_error(v_cali_1, chars->adc_num, chars->atten); + //Curve Fitting error correction + esp_adc_error_calc_param_t param = { + .v_cali_input = v_cali_1, + .term_num = (chars->atten == 3) ? 5 : 3, + .coeff = (chars->adc_num == ADC_UNIT_1) ? &adc1_error_coef_atten : &adc2_error_coef_atten, + .sign = (chars->adc_num == ADC_UNIT_1) ? &adc1_error_sign : &adc2_error_sign, + }; + error = esp_adc_cal_get_reading_error(¶m, chars->atten); + voltage = (int32_t)v_cali_1 - error; return voltage; } - -esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, - const esp_adc_cal_characteristics_t *chars, - uint32_t *voltage) -{ - // Check parameters - ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No characteristic input"); - ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, LOG_TAG, "No output buffer"); - - esp_err_t ret = ESP_OK; - int adc_reading; - if (chars->adc_num == ADC_UNIT_1) { - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel"); - adc_reading = adc1_get_raw(channel); - } else { - ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, LOG_TAG, "Invalid channel"); - ret = adc2_get_raw(channel, chars->bit_width, &adc_reading); - } - *voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars); - return ret; -} diff --git a/components/esp_adc_cal/esp_adc_cal_common.c b/components/esp_adc_cal/esp_adc_cal_common.c new file mode 100644 index 0000000000..6fb7040afe --- /dev/null +++ b/components/esp_adc_cal/esp_adc_cal_common.c @@ -0,0 +1,85 @@ +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include "esp_types.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_check.h" +#include "driver/adc.h" +#include "hal/adc_types.h" +#include "esp_adc_cal.h" +#include "esp_adc_cal_internal.h" + +const static char *TAG = "ADC_CALI"; + +esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, + const esp_adc_cal_characteristics_t *chars, + uint32_t *voltage) +{ + // Check parameters + ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, TAG, "No characteristic input"); + ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, TAG, "No output buffer"); + + esp_err_t ret = ESP_OK; + int adc_reading; + if (chars->adc_num == ADC_UNIT_1) { + ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, TAG, "Invalid channel"); + adc_reading = adc1_get_raw(channel); + } else { + ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, TAG, "Invalid channel"); + ret = adc2_get_raw(channel, chars->bit_width, &adc_reading); + } + *voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars); + 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 diff --git a/components/esp_adc_cal/esp_adc_cal_internal.h b/components/esp_adc_cal/esp_adc_cal_internal.h new file mode 100644 index 0000000000..518c397f5b --- /dev/null +++ b/components/esp_adc_cal/esp_adc_cal_internal.h @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#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 diff --git a/components/esp_adc_cal/include/esp_adc_cal.h b/components/esp_adc_cal/include/esp_adc_cal.h index 171b2ed850..445b7f65d3 100644 --- a/components/esp_adc_cal/include/esp_adc_cal.h +++ b/components/esp_adc_cal/include/esp_adc_cal.h @@ -1,16 +1,8 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #ifndef __ESP_ADC_CAL_H__ #define __ESP_ADC_CAL_H__