mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 04:59:55 +00:00 
			
		
		
		
	adc: upgrade adc calibration algorithm to version 2 on c3
This commit is contained in:
		| @@ -1,7 +1,7 @@ | |||||||
| idf_build_get_property(target IDF_TARGET) | idf_build_get_property(target IDF_TARGET) | ||||||
|  |  | ||||||
| set(srcs "esp_adc_cal_common.c") | 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}") | if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${src_target}") | ||||||
|     list(APPEND srcs ${src_target}) |     list(APPEND srcs ${src_target}) | ||||||
| endif() | endif() | ||||||
|   | |||||||
| @@ -14,6 +14,7 @@ | |||||||
| #include "hal/adc_ll.h" | #include "hal/adc_ll.h" | ||||||
| #include "esp32c3/esp_efuse_rtc_calib.h" | #include "esp32c3/esp_efuse_rtc_calib.h" | ||||||
| #include "esp_adc_cal.h" | #include "esp_adc_cal.h" | ||||||
|  | #include "../esp_adc_cal_internal.h" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| #define ADC_CALIB_CHECK(cond, err_msg, ret) do {\ | #define ADC_CALIB_CHECK(cond, err_msg, ret) do {\ | ||||||
| @@ -28,10 +29,40 @@ const static char LOG_TAG[] = "adc_calib"; | |||||||
| 
 | 
 | ||||||
| /* ------------------------ Characterization Constants ---------------------- */ | /* ------------------------ Characterization Constants ---------------------- */ | ||||||
| 
 | 
 | ||||||
| // coeff_a and coeff_b are actually floats
 | // coeff_a is actually a float number
 | ||||||
| // they are scaled to put them into uint32_t so that the headers do not have to be changed
 | // 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_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 ------------------ */ | /* -------------------- Characterization Helper Data Types ------------------ */ | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t voltage; |     uint32_t voltage; | ||||||
| @@ -45,9 +76,9 @@ typedef struct { | |||||||
|     union { |     union { | ||||||
|         adc_calib_data_ver1 ver1; |         adc_calib_data_ver1 ver1; | ||||||
|     } efuse_data; |     } 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); |     assert(version_num == 1); | ||||||
|     esp_err_t ret; |     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 |  * Estimate the (assumed) linear relationship btwn the measured raw value and the voltage | ||||||
|  * with the previously done measurement when the chip was manufactured. |  * 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); |     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_adc_cal_characteristics_t *chars) | ||||||
| { | { | ||||||
|     esp_err_t ret; |     esp_err_t ret; | ||||||
|     adc_calib_parsed_info efuse_parsed_data = {0}; |     adc_calib_parsed_info_t efuse_parsed_data = {0}; | ||||||
|     // Check parameters
 |     // 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(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); |     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) | 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(¶m, chars->atten); | ||||||
|  | 
 | ||||||
|  |     return (int32_t)v_cali_1 - error; | ||||||
| } | } | ||||||
| @@ -170,7 +170,6 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num, | |||||||
|         esp_adc_cal_characteristics_t *chars) |         esp_adc_cal_characteristics_t *chars) | ||||||
| { | { | ||||||
|     bool res; |     bool res; | ||||||
|     bool res __attribute__((unused)); |  | ||||||
|     adc_calib_parsed_info efuse_parsed_data = {0}; |     adc_calib_parsed_info efuse_parsed_data = {0}; | ||||||
|     // Check parameters
 |     // Check parameters
 | ||||||
|     assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2)); |     assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2)); | ||||||
| @@ -12,6 +12,7 @@ | |||||||
| #include "driver/adc.h" | #include "driver/adc.h" | ||||||
| #include "hal/adc_types.h" | #include "hal/adc_types.h" | ||||||
| #include "esp_adc_cal.h" | #include "esp_adc_cal.h" | ||||||
|  | #include "esp_adc_cal_internal.h" | ||||||
|  |  | ||||||
| #define ADC_CAL_CHECK(cond, ret) ({                                         \ | #define ADC_CAL_CHECK(cond, ret) ({                                         \ | ||||||
|             if(!(cond)){                                                    \ |             if(!(cond)){                                                    \ | ||||||
| @@ -44,3 +45,49 @@ esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, | |||||||
|     } |     } | ||||||
|     return ret; |     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 | ||||||
|   | |||||||
							
								
								
									
										50
									
								
								components/esp_adc_cal/esp_adc_cal_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								components/esp_adc_cal/esp_adc_cal_internal.h
									
									
									
									
									
										Normal 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 | ||||||
| @@ -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 |  * SPDX-License-Identifier: Apache-2.0 | ||||||
|  */ |  */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Armando
					Armando