From 5cc329b9d08028de10f48aacebf4225162ed6660 Mon Sep 17 00:00:00 2001 From: Wu Bo Wen Date: Thu, 3 Dec 2020 20:08:59 +0800 Subject: [PATCH] driver/adc: support for esp32s2 adc calibration scheme V2 notice that the o_code is now pulled from efuse instead of automatically calibrated. This may influence other parts of the system. Closes https://github.com/espressif/esp-idf/issues/5455 --- components/driver/adc_common.c | 8 +- components/driver/esp32s2/rtc_tempsensor.c | 28 +- components/efuse/CMakeLists.txt | 3 + .../include/esp32s2/esp_efuse_rtc_table.h | 108 +++++++ .../efuse/src/esp32s2/esp_efuse_rtc_table.c | 167 +++++++++++ components/efuse/src/esp_efuse_utility.c | 2 +- components/esp_adc_cal/esp_adc_cal_esp32s2.c | 279 +++++++----------- components/esp_adc_cal/include/esp_adc_cal.h | 2 + components/esp_hw_support/CMakeLists.txt | 1 + .../port/esp32s2/private_include/regi2c_ulp.h | 7 + .../esp_hw_support/port/esp32s2/rtc_init.c | 116 +++++--- components/hal/esp32s2/adc_hal.c | 100 ++++--- 12 files changed, 557 insertions(+), 264 deletions(-) create mode 100644 components/efuse/include/esp32s2/esp_efuse_rtc_table.h create mode 100644 components/efuse/src/esp32s2/esp_efuse_rtc_table.c diff --git a/components/driver/adc_common.c b/components/driver/adc_common.c index 4d39e6ac6b..f87c5f6430 100644 --- a/components/driver/adc_common.c +++ b/components/driver/adc_common.c @@ -546,7 +546,9 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) { #ifdef CONFIG_IDF_TARGET_ESP32 - if (adc_unit & ADC_UNIT_1) return ESP_ERR_INVALID_ARG; + if (adc_unit & ADC_UNIT_1) { + return ESP_ERR_INVALID_ARG; + } #endif adc2_channel_t ch = ADC2_CHANNEL_MAX; /* Check if the GPIO supported. */ @@ -556,7 +558,9 @@ esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) break; } } - if (ch == ADC2_CHANNEL_MAX) return ESP_ERR_INVALID_ARG; + if (ch == ADC2_CHANNEL_MAX) { + return ESP_ERR_INVALID_ARG; + } ADC_ENTER_CRITICAL(); adc_hal_set_power_manage(ADC_POWER_SW_ON); diff --git a/components/driver/esp32s2/rtc_tempsensor.c b/components/driver/esp32s2/rtc_tempsensor.c index 656bc9815a..67253b2820 100644 --- a/components/driver/esp32s2/rtc_tempsensor.c +++ b/components/driver/esp32s2/rtc_tempsensor.c @@ -25,6 +25,8 @@ #include "soc/sens_struct.h" #include "driver/temp_sensor.h" #include "regi2c_ctrl.h" +#include "esp_log.h" +#include "esp32s2/esp_efuse_rtc_table.h" static const char *TAG = "tsens"; @@ -59,6 +61,8 @@ static const tsens_dac_offset_t dac_offset[TSENS_DAC_MAX] = { static SemaphoreHandle_t rtc_tsens_mux = NULL; +static float deltaT = 1000; // greater than range + esp_err_t temp_sensor_set_config(temp_sensor_config_t tsens) { CLEAR_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_FORCE_PD_M); @@ -133,6 +137,28 @@ esp_err_t temp_sensor_read_raw(uint32_t *tsens_out) return ESP_OK; } +static void read_delta_t_from_efuse(void) +{ + uint32_t version = esp_efuse_rtc_table_read_calib_version(); + if (version == 1 || version == 2) { + // fetch calibration value for temp sensor from eFuse + deltaT = esp_efuse_rtc_table_get_parsed_efuse_value(RTCCALIB_IDX_TMPSENSOR, false) / 10.0; + } else { + // no value to fetch, use 0. + deltaT = 0; + } + ESP_LOGD(TAG, "deltaT = %f\n", deltaT); +} + +static float parse_temp_sensor_raw_value(uint32_t tsens_raw, const tsens_dac_offset_t *dac) +{ + if (deltaT > 512) { //suggests that the value is not initialized + read_delta_t_from_efuse(); + } + float result = (TSENS_ADC_FACTOR * (float)tsens_raw - TSENS_DAC_FACTOR * dac->offset - TSENS_SYS_OFFSET) - deltaT; + return result; +} + esp_err_t temp_sensor_read_celsius(float *celsius) { TSENS_CHECK(celsius != NULL, ESP_ERR_INVALID_ARG); @@ -143,7 +169,7 @@ esp_err_t temp_sensor_read_celsius(float *celsius) ret = temp_sensor_read_raw(&tsens_out); TSENS_CHECK(ret == ESP_OK, ret); const tsens_dac_offset_t *dac = &dac_offset[tsens.dac_offset]; - *celsius = (TSENS_ADC_FACTOR * (float)tsens_out - TSENS_DAC_FACTOR * dac->offset - TSENS_SYS_OFFSET); + *celsius = parse_temp_sensor_raw_value(tsens_out, dac); if (*celsius < dac->range_min || *celsius > dac->range_max) { ESP_LOGW(TAG, "Exceeding the temperature range!"); ret = ESP_ERR_INVALID_STATE; diff --git a/components/efuse/CMakeLists.txt b/components/efuse/CMakeLists.txt index 378b5edb4b..48005d8e2d 100644 --- a/components/efuse/CMakeLists.txt +++ b/components/efuse/CMakeLists.txt @@ -8,6 +8,9 @@ if(EXISTS "${COMPONENT_DIR}/${target}") list(APPEND srcs "src/${target}/esp_efuse_api.c" "src/${target}/esp_efuse_fields.c" "src/${target}/esp_efuse_utility.c") + if("esp32s2" STREQUAL "${target}") + list(APPEND srcs "src/${target}/esp_efuse_rtc_table.c") + endif() endif() list(APPEND srcs "src/esp_efuse_api.c" diff --git a/components/efuse/include/esp32s2/esp_efuse_rtc_table.h b/components/efuse/include/esp32s2/esp_efuse_rtc_table.h new file mode 100644 index 0000000000..b9157ef079 --- /dev/null +++ b/components/efuse/include/esp32s2/esp_efuse_rtc_table.h @@ -0,0 +1,108 @@ +// Copyright 2017-2018 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. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "esp_err.h" +#include "sdkconfig.h" + +#define RTCCALIB_ESP32S2_ADCCOUNT 2 +#define RTCCALIB_ESP32S2_ATTENCOUNT 4 + +#define RTCCALIB_V1_PARAM_VLOW 0 +#define RTCCALIB_V1_PARAM_VHIGH 1 +#define RTCCALIB_V2_PARAM_VHIGH 0 +#define RTCCALIB_V2_PARAM_VINIT 1 + +// these are the tags. Either use them directly or use esp_efuse_rtc_table_get_tag to calculate +// the corresponding tag. +#define RTCCALIB_V1IDX_A10L 1 +#define RTCCALIB_V1IDX_A11L 2 +#define RTCCALIB_V1IDX_A12L 3 +#define RTCCALIB_V1IDX_A13L 4 +#define RTCCALIB_V1IDX_A20L 5 +#define RTCCALIB_V1IDX_A21L 6 +#define RTCCALIB_V1IDX_A22L 7 +#define RTCCALIB_V1IDX_A23L 8 +#define RTCCALIB_V1IDX_A10H 9 +#define RTCCALIB_V1IDX_A11H 10 +#define RTCCALIB_V1IDX_A12H 11 +#define RTCCALIB_V1IDX_A13H 12 +#define RTCCALIB_V1IDX_A20H 13 +#define RTCCALIB_V1IDX_A21H 14 +#define RTCCALIB_V1IDX_A22H 15 +#define RTCCALIB_V1IDX_A23H 16 +#define RTCCALIB_V2IDX_A10H 17 +#define RTCCALIB_V2IDX_A11H 18 +#define RTCCALIB_V2IDX_A12H 19 +#define RTCCALIB_V2IDX_A13H 20 +#define RTCCALIB_V2IDX_A20H 21 +#define RTCCALIB_V2IDX_A21H 22 +#define RTCCALIB_V2IDX_A22H 23 +#define RTCCALIB_V2IDX_A23H 24 +#define RTCCALIB_V2IDX_A10I 25 +#define RTCCALIB_V2IDX_A11I 26 +#define RTCCALIB_V2IDX_A12I 27 +#define RTCCALIB_V2IDX_A13I 28 +#define RTCCALIB_V2IDX_A20I 29 +#define RTCCALIB_V2IDX_A21I 30 +#define RTCCALIB_V2IDX_A22I 31 +#define RTCCALIB_V2IDX_A23I 32 +#define RTCCALIB_IDX_TMPSENSOR 33 + +/** + * @brief Get rtc calibration version. + */ +int esp_efuse_rtc_table_read_calib_version(void); + +/** + * @brief Helper function to calculate a tag from human-readable parameters. + * Tag is used to index the desired data from the efuse. + * For example, (1, 1, 3, 1) yields the tag RTCCALIB_V1IDX_A13H + * extra params are used for identification when a adc_num-atten combination has + * multiple efuse values. + * @param adc_channel_num verbatim numbering of the ADC channel. For channel 1, use 1 and not 0. + * @param atten attenuation. use the enum value. + * @param version the version of the scheme to index for. + * @param extra_params defined differently for each version. + * */ +int esp_efuse_rtc_table_get_tag(int version, int adc_channel_num, int atten, int extra_params); + +/** + * @brief Fetches a raw value from efuse and does signed bit parsing + * @param tag tag obtained with esp_efuse_rtc_table_get_tag + * + * */ +int esp_efuse_rtc_table_get_raw_efuse_value(int tag); + +/** + * @brief Fetches a raw value from efuse and resolve it to get + * the original number that it meant to represent. + * + * @param tag tag obtained with esp_efuse_rtc_table_get_tag + * @param use_zero_inputs Does not perform the raw value fetching before resolving the number, + * but proceed as if all zeros were read from efuse. + * + * */ +int esp_efuse_rtc_table_get_parsed_efuse_value(int tag, bool skip_efuse_reading); + +#ifdef __cplusplus +} +#endif diff --git a/components/efuse/src/esp32s2/esp_efuse_rtc_table.c b/components/efuse/src/esp32s2/esp_efuse_rtc_table.c new file mode 100644 index 0000000000..d9fcb6c03e --- /dev/null +++ b/components/efuse/src/esp32s2/esp_efuse_rtc_table.c @@ -0,0 +1,167 @@ +// Copyright 2017-2018 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. + +#include +#include "esp32s2/esp_efuse_rtc_table.h" +#include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "esp_log.h" +#include "soc/soc_caps.h" + +#define RTC_TBL_LOG_TAG "efuse_rtc_table" + + + +/* Note on definition of tags + * + * For adc calibration, value = raw * multiplier + offset, but these values are kind of arbitrary so + * we use a lookup table to do the bookkeeping. + * + * The offset of an item can be calculated as follows: + * PARAM_OFFSET + ADC_NUM(which is the UNIT_COUNT minus 1) * ATTEN_NUM + ATTEN_NUM + * where PARAM_OFFSET is the index of the first item. + * + * ADC, ATTEN form a 2-dim array. For each (version number, extra parameters) tuple we keep a such array, + * and use if-else statements to choose which array we use. + * */ + +#define RTCCALIB_V1_ADCREADINGLOW_OFFSET RTCCALIB_V1IDX_A10L +#define RTCCALIB_V1_ADCREADINGHIGH_OFFSET RTCCALIB_V1IDX_A10H +#define RTCCALIB_V2_ADCREADINGHIGH_OFFSET RTCCALIB_V2IDX_A10H +#define RTCCALIB_V2_ADCREADINGINIT_OFFSET RTCCALIB_V2IDX_A10I + +typedef struct { + const int tag; // should be the same as the index in adc_efuse_raw_map + const int block; + const int begin_bit; + const int length; + const int multiplier; + const int base; + const int depends; +} efuse_map_info_t; + +static const efuse_map_info_t adc_efuse_raw_map[] = { + {0}, + // INDEXING TAG, BLOCK, BEGIN_BIT, LENGTH, MULTIPLIER, OFFSET BASE, OFFSET DEP + {RTCCALIB_V1IDX_A10L, 2, 208, 6, 4, 2231, 0}, + {RTCCALIB_V1IDX_A11L, 2, 214, 6, 4, 1643, 0}, + {RTCCALIB_V1IDX_A12L, 2, 220, 6, 4, 1290, 0}, + {RTCCALIB_V1IDX_A13L, 2, 226, 6, 4, 701, 0}, + {RTCCALIB_V1IDX_A20L, 2, 232, 6, 4, 2305, 0}, + {RTCCALIB_V1IDX_A21L, 2, 238, 6, 4, 1693, 0}, + {RTCCALIB_V1IDX_A22L, 2, 244, 6, 4, 1343, 0}, + {RTCCALIB_V1IDX_A23L, 2, 250, 6, 4, 723, 0}, + + {RTCCALIB_V1IDX_A10H, 2, 144, 8, 4, 5775, 0}, + {RTCCALIB_V1IDX_A11H, 2, 152, 8, 4, 5693, 0}, + {RTCCALIB_V1IDX_A12H, 2, 160, 8, 4, 5723, 0}, + {RTCCALIB_V1IDX_A13H, 2, 168, 8, 4, 6209, 0}, + {RTCCALIB_V1IDX_A20H, 2, 176, 8, 4, 5817, 0}, + {RTCCALIB_V1IDX_A21H, 2, 184, 8, 4, 5703, 0}, + {RTCCALIB_V1IDX_A22H, 2, 192, 8, 4, 5731, 0}, + {RTCCALIB_V1IDX_A23H, 2, 200, 8, 4, 6157, 0}, + + {RTCCALIB_V2IDX_A10H, 2, 197, 6, 2, 169, RTCCALIB_V2IDX_A12H}, + {RTCCALIB_V2IDX_A11H, 2, 203, 6, 2, -26, RTCCALIB_V2IDX_A12H}, + {RTCCALIB_V2IDX_A12H, 2, 209, 9, 2, 126, RTCCALIB_V2IDX_A21H}, + {RTCCALIB_V2IDX_A13H, 2, 218, 7, 2, 387, RTCCALIB_V2IDX_A12H}, + {RTCCALIB_V2IDX_A20H, 2, 225, 7, 2, 177, RTCCALIB_V2IDX_A21H}, + {RTCCALIB_V2IDX_A21H, 2, 232, 10, 2, 5815, 0}, + {RTCCALIB_V2IDX_A22H, 2, 242, 7, 2, 27, RTCCALIB_V2IDX_A21H}, + {RTCCALIB_V2IDX_A23H, 2, 249, 7, 2, 410, RTCCALIB_V2IDX_A21H}, + + {RTCCALIB_V2IDX_A10I, 2, 147, 8, 2, 1519, 0}, + {RTCCALIB_V2IDX_A11I, 2, 155, 6, 2, 88, RTCCALIB_V2IDX_A10I}, + {RTCCALIB_V2IDX_A12I, 2, 161, 5, 2, 8, RTCCALIB_V2IDX_A11I}, + {RTCCALIB_V2IDX_A13I, 2, 166, 6, 2, 70, RTCCALIB_V2IDX_A12I}, + {RTCCALIB_V2IDX_A20I, 2, 172, 8, 2, 1677, 0}, + {RTCCALIB_V2IDX_A21I, 2, 180, 6, 2, 23, RTCCALIB_V2IDX_A20I}, + {RTCCALIB_V2IDX_A22I, 2, 186, 5, 2, 6, RTCCALIB_V2IDX_A21I}, + {RTCCALIB_V2IDX_A23I, 2, 191, 6, 2, 13, RTCCALIB_V2IDX_A22I}, + + {RTCCALIB_IDX_TMPSENSOR, 2, 135, 9, 1, 0, 0}, + +}; + + +int esp_efuse_rtc_table_read_calib_version(void) +{ + uint32_t result = 0; + esp_efuse_read_field_blob(ESP_EFUSE_BLOCK2_VERSION, &result, 32); + return result; +} + +int esp_efuse_rtc_table_get_tag(int version, int adc_num, int atten, int extra_params) +{ + int param_offset; // used to index which (adc_num, atten) array to use. + if (version == 1 && extra_params == RTCCALIB_V1_PARAM_VLOW) { // Volage LOW, Version 1 + param_offset = RTCCALIB_V1_ADCREADINGLOW_OFFSET; + } else if (version == 1 && extra_params == RTCCALIB_V1_PARAM_VHIGH) { + param_offset = RTCCALIB_V1_ADCREADINGHIGH_OFFSET; + } else if (version == 2 && extra_params == RTCCALIB_V2_PARAM_VHIGH) { + param_offset = RTCCALIB_V2_ADCREADINGHIGH_OFFSET; + } else if (version == 2 && extra_params == RTCCALIB_V2_PARAM_VINIT) { + param_offset = RTCCALIB_V2_ADCREADINGINIT_OFFSET; + } else { + return -1; + } + + int result = param_offset + (adc_num - 1) * RTCCALIB_ESP32S2_ATTENCOUNT + atten; + ESP_EARLY_LOGV(RTC_TBL_LOG_TAG, "V%d ADC%d ATTEN%d PARAM%d -> %d", version, adc_num, atten, extra_params, result); + return result; +} + +/* + * Converts a signed-bit int to a normal (2-complement) int. + * */ +static int signed_bit_to_int(uint32_t number, int len) +{ + if (number >> (len - 1)) { + // first bit is set, unset that bit and negate the number. + number = -(number ^ (1 << (len - 1))); + } + return number; +} + +int esp_efuse_rtc_table_get_raw_efuse_value(int tag) +{ + assert(tag > 0); + if (tag == 0) { + return 0; + } + uint32_t val = 0; + esp_efuse_read_block(adc_efuse_raw_map[tag].block, &val, adc_efuse_raw_map[tag].begin_bit, adc_efuse_raw_map[tag].length); + int result = signed_bit_to_int(val, adc_efuse_raw_map[tag].length); + ESP_EARLY_LOGV(RTC_TBL_LOG_TAG, "Fetching raw for tag %d @blk%d bit%d len%d: %d", tag, adc_efuse_raw_map[tag].block, adc_efuse_raw_map[tag].begin_bit, adc_efuse_raw_map[tag].length, + result); + return result; +} + +int esp_efuse_rtc_table_get_parsed_efuse_value(int tag, bool skip_efuse_reading) +{ + assert(tag >= 0); + if (tag == 0) { + return 0; // tag 0 is the dummy tag and has no value. (used by depends) + } + + int efuse_val = 0; + if (!skip_efuse_reading) { + efuse_val = esp_efuse_rtc_table_get_raw_efuse_value(tag) * adc_efuse_raw_map[tag].multiplier; + } + int result = efuse_val + adc_efuse_raw_map[tag].base + + esp_efuse_rtc_table_get_parsed_efuse_value(adc_efuse_raw_map[tag].depends, skip_efuse_reading); + + ESP_EARLY_LOGV(RTC_TBL_LOG_TAG, "Parsed efuse val for tag %d: %d", tag, result); + return result; +} diff --git a/components/efuse/src/esp_efuse_utility.c b/components/efuse/src/esp_efuse_utility.c index 3a10401fdc..6159ef2c9f 100644 --- a/components/efuse/src/esp_efuse_utility.c +++ b/components/efuse/src/esp_efuse_utility.c @@ -68,7 +68,7 @@ esp_err_t esp_efuse_utility_process(const esp_efuse_desc_t* field[], void* ptr, if ((bits_counter + num_bits) > req_size) { // Limits the length of the field. num_bits = req_size - bits_counter; } - ESP_LOGD(TAG, "In EFUSE_BLK%d__DATA%d_REG is used %d bits starting with %d bit", + ESP_EARLY_LOGD(TAG, "In EFUSE_BLK%d__DATA%d_REG is used %d bits starting with %d bit", (int)field[i]->efuse_block, num_reg, num_bits, start_bit); err = func_proc(num_reg, field[i]->efuse_block, start_bit, num_bits, ptr, &bits_counter); ++i_reg; diff --git a/components/esp_adc_cal/esp_adc_cal_esp32s2.c b/components/esp_adc_cal/esp_adc_cal_esp32s2.c index 091de9df90..4230eea66c 100644 --- a/components/esp_adc_cal/esp_adc_cal_esp32s2.c +++ b/components/esp_adc_cal/esp_adc_cal_esp32s2.c @@ -20,166 +20,94 @@ #include "assert.h" #include "esp_adc_cal.h" #include "esp_efuse.h" +#include "esp_efuse_table.h" +#include "esp32s2/esp_efuse_rtc_table.h" +#include "hal/adc_hal.h" #define ADC_CAL_CHECK(cond, ret) ({ \ if(!(cond)){ \ return ret; \ } \ }) +const static char LOG_TAG[] = "adc_calib"; + /* ------------------------ Characterization Constants ---------------------- */ -#define ADC_CHAR_VERSION1_EFUSEVAL 1 - -static const uint32_t adc1_D_mean_low[] = {2231, 1643, 1290, 701}; -static const uint32_t adc2_D_mean_low[] = {2305, 1693, 1343, 723}; -static const uint32_t adc1_D_mean_high[] = {5775, 5692, 5725, 6209}; -static const uint32_t adc2_D_mean_high[] = {5817, 5703, 5731, 6157}; - -static const int Dlow_data_length = 6; -static const int Dhigh_data_length = 8; - -static const int adc_efuse_block = 2; -static const int adc_calib_ver_block = 2; -static const int adc_calib_ver_word_loc = 4; -static const int adc_calib_ver_offset = 4; -static const int adc_calib_ver_len = 3; - -static const int adc1_atten0_Dlow_word_loc = 6; -static const int adc2_atten0_Dlow_word_loc = 7; -static const int adc1_atten0_Dhigh_word_loc = 4; -static const int adc2_atten0_Dhigh_word_loc = 5; - -static const int adc1_atten0_Dlow_offset = 16; -static const int adc2_atten0_Dlow_offset = 8; -static const int adc1_atten0_Dhigh_offset = 16; -static const int adc2_atten0_Dhigh_offset = 16; -/* ----------------------- EFuse Access Functions --------------------------- */ -/** - * Convenience function that reads a few bits from efuse and assembles them. - * For example, if the contents of the EFuse are: - * Word2: 0x1234 Word3:0x5678 - * Then, setting base=2, offset=24, len=24 will yield 0x456. - * @note does not check for boundaries, make sure parameters are correct - * @param blk EFuse Block - * @param base the starting word - * @param offset the bit offset in the starting word - * @param bit how many consecutive bits to fetch - * @return the assembled number - */ -static uint32_t get_consecutive_bits_from_blk(int blk, uint32_t base, int offset, int len) -{ - - base += offset / 32; - offset %= 32; - if (offset + len <= 32 || base == 7) { - uint32_t result = esp_efuse_read_reg(blk, base); - result <<= (32 - offset - len); - result >>= (32 - len); - return result; - } else { - // need to fetch both bytes. - uint64_t result = ((uint64_t)esp_efuse_read_reg(blk, base + 1) << 32) + esp_efuse_read_reg(blk, base); - result &= ((uint64_t)1 << (offset + len)) - 1; - result >>= offset; - return result; - } -} - -/** - * To save space in EFuse, the calibration values for adc are compressed. - * The compression scheme is: for X bits of ADC Efuse data, - * The actual ADC reading is: BASE_VALUE + 4*ADC_OFFSET - * where ADC_OFFSET = bits X-1:0 in Efuse, the highest bit is the sign bit (0:+, 1:-). - * - * The following functions do this conversion. - * @param efuse_val raw values read from efuse. - * @param adc_num Specifies the channel number. The 2 adc channels each have different calibration values. - * @param attem Specifies the attenuation. Different attenuation level have different calibration values. - */ -static uint32_t efuse_low_val_to_d(uint16_t efuse_val, adc_unit_t adc_num, adc_atten_t atten) -{ - // efuse_val is 5 bits + 6th sign bit. - int32_t rawoffsetval = efuse_val & ((1 << (Dlow_data_length - 1)) - 1); - // if the sign bit is 1, it means it is a negative sign. - int32_t offset = (efuse_val & (1 << (Dlow_data_length - 1))) ? (-rawoffsetval * 4) : (rawoffsetval * 4); - if (adc_num == ADC_UNIT_1) { - return offset + adc1_D_mean_low[atten - ADC_ATTEN_DB_0]; - } else { - return offset + adc2_D_mean_low[atten - ADC_ATTEN_DB_0]; - } -} - -static uint32_t efuse_high_val_to_d (uint16_t efuse_val, adc_unit_t adc_num, adc_atten_t atten) -{ - // efuse_val is 7 bits + 8th sign bit. - int32_t rawoffsetval = efuse_val & ((1 << (Dhigh_data_length - 1)) - 1); - int32_t offset = (efuse_val & (1 << (Dhigh_data_length - 1))) ? (-rawoffsetval * 4) : (rawoffsetval * 4); - if (adc_num == ADC_UNIT_1) { - return offset + adc1_D_mean_high[atten - ADC_ATTEN_DB_0]; - } else { - return offset + adc2_D_mean_high[atten - ADC_ATTEN_DB_0]; - } - -} - -/** - * To save space in EFuse, the calibration values for adc are compressed. - * The compression scheme is: for X bits of ADC Efuse data, - * The actual ADC reading is: BASE_VALUE + 4*ADC_OFFSET - * where ADC_OFFSET = bits X-1:0 in Efuse, the highest bit is the sign bit (0:+, 1:-). - * - * The following functions do the reading. - * @param efuse_val raw values read from efuse. - * @param adc_num Specifies the channel number. The 2 adc channels each have different calibration values. - * @param attem Specifies the attenuation. Different attenuation level have different calibration values. - */ -static uint32_t read_efuse_tp_low(adc_unit_t adc_num, adc_atten_t atten) -{ - // this fcn retrieves and decodes the calibration value stored in efuse. - uint32_t base; - int offset; - // may need to move magic numbers out - if (adc_num == ADC_UNIT_1) { - // the first value is at the 16th bit of the 6th word of the efuse block 2, each value is 6 bits long. - base = adc1_atten0_Dlow_word_loc; - offset = adc1_atten0_Dlow_offset + Dlow_data_length * (atten - ADC_ATTEN_DB_0); - - } else { - // the first value is at the 8th bit of the 7th word of the efuse block 2, each value is 6 bits long. - base = adc2_atten0_Dlow_word_loc; - offset = adc2_atten0_Dlow_offset + Dlow_data_length * (atten - ADC_ATTEN_DB_0); - } - uint32_t read_result = get_consecutive_bits_from_blk(adc_efuse_block, base, offset, Dlow_data_length); - return read_result; -} - -static uint32_t read_efuse_tp_high(adc_unit_t adc_num, adc_atten_t atten) -{ - // this fcn retrieves and decodes the calibration value stored in efuse. - uint32_t base; - int offset; - - if (adc_num == ADC_UNIT_1) { - // the first value is at the 16th bit of the 4th word of the efuse block 2, each value is 8 bits long. - base = adc1_atten0_Dhigh_word_loc; - offset = adc1_atten0_Dhigh_offset + Dhigh_data_length * (atten - ADC_ATTEN_DB_0); - - } else { - // the first value is at the 16th bit of the 5th word of the efuse block 2, each value is 8 bits long. - base = adc2_atten0_Dhigh_word_loc; - offset = adc2_atten0_Dhigh_offset + Dhigh_data_length * (atten - ADC_ATTEN_DB_0); - } - uint32_t read_result = get_consecutive_bits_from_blk(adc_efuse_block, base, offset, Dhigh_data_length); - return read_result; -} - -/* ----------------------- Characterization Functions ----------------------- */ // 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 static const int coeff_a_scaling = 65536; static const int coeff_b_scaling = 1024; +/* -------------------- Characterization Helper Data Types ------------------ */ +typedef struct { + int adc_calib_high; + int adc_calib_low; +} adc_calib_data_ver1; +typedef struct { + int adc_calib_high; // the reading of adc ... + int adc_calib_high_voltage; // ... at this voltage (mV) +} adc_calib_data_ver2; + +typedef struct { + char version_num; + adc_unit_t adc_num; + adc_atten_t atten_level; + union { + adc_calib_data_ver1 ver1; + adc_calib_data_ver2 ver2; + } efuse_data; +} adc_calib_parsed_info; + +static bool prepare_calib_data_for(adc_unit_t adc_num, adc_atten_t atten, adc_calib_parsed_info *parsed_data_storage) +{ + int version_num = esp_efuse_rtc_table_read_calib_version(); + int tag; + parsed_data_storage->version_num = version_num; + parsed_data_storage->adc_num = adc_num; + parsed_data_storage->atten_level = atten; + switch (version_num) { + case 1: + // note: use the adc_num as in hal, which start from 0. + tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VLOW); + parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); + tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VHIGH); + parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); + break; + case 2: + tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V2_PARAM_VHIGH); + parsed_data_storage->efuse_data.ver2.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); + switch (parsed_data_storage->atten_level) { + case ADC_ATTEN_DB_0: + parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 600; + break; + case ADC_ATTEN_DB_2_5: + parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 800; + break; + case ADC_ATTEN_DB_6: + parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 1000; + break; + case ADC_ATTEN_DB_11: + parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 2000; + break; + default: + break; + } + break; + default: + // fall back to case 1 with zeros as params. + parsed_data_storage->version_num = 1; + tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VLOW); + parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true); + tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VHIGH); + parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true); + break; + } + return true; +} + +/* ----------------------- Characterization Functions ----------------------- */ /** + * (Used in V1 of calibration scheme) * The Two Point calibration measures the reading at two specific input voltages, and calculates the (assumed linear) relation * between input voltage and ADC response. (Response = A * Vinput + B) * A and B are scaled ints. @@ -202,6 +130,32 @@ static void characterize_using_two_point(adc_unit_t adc_num, *coeff_b = coeff_b_scaling * (v_low * high - v_high[atten] * low) / (high - low); } +/* + * Estimate the (assumed) linear relationship btwn the measured raw value and the voltage + * with the previously done measurement when the chip was manufactured. + * */ +static bool calculate_characterization_coefficients(const adc_calib_parsed_info *parsed_data, esp_adc_cal_characteristics_t *chars) +{ + switch (parsed_data->version_num) { + case 1: + 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); + + characterize_using_two_point(parsed_data->adc_num, parsed_data->atten_level, + parsed_data->efuse_data.ver1.adc_calib_high, parsed_data->efuse_data.ver1.adc_calib_low, + &(chars->coeff_a), &(chars->coeff_b)); + break; + case 2: + ESP_LOGD(LOG_TAG, "Calib V2, volt%dmV\n", parsed_data->efuse_data.ver2.adc_calib_high); + chars->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver2.adc_calib_high_voltage / + parsed_data->efuse_data.ver2.adc_calib_high; + chars->coeff_b = 0; + break; + default: + return false; + break; + } + return true; +} /* ------------------------- Public API ------------------------------------- */ esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source) @@ -209,14 +163,9 @@ esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source) if (source != ESP_ADC_CAL_VAL_EFUSE_TP) { return ESP_ERR_NOT_SUPPORTED; } - uint8_t adc1_atten0_dh = get_consecutive_bits_from_blk(adc_efuse_block, adc1_atten0_Dhigh_word_loc, adc1_atten0_Dhigh_offset, Dhigh_data_length); - uint8_t adc2_atten0_dh = get_consecutive_bits_from_blk(adc_efuse_block, adc2_atten0_Dhigh_word_loc, adc2_atten0_Dhigh_offset, Dhigh_data_length); - if (!adc1_atten0_dh || !adc2_atten0_dh) { - return ESP_ERR_NOT_SUPPORTED; - } - uint8_t adc_encoding_version = get_consecutive_bits_from_blk(adc_calib_ver_block, adc_calib_ver_word_loc, adc_calib_ver_offset, adc_calib_ver_len); - if (adc_encoding_version != 1) { - // current version only accepts encoding ver 1. + uint8_t adc_encoding_version = esp_efuse_rtc_table_read_calib_version(); + if (adc_encoding_version != 1 && adc_encoding_version != 2) { + // current version only accepts encoding ver 1 and ver 2. return ESP_ERR_INVALID_VERSION; } return ESP_OK; @@ -228,24 +177,20 @@ esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num, uint32_t default_vref, esp_adc_cal_characteristics_t *chars) { + bool res; + adc_calib_parsed_info efuse_parsed_data = {0}; // Check parameters assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2)); assert(chars != NULL); assert(bit_width == ADC_WIDTH_BIT_13); - // Characterize based on efuse Two Point values. If these values are not present in efuse, - // or efuse values are of a version that we do not recognize, automatically assume default values. - uint32_t adc_calib_high, adc_calib_low; - if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) { - adc_calib_high = read_efuse_tp_high(adc_num, atten); - adc_calib_low = read_efuse_tp_low(adc_num, atten); - } else { - adc_calib_high = 0; - adc_calib_low = 0; - } - uint32_t high = efuse_high_val_to_d(adc_calib_high, adc_num, atten); - uint32_t low = efuse_low_val_to_d(adc_calib_low, adc_num, atten); - characterize_using_two_point(adc_num, atten, high, low, &(chars->coeff_a), &(chars->coeff_b)); + // make sure adc is calibrated. + res = prepare_calib_data_for(adc_num, atten, &efuse_parsed_data); + assert(res); + res = calculate_characterization_coefficients(&efuse_parsed_data, chars); + assert(res); + ESP_LOGD(LOG_TAG, "adc%d (atten leven %d) calibration done: A:%d B:%d\n", adc_num, atten, chars->coeff_a, chars->coeff_b); + // Initialize remaining fields chars->adc_num = adc_num; chars->atten = atten; diff --git a/components/esp_adc_cal/include/esp_adc_cal.h b/components/esp_adc_cal/include/esp_adc_cal.h index 2bb6470fd1..5a65b0f37d 100644 --- a/components/esp_adc_cal/include/esp_adc_cal.h +++ b/components/esp_adc_cal/include/esp_adc_cal.h @@ -56,6 +56,8 @@ typedef struct { * burned to the eFuse of the current ESP32 * * @param value_type Type of calibration value (ESP_ADC_CAL_VAL_EFUSE_VREF or ESP_ADC_CAL_VAL_EFUSE_TP) + * @note in ESP32S2, only ESP_ADC_CAL_VAL_EFUSE_TP is supported. Some old ESP32S2s do not support this, either. + * In which case you have to calibrate it manually, possibly by performing your own two-point calibration on the chip. * * @return * - ESP_OK: The calibration mode is supported in eFuse diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 987abe80ee..4119a1ede6 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -9,6 +9,7 @@ idf_component_register(SRCS "compare_set.c" "cpu_util.c" INCLUDE_DIRS include REQUIRES ${requires} + PRIV_REQUIRES efuse LDFRAGMENTS linker.lf) idf_build_get_property(target IDF_TARGET) diff --git a/components/esp_hw_support/port/esp32s2/private_include/regi2c_ulp.h b/components/esp_hw_support/port/esp32s2/private_include/regi2c_ulp.h index fdb5e48f76..de38328a2c 100644 --- a/components/esp_hw_support/port/esp32s2/private_include/regi2c_ulp.h +++ b/components/esp_hw_support/port/esp32s2/private_include/regi2c_ulp.h @@ -37,3 +37,10 @@ #define I2C_ULP_BG_O_DONE_FLAG 3 #define I2C_ULP_BG_O_DONE_FLAG_MSB 3 #define I2C_ULP_BG_O_DONE_FLAG_LSB 3 + +#define I2C_ULP_OCODE_ADDR 6 +#define I2C_ULP_OCODE_ADDR_MSB 7 +#define I2C_ULP_OCODE_ADDR_LSB 0 +#define I2C_ULP_IR_FORCE_CODE_ADDR 5 +#define I2C_ULP_IR_FORCE_CODE_ADDR_MSB 6 +#define I2C_ULP_IR_FORCE_CODE_ADDR_LSB 6 diff --git a/components/esp_hw_support/port/esp32s2/rtc_init.c b/components/esp_hw_support/port/esp32s2/rtc_init.c index 0753f63ac4..dfbff46150 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_init.c +++ b/components/esp_hw_support/port/esp32s2/rtc_init.c @@ -21,9 +21,11 @@ #include "soc/gpio_reg.h" #include "soc/spi_mem_reg.h" #include "soc/extmem_reg.h" +#include "regi2c_ulp.h" #include "regi2c_ctrl.h" #include "soc_log.h" - +#include "esp_efuse.h" +#include "esp_efuse_table.h" static const char *TAG = "rtc_init"; void rtc_init(rtc_config_t cfg) @@ -146,55 +148,73 @@ void rtc_init(rtc_config_t cfg) CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_UNHOLD); CLEAR_PERI_REG_MASK(RTC_CNTL_DIG_ISO_REG, RTC_CNTL_DG_PAD_FORCE_NOISO); } - if (cfg.cali_ocode) - { - /* - Bangap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration(must close PLL). - Method: - 1. read current cpu config, save in old_config; - 2. switch cpu to xtal because PLL will be closed when o-code calibration; - 3. begin o-code calibration; - 4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout; - 5. set cpu to old-config. - */ - rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get(); - rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL; - rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256; - rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX; - if (slow_clk_freq == (rtc_slow_freq_x32k)) { - cal_clk = RTC_CAL_32K_XTAL; - } else if (slow_clk_freq == rtc_slow_freq_8MD256) { - cal_clk = RTC_CAL_8MD256; - } - - uint64_t max_delay_time_us = 10000; - uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100); - uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period); - uint64_t cycle0 = rtc_time_get(); - uint64_t timeout_cycle = cycle0 + max_delay_cycle; - uint64_t cycle1 = 0; - - rtc_cpu_freq_config_t old_config; - rtc_clk_cpu_freq_get_config(&old_config); - rtc_clk_cpu_freq_set_xtal(); - - - REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0); - REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1); - bool odone_flag = 0; - bool bg_odone_flag = 0; - while(1) { - odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG); - bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG); - cycle1 = rtc_time_get(); - if (odone_flag && bg_odone_flag) - break; - if (cycle1 >= timeout_cycle) { - SOC_LOGW(TAG, "o_code calibration fail"); - break; + if (cfg.cali_ocode) { + uint32_t rtc_calib_version = 0; + esp_efuse_read_field_blob(ESP_EFUSE_BLOCK2_VERSION, &rtc_calib_version, 32); + if (rtc_calib_version == 2) { + // use efuse ocode. + uint32_t ocode1 = 0; + uint32_t ocode2 = 0; + uint32_t ocode; + esp_efuse_read_block(2, &ocode1, 16*8, 4); + esp_efuse_read_block(2, &ocode2, 18*8, 3); + ocode = (ocode2 << 4) + ocode1; + if (ocode >> 6) { + ocode = 93 - (ocode ^ (1 << 6)); + } else { + ocode = 93 + ocode; } + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_OCODE_ADDR, ocode); + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_FORCE_CODE_ADDR, 1); + } else { + /* + Bangap output voltage is not precise when calibrate o-code by hardware sometimes, so need software o-code calibration(must close PLL). + Method: + 1. read current cpu config, save in old_config; + 2. switch cpu to xtal because PLL will be closed when o-code calibration; + 3. begin o-code calibration; + 4. wait o-code calibration done flag(odone_flag & bg_odone_flag) or timeout; + 5. set cpu to old-config. + */ + rtc_slow_freq_t slow_clk_freq = rtc_clk_slow_freq_get(); + rtc_slow_freq_t rtc_slow_freq_x32k = RTC_SLOW_FREQ_32K_XTAL; + rtc_slow_freq_t rtc_slow_freq_8MD256 = RTC_SLOW_FREQ_8MD256; + rtc_cal_sel_t cal_clk = RTC_CAL_RTC_MUX; + if (slow_clk_freq == (rtc_slow_freq_x32k)) { + cal_clk = RTC_CAL_32K_XTAL; + } else if (slow_clk_freq == rtc_slow_freq_8MD256) { + cal_clk = RTC_CAL_8MD256; + } + + uint64_t max_delay_time_us = 10000; + uint32_t slow_clk_period = rtc_clk_cal(cal_clk, 100); + uint64_t max_delay_cycle = rtc_time_us_to_slowclk(max_delay_time_us, slow_clk_period); + uint64_t cycle0 = rtc_time_get(); + uint64_t timeout_cycle = cycle0 + max_delay_cycle; + uint64_t cycle1 = 0; + + rtc_cpu_freq_config_t old_config; + rtc_clk_cpu_freq_get_config(&old_config); + rtc_clk_cpu_freq_set_xtal(); + + + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 0); + REGI2C_WRITE_MASK(I2C_ULP, I2C_ULP_IR_RESETB, 1); + bool odone_flag = 0; + bool bg_odone_flag = 0; + while(1) { + odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_O_DONE_FLAG); + bg_odone_flag = REGI2C_READ_MASK(I2C_ULP, I2C_ULP_BG_O_DONE_FLAG); + cycle1 = rtc_time_get(); + if (odone_flag && bg_odone_flag) + break; + if (cycle1 >= timeout_cycle) { + SOC_LOGW(TAG, "o_code calibration fail"); + break; + } + } + rtc_clk_cpu_freq_set_config(&old_config); } - rtc_clk_cpu_freq_set_config(&old_config); } } diff --git a/components/hal/esp32s2/adc_hal.c b/components/hal/esp32s2/adc_hal.c index fbb070383d..588d01bd7d 100644 --- a/components/hal/esp32s2/adc_hal.c +++ b/components/hal/esp32s2/adc_hal.c @@ -18,6 +18,8 @@ #include "hal/adc_hal.h" #include "hal/adc_types.h" #include "hal/adc_hal_conf.h" +#include "esp_log.h" +#include "esp32s2/esp_efuse_rtc_table.h" /*--------------------------------------------------------------- Digital controller setting @@ -189,13 +191,6 @@ uint32_t adc_hal_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atte } } - uint32_t code_list[ADC_HAL_CAL_TIMES] = {0}; - uint32_t code_sum = 0; - uint32_t code_h = 0; - uint32_t code_l = 0; - uint32_t chk_code = 0; - uint32_t dout = 0; - adc_hal_set_power_manage(ADC_POWER_SW_ON); if (adc_n == ADC_NUM_2) { adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); @@ -206,56 +201,71 @@ uint32_t adc_hal_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atte // adc_hal_arbiter_config(adc_arbiter_t *config) adc_ll_calibration_prepare(adc_n, channel, internal_gnd); - /* Enable/disable internal connect GND (for calibration). */ - if (internal_gnd) { - adc_ll_rtc_disable_channel(adc_n, channel); - adc_ll_set_atten(adc_n, 0, atten); // Note: when disable all channel, HW auto select channel0 atten param. + uint32_t dout = 0; + // check if we can fetch the values from eFuse. + int version = esp_efuse_rtc_table_read_calib_version(); + if (version == 2) { + int tag = esp_efuse_rtc_table_get_tag(version, adc_n + 1, atten, RTCCALIB_V2_PARAM_VINIT); + dout = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); } else { - adc_ll_rtc_enable_channel(adc_n, channel); - adc_ll_set_atten(adc_n, channel, atten); - } + uint32_t code_list[ADC_HAL_CAL_TIMES] = {0}; + uint32_t code_sum = 0; + uint32_t code_h = 0; + uint32_t code_l = 0; + uint32_t chk_code = 0; - for (uint8_t rpt = 0 ; rpt < ADC_HAL_CAL_TIMES ; rpt ++) { - code_h = ADC_HAL_CAL_OFFSET_RANGE; - code_l = 0; - chk_code = (code_h + code_l) / 2; - adc_ll_set_calibration_param(adc_n, chk_code); - dout = adc_hal_read_self_cal(adc_n, channel); - while (code_h - code_l > 1) { - if (dout == 0) { - code_h = chk_code; - } else { - code_l = chk_code; - } + /* Enable/disable internal connect GND (for calibration). */ + if (internal_gnd) { + adc_ll_rtc_disable_channel(adc_n, channel); + adc_ll_set_atten(adc_n, 0, atten); // Note: when disable all channel, HW auto select channel0 atten param. + } else { + adc_ll_rtc_enable_channel(adc_n, channel); + adc_ll_set_atten(adc_n, channel, atten); + } + + for (uint8_t rpt = 0 ; rpt < ADC_HAL_CAL_TIMES ; rpt ++) { + code_h = ADC_HAL_CAL_OFFSET_RANGE; + code_l = 0; chk_code = (code_h + code_l) / 2; adc_ll_set_calibration_param(adc_n, chk_code); dout = adc_hal_read_self_cal(adc_n, channel); - if ((code_h - code_l == 1)) { - chk_code += 1; + while (code_h - code_l > 1) { + if (dout == 0) { + code_h = chk_code; + } else { + code_l = chk_code; + } + chk_code = (code_h + code_l) / 2; adc_ll_set_calibration_param(adc_n, chk_code); dout = adc_hal_read_self_cal(adc_n, channel); + if ((code_h - code_l == 1)) { + chk_code += 1; + adc_ll_set_calibration_param(adc_n, chk_code); + dout = adc_hal_read_self_cal(adc_n, channel); + } + } + code_list[rpt] = chk_code; + code_sum += chk_code; + } + code_l = code_list[0]; + code_h = code_list[0]; + for (uint8_t i = 0 ; i < ADC_HAL_CAL_TIMES ; i++) { + if (code_l > code_list[i]) { + code_l = code_list[i]; + } + if (code_h < code_list[i]) { + code_h = code_list[i]; } } - code_list[rpt] = chk_code; - code_sum += chk_code; - } - code_l = code_list[0]; - code_h = code_list[0]; - for (uint8_t i = 0 ; i < ADC_HAL_CAL_TIMES ; i++) { - if (code_l > code_list[i]) { - code_l = code_list[i]; - } - if (code_h < code_list[i]) { - code_h = code_list[i]; - } - } - chk_code = code_h + code_l; - dout = ((code_sum - chk_code) % (ADC_HAL_CAL_TIMES - 2) < 4) - ? (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) - : (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) + 1; + chk_code = code_h + code_l; + dout = ((code_sum - chk_code) % (ADC_HAL_CAL_TIMES - 2) < 4) + ? (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) + : (code_sum - chk_code) / (ADC_HAL_CAL_TIMES - 2) + 1; + } adc_ll_set_calibration_param(adc_n, dout); adc_ll_calibration_finish(adc_n); s_adc_cali_param[adc_n][atten] = (uint16_t)dout; + return dout; }