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 "esp_types.h"
9 #include "soc/efuse_periph.h"
10 #include "esp_err.h"
11 #include "esp_check.h"
12 #include "assert.h"
13 #include "esp_efuse.h"
14 #include "esp_efuse_table.h"
15 #include "esp_efuse_rtc_table.h"
16 #include "hal/adc_hal.h"
17 #include "hal/adc_types.h"
18 #include "driver/adc_types_legacy.h"
19 #include "esp_adc_cal_types_legacy.h"
20
21 const static char LOG_TAG[] = "adc_calib";
22
23 /* ------------------------ Characterization Constants ---------------------- */
24
25 // coeff_a and coeff_b are actually floats
26 // they are scaled to put them into uint32_t so that the headers do not have to be changed
27 static const int coeff_a_scaling = 65536;
28 static const int coeff_b_scaling = 1024;
29 /* -------------------- Characterization Helper Data Types ------------------ */
30 typedef struct {
31 int adc_calib_high;
32 int adc_calib_low;
33 } adc_calib_data_ver1;
34
35 typedef struct {
36 int adc_calib_high; // the reading of adc ...
37 int adc_calib_high_voltage; // ... at this voltage (mV)
38 } adc_calib_data_ver2;
39
40 typedef struct {
41 char version_num;
42 adc_unit_t adc_num;
43 adc_atten_t atten_level;
44 union {
45 adc_calib_data_ver1 ver1;
46 adc_calib_data_ver2 ver2;
47 } efuse_data;
48 } adc_calib_parsed_info;
49
prepare_calib_data_for(adc_unit_t adc_num,adc_atten_t atten,adc_calib_parsed_info * parsed_data_storage)50 static bool prepare_calib_data_for(adc_unit_t adc_num, adc_atten_t atten, adc_calib_parsed_info *parsed_data_storage)
51 {
52 int version_num = esp_efuse_rtc_table_read_calib_version();
53 int tag;
54 parsed_data_storage->version_num = version_num;
55 parsed_data_storage->adc_num = adc_num;
56 parsed_data_storage->atten_level = atten;
57 switch (version_num) {
58 case 1:
59 // note: use the adc_num as in hal, which start from 0.
60 tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VLOW);
61 parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
62 tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VHIGH);
63 parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
64 break;
65 case 2:
66 tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V2_PARAM_VHIGH);
67 parsed_data_storage->efuse_data.ver2.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
68 switch (parsed_data_storage->atten_level) {
69 case ADC_ATTEN_DB_0:
70 parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 600;
71 break;
72 case ADC_ATTEN_DB_2_5:
73 parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 800;
74 break;
75 case ADC_ATTEN_DB_6:
76 parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 1000;
77 break;
78 case ADC_ATTEN_DB_11:
79 parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 2000;
80 break;
81 default:
82 break;
83 }
84 break;
85 default:
86 // fall back to case 1 with zeros as params.
87 parsed_data_storage->version_num = 1;
88 tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VLOW);
89 parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true);
90 tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VHIGH);
91 parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true);
92 break;
93 }
94 return true;
95 }
96
97 /* ----------------------- Characterization Functions ----------------------- */
98 /**
99 * (Used in V1 of calibration scheme)
100 * The Two Point calibration measures the reading at two specific input voltages, and calculates the (assumed linear) relation
101 * between input voltage and ADC response. (Response = A * Vinput + B)
102 * A and B are scaled ints.
103 * @param high The ADC response at the higher voltage of the corresponding attenuation (600mV, 800mV, 1000mV, 2000mV).
104 * @param low The ADC response at the lower voltage of the corresponding attenuation (all 250mV).
105 *
106 */
characterize_using_two_point(adc_unit_t adc_num,adc_atten_t atten,uint32_t high,uint32_t low,uint32_t * coeff_a,uint32_t * coeff_b)107 static void characterize_using_two_point(adc_unit_t adc_num,
108 adc_atten_t atten,
109 uint32_t high,
110 uint32_t low,
111 uint32_t *coeff_a,
112 uint32_t *coeff_b)
113 {
114 // once we have recovered the reference high(Dhigh) and low(Dlow) readings, we can calculate a and b from
115 // the measured high and low readings
116 static const uint32_t v_high[] = {600, 800, 1000, 2000};
117 static const uint32_t v_low = 250;
118 *coeff_a = coeff_a_scaling * (v_high[atten] - v_low) / (high - low);
119 *coeff_b = coeff_b_scaling * (v_low * high - v_high[atten] * low) / (high - low);
120 }
121
122 /*
123 * Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
124 * with the previously done measurement when the chip was manufactured.
125 * */
calculate_characterization_coefficients(const adc_calib_parsed_info * parsed_data,esp_adc_cal_characteristics_t * chars)126 static bool calculate_characterization_coefficients(const adc_calib_parsed_info *parsed_data, esp_adc_cal_characteristics_t *chars)
127 {
128 switch (parsed_data->version_num) {
129 case 1:
130 ESP_LOGD(LOG_TAG, "Calib V1, low%dmV, high%dmV\n", parsed_data->efuse_data.ver1.adc_calib_low, parsed_data->efuse_data.ver1.adc_calib_high);
131
132 characterize_using_two_point(parsed_data->adc_num, parsed_data->atten_level,
133 parsed_data->efuse_data.ver1.adc_calib_high, parsed_data->efuse_data.ver1.adc_calib_low,
134 &(chars->coeff_a), &(chars->coeff_b));
135 break;
136 case 2:
137 ESP_LOGD(LOG_TAG, "Calib V2, volt%dmV\n", parsed_data->efuse_data.ver2.adc_calib_high);
138 chars->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver2.adc_calib_high_voltage /
139 parsed_data->efuse_data.ver2.adc_calib_high;
140 chars->coeff_b = 0;
141 break;
142 default:
143 return false;
144 break;
145 }
146 return true;
147 }
148
149 /* ------------------------- Public API ------------------------------------- */
esp_adc_cal_check_efuse(esp_adc_cal_value_t source)150 esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
151 {
152 if (source != ESP_ADC_CAL_VAL_EFUSE_TP) {
153 return ESP_ERR_NOT_SUPPORTED;
154 }
155 uint8_t adc_encoding_version = esp_efuse_rtc_table_read_calib_version();
156 if (adc_encoding_version != 1 && adc_encoding_version != 2) {
157 // current version only accepts encoding ver 1 and ver 2.
158 return ESP_ERR_INVALID_VERSION;
159 }
160 return ESP_OK;
161 }
162
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)163 esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
164 adc_atten_t atten,
165 adc_bits_width_t bit_width,
166 uint32_t default_vref,
167 esp_adc_cal_characteristics_t *chars)
168 {
169 bool res __attribute__((unused));
170 adc_calib_parsed_info efuse_parsed_data = {0};
171 // Check parameters
172 assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2));
173 assert(chars != NULL);
174 assert(bit_width == ADC_WIDTH_BIT_13);
175
176 // make sure adc is calibrated.
177 res = prepare_calib_data_for(adc_num, atten, &efuse_parsed_data);
178 assert(res);
179 res = calculate_characterization_coefficients(&efuse_parsed_data, chars);
180 assert(res);
181 ESP_LOGD(LOG_TAG, "adc%d (atten leven %d) calibration done: A:%"PRId32" B:%"PRId32"\n", adc_num, atten, chars->coeff_a, chars->coeff_b);
182
183 // Initialize remaining fields
184 chars->adc_num = adc_num;
185 chars->atten = atten;
186 chars->bit_width = bit_width;
187
188 // these values are not used as the corresponding calibration themes are deprecated.
189 chars->vref = 0;
190 chars->low_curve = NULL;
191 chars->high_curve = NULL;
192
193 // in esp32s2 we only use the two point method to calibrate the adc.
194 return ESP_ADC_CAL_VAL_EFUSE_TP;
195 }
196
esp_adc_cal_raw_to_voltage(uint32_t adc_reading,const esp_adc_cal_characteristics_t * chars)197 uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
198 {
199 assert(chars != NULL);
200 return adc_reading * chars->coeff_a / coeff_a_scaling + chars->coeff_b / coeff_b_scaling;
201 }
202