diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 5dc25f9776..4e65c15274 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -121,7 +121,7 @@ else() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS ${includes} PRIV_INCLUDE_DIRS "include/driver" - PRIV_REQUIRES efuse esp_timer esp_adc + PRIV_REQUIRES efuse esp_timer REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support LDFRAGMENTS linker.lf) endif() diff --git a/components/driver/deprecated/adc_dma_legacy.c b/components/driver/deprecated/adc_dma_legacy.c index 625773a79e..9097a7170e 100644 --- a/components/driver/deprecated/adc_dma_legacy.c +++ b/components/driver/deprecated/adc_dma_legacy.c @@ -19,11 +19,11 @@ #include "freertos/timers.h" #include "freertos/ringbuf.h" #include "esp_private/periph_ctrl.h" -#include "esp_private/adc_private.h" -#include "esp_private/adc_lock.h" +#include "esp_private/adc_share_hw_ctrl.h" #include "hal/adc_types.h" #include "hal/adc_hal.h" #include "hal/dma_types.h" +#include "hal/adc_hal_common.h" #include "driver/gpio.h" #include "driver/adc_types_legacy.h" @@ -588,3 +588,23 @@ static void check_adc_continuous_driver_conflict(void) } ESP_EARLY_LOGW(ADC_TAG, "legacy driver is deprecated, please migrate to `esp_adc/adc_continuous.h`"); } + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED +/*--------------------------------------------------------------- + ADC Hardware Calibration +---------------------------------------------------------------*/ +static __attribute__((constructor)) void adc_hw_calibration(void) +{ + //Calculate all ICode + for (int i = 0; i < SOC_ADC_PERIPH_NUM; i++) { + adc_hal_calibration_init(i); + for (int j = 0; j < SOC_ADC_ATTEN_NUM; j++) { + /** + * This may get wrong when attenuations are NOT consecutive on some chips, + * update this when bringing up the calibration on that chip + */ + adc_calc_hw_calibration_code(i, j); + } + } +} +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED diff --git a/components/driver/deprecated/adc_i2s_deprecated.c b/components/driver/deprecated/adc_i2s_deprecated.c index 245214f9f6..ad125c8481 100644 --- a/components/driver/deprecated/adc_i2s_deprecated.c +++ b/components/driver/deprecated/adc_i2s_deprecated.c @@ -20,7 +20,6 @@ #ifdef CONFIG_PM_ENABLE #include "esp_pm.h" #endif -#include "esp_private/adc_private.h" #include "freertos/FreeRTOS.h" #include "driver/adc_i2s_legacy.h" diff --git a/components/driver/deprecated/adc_legacy.c b/components/driver/deprecated/adc_legacy.c index 5620b56a6d..67d586efc5 100644 --- a/components/driver/deprecated/adc_legacy.c +++ b/components/driver/deprecated/adc_legacy.c @@ -18,13 +18,13 @@ #include "driver/rtc_io.h" #include "sys/lock.h" #include "driver/gpio.h" -#include "esp_private/adc_private.h" +#include "esp_private/adc_share_hw_ctrl.h" #include "adc1_private.h" #include "hal/adc_types.h" #include "hal/adc_hal.h" +#include "hal/adc_hal_common.h" #include "hal/adc_hal_conf.h" #include "esp_private/periph_ctrl.h" -#include "esp_private/adc_lock.h" #include "driver/adc_types_legacy.h" #if SOC_DAC_SUPPORTED @@ -904,8 +904,6 @@ static esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, int *out_raw) return ESP_OK; } -#if !CONFIG_IDF_TARGET_ESP32 -//wrapper should be removed after I2S deprecation /** * @brief This function will be called during start up, to check that adc_oneshot driver is not running along with the legacy adc oneshot driver */ @@ -921,4 +919,23 @@ static void check_adc_oneshot_driver_conflict(void) } ESP_EARLY_LOGW(ADC_TAG, "legacy driver is deprecated, please migrate to `esp_adc/adc_oneshot.h`"); } -#endif + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED +/*--------------------------------------------------------------- + ADC Hardware Calibration +---------------------------------------------------------------*/ +static __attribute__((constructor)) void adc_hw_calibration(void) +{ + //Calculate all ICode + for (int i = 0; i < SOC_ADC_PERIPH_NUM; i++) { + adc_hal_calibration_init(i); + for (int j = 0; j < SOC_ADC_ATTEN_NUM; j++) { + /** + * This may get wrong when attenuations are NOT consecutive on some chips, + * update this when bringing up the calibration on that chip + */ + adc_calc_hw_calibration_code(i, j); + } + } +} +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED diff --git a/components/driver/deprecated/i2s_legacy.c b/components/driver/deprecated/i2s_legacy.c index 5b29e52d62..21e7dde2f6 100644 --- a/components/driver/deprecated/i2s_legacy.c +++ b/components/driver/deprecated/i2s_legacy.c @@ -27,7 +27,7 @@ #include "hal/i2s_hal.h" #if SOC_I2S_SUPPORTS_DAC #include "driver/dac.h" -#include "esp_private/adc_private.h" +#include "esp_private/adc_share_hw_ctrl.h" #include "adc1_private.h" #include "driver/adc_i2s_legacy.h" #include "driver/adc_types_legacy.h" diff --git a/components/esp_adc/CMakeLists.txt b/components/esp_adc/CMakeLists.txt index 44e8d40724..35d5a68737 100644 --- a/components/esp_adc/CMakeLists.txt +++ b/components/esp_adc/CMakeLists.txt @@ -6,18 +6,12 @@ set(srcs "adc_cali.c" "adc_cali_curve_fitting.c" "adc_oneshot.c" "adc_common.c" - "adc_lock.c" "deprecated/esp_adc_cal_common_legacy.c") if(CONFIG_SOC_ADC_DMA_SUPPORTED) list(APPEND srcs "adc_continuous.c") endif() -# init constructor for wifi -if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/adc2_init_cal.c") - list(APPEND srcs "${target}/adc2_init_cal.c") -endif() - # line fitting scheme if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/adc_cali_line_fitting.c") list(APPEND srcs "${target}/adc_cali_line_fitting.c") diff --git a/components/esp_adc/adc_common.c b/components/esp_adc/adc_common.c index 1e449f6653..2199d46ce2 100644 --- a/components/esp_adc/adc_common.c +++ b/components/esp_adc/adc_common.c @@ -11,18 +11,13 @@ #include "freertos/FreeRTOS.h" #include "esp_private/periph_ctrl.h" #include "esp_private/adc_private.h" +#include "esp_private/adc_share_hw_ctrl.h" #include "driver/gpio.h" #include "hal/adc_hal.h" #include "hal/adc_hal_common.h" #include "hal/adc_hal_conf.h" #include "soc/adc_periph.h" -//For calibration -#if CONFIG_IDF_TARGET_ESP32S2 -#include "esp_efuse_rtc_table.h" -#elif SOC_ADC_CALIBRATION_V1_SUPPORTED -#include "esp_efuse_rtc_calib.h" -#endif static const char *TAG = "adc_common"; static portMUX_TYPE s_spinlock = portMUX_INITIALIZER_UNLOCKED; @@ -62,54 +57,6 @@ void adc_apb_periph_free(void) portEXIT_CRITICAL(&s_spinlock); } -/*------------------------------------------------------------------------------ -* ADC Power -*----------------------------------------------------------------------------*/ -// This gets incremented when adc_power_acquire() is called, and decremented when -// adc_power_release() is called. ADC is powered down when the value reaches zero. -// Should be modified within critical section (ADC_ENTER/EXIT_CRITICAL). -static int s_adc_power_on_cnt; - -static void adc_power_on_internal(void) -{ - /* Set the power always on to increase precision. */ - adc_hal_set_power_manage(ADC_POWER_SW_ON); -} - -void adc_power_acquire(void) -{ - portENTER_CRITICAL(&rtc_spinlock); - s_adc_power_on_cnt++; - if (s_adc_power_on_cnt == 1) { - adc_power_on_internal(); - } - portEXIT_CRITICAL(&rtc_spinlock); -} - -static void adc_power_off_internal(void) -{ -#if CONFIG_IDF_TARGET_ESP32 - adc_hal_set_power_manage(ADC_POWER_SW_OFF); -#else - adc_hal_set_power_manage(ADC_POWER_BY_FSM); -#endif -} - -void adc_power_release(void) -{ - portENTER_CRITICAL(&rtc_spinlock); - s_adc_power_on_cnt--; - /* Sanity check */ - if (s_adc_power_on_cnt < 0) { - portEXIT_CRITICAL(&rtc_spinlock); - ESP_LOGE(TAG, "%s called, but s_adc_power_on_cnt == 0", __func__); - abort(); - } else if (s_adc_power_on_cnt == 0) { - adc_power_off_internal(); - } - portEXIT_CRITICAL(&rtc_spinlock); -} - /*--------------------------------------------------------------- ADC IOs ---------------------------------------------------------------*/ @@ -145,52 +92,6 @@ esp_err_t adc_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_n /*--------------------------------------------------------------- ADC Hardware Calibration ---------------------------------------------------------------*/ -#if CONFIG_IDF_TARGET_ESP32S2 -#define esp_efuse_rtc_calib_get_ver() esp_efuse_rtc_table_read_calib_version() - -static inline uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten) -{ - int tag = esp_efuse_rtc_table_get_tag(version, adc_unit + 1, atten, RTCCALIB_V2_PARAM_VINIT); - return esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); -} -#endif - -static uint32_t s_adc_cali_param[SOC_ADC_PERIPH_NUM][SOC_ADC_ATTEN_NUM] = {}; - -void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten) -{ - if (s_adc_cali_param[adc_n][atten]) { - ESP_EARLY_LOGV(TAG, "Use calibrated val ADC%d atten=%d: %04X", adc_n + 1, atten, s_adc_cali_param[adc_n][atten]); - return ; - } - - // check if we can fetch the values from eFuse. - int version = esp_efuse_rtc_calib_get_ver(); - - uint32_t init_code = 0; - - if (version == ESP_EFUSE_ADC_CALIB_VER) { - init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten); - } else { - ESP_EARLY_LOGD(TAG, "Calibration eFuse is not configured, use self-calibration for ICode"); - adc_power_acquire(); - portENTER_CRITICAL(&rtc_spinlock); - adc_ll_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT); - const bool internal_gnd = true; - init_code = adc_hal_self_calibration(adc_n, atten, internal_gnd); - portEXIT_CRITICAL(&rtc_spinlock); - adc_power_release(); - } - - s_adc_cali_param[adc_n][atten] = init_code; - ESP_EARLY_LOGV(TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n + 1, atten, init_code); -} - -void IRAM_ATTR adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten) -{ - adc_hal_set_calibration_param(adc_n, s_adc_cali_param[adc_n][atten]); -} - static __attribute__((constructor)) void adc_hw_calibration(void) { //Calculate all ICode diff --git a/components/esp_adc/adc_continuous.c b/components/esp_adc/adc_continuous.c index b5dd51d70d..73c00e6cf9 100644 --- a/components/esp_adc/adc_continuous.c +++ b/components/esp_adc/adc_continuous.c @@ -20,7 +20,7 @@ #include "freertos/ringbuf.h" #include "esp_private/periph_ctrl.h" #include "esp_private/adc_private.h" -#include "esp_private/adc_lock.h" +#include "esp_private/adc_share_hw_ctrl.h" #include "driver/gpio.h" #include "esp_adc/adc_continuous.h" #include "hal/adc_types.h" diff --git a/components/esp_adc/adc_lock.c b/components/esp_adc/adc_lock.c index 8251aabbc7..e69de29bb2 100644 --- a/components/esp_adc/adc_lock.c +++ b/components/esp_adc/adc_lock.c @@ -1,87 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include "sdkconfig.h" -#include "sys/lock.h" -#include "esp_log.h" -#include "esp_err.h" -#include "esp_check.h" -#include "hal/adc_types.h" - -#include "esp_private/adc_lock.h" -#include "esp_private/adc2_wifi.h" - - -static const char *TAG = "adc_lock"; - -static _lock_t adc1_lock; -static _lock_t adc2_lock; - -esp_err_t adc_lock_acquire(adc_unit_t adc_unit) -{ - if (adc_unit == ADC_UNIT_1) { - _lock_acquire(&adc1_lock); - } - - if (adc_unit == ADC_UNIT_2) { - _lock_acquire(&adc2_lock); - } - - return ESP_OK; -} - -esp_err_t adc_lock_release(adc_unit_t adc_unit) -{ - if (adc_unit == ADC_UNIT_2) { - ESP_RETURN_ON_FALSE(((uint32_t *)adc2_lock != NULL), ESP_ERR_INVALID_STATE, TAG, "adc2 lock release without acquiring"); - _lock_release(&adc2_lock); - } - - if (adc_unit == ADC_UNIT_1) { - ESP_RETURN_ON_FALSE(((uint32_t *)adc1_lock != NULL), ESP_ERR_INVALID_STATE, TAG, "adc1 lock release without acquiring"); - _lock_release(&adc1_lock); - } - - return ESP_OK; -} - -esp_err_t adc_lock_try_acquire(adc_unit_t adc_unit) -{ - if (adc_unit == ADC_UNIT_1) { - if (_lock_try_acquire(&adc1_lock) == -1) { - return ESP_ERR_TIMEOUT; - } - } - - if (adc_unit == ADC_UNIT_2) { - if (_lock_try_acquire(&adc2_lock) == -1) { - return ESP_ERR_TIMEOUT; - } - } - - return ESP_OK; -} - -esp_err_t adc2_wifi_acquire(void) -{ -#if CONFIG_IDF_TARGET_ESP32 - /* Wi-Fi module will use adc2. Use locks to avoid conflicts. */ - adc_lock_acquire(ADC_UNIT_2); - ESP_LOGD(TAG, "Wi-Fi takes adc2 lock."); -#endif - - return ESP_OK; -} - -esp_err_t adc2_wifi_release(void) -{ -#if CONFIG_IDF_TARGET_ESP32 - return adc_lock_release(ADC_UNIT_2); -#endif - - return ESP_OK; -} diff --git a/components/esp_adc/adc_oneshot.c b/components/esp_adc/adc_oneshot.c index da90cf486e..681166bf07 100644 --- a/components/esp_adc/adc_oneshot.c +++ b/components/esp_adc/adc_oneshot.c @@ -16,7 +16,7 @@ #include "driver/rtc_io.h" #include "esp_adc/adc_oneshot.h" #include "esp_private/adc_private.h" -#include "esp_private/adc_lock.h" +#include "esp_private/adc_share_hw_ctrl.h" #include "hal/adc_types.h" #include "hal/adc_oneshot_hal.h" #include "hal/adc_ll.h" diff --git a/components/esp_adc/include/esp_private/adc2_wifi.h b/components/esp_adc/include/esp_private/adc2_wifi.h deleted file mode 100644 index 2d0e1baad5..0000000000 --- a/components/esp_adc/include/esp_private/adc2_wifi.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "sdkconfig.h" -#include "esp_err.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** - * @brief For WIFI module to claim the usage of ADC2. - * - * Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``. - * The WIFI module may have to wait for a short time for the current conversion (if exist) to finish. - * - * @return - * - ESP_OK success - * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. - */ -esp_err_t adc2_wifi_acquire(void); - -/** - * @brief For WIFI module to let other tasks use the ADC2 when WIFI is not work. - * - * Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``. - * Call this function to release the occupation of ADC2 by WIFI. - * - * @return - * - ESP_OK: On success - * - ESP_ERR_INVALID_STATE: The lock(s) isn't acquired yet - */ -esp_err_t adc2_wifi_release(void); - -#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); -#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 -} -#endif diff --git a/components/esp_adc/include/esp_private/adc_lock.h b/components/esp_adc/include/esp_private/adc_lock.h index a11b73e833..e69de29bb2 100644 --- a/components/esp_adc/include/esp_private/adc_lock.h +++ b/components/esp_adc/include/esp_private/adc_lock.h @@ -1,60 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "esp_err.h" -#include "hal/adc_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Acquire ADC lock by unit - * - * The lock acquiring sequence will be: ADC1, ADC2, ... - * - * @note If any of the locks are taken, this API will wait until the lock is successfully acquired. - * - * @param[in] adc_unit ADC unit ID - * - * @return - * - ESP_OK: On success - */ -esp_err_t adc_lock_acquire(adc_unit_t adc_unit); - -/** - * @brief Release ADC lock by unit - * - * The lock releasing sequence will be: ..., ADC2, ADC1 - * - * @param[in] adc_unit ADC unit ID - * - * @return - * - ESP_OK: On success - * - ESP_ERR_INVALID_STATE: The lock(s) isn't acquired yet - */ -esp_err_t adc_lock_release(adc_unit_t adc_unit); - -/** - * @brief Try to acquire ADC lock by unit - * - * The lock acquiring sequence will be: ADC1, ADC2, ... - * - * @note If any of the locks are taken, this API will return immediately with an error `ESP_ERR_TIMEOUT` - * - * @param[in] adc_unit ADC unit ID - * - * @return - * - ESP_OK: On success - * - ESP_ERR_TIMEOUT: Lock(s) is taken already - */ -esp_err_t adc_lock_try_acquire(adc_unit_t adc_unit); - -#ifdef __cplusplus -} -#endif diff --git a/components/esp_adc/include/esp_private/adc_private.h b/components/esp_adc/include/esp_private/adc_private.h index a491911936..03aa22298c 100644 --- a/components/esp_adc/include/esp_private/adc_private.h +++ b/components/esp_adc/include/esp_private/adc_private.h @@ -34,20 +34,6 @@ void adc_apb_periph_claim(void); void adc_apb_periph_free(void); -/*------------------------------------------------------------------------------ -* ADC Power -*----------------------------------------------------------------------------*/ -/** - * @brief Acquire the ADC Power - */ -void adc_power_acquire(void); - -/** - * @brief Release the ADC Power - */ -void adc_power_release(void); - - /*--------------------------------------------------------------- ADC IOs ---------------------------------------------------------------*/ @@ -79,27 +65,6 @@ esp_err_t adc_io_to_channel(int io_num, adc_unit_t *unit_id, adc_channel_t *chan esp_err_t adc_channel_to_io(adc_unit_t unit_id, adc_channel_t channel, int *io_num); -#if SOC_ADC_CALIBRATION_V1_SUPPORTED -/*--------------------------------------------------------------- - ADC Hardware Calibration ----------------------------------------------------------------*/ -/** - * @brief Calculate the ADC HW calibration code. (Based on the pre-stored efuse or actual calibration) - * - * @param adc_n ADC unit to calibrate - * @param atten Attenuation to use - */ -void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten); - -/** - * @brief Set the ADC HW calibration code. - * - * @param adc_n ADC unit to calibrate - * @param atten Attenuation to use - */ -void adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten); -#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED - /*--------------------------------------------------------------- ADC Oneshot Read API ISR Version ---------------------------------------------------------------*/ diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 788cdfa686..e7c78d9a4e 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -15,7 +15,8 @@ if(NOT BOOTLOADER_BUILD) "sleep_modes.c" "sleep_gpio.c" "sleep_mac_bb.c" - "regi2c_ctrl.c") + "regi2c_ctrl.c" + "adc_share_hw_ctrl.c") if(NOT CONFIG_IDF_TARGET_ESP32 AND NOT CONFIG_IDF_TARGET_ESP32S2) list(APPEND srcs "sleep_retention.c") diff --git a/components/esp_hw_support/adc_share_hw_ctrl.c b/components/esp_hw_support/adc_share_hw_ctrl.c new file mode 100644 index 0000000000..e3c0591e9e --- /dev/null +++ b/components/esp_hw_support/adc_share_hw_ctrl.c @@ -0,0 +1,212 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * ADC is shared by multiple components, including: + * - esp_phy + * - esp_wifi + * - driver + * + * However, usages of above components are different. + * Therefore, we put the common used parts into `esp_hw_support`, including: + * - adc power maintainance + * - adc hw calibration settings + * - adc locks, to prevent concurrently using adc hw + */ + +#include +#include "sdkconfig.h" +#include "sys/lock.h" +#include "esp_log.h" +#include "esp_check.h" +#include "freertos/FreeRTOS.h" +#include "hal/adc_types.h" +#include "hal/adc_hal.h" +#include "hal/adc_hal_common.h" +#include "hal/adc_hal_conf.h" +#include "esp_private/adc_share_hw_ctrl.h" +//For calibration +#if CONFIG_IDF_TARGET_ESP32S2 +#include "esp_efuse_rtc_table.h" +#elif SOC_ADC_CALIBRATION_V1_SUPPORTED +#include "esp_efuse_rtc_calib.h" +#endif + + +static const char *TAG = "adc_share_hw_ctrl"; +extern portMUX_TYPE rtc_spinlock; + +/*------------------------------------------------------------------------------ +* ADC Power +*----------------------------------------------------------------------------*/ +// This gets incremented when adc_power_acquire() is called, and decremented when +// adc_power_release() is called. ADC is powered down when the value reaches zero. +// Should be modified within critical section (ADC_ENTER/EXIT_CRITICAL). +static int s_adc_power_on_cnt; + +static void adc_power_on_internal(void) +{ + /* Set the power always on to increase precision. */ + adc_hal_set_power_manage(ADC_POWER_SW_ON); +} + +void adc_power_acquire(void) +{ + portENTER_CRITICAL(&rtc_spinlock); + s_adc_power_on_cnt++; + if (s_adc_power_on_cnt == 1) { + adc_power_on_internal(); + } + portEXIT_CRITICAL(&rtc_spinlock); +} + +static void adc_power_off_internal(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + adc_hal_set_power_manage(ADC_POWER_SW_OFF); +#else + adc_hal_set_power_manage(ADC_POWER_BY_FSM); +#endif +} + +void adc_power_release(void) +{ + portENTER_CRITICAL(&rtc_spinlock); + s_adc_power_on_cnt--; + /* Sanity check */ + if (s_adc_power_on_cnt < 0) { + portEXIT_CRITICAL(&rtc_spinlock); + ESP_LOGE(TAG, "%s called, but s_adc_power_on_cnt == 0", __func__); + abort(); + } else if (s_adc_power_on_cnt == 0) { + adc_power_off_internal(); + } + portEXIT_CRITICAL(&rtc_spinlock); +} + + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED +/*--------------------------------------------------------------- + ADC Hardware Calibration +---------------------------------------------------------------*/ +#if CONFIG_IDF_TARGET_ESP32S2 +#define esp_efuse_rtc_calib_get_ver() esp_efuse_rtc_table_read_calib_version() + +static inline uint32_t esp_efuse_rtc_calib_get_init_code(int version, uint32_t adc_unit, int atten) +{ + int tag = esp_efuse_rtc_table_get_tag(version, adc_unit + 1, atten, RTCCALIB_V2_PARAM_VINIT); + return esp_efuse_rtc_table_get_parsed_efuse_value(tag, false); +} +#endif + +static uint32_t s_adc_cali_param[SOC_ADC_PERIPH_NUM][SOC_ADC_ATTEN_NUM] = {}; + +void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten) +{ + if (s_adc_cali_param[adc_n][atten]) { + ESP_EARLY_LOGV(TAG, "Use calibrated val ADC%d atten=%d: %04X", adc_n + 1, atten, s_adc_cali_param[adc_n][atten]); + return ; + } + + // check if we can fetch the values from eFuse. + int version = esp_efuse_rtc_calib_get_ver(); + + uint32_t init_code = 0; + + if (version == ESP_EFUSE_ADC_CALIB_VER) { + init_code = esp_efuse_rtc_calib_get_init_code(version, adc_n, atten); + } else { + ESP_EARLY_LOGD(TAG, "Calibration eFuse is not configured, use self-calibration for ICode"); + adc_power_acquire(); + portENTER_CRITICAL(&rtc_spinlock); + adc_ll_pwdet_set_cct(ADC_HAL_PWDET_CCT_DEFAULT); + const bool internal_gnd = true; + init_code = adc_hal_self_calibration(adc_n, atten, internal_gnd); + portEXIT_CRITICAL(&rtc_spinlock); + adc_power_release(); + } + + s_adc_cali_param[adc_n][atten] = init_code; + ESP_EARLY_LOGV(TAG, "Calib(V%d) ADC%d atten=%d: %04X", version, adc_n + 1, atten, init_code); +} + +void IRAM_ATTR adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten) +{ + adc_hal_set_calibration_param(adc_n, s_adc_cali_param[adc_n][atten]); +} +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED + + +/*--------------------------------------------------------------- + ADC Hardware Locks +---------------------------------------------------------------*/ +static _lock_t adc1_lock; +static _lock_t adc2_lock; + +esp_err_t adc_lock_acquire(adc_unit_t adc_unit) +{ + if (adc_unit == ADC_UNIT_1) { + _lock_acquire(&adc1_lock); + } + + if (adc_unit == ADC_UNIT_2) { + _lock_acquire(&adc2_lock); + } + + return ESP_OK; +} + +esp_err_t adc_lock_release(adc_unit_t adc_unit) +{ + if (adc_unit == ADC_UNIT_2) { + ESP_RETURN_ON_FALSE(((uint32_t *)adc2_lock != NULL), ESP_ERR_INVALID_STATE, TAG, "adc2 lock release without acquiring"); + _lock_release(&adc2_lock); + } + + if (adc_unit == ADC_UNIT_1) { + ESP_RETURN_ON_FALSE(((uint32_t *)adc1_lock != NULL), ESP_ERR_INVALID_STATE, TAG, "adc1 lock release without acquiring"); + _lock_release(&adc1_lock); + } + + return ESP_OK; +} + +esp_err_t adc_lock_try_acquire(adc_unit_t adc_unit) +{ + if (adc_unit == ADC_UNIT_1) { + if (_lock_try_acquire(&adc1_lock) == -1) { + return ESP_ERR_TIMEOUT; + } + } + + if (adc_unit == ADC_UNIT_2) { + if (_lock_try_acquire(&adc2_lock) == -1) { + return ESP_ERR_TIMEOUT; + } + } + + return ESP_OK; +} + +esp_err_t adc2_wifi_acquire(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + /* Wi-Fi module will use adc2. Use locks to avoid conflicts. */ + adc_lock_acquire(ADC_UNIT_2); + ESP_LOGD(TAG, "Wi-Fi takes adc2 lock."); +#endif + + return ESP_OK; +} + +esp_err_t adc2_wifi_release(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + return adc_lock_release(ADC_UNIT_2); +#endif + + return ESP_OK; +} diff --git a/components/esp_hw_support/include/esp_private/adc_share_hw_ctrl.h b/components/esp_hw_support/include/esp_private/adc_share_hw_ctrl.h new file mode 100644 index 0000000000..9d5f839e8d --- /dev/null +++ b/components/esp_hw_support/include/esp_private/adc_share_hw_ctrl.h @@ -0,0 +1,153 @@ +/* + * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * ADC is shared by multiple components, including: + * - esp_phy + * - esp_wifi + * - driver + * + * However, usages of above components are different. + * Therefore, we put the common used parts into `esp_hw_support`, including: + * - adc power maintainance + * - adc hw calibration settings + * - adc locks, to prevent concurrently using adc hw + */ + +#pragma once +#include "esp_err.h" +#include "hal/adc_types.h" +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ +* ADC Power +*----------------------------------------------------------------------------*/ +/** + * @brief Acquire the ADC Power + */ +void adc_power_acquire(void); + +/** + * @brief Release the ADC Power + */ +void adc_power_release(void); + + +#if SOC_ADC_CALIBRATION_V1_SUPPORTED +/*--------------------------------------------------------------- + ADC Hardware Calibration +---------------------------------------------------------------*/ +/** + * @brief Calculate the ADC HW calibration code. (Based on the pre-stored efuse or actual calibration) + * + * @param adc_n ADC unit to calibrate + * @param atten Attenuation to use + */ +void adc_calc_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten); + +/** + * @brief Set the ADC HW calibration code. + * + * @param adc_n ADC unit to calibrate + * @param atten Attenuation to use + */ +void adc_set_hw_calibration_code(adc_unit_t adc_n, adc_atten_t atten); +#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED + + +/*--------------------------------------------------------------- + ADC Cross Peripheral Locks +---------------------------------------------------------------*/ +/** + * @brief Acquire ADC lock by unit + * + * The lock acquiring sequence will be: ADC1, ADC2, ... + * + * @note If any of the locks are taken, this API will wait until the lock is successfully acquired. + * + * @param[in] adc_unit ADC unit ID + * + * @return + * - ESP_OK: On success + */ +esp_err_t adc_lock_acquire(adc_unit_t adc_unit); + +/** + * @brief Release ADC lock by unit + * + * The lock releasing sequence will be: ..., ADC2, ADC1 + * + * @param[in] adc_unit ADC unit ID + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_STATE: The lock(s) isn't acquired yet + */ +esp_err_t adc_lock_release(adc_unit_t adc_unit); + +/** + * @brief Try to acquire ADC lock by unit + * + * The lock acquiring sequence will be: ADC1, ADC2, ... + * + * @note If any of the locks are taken, this API will return immediately with an error `ESP_ERR_TIMEOUT` + * + * @param[in] adc_unit ADC unit ID + * + * @return + * - ESP_OK: On success + * - ESP_ERR_TIMEOUT: Lock(s) is taken already + */ +esp_err_t adc_lock_try_acquire(adc_unit_t adc_unit); + +/** + * @brief For WIFI module to claim the usage of ADC2. + * + * Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``. + * The WIFI module may have to wait for a short time for the current conversion (if exist) to finish. + * + * @return + * - ESP_OK success + * - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success. + */ +esp_err_t adc2_wifi_acquire(void); + +/** + * @brief For WIFI module to let other tasks use the ADC2 when WIFI is not work. + * + * Other tasks will be forbidden to use ADC2 between ``adc2_wifi_acquire`` and ``adc2_wifi_release``. + * Call this function to release the occupation of ADC2 by WIFI. + * + * @return + * - ESP_OK: On success + * - ESP_ERR_INVALID_STATE: The lock(s) isn't acquired yet + */ +esp_err_t adc2_wifi_release(void); + + +#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); +#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 +} +#endif diff --git a/components/esp_hw_support/port/esp32c3/CMakeLists.txt b/components/esp_hw_support/port/esp32c3/CMakeLists.txt index 74a4790747..3496747ded 100644 --- a/components/esp_hw_support/port/esp32c3/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32c3/CMakeLists.txt @@ -12,6 +12,9 @@ if(NOT BOOTLOADER_BUILD) "esp_crypto_lock.c" "esp_ds.c") + # init constructor for wifi + list(APPEND srcs "adc2_init_cal.c") + if(CONFIG_ESP_SYSTEM_MEMPROT_FEATURE) list(APPEND srcs "esp_memprot.c" "../esp_memprot_conv.c") endif() diff --git a/components/esp_adc/esp32c3/adc2_init_cal.c b/components/esp_hw_support/port/esp32c3/adc2_init_cal.c similarity index 94% rename from components/esp_adc/esp32c3/adc2_init_cal.c rename to components/esp_hw_support/port/esp32c3/adc2_init_cal.c index 8bf714b328..edb92a8eb2 100644 --- a/components/esp_adc/esp32c3/adc2_init_cal.c +++ b/components/esp_hw_support/port/esp32c3/adc2_init_cal.c @@ -11,8 +11,7 @@ Don't put any other code into this file. */ #include "freertos/FreeRTOS.h" #include "hal/adc_types.h" #include "hal/adc_hal_common.h" -#include "esp_private/adc2_wifi.h" -#include "esp_private/adc_private.h" +#include "esp_private/adc_share_hw_ctrl.h" extern portMUX_TYPE rtc_spinlock; diff --git a/components/esp_hw_support/port/esp32s2/CMakeLists.txt b/components/esp_hw_support/port/esp32s2/CMakeLists.txt index 6c8161c3f4..545c19bdca 100644 --- a/components/esp_hw_support/port/esp32s2/CMakeLists.txt +++ b/components/esp_hw_support/port/esp32s2/CMakeLists.txt @@ -17,6 +17,9 @@ if(NOT BOOTLOADER_BUILD) "esp_crypto_lock.c" "esp_ds.c") + # init constructor for wifi + list(APPEND srcs "adc2_init_cal.c") + endif() add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" "${srcs}") diff --git a/components/esp_adc/esp32s2/adc2_init_cal.c b/components/esp_hw_support/port/esp32s2/adc2_init_cal.c similarity index 94% rename from components/esp_adc/esp32s2/adc2_init_cal.c rename to components/esp_hw_support/port/esp32s2/adc2_init_cal.c index 8bf714b328..edb92a8eb2 100644 --- a/components/esp_adc/esp32s2/adc2_init_cal.c +++ b/components/esp_hw_support/port/esp32s2/adc2_init_cal.c @@ -11,8 +11,7 @@ Don't put any other code into this file. */ #include "freertos/FreeRTOS.h" #include "hal/adc_types.h" #include "hal/adc_hal_common.h" -#include "esp_private/adc2_wifi.h" -#include "esp_private/adc_private.h" +#include "esp_private/adc_share_hw_ctrl.h" extern portMUX_TYPE rtc_spinlock; diff --git a/components/esp_phy/CMakeLists.txt b/components/esp_phy/CMakeLists.txt index b5947b557f..04524d2176 100644 --- a/components/esp_phy/CMakeLists.txt +++ b/components/esp_phy/CMakeLists.txt @@ -31,7 +31,7 @@ endif() # [refactor-todo]: requires "driver" component for periph_ctrl header file idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" "${idf_target}/include" - PRIV_REQUIRES nvs_flash driver efuse esp_timer esp_adc esp_wifi + PRIV_REQUIRES nvs_flash driver efuse esp_timer esp_wifi LDFRAGMENTS "${ldfragments}" EMBED_FILES ${embed_files} ) diff --git a/components/esp_phy/src/phy_override.c b/components/esp_phy/src/phy_override.c index 9ba3700413..9115abaa5e 100644 --- a/components/esp_phy/src/phy_override.c +++ b/components/esp_phy/src/phy_override.c @@ -7,7 +7,7 @@ #include #include "esp_attr.h" #include "esp_private/regi2c_ctrl.h" -#include "esp_private/adc_private.h" +#include "esp_private/adc_share_hw_ctrl.h" /* * This file is used to override the hooks provided by the PHY lib for some system features. diff --git a/components/esp_wifi/CMakeLists.txt b/components/esp_wifi/CMakeLists.txt index 0bb4b26206..96b558787b 100644 --- a/components/esp_wifi/CMakeLists.txt +++ b/components/esp_wifi/CMakeLists.txt @@ -31,7 +31,7 @@ endif() idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "include" REQUIRES esp_event esp_phy esp_netif - PRIV_REQUIRES driver esptool_py esp_pm esp_timer nvs_flash esp_adc + PRIV_REQUIRES driver esptool_py esp_pm esp_timer nvs_flash wpa_supplicant hal lwip ${extra_priv_requires} LDFRAGMENTS "${ldfragments}") diff --git a/components/esp_wifi/src/wifi_init.c b/components/esp_wifi/src/wifi_init.c index 0f5a9a5a7e..3019bbf499 100644 --- a/components/esp_wifi/src/wifi_init.c +++ b/components/esp_wifi/src/wifi_init.c @@ -8,14 +8,13 @@ #include #include "esp_log.h" #include "esp_private/wifi.h" -#include "esp_private/adc2_wifi.h" +#include "esp_private/adc_share_hw_ctrl.h" #include "esp_pm.h" #include "esp_sleep.h" #include "esp_private/pm_impl.h" #include "esp_private/esp_clk.h" #include "esp_wpa.h" #include "esp_netif.h" -#include "esp_private/adc_private.h" #include "esp_coexist_internal.h" #include "esp_phy_init.h" #include "phy.h" diff --git a/components/ulp/ulp_riscv/ulp_riscv_adc.c b/components/ulp/ulp_riscv/ulp_riscv_adc.c index 32f0e9bdc9..9241dd9c6a 100644 --- a/components/ulp/ulp_riscv/ulp_riscv_adc.c +++ b/components/ulp/ulp_riscv/ulp_riscv_adc.c @@ -8,10 +8,10 @@ #include "esp_err.h" #include "esp_check.h" #include "esp_log.h" -#include "esp_private/adc_private.h" #include "esp_adc/adc_oneshot.h" #include "hal/adc_hal_common.h" #include "esp_private/esp_sleep_internal.h" +#include "esp_private/adc_share_hw_ctrl.h" static const char *TAG = "ulp_riscv_adc"; diff --git a/docs/en/migration-guides/release-5.x/peripherals.rst b/docs/en/migration-guides/release-5.x/peripherals.rst index c2584d4466..15c4a742fd 100644 --- a/docs/en/migration-guides/release-5.x/peripherals.rst +++ b/docs/en/migration-guides/release-5.x/peripherals.rst @@ -19,8 +19,8 @@ ADC - ADC oneshot mode driver has been redesigned. New driver is in ``esp_adc`` component and the include path is ``esp_adc/adc_oneshot.h``. Legacy driver is still available in the previous include path ``driver/adc.h``. However, by default, including ``driver/adc.h`` will bring a build warning like `legacy adc driver is deprecated, please migrate to use esp_adc/adc_oneshot.h and esp_adc/adc_continuous.h for oneshot mode and continuous mode drivers respectively`. The warning can be suppressed by the Kconfig option :ref:`CONFIG_ADC_SUPPRESS_DEPRECATE_WARN`. - ADC continuous mode driver has been moved from ``driver`` component to ``esp_adc`` component. Include path has been changed from ``driver/adc.h`` to ``esp_adc/adc_continuous.h``. Legacy driver is still available in the previous include path ``driver/adc.h``. Similarly, including it will bring a build warning, and it can be suppressed by the Kconfig option :ref:`CONFIG_ADC_SUPPRESS_DEPRECATE_WARN`. - ADC calibration driver has been redesigned. New driver is in ``esp_adc`` component and the include path is ``esp_adc/adc_cali.h`` and ``esp_adc/adc_cali_scheme.h``. Legacy driver is still available by including ``esp_adc_cal.h``. However, by default, including ``esp_adc_cal.h`` will bring a build warning like `legacy adc calibration driver is deprecated, please migrate to use esp_adc/adc_cali.h and esp_adc/adc_cali_scheme.h`. The warning can be suppressed by the Kconfig option :ref:`CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN`. -- API ``adc_power_acquire`` and ``adc_power_release`` have been deprecated. These two are used by other drivers to maintain ADC power due to hardware limitation. After this change, ADC power will still be handled by the drivers. However, for users who are interested in this, the include path has been changed from ``driver/adc.h`` to ``esp_private/adc_private.h``. -- Previous ``driver/adc2_wifi_private.h`` has been moved to ``esp_private/adc2_wifi.h``. +- API ``adc_power_acquire`` and ``adc_power_release`` have been deprecated. These two are used by other drivers to maintain ADC power due to hardware limitation. After this change, ADC power will still be handled by the drivers. However, for users who are interested in this, the include path has been changed from ``driver/adc.h`` to ``esp_private/adc_share_hw_ctrl.h``. +- Previous ``driver/adc2_wifi_private.h`` has been moved to ``esp_private/adc_share_hw_ctrl.h``. - Enums ``ADC_UNIT_BOTH``, ``ADC_UNIT_ALTER`` and ``ADC_UNIT_MAX`` in ``adc_unit_t`` have been removed. - Enum ``ADC_CHANNEL_MAX`` in ``adc_channel_t`` has been removed. Some channels are not supported on some chips, driver will give a dynamic error if an unsupported channels are used. - Enum ``ADC_ATTEN_MAX`` has been removed. Some attenuations are not supported on some chips, driver will give a dynamic error if an unsupported attenuation is used. diff --git a/tools/test_apps/system/g1_components/CMakeLists.txt b/tools/test_apps/system/g1_components/CMakeLists.txt index f27b001a15..7c69876019 100644 --- a/tools/test_apps/system/g1_components/CMakeLists.txt +++ b/tools/test_apps/system/g1_components/CMakeLists.txt @@ -40,11 +40,6 @@ set(extra_components_which_shouldnt_be_included # Figure out if these components can exist without a dependency on efuse. # If not, see if esp_hw_support can provide minimal efuse component replacement in G1 build. efuse - # [refactor-todo]: esp_adc is a dependency of driver, esp_phy and esp_wii. - # Driver dependency only exists in legacy drivers. After removing deprecated drivers, this dependency can be fixed - # esp_phy requires esp_adc to maintain the ADC power for PWDET usage - # esp_wifi requires esp_adc to do the initial calibration for PWDET usage - esp_adc # esp_pm is pulled in by freertos, can be made a weak dependency # conditional on related Kconfig option. It is also used by esp_wifi, driver, mbedtls, # all of which should be removed from G1-only build.