From 83ed258f6f4ad3c754ec25acf0080e618c10fee2 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 25 Dec 2020 14:24:19 +0800 Subject: [PATCH 1/5] adc_digi: update_adc_api_for_5M_freq_limit The ``adc_digi_config_t`` struct is modified on esp32c3: configuration of clock divider factors are not provided anymore. The SARADC sampling frequency is provided instead. In this way, we can handle the frequency limit better. From 3fde25374acc6043ae7ec58c9597b7e687c9f4db Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 5 Jan 2021 11:00:05 +0800 Subject: [PATCH 2/5] adc: add comment for ADC sampling frequency From c257daa950ecc89745b7ff621ae2ca748a55d982 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Mon, 4 Jan 2021 12:25:24 +0800 Subject: [PATCH 3/5] wifi: run adc2 calibration on C3 --- components/driver/include/driver/adc2_wifi_private.h | 11 +++++++++-- components/esp_wifi/src/wifi_init.c | 2 -- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/components/driver/include/driver/adc2_wifi_private.h b/components/driver/include/driver/adc2_wifi_private.h index c5204f8884..c4f622658d 100644 --- a/components/driver/include/driver/adc2_wifi_private.h +++ b/components/driver/include/driver/adc2_wifi_private.h @@ -43,14 +43,21 @@ esp_err_t adc2_wifi_acquire(void); */ esp_err_t adc2_wifi_release(void); -#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 /** * @brief This API help ADC2 calibration constructor be linked. * * @note This is a private function, Don't call `adc2_cal_include` in user code. */ void adc2_cal_include(void); -#endif //CONFIG_IDF_TARGET_ESP32S2 +#else +/** + * @brief There's no calibration involved on this chip. + * + * @note This is a private function, Don't call `adc2_cal_include` in user code. + */ +#define adc2_cal_include() +#endif //CONFIG_IDF_TARGET_* #ifdef __cplusplus } diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 85d74a777c..5a5a5ffcdb 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -247,9 +247,7 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config) return result; } } -#if CONFIG_IDF_TARGET_ESP32S2 adc2_cal_include(); //This enables the ADC2 calibration constructor at start up. -#endif esp_wifi_config_info(); return result; } From 3d7da2c8ffcdade675763647c7610c2f136e6868 Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Fri, 8 Jan 2021 18:44:39 +0800 Subject: [PATCH 4/5] adc: simplify LL on C3 --- components/hal/adc_hal.c | 12 ++---------- components/hal/esp32/include/hal/adc_ll.h | 3 +-- components/hal/esp32c3/include/hal/adc_ll.h | 18 ++++-------------- components/hal/esp32s2/include/hal/adc_ll.h | 2 +- components/hal/esp32s3/include/hal/adc_ll.h | 2 +- 5 files changed, 9 insertions(+), 28 deletions(-) diff --git a/components/hal/adc_hal.c b/components/hal/adc_hal.c index 4cb8922a86..81260a77ec 100644 --- a/components/hal/adc_hal.c +++ b/components/hal/adc_hal.c @@ -163,20 +163,12 @@ void adc_hal_onetime_start(adc_digi_config_t *adc_digi_config) void adc_hal_adc1_onetime_sample_enable(bool enable) { - if (enable) { - adc_ll_adc1_onetime_sample_ena(); - } else { - adc_ll_adc1_onetime_sample_dis(); - } + adc_ll_adc1_onetime_sample_enable(enable); } void adc_hal_adc2_onetime_sample_enable(bool enable) { - if (enable) { - adc_ll_adc2_onetime_sample_ena(); - } else { - adc_ll_adc2_onetime_sample_dis(); - } + adc_ll_adc2_onetime_sample_enable(enable); } void adc_hal_onetime_channel(adc_ll_num_t unit, adc_channel_t channel) diff --git a/components/hal/esp32/include/hal/adc_ll.h b/components/hal/esp32/include/hal/adc_ll.h index ac8e9bd39c..587d7e7a34 100644 --- a/components/hal/esp32/include/hal/adc_ll.h +++ b/components/hal/esp32/include/hal/adc_ll.h @@ -299,9 +299,8 @@ static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel) * @note Only one channel can be selected in once measurement. * * @param adc_n ADC unit. - * @param channel ADC channel number for each ADCn. */ -static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n, int channel) +static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n) { if (adc_n == ADC_NUM_1) { SENS.sar_meas_start1.sar1_en_pad = 0; //only one channel is selected. diff --git a/components/hal/esp32c3/include/hal/adc_ll.h b/components/hal/esp32c3/include/hal/adc_ll.h index 913b59ed35..1287d2c368 100644 --- a/components/hal/esp32c3/include/hal/adc_ll.h +++ b/components/hal/esp32c3/include/hal/adc_ll.h @@ -912,14 +912,9 @@ static inline bool adc_ll_intr_get_status(adc_ll_intr_t mask) } //--------------------------------adc1------------------------------// -static inline void adc_ll_adc1_onetime_sample_ena(void) +static inline void adc_ll_adc1_onetime_sample_enable(bool enable) { - APB_SARADC.onetime_sample.adc1_onetime_sample = 1; -} - -static inline void adc_ll_adc1_onetime_sample_dis(void) -{ - APB_SARADC.onetime_sample.adc1_onetime_sample = 0; + APB_SARADC.onetime_sample.adc1_onetime_sample = enable; } static inline uint32_t adc_ll_adc1_read(void) @@ -929,14 +924,9 @@ static inline uint32_t adc_ll_adc1_read(void) } //--------------------------------adc2------------------------------// -static inline void adc_ll_adc2_onetime_sample_ena(void) +static inline void adc_ll_adc2_onetime_sample_enable(bool enable) { - APB_SARADC.onetime_sample.adc2_onetime_sample = 1; -} - -static inline void adc_ll_adc2_onetime_sample_dis(void) -{ - APB_SARADC.onetime_sample.adc2_onetime_sample = 0; + APB_SARADC.onetime_sample.adc2_onetime_sample = enable; } static inline uint32_t adc_ll_adc2_read(void) diff --git a/components/hal/esp32s2/include/hal/adc_ll.h b/components/hal/esp32s2/include/hal/adc_ll.h index 1d306db61a..bf1ac802e2 100644 --- a/components/hal/esp32s2/include/hal/adc_ll.h +++ b/components/hal/esp32s2/include/hal/adc_ll.h @@ -690,7 +690,7 @@ static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel) * @param adc_n ADC unit. * @param channel ADC channel number for each ADCn. */ -static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n, int channel) +static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n) { if (adc_n == ADC_NUM_1) { SENS.sar_meas1_ctrl2.sar1_en_pad = 0; //only one channel is selected. diff --git a/components/hal/esp32s3/include/hal/adc_ll.h b/components/hal/esp32s3/include/hal/adc_ll.h index b37575193a..276d587adf 100644 --- a/components/hal/esp32s3/include/hal/adc_ll.h +++ b/components/hal/esp32s3/include/hal/adc_ll.h @@ -606,7 +606,7 @@ static inline void adc_ll_rtc_enable_channel(adc_ll_num_t adc_n, int channel) * @param adc_n ADC unit. * @param channel ADC channel number for each ADCn. */ -static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n, int channel) +static inline void adc_ll_rtc_disable_channel(adc_ll_num_t adc_n) { if (adc_n == ADC_NUM_1) { SENS.sar_meas1_ctrl2.sar1_en_pad = 0; //only one channel is selected. From 2b834181412b1f4394c4b5a32ba5400334a9dacb Mon Sep 17 00:00:00 2001 From: "Michael (XIAO Xufeng)" Date: Tue, 19 Jan 2021 20:00:01 +0800 Subject: [PATCH 5/5] adc: add fallback calibration method Also: 1. Separate static configuration into init phase to improve performance 2. Add a init code config layer to avoid duplicated configuration 3. Add a HW_CALIBRATION_V1 caps --- components/driver/adc_common.c | 8 + components/driver/esp32c3/adc.c | 57 ++++--- components/driver/esp32s2/adc.c | 5 + components/driver/test/test_adc_dma.c | 30 +++- .../esp32c3/private_include/regi2c_lp_bias.h | 4 + components/hal/adc_hal.c | 159 ++++++++++++++++++ components/hal/esp32c3/include/hal/adc_hal.h | 14 -- components/hal/esp32c3/include/hal/adc_ll.h | 16 +- components/hal/esp32s2/adc_hal.c | 83 --------- components/hal/esp32s2/include/hal/adc_hal.h | 29 ---- components/hal/esp32s2/include/hal/adc_ll.h | 14 +- components/hal/include/hal/adc_hal.h | 42 +++++ components/soc/esp32c3/include/soc/soc_caps.h | 1 + components/soc/esp32s2/include/soc/soc_caps.h | 2 + 14 files changed, 304 insertions(+), 160 deletions(-) diff --git a/components/driver/adc_common.c b/components/driver/adc_common.c index 3c2400185d..c33f7832c4 100644 --- a/components/driver/adc_common.c +++ b/components/driver/adc_common.c @@ -308,6 +308,10 @@ esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten) adc_hal_set_atten(ADC_NUM_1, channel, atten); ADC_EXIT_CRITICAL(); +#if SOC_ADC_HW_CALIBRATION_V1 + adc_hal_calibration_init(ADC_NUM_1); +#endif + return ESP_OK; } @@ -472,6 +476,10 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) ADC2_WIFI_LOCK_RELEASE(); ADC2_EXIT_CRITICAL(); +#if SOC_ADC_HW_CALIBRATION_V1 + adc_hal_calibration_init(ADC_NUM_2); +#endif + return ESP_OK; } diff --git a/components/driver/esp32c3/adc.c b/components/driver/esp32c3/adc.c index 628bb2f642..e85f3e9a28 100644 --- a/components/driver/esp32c3/adc.c +++ b/components/driver/esp32c3/adc.c @@ -201,6 +201,9 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config) periph_module_enable(PERIPH_SARADC_MODULE); periph_module_enable(PERIPH_GDMA_MODULE); + adc_hal_calibration_init(ADC_NUM_1); + adc_hal_calibration_init(ADC_NUM_2); + return ret; cleanup: @@ -268,8 +271,6 @@ esp_err_t adc_digi_start(void) ADC_DIGI_LOCK_ACQUIRE(); adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); - adc_hal_init(); - if (s_adc_digi_ctx->use_adc1) { uint32_t cal_val = adc_get_calibration_offset(ADC_NUM_1, ADC_CHANNEL_MAX, s_adc_digi_ctx->adc1_atten); adc_hal_set_calibration_param(ADC_NUM_1, cal_val); @@ -279,6 +280,8 @@ esp_err_t adc_digi_start(void) adc_hal_set_calibration_param(ADC_NUM_2, cal_val); } + adc_hal_init(); + adc_hal_arbiter_config(&config); adc_hal_digi_init(&s_adc_digi_ctx->hal_dma, &s_adc_digi_ctx->hal_dma_config); adc_hal_digi_controller_config(&s_adc_digi_ctx->digi_controller_config); @@ -418,6 +421,8 @@ esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten) s_atten1_single[channel] = atten; ret = adc_digi_gpio_init(ADC_NUM_1, BIT(channel)); + adc_hal_calibration_init(ADC_NUM_1); + return ret; } @@ -441,18 +446,19 @@ int adc1_get_raw(adc1_channel_t channel) adc_hal_digi_controller_config(&dig_cfg); adc_hal_intr_clear(ADC_EVENT_ADC1_DONE); + + adc_hal_adc1_onetime_sample_enable(true); adc_hal_onetime_channel(ADC_NUM_1, channel); adc_hal_set_onetime_atten(atten); //Trigger single read. - adc_hal_adc1_onetime_sample_enable(true); adc_hal_onetime_start(&dig_cfg); - while (!adc_hal_intr_get_raw(ADC_EVENT_ADC1_DONE)); + adc_hal_single_read(ADC_NUM_1, &raw_out); + adc_hal_intr_clear(ADC_EVENT_ADC1_DONE); adc_hal_adc1_onetime_sample_enable(false); - adc_hal_single_read(ADC_NUM_1, &raw_out); adc_hal_digi_deinit(); periph_module_disable(PERIPH_SARADC_MODULE); @@ -470,6 +476,8 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten) s_atten2_single[channel] = atten; ret = adc_digi_gpio_init(ADC_NUM_2, BIT(channel)); + adc_hal_calibration_init(ADC_NUM_2); + return ret; } @@ -498,28 +506,26 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * adc_hal_digi_controller_config(&dig_cfg); adc_hal_intr_clear(ADC_EVENT_ADC2_DONE); + + adc_hal_adc2_onetime_sample_enable(true); adc_hal_onetime_channel(ADC_NUM_2, channel); adc_hal_set_onetime_atten(atten); //Trigger single read. - adc_hal_adc2_onetime_sample_enable(true); adc_hal_onetime_start(&dig_cfg); - while (!adc_hal_intr_get_raw(ADC_EVENT_ADC2_DONE)); + ret = adc_hal_single_read(ADC_NUM_2, raw_out); + adc_hal_intr_clear(ADC_EVENT_ADC2_DONE); adc_hal_adc2_onetime_sample_enable(false); - ret = adc_hal_single_read(ADC_NUM_2, raw_out); - if (ret != ESP_OK) { - return ret; - } adc_hal_digi_deinit(); periph_module_disable(PERIPH_SARADC_MODULE); ADC_DIGI_LOCK_RELEASE(); SAC_ADC2_LOCK_RELEASE(); - return ESP_OK; + return ret; } @@ -794,7 +800,7 @@ esp_err_t adc_digi_isr_deregister(void) RTC controller setting ---------------------------------------------------------------*/ -static uint16_t s_adc_cali_param[ADC_ATTEN_MAX] = {}; +static uint16_t s_adc_cali_param[ADC_UNIT_MAX][ADC_ATTEN_MAX] = {}; //NOTE: according to calibration version, different types of lock may be taken during the process: // 1. Semaphore when reading efuse @@ -803,8 +809,8 @@ static uint16_t s_adc_cali_param[ADC_ATTEN_MAX] = {}; static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten) { const bool no_cal = false; - if (s_adc_cali_param[atten]) { - return (uint32_t)s_adc_cali_param[atten]; + if (s_adc_cali_param[adc_n][atten]) { + return (uint32_t)s_adc_cali_param[adc_n][atten]; } if (no_cal) { @@ -813,17 +819,30 @@ static uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t cha // check if we can fetch the values from eFuse. int version = esp_efuse_rtc_calib_get_ver(); - assert(version == 1); - uint32_t init_code = esp_efuse_rtc_calib_get_init_code(version, atten); - ESP_LOGD(ADC_TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n, atten, init_code); - s_adc_cali_param[atten] = init_code; + uint32_t init_code = 0; + if (version == 1) { + //for calibration v1, both ADC units use the same init code (calibrated by ADC1) + init_code = esp_efuse_rtc_calib_get_init_code(version, atten); + ESP_LOGD(ADC_TAG, "Calib(V%d) ADC0, 1 atten=%d: %04X", version, atten, init_code); + s_adc_cali_param[0][atten] = init_code; + s_adc_cali_param[1][atten] = init_code; + } else { + const bool internal_gnd = true; + ADC_ENTER_CRITICAL(); + init_code = adc_hal_self_calibration(adc_n, channel, atten, internal_gnd); + ADC_EXIT_CRITICAL(); + ESP_LOGD(ADC_TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n, atten, init_code); + s_adc_cali_param[adc_n][atten] = init_code; + } + return init_code; } // Internal function to calibrate PWDET for WiFi esp_err_t adc_cal_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten) { + adc_hal_calibration_init(adc_n); uint32_t cal_val = adc_get_calibration_offset(adc_n, channel, atten); ADC_ENTER_CRITICAL(); adc_hal_set_calibration_param(adc_n, cal_val); diff --git a/components/driver/esp32s2/adc.c b/components/driver/esp32s2/adc.c index d38fca916d..40067cd1c4 100644 --- a/components/driver/esp32s2/adc.c +++ b/components/driver/esp32s2/adc.c @@ -74,6 +74,10 @@ esp_err_t adc_digi_init(void) adc_hal_init(); adc_hal_arbiter_config(&config); ADC_EXIT_CRITICAL(); + + adc_hal_calibration_init(ADC_NUM_1); + adc_hal_calibration_init(ADC_NUM_2); + return ESP_OK; } @@ -472,6 +476,7 @@ uint32_t adc_get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t channel, a esp_err_t adc_cal_offset(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten) { + adc_hal_calibration_init(adc_n); uint32_t cal_val = adc_get_calibration_offset(adc_n, channel, atten, false); ADC_ENTER_CRITICAL(); adc_hal_set_calibration_param(adc_n, cal_val); diff --git a/components/driver/test/test_adc_dma.c b/components/driver/test/test_adc_dma.c index d9504cd6d4..9122509c6c 100644 --- a/components/driver/test/test_adc_dma.c +++ b/components/driver/test/test_adc_dma.c @@ -175,9 +175,13 @@ TEST_CASE("test_adc_dma", "[adc][ignore][manual]") ESP_LOGI("TEST_ADC", "Test with atten: %d", atten); memset(read_buf, 0xce, buffer_size); + bool do_calibration = false; + esp_adc_cal_characteristics_t chan1_char = {}; esp_adc_cal_value_t cal_ret = esp_adc_cal_characterize(ADC_UNIT_1, atten, ADC_WIDTH_12Bit, 0, &chan1_char); - TEST_ASSERT(cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP); + if (cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP) { + do_calibration = true; + } continuous_adc_init(adc1_chan_mask, adc2_chan_mask, channel, sizeof(channel) / sizeof(adc_channel_t), atten); adc_digi_start(); @@ -201,9 +205,11 @@ TEST_CASE("test_adc_dma", "[adc][ignore][manual]") print_summary(print_figure); - uint32_t raw = get_average(); - uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(raw, &chan1_char); - printf("Voltage = %d mV\n", voltage_mv); + if (do_calibration) { + uint32_t raw = get_average(); + uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(raw, &chan1_char); + printf("Voltage = %d mV\n", voltage_mv); + } adc_digi_stop(); TEST_ESP_OK(adc_digi_deinitialize()); @@ -240,9 +246,13 @@ TEST_CASE("test_adc_single", "[adc][ignore][manual]") adc1_config_channel_atten(ADC1_CHANNEL_2, atten); + bool do_calibration = false; + esp_adc_cal_characteristics_t chan1_char = {}; esp_adc_cal_value_t cal_ret = esp_adc_cal_characterize(ADC_UNIT_1, atten, ADC_WIDTH_12Bit, 0, &chan1_char); - TEST_ASSERT(cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP); + if (cal_ret == ESP_ADC_CAL_VAL_EFUSE_TP) { + do_calibration = true; + } const int test_count = TEST_COUNT; @@ -258,9 +268,13 @@ TEST_CASE("test_adc_single", "[adc][ignore][manual]") print_summary(print_figure); break; } - uint32_t raw = get_average(); - uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(raw, &chan1_char); - printf("Voltage = %d mV\n", voltage_mv); + + if (do_calibration) { + uint32_t raw = get_average(); + uint32_t voltage_mv = esp_adc_cal_raw_to_voltage(raw, &chan1_char); + printf("Voltage = %d mV\n", voltage_mv); + } + if (atten == target_atten) { break; diff --git a/components/esp_hw_support/port/esp32c3/private_include/regi2c_lp_bias.h b/components/esp_hw_support/port/esp32c3/private_include/regi2c_lp_bias.h index f89a53f0b4..0dae77107c 100644 --- a/components/esp_hw_support/port/esp32c3/private_include/regi2c_lp_bias.h +++ b/components/esp_hw_support/port/esp32c3/private_include/regi2c_lp_bias.h @@ -50,6 +50,10 @@ #define I2C_ULP_BG_O_DONE_FLAG_MSB 3 #define I2C_ULP_BG_O_DONE_FLAG_LSB 3 +#define I2C_ULP_OCODE 4 +#define I2C_ULP_OCODE_MSB 7 +#define I2C_ULP_OCODE_LSB 0 + #define I2C_ULP_IR_FORCE_CODE 5 #define I2C_ULP_IR_FORCE_CODE_MSB 6 #define I2C_ULP_IR_FORCE_CODE_LSB 6 diff --git a/components/hal/adc_hal.c b/components/hal/adc_hal.c index 81260a77ec..a2ffdd5a36 100644 --- a/components/hal/adc_hal.c +++ b/components/hal/adc_hal.c @@ -12,8 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "soc/soc_caps.h" #include "hal/adc_hal.h" #include "hal/adc_hal_conf.h" +#include "sdkconfig.h" +#include #if CONFIG_IDF_TARGET_ESP32C3 @@ -50,6 +53,159 @@ int adc_hal_convert(adc_ll_num_t adc_n, int channel, int *value) } #endif +/*--------------------------------------------------------------- + ADC calibration setting +---------------------------------------------------------------*/ +#if SOC_ADC_HW_CALIBRATION_V1 +// ESP32-S2 and C3 support HW offset calibration. + +void adc_hal_calibration_init(adc_ll_num_t adc_n) +{ + adc_ll_calibration_init(adc_n); +} + +static uint32_t s_previous_init_code[SOC_ADC_PERIPH_NUM] = {-1, -1}; + +void adc_hal_set_calibration_param(adc_ll_num_t adc_n, uint32_t param) +{ + if (param != s_previous_init_code[adc_n]) { + adc_ll_set_calibration_param(adc_n, param); + s_previous_init_code[adc_n] = param; + } +} + +#if CONFIG_IDF_TARGET_ESP32S2 +static void cal_setup(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd) +{ + adc_hal_set_controller(adc_n, ADC_CTRL_RTC); //Set controller + + /* Enable/disable internal connect GND (for calibration). */ + if (internal_gnd) { + adc_ll_rtc_disable_channel(adc_n); + 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); + } +} + +static uint32_t read_cal_channel(adc_ll_num_t adc_n, int channel) +{ + adc_ll_rtc_start_convert(adc_n, channel); + while (adc_ll_rtc_convert_is_done(adc_n) != true); + return (uint32_t)adc_ll_rtc_get_convert_value(adc_n); +} + +#elif CONFIG_IDF_TARGET_ESP32C3 +static void cal_setup(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd) +{ + adc_hal_set_controller(adc_n, ADC_CTRL_DIG); //Set controller + + adc_digi_config_t dig_cfg = { + .conv_limit_en = 0, + .conv_limit_num = 250, + .sample_freq_hz = SOC_ADC_SAMPLE_FREQ_THRES_HIGH, + }; + adc_hal_digi_controller_config(&dig_cfg); + + /* Enable/disable internal connect GND (for calibration). */ + if (internal_gnd) { + const int esp32c3_invalid_chan = (adc_n == ADC_NUM_1)? 0xF: 0x1; + adc_ll_onetime_set_channel(adc_n, esp32c3_invalid_chan); + } else { + adc_ll_onetime_set_channel(adc_n, channel); + } + adc_ll_onetime_set_atten(atten); + adc_hal_adc1_onetime_sample_enable((adc_n == ADC_NUM_1)); + adc_hal_adc2_onetime_sample_enable((adc_n == ADC_NUM_2)); +} + +static uint32_t read_cal_channel(adc_ll_num_t adc_n, int channel) +{ + adc_ll_intr_clear(ADC_LL_INTR_ADC1_DONE | ADC_LL_INTR_ADC2_DONE); + adc_ll_onetime_start(false); + esp_rom_delay_us(5); + adc_ll_onetime_start(true); + + while(!adc_ll_intr_get_raw(ADC_LL_INTR_ADC1_DONE | ADC_LL_INTR_ADC2_DONE)); + + uint32_t read_val = -1; + if (adc_n == ADC_NUM_1) { + read_val = adc_ll_adc1_read(); + } else if (adc_n == ADC_NUM_2) { + read_val = adc_ll_adc2_read(); + if (adc_ll_analysis_raw_data(adc_n, read_val)) { + return -1; + } + } + return read_val; +} +#endif //CONFIG_IDF_TARGET_* + +#define ADC_HAL_CAL_TIMES (10) +#define ADC_HAL_CAL_OFFSET_RANGE (4096) + +uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd) +{ + adc_hal_set_power_manage(ADC_POWER_SW_ON); + + if (adc_n == ADC_NUM_2) { + adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); + adc_hal_arbiter_config(&config); + } + + cal_setup(adc_n, channel, atten, internal_gnd); + + adc_ll_calibration_prepare(adc_n, channel, internal_gnd); + + 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); + uint32_t self_cal = read_cal_channel(adc_n, channel); + while (code_h - code_l > 1) { + if (self_cal == 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); + self_cal = read_cal_channel(adc_n, channel); + if ((code_h - code_l == 1)) { + chk_code += 1; + adc_ll_set_calibration_param(adc_n, chk_code); + self_cal = read_cal_channel(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++) { + code_l = MIN(code_l, code_list[i]); + code_h = MAX(code_h, code_list[i]); + } + + chk_code = code_h + code_l; + uint32_t ret = ((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_calibration_finish(adc_n); + return ret; +} +#endif //SOC_ADC_HW_CALIBRATION_V1 + #if CONFIG_IDF_TARGET_ESP32C3 //This feature is currently supported on ESP32C3, will be supported on other chips soon /*--------------------------------------------------------------- @@ -130,6 +286,9 @@ void adc_hal_digi_init(adc_dma_hal_context_t *adc_dma_ctx, adc_dma_hal_config_t gdma_ll_enable_clock(adc_dma_ctx->dev, true); gdma_ll_clear_interrupt_status(adc_dma_ctx->dev, dma_config->dma_chan, UINT32_MAX); gdma_ll_rx_connect_to_periph(adc_dma_ctx->dev, dma_config->dma_chan, SOC_GDMA_TRIG_PERIPH_ADC0); + + adc_ll_adc1_onetime_sample_enable(false); + adc_ll_adc2_onetime_sample_enable(false); } /*--------------------------------------------------------------- diff --git a/components/hal/esp32c3/include/hal/adc_hal.h b/components/hal/esp32c3/include/hal/adc_hal.h index 122d438d3e..2f6fffeaad 100644 --- a/components/hal/esp32c3/include/hal/adc_hal.h +++ b/components/hal/esp32c3/include/hal/adc_hal.h @@ -206,20 +206,6 @@ void adc_hal_digi_monitor_enable(adc_digi_monitor_idx_t mon_idx, bool enable); */ void adc_hal_arbiter_config(adc_arbiter_t *config); -/*--------------------------------------------------------------- - ADC calibration setting ----------------------------------------------------------------*/ - - -/** - * Set the calibration result (initial data) to ADC. - * - * @note Different ADC units and different attenuation options use different calibration data (initial data). - * - * @param adc_n ADC index number. - */ -#define adc_hal_set_calibration_param(adc_n, param) adc_ll_set_calibration_param(adc_n, param); - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/adc_ll.h b/components/hal/esp32c3/include/hal/adc_ll.h index 1287d2c368..ecbface280 100644 --- a/components/hal/esp32c3/include/hal/adc_ll.h +++ b/components/hal/esp32c3/include/hal/adc_ll.h @@ -738,6 +738,17 @@ static inline void adc_ll_set_arbiter_priority(uint8_t pri_rtc, uint8_t pri_dig, } /* ADC calibration code. */ +/** + * @brief Set common calibration configuration. Should be shared with other parts (PWDET). + */ +static inline void adc_ll_calibration_init(adc_ll_num_t adc_n) +{ + if (adc_n == ADC_NUM_1) { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 1); + } else { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 1); + } +} /** * Configure the registers for ADC calibration. You need to call the ``adc_ll_calibration_finish`` interface to resume after calibration. @@ -751,19 +762,14 @@ static inline void adc_ll_set_arbiter_priority(uint8_t pri_rtc, uint8_t pri_dig, */ static inline void adc_ll_calibration_prepare(adc_ll_num_t adc_n, adc_channel_t channel, bool internal_gnd) { - /* Should be called before writing I2C registers. */ - SET_PERI_REG_MASK(RTC_CNTL_ANA_CONF_REG, RTC_CNTL_SAR_I2C_PU); - /* Enable/disable internal connect GND (for calibration). */ if (adc_n == ADC_NUM_1) { - REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 4); if (internal_gnd) { REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 1); } else { REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0); } } else { - REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 4); if (internal_gnd) { REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 1); } else { diff --git a/components/hal/esp32s2/adc_hal.c b/components/hal/esp32s2/adc_hal.c index 68e8b98071..9a8992cb2c 100644 --- a/components/hal/esp32s2/adc_hal.c +++ b/components/hal/esp32s2/adc_hal.c @@ -146,86 +146,3 @@ void adc_hal_arbiter_config(adc_arbiter_t *config) adc_ll_set_arbiter_work_mode(config->mode); adc_ll_set_arbiter_priority(config->rtc_pri, config->dig_pri, config->pwdet_pri); } - -/*--------------------------------------------------------------- - ADC calibration setting ----------------------------------------------------------------*/ -#define ADC_HAL_CAL_TIMES (10) -#define ADC_HAL_CAL_OFFSET_RANGE (4096) - -static uint32_t read_cal_channel(adc_ll_num_t adc_n, int channel) -{ - adc_ll_rtc_start_convert(adc_n, channel); - while (adc_ll_rtc_convert_is_done(adc_n) != true); - return (uint32_t)adc_ll_rtc_get_convert_value(adc_n); -} - -uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd) -{ - adc_hal_set_power_manage(ADC_POWER_SW_ON); - - if (adc_n == ADC_NUM_2) { - adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT(); - adc_hal_arbiter_config(&config); - } - adc_hal_set_controller(adc_n, ADC_CTRL_RTC); //Set controller - - - 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. - } 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); - uint32_t self_cal = read_cal_channel(adc_n, channel); - while (code_h - code_l > 1) { - if (self_cal == 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); - self_cal = read_cal_channel(adc_n, channel); - if ((code_h - code_l == 1)) { - chk_code += 1; - adc_ll_set_calibration_param(adc_n, chk_code); - self_cal = read_cal_channel(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]; - } - } - chk_code = code_h + code_l; - uint32_t ret = ((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_calibration_finish(adc_n); - return ret; -} diff --git a/components/hal/esp32s2/include/hal/adc_hal.h b/components/hal/esp32s2/include/hal/adc_hal.h index d72f94cce7..ac80417ff3 100644 --- a/components/hal/esp32s2/include/hal/adc_hal.h +++ b/components/hal/esp32s2/include/hal/adc_hal.h @@ -214,35 +214,6 @@ void adc_hal_digi_monitor_config(adc_ll_num_t adc_n, adc_digi_monitor_t *config) */ void adc_hal_arbiter_config(adc_arbiter_t *config); -/*--------------------------------------------------------------- - ADC calibration setting ----------------------------------------------------------------*/ - -/** - * Calibrate the ADC using internal connections. - * - * @note Different ADC units and different attenuation options use different calibration data (initial data). - * - * @param adc_n ADC index number. - * @param channel adc channel number. - * @param atten The attenuation for the channel - * @param internal_gnd true: Disconnect from the IO port and use the internal GND as the calibration voltage. - * false: Use IO external voltage as calibration voltage. - * - * @return - * - The calibration result (initial data) to ADC, use `adc_hal_set_calibration_param` to set. - */ -uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd); - -/** - * Set the calibration result (initial data) to ADC. - * - * @note Different ADC units and different attenuation options use different calibration data (initial data). - * - * @param adc_n ADC index number. - */ -#define adc_hal_set_calibration_param(adc_n, param) adc_ll_set_calibration_param(adc_n, param); - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/adc_ll.h b/components/hal/esp32s2/include/hal/adc_ll.h index bf1ac802e2..ffad47a5c3 100644 --- a/components/hal/esp32s2/include/hal/adc_ll.h +++ b/components/hal/esp32s2/include/hal/adc_ll.h @@ -1123,6 +1123,18 @@ static inline void adc_ll_disable_sleep_controller(void) } /* ADC calibration code. */ +/** + * @brief Set common calibration configuration. Should be shared with other parts (PWDET). + */ +static inline void adc_ll_calibration_init(adc_ll_num_t adc_n) +{ + if (adc_n == ADC_NUM_1) { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 4); + } else { + REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 4); + } +} + /** * Configure the registers for ADC calibration. You need to call the ``adc_ll_calibration_finish`` interface to resume after calibration. * @@ -1143,14 +1155,12 @@ static inline void adc_ll_calibration_prepare(adc_ll_num_t adc_n, adc_channel_t /* Enable/disable internal connect GND (for calibration). */ if (adc_n == ADC_NUM_1) { - REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_DREF_ADDR, 4); if (internal_gnd) { REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 1); } else { REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR1_ENCAL_GND_ADDR, 0); } } else { - REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_DREF_ADDR, 4); if (internal_gnd) { REGI2C_WRITE_MASK(I2C_SAR_ADC, ADC_SAR2_ENCAL_GND_ADDR, 1); } else { diff --git a/components/hal/include/hal/adc_hal.h b/components/hal/include/hal/adc_hal.h index dc048d4ad2..db7a1e3aa2 100644 --- a/components/hal/include/hal/adc_hal.h +++ b/components/hal/include/hal/adc_hal.h @@ -1,5 +1,6 @@ #pragma once +#include "soc/soc_caps.h" #include "hal/adc_types.h" #include "hal/adc_ll.h" @@ -206,6 +207,47 @@ void adc_hal_digi_controller_config(const adc_digi_config_t *cfg); */ #define adc_hal_digi_clear_pattern_table(adc_n) adc_ll_digi_clear_pattern_table(adc_n) +/*--------------------------------------------------------------- + ADC calibration setting +---------------------------------------------------------------*/ +#if SOC_ADC_HW_CALIBRATION_V1 +// ESP32-S2 and C3 support HW offset calibration. + +/** + * @brief Initialize default parameter for the calibration block. + * + * @param adc_n ADC index numer + */ +void adc_hal_calibration_init(adc_ll_num_t adc_n); + +/** + * Set the calibration result (initial data) to ADC. + * + * @note Different ADC units and different attenuation options use different calibration data (initial data). + * + * @param adc_n ADC index number. + * @param param the calibration parameter to configure + */ +void adc_hal_set_calibration_param(adc_ll_num_t adc_n, uint32_t param); + +/** + * Calibrate the ADC using internal connections. + * + * @note Different ADC units and different attenuation options use different calibration data (initial data). + * + * @param adc_n ADC index number. + * @param channel adc channel number. + * @param atten The attenuation for the channel + * @param internal_gnd true: Disconnect from the IO port and use the internal GND as the calibration voltage. + * false: Use IO external voltage as calibration voltage. + * + * @return + * - The calibration result (initial data) to ADC, use `adc_hal_set_calibration_param` to set. + */ +uint32_t adc_hal_self_calibration(adc_ll_num_t adc_n, adc_channel_t channel, adc_atten_t atten, bool internal_gnd); + +#endif //SOC_ADC_HW_CALIBRATION_V1 + #if CONFIG_IDF_TARGET_ESP32C3 /*--------------------------------------------------------------- DMA setting diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 0f256f5843..98ff169a19 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -109,6 +109,7 @@ #define SOC_ADC_MAX_BITWIDTH (12) #define SOC_ADC_DIGI_FILTER_NUM (2) #define SOC_ADC_DIGI_MONITOR_NUM (2) +#define SOC_ADC_HW_CALIBRATION_V1 (1) /*!< support HW offset calibration */ #define SOC_ADC_SUPPORT_DMA_MODE(PERIPH_NUM) 1 //F_sample = F_digi_con / 2 / interval. F_digi_con = 5M for now. 30 <= interva <= 4095 #define SOC_ADC_SAMPLE_FREQ_THRES_HIGH 83333 diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index 6368926b85..76ce4697ff 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -58,6 +58,8 @@ #define SOC_ADC_CHANNEL_NUM(PERIPH_NUM) (10) #define SOC_ADC_MAX_CHANNEL_NUM (10) #define SOC_ADC_MAX_BITWIDTH (13) +#define SOC_ADC_HW_CALIBRATION_V1 (1) /*!< support HW offset calibration */ + /** * Check if adc support digital controller (DMA) mode.