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/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/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/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; } diff --git a/components/hal/adc_hal.c b/components/hal/adc_hal.c index 4cb8922a86..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); } /*--------------------------------------------------------------- @@ -163,20 +322,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_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 913b59ed35..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 { @@ -912,14 +918,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 +930,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/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 1d306db61a..ffad47a5c3 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. @@ -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/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. 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 63ff028fb2..53718723b1 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 026ad37f06..d443e5a3ae 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.