1 /*
2 * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include <stdbool.h>
9 #include <string.h>
10 #include "esp_types.h"
11 #include "esp_err.h"
12 #include "esp_log.h"
13 #include "driver/adc.h"
14 #include "hal/adc_ll.h"
15 #include "esp_efuse_rtc_calib.h"
16 #include "esp_adc_cal.h"
17 #include "esp_adc_cal_internal.h"
18
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_REGISTER(adc_cal, CONFIG_ADC_LOG_LEVEL);
22
23 //const static char LOG_TAG[] = "ADC_CALI";
24
25
26 /* ------------------------ Characterization Constants ---------------------- */
27
28 // coeff_a is actually a float number
29 // it is scaled to put them into uint32_t so that the headers do not have to be changed
30 static const int coeff_a_scaling = 65536;
31
32 /**
33 * @note Error Calculation
34 * Coefficients for calculating the reading voltage error.
35 * Four sets of coefficients for atten0 ~ atten3 respectively.
36 *
37 * For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient.
38 *
39 * @note {0,0} stands for unused item
40 * @note In case of the overflow, these coeffcients are recorded as Absolute Value
41 * @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);
42 * @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered.
43 * @note ADC1 and ADC2 use same coeffients
44 */
45 const static uint64_t adc_error_coef_atten[4][5][2] = {
46 {{225966470500043, 1e15}, {7265418501948, 1e16}, {109410402681, 1e16}, {0, 0}, {0, 0}}, //atten0
47 {{4229623392600516, 1e16}, {731527490903, 1e16}, {88166562521, 1e16}, {0, 0}, {0, 0}}, //atten1
48 {{1017859239236435, 1e15}, {97159265299153, 1e16}, {149794028038, 1e16}, {0, 0}, {0, 0}}, //atten2
49 {{14912262772850453, 1e16}, {228549975564099, 1e16}, {356391935717, 1e16}, {179964582, 1e16}, {42046, 1e16}} //atten3
50 };
51 /**
52 * Term sign
53 * @note ADC1 and ADC2 use same coeffients
54 */
55 const static int32_t adc_error_sign[4][5] = {
56 {-1, -1, 1, 0, 0}, //atten0
57 { 1, -1, 1, 0, 0}, //atten1
58 {-1, -1, 1, 0, 0}, //atten2
59 {-1, -1, 1, -1, 1} //atten3
60 };
61
62 /* -------------------- Characterization Helper Data Types ------------------ */
63 typedef struct {
64 uint32_t voltage;
65 uint32_t digi;
66 } adc_calib_data_ver1;
67
68 typedef struct {
69 char version_num;
70 adc_unit_t adc_num;
71 adc_atten_t atten_level;
72 union {
73 adc_calib_data_ver1 ver1;
74 } efuse_data;
75 } adc_calib_parsed_info_t;
76
prepare_calib_data_for(int version_num,adc_unit_t adc_num,adc_atten_t atten,adc_calib_parsed_info_t * parsed_data_storage)77 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)
78 {
79 assert(version_num == 1);
80 esp_err_t ret;
81
82 parsed_data_storage->version_num = version_num;
83 parsed_data_storage->adc_num = adc_num;
84 parsed_data_storage->atten_level = atten;
85 // V1 we don't have calibration data for ADC2, using the efuse data of ADC1
86 uint32_t voltage, digi;
87 ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, atten, &digi, &voltage);
88 if (ret != ESP_OK) {
89 return ret;
90 }
91 parsed_data_storage->efuse_data.ver1.voltage = voltage;
92 parsed_data_storage->efuse_data.ver1.digi = digi;
93 return ret;
94 }
95
96 /* ----------------------- Characterization Functions ----------------------- */
97 /*
98 * Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
99 * with the previously done measurement when the chip was manufactured.
100 */
calculate_characterization_coefficients(const adc_calib_parsed_info_t * parsed_data,esp_adc_cal_characteristics_t * chars)101 static void calculate_characterization_coefficients(const adc_calib_parsed_info_t *parsed_data, esp_adc_cal_characteristics_t *chars)
102 {
103 LOG_DBG("Calib V1, Cal Voltage = %d, Digi out = %d\n", parsed_data->efuse_data.ver1.voltage, parsed_data->efuse_data.ver1.digi);
104
105 chars->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver1.voltage / parsed_data->efuse_data.ver1.digi;
106 chars->coeff_b = 0;
107 }
108
109 /* ------------------------- Public API ------------------------------------- */
esp_adc_cal_check_efuse(esp_adc_cal_value_t source)110 esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
111 {
112 if (source != ESP_ADC_CAL_VAL_EFUSE_TP) {
113 return ESP_ERR_NOT_SUPPORTED;
114 }
115 uint8_t adc_encoding_version = esp_efuse_rtc_calib_get_ver();
116 if (adc_encoding_version != 1) {
117 // current version only accepts encoding ver 1.
118 return ESP_ERR_INVALID_VERSION;
119 }
120
121 return ESP_OK;
122 }
123
esp_adc_cal_characterize(adc_unit_t adc_num,adc_atten_t atten,adc_bits_width_t bit_width,uint32_t default_vref,esp_adc_cal_characteristics_t * chars)124 esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
125 adc_atten_t atten,
126 adc_bits_width_t bit_width,
127 uint32_t default_vref,
128 esp_adc_cal_characteristics_t *chars)
129 {
130 esp_err_t ret;
131 adc_calib_parsed_info_t efuse_parsed_data = {0};
132 // Check parameters
133 if (adc_num != ADC_UNIT_1 && adc_num != ADC_UNIT_2) {
134 return ESP_ADC_CAL_VAL_NOT_SUPPORTED;
135 }
136 if (!chars) {
137 return ESP_ADC_CAL_VAL_NOT_SUPPORTED;
138 }
139 if (bit_width != ADC_WIDTH_BIT_12) {
140 return ESP_ADC_CAL_VAL_NOT_SUPPORTED;
141 }
142 if (atten >= ADC_ATTEN_MAX) {
143 return ESP_ADC_CAL_VAL_NOT_SUPPORTED;
144 }
145
146 int version_num = esp_efuse_rtc_calib_get_ver();
147 if (version_num != 1) {
148 return ESP_ADC_CAL_VAL_NOT_SUPPORTED;
149 }
150
151 memset(chars, 0, sizeof(esp_adc_cal_characteristics_t));
152
153 // make sure adc is calibrated.
154 ret = prepare_calib_data_for(version_num, adc_num, atten, &efuse_parsed_data);
155 if (ret != ESP_OK) {
156 abort();
157 }
158
159 calculate_characterization_coefficients(&efuse_parsed_data, chars);
160
161 // Initialize remaining fields
162 chars->adc_num = adc_num;
163 chars->atten = atten;
164 chars->bit_width = bit_width;
165
166 // in esp32c3 we only use the two point method to calibrate the adc.
167 return ESP_ADC_CAL_VAL_EFUSE_TP;
168 }
169
esp_adc_cal_raw_to_voltage(uint32_t adc_reading,const esp_adc_cal_characteristics_t * chars)170 uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
171 {
172 assert(chars != NULL);
173
174 int32_t error = 0;
175 uint64_t v_cali_1 = adc_reading * chars->coeff_a / coeff_a_scaling;
176 esp_adc_error_calc_param_t param = {
177 .v_cali_input = v_cali_1,
178 .term_num = (chars->atten == 3) ? 5 : 3,
179 .coeff = &adc_error_coef_atten,
180 .sign = &adc_error_sign,
181 };
182 error = esp_adc_cal_get_reading_error(¶m, chars->atten);
183
184 return (int32_t)v_cali_1 - error;
185 }
186