1 /*
2  * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdint.h>
8 #include "sdkconfig.h"
9 #include "assert.h"
10 #include "esp_types.h"
11 #include "esp_err.h"
12 #include "esp_check.h"
13 #include "esp_heap_caps.h"
14 #include "hal/adc_types.h"
15 #include "hal/efuse_ll.h"
16 #include "soc/soc_caps.h"
17 #include "esp_adc/adc_cali_scheme.h"
18 #include "adc_cali_interface.h"
19 
20 /* ----------------------------- Configuration ------------------------------ */
21 #ifdef CONFIG_ADC_CALI_EFUSE_TP_ENABLE
22 #define EFUSE_TP_ENABLED        1
23 #else
24 #define EFUSE_TP_ENABLED        0
25 #endif
26 
27 #ifdef CONFIG_ADC_CALI_EFUSE_VREF_ENABLE
28 #define EFUSE_VREF_ENABLED      1
29 #else
30 #define EFUSE_VREF_ENABLED      0
31 #endif
32 
33 #ifdef CONFIG_ADC_CALI_LUT_ENABLE
34 #define LUT_ENABLED             1
35 #else
36 #define LUT_ENABLED             0
37 #endif
38 
39 /* ESP32s with both Two Point Values and Vref burned into eFuse are required to
40  * also burn the EFUSE_BLK3_PART_RESERVE flag. A limited set of ESP32s
41  * (not available through regular sales channel) DO NOT have the
42  * EFUSE_BLK3_PART_RESERVE burned. Moreover, this set of ESP32s represents Vref
43  * in Two's Complement format. If this is the case, modify the preprocessor
44  * definitions below as follows...
45  * #define CHECK_BLK3_FLAG         0        //Do not check BLK3 flag as it is not burned
46  * #define VREF_FORMAT             1        //eFuse Vref is in Two's Complement format
47  */
48 #define CHECK_BLK3_FLAG         1
49 #define VREF_FORMAT             0
50 
51 /* ------------------------------ eFuse Access ----------------------------- */
52 #define VREF_MASK                       0x1F
53 #define VREF_STEP_SIZE                  7
54 #define VREF_OFFSET                     1100
55 
56 #define TP_LOW1_OFFSET                  278
57 #define TP_LOW2_OFFSET                  421
58 #define TP_LOW_MASK                     0x7F
59 #define TP_LOW_VOLTAGE                  150
60 #define TP_HIGH1_OFFSET                 3265
61 #define TP_HIGH2_OFFSET                 3406
62 #define TP_HIGH_MASK                    0x1FF
63 #define TP_HIGH_VOLTAGE                 850
64 #define TP_STEP_SIZE                    4
65 
66 /* ----------------------- Raw to Voltage Constants ------------------------- */
67 #define LIN_COEFF_A_SCALE               65536
68 #define LIN_COEFF_A_ROUND               (LIN_COEFF_A_SCALE/2)
69 
70 #define LUT_VREF_LOW                    1000
71 #define LUT_VREF_HIGH                   1200
72 #define LUT_ADC_STEP_SIZE               64
73 #define LUT_POINTS                      20
74 #define LUT_LOW_THRESH                  2880
75 #define LUT_HIGH_THRESH                 (LUT_LOW_THRESH + LUT_ADC_STEP_SIZE)
76 #define ADC_12_BIT_RES                  4096
77 
78 /* ------------------------ Characterization Constants ---------------------- */
79 static const uint32_t adc1_tp_atten_scale[4] = {65504, 86975, 120389, 224310};
80 static const uint32_t adc2_tp_atten_scale[4] = {65467, 86861, 120416, 224708};
81 static const uint32_t adc1_tp_atten_offset[4] = {0, 1, 27, 54};
82 static const uint32_t adc2_tp_atten_offset[4] = {0, 9, 26, 66};
83 
84 static const uint32_t adc1_vref_atten_scale[4] = {57431, 76236, 105481, 196602};
85 static const uint32_t adc2_vref_atten_scale[4] = {57236, 76175, 105678, 197170};
86 static const uint32_t adc1_vref_atten_offset[4] = {75, 78, 107, 142};
87 static const uint32_t adc2_vref_atten_offset[4] = {63, 66, 89, 128};
88 
89 //20 Point lookup tables, covering ADC readings from 2880 to 4096, step size of 64
90 static const uint32_t lut_adc1_low[LUT_POINTS] = {2240, 2297, 2352, 2405, 2457, 2512, 2564, 2616, 2664, 2709,
91                                                   2754, 2795, 2832, 2868, 2903, 2937, 2969, 3000, 3030, 3060};
92 static const uint32_t lut_adc1_high[LUT_POINTS] = {2667, 2706, 2745, 2780, 2813, 2844, 2873, 2901, 2928, 2956,
93                                                    2982, 3006, 3032, 3059, 3084, 3110, 3135, 3160, 3184, 3209};
94 static const uint32_t lut_adc2_low[LUT_POINTS] = {2238, 2293, 2347, 2399, 2451, 2507, 2561, 2613, 2662, 2710,
95                                                   2754, 2792, 2831, 2869, 2904, 2937, 2968, 2999, 3029, 3059};
96 static const uint32_t lut_adc2_high[LUT_POINTS] = {2657, 2698, 2738, 2774, 2807, 2838, 2867, 2894, 2921, 2946,
97                                                    2971, 2996, 3020, 3043, 3067, 3092, 3116, 3139, 3162, 3185};
98 
99 const __attribute__((unused)) static char *TAG = "adc_cali";
100 
101 
102 /* ----------------------- EFuse Access Functions --------------------------- */
103 static bool check_efuse_vref(void);
104 static bool check_efuse_tp(void);
105 static inline int decode_bits(uint32_t bits, uint32_t mask, bool is_twos_compl);
106 static uint32_t read_efuse_vref(void);
107 static uint32_t read_efuse_tp_low(adc_unit_t unit_id);
108 static uint32_t read_efuse_tp_high(adc_unit_t unit_id);
109 
110 
111 /* ----------------------- Characterization Functions ----------------------- */
112 static void characterize_using_two_point(adc_unit_t unit_id,
113                                          adc_atten_t atten,
114                                          uint32_t high,
115                                          uint32_t low,
116                                          uint32_t *coeff_a,
117                                          uint32_t *coeff_b);
118 static void characterize_using_vref(adc_unit_t unit_id,
119                                     adc_atten_t atten,
120                                     uint32_t vref,
121                                     uint32_t *coeff_a,
122                                     uint32_t *coeff_b);
123 
124 
125 /* ------------------------ Conversion Functions --------------------------- */
126 static uint32_t calculate_voltage_linear(uint32_t adc_reading, uint32_t coeff_a, uint32_t coeff_b);
127 //Only call when ADC reading is above threshold
128 static uint32_t calculate_voltage_lut(uint32_t adc, uint32_t vref, const uint32_t *low_vref_curve, const uint32_t *high_vref_curve);
129 
interpolate_two_points(uint32_t y1,uint32_t y2,uint32_t x_step,uint32_t x)130 static inline uint32_t interpolate_two_points(uint32_t y1, uint32_t y2, uint32_t x_step, uint32_t x)
131 {
132     //Interpolate between two points (x1,y1) (x2,y2) between 'lower' and 'upper' separated by 'step'
133     return ((y1 * x_step) + (y2 * x) - (y1 * x) + (x_step / 2)) / x_step;
134 }
135 
136 
137 /* ------------------------ Interface Functions --------------------------- */
138 static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage);
139 
140 
141 /* ------------------------ Context Structure--------------------------- */
142 typedef struct {
143     adc_unit_t unit_id;                             ///< ADC unit
144     adc_atten_t atten;                              ///< ADC attenuation
145     adc_bitwidth_t bitwidth;                        ///< ADC bit width
146     uint32_t coeff_a;                               ///< Gradient of ADC-Voltage curve
147     uint32_t coeff_b;                               ///< Offset of ADC-Voltage curve
148     uint32_t vref;                                  ///< Vref used by lookup table
149     const uint32_t *low_curve;                      ///< Pointer to low Vref curve of lookup table (NULL if unused)
150     const uint32_t *high_curve;                     ///< Pointer to high Vref curve of lookup table (NULL if unused)
151     adc_cali_line_fitting_efuse_val_t efuse_val;    ///< Type of calibration value used in characterization
152 } cali_chars_line_fitting_t;
153 
154 
155 /* ------------------------- Public API ------------------------------------- */
adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t * config,adc_cali_handle_t * ret_handle)156 esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t *config, adc_cali_handle_t *ret_handle)
157 {
158     esp_err_t ret = ESP_OK;
159     ESP_RETURN_ON_FALSE(config && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
160     ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit");
161     ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation");
162     ESP_RETURN_ON_FALSE(((config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth");
163 
164     adc_cali_scheme_t *scheme = (adc_cali_scheme_t *)heap_caps_calloc(1, sizeof(adc_cali_scheme_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
165     ESP_RETURN_ON_FALSE(scheme, ESP_ERR_NO_MEM, TAG, "no mem for adc calibration scheme");
166 
167     cali_chars_line_fitting_t *chars = (cali_chars_line_fitting_t *)heap_caps_calloc(1, sizeof(cali_chars_line_fitting_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
168     ESP_GOTO_ON_FALSE(chars, ESP_ERR_NO_MEM, err, TAG, "no memory for the calibration characteristics");
169 
170     //Check eFuse if enabled to do so
171     if (check_efuse_tp() && EFUSE_TP_ENABLED) {
172         //Characterize based on Two Point values
173         chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP;
174         //Characterize based on Two Point values
175         uint32_t high = read_efuse_tp_high(config->unit_id);
176         uint32_t low = read_efuse_tp_low(config->unit_id);
177         characterize_using_two_point(config->unit_id, config->atten, high, low, &chars->coeff_a, &chars->coeff_b);
178     } else if (check_efuse_vref() && EFUSE_VREF_ENABLED) {
179         //Characterize based on eFuse Vref
180         chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF;
181         chars->vref = read_efuse_vref();
182         characterize_using_vref(config->unit_id, config->atten, chars->vref, &chars->coeff_a, &chars->coeff_b);
183     } else {
184         //Characterized based on default Vref
185         chars->efuse_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF;
186         ESP_GOTO_ON_FALSE(config->default_vref, ESP_ERR_INVALID_ARG, err, TAG, "default vref didn't set");
187         chars->vref = config->default_vref;
188         characterize_using_vref(config->unit_id, config->atten, chars->vref, &chars->coeff_a, &chars->coeff_b);
189     }
190 
191     chars->unit_id = config->unit_id;
192     chars->atten = config->atten;
193     chars->bitwidth = (config->bitwidth == ADC_BITWIDTH_DEFAULT) ? ADC_BITWIDTH_12 : config->bitwidth;
194     //Initialize fields for lookup table if necessary
195     if (LUT_ENABLED && config->atten == ADC_ATTEN_DB_12) {
196         chars->low_curve = (config->unit_id == ADC_UNIT_1) ? lut_adc1_low : lut_adc2_low;
197         chars->high_curve = (config->unit_id == ADC_UNIT_1) ? lut_adc1_high : lut_adc2_high;
198     } else {
199         chars->low_curve = NULL;
200         chars->high_curve = NULL;
201     }
202     scheme->raw_to_voltage = cali_raw_to_voltage;
203     scheme->ctx = chars;
204     *ret_handle = scheme;
205 
206     return ESP_OK;
207 
208 err:
209     if (scheme) {
210         heap_caps_free(scheme);
211     }
212     return ret;
213 }
214 
adc_cali_scheme_line_fitting_check_efuse(adc_cali_line_fitting_efuse_val_t * cali_val)215 esp_err_t adc_cali_scheme_line_fitting_check_efuse(adc_cali_line_fitting_efuse_val_t *cali_val)
216 {
217     ESP_RETURN_ON_FALSE(cali_val, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
218 
219     if (check_efuse_tp()) {
220         *cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP;
221     } else if (check_efuse_vref()) {
222         *cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF;
223     } else {
224         *cali_val = ADC_CALI_LINE_FITTING_EFUSE_VAL_DEFAULT_VREF;
225     }
226 
227     return ESP_OK;
228 }
229 
adc_cali_delete_scheme_line_fitting(adc_cali_handle_t handle)230 esp_err_t adc_cali_delete_scheme_line_fitting(adc_cali_handle_t handle)
231 {
232     ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
233 
234     heap_caps_free(handle->ctx);
235     handle->ctx = NULL;
236 
237     heap_caps_free(handle);
238     handle = NULL;
239 
240     return ESP_OK;
241 }
242 
243 /* ------------------------ Interface Functions --------------------------- */
cali_raw_to_voltage(void * arg,int raw,int * voltage)244 static esp_err_t cali_raw_to_voltage(void *arg, int raw, int *voltage)
245 {
246     //pointers are checked in the upper layer
247 
248     cali_chars_line_fitting_t *ctx = arg;
249 
250     //Scale adc_rading if not 12 bits wide
251     raw = (raw << (ADC_BITWIDTH_12 - ctx->bitwidth));
252     if (raw > ADC_12_BIT_RES - 1) {
253         raw = ADC_12_BIT_RES - 1;    //Set to 12bit res max
254     }
255 
256     if (LUT_ENABLED && (ctx->atten == ADC_ATTEN_DB_12) && (raw >= LUT_LOW_THRESH)) {  //Check if in non-linear region
257         //Use lookup table to get voltage in non linear portion of ADC_ATTEN_DB_12
258         uint32_t lut_voltage = calculate_voltage_lut(raw, ctx->vref, ctx->low_curve, ctx->high_curve);
259         if (raw <= LUT_HIGH_THRESH) {   //If ADC is transitioning from linear region to non-linear region
260             //Linearly interpolate between linear voltage and lut voltage
261             uint32_t linear_voltage = calculate_voltage_linear(raw, ctx->coeff_a, ctx->coeff_b);
262             *voltage = interpolate_two_points(linear_voltage, lut_voltage, LUT_ADC_STEP_SIZE, (raw - LUT_LOW_THRESH));
263         } else {
264             *voltage = lut_voltage;
265         }
266     } else {
267         *voltage = calculate_voltage_linear(raw, ctx->coeff_a, ctx->coeff_b);
268     }
269 
270     return ESP_OK;
271 }
272 
273 /* ----------------------- EFuse Access Functions --------------------------- */
check_efuse_vref(void)274 static bool check_efuse_vref(void)
275 {
276     //Check if Vref is burned in eFuse
277     return (efuse_ll_get_adc_vref() != 0) ? true : false;
278 }
279 
check_efuse_tp(void)280 static bool check_efuse_tp(void)
281 {
282     //Check if Two Point values are burned in eFuse
283     if (CHECK_BLK3_FLAG && (efuse_ll_get_blk3_part_reserve() == 0)) {
284         return false;
285     }
286     //All TP cal values must be non zero
287     return efuse_ll_get_adc1_tp_low() &&
288            efuse_ll_get_adc2_tp_low() &&
289            efuse_ll_get_adc1_tp_high() &&
290            efuse_ll_get_adc2_tp_high();
291 }
292 
decode_bits(uint32_t bits,uint32_t mask,bool is_twos_compl)293 static inline int decode_bits(uint32_t bits, uint32_t mask, bool is_twos_compl)
294 {
295     int ret;
296     if (bits & (~(mask >> 1) & mask)) {      //Check sign bit (MSB of mask)
297         //Negative
298         if (is_twos_compl) {
299             ret = -(((~bits) + 1) & (mask >> 1));   //2's complement
300         } else {
301             ret = -(bits & (mask >> 1));    //Sign-magnitude
302         }
303     } else {
304         //Positive
305         ret = bits & (mask >> 1);
306     }
307     return ret;
308 }
309 
read_efuse_vref(void)310 static uint32_t read_efuse_vref(void)
311 {
312     //eFuse stores deviation from ideal reference voltage
313     uint32_t ret = VREF_OFFSET;       //Ideal vref
314     uint32_t bits = efuse_ll_get_adc_vref();
315     ret += decode_bits(bits, VREF_MASK, VREF_FORMAT) * VREF_STEP_SIZE;
316     return ret;     //ADC Vref in mV
317 }
318 
read_efuse_tp_low(adc_unit_t unit_id)319 static uint32_t read_efuse_tp_low(adc_unit_t unit_id)
320 {
321     //ADC reading at 150mV stored in two's complement format
322     uint32_t ret;
323     uint32_t bits;
324 
325     if (unit_id == ADC_UNIT_1) {
326         ret = TP_LOW1_OFFSET;
327         bits = efuse_ll_get_adc1_tp_low();
328     } else {
329         ret = TP_LOW2_OFFSET;
330         bits = efuse_ll_get_adc2_tp_low();
331     }
332     ret += decode_bits(bits, TP_LOW_MASK, true) * TP_STEP_SIZE;
333     return ret;     //Reading of ADC at 150mV
334 }
335 
read_efuse_tp_high(adc_unit_t unit_id)336 static uint32_t read_efuse_tp_high(adc_unit_t unit_id)
337 {
338     //ADC reading at 850mV stored in two's complement format
339     uint32_t ret;
340     uint32_t bits;
341 
342     if (unit_id == ADC_UNIT_1) {
343         ret = TP_HIGH1_OFFSET;
344         bits = efuse_ll_get_adc1_tp_high();
345     } else {
346         ret = TP_HIGH2_OFFSET;
347         bits = efuse_ll_get_adc2_tp_high();
348     }
349     ret += decode_bits(bits, TP_HIGH_MASK, true) * TP_STEP_SIZE;
350     return ret;     //Reading of ADC at 850mV
351 }
352 
353 
354 /* ----------------------- Characterization Functions ----------------------- */
characterize_using_two_point(adc_unit_t unit_id,adc_atten_t atten,uint32_t high,uint32_t low,uint32_t * coeff_a,uint32_t * coeff_b)355 static void characterize_using_two_point(adc_unit_t unit_id,
356                                          adc_atten_t atten,
357                                          uint32_t high,
358                                          uint32_t low,
359                                          uint32_t *coeff_a,
360                                          uint32_t *coeff_b)
361 {
362     const uint32_t *atten_scales;
363     const uint32_t *atten_offsets;
364 
365     if (unit_id == ADC_UNIT_1) { //Using ADC 1
366         atten_scales = adc1_tp_atten_scale;
367         atten_offsets = adc1_tp_atten_offset;
368     } else {    //Using ADC 2
369         atten_scales = adc2_tp_atten_scale;
370         atten_offsets = adc2_tp_atten_offset;
371     }
372     //Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
373     uint32_t delta_x = high - low;
374     uint32_t delta_v = TP_HIGH_VOLTAGE - TP_LOW_VOLTAGE;
375     //Where coeff_a = (delta_v/delta_x) * atten_scale
376     *coeff_a = (delta_v * atten_scales[atten] + (delta_x / 2)) / delta_x;   //+(delta_x/2) for rounding
377     //Where coeff_b = high_v - ((delta_v/delta_x) * high_x) + atten_offset
378     *coeff_b = TP_HIGH_VOLTAGE - ((delta_v * high + (delta_x / 2)) / delta_x) + atten_offsets[atten];
379 }
380 
characterize_using_vref(adc_unit_t unit_id,adc_atten_t atten,uint32_t vref,uint32_t * coeff_a,uint32_t * coeff_b)381 static void characterize_using_vref(adc_unit_t unit_id,
382                                     adc_atten_t atten,
383                                     uint32_t vref,
384                                     uint32_t *coeff_a,
385                                     uint32_t *coeff_b)
386 {
387     const uint32_t *atten_scales;
388     const uint32_t *atten_offsets;
389 
390     if (unit_id == ADC_UNIT_1) { //Using ADC 1
391         atten_scales = adc1_vref_atten_scale;
392         atten_offsets = adc1_vref_atten_offset;
393     } else {    //Using ADC 2
394         atten_scales = adc2_vref_atten_scale;
395         atten_offsets = adc2_vref_atten_offset;
396     }
397     //Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
398     //Where coeff_a = (vref/4096) * atten_scale
399     *coeff_a = (vref * atten_scales[atten]) / (ADC_12_BIT_RES);
400     *coeff_b = atten_offsets[atten];
401 }
402 
403 
404 /* ------------------------ Conversion Functions --------------------------- */
calculate_voltage_linear(uint32_t adc_reading,uint32_t coeff_a,uint32_t coeff_b)405 static uint32_t calculate_voltage_linear(uint32_t adc_reading, uint32_t coeff_a, uint32_t coeff_b)
406 {
407     //Where voltage = coeff_a * adc_reading + coeff_b
408     return (((coeff_a * adc_reading) + LIN_COEFF_A_ROUND) / LIN_COEFF_A_SCALE) + coeff_b;
409 }
410 
411 //Only call when ADC reading is above threshold
calculate_voltage_lut(uint32_t adc,uint32_t vref,const uint32_t * low_vref_curve,const uint32_t * high_vref_curve)412 static uint32_t calculate_voltage_lut(uint32_t adc, uint32_t vref, const uint32_t *low_vref_curve, const uint32_t *high_vref_curve)
413 {
414     //Get index of lower bound points of LUT
415     uint32_t i = (adc - LUT_LOW_THRESH) / LUT_ADC_STEP_SIZE;
416 
417     //Let the X Axis be Vref, Y axis be ADC reading, and Z be voltage
418     int x2dist = LUT_VREF_HIGH - vref;                 //(x2 - x)
419     int x1dist = vref - LUT_VREF_LOW;                  //(x - x1)
420     int y2dist = ((i + 1) * LUT_ADC_STEP_SIZE) + LUT_LOW_THRESH - adc;  //(y2 - y)
421     int y1dist = adc - ((i * LUT_ADC_STEP_SIZE) + LUT_LOW_THRESH);        //(y - y1)
422 
423     //For points for bilinear interpolation
424     int q11 = low_vref_curve[i];                    //Lower bound point of low_vref_curve
425     int q12 = low_vref_curve[i + 1];                //Upper bound point of low_vref_curve
426     int q21 = high_vref_curve[i];                   //Lower bound point of high_vref_curve
427     int q22 = high_vref_curve[i + 1];               //Upper bound point of high_vref_curve
428 
429     //Bilinear interpolation
430     //Where z = 1/((x2-x1)*(y2-y1)) * ( (q11*x2dist*y2dist) + (q21*x1dist*y2dist) + (q12*x2dist*y1dist) + (q22*x1dist*y1dist) )
431     int voltage = (q11 * x2dist * y2dist) + (q21 * x1dist * y2dist) + (q12 * x2dist * y1dist) + (q22 * x1dist * y1dist);
432     voltage += ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE) / 2; //Integer division rounding
433     voltage /= ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE);    //Divide by ((x2-x1)*(y2-y1))
434     return (uint32_t)voltage;
435 }
436