diff --git a/components/driver/adc_common.c b/components/driver/adc_common.c index dbbadf9052..3c2400185d 100644 --- a/components/driver/adc_common.c +++ b/components/driver/adc_common.c @@ -74,6 +74,14 @@ In ADC2, there're two locks used for different cases: adc2_spinlock should be acquired first, then adc2_wifi_lock or rtc_spinlock. */ +// 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); +static void adc_power_off_internal(void); + #ifdef CONFIG_IDF_TARGET_ESP32 //prevent ADC2 being used by wifi and other tasks at the same time. static _lock_t adc2_wifi_lock; @@ -122,36 +130,60 @@ static uint32_t get_calibration_offset(adc_ll_num_t adc_n, adc_channel_t chan) } #endif -void adc_power_always_on(void) +void adc_power_acquire(void) { + bool powered_on = false; ADC_ENTER_CRITICAL(); - adc_hal_set_power_manage(ADC_POWER_SW_ON); + s_adc_power_on_cnt++; + if (s_adc_power_on_cnt == 1) { + adc_power_on_internal(); + powered_on = true; + } ADC_EXIT_CRITICAL(); + if (powered_on) { + ESP_LOGV(ADC_TAG, "%s: ADC powered on", __func__); + } } -void adc_power_on(void) +void adc_power_release(void) +{ + bool powered_off = false; + ADC_ENTER_CRITICAL(); + s_adc_power_on_cnt--; + /* Sanity check */ + if (s_adc_power_on_cnt < 0) { + ADC_EXIT_CRITICAL(); + ESP_LOGE(ADC_TAG, "%s called, but s_adc_power_on_cnt == 0", __func__); + abort(); + } else if (s_adc_power_on_cnt == 0) { + adc_power_off_internal(); + powered_off = true; + } + ADC_EXIT_CRITICAL(); + if (powered_off) { + ESP_LOGV(ADC_TAG, "%s: ADC powered off", __func__); + } +} + +static void adc_power_on_internal(void) { ADC_ENTER_CRITICAL(); - /* The power FSM controlled mode saves more power, while the ADC noise may get increased. */ -#ifndef CONFIG_ADC_FORCE_XPD_FSM /* Set the power always on to increase precision. */ adc_hal_set_power_manage(ADC_POWER_SW_ON); -#else - /* Use the FSM to turn off the power while not used to save power. */ - if (adc_hal_get_power_manage() != ADC_POWER_BY_FSM) { - adc_hal_set_power_manage(ADC_POWER_SW_ON); - } -#endif ADC_EXIT_CRITICAL(); } -void adc_power_off(void) +void adc_power_on(void) __attribute__((alias("adc_power_on_internal"))); + +static void adc_power_off_internal(void) { ADC_ENTER_CRITICAL(); adc_hal_set_power_manage(ADC_POWER_SW_OFF); ADC_EXIT_CRITICAL(); } +void adc_power_off(void) __attribute__((alias("adc_power_off_internal"))); + esp_err_t adc_set_clk_div(uint8_t clk_div) { ADC_ENTER_CRITICAL(); @@ -337,7 +369,7 @@ int adc1_get_raw(adc1_channel_t channel) int adc_value; ADC_CHANNEL_CHECK(ADC_NUM_1, channel); adc1_rtc_mode_acquire(); - adc_power_on(); + adc_power_acquire(); #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // Get calibration value before going into critical section @@ -359,6 +391,7 @@ int adc1_get_raw(adc1_channel_t channel) #endif ADC_EXIT_CRITICAL(); + adc_power_release(); adc1_lock_release(); return adc_value; } @@ -371,7 +404,7 @@ int adc1_get_voltage(adc1_channel_t channel) //Deprecated. Use adc1_get_raw() #if SOC_ULP_SUPPORTED void adc1_ulp_enable(void) { - adc_power_on(); + adc_power_acquire(); ADC_ENTER_CRITICAL(); adc_hal_set_controller(ADC_NUM_1, ADC_CTRL_ULP); @@ -492,7 +525,7 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * ADC_CHECK(width_bit == ADC_WIDTH_BIT_13, "WIDTH ERR: ESP32S2 support 13 bit width", ESP_ERR_INVALID_ARG); #endif - adc_power_on(); //in critical section with whole rtc module + adc_power_acquire(); //in critical section with whole rtc module #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 // Get calibration value before going into critical section @@ -503,6 +536,7 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * if ( ADC2_WIFI_LOCK_TRY_ACQUIRE() == -1 ) { //try the lock, return if failed (wifi using). ADC2_EXIT_CRITICAL(); + adc_power_release(); return ESP_ERR_TIMEOUT; } #ifdef CONFIG_ADC_DISABLE_DAC @@ -544,8 +578,12 @@ esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int * if (adc_value < 0) { ESP_LOGD( ADC_TAG, "ADC2 ARB: Return data is invalid." ); + adc_power_release(); return ESP_ERR_INVALID_STATE; } + + //in critical section with whole rtc module + adc_power_release(); *raw_out = adc_value; return ESP_OK; } @@ -558,7 +596,9 @@ esp_err_t adc2_vref_to_gpio(gpio_num_t gpio) esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) { #ifdef CONFIG_IDF_TARGET_ESP32 + adc_power_acquire(); if (adc_unit & ADC_UNIT_1) { + adc_power_release(); return ESP_ERR_INVALID_ARG; } #endif @@ -571,6 +611,7 @@ esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio) } } if (ch == ADC2_CHANNEL_MAX) { + adc_power_release(); return ESP_ERR_INVALID_ARG; } diff --git a/components/driver/i2s.c b/components/driver/i2s.c index c6a4c56b49..e705467491 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -867,6 +867,13 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co periph_module_enable(i2s_periph_signal[i2s_num].module); #if SOC_I2S_SUPPORTS_ADC_DAC + if(i2s_config->mode & I2S_MODE_ADC_BUILT_IN) { + //in ADC built-in mode, we need to call i2s_set_adc_mode to + //initialize the specific ADC channel. + //in the current stage, we only support ADC1 and single channel mode. + //In default data mode, the ADC data is in 12-bit resolution mode. + adc_power_acquire(); + } #endif // configure I2S data port interface. i2s_hal_config_param(&(p_i2s_obj[i2s_num]->hal), i2s_config); diff --git a/components/driver/include/driver/adc_common.h b/components/driver/include/driver/adc_common.h index 4596505822..abb1b17e57 100644 --- a/components/driver/include/driver/adc_common.h +++ b/components/driver/include/driver/adc_common.h @@ -151,14 +151,32 @@ typedef struct adc_digi_init_config_s { /** * @brief Enable ADC power + * @deprecated Use adc_power_acquire and adc_power_release instead. */ -void adc_power_on(void); +void adc_power_on(void) __attribute__((deprecated)); /** * @brief Power off SAR ADC - * This function will force power down for ADC + * @deprecated Use adc_power_acquire and adc_power_release instead. + * This function will force power down for ADC. + * This function is deprecated because forcing power ADC power off may + * disrupt operation of other components which may be using the ADC. */ -void adc_power_off(void); +void adc_power_off(void) __attribute__((deprecated)); + +/** + * @brief Increment the usage counter for ADC module. + * ADC will stay powered on while the counter is greater than 0. + * Call adc_power_release when done using the ADC. + */ +void adc_power_acquire(void); + +/** + * @brief Decrement the usage counter for ADC module. + * ADC will stay powered on while the counter is greater than 0. + * Call this function when done using the ADC. + */ +void adc_power_release(void); /** * @brief Initialize ADC pad @@ -250,6 +268,8 @@ esp_err_t adc1_config_width(adc_bits_width_t width_bit); * the input of GPIO36 and GPIO39 will be pulled down for about 80ns. * When enabling power for any of these peripherals, ignore input from GPIO36 and GPIO39. * Please refer to section 3.11 of 'ECO_and_Workarounds_for_Bugs_in_ESP32' for the description of this issue. + * As a workaround, call adc_power_acquire() in the app. This will result in higher power consumption (by ~1mA), + * but will remove the glitches on GPIO36 and GPIO39. * * @note Call ``adc1_config_width()`` before the first time this * function is called. @@ -375,6 +395,9 @@ esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten); * the input of GPIO36 and GPIO39 will be pulled down for about 80ns. * When enabling power for any of these peripherals, ignore input from GPIO36 and GPIO39. * Please refer to section 3.11 of 'ECO_and_Workarounds_for_Bugs_in_ESP32' for the description of this issue. + * As a workaround, call adc_power_acquire() in the app. This will result in higher power consumption (by ~1mA), + * but will remove the glitches on GPIO36 and GPIO39. + * * * @note ESP32: * For a given channel, ``adc2_config_channel_atten()``