Merge branch 'refactor/remove_legacy_adc_driver' into 'master'

adc: removed the legacy adc driver and legacy adc calibration driver since v6.0

Closes IDF-13177

See merge request espressif/esp-idf!39478
This commit is contained in:
Armando (Dou Yiwen)
2025-06-19 02:48:05 +00:00
39 changed files with 43 additions and 4097 deletions

View File

@ -16,15 +16,6 @@ set(includes "deprecated"
# Always included linker fragments
set(ldfragments "")
# ADC related source files (deprecated)
if(CONFIG_SOC_ADC_SUPPORTED)
list(APPEND srcs "deprecated/adc_legacy.c")
if(CONFIG_SOC_ADC_DMA_SUPPORTED)
list(APPEND srcs "deprecated/adc_dma_legacy.c")
endif()
endif()
# I2C related source files
if(CONFIG_SOC_I2C_SUPPORTED)
list(APPEND srcs "i2c/i2c.c")
@ -61,18 +52,11 @@ if(CONFIG_SOC_TWAI_SUPPORTED AND NOT CONFIG_SOC_TWAI_SUPPORT_FD)
list(APPEND ldfragments "twai/linker.lf")
endif()
# Other source files
if(${target} STREQUAL "esp32")
list(APPEND srcs "deprecated/adc_i2s_deprecated.c")
endif()
if(BOOTLOADER_BUILD)
# Bootloader shall NOT depend on the drivers
idf_component_register()
else()
# (REQUIRES cannot hide soc headers, since many arguments in the driver headers are chip-dependent)
# (Legacy drivers requires `esp_adc`, due to ADC HW resource mutex logics are there.
# Can be removed together with legacy drivers)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ${includes}
PRIV_REQUIRES efuse esp_timer esp_mm
@ -86,9 +70,4 @@ else()
esp_driver_twai
LDFRAGMENTS ${ldfragments}
)
if(CONFIG_SOC_ADC_SUPPORTED AND
CONFIG_COMPILER_STATIC_ANALYZER AND CMAKE_C_COMPILER_ID STREQUAL "GNU") # TODO GCC-366
set_source_files_properties(deprecated/adc_legacy.c
PROPERTIES COMPILE_FLAGS "-Wno-analyzer-use-of-uninitialized-value")
endif()
endif()

View File

@ -2,72 +2,6 @@ menu "Driver Configurations"
orsource "./twai/Kconfig.twai"
menu "Legacy ADC Driver Configuration"
config ADC_DISABLE_DAC
depends on SOC_DAC_SUPPORTED
bool "Disable DAC when ADC2 is used on GPIO 25 and 26"
default y
help
If this is set, the ADC2 driver will disable the output of the DAC corresponding to the specified
channel. This is the default value.
For testing, disable this option so that we can measure the output of DAC by internal ADC.
config ADC_SUPPRESS_DEPRECATE_WARN
bool "Suppress legacy driver deprecated warning"
default n
help
Whether to suppress the deprecation warnings when using legacy adc driver (driver/adc.h).
If you want to continue using the legacy driver, and don't want to see related deprecation warnings,
you can enable this option.
config ADC_SKIP_LEGACY_CONFLICT_CHECK
bool "Skip legacy conflict check"
default n
help
This configuration option allows the user to bypass the conflict check mechanism with legacy code.
menu "Legacy ADC Calibration Configuration"
config ADC_CAL_EFUSE_TP_ENABLE
depends on IDF_TARGET_ESP32
bool "Use Two Point Values"
default "y"
help
Some ESP32s have Two Point calibration values burned into eFuse BLOCK3.
This option will allow the ADC calibration component to characterize the
ADC-Voltage curve using Two Point values if they are available.
config ADC_CAL_EFUSE_VREF_ENABLE
depends on IDF_TARGET_ESP32
bool "Use eFuse Vref"
default "y"
help
Some ESP32s have Vref burned into eFuse BLOCK0. This option will allow
the ADC calibration component to characterize the ADC-Voltage curve using
eFuse Vref if it is available.
config ADC_CAL_LUT_ENABLE
depends on IDF_TARGET_ESP32
bool "Use Lookup Tables"
default "y"
help
This option will allow the ADC calibration component to use Lookup Tables
to correct for non-linear behavior in 11db attenuation. Other attenuations
do not exhibit non-linear behavior hence will not be affected by this option.
config ADC_CALI_SUPPRESS_DEPRECATE_WARN
bool "Suppress legacy driver deprecated warning"
default n
help
Whether to suppress the deprecation warnings when using legacy adc calibration
driver (esp_adc_cal.h).
If you want to continue using the legacy driver, and don't want to see related
deprecation warnings, you can enable this option.
endmenu # Legacy ADC Calibration Configuration
endmenu # Legacy ADC Driver Configuration
menu "Legacy MCPWM Driver Configurations"
depends on SOC_MCPWM_SUPPORTED
config MCPWM_SUPPRESS_DEPRECATE_WARN

View File

@ -1,51 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
/**
* @brief For I2S dma to claim the usage of ADC1.
*
* Other tasks will be forbidden to use ADC1 between ``adc1_dma_mode_acquire`` and ``adc1_i2s_release``.
* The I2S 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 adc1_dma_mode_acquire(void);
/**
* @brief For ADC1 to claim the usage of ADC1.
*
* Other tasks will be forbidden to use ADC1 between ``adc1_rtc_mode_acquire`` and ``adc1_i2s_release``.
* The ADC1 may have to wait for some time for the I2S read operation to finish.
*
* @return
* - ESP_OK success
* - ESP_ERR_TIMEOUT reserved for future use. Currently the function will wait until success.
*/
esp_err_t adc1_rtc_mode_acquire(void);
/**
* @brief to let other tasks use the ADC1 when I2S is not work.
*
* Other tasks will be forbidden to use ADC1 between ``adc1_adc/i2s_mode_acquire`` and ``adc1_i2s_release``.
* Call this function to release the occupation of ADC1
*
* @return always return ESP_OK.
*/
esp_err_t adc1_lock_release(void);
#ifdef __cplusplus
}
#endif

View File

@ -1,677 +0,0 @@
/*
* SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_types.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "sdkconfig.h"
#include "soc/soc_caps.h"
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "esp_check.h"
#include "sys/lock.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "freertos/ringbuf.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/adc_share_hw_ctrl.h"
#include "esp_private/sar_periph_ctrl.h"
#include "hal/adc_types.h"
#include "hal/adc_hal.h"
#include "hal/dma_types.h"
#include "hal/adc_hal_common.h"
#include "esp_private/regi2c_ctrl.h"
#include "driver/gpio.h"
#include "driver/adc_types_legacy.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
//For DMA
#if SOC_GDMA_SUPPORTED
#include "esp_private/gdma.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "hal/spi_types.h"
#include "esp_private/spi_common_internal.h"
#elif CONFIG_IDF_TARGET_ESP32
#include "driver/i2s_types.h"
#include "soc/i2s_periph.h"
#include "esp_private/i2s_platform.h"
#endif
static const char *ADC_TAG = "ADC";
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
#define INTERNAL_BUF_NUM 5
#if SOC_AHB_GDMA_SUPPORTED
#define ADC_GDMA_HOST 0
#define ADC_DMA_INTR_MASK GDMA_LL_EVENT_RX_SUC_EOF
#define ADC_DMA_INTR_MASK GDMA_LL_EVENT_RX_SUC_EOF
#define adc_dma_start(adc_dma, addr) gdma_start(s_adc_digi_ctx->rx_dma_channel, (intptr_t)addr)
#define adc_dma_stop(adc_dma) gdma_stop(s_adc_digi_ctx->rx_dma_channel)
#define adc_dma_reset(adc_dma) gdma_reset(s_adc_digi_ctx->rx_dma_channel)
#define adc_dma_clear_intr(adc_dma)
#define adc_dma_enable_intr(adc_dma)
#define adc_dma_disable_intr(adc_dma)
#define adc_dma_deinit(adc_dma) do { \
gdma_disconnect(s_adc_digi_ctx->rx_dma_channel); \
gdma_del_channel(s_adc_digi_ctx->rx_dma_channel); \
} while (0)
#elif CONFIG_IDF_TARGET_ESP32S2
#define ADC_DMA_SPI_HOST SPI3_HOST
#define ADC_DMA_INTR_MASK SPI_LL_INTR_IN_SUC_EOF
#define adc_dma_start(adc_dma, addr) spi_dma_ll_rx_start(s_adc_digi_ctx->adc_spi_dev, s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id, (lldesc_t *)addr)
#define adc_dma_stop(adc_dma) spi_dma_ll_rx_stop(s_adc_digi_ctx->adc_spi_dev, s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id);
#define adc_dma_reset(adc_dma) spi_dma_ll_rx_reset(s_adc_digi_ctx->adc_spi_dev, s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id);
#define adc_dma_clear_intr(adc_dma) spi_ll_clear_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK)
#define adc_dma_enable_intr(adc_dma) spi_ll_enable_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK);
#define adc_dma_disable_intr(adc_dma) spi_ll_disable_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK);
#define adc_dma_deinit(adc_dma) do { \
esp_intr_free(s_adc_digi_ctx->intr_hdl); \
spicommon_dma_chan_free(s_adc_digi_ctx->spi_dma_ctx); \
spicommon_periph_free(ADC_DMA_SPI_HOST); \
} while (0)
#elif CONFIG_IDF_TARGET_ESP32
#define ADC_DMA_I2S_HOST I2S_NUM_0
#define ADC_DMA_INTR_MASK BIT(9)
#define adc_dma_start(adc_dma, addr) do { \
i2s_ll_enable_dma(s_adc_digi_ctx->adc_i2s_dev, true); \
i2s_ll_rx_start_link(s_adc_digi_ctx->adc_i2s_dev, (uint32_t)addr); \
} while (0)
#define adc_dma_stop(adc_dma) i2s_ll_rx_stop_link(s_adc_digi_ctx->adc_i2s_dev);
#define adc_dma_reset(adc_dma) i2s_ll_rx_reset_dma(s_adc_digi_ctx->adc_i2s_dev);
#define adc_dma_clear_intr(adc_dma) i2s_ll_clear_intr_status(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK);
#define adc_dma_enable_intr(adc_dma) i2s_ll_enable_intr(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK, true);
#define adc_dma_disable_intr(adc_dma) i2s_ll_enable_intr(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK, false);
#define adc_dma_deinit(adc_dma) do { \
esp_intr_free(s_adc_digi_ctx->intr_hdl); \
i2s_platform_release_occupation(I2S_CTLR_HP, ADC_DMA_I2S_HOST); \
} while (0)
#endif
/*---------------------------------------------------------------
Digital Controller Context
---------------------------------------------------------------*/
typedef struct adc_digi_context_t {
uint8_t *rx_dma_buf; //dma buffer
adc_hal_dma_ctx_t hal; //hal context
#if SOC_GDMA_SUPPORTED
gdma_channel_handle_t rx_dma_channel; //dma rx channel handle
#elif CONFIG_IDF_TARGET_ESP32S2
spi_host_device_t spi_host; //ADC uses this SPI DMA
spi_dma_ctx_t *spi_dma_ctx; //spi_dma context
intr_handle_t intr_hdl; //Interrupt handler
spi_dev_t *adc_spi_dev ;
#elif CONFIG_IDF_TARGET_ESP32
i2s_port_t i2s_host; //ADC uses this I2S DMA
intr_handle_t intr_hdl; //Interrupt handler
i2s_dev_t *adc_i2s_dev;
#endif
RingbufHandle_t ringbuf_hdl; //RX ringbuffer handler
intptr_t rx_eof_desc_addr; //eof descriptor address of RX channel
bool ringbuf_overflow_flag; //1: ringbuffer overflow
bool driver_start_flag; //1: driver is started; 0: driver is stopped
bool use_adc1; //1: ADC unit1 will be used; 0: ADC unit1 won't be used.
bool use_adc2; //1: ADC unit2 will be used; 0: ADC unit2 won't be used. This determines whether to acquire sar_adc2_mutex lock or not.
adc_atten_t adc1_atten; //Attenuation for ADC1. On this chip each ADC can only support one attenuation.
adc_atten_t adc2_atten; //Attenuation for ADC2. On this chip each ADC can only support one attenuation.
adc_hal_digi_ctrlr_cfg_t hal_digi_ctrlr_cfg; //Hal digital controller configuration
esp_pm_lock_handle_t pm_lock; //For power management
} adc_digi_context_t;
static adc_digi_context_t *s_adc_digi_ctx = NULL;
#ifdef CONFIG_PM_ENABLE
//Only for deprecated API
extern esp_pm_lock_handle_t adc_digi_arbiter_lock;
#endif //CONFIG_PM_ENABLE
/*---------------------------------------------------------------
ADC Continuous Read Mode (via DMA)
---------------------------------------------------------------*/
//Function to address transaction
static bool s_adc_dma_intr(adc_digi_context_t *adc_digi_ctx);
#if SOC_GDMA_SUPPORTED
static bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data);
#else
static void adc_dma_intr_handler(void *arg);
#endif
static int8_t adc_digi_get_io_num(adc_unit_t adc_unit, uint8_t adc_channel)
{
assert(adc_unit < SOC_ADC_PERIPH_NUM);
uint8_t adc_n = (adc_unit == ADC_UNIT_1) ? 0 : 1;
return adc_channel_io_map[adc_n][adc_channel];
}
static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask)
{
esp_err_t ret = ESP_OK;
uint64_t gpio_mask = 0;
uint32_t n = 0;
int8_t io = 0;
while (channel_mask) {
if (channel_mask & 0x1) {
io = adc_digi_get_io_num(adc_unit, n);
if (io < 0) {
return ESP_ERR_INVALID_ARG;
}
gpio_mask |= BIT64(io);
}
channel_mask = channel_mask >> 1;
n++;
}
gpio_config_t cfg = {
.pin_bit_mask = gpio_mask,
.mode = GPIO_MODE_DISABLE,
};
ret = gpio_config(&cfg);
return ret;
}
esp_err_t adc_digi_deinitialize(void)
{
if (!s_adc_digi_ctx) {
return ESP_ERR_INVALID_STATE;
}
if (s_adc_digi_ctx->driver_start_flag != 0) {
ESP_LOGE(ADC_TAG, "The driver is not stopped");
return ESP_ERR_INVALID_STATE;
}
if (s_adc_digi_ctx->ringbuf_hdl) {
vRingbufferDelete(s_adc_digi_ctx->ringbuf_hdl);
s_adc_digi_ctx->ringbuf_hdl = NULL;
}
#if CONFIG_PM_ENABLE
if (s_adc_digi_ctx->pm_lock) {
esp_pm_lock_delete(s_adc_digi_ctx->pm_lock);
}
#endif //CONFIG_PM_ENABLE
ANALOG_CLOCK_DISABLE();
free(s_adc_digi_ctx->rx_dma_buf);
free(s_adc_digi_ctx->hal.rx_desc);
free(s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern);
adc_dma_deinit(s_adc_digi_ctx);
free(s_adc_digi_ctx);
s_adc_digi_ctx = NULL;
adc_apb_periph_free();
return ESP_OK;
}
esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
{
esp_err_t ret = ESP_OK;
ESP_RETURN_ON_FALSE((init_config->conv_num_each_intr % SOC_ADC_DIGI_DATA_BYTES_PER_CONV == 0), ESP_ERR_INVALID_ARG, ADC_TAG, "conv_frame_size should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`");
s_adc_digi_ctx = calloc(1, sizeof(adc_digi_context_t));
if (s_adc_digi_ctx == NULL) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//ringbuffer
s_adc_digi_ctx->ringbuf_hdl = xRingbufferCreate(init_config->max_store_buf_size, RINGBUF_TYPE_BYTEBUF);
if (!s_adc_digi_ctx->ringbuf_hdl) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//malloc internal buffer used by DMA
s_adc_digi_ctx->rx_dma_buf = heap_caps_calloc(1, init_config->conv_num_each_intr * INTERNAL_BUF_NUM, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
if (!s_adc_digi_ctx->rx_dma_buf) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//malloc dma descriptor
uint32_t dma_desc_num_per_frame = (init_config->conv_num_each_intr + DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED - 1) / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
uint32_t dma_desc_max_num = dma_desc_num_per_frame * INTERNAL_BUF_NUM;
s_adc_digi_ctx->hal.rx_desc = heap_caps_calloc(1, (sizeof(dma_descriptor_t)) * dma_desc_max_num, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
if (!s_adc_digi_ctx->hal.rx_desc) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//malloc pattern table
s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern = calloc(1, SOC_ADC_PATT_LEN_MAX * sizeof(adc_digi_pattern_config_t));
if (!s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
#if CONFIG_PM_ENABLE
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc_dma", &s_adc_digi_ctx->pm_lock);
if (ret != ESP_OK) {
goto cleanup;
}
#endif //CONFIG_PM_ENABLE
//init gpio pins
if (init_config->adc1_chan_mask) {
ret = adc_digi_gpio_init(ADC_UNIT_1, init_config->adc1_chan_mask);
if (ret != ESP_OK) {
goto cleanup;
}
}
if (init_config->adc2_chan_mask) {
ret = adc_digi_gpio_init(ADC_UNIT_2, init_config->adc2_chan_mask);
if (ret != ESP_OK) {
goto cleanup;
}
}
#if SOC_GDMA_SUPPORTED
//alloc rx gdma channel
gdma_channel_alloc_config_t rx_alloc_config = {
.direction = GDMA_CHANNEL_DIRECTION_RX,
};
ret = gdma_new_ahb_channel(&rx_alloc_config, &s_adc_digi_ctx->rx_dma_channel);
if (ret != ESP_OK) {
goto cleanup;
}
gdma_connect(s_adc_digi_ctx->rx_dma_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_ADC, 0));
gdma_strategy_config_t strategy_config = {
.auto_update_desc = true,
.owner_check = true
};
gdma_apply_strategy(s_adc_digi_ctx->rx_dma_channel, &strategy_config);
gdma_rx_event_callbacks_t cbs = {
.on_recv_eof = adc_dma_in_suc_eof_callback
};
gdma_register_rx_event_callbacks(s_adc_digi_ctx->rx_dma_channel, &cbs, s_adc_digi_ctx);
#elif CONFIG_IDF_TARGET_ESP32S2
//ADC utilises SPI3 DMA on ESP32S2
bool spi_success = false;
spi_success = spicommon_periph_claim(ADC_DMA_SPI_HOST, "adc");
ret = spicommon_dma_chan_alloc(ADC_DMA_SPI_HOST, SPI_DMA_CH_AUTO, &(s_adc_digi_ctx->spi_dma_ctx));
if (ret != ESP_OK || spi_success != ESP_OK) {
goto cleanup;
}
if (!spi_success || (s_adc_digi_ctx->spi_host != ADC_DMA_SPI_HOST)) {
goto cleanup;
}
ret = esp_intr_alloc(spicommon_irqdma_source_for_host(ADC_DMA_SPI_HOST), 0, adc_dma_intr_handler,
(void *)s_adc_digi_ctx, &s_adc_digi_ctx->intr_hdl);
if (ret != ESP_OK) {
goto cleanup;
}
s_adc_digi_ctx->adc_spi_dev = SPI_LL_GET_HW(ADC_DMA_SPI_HOST);
#elif CONFIG_IDF_TARGET_ESP32
//ADC utilises I2S0 DMA on ESP32
ret = i2s_platform_acquire_occupation(I2S_CTLR_HP, ADC_DMA_I2S_HOST, "adc");
if (ret != ESP_OK) {
ret = ESP_ERR_NOT_FOUND;
goto cleanup;
}
s_adc_digi_ctx->i2s_host = I2S_NUM_0;
ret = esp_intr_alloc(i2s_periph_signal[ADC_DMA_I2S_HOST].irq, 0, adc_dma_intr_handler,
(void *)s_adc_digi_ctx, &s_adc_digi_ctx->intr_hdl);
if (ret != ESP_OK) {
goto cleanup;
}
s_adc_digi_ctx->adc_i2s_dev = I2S_LL_GET_HW(ADC_DMA_I2S_HOST);
#endif
adc_hal_dma_config_t config = {
.eof_desc_num = INTERNAL_BUF_NUM,
.eof_step = dma_desc_num_per_frame,
.eof_num = init_config->conv_num_each_intr / SOC_ADC_DIGI_DATA_BYTES_PER_CONV
};
adc_hal_dma_ctx_config(&s_adc_digi_ctx->hal, &config);
adc_apb_periph_claim();
ANALOG_CLOCK_ENABLE();
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_hal_calibration_init(ADC_UNIT_1);
adc_hal_calibration_init(ADC_UNIT_2);
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
return ret;
cleanup:
adc_digi_deinitialize();
return ret;
}
#if SOC_GDMA_SUPPORTED
static IRAM_ATTR bool adc_dma_in_suc_eof_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data)
{
assert(event_data);
s_adc_digi_ctx->rx_eof_desc_addr = event_data->rx_eof_desc_addr;
return s_adc_dma_intr(user_data);
}
#else
static IRAM_ATTR void adc_dma_intr_handler(void *arg)
{
adc_digi_context_t *ctx = (adc_digi_context_t *)arg;
bool need_yield = false;
#if CONFIG_IDF_TARGET_ESP32S2
bool conversion_finish = spi_ll_get_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK);
if (conversion_finish) {
spi_ll_clear_intr(s_adc_digi_ctx->adc_spi_dev, ADC_DMA_INTR_MASK);
intptr_t desc_addr = spi_dma_ll_get_in_suc_eof_desc_addr(s_adc_digi_ctx->adc_spi_dev, s_adc_digi_ctx->spi_dma_ctx->rx_dma_chan.chan_id);
ctx->rx_eof_desc_addr = desc_addr;
need_yield = s_adc_dma_intr(ctx);
}
#elif CONFIG_IDF_TARGET_ESP32
bool conversion_finish = i2s_ll_get_intr_status(s_adc_digi_ctx->adc_i2s_dev) & ADC_DMA_INTR_MASK;
if (conversion_finish) {
i2s_ll_clear_intr_status(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK);
uint32_t desc_addr;
i2s_ll_rx_get_eof_des_addr(s_adc_digi_ctx->adc_i2s_dev, &desc_addr);
ctx->rx_eof_desc_addr = (intptr_t)desc_addr;
need_yield = s_adc_dma_intr(ctx);
}
#endif
if (need_yield) {
portYIELD_FROM_ISR();
}
}
#endif
static IRAM_ATTR bool s_adc_dma_intr(adc_digi_context_t *adc_digi_ctx)
{
BaseType_t taskAwoken = 0;
BaseType_t ret;
adc_hal_dma_desc_status_t status = false;
uint8_t *finished_buffer = NULL;
uint32_t finished_size = 0;
while (1) {
status = adc_hal_get_reading_result(&adc_digi_ctx->hal, adc_digi_ctx->rx_eof_desc_addr, &finished_buffer, &finished_size);
if (status != ADC_HAL_DMA_DESC_VALID) {
break;
}
ret = xRingbufferSendFromISR(adc_digi_ctx->ringbuf_hdl, finished_buffer, finished_size, &taskAwoken);
if (ret == pdFALSE) {
//ringbuffer overflow
adc_digi_ctx->ringbuf_overflow_flag = 1;
}
}
return (taskAwoken == pdTRUE);
}
esp_err_t adc_digi_start(void)
{
if (s_adc_digi_ctx->driver_start_flag != 0) {
ESP_LOGE(ADC_TAG, "The driver is already started");
return ESP_ERR_INVALID_STATE;
}
//reset ADC digital part to reset ADC sampling EOF counter
ADC_BUS_CLK_ATOMIC() {
adc_ll_reset_register();
}
sar_periph_ctrl_adc_continuous_power_acquire();
//reset flags
s_adc_digi_ctx->ringbuf_overflow_flag = 0;
s_adc_digi_ctx->driver_start_flag = 1;
if (s_adc_digi_ctx->use_adc1) {
adc_lock_acquire(ADC_UNIT_1);
}
if (s_adc_digi_ctx->use_adc2) {
adc_lock_acquire(ADC_UNIT_2);
}
#if CONFIG_PM_ENABLE
// Lock APB frequency while ADC driver is in use
esp_pm_lock_acquire(s_adc_digi_ctx->pm_lock);
#endif
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
if (s_adc_digi_ctx->use_adc1) {
adc_set_hw_calibration_code(ADC_UNIT_1, s_adc_digi_ctx->adc1_atten);
}
if (s_adc_digi_ctx->use_adc2) {
adc_set_hw_calibration_code(ADC_UNIT_2, s_adc_digi_ctx->adc2_atten);
}
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED
#if SOC_ADC_ARBITER_SUPPORTED
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
adc_hal_arbiter_config(&config);
#endif //#if SOC_ADC_ARBITER_SUPPORTED
adc_hal_set_controller(ADC_UNIT_1, ADC_HAL_CONTINUOUS_READ_MODE);
adc_hal_set_controller(ADC_UNIT_2, ADC_HAL_CONTINUOUS_READ_MODE);
adc_hal_digi_init(&s_adc_digi_ctx->hal);
#if !CONFIG_IDF_TARGET_ESP32
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)(s_adc_digi_ctx->hal_digi_ctrlr_cfg.clk_src), true));
#endif
adc_hal_digi_controller_config(&s_adc_digi_ctx->hal, &s_adc_digi_ctx->hal_digi_ctrlr_cfg);
adc_dma_stop(s_adc_digi_ctx);
adc_hal_digi_connect(false);
adc_dma_reset(s_adc_digi_ctx);
adc_hal_digi_reset();
adc_hal_digi_dma_link(&s_adc_digi_ctx->hal, s_adc_digi_ctx->rx_dma_buf);
adc_dma_start(s_adc_digi_ctx, s_adc_digi_ctx->hal.rx_desc);
adc_hal_digi_connect(true);
adc_hal_digi_enable(true);
return ESP_OK;
}
esp_err_t adc_digi_stop(void)
{
if (s_adc_digi_ctx->driver_start_flag != 1) {
ESP_LOGE(ADC_TAG, "The driver is already stopped");
return ESP_ERR_INVALID_STATE;
}
s_adc_digi_ctx->driver_start_flag = 0;
adc_dma_stop(s_adc_digi_ctx);
adc_hal_digi_enable(false);
adc_hal_digi_connect(false);
adc_hal_digi_deinit();
#if CONFIG_PM_ENABLE
if (s_adc_digi_ctx->pm_lock) {
esp_pm_lock_release(s_adc_digi_ctx->pm_lock);
}
#endif //CONFIG_PM_ENABLE
if (s_adc_digi_ctx->use_adc2) {
adc_lock_release(ADC_UNIT_2);
}
if (s_adc_digi_ctx->use_adc1) {
adc_lock_release(ADC_UNIT_1);
}
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)(s_adc_digi_ctx->hal_digi_ctrlr_cfg.clk_src), false));
sar_periph_ctrl_adc_continuous_power_release();
return ESP_OK;
}
esp_err_t adc_digi_read_bytes(uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms)
{
TickType_t ticks_to_wait;
esp_err_t ret = ESP_OK;
uint8_t *data = NULL;
size_t size = 0;
ticks_to_wait = timeout_ms / portTICK_PERIOD_MS;
if (timeout_ms == ADC_MAX_DELAY) {
ticks_to_wait = portMAX_DELAY;
}
data = xRingbufferReceiveUpTo(s_adc_digi_ctx->ringbuf_hdl, &size, ticks_to_wait, length_max);
if (!data) {
ESP_LOGV(ADC_TAG, "No data, increase timeout or reduce conv_num_each_intr");
ret = ESP_ERR_TIMEOUT;
*out_length = 0;
return ret;
}
memcpy(buf, data, size);
vRingbufferReturnItem(s_adc_digi_ctx->ringbuf_hdl, data);
assert((size % 4) == 0);
*out_length = size;
if (s_adc_digi_ctx->ringbuf_overflow_flag) {
ret = ESP_ERR_INVALID_STATE;
}
return ret;
}
/*---------------------------------------------------------------
Digital controller setting
---------------------------------------------------------------*/
esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config)
{
if (!s_adc_digi_ctx) {
return ESP_ERR_INVALID_STATE;
}
//Pattern related check
ESP_RETURN_ON_FALSE(config->pattern_num <= SOC_ADC_PATT_LEN_MAX, ESP_ERR_INVALID_ARG, ADC_TAG, "Max pattern num is %d", SOC_ADC_PATT_LEN_MAX);
#if CONFIG_IDF_TARGET_ESP32
for (int i = 0; i < config->pattern_num; i++) {
ESP_RETURN_ON_FALSE((config->adc_pattern[i].bit_width >= SOC_ADC_DIGI_MIN_BITWIDTH && config->adc_pattern->bit_width <= SOC_ADC_DIGI_MAX_BITWIDTH), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC bitwidth not supported");
ESP_RETURN_ON_FALSE(config->adc_pattern[i].unit == 0, ESP_ERR_INVALID_ARG, ADC_TAG, "Only support using ADC1 DMA mode");
}
#else
for (int i = 0; i < config->pattern_num; i++) {
ESP_RETURN_ON_FALSE((config->adc_pattern[i].bit_width == SOC_ADC_DIGI_MAX_BITWIDTH), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC bitwidth not supported");
}
#endif
ESP_RETURN_ON_FALSE(config->sample_freq_hz <= SOC_ADC_SAMPLE_FREQ_THRES_HIGH && config->sample_freq_hz >= SOC_ADC_SAMPLE_FREQ_THRES_LOW, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC sampling frequency out of range");
#if CONFIG_IDF_TARGET_ESP32
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1");
#elif CONFIG_IDF_TARGET_ESP32S2
if (config->conv_mode == ADC_CONV_BOTH_UNIT || config->conv_mode == ADC_CONV_ALTER_UNIT) {
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2");
} else if (config->conv_mode == ADC_CONV_SINGLE_UNIT_1 || config->conv_mode == ADC_CONV_SINGLE_UNIT_2) {
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE1, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type1");
}
#else
ESP_RETURN_ON_FALSE(config->format == ADC_DIGI_OUTPUT_FORMAT_TYPE2, ESP_ERR_INVALID_ARG, ADC_TAG, "Please use type2");
#endif
s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern_len = config->pattern_num;
s_adc_digi_ctx->hal_digi_ctrlr_cfg.sample_freq_hz = config->sample_freq_hz;
s_adc_digi_ctx->hal_digi_ctrlr_cfg.conv_mode = config->conv_mode;
memcpy(s_adc_digi_ctx->hal_digi_ctrlr_cfg.adc_pattern, config->adc_pattern, config->pattern_num * sizeof(adc_digi_pattern_config_t));
const int atten_uninitialized = 999;
s_adc_digi_ctx->adc1_atten = atten_uninitialized;
s_adc_digi_ctx->adc2_atten = atten_uninitialized;
s_adc_digi_ctx->use_adc1 = 0;
s_adc_digi_ctx->use_adc2 = 0;
for (int i = 0; i < config->pattern_num; i++) {
const adc_digi_pattern_config_t *pat = &config->adc_pattern[i];
if (pat->unit == ADC_UNIT_1) {
s_adc_digi_ctx->use_adc1 = 1;
if (s_adc_digi_ctx->adc1_atten == atten_uninitialized) {
s_adc_digi_ctx->adc1_atten = pat->atten;
} else if (s_adc_digi_ctx->adc1_atten != pat->atten) {
return ESP_ERR_INVALID_ARG;
}
} else if (pat->unit == ADC_UNIT_2) {
//See whether ADC2 will be used or not. If yes, the ``sar_adc2_mutex`` should be acquired in the continuous read driver
s_adc_digi_ctx->use_adc2 = 1;
if (s_adc_digi_ctx->adc2_atten == atten_uninitialized) {
s_adc_digi_ctx->adc2_atten = pat->atten;
} else if (s_adc_digi_ctx->adc2_atten != pat->atten) {
return ESP_ERR_INVALID_ARG;
}
}
}
return ESP_OK;
}
#if !CONFIG_ADC_SKIP_LEGACY_CONFLICT_CHECK
/**
* @brief This function will be called during start up, to check that adc_continuous driver is not running along with the legacy adc_continuous driver
*/
__attribute__((constructor))
static void check_adc_continuous_driver_conflict(void)
{
// This function was declared as weak here. adc_continuous driver has one implementation.
// So if adc_continuous driver is not linked in, then `adc_continuous_new_handle` should be NULL at runtime.
extern __attribute__((weak)) esp_err_t adc_continuous_new_handle(const void *init_config, void **ret_handle);
if ((void *)adc_continuous_new_handle != NULL) {
ESP_EARLY_LOGE(ADC_TAG, "CONFLICT! driver_ng is not allowed to be used with the legacy driver");
abort();
}
ESP_EARLY_LOGW(ADC_TAG, "legacy driver is deprecated, please migrate to `esp_adc/adc_continuous.h`");
}
#endif //CONFIG_ADC_SKIP_LEGACY_CONFLICT_CHECK
#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);
#if SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED
/* Load the channel compensation from efuse */
for (int k = 0; k < SOC_ADC_CHANNEL_NUM(i); k++) {
adc_load_hw_calibration_chan_compens(i, k, j);
}
#endif
}
}
}
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED

View File

@ -1,248 +0,0 @@
/*
* SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*----------------------------------------------------------------------------------
This file contains ESP32 and ESP32S2 Deprecated ADC APIs and functions
-----------------------------------------------------------------------------------*/
#include "sdkconfig.h"
#include "esp_types.h"
#include "esp_log.h"
#include "esp_intr_alloc.h"
#include "driver/rtc_io.h"
#include "hal/adc_ll.h"
#include "hal/adc_types.h"
#ifdef CONFIG_PM_ENABLE
#include "esp_pm.h"
#endif
#include "freertos/FreeRTOS.h"
#include "driver/adc_i2s_legacy.h"
#include "driver/adc_types_legacy.h"
static __attribute__((unused)) const char *ADC_TAG = "ADC";
#define ADC_CHECK_RET(fun_ret) ({ \
if (fun_ret != ESP_OK) { \
ESP_LOGE(ADC_TAG,"%s:%d",__FUNCTION__,__LINE__); \
return ESP_FAIL; \
} \
})
#define ADC_CHECK(a, str, ret_val) ({ \
if (!(a)) { \
ESP_LOGE(ADC_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
return (ret_val); \
} \
})
#define ADC_CHANNEL_CHECK(periph, channel) ADC_CHECK(channel < SOC_ADC_CHANNEL_NUM(periph), "ADC"#periph" channel error", ESP_ERR_INVALID_ARG)
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
#define ADC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
#define ADC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_handle_t adc_digi_arbiter_lock = NULL;
#endif //CONFIG_PM_ENABLE
#if CONFIG_IDF_TARGET_ESP32
/*---------------------------------------------------------------
ESP32 Deprecated ADC APIs and functions
---------------------------------------------------------------*/
#define DIG_ADC_OUTPUT_FORMAT_DEFUALT (ADC_DIGI_FORMAT_12BIT)
#define DIG_ADC_ATTEN_DEFUALT (ADC_ATTEN_DB_12)
#define DIG_ADC_BIT_WIDTH_DEFUALT (3) //3 for ADC_WIDTH_BIT_12
/**
* @brief ADC digital controller (DMA mode) conversion rules setting.
*/
typedef struct {
union {
struct {
uint8_t atten: 2; /*!< ADC sampling voltage attenuation configuration. Modification of attenuation affects the range of measurements.
0: measurement range 0 - 800mV,
1: measurement range 0 - 1100mV,
2: measurement range 0 - 1350mV,
3: measurement range 0 - 2600mV. */
uint8_t bit_width: 2; /*!< ADC resolution.
- 0: 9 bit;
- 1: 10 bit;
- 2: 11 bit;
- 3: 12 bit. */
int8_t channel: 4; /*!< ADC channel index. */
};
uint8_t val; /*!<Raw data value */
};
} adc_digi_pattern_table_t;
/**
* @brief ADC digital controller (DMA mode) output data format option.
*/
typedef enum {
ADC_DIGI_FORMAT_12BIT, /*!<ADC to DMA data format, [15:12]-channel, [11: 0]-12 bits ADC data (`adc_digi_output_data_t`). Note: For single convert mode. */
ADC_DIGI_FORMAT_11BIT, /*!<ADC to DMA data format, [15]-adc unit, [14:11]-channel, [10: 0]-11 bits ADC data (`adc_digi_output_data_t`). Note: For multi or alter convert mode. */
ADC_DIGI_FORMAT_MAX,
} adc_digi_format_t;
/**
* Explanation of the relationship between `conv_limit_num`, `dma_eof_num` and the number of DMA outputs:
*
* +---------------------+--------+--------+--------+
* | conv_mode | single | both | alter |
* +---------------------+--------+--------+--------+
* | trigger meas times | 1 | 1 | 1 |
* +---------------------+--------+--------+--------+
* | conv_limit_num | +1 | +1 | +1 |
* | dma_eof_num | +1 | +2 | +1 |
* | dma output (byte) | +2 | +4 | +2 |
* +---------------------+--------+--------+--------+
*/
typedef struct {
uint32_t adc1_pattern_len; /*!<Pattern table length for digital controller. Range: 0 ~ 16 (0: Don't change the pattern table setting).
The pattern table that defines the conversion rules for each SAR ADC. Each table has 16 items, in which channel selection,
resolution and attenuation are stored. When the conversion is started, the controller reads conversion rules from the
pattern table one by one. For each controller the scan sequence has at most 16 different rules before repeating itself. */
uint32_t adc2_pattern_len; /*!<Refer to ``adc1_pattern_len`` */
adc_digi_pattern_table_t *adc1_pattern; /*!<Pointer to pattern table for digital controller. The table size defined by `adc1_pattern_len`. */
adc_digi_pattern_table_t *adc2_pattern; /*!<Refer to `adc1_pattern` */
adc_digi_convert_mode_t conv_mode; /*!<ADC conversion mode for digital controller. See ``adc_digi_convert_mode_t``. */
adc_digi_format_t format; /*!<ADC output data format for digital controller. See ``adc_digi_format_t``. */
} adc_digi_config_t;
/**
* Set adc output 16-bit-data format from digital controller.
*
* @param data_sel 1: [15] unit, [14:11] channel, [10:0] data, 11-bit-width at most. Only work under `ADC_LL_DIGI_CONV_BOTH_UNIT` or `ADC_LL_DIGI_CONV_ALTER_UNIT` mode.
* 0: [15:12] channel, [11:0] data, 12-bit-width at most. Only work under `ADC_LL_DIGI_CONV_ONLY_ADC1` or `ADC_LL_DIGI_CONV_ONLY_ADC2` mode
* @note see `adc_ll_digi_pattern_table_t` for more detail of data bit width
*/
static inline void adc_ll_digi_set_output_format(bool data_sel)
{
SYSCON.saradc_ctrl.data_sar_sel = data_sel;
}
static inline void adc_ll_digi_prepare_pattern_table(adc_unit_t adc_n, uint32_t pattern_index, adc_digi_pattern_table_t pattern)
{
uint32_t tab;
uint8_t index = pattern_index / 4;
uint8_t offset = (pattern_index % 4) * 8;
if (adc_n == ADC_UNIT_1) {
tab = SYSCON.saradc_sar1_patt_tab[index]; // Read old register value
tab &= (~(0xFF000000 >> offset)); // clear old data
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
SYSCON.saradc_sar1_patt_tab[index] = tab; // Write back
} else { // adc_n == ADC_UNIT_2
tab = SYSCON.saradc_sar2_patt_tab[index]; // Read old register value
tab &= (~(0xFF000000 >> offset)); // clear old data
tab |= ((uint32_t)pattern.val << 24) >> offset; // Fill in the new data
SYSCON.saradc_sar2_patt_tab[index] = tab; // Write back
}
}
static void adc_digi_controller_reg_set(const adc_digi_config_t *cfg)
{
/* On ESP32, only support ADC1 */
switch (cfg->conv_mode) {
case ADC_CONV_SINGLE_UNIT_1:
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC1);
break;
case ADC_CONV_SINGLE_UNIT_2:
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ONLY_ADC2);
break;
case ADC_CONV_BOTH_UNIT:
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_BOTH_UNIT);
break;
case ADC_CONV_ALTER_UNIT:
adc_ll_digi_set_convert_mode(ADC_LL_DIGI_CONV_ALTER_UNIT);
break;
default:
abort();
}
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_1) {
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);
if (cfg->adc1_pattern_len) {
adc_ll_digi_clear_pattern_table(ADC_UNIT_1);
adc_ll_digi_set_pattern_table_len(ADC_UNIT_1, cfg->adc1_pattern_len);
for (uint32_t i = 0; i < cfg->adc1_pattern_len; i++) {
adc_ll_digi_prepare_pattern_table(ADC_UNIT_1, i, cfg->adc1_pattern[i]);
}
}
}
if (cfg->conv_mode & ADC_CONV_SINGLE_UNIT_2) {
adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_DIG);
if (cfg->adc2_pattern_len) {
adc_ll_digi_clear_pattern_table(ADC_UNIT_2);
adc_ll_digi_set_pattern_table_len(ADC_UNIT_2, cfg->adc2_pattern_len);
for (uint32_t i = 0; i < cfg->adc2_pattern_len; i++) {
adc_ll_digi_prepare_pattern_table(ADC_UNIT_2, i, cfg->adc2_pattern[i]);
}
}
}
adc_ll_digi_set_output_format(cfg->format);
adc_ll_digi_convert_limit_enable(ADC_LL_DEFAULT_CONV_LIMIT_EN);
adc_ll_digi_set_convert_limit_num(ADC_LL_DEFAULT_CONV_LIMIT_NUM);
adc_ll_digi_set_data_source(ADC_I2S_DATA_SRC_ADC);
}
esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src)
{
ADC_CHECK((src == ADC_I2S_DATA_SRC_IO_SIG || src == ADC_I2S_DATA_SRC_ADC), "ADC i2s data source error", ESP_ERR_INVALID_ARG);
ADC_ENTER_CRITICAL();
adc_ll_digi_set_data_source(src);
ADC_EXIT_CRITICAL();
return ESP_OK;
}
extern esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel);
esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel)
{
if (adc_unit == ADC_UNIT_1) {
ADC_CHANNEL_CHECK(ADC_UNIT_1, channel);
} else if (adc_unit == ADC_UNIT_2) {
//ADC2 does not support DMA mode
ADC_CHECK(false, "ADC2 not support DMA for now.", ESP_ERR_INVALID_ARG);
ADC_CHANNEL_CHECK(ADC_UNIT_2, channel);
}
adc_digi_pattern_table_t adc1_pattern[1];
adc_digi_pattern_table_t adc2_pattern[1];
adc_digi_config_t dig_cfg = {
.format = DIG_ADC_OUTPUT_FORMAT_DEFUALT,
.conv_mode = ADC_CONV_SINGLE_UNIT_1,
};
if (adc_unit == ADC_UNIT_1) {
adc1_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT;
adc1_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT;
adc1_pattern[0].channel = channel;
dig_cfg.adc1_pattern_len = 1;
dig_cfg.adc1_pattern = adc1_pattern;
} else if (adc_unit == ADC_UNIT_2) {
adc2_pattern[0].atten = DIG_ADC_ATTEN_DEFUALT;
adc2_pattern[0].bit_width = DIG_ADC_BIT_WIDTH_DEFUALT;
adc2_pattern[0].channel = channel;
dig_cfg.adc2_pattern_len = 1;
dig_cfg.adc2_pattern = adc2_pattern;
}
adc_common_gpio_init(adc_unit, channel);
ADC_ENTER_CRITICAL();
adc_ll_digi_set_fsm_time(ADC_LL_FSM_RSTB_WAIT_DEFAULT, ADC_LL_FSM_START_WAIT_DEFAULT,
ADC_LL_FSM_STANDBY_WAIT_DEFAULT);
adc_ll_set_sample_cycle(ADC_LL_SAMPLE_CYCLE_DEFAULT);
adc_ll_pwdet_set_cct(ADC_LL_PWDET_CCT_DEFAULT);
adc_ll_digi_output_invert(ADC_UNIT_1, ADC_LL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_1));
adc_ll_digi_output_invert(ADC_UNIT_2, ADC_LL_DIGI_DATA_INVERT_DEFAULT(ADC_UNIT_2));
adc_ll_digi_set_clk_div(ADC_LL_DIGI_SAR_CLK_DIV_DEFAULT);
adc_digi_controller_reg_set(&dig_cfg);
ADC_EXIT_CRITICAL();
return ESP_OK;
}
#endif //#if CONFIG_IDF_TARGET_ESP32

View File

@ -1,952 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <esp_types.h>
#include <stdlib.h>
#include <ctype.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_pm.h"
#include "soc/rtc.h"
#include "soc/soc_caps.h"
#include "esp_private/gpio.h"
#include "sys/lock.h"
#include "esp_private/adc_share_hw_ctrl.h"
#include "esp_private/sar_periph_ctrl.h"
#include "adc1_private.h"
#include "hal/adc_types.h"
#include "hal/adc_hal.h"
#include "hal/adc_ll.h"
#include "hal/adc_hal_common.h"
#include "esp_private/esp_clk_tree_common.h"
#include "esp_private/regi2c_ctrl.h"
#include "esp_private/periph_ctrl.h"
#include "driver/adc_types_legacy.h"
#include "esp_clk_tree.h"
#if SOC_DAC_SUPPORTED
#include "hal/dac_types.h"
#include "hal/dac_ll.h"
#endif
#if CONFIG_IDF_TARGET_ESP32S3
#include "esp_efuse_rtc_calib.h"
#endif
static const char *ADC_TAG = "ADC";
#define ADC_GET_IO_NUM(periph, channel) (adc_channel_io_map[periph][channel])
//////////////////////// Locks ///////////////////////////////////////////
extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
#define RTC_ENTER_CRITICAL() portENTER_CRITICAL(&rtc_spinlock)
#define RTC_EXIT_CRITICAL() portEXIT_CRITICAL(&rtc_spinlock)
#define DIGI_ENTER_CRITICAL()
#define DIGI_EXIT_CRITICAL()
#define ADC_POWER_ENTER() RTC_ENTER_CRITICAL()
#define ADC_POWER_EXIT() RTC_EXIT_CRITICAL()
#define DIGI_CONTROLLER_ENTER() DIGI_ENTER_CRITICAL()
#define DIGI_CONTROLLER_EXIT() DIGI_EXIT_CRITICAL()
#define SARADC1_ENTER() RTC_ENTER_CRITICAL()
#define SARADC1_EXIT() RTC_EXIT_CRITICAL()
#define SARADC2_ENTER() RTC_ENTER_CRITICAL()
#define SARADC2_EXIT() RTC_EXIT_CRITICAL()
//n stands for ADC unit: 1 for ADC1 and 2 for ADC2. Currently both unit touches the same registers
#define VREF_ENTER(n) RTC_ENTER_CRITICAL()
#define VREF_EXIT(n) RTC_EXIT_CRITICAL()
#define FSM_ENTER() RTC_ENTER_CRITICAL()
#define FSM_EXIT() RTC_EXIT_CRITICAL()
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32P4
//prevent ADC1 being used by I2S dma and other tasks at the same time.
static _lock_t adc1_dma_lock;
#define SARADC1_ACQUIRE() _lock_acquire( &adc1_dma_lock )
#define SARADC1_RELEASE() _lock_release( &adc1_dma_lock )
#endif
/*
In ADC2, there're two locks used for different cases:
1. lock shared with app and Wi-Fi:
ESP32:
When Wi-Fi using the ADC2, we assume it will never stop, so app checks the lock and returns immediately if failed.
ESP32S2:
The controller's control over the ADC is determined by the arbiter. There is no need to control by lock.
2. lock shared between tasks:
when several tasks sharing the ADC2, we want to guarantee
all the requests will be handled.
Since conversions are short (about 31us), app returns the lock very soon,
we use a spinlock to stand there waiting to do conversions one by one.
adc2_spinlock should be acquired first, then call `adc_lock_release(ADC_UNIT_2)` or rtc_spinlock.
*/
#if CONFIG_IDF_TARGET_ESP32S2
#ifdef CONFIG_PM_ENABLE
static esp_pm_lock_handle_t s_adc2_arbiter_lock;
#endif //CONFIG_PM_ENABLE
#endif // !CONFIG_IDF_TARGET_ESP32
static uint32_t clk_src_freq_hz;
static esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, uint32_t clk_src_freq_hz, int *out_raw);
/*---------------------------------------------------------------
ADC Common
---------------------------------------------------------------*/
esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num)
{
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1), ESP_ERR_INVALID_ARG, ADC_TAG, "invalid channel");
int io = ADC_GET_IO_NUM(ADC_UNIT_1, channel);
if (io < 0) {
return ESP_ERR_INVALID_ARG;
} else {
*gpio_num = (gpio_num_t)io;
}
return ESP_OK;
}
#if (SOC_ADC_PERIPH_NUM >= 2)
esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num)
{
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_2), ESP_ERR_INVALID_ARG, ADC_TAG, "invalid channel");
int io = ADC_GET_IO_NUM(ADC_UNIT_2, channel);
if (io < 0) {
return ESP_ERR_INVALID_ARG;
} else {
*gpio_num = (gpio_num_t)io;
}
return ESP_OK;
}
#endif
//------------------------------------------------------------RTC Single Read----------------------------------------------//
#if SOC_ADC_RTC_CTRL_SUPPORTED
esp_err_t adc_set_clk_div(uint8_t clk_div)
{
DIGI_CONTROLLER_ENTER();
adc_ll_digi_set_clk_div(clk_div);
DIGI_CONTROLLER_EXIT();
return ESP_OK;
}
static void adc_rtc_chan_init(adc_unit_t adc_unit)
{
if (adc_unit == ADC_UNIT_1) {
/* Workaround: Disable the synchronization operation function of ADC1 and DAC.
If enabled(default), ADC RTC controller sampling will cause the DAC channel output voltage. */
#if SOC_DAC_SUPPORTED
dac_ll_rtc_sync_by_adc(false);
#endif
adc_oneshot_ll_output_invert(ADC_UNIT_1, ADC_LL_DATA_INVERT_DEFAULT(ADC_UNIT_1));
adc_ll_set_sar_clk_div(ADC_UNIT_1, ADC_LL_SAR_CLK_DIV_DEFAULT(ADC_UNIT_1));
#ifdef CONFIG_IDF_TARGET_ESP32
adc_ll_hall_disable(); //Disable other peripherals.
adc_ll_amp_disable(); //Currently the LNA is not open, close it by default.
#endif
}
if (adc_unit == ADC_UNIT_2) {
adc_ll_pwdet_set_cct(ADC_LL_PWDET_CCT_DEFAULT);
adc_oneshot_ll_output_invert(ADC_UNIT_2, ADC_LL_DATA_INVERT_DEFAULT(ADC_UNIT_2));
adc_ll_set_sar_clk_div(ADC_UNIT_2, ADC_LL_SAR_CLK_DIV_DEFAULT(ADC_UNIT_2));
}
}
esp_err_t adc_common_gpio_init(adc_unit_t adc_unit, adc_channel_t channel)
{
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(adc_unit), ESP_ERR_INVALID_ARG, ADC_TAG, "invalid channel");
gpio_num_t gpio_num = 0;
//If called with `ADC_UNIT_BOTH (ADC_UNIT_1 | ADC_UNIT_2)`, both if blocks will be run
if (adc_unit == ADC_UNIT_1) {
gpio_num = ADC_GET_IO_NUM(ADC_UNIT_1, channel);
} else if (adc_unit == ADC_UNIT_2) {
gpio_num = ADC_GET_IO_NUM(ADC_UNIT_2, channel);
} else {
return ESP_ERR_INVALID_ARG;
}
return gpio_config_as_analog(gpio_num);
}
esp_err_t adc_set_data_inv(adc_unit_t adc_unit, bool inv_en)
{
if (adc_unit == ADC_UNIT_1) {
SARADC1_ENTER();
adc_oneshot_ll_output_invert(ADC_UNIT_1, inv_en);
SARADC1_EXIT();
}
if (adc_unit == ADC_UNIT_2) {
SARADC2_ENTER();
adc_oneshot_ll_output_invert(ADC_UNIT_2, inv_en);
SARADC2_EXIT();
}
return ESP_OK;
}
esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit)
{
ESP_RETURN_ON_FALSE(width_bit < ADC_WIDTH_MAX, ESP_ERR_INVALID_ARG, ADC_TAG, "unsupported bit width");
adc_bitwidth_t bitwidth = 0;
#if CONFIG_IDF_TARGET_ESP32
if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) {
bitwidth = SOC_ADC_RTC_MAX_BITWIDTH;
} else {
switch (width_bit) {
case ADC_WIDTH_BIT_9:
bitwidth = ADC_BITWIDTH_9;
break;
case ADC_WIDTH_BIT_10:
bitwidth = ADC_BITWIDTH_10;
break;
case ADC_WIDTH_BIT_11:
bitwidth = ADC_BITWIDTH_11;
break;
case ADC_WIDTH_BIT_12:
bitwidth = ADC_BITWIDTH_12;
break;
default:
return ESP_ERR_INVALID_ARG;
}
}
#elif CONFIG_IDF_TARGET_ESP32S2
bitwidth = ADC_BITWIDTH_13;
#else //esp32s3
bitwidth = ADC_BITWIDTH_12;
#endif
if (adc_unit == ADC_UNIT_1) {
SARADC1_ENTER();
adc_oneshot_ll_set_output_bits(ADC_UNIT_1, bitwidth);
SARADC1_EXIT();
}
if (adc_unit == ADC_UNIT_2) {
SARADC2_ENTER();
adc_oneshot_ll_set_output_bits(ADC_UNIT_2, bitwidth);
SARADC2_EXIT();
}
return ESP_OK;
}
/**
* @brief Reset RTC controller FSM.
*
* @return
* - ESP_OK Success
*/
#if !CONFIG_IDF_TARGET_ESP32
esp_err_t adc_rtc_reset(void)
{
FSM_ENTER();
adc_ll_rtc_reset();
FSM_EXIT();
return ESP_OK;
}
#endif
/*-------------------------------------------------------------------------------------
* ADC1
*------------------------------------------------------------------------------------*/
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
{
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1), ESP_ERR_INVALID_ARG, ADC_TAG, "invalid channel");
ESP_RETURN_ON_FALSE(atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC Atten Err");
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
if (!clk_src_freq_hz) {
//should never fail
esp_clk_tree_src_get_freq_hz(ADC_DIGI_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
}
#endif //#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
adc_common_gpio_init(ADC_UNIT_1, channel);
SARADC1_ENTER();
adc_rtc_chan_init(ADC_UNIT_1);
adc_oneshot_ll_set_atten(ADC_UNIT_1, channel, atten);
SARADC1_EXIT();
return ESP_OK;
}
esp_err_t adc1_config_width(adc_bits_width_t width_bit)
{
ESP_RETURN_ON_FALSE(width_bit < ADC_WIDTH_MAX, ESP_ERR_INVALID_ARG, ADC_TAG, "unsupported bit width");
adc_bitwidth_t bitwidth = 0;
#if CONFIG_IDF_TARGET_ESP32
if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) {
bitwidth = SOC_ADC_RTC_MAX_BITWIDTH;
} else {
switch (width_bit) {
case ADC_WIDTH_BIT_9:
bitwidth = ADC_BITWIDTH_9;
break;
case ADC_WIDTH_BIT_10:
bitwidth = ADC_BITWIDTH_10;
break;
case ADC_WIDTH_BIT_11:
bitwidth = ADC_BITWIDTH_11;
break;
case ADC_WIDTH_BIT_12:
bitwidth = ADC_BITWIDTH_12;
break;
default:
return ESP_ERR_INVALID_ARG;
}
}
#elif CONFIG_IDF_TARGET_ESP32S2
bitwidth = ADC_BITWIDTH_13;
#else //esp32s3
bitwidth = ADC_BITWIDTH_12;
#endif
SARADC1_ENTER();
adc_oneshot_ll_set_output_bits(ADC_UNIT_1, bitwidth);
SARADC1_EXIT();
return ESP_OK;
}
esp_err_t adc1_dma_mode_acquire(void)
{
/* Use locks to avoid digtal and RTC controller conflicts.
for adc1, block until acquire the lock. */
SARADC1_ACQUIRE();
ESP_LOGD(ADC_TAG, "dma mode takes adc1 lock.");
sar_periph_ctrl_adc_continuous_power_acquire();
SARADC1_ENTER();
/* switch SARADC into DIG channel */
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_DIG);
SARADC1_EXIT();
return ESP_OK;
}
esp_err_t adc1_rtc_mode_acquire(void)
{
/* Use locks to avoid digtal and RTC controller conflicts.
for adc1, block until acquire the lock. */
SARADC1_ACQUIRE();
sar_periph_ctrl_adc_oneshot_power_acquire();
SARADC1_ENTER();
/* switch SARADC into RTC channel. */
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_RTC);
SARADC1_EXIT();
return ESP_OK;
}
esp_err_t adc1_lock_release(void)
{
ESP_RETURN_ON_FALSE((uint32_t *)adc1_dma_lock != NULL, ESP_ERR_INVALID_STATE, ADC_TAG, "adc1 lock release called before acquire");
/* Use locks to avoid digtal and RTC controller conflicts. for adc1, block until acquire the lock. */
sar_periph_ctrl_adc_oneshot_power_release();
SARADC1_RELEASE();
return ESP_OK;
}
int adc1_get_raw(adc1_channel_t channel)
{
int adc_value;
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1), ESP_ERR_INVALID_ARG, ADC_TAG, "invalid channel");
adc1_rtc_mode_acquire();
ANALOG_CLOCK_ENABLE();
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_hal_calibration_init(ADC_UNIT_1);
adc_atten_t atten = adc_ll_get_atten(ADC_UNIT_1, channel);
adc_set_hw_calibration_code(ADC_UNIT_1, atten);
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
ANALOG_CLOCK_DISABLE();
SARADC1_ENTER();
#ifdef CONFIG_IDF_TARGET_ESP32
adc_ll_hall_disable(); //Disable other peripherals.
adc_ll_amp_disable(); //Currently the LNA is not open, close it by default.
#endif
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_RTC); //Set controller
adc_oneshot_ll_set_channel(ADC_UNIT_1, channel);
adc_hal_convert(ADC_UNIT_1, channel, clk_src_freq_hz, &adc_value); //Start conversion, For ADC1, the data always valid.
#if !CONFIG_IDF_TARGET_ESP32
adc_ll_rtc_reset(); //Reset FSM of rtc controller
#endif
SARADC1_EXIT();
adc1_lock_release();
return adc_value;
}
int adc1_get_voltage(adc1_channel_t channel) //Deprecated. Use adc1_get_raw() instead
{
return adc1_get_raw(channel);
}
#if SOC_ULP_SUPPORTED
void adc1_ulp_enable(void)
{
sar_periph_ctrl_adc_oneshot_power_acquire();
SARADC1_ENTER();
adc_ll_set_controller(ADC_UNIT_1, ADC_LL_CTRL_ULP);
/* since most users do not need LNA and HALL with uLP, we disable them here
open them in the uLP if needed. */
#ifdef CONFIG_IDF_TARGET_ESP32
/* disable other peripherals. */
adc_ll_hall_disable();
adc_ll_amp_disable();
#endif
SARADC1_EXIT();
}
#endif
#if (SOC_ADC_PERIPH_NUM >= 2)
/*---------------------------------------------------------------
ADC2
---------------------------------------------------------------*/
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
{
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_2), ESP_ERR_INVALID_ARG, ADC_TAG, "invalid channel");
ESP_RETURN_ON_FALSE(atten <= SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 Atten Err");
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
if (!clk_src_freq_hz) {
//should never fail
esp_clk_tree_src_get_freq_hz(ADC_DIGI_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
}
#endif //#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
adc_common_gpio_init(ADC_UNIT_2, channel);
#if CONFIG_IDF_TARGET_ESP32
/** For ESP32S2 and S3, the right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/
if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) {
//try the lock, return if failed (wifi using).
return ESP_ERR_TIMEOUT;
}
#endif
//avoid collision with other tasks
SARADC2_ENTER();
adc_rtc_chan_init(ADC_UNIT_2);
adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten);
SARADC2_EXIT();
#if CONFIG_IDF_TARGET_ESP32
adc_lock_release(ADC_UNIT_2);
#endif
return ESP_OK;
}
static inline void adc2_init(void)
{
#if CONFIG_IDF_TARGET_ESP32S2
#ifdef CONFIG_PM_ENABLE
/* Lock APB clock. */
if (s_adc2_arbiter_lock == NULL) {
esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "adc2", &s_adc2_arbiter_lock);
}
#endif //CONFIG_PM_ENABLE
#endif //CONFIG_IDF_TARGET_ESP32S2
}
static inline void adc2_dac_disable(adc2_channel_t channel)
{
#if SOC_DAC_SUPPORTED
#ifdef CONFIG_IDF_TARGET_ESP32
if (channel == ADC2_CHANNEL_8) { // the same as DAC channel 0
dac_ll_power_down(DAC_CHAN_0);
} else if (channel == ADC2_CHANNEL_9) {
dac_ll_power_down(DAC_CHAN_1);
}
#else
if (channel == ADC2_CHANNEL_6) { // the same as DAC channel 0
dac_ll_power_down(DAC_CHAN_0);
} else if (channel == ADC2_CHANNEL_7) {
dac_ll_power_down(DAC_CHAN_1);
}
#endif
#endif // SOC_DAC_SUPPORTED
}
/**
* @note For ESP32S2:
* The arbiter's working clock is APB_CLK. When the APB_CLK clock drops below 8 MHz, the arbiter must be in shield mode.
* Or, the RTC controller will fail when get raw data.
* This issue does not occur on digital controllers (DMA mode), and the hardware guarantees that there will be no errors.
*/
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out)
{
esp_err_t ret = ESP_OK;
int adc_value = 0;
adc_bitwidth_t bitwidth = 0;
ESP_RETURN_ON_FALSE(raw_out != NULL, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC out value err");
ESP_RETURN_ON_FALSE(channel < ADC2_CHANNEL_MAX, ESP_ERR_INVALID_ARG, ADC_TAG, "ADC Channel Err");
ESP_RETURN_ON_FALSE(width_bit < ADC_WIDTH_MAX, ESP_ERR_INVALID_ARG, ADC_TAG, "unsupported bit width");
#if CONFIG_IDF_TARGET_ESP32
if ((uint32_t)width_bit == (uint32_t)ADC_BITWIDTH_DEFAULT) {
bitwidth = SOC_ADC_RTC_MAX_BITWIDTH;
} else {
switch (width_bit) {
case ADC_WIDTH_BIT_9:
bitwidth = ADC_BITWIDTH_9;
break;
case ADC_WIDTH_BIT_10:
bitwidth = ADC_BITWIDTH_10;
break;
case ADC_WIDTH_BIT_11:
bitwidth = ADC_BITWIDTH_11;
break;
case ADC_WIDTH_BIT_12:
bitwidth = ADC_BITWIDTH_12;
break;
default:
return ESP_ERR_INVALID_ARG;
}
}
#elif CONFIG_IDF_TARGET_ESP32S2
bitwidth = ADC_BITWIDTH_13;
#else //esp32s3
bitwidth = ADC_BITWIDTH_12;
#endif
#if CONFIG_IDF_TARGET_ESP32
/** For ESP32S2 and S3, the right to use ADC2 is controlled by the arbiter, and there is no need to set a lock.*/
if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) {
//try the lock, return if failed (wifi using).
return ESP_ERR_TIMEOUT;
}
#endif
sar_periph_ctrl_adc_oneshot_power_acquire(); //in critical section with whole rtc module
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_hal_calibration_init(ADC_UNIT_2);
adc_atten_t atten = adc_ll_get_atten(ADC_UNIT_2, channel);
adc_set_hw_calibration_code(ADC_UNIT_2, atten);
#endif //SOC_ADC_CALIBRATION_V1_SUPPORTED
//avoid collision with other tasks
adc2_init(); // in critical section with whole rtc module. because the PWDET use the same registers, place it here.
SARADC2_ENTER();
#if SOC_ADC_ARBITER_SUPPORTED
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
adc_hal_arbiter_config(&config);
#endif
#ifdef CONFIG_ADC_DISABLE_DAC
adc2_dac_disable(channel); //disable other peripherals
#endif
adc_oneshot_ll_set_output_bits(ADC_UNIT_2, bitwidth);
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32P4
adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_RTC);// set controller
#else
adc_ll_set_controller(ADC_UNIT_2, ADC_LL_CTRL_ARB);// set controller
#endif
#if CONFIG_IDF_TARGET_ESP32S2
#ifdef CONFIG_PM_ENABLE
if (s_adc2_arbiter_lock) {
esp_pm_lock_acquire(s_adc2_arbiter_lock);
}
#endif //CONFIG_PM_ENABLE
#endif //CONFIG_IDF_TARGET_ESP32
adc_oneshot_ll_set_channel(ADC_UNIT_2, channel);
ret = adc_hal_convert(ADC_UNIT_2, channel, clk_src_freq_hz, &adc_value);
if (ret != ESP_OK) {
adc_value = -1;
}
#if CONFIG_IDF_TARGET_ESP32S2
#ifdef CONFIG_PM_ENABLE
/* Release APB clock. */
if (s_adc2_arbiter_lock) {
esp_pm_lock_release(s_adc2_arbiter_lock);
}
#endif //CONFIG_PM_ENABLE
#endif //CONFIG_IDF_TARGET_ESP32
SARADC2_EXIT();
sar_periph_ctrl_adc_oneshot_power_release();
#if CONFIG_IDF_TARGET_ESP32
adc_lock_release(ADC_UNIT_2);
#endif
*raw_out = adc_value;
return ret;
}
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
{
#ifdef CONFIG_IDF_TARGET_ESP32
if (adc_unit == ADC_UNIT_1) {
return ESP_ERR_INVALID_ARG;
}
#endif
adc2_channel_t ch = ADC2_CHANNEL_MAX;
/* Check if the GPIO supported. */
for (int i = 0; i < ADC2_CHANNEL_MAX; i++) {
if (gpio == ADC_GET_IO_NUM(ADC_UNIT_2, i)) {
ch = i;
break;
}
}
if (ch == ADC2_CHANNEL_MAX) {
return ESP_ERR_INVALID_ARG;
}
sar_periph_ctrl_adc_oneshot_power_acquire();
if (adc_unit == ADC_UNIT_1) {
VREF_ENTER(1);
adc_ll_vref_output(ADC_UNIT_1, ch, true);
VREF_EXIT(1);
} else if (adc_unit == ADC_UNIT_2) {
VREF_ENTER(2);
adc_ll_vref_output(ADC_UNIT_2, ch, true);
VREF_EXIT(2);
}
//Configure RTC gpio, Only ADC2's channels IO are supported to output reference voltage.
adc_common_gpio_init(ADC_UNIT_2, ch);
return ESP_OK;
}
#endif //SOC_ADC_RTC_CTRL_SUPPORTED
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
/*---------------------------------------------------------------
Legacy ADC Single Read Mode
when RTC controller isn't supported
---------------------------------------------------------------*/
#include "esp_check.h"
portMUX_TYPE adc_reg_lock = portMUX_INITIALIZER_UNLOCKED;
#define ADC_REG_LOCK_ENTER() portENTER_CRITICAL(&adc_reg_lock)
#define ADC_REG_LOCK_EXIT() portEXIT_CRITICAL(&adc_reg_lock)
static adc_atten_t s_atten1_single[ADC1_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC1, used by single read API
#if (SOC_ADC_PERIPH_NUM >= 2)
static adc_atten_t s_atten2_single[ADC2_CHANNEL_MAX]; //Array saving attenuate of each channel of ADC2, used by single read API
#endif
static int8_t adc_digi_get_io_num(adc_unit_t adc_unit, uint8_t adc_channel)
{
assert(adc_unit < SOC_ADC_PERIPH_NUM);
uint8_t adc_n = (adc_unit == ADC_UNIT_1) ? 0 : 1;
return adc_channel_io_map[adc_n][adc_channel];
}
static esp_err_t adc_digi_gpio_init(adc_unit_t adc_unit, uint16_t channel_mask)
{
esp_err_t ret = ESP_OK;
uint32_t n = 0;
int8_t io = 0;
while (channel_mask) {
if (channel_mask & 0x1) {
io = adc_digi_get_io_num(adc_unit, n);
if (io < 0) {
return ESP_ERR_INVALID_ARG;
}
gpio_config_as_analog(io);
}
channel_mask = channel_mask >> 1;
n++;
}
return ret;
}
#if CONFIG_IDF_TARGET_ESP32C3
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
{
esp_err_t ret;
uint32_t channel = ADC2_CHANNEL_MAX;
if (adc_unit == ADC_UNIT_2) {
for (int i = 0; i < ADC2_CHANNEL_MAX; i++) {
if (gpio == ADC_GET_IO_NUM(ADC_UNIT_2, i)) {
channel = i;
break;
}
}
if (channel == ADC2_CHANNEL_MAX) {
return ESP_ERR_INVALID_ARG;
}
}
sar_periph_ctrl_adc_oneshot_power_acquire();
if (adc_unit == ADC_UNIT_1) {
RTC_ENTER_CRITICAL();
adc_ll_vref_output(ADC_UNIT_1, channel, true);
RTC_EXIT_CRITICAL();
} else { //ADC_UNIT_2
RTC_ENTER_CRITICAL();
adc_ll_vref_output(ADC_UNIT_2, channel, true);
RTC_EXIT_CRITICAL();
}
ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel));
return ret;
}
#endif
esp_err_t adc1_config_width(adc_bits_width_t width_bit)
{
//On ESP32C3, the data width is always 12-bits.
if (width_bit != ADC_WIDTH_BIT_12) {
return ESP_ERR_INVALID_ARG;
}
return ESP_OK;
}
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten)
{
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_1), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC1 channel error");
ESP_RETURN_ON_FALSE((atten < SOC_ADC_ATTEN_NUM), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC Atten Err");
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
if (!clk_src_freq_hz) {
//should never fail
esp_clk_tree_src_get_freq_hz(ADC_DIGI_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
}
#endif //#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
esp_err_t ret = ESP_OK;
s_atten1_single[channel] = atten;
ret = adc_digi_gpio_init(ADC_UNIT_1, BIT(channel));
return ret;
}
int adc1_get_raw(adc1_channel_t channel)
{
int raw_out = 0;
if (adc_lock_try_acquire(ADC_UNIT_1) != ESP_OK) {
return ESP_ERR_TIMEOUT;
}
adc_apb_periph_claim();
sar_periph_ctrl_adc_oneshot_power_acquire();
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)ADC_DIGI_CLK_SRC_DEFAULT, true));
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_DEFAULT);
adc_atten_t atten = s_atten1_single[channel];
ANALOG_CLOCK_ENABLE();
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_hal_calibration_init(ADC_UNIT_1);
adc_set_hw_calibration_code(ADC_UNIT_1, atten);
#endif
ANALOG_CLOCK_DISABLE();
ADC_REG_LOCK_ENTER();
adc_oneshot_ll_set_atten(ADC_UNIT_1, channel, atten);
adc_hal_convert(ADC_UNIT_1, channel, clk_src_freq_hz, &raw_out);
ADC_REG_LOCK_EXIT();
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)ADC_DIGI_CLK_SRC_DEFAULT, false));
sar_periph_ctrl_adc_oneshot_power_release();
adc_apb_periph_free();
adc_lock_release(ADC_UNIT_1);
return raw_out;
}
#if (SOC_ADC_PERIPH_NUM >= 2)
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten)
{
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(ADC_UNIT_2), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 channel error");
ESP_RETURN_ON_FALSE((atten <= ADC_ATTEN_DB_12), ESP_ERR_INVALID_ARG, ADC_TAG, "ADC2 Atten Err");
esp_err_t ret = ESP_OK;
s_atten2_single[channel] = atten;
ret = adc_digi_gpio_init(ADC_UNIT_2, BIT(channel));
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_hal_calibration_init(ADC_UNIT_2);
#endif
return ret;
}
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out)
{
//On ESP32C3, the data width is always 12-bits.
if (width_bit != ADC_WIDTH_BIT_12) {
return ESP_ERR_INVALID_ARG;
}
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
if (!clk_src_freq_hz) {
//should never fail
esp_clk_tree_src_get_freq_hz(ADC_DIGI_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
}
#endif //#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
esp_err_t ret = ESP_OK;
if (adc_lock_try_acquire(ADC_UNIT_2) != ESP_OK) {
return ESP_ERR_TIMEOUT;
}
adc_apb_periph_claim();
sar_periph_ctrl_adc_oneshot_power_acquire();
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)ADC_DIGI_CLK_SRC_DEFAULT, true));
adc_ll_digi_clk_sel(ADC_DIGI_CLK_SRC_DEFAULT);
#if SOC_ADC_ARBITER_SUPPORTED
adc_arbiter_t config = ADC_ARBITER_CONFIG_DEFAULT();
adc_hal_arbiter_config(&config);
#endif
adc_atten_t atten = s_atten2_single[channel];
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
adc_set_hw_calibration_code(ADC_UNIT_2, atten);
#endif
ADC_REG_LOCK_ENTER();
adc_oneshot_ll_set_atten(ADC_UNIT_2, channel, atten);
ret = adc_hal_convert(ADC_UNIT_2, channel, clk_src_freq_hz, raw_out);
ADC_REG_LOCK_EXIT();
ESP_ERROR_CHECK(esp_clk_tree_enable_src((soc_module_clk_t)ADC_DIGI_CLK_SRC_DEFAULT, false));
sar_periph_ctrl_adc_oneshot_power_release();
adc_apb_periph_free();
adc_lock_release(ADC_UNIT_2);
return ret;
}
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
#endif //#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
static void adc_hal_onetime_start(adc_unit_t adc_n, uint32_t clk_src_freq_hz)
{
#if SOC_ADC_DIG_CTRL_SUPPORTED && !SOC_ADC_RTC_CTRL_SUPPORTED
(void)adc_n;
/**
* There is a hardware limitation. If the APB clock frequency is high, the step of this reg signal: ``onetime_start`` may not be captured by the
* ADC digital controller (when its clock frequency is too slow). A rough estimate for this step should be at least 3 ADC digital controller
* clock cycle.
*/
uint32_t digi_clk = clk_src_freq_hz / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_A_DEFAULT / ADC_LL_CLKM_DIV_B_DEFAULT + 1);
//Convert frequency to time (us). Since decimals are removed by this division operation. Add 1 here in case of the fact that delay is not enough.
uint32_t delay = (1000 * 1000) / digi_clk + 1;
//3 ADC digital controller clock cycle
delay = delay * 3;
//This coefficient (8) is got from test, and verified from DT. When digi_clk is not smaller than ``APB_CLK_FREQ/8``, no delay is needed.
if (digi_clk >= APB_CLK_FREQ / 8) {
delay = 0;
}
adc_oneshot_ll_start(false);
esp_rom_delay_us(delay);
adc_oneshot_ll_start(true);
//No need to delay here. Because if the start signal is not seen, there won't be a done intr.
#else
(void)clk_src_freq_hz;
adc_oneshot_ll_start(adc_n);
#endif
}
static esp_err_t adc_hal_convert(adc_unit_t adc_n, int channel, uint32_t clk_src_freq_hz, int *out_raw)
{
uint32_t event = (adc_n == ADC_UNIT_1) ? ADC_LL_EVENT_ADC1_ONESHOT_DONE : ADC_LL_EVENT_ADC2_ONESHOT_DONE;
adc_oneshot_ll_clear_event(event);
adc_oneshot_ll_disable_all_unit();
adc_oneshot_ll_enable(adc_n);
adc_oneshot_ll_set_channel(adc_n, channel);
adc_hal_onetime_start(adc_n, clk_src_freq_hz);
while (adc_oneshot_ll_get_event(event) != true) {
;
}
*out_raw = adc_oneshot_ll_get_raw_result(adc_n);
if (adc_oneshot_ll_raw_check_valid(adc_n, *out_raw) == false) {
return ESP_ERR_INVALID_STATE;
}
//HW workaround: when enabling periph clock, this should be false
adc_oneshot_ll_disable_all_unit();
return ESP_OK;
}
#if !CONFIG_ADC_SKIP_LEGACY_CONFLICT_CHECK
/**
* @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
*/
__attribute__((constructor))
static void check_adc_oneshot_driver_conflict(void)
{
// This function was declared as weak here. adc_oneshot driver has one implementation.
// So if adc_oneshot driver is not linked in, then `adc_oneshot_new_unit` should be NULL at runtime.
extern __attribute__((weak)) esp_err_t adc_oneshot_new_unit(const void *init_config, void **ret_unit);
if ((void *)adc_oneshot_new_unit != NULL) {
ESP_EARLY_LOGE(ADC_TAG, "CONFLICT! driver_ng is not allowed to be used with the legacy driver");
abort();
}
ESP_EARLY_LOGW(ADC_TAG, "legacy driver is deprecated, please migrate to `esp_adc/adc_oneshot.h`");
}
#endif //CONFIG_ADC_SKIP_LEGACY_CONFLICT_CHECK
#if SOC_ADC_CALIBRATION_V1_SUPPORTED
/*---------------------------------------------------------------
ADC Hardware Calibration
---------------------------------------------------------------*/
static __attribute__((constructor)) void adc_hw_calibration(void)
{
ANALOG_CLOCK_ENABLE();
//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);
#if SOC_ADC_CALIB_CHAN_COMPENS_SUPPORTED
/* Load the channel compensation from efuse */
for (int k = 0; k < SOC_ADC_CHANNEL_NUM(i); k++) {
adc_load_hw_calibration_chan_compens(i, k, j);
}
#endif
}
}
ANALOG_CLOCK_DISABLE();
}
#endif //#if SOC_ADC_CALIBRATION_V1_SUPPORTED

View File

@ -1,355 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*----------------------------------------------------------------------------------
This file contains Deprecated ADC APIs
-----------------------------------------------------------------------------------*/
#pragma once
#include "sdkconfig.h"
#include "esp_err.h"
#include "driver/gpio.h"
#include "driver/adc_types_legacy.h"
#include "hal/adc_types.h"
#if !CONFIG_ADC_SUPPRESS_DEPRECATE_WARN
#warning "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"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------
Deprecated API
---------------------------------------------------------------*/
/*---------------------------------------------------------------
ADC Single Read Setting
---------------------------------------------------------------*/
/**
* @brief Get the GPIO number of a specific ADC1 channel.
*
* @param channel Channel to get the GPIO number
* @param gpio_num output buffer to hold the GPIO number
*
* @return
* - ESP_OK if success
* - ESP_ERR_INVALID_ARG if channel not valid
*/
esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_num);
/**
* @brief Set the attenuation of a particular channel on ADC1, and configure its associated GPIO pin mux.
*
* The default ADC voltage is for attenuation 0 dB and listed in the table below.
* By setting higher attenuation it is possible to read higher voltages.
*
* Due to ADC characteristics, most accurate results are obtained within the "suggested range"
* shown in the following table.
*
* +----------+-------------+-----------------+
* | | attenuation | suggested range |
* | SoC | (dB) | (mV) |
* +==========+=============+=================+
* | | 0 | 100 ~ 950 |
* | +-------------+-----------------+
* | | 2.5 | 100 ~ 1250 |
* | ESP32 +-------------+-----------------+
* | | 6 | 150 ~ 1750 |
* | +-------------+-----------------+
* | | 11 | 150 ~ 2450 |
* +----------+-------------+-----------------+
* | | 0 | 0 ~ 750 |
* | +-------------+-----------------+
* | | 2.5 | 0 ~ 1050 |
* | ESP32-S2 +-------------+-----------------+
* | | 6 | 0 ~ 1300 |
* | +-------------+-----------------+
* | | 11 | 0 ~ 2500 |
* +----------+-------------+-----------------+
*
* For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges.
*
* @note For any given channel, this function must be called before the first time ``adc1_get_raw()`` is called for that channel.
*
* @note This function can be called multiple times to configure multiple
* ADC channels simultaneously. You may call ``adc1_get_raw()`` only after configuring a channel.
*
* @param channel ADC1 channel to configure
* @param atten Attenuation level
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc1_config_channel_atten(adc1_channel_t channel, adc_atten_t atten);
/**
* @brief Configure ADC1 capture width, meanwhile enable output invert for ADC1.
* The configuration is for all channels of ADC1
* @param width_bit Bit capture width for ADC1
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc1_config_width(adc_bits_width_t width_bit);
/**
* @brief Take an ADC1 reading from a single channel.
* @note ESP32:
* When the power switch of SARADC1, SARADC2, HALL sensor and AMP sensor is turned on,
* 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 sar_periph_ctrl_adc_oneshot_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.
*
* @note For any given channel, adc1_config_channel_atten(channel)
* must be called before the first time this function is called. Configuring
* a new channel does not prevent a previously configured channel from being read.
*
* @param channel ADC1 channel to read
*
* @return
* - -1: Parameter error
* - Other: ADC1 channel reading.
*/
int adc1_get_raw(adc1_channel_t channel);
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
//TODO IDF-3610, replace these with proper caps
/**
* @brief Set ADC data invert
* @param adc_unit ADC unit index
* @param inv_en whether enable data invert
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_set_data_inv(adc_unit_t adc_unit, bool inv_en);
/**
* @brief Set ADC source clock
* @param clk_div ADC clock divider, ADC clock is divided from APB clock
* @return
* - ESP_OK success
*/
esp_err_t adc_set_clk_div(uint8_t clk_div);
/**
* @brief Configure ADC capture width.
*
* @param adc_unit ADC unit index
* @param width_bit Bit capture width for ADC unit.
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_set_data_width(adc_unit_t adc_unit, adc_bits_width_t width_bit);
/**
* @brief Configure ADC1 to be usable by the ULP
*
* This function reconfigures ADC1 to be controlled by the ULP.
* Effect of this function can be reverted using ``adc1_get_raw()`` function.
*
* Note that adc1_config_channel_atten, ``adc1_config_width()`` functions need
* to be called to configure ADC1 channels, before ADC1 is used by the ULP.
*/
void adc1_ulp_enable(void);
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
#if (SOC_ADC_PERIPH_NUM >= 2)
/**
* @brief Get the GPIO number of a specific ADC2 channel.
*
* @param channel Channel to get the GPIO number
*
* @param gpio_num output buffer to hold the GPIO number
*
* @return
* - ESP_OK if success
* - ESP_ERR_INVALID_ARG if channel not valid
*/
esp_err_t adc2_pad_get_io_num(adc2_channel_t channel, gpio_num_t *gpio_num);
/**
* @brief Configure the ADC2 channel, including setting attenuation.
*
* The default ADC voltage is for attenuation 0 dB and listed in the table below.
* By setting higher attenuation it is possible to read higher voltages.
*
* Due to ADC characteristics, most accurate results are obtained within the "suggested range"
* shown in the following table.
*
* +----------+-------------+-----------------+
* | | attenuation | suggested range |
* | SoC | (dB) | (mV) |
* +==========+=============+=================+
* | | 0 | 100 ~ 950 |
* | +-------------+-----------------+
* | | 2.5 | 100 ~ 1250 |
* | ESP32 +-------------+-----------------+
* | | 6 | 150 ~ 1750 |
* | +-------------+-----------------+
* | | 11 | 150 ~ 2450 |
* +----------+-------------+-----------------+
* | | 0 | 0 ~ 750 |
* | +-------------+-----------------+
* | | 2.5 | 0 ~ 1050 |
* | ESP32-S2 +-------------+-----------------+
* | | 6 | 0 ~ 1300 |
* | +-------------+-----------------+
* | | 11 | 0 ~ 2500 |
* +----------+-------------+-----------------+
*
* For maximum accuracy, use the ADC calibration APIs and measure voltages within these recommended ranges.
*
* @note This function also configures the input GPIO pin mux to
* connect it to the ADC2 channel. It must be called before calling
* ``adc2_get_raw()`` for this channel.
*
* @note For any given channel, this function must be called before the first time ``adc2_get_raw()`` is called for that channel.
*
* @param channel ADC2 channel to configure
* @param atten Attenuation level
*
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc2_config_channel_atten(adc2_channel_t channel, adc_atten_t atten);
/**
* @brief Take an ADC2 reading on a single channel
*
* @note ESP32:
* When the power switch of SARADC1, SARADC2, HALL sensor and AMP sensor is turned on,
* 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 sar_periph_ctrl_adc_oneshot_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()``
* must be called before the first time this function is called. If Wi-Fi is started via ``esp_wifi_start()``, this
* function will always fail with ``ESP_ERR_TIMEOUT``.
*
* @note ESP32-S2:
* ADC2 support hardware arbiter. The arbiter is to improve the use efficiency of ADC2. After the control right is robbed by the high priority,
* the low priority controller will read the invalid ADC2 data. Default priority: Wi-Fi > RTC > Digital;
*
* @param channel ADC2 channel to read
* @param width_bit Bit capture width for ADC2
* @param raw_out the variable to hold the output data.
*
* @return
* - ESP_OK if success
* - ESP_ERR_TIMEOUT ADC2 is being used by other controller and the request timed out.
* - ESP_ERR_INVALID_STATE The controller status is invalid. Please try again.
*/
esp_err_t adc2_get_raw(adc2_channel_t channel, adc_bits_width_t width_bit, int *raw_out);
/**
* @brief Output ADC1 or ADC2's reference voltage to ``adc2_channe_t``'s IO.
*
* This function routes the internal reference voltage of ADCn to one of
* ADC2's channels. This reference voltage can then be manually measured
* for calibration purposes.
*
* @note ESP32 only supports output of ADC2's internal reference voltage.
* @param[in] adc_unit ADC unit index
* @param[in] gpio GPIO number (Only ADC2's channels IO are supported)
*
* @return
* - ESP_OK: v_ref successfully routed to selected GPIO
* - ESP_ERR_INVALID_ARG: Unsupported GPIO
*/
esp_err_t adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio);
#endif //#if (SOC_ADC_PERIPH_NUM >= 2)
/*---------------------------------------------------------------
ADC DMA Read Setting
---------------------------------------------------------------*/
#if SOC_ADC_DMA_SUPPORTED
/**
* @brief Initialize the Digital ADC.
*
* @param init_config Pointer to Digital ADC initialization config. Refer to ``adc_digi_init_config_t``.
*
* @return
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
* - ESP_ERR_NOT_FOUND No free interrupt found with the specified flags
* - ESP_ERR_NO_MEM If out of memory
* - ESP_OK On success
*/
esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config);
/**
* @brief Read bytes from Digital ADC through DMA.
*
* @param[out] buf Buffer to read from ADC.
* @param[in] length_max Expected length of data read from the ADC.
* @param[out] out_length Real length of data read from the ADC via this API.
* @param[in] timeout_ms Time to wait for data via this API, in millisecond.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid. Usually it means the ADC sampling rate is faster than the task processing rate.
* - ESP_ERR_TIMEOUT Operation timed out
* - ESP_OK On success
*/
esp_err_t adc_digi_read_bytes(uint8_t *buf, uint32_t length_max, uint32_t *out_length, uint32_t timeout_ms);
/**
* @brief Start the Digital ADC and DMA peripherals. After this, the hardware starts working.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid.
* - ESP_OK On success
*/
esp_err_t adc_digi_start(void);
/**
* @brief Stop the Digital ADC and DMA peripherals. After this, the hardware stops working.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid.
* - ESP_OK On success
*/
esp_err_t adc_digi_stop(void);
/**
* @brief Deinitialize the Digital ADC.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid.
* - ESP_OK On success
*/
esp_err_t adc_digi_deinitialize(void);
/**
* @brief Setting the digital controller.
*
* @param config Pointer to digital controller parameter. Refer to ``adc_digi_config_t``.
*
* @return
* - ESP_ERR_INVALID_STATE Driver state is invalid.
* - ESP_ERR_INVALID_ARG If the combination of arguments is invalid.
* - ESP_OK On success
*/
esp_err_t adc_digi_controller_configure(const adc_digi_configuration_t *config);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,51 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "esp_err.h"
#include "hal/adc_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef CONFIG_IDF_TARGET_ESP32
/**
* @brief ESP32 ADC DMA source selection.
*/
typedef enum {
ADC_I2S_DATA_SRC_IO_SIG = 0, /*!< I2S data from GPIO matrix signal */
ADC_I2S_DATA_SRC_ADC = 1, /*!< I2S data from ADC */
} adc_i2s_source_t;
#endif
#if CONFIG_IDF_TARGET_ESP32
/*---------------------------------------------------------------
ESP32 Deprecated API
---------------------------------------------------------------*/
/**
* @brief Set I2S data source
* @param src I2S DMA data source, I2S DMA can get data from digital signals or from ADC.
* @return
* - ESP_OK success
*/
esp_err_t adc_set_i2s_data_source(adc_i2s_source_t src);
/**
* @brief Initialize I2S ADC mode
* @param adc_unit ADC unit index
* @param channel ADC channel index
* @return
* - ESP_OK success
* - ESP_ERR_INVALID_ARG Parameter error
*/
esp_err_t adc_i2s_mode_init(adc_unit_t adc_unit, adc_channel_t channel);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -1,130 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "hal/adc_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief ADC resolution setting option.
* @note Only used in single read mode
*/
typedef enum {
#if CONFIG_IDF_TARGET_ESP32
ADC_WIDTH_BIT_9 = 9, /*!< ADC capture width is 9Bit. */
ADC_WIDTH_BIT_10 = 10, /*!< ADC capture width is 10Bit. */
ADC_WIDTH_BIT_11 = 11, /*!< ADC capture width is 11Bit. */
ADC_WIDTH_BIT_12 = 12, /*!< ADC capture width is 12Bit. */
#elif SOC_ADC_RTC_MAX_BITWIDTH == 12
ADC_WIDTH_BIT_12 = 12, /*!< ADC capture width is 12Bit. */
#elif SOC_ADC_RTC_MAX_BITWIDTH == 13
ADC_WIDTH_BIT_13 = 13, /*!< ADC capture width is 13Bit. */
#endif
ADC_WIDTH_MAX,
} adc_bits_width_t;
/**
* The default (max) bit width of the ADC of current version. You can also get the maximum bitwidth
* by `SOC_ADC_RTC_MAX_BITWIDTH` defined in soc_caps.h.
*/
#define ADC_WIDTH_BIT_DEFAULT (ADC_WIDTH_MAX-1)
typedef enum {
ADC1_CHANNEL_0 = 0,
ADC1_CHANNEL_1,
ADC1_CHANNEL_2,
ADC1_CHANNEL_3,
#if SOC_ADC_CHANNEL_NUM(0) > 4
ADC1_CHANNEL_4,
#endif
#if SOC_ADC_CHANNEL_NUM(0) > 5
ADC1_CHANNEL_5,
#endif
#if SOC_ADC_CHANNEL_NUM(0) > 6
ADC1_CHANNEL_6,
#endif
#if SOC_ADC_CHANNEL_NUM(0) > 7
ADC1_CHANNEL_7,
#endif
#if SOC_ADC_CHANNEL_NUM(0) > 8
ADC1_CHANNEL_8,
#endif
#if SOC_ADC_CHANNEL_NUM(0) > 9
ADC1_CHANNEL_9,
#endif
ADC1_CHANNEL_MAX = SOC_ADC_CHANNEL_NUM(0),
} adc1_channel_t;
#if SOC_ADC_PERIPH_NUM > 1
typedef enum {
ADC2_CHANNEL_0 = 0,
#if SOC_ADC_CHANNEL_NUM(1) > 1
ADC2_CHANNEL_1,
#endif
#if SOC_ADC_CHANNEL_NUM(1) > 2
ADC2_CHANNEL_2,
#endif
#if SOC_ADC_CHANNEL_NUM(1) > 3
ADC2_CHANNEL_3,
#endif
#if SOC_ADC_CHANNEL_NUM(1) > 4
ADC2_CHANNEL_4,
#endif
#if SOC_ADC_CHANNEL_NUM(1) > 5
ADC2_CHANNEL_5,
#endif
#if SOC_ADC_CHANNEL_NUM(1) > 6
ADC2_CHANNEL_6,
#endif
#if SOC_ADC_CHANNEL_NUM(1) > 7
ADC2_CHANNEL_7,
#endif
#if SOC_ADC_CHANNEL_NUM(1) > 8
ADC2_CHANNEL_8,
#endif
#if SOC_ADC_CHANNEL_NUM(1) > 9
ADC2_CHANNEL_9,
#endif
ADC2_CHANNEL_MAX = SOC_ADC_CHANNEL_NUM(1),
} adc2_channel_t;
#endif
#if SOC_ADC_DMA_SUPPORTED
/**
* @brief Digital ADC DMA read max timeout value, it may make the ``adc_digi_read_bytes`` block forever if the OS supports
*/
#define ADC_MAX_DELAY UINT32_MAX
/**
* @brief ADC DMA driver configuration
*/
typedef struct adc_digi_init_config_s {
uint32_t max_store_buf_size; ///< Max length of the converted data that driver can store before they are processed.
uint32_t conv_num_each_intr; ///< Bytes of data that can be converted in 1 interrupt. This should be in multiples of `SOC_ADC_DIGI_DATA_BYTES_PER_CONV`.
uint32_t adc1_chan_mask; ///< Channel list of ADC1 to be initialized.
uint32_t adc2_chan_mask; ///< Channel list of ADC2 to be initialized.
} adc_digi_init_config_t;
/**
* @brief ADC digital controller settings
*/
typedef struct {
bool conv_limit_en; ///< Suggest leaving it empty, this parameter has been deprecated
uint32_t conv_limit_num; ///< suggest leaving it empty, this parameter has been deprecated
uint32_t pattern_num; ///< Number of ADC channels that will be used
adc_digi_pattern_config_t *adc_pattern; ///< List of configs for each ADC channel that will be used
uint32_t sample_freq_hz; /*!< Please refer to `soc/soc_caps.h` to know the ADC sampling frequency range*/
adc_digi_convert_mode_t conv_mode; ///< ADC DMA conversion mode, see `adc_digi_convert_mode_t`.
adc_digi_output_format_t format; ///< ADC DMA conversion output format, see `adc_digi_output_format_t`.
} adc_digi_configuration_t;
#endif // #if SOC_ADC_DMA_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@ -1,19 +1,5 @@
# Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
components/driver/test_apps/legacy_adc_driver:
disable:
- if: SOC_ADC_SUPPORTED != 1
disable_test:
- if: IDF_TARGET == "esp32c61"
temporary: true
reason: lack of runners
depends_components:
- efuse
- esp_driver_i2s
- esp_driver_spi
depends_filepatterns:
- components/driver/deprecated/**/*adc*
components/driver/test_apps/legacy_i2c_driver:
disable:
- if: SOC_I2C_SUPPORTED != 1

View File

@ -1,8 +0,0 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(legacy_adc_driver_test)

View File

@ -1,2 +0,0 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |

View File

@ -1,6 +0,0 @@
set(srcs "test_app_main.c"
"test_legacy_adc.c")
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES unity driver
WHOLE_ARCHIVE)

View File

@ -1,40 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "unity.h"
#include "unity_test_runner.h"
#include "esp_heap_caps.h"
#define TEST_MEMORY_LEAK_THRESHOLD (-400)
static size_t before_free_8bit;
static size_t before_free_32bit;
static void check_leak(size_t before_free, size_t after_free, const char *type)
{
ssize_t delta = after_free - before_free;
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
}
void setUp(void)
{
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
}
void tearDown(void)
{
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
check_leak(before_free_8bit, after_free_8bit, "8BIT");
check_leak(before_free_32bit, after_free_32bit, "32BIT");
}
void app_main(void)
{
unity_run_menu();
}

View File

@ -1,161 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdlib.h>
#include "unity.h"
#include "esp_log.h"
#include "driver/adc.h"
#include "driver/gpio.h"
#include "driver/rtc_io.h"
#include "soc/adc_periph.h"
#include "hal/adc_ll.h"
#define ADC_GET_IO_NUM(unit, channel) (adc_channel_io_map[unit][channel])
/**
* We use weak pulldown, `ADC_TEST_LOW_THRESH` may vary.
* If connect to GND, `ADC_TEST_LOW_THRESH` will usually within 10
*/
#if CONFIG_IDF_TARGET_ESP32
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 10
#define ADC_TEST_HIGH_VAL 4095
#define ADC_TEST_HIGH_THRESH 10
#elif CONFIG_IDF_TARGET_ESP32S2
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 35
#define ADC_TEST_HIGH_VAL 8191
#define ADC_TEST_HIGH_THRESH 10
#elif CONFIG_IDF_TARGET_ESP32C3
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 60 //This is due to ADC2 accuracy is not as good as ADC1, and also we use weak pulldown
#define ADC_TEST_HIGH_VAL 4095
#define ADC_TEST_HIGH_THRESH 10
#elif CONFIG_IDF_TARGET_ESP32S3
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 15
#define ADC_TEST_HIGH_VAL 4095
#define ADC_TEST_HIGH_THRESH 0
#elif CONFIG_IDF_TARGET_ESP32C2
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 15
#define ADC_TEST_HIGH_VAL 3400
#define ADC_TEST_HIGH_THRESH 200
#elif CONFIG_IDF_TARGET_ESP32C6
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 15
#define ADC_TEST_HIGH_VAL 3350
#define ADC_TEST_HIGH_THRESH 200
#elif CONFIG_IDF_TARGET_ESP32H2
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 17
#define ADC_TEST_HIGH_VAL 3390
#define ADC_TEST_HIGH_THRESH 200
#elif CONFIG_IDF_TARGET_ESP32P4
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 10
#define ADC_TEST_HIGH_VAL 3360
#define ADC_TEST_HIGH_THRESH 200
#elif CONFIG_IDF_TARGET_ESP32C5
#define ADC_TEST_LOW_VAL 0
#define ADC_TEST_LOW_THRESH 17
#define ADC_TEST_HIGH_VAL 3375
#define ADC_TEST_HIGH_THRESH 200
#elif CONFIG_IDF_TARGET_ESP32C61
#define ADC_TEST_LOW_VAL 2140
#define ADC_TEST_LOW_THRESH 200
#define ADC_TEST_HIGH_VAL 4095
#define ADC_TEST_HIGH_THRESH 200
#endif
//ADC Channels
#if CONFIG_IDF_TARGET_ESP32
#define ADC1_TEST_CHAN0 ADC1_CHANNEL_4
#define ADC2_TEST_CHAN0 ADC2_CHANNEL_0
#elif (SOC_ADC_PERIPH_NUM >= 2)
#define ADC1_TEST_CHAN0 ADC1_CHANNEL_2
#define ADC2_TEST_CHAN0 ADC2_CHANNEL_0
#else
#define ADC1_TEST_CHAN0 ADC1_CHANNEL_2
#endif
//ESP32C3 ADC2 oneshot mode is not supported anymore
#define ADC_TEST_ADC2 ((SOC_ADC_PERIPH_NUM >= 2) && !CONFIG_IDF_TARGET_ESP32C3)
const __attribute__((unused)) static char *TAG = "TEST_ADC_LEGACY";
void test_adc_set_io_level(adc_unit_t unit, adc_channel_t channel, bool level)
{
TEST_ASSERT(channel < SOC_ADC_CHANNEL_NUM(unit) && "invalid channel");
uint32_t io_num = ADC_GET_IO_NUM(unit, channel);
TEST_ESP_OK(gpio_set_pull_mode(io_num, (level ? GPIO_PULLUP_ONLY : GPIO_PULLDOWN_ONLY)));
#if SOC_RTCIO_INPUT_OUTPUT_SUPPORTED
if (rtc_gpio_is_valid_gpio(io_num)) {
if (level) {
TEST_ESP_OK(rtc_gpio_pullup_en(io_num));
TEST_ESP_OK(rtc_gpio_pulldown_dis(io_num));
} else {
TEST_ESP_OK(rtc_gpio_pullup_dis(io_num));
TEST_ESP_OK(rtc_gpio_pulldown_en(io_num));
}
}
#endif
}
TEST_CASE("Legacy ADC oneshot high/low test", "[legacy_adc_oneshot]")
{
int adc_raw = 0;
//ADC1 config
TEST_ESP_OK(adc1_config_width(ADC_WIDTH_BIT_DEFAULT));
TEST_ESP_OK(adc1_config_channel_atten(ADC1_TEST_CHAN0, ADC_ATTEN_DB_12));
#if ADC_TEST_ADC2
//ADC2 config
TEST_ESP_OK(adc2_config_channel_atten(ADC2_TEST_CHAN0, ADC_ATTEN_DB_12));
#endif
test_adc_set_io_level(ADC_UNIT_1, (adc1_channel_t)ADC1_TEST_CHAN0, 0);
adc_raw = adc1_get_raw(ADC1_TEST_CHAN0);
ESP_LOGI(TAG, "ADC%d Channel %d raw: %d", ADC_UNIT_1 + 1, ADC1_TEST_CHAN0, adc_raw);
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw);
test_adc_set_io_level(ADC_UNIT_1, (adc1_channel_t)ADC1_TEST_CHAN0, 1);
adc_raw = adc1_get_raw(ADC1_TEST_CHAN0);
ESP_LOGI(TAG, "ADC%d Channel %d raw: %d", ADC_UNIT_1 + 1, ADC1_TEST_CHAN0, adc_raw);
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw);
#if ADC_TEST_ADC2
test_adc_set_io_level(ADC_UNIT_2, (adc2_channel_t)ADC2_TEST_CHAN0, 0);
TEST_ESP_OK(adc2_get_raw(ADC2_TEST_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc_raw));
ESP_LOGI(TAG, "ADC%d Channel %d raw: %d", ADC_UNIT_2 + 1, ADC2_TEST_CHAN0, adc_raw);
TEST_ASSERT_INT_WITHIN(ADC_TEST_LOW_THRESH, ADC_TEST_LOW_VAL, adc_raw);
test_adc_set_io_level(ADC_UNIT_2, (adc2_channel_t)ADC2_TEST_CHAN0, 1);
TEST_ESP_OK(adc2_get_raw(ADC2_TEST_CHAN0, ADC_WIDTH_BIT_DEFAULT, &adc_raw));
ESP_LOGI(TAG, "ADC%d Channel %d raw: %d", ADC_UNIT_2 + 1, ADC2_TEST_CHAN0, adc_raw);
TEST_ASSERT_INT_WITHIN(ADC_TEST_HIGH_THRESH, ADC_TEST_HIGH_VAL, adc_raw);
#endif
}

View File

@ -1,36 +0,0 @@
# SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
from pytest_embedded_idf.utils import idf_parametrize
@pytest.mark.adc
@pytest.mark.parametrize(
'config',
[
'release',
],
indirect=True,
)
@idf_parametrize(
'target',
['esp32', 'esp32s2', 'esp32s3', 'esp32c3', 'esp32c6', 'esp32h2', 'esp32c5', 'esp32p4'],
indirect=['target'],
)
def test_legacy_adc(dut: Dut) -> None:
dut.run_all_single_board_cases()
@pytest.mark.adc
@pytest.mark.xtal_26mhz
@pytest.mark.parametrize(
'config, baud',
[
('esp32c2_xtal26m_release', '74880'),
],
indirect=True,
)
@idf_parametrize('target', ['esp32c2'], indirect=['target'])
def test_legacy_adc_esp32c2_xtal_26mhz(dut: Dut) -> None:
dut.run_all_single_board_cases()

View File

@ -1,8 +0,0 @@
CONFIG_IDF_TARGET="esp32c2"
CONFIG_XTAL_FREQ_26=y
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -1,5 +0,0 @@
CONFIG_PM_ENABLE=y
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y

View File

@ -1,3 +0,0 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_TASK_WDT_EN=n
CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y

View File

@ -4,7 +4,7 @@ if(${target} STREQUAL "linux")
return() # This component is not supported by the POSIX/Linux simulator
endif()
set(includes "include" "interface" "${target}/include" "deprecated/include")
set(includes "include" "interface" "${target}/include")
set(srcs)
@ -14,7 +14,6 @@ if(CONFIG_SOC_ADC_SUPPORTED)
"adc_common.c"
"adc_cali.c"
"adc_cali_curve_fitting.c"
"deprecated/esp_adc_cal_common_legacy.c"
)
if(CONFIG_SOC_ADC_DMA_SUPPORTED)
@ -46,11 +45,6 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/curve_fitting_coefficients.c")
list(APPEND srcs "${target}/curve_fitting_coefficients.c")
endif()
# legacy calibration driver
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deprecated/${target}/esp_adc_cal_legacy.c")
list(APPEND srcs "deprecated/${target}/esp_adc_cal_legacy.c")
endif()
set(extra_requires)
idf_build_get_property(target IDF_TARGET)
if(${target} STREQUAL "esp32")
@ -60,8 +54,6 @@ if(${target} STREQUAL "esp32s2")
list(APPEND extra_requires esp_driver_spi)
endif()
list(APPEND extra_requires driver) # esp_adc depends on "driver/adc_types_legacy.h"
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${includes}
PRIV_REQUIRES esp_driver_gpio efuse esp_pm esp_ringbuf esp_mm ${extra_requires}

View File

@ -1,352 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "esp_types.h"
#include "esp_err.h"
#include "esp_check.h"
#include "assert.h"
#include "hal/efuse_ll.h"
#include "hal/adc_types.h"
#include "driver/adc_types_legacy.h"
#include "esp_adc_cal_types_legacy.h"
/* ----------------------------- Configuration ------------------------------ */
#ifdef CONFIG_ADC_CAL_EFUSE_TP_ENABLE
#define EFUSE_TP_ENABLED 1
#else
#define EFUSE_TP_ENABLED 0
#endif
#ifdef CONFIG_ADC_CAL_EFUSE_VREF_ENABLE
#define EFUSE_VREF_ENABLED 1
#else
#define EFUSE_VREF_ENABLED 0
#endif
#ifdef CONFIG_ADC_CAL_LUT_ENABLE
#define LUT_ENABLED 1
#else
#define LUT_ENABLED 0
#endif
/* ESP32s with both Two Point Values and Vref burned into eFuse are required to
* also also burn the EFUSE_BLK3_PART_RESERVE flag. A limited set of ESP32s
* (not available through regular sales channel) DO NOT have the
* EFUSE_BLK3_PART_RESERVE burned. Moreover, this set of ESP32s represents Vref
* in Two's Complement format. If this is the case, modify the preprocessor
* definitions below as follows...
* #define CHECK_BLK3_FLAG 0 //Do not check BLK3 flag as it is not burned
* #define VREF_FORMAT 1 //eFuse Vref is in Two's Complement format
*/
#define CHECK_BLK3_FLAG 1
#define VREF_FORMAT 0
/* ------------------------------ eFuse Access ----------------------------- */
#define VREF_MASK 0x1F
#define VREF_STEP_SIZE 7
#define VREF_OFFSET 1100
#define TP_LOW1_OFFSET 278
#define TP_LOW2_OFFSET 421
#define TP_LOW_MASK 0x7F
#define TP_LOW_VOLTAGE 150
#define TP_HIGH1_OFFSET 3265
#define TP_HIGH2_OFFSET 3406
#define TP_HIGH_MASK 0x1FF
#define TP_HIGH_VOLTAGE 850
#define TP_STEP_SIZE 4
/* ----------------------- Raw to Voltage Constants ------------------------- */
#define LIN_COEFF_A_SCALE 65536
#define LIN_COEFF_A_ROUND (LIN_COEFF_A_SCALE/2)
#define LUT_VREF_LOW 1000
#define LUT_VREF_HIGH 1200
#define LUT_ADC_STEP_SIZE 64
#define LUT_POINTS 20
#define LUT_LOW_THRESH 2880
#define LUT_HIGH_THRESH (LUT_LOW_THRESH + LUT_ADC_STEP_SIZE)
#define ADC_12_BIT_RES 4096
/* ------------------------ Characterization Constants ---------------------- */
static const uint32_t adc1_tp_atten_scale[4] = {65504, 86975, 120389, 224310};
static const uint32_t adc2_tp_atten_scale[4] = {65467, 86861, 120416, 224708};
static const uint32_t adc1_tp_atten_offset[4] = {0, 1, 27, 54};
static const uint32_t adc2_tp_atten_offset[4] = {0, 9, 26, 66};
static const uint32_t adc1_vref_atten_scale[4] = {57431, 76236, 105481, 196602};
static const uint32_t adc2_vref_atten_scale[4] = {57236, 76175, 105678, 197170};
static const uint32_t adc1_vref_atten_offset[4] = {75, 78, 107, 142};
static const uint32_t adc2_vref_atten_offset[4] = {63, 66, 89, 128};
//20 Point lookup tables, covering ADC readings from 2880 to 4096, step size of 64
static const uint32_t lut_adc1_low[LUT_POINTS] = {2240, 2297, 2352, 2405, 2457, 2512, 2564, 2616, 2664, 2709,
2754, 2795, 2832, 2868, 2903, 2937, 2969, 3000, 3030, 3060
};
static const uint32_t lut_adc1_high[LUT_POINTS] = {2667, 2706, 2745, 2780, 2813, 2844, 2873, 2901, 2928, 2956,
2982, 3006, 3032, 3059, 3084, 3110, 3135, 3160, 3184, 3209
};
static const uint32_t lut_adc2_low[LUT_POINTS] = {2238, 2293, 2347, 2399, 2451, 2507, 2561, 2613, 2662, 2710,
2754, 2792, 2831, 2869, 2904, 2937, 2968, 2999, 3029, 3059
};
static const uint32_t lut_adc2_high[LUT_POINTS] = {2657, 2698, 2738, 2774, 2807, 2838, 2867, 2894, 2921, 2946,
2971, 2996, 3020, 3043, 3067, 3092, 3116, 3139, 3162, 3185
};
/* ----------------------- EFuse Access Functions --------------------------- */
static bool check_efuse_vref(void)
{
//Check if Vref is burned in eFuse
return (efuse_ll_get_adc_vref() != 0) ? true : false;
}
static bool check_efuse_tp(void)
{
//Check if Two Point values are burned in eFuse
if (CHECK_BLK3_FLAG && (efuse_ll_get_blk3_part_reserve() == 0)) {
return false;
}
//All TP cal values must be non zero
return efuse_ll_get_adc1_tp_low() &&
efuse_ll_get_adc2_tp_low() &&
efuse_ll_get_adc1_tp_high() &&
efuse_ll_get_adc2_tp_high();
}
static inline int decode_bits(uint32_t bits, uint32_t mask, bool is_twos_compl)
{
int ret;
if (bits & (~(mask >> 1) & mask)) { //Check sign bit (MSB of mask)
//Negative
if (is_twos_compl) {
ret = -(((~bits) + 1) & (mask >> 1)); //2's complement
} else {
ret = -(bits & (mask >> 1)); //Sign-magnitude
}
} else {
//Positive
ret = bits & (mask >> 1);
}
return ret;
}
static uint32_t read_efuse_vref(void)
{
//eFuse stores deviation from ideal reference voltage
uint32_t ret = VREF_OFFSET; //Ideal vref
uint32_t bits = efuse_ll_get_adc_vref();
ret += decode_bits(bits, VREF_MASK, VREF_FORMAT) * VREF_STEP_SIZE;
return ret; //ADC Vref in mV
}
static uint32_t read_efuse_tp_low(adc_unit_t adc_num)
{
//ADC reading at 150mV stored in two's complement format
uint32_t ret;
uint32_t bits;
if (adc_num == ADC_UNIT_1) {
ret = TP_LOW1_OFFSET;
bits = efuse_ll_get_adc1_tp_low();
} else {
ret = TP_LOW2_OFFSET;
bits = efuse_ll_get_adc2_tp_low();
}
ret += decode_bits(bits, TP_LOW_MASK, true) * TP_STEP_SIZE;
return ret; //Reading of ADC at 150mV
}
static uint32_t read_efuse_tp_high(adc_unit_t adc_num)
{
//ADC reading at 850mV stored in two's complement format
uint32_t ret;
uint32_t bits;
if (adc_num == ADC_UNIT_1) {
ret = TP_HIGH1_OFFSET;
bits = efuse_ll_get_adc1_tp_high();
} else {
ret = TP_HIGH2_OFFSET;
bits = efuse_ll_get_adc2_tp_high();
}
ret += decode_bits(bits, TP_HIGH_MASK, true) * TP_STEP_SIZE;
return ret; //Reading of ADC at 850mV
}
/* ----------------------- Characterization Functions ----------------------- */
static void characterize_using_two_point(adc_unit_t adc_num,
adc_atten_t atten,
uint32_t high,
uint32_t low,
uint32_t *coeff_a,
uint32_t *coeff_b)
{
const uint32_t *atten_scales;
const uint32_t *atten_offsets;
if (adc_num == ADC_UNIT_1) { //Using ADC 1
atten_scales = adc1_tp_atten_scale;
atten_offsets = adc1_tp_atten_offset;
} else { //Using ADC 2
atten_scales = adc2_tp_atten_scale;
atten_offsets = adc2_tp_atten_offset;
}
//Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
uint32_t delta_x = high - low;
uint32_t delta_v = TP_HIGH_VOLTAGE - TP_LOW_VOLTAGE;
//Where coeff_a = (delta_v/delta_x) * atten_scale
*coeff_a = (delta_v * atten_scales[atten] + (delta_x / 2)) / delta_x; //+(delta_x/2) for rounding
//Where coeff_b = high_v - ((delta_v/delta_x) * high_x) + atten_offset
*coeff_b = TP_HIGH_VOLTAGE - ((delta_v * high + (delta_x / 2)) / delta_x) + atten_offsets[atten];
}
static void characterize_using_vref(adc_unit_t adc_num,
adc_atten_t atten,
uint32_t vref,
uint32_t *coeff_a,
uint32_t *coeff_b)
{
const uint32_t *atten_scales;
const uint32_t *atten_offsets;
if (adc_num == ADC_UNIT_1) { //Using ADC 1
atten_scales = adc1_vref_atten_scale;
atten_offsets = adc1_vref_atten_offset;
} else { //Using ADC 2
atten_scales = adc2_vref_atten_scale;
atten_offsets = adc2_vref_atten_offset;
}
//Characterize ADC-Voltage curve as y = (coeff_a * x) + coeff_b
//Where coeff_a = (vref/4096) * atten_scale
*coeff_a = (vref * atten_scales[atten]) / (ADC_12_BIT_RES);
*coeff_b = atten_offsets[atten];
}
/* ------------------------ Conversion Functions --------------------------- */
static uint32_t calculate_voltage_linear(uint32_t adc_reading, uint32_t coeff_a, uint32_t coeff_b)
{
//Where voltage = coeff_a * adc_reading + coeff_b
return (((coeff_a * adc_reading) + LIN_COEFF_A_ROUND) / LIN_COEFF_A_SCALE) + coeff_b;
}
//Only call when ADC reading is above threshold
static uint32_t calculate_voltage_lut(uint32_t adc, uint32_t vref, const uint32_t *low_vref_curve, const uint32_t *high_vref_curve)
{
//Get index of lower bound points of LUT
uint32_t i = (adc - LUT_LOW_THRESH) / LUT_ADC_STEP_SIZE;
//Let the X Axis be Vref, Y axis be ADC reading, and Z be voltage
int x2dist = LUT_VREF_HIGH - vref; //(x2 - x)
int x1dist = vref - LUT_VREF_LOW; //(x - x1)
int y2dist = ((i + 1) * LUT_ADC_STEP_SIZE) + LUT_LOW_THRESH - adc; //(y2 - y)
int y1dist = adc - ((i * LUT_ADC_STEP_SIZE) + LUT_LOW_THRESH); //(y - y1)
//For points for bilinear interpolation
int q11 = low_vref_curve[i]; //Lower bound point of low_vref_curve
int q12 = low_vref_curve[i + 1]; //Upper bound point of low_vref_curve
int q21 = high_vref_curve[i]; //Lower bound point of high_vref_curve
int q22 = high_vref_curve[i + 1]; //Upper bound point of high_vref_curve
//Bilinear interpolation
//Where z = 1/((x2-x1)*(y2-y1)) * ( (q11*x2dist*y2dist) + (q21*x1dist*y2dist) + (q12*x2dist*y1dist) + (q22*x1dist*y1dist) )
int voltage = (q11 * x2dist * y2dist) + (q21 * x1dist * y2dist) + (q12 * x2dist * y1dist) + (q22 * x1dist * y1dist);
voltage += ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE) / 2; //Integer division rounding
voltage /= ((LUT_VREF_HIGH - LUT_VREF_LOW) * LUT_ADC_STEP_SIZE); //Divide by ((x2-x1)*(y2-y1))
return (uint32_t)voltage;
}
static inline uint32_t interpolate_two_points(uint32_t y1, uint32_t y2, uint32_t x_step, uint32_t x)
{
//Interpolate between two points (x1,y1) (x2,y2) between 'lower' and 'upper' separated by 'step'
return ((y1 * x_step) + (y2 * x) - (y1 * x) + (x_step / 2)) / x_step;
}
/* ------------------------- Public API ------------------------------------- */
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
{
if (source == ESP_ADC_CAL_VAL_EFUSE_TP) {
return (check_efuse_tp()) ? ESP_OK : ESP_ERR_NOT_SUPPORTED;
} else if (source == ESP_ADC_CAL_VAL_EFUSE_VREF) {
return (check_efuse_vref()) ? ESP_OK : ESP_ERR_NOT_SUPPORTED;
} else {
return ESP_ERR_INVALID_ARG;
}
}
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars)
{
//Check parameters
assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2));
assert(chars != NULL);
assert(bit_width < ADC_WIDTH_MAX);
//Check eFuse if enabled to do so
bool efuse_tp_present = check_efuse_tp();
bool efuse_vref_present = check_efuse_vref();
esp_adc_cal_value_t ret;
if (efuse_tp_present && EFUSE_TP_ENABLED) {
//Characterize based on Two Point values
uint32_t high = read_efuse_tp_high(adc_num);
uint32_t low = read_efuse_tp_low(adc_num);
characterize_using_two_point(adc_num, atten, high, low, &chars->coeff_a, &chars->coeff_b);
ret = ESP_ADC_CAL_VAL_EFUSE_TP;
} else if (efuse_vref_present && EFUSE_VREF_ENABLED) {
//Characterize based on eFuse Vref
uint32_t vref = read_efuse_vref();
characterize_using_vref(adc_num, atten, vref, &chars->coeff_a, &chars->coeff_b);
ret = ESP_ADC_CAL_VAL_EFUSE_VREF;
} else {
//Characterized based on default Vref
characterize_using_vref(adc_num, atten, default_vref, &chars->coeff_a, &chars->coeff_b);
ret = ESP_ADC_CAL_VAL_DEFAULT_VREF;
}
//Initialized remaining fields
chars->adc_num = adc_num;
chars->atten = atten;
chars->bit_width = bit_width;
chars->vref = (EFUSE_VREF_ENABLED && efuse_vref_present) ? read_efuse_vref() : default_vref;
//Initialize fields for lookup table if necessary
if (LUT_ENABLED && atten == ADC_ATTEN_DB_12) {
chars->low_curve = (adc_num == ADC_UNIT_1) ? lut_adc1_low : lut_adc2_low;
chars->high_curve = (adc_num == ADC_UNIT_1) ? lut_adc1_high : lut_adc2_high;
} else {
chars->low_curve = NULL;
chars->high_curve = NULL;
}
return ret;
}
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
assert(chars != NULL);
//Scale adc_rading if not 12 bits wide
adc_reading = (adc_reading << (ADC_WIDTH_BIT_12 - chars->bit_width));
if (adc_reading > ADC_12_BIT_RES - 1) {
adc_reading = ADC_12_BIT_RES - 1; //Set to 12bit res max
}
if (LUT_ENABLED && (chars->atten == ADC_ATTEN_DB_12) && (adc_reading >= LUT_LOW_THRESH)) { //Check if in non-linear region
//Use lookup table to get voltage in non linear portion of ADC_ATTEN_DB_12
uint32_t lut_voltage = calculate_voltage_lut(adc_reading, chars->vref, chars->low_curve, chars->high_curve);
if (adc_reading <= LUT_HIGH_THRESH) { //If ADC is transitioning from linear region to non-linear region
//Linearly interpolate between linear voltage and lut voltage
uint32_t linear_voltage = calculate_voltage_linear(adc_reading, chars->coeff_a, chars->coeff_b);
return interpolate_two_points(linear_voltage, lut_voltage, LUT_ADC_STEP_SIZE, (adc_reading - LUT_LOW_THRESH));
} else {
return lut_voltage;
}
} else {
return calculate_voltage_linear(adc_reading, chars->coeff_a, chars->coeff_b);
}
}

View File

@ -1,175 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "esp_types.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_efuse_rtc_calib.h"
#include "hal/adc_ll.h"
#include "hal/adc_types.h"
#include "driver/adc_types_legacy.h"
#include "esp_adc_cal_types_legacy.h"
#include "../esp_adc_cal_internal_legacy.h"
const static char LOG_TAG[] = "ADC_CALI";
/* ------------------------ Characterization Constants ---------------------- */
// coeff_a is actually a float number
// it is scaled to put them into uint32_t so that the headers do not have to be changed
static const int coeff_a_scaling = 65536;
/**
* @note Error Calculation
* Coefficients for calculating the reading voltage error.
* Four sets of coefficients for atten0 ~ atten3 respectively.
*
* For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient.
*
* @note {0,0} stands for unused item
* @note In case of the overflow, these coefficients are recorded as Absolute Value
* @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
* @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered.
* @note ADC1 and ADC2 use same coefficients
*/
const static uint64_t adc_error_coef_atten[4][5][2] = {
{{225966470500043, 1e15}, {7265418501948, 1e16}, {109410402681, 1e16}, {0, 0}, {0, 0}}, //atten0
{{4229623392600516, 1e16}, {731527490903, 1e16}, {88166562521, 1e16}, {0, 0}, {0, 0}}, //atten1
{{1017859239236435, 1e15}, {97159265299153, 1e16}, {149794028038, 1e16}, {0, 0}, {0, 0}}, //atten2
{{14912262772850453, 1e16}, {228549975564099, 1e16}, {356391935717, 1e16}, {179964582, 1e16}, {42046, 1e16}} //atten3
};
/**
* Term sign
* @note ADC1 and ADC2 use same coefficients
*/
const static int32_t adc_error_sign[4][5] = {
{-1, -1, 1, 0, 0}, //atten0
{ 1, -1, 1, 0, 0}, //atten1
{-1, -1, 1, 0, 0}, //atten2
{-1, -1, 1, -1, 1} //atten3
};
/* -------------------- Characterization Helper Data Types ------------------ */
typedef struct {
uint32_t voltage;
uint32_t digi;
} adc_calib_data_ver1;
typedef struct {
char version_num;
adc_unit_t adc_num;
adc_atten_t atten_level;
union {
adc_calib_data_ver1 ver1;
} efuse_data;
} adc_calib_parsed_info_t;
static esp_err_t prepare_calib_data_for(int version_num, adc_unit_t adc_num, adc_atten_t atten, adc_calib_parsed_info_t *parsed_data_storage)
{
assert(version_num == 1);
esp_err_t ret;
parsed_data_storage->version_num = version_num;
parsed_data_storage->adc_num = adc_num;
parsed_data_storage->atten_level = atten;
uint32_t voltage, digi;
/**
* V1 we don't have calibration data for ADC2, using the efuse data of ADC1.
* Here passing the `adc_num` is just for compatibility
*/
ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, adc_num, atten, &digi, &voltage);
if (ret != ESP_OK) {
return ret;
}
parsed_data_storage->efuse_data.ver1.voltage = voltage;
parsed_data_storage->efuse_data.ver1.digi = digi;
return ret;
}
/* ----------------------- Characterization Functions ----------------------- */
/*
* Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
* with the previously done measurement when the chip was manufactured.
*/
static void calculate_characterization_coefficients(const adc_calib_parsed_info_t *parsed_data, esp_adc_cal_characteristics_t *chars)
{
ESP_LOGD(LOG_TAG, "Calib V1, Cal Voltage = %"PRId32", Digi out = %"PRId32, parsed_data->efuse_data.ver1.voltage, parsed_data->efuse_data.ver1.digi);
chars->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver1.voltage / parsed_data->efuse_data.ver1.digi;
chars->coeff_b = 0;
}
/* ------------------------- Public API ------------------------------------- */
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
{
if (source != ESP_ADC_CAL_VAL_EFUSE_TP) {
return ESP_ERR_NOT_SUPPORTED;
}
uint8_t adc_encoding_version = esp_efuse_rtc_calib_get_ver();
if (adc_encoding_version != 1) {
// current version only accepts encoding ver 1.
return ESP_ERR_INVALID_VERSION;
}
return ESP_OK;
}
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars)
{
esp_err_t ret;
adc_calib_parsed_info_t efuse_parsed_data = {0};
// Check parameters
ESP_RETURN_ON_FALSE(adc_num == ADC_UNIT_1 || adc_num == ADC_UNIT_2, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid unit num");
ESP_RETURN_ON_FALSE(chars != NULL, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid characteristic");
ESP_RETURN_ON_FALSE(bit_width == ADC_WIDTH_BIT_12, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid bit_width");
ESP_RETURN_ON_FALSE(atten < SOC_ADC_ATTEN_NUM, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid attenuation");
int version_num = esp_efuse_rtc_calib_get_ver();
ESP_RETURN_ON_FALSE(version_num == 1, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "No calibration efuse burnt");
memset(chars, 0, sizeof(esp_adc_cal_characteristics_t));
// make sure adc is calibrated.
ret = prepare_calib_data_for(version_num, adc_num, atten, &efuse_parsed_data);
if (ret != ESP_OK) {
abort();
}
calculate_characterization_coefficients(&efuse_parsed_data, chars);
ESP_LOGD(LOG_TAG, "adc%d (atten leven %d) calibration done: A:%"PRId32" B:%"PRId32, adc_num, atten, chars->coeff_a, chars->coeff_b);
// Initialize remaining fields
chars->adc_num = adc_num;
chars->atten = atten;
chars->bit_width = bit_width;
// in esp32c3 we only use the two point method to calibrate the adc.
return ESP_ADC_CAL_VAL_EFUSE_TP;
}
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
assert(chars != NULL);
int32_t error = 0;
uint64_t v_cali_1 = (uint64_t)adc_reading * chars->coeff_a / coeff_a_scaling;
esp_adc_error_calc_param_t param = {
.v_cali_input = v_cali_1,
.term_num = (chars->atten == 3) ? 5 : 3,
.coeff = &adc_error_coef_atten,
.sign = &adc_error_sign,
};
error = esp_adc_cal_get_reading_error(&param, chars->atten);
return (int32_t)v_cali_1 - error;
}

View File

@ -1,201 +0,0 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include "esp_types.h"
#include "soc/efuse_periph.h"
#include "esp_err.h"
#include "esp_check.h"
#include "assert.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_efuse_rtc_table.h"
#include "hal/adc_hal.h"
#include "hal/adc_types.h"
#include "driver/adc_types_legacy.h"
#include "esp_adc_cal_types_legacy.h"
const static char LOG_TAG[] = "adc_calib";
/* ------------------------ Characterization Constants ---------------------- */
// coeff_a and coeff_b are actually floats
// they are scaled to put them into uint32_t so that the headers do not have to be changed
static const int coeff_a_scaling = 65536;
static const int coeff_b_scaling = 1024;
/* -------------------- Characterization Helper Data Types ------------------ */
typedef struct {
int adc_calib_high;
int adc_calib_low;
} adc_calib_data_ver1;
typedef struct {
int adc_calib_high; // the reading of adc ...
int adc_calib_high_voltage; // ... at this voltage (mV)
} adc_calib_data_ver2;
typedef struct {
char version_num;
adc_unit_t adc_num;
adc_atten_t atten_level;
union {
adc_calib_data_ver1 ver1;
adc_calib_data_ver2 ver2;
} efuse_data;
} adc_calib_parsed_info;
static bool prepare_calib_data_for(adc_unit_t adc_num, adc_atten_t atten, adc_calib_parsed_info *parsed_data_storage)
{
int version_num = esp_efuse_rtc_table_read_calib_version();
int tag;
parsed_data_storage->version_num = version_num;
parsed_data_storage->adc_num = adc_num;
parsed_data_storage->atten_level = atten;
switch (version_num) {
case 1:
// note: use the adc_num as in hal, which start from 0.
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VLOW);
parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VHIGH);
parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
break;
case 2:
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V2_PARAM_VHIGH);
parsed_data_storage->efuse_data.ver2.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, false);
switch (parsed_data_storage->atten_level) {
case ADC_ATTEN_DB_0:
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 600;
break;
case ADC_ATTEN_DB_2_5:
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 800;
break;
case ADC_ATTEN_DB_6:
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 1000;
break;
case ADC_ATTEN_DB_12:
parsed_data_storage->efuse_data.ver2.adc_calib_high_voltage = 2000;
break;
default:
break;
}
break;
default:
// fall back to case 1 with zeros as params.
parsed_data_storage->version_num = 1;
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VLOW);
parsed_data_storage->efuse_data.ver1.adc_calib_high = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true);
tag = esp_efuse_rtc_table_get_tag(version_num, adc_num, atten, RTCCALIB_V1_PARAM_VHIGH);
parsed_data_storage->efuse_data.ver1.adc_calib_low = esp_efuse_rtc_table_get_parsed_efuse_value(tag, true);
break;
}
return true;
}
/* ----------------------- Characterization Functions ----------------------- */
/**
* (Used in V1 of calibration scheme)
* The Two Point calibration measures the reading at two specific input voltages, and calculates the (assumed linear) relation
* between input voltage and ADC response. (Response = A * Vinput + B)
* A and B are scaled ints.
* @param high The ADC response at the higher voltage of the corresponding attenuation (600mV, 800mV, 1000mV, 2000mV).
* @param low The ADC response at the lower voltage of the corresponding attenuation (all 250mV).
*
*/
static void characterize_using_two_point(adc_unit_t adc_num,
adc_atten_t atten,
uint32_t high,
uint32_t low,
uint32_t *coeff_a,
uint32_t *coeff_b)
{
// once we have recovered the reference high(Dhigh) and low(Dlow) readings, we can calculate a and b from
// the measured high and low readings
static const uint32_t v_high[] = {600, 800, 1000, 2000};
static const uint32_t v_low = 250;
*coeff_a = coeff_a_scaling * (v_high[atten] - v_low) / (high - low);
*coeff_b = coeff_b_scaling * (v_low * high - v_high[atten] * low) / (high - low);
}
/*
* Estimate the (assumed) linear relationship btwn the measured raw value and the voltage
* with the previously done measurement when the chip was manufactured.
* */
static bool calculate_characterization_coefficients(const adc_calib_parsed_info *parsed_data, esp_adc_cal_characteristics_t *chars)
{
switch (parsed_data->version_num) {
case 1:
ESP_LOGD(LOG_TAG, "Calib V1, low%dmV, high%dmV", parsed_data->efuse_data.ver1.adc_calib_low, parsed_data->efuse_data.ver1.adc_calib_high);
characterize_using_two_point(parsed_data->adc_num, parsed_data->atten_level,
parsed_data->efuse_data.ver1.adc_calib_high, parsed_data->efuse_data.ver1.adc_calib_low,
&(chars->coeff_a), &(chars->coeff_b));
break;
case 2:
ESP_LOGD(LOG_TAG, "Calib V2, volt%dmV", parsed_data->efuse_data.ver2.adc_calib_high);
chars->coeff_a = coeff_a_scaling * parsed_data->efuse_data.ver2.adc_calib_high_voltage /
parsed_data->efuse_data.ver2.adc_calib_high;
chars->coeff_b = 0;
break;
default:
return false;
break;
}
return true;
}
/* ------------------------- Public API ------------------------------------- */
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
{
if (source != ESP_ADC_CAL_VAL_EFUSE_TP) {
return ESP_ERR_NOT_SUPPORTED;
}
uint8_t adc_encoding_version = esp_efuse_rtc_table_read_calib_version();
if (adc_encoding_version != 1 && adc_encoding_version != 2) {
// current version only accepts encoding ver 1 and ver 2.
return ESP_ERR_INVALID_VERSION;
}
return ESP_OK;
}
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars)
{
bool res __attribute__((unused));
adc_calib_parsed_info efuse_parsed_data = {0};
// Check parameters
assert((adc_num == ADC_UNIT_1) || (adc_num == ADC_UNIT_2));
assert(chars != NULL);
assert(bit_width == ADC_WIDTH_BIT_13);
// make sure adc is calibrated.
res = prepare_calib_data_for(adc_num, atten, &efuse_parsed_data);
assert(res);
res = calculate_characterization_coefficients(&efuse_parsed_data, chars);
assert(res);
ESP_LOGD(LOG_TAG, "adc%d (atten leven %d) calibration done: A:%" PRId32 " B:%" PRId32, adc_num, atten, chars->coeff_a, chars->coeff_b);
// Initialize remaining fields
chars->adc_num = adc_num;
chars->atten = atten;
chars->bit_width = bit_width;
// these values are not used as the corresponding calibration themes are deprecated.
chars->vref = 0;
chars->low_curve = NULL;
chars->high_curve = NULL;
// in esp32s2 we only use the two point method to calibrate the adc.
return ESP_ADC_CAL_VAL_EFUSE_TP;
}
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
assert(chars != NULL);
return adc_reading * chars->coeff_a / coeff_a_scaling + chars->coeff_b / coeff_b_scaling;
}

View File

@ -1,186 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "esp_types.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "hal/adc_types.h"
#include "esp_efuse_rtc_calib.h"
#include "hal/adc_types.h"
#include "driver/adc_types_legacy.h"
#include "esp_adc_cal_types_legacy.h"
#include "../esp_adc_cal_internal_legacy.h"
const static char LOG_TAG[] = "ADC_CALI";
/* ------------------------ Characterization Constants ---------------------- */
//coeff_a is actually a float number
//it is scaled to put them into uint32_t so that the headers do not have to be changed
static const int coeff_a_scaling = 1000000;
/**
* @note Error Calculation
* Coefficients for calculating the reading voltage error.
* Four sets of coefficients for atten0 ~ atten3 respectively.
*
* For each item, first element is the Coefficient, second element is the Multiple. (Coefficient / Multiple) is the real coefficient.
*
* @note {0,0} stands for unused item
* @note In case of the overflow, these coefficients are recorded as Absolute Value
* @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
* @note Above formula is rewritten from the original documentation, please note that the coefficients are re-ordered.
*/
const static uint64_t adc1_error_coef_atten[4][5][2] = {
{{27856531419538344, 1e16}, {50871540569528, 1e16}, {9798249589, 1e15}, {0, 0}, {0, 0}}, //ADC1 atten0
{{29831022915028695, 1e16}, {49393185868806, 1e16}, {101379430548, 1e16}, {0, 0}, {0, 0}}, //ADC1 atten1
{{23285545746296417, 1e16}, {147640181047414, 1e16}, {208385525314, 1e16}, {0, 0}, {0, 0}}, //ADC1 atten2
{{644403418269478, 1e15}, {644334888647536, 1e16}, {1297891447611, 1e16}, {70769718, 1e15}, {13515, 1e15}} //ADC1 atten3
};
const static uint64_t adc2_error_coef_atten[4][5][2] = {
{{25668651654328927, 1e16}, {1353548869615, 1e16}, {36615265189, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten0
{{23690184690298404, 1e16}, {66319894226185, 1e16}, {118964995959, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten1
{{9452499397020617, 1e16}, {200996773954387, 1e16}, {259011467956, 1e16}, {0, 0}, {0, 0}}, //ADC2 atten2
{{12247719764336924, 1e16}, {755717904943462, 1e16}, {1478791187119, 1e16}, {79672528, 1e15}, {15038, 1e15}} //ADC2 atten3
};
/**
* Term sign
*/
const static int32_t adc1_error_sign[4][5] = {
{-1, -1, 1, 0, 0}, //ADC1 atten0
{-1, -1, 1, 0, 0}, //ADC1 atten1
{-1, -1, 1, 0, 0}, //ADC1 atten2
{-1, -1, 1, -1, 1} //ADC1 atten3
};
const static int32_t adc2_error_sign[4][5] = {
{-1, 1, 1, 0, 0}, //ADC2 atten0
{-1, -1, 1, 0, 0}, //ADC2 atten1
{-1, -1, 1, 0, 0}, //ADC2 atten2
{ 1, -1, 1, -1, 1} //ADC2 atten3
};
/* -------------------- Characterization Helper Data Types ------------------ */
typedef struct {
uint32_t voltage;
uint32_t digi;
} adc_calib_data_ver1_t;
typedef struct {
char version_num;
adc_unit_t adc_num;
adc_atten_t atten_level;
union {
adc_calib_data_ver1_t ver1;
} ref_data;
} adc_calib_info_t;
//To get the reference point (Dout, Vin)
static esp_err_t get_reference_point(int version_num, adc_unit_t adc_num, adc_atten_t atten, adc_calib_info_t *calib_info)
{
assert(version_num == 1);
esp_err_t ret;
calib_info->version_num = version_num;
calib_info->adc_num = adc_num;
calib_info->atten_level = atten;
uint32_t voltage = 0;
uint32_t digi = 0;
ret = esp_efuse_rtc_calib_get_cal_voltage(version_num, adc_num, atten, &digi, &voltage);
assert(ret == ESP_OK);
calib_info->ref_data.ver1.voltage = voltage;
calib_info->ref_data.ver1.digi = digi;
return ret;
}
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t source)
{
if (source != ESP_ADC_CAL_VAL_EFUSE_TP_FIT) {
return ESP_ERR_NOT_SUPPORTED;
}
uint8_t adc_encoding_version = esp_efuse_rtc_calib_get_ver();
if (adc_encoding_version != 1) {
// current version only accepts encoding ver 1.
return ESP_ERR_INVALID_VERSION;
}
return ESP_OK;
}
/*
* Get an expected linear relationship btwn Vin and Dout
*/
static void calculate_characterization_coefficients(const adc_calib_info_t *parsed_data, esp_adc_cal_characteristics_t *chars)
{
chars->coeff_a = coeff_a_scaling * parsed_data->ref_data.ver1.voltage / parsed_data->ref_data.ver1.digi;
chars->coeff_b = 0;
ESP_LOGV(LOG_TAG, "Calib V1, Cal Voltage = %" PRId32 ", Digi out = %" PRId32 ", Coef_a = %" PRId32, parsed_data->ref_data.ver1.voltage, parsed_data->ref_data.ver1.digi, chars->coeff_a);
}
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars)
{
(void) default_vref;
// Check parameters
ESP_RETURN_ON_FALSE(adc_num == ADC_UNIT_1 || adc_num == ADC_UNIT_2, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid unit num");
ESP_RETURN_ON_FALSE(chars != NULL, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid characteristic");
ESP_RETURN_ON_FALSE(atten < SOC_ADC_ATTEN_NUM, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "Invalid attenuation");
int version_num = esp_efuse_rtc_calib_get_ver();
ESP_RETURN_ON_FALSE(version_num == 1, ESP_ADC_CAL_VAL_NOT_SUPPORTED, LOG_TAG, "No calibration efuse burnt");
memset(chars, 0, sizeof(esp_adc_cal_characteristics_t));
adc_calib_info_t calib_info = {0};
// make sure adc is calibrated.
get_reference_point(version_num, adc_num, atten, &calib_info);
calculate_characterization_coefficients(&calib_info, chars);
// Initialize remaining fields
chars->adc_num = adc_num;
chars->atten = atten;
chars->bit_width = bit_width;
return ESP_ADC_CAL_VAL_EFUSE_TP_FIT;
}
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars)
{
assert(chars != NULL);
//ADC reading won't exceed 4096. Otherwise the raw reading result is wrong, the next calculation will overflow.
assert(adc_reading < 4096);
uint32_t voltage = 0;
int32_t error = 0;
uint64_t v_cali_1 = 0;
//raw * gradient * 1000000
v_cali_1 = (uint64_t)adc_reading * chars->coeff_a;
//convert to real number
v_cali_1 = v_cali_1 / coeff_a_scaling;
ESP_LOGV(LOG_TAG, "v_cali_1 is %llu", v_cali_1);
//Curve Fitting error correction
esp_adc_error_calc_param_t param = {
.v_cali_input = v_cali_1,
.term_num = (chars->atten == 3) ? 5 : 3,
.coeff = (chars->adc_num == ADC_UNIT_1) ? &adc1_error_coef_atten :&adc2_error_coef_atten,
.sign = (chars->adc_num == ADC_UNIT_1) ? &adc1_error_sign :&adc2_error_sign,
};
error = esp_adc_cal_get_reading_error(&param, chars->atten);
voltage = (int32_t)v_cali_1 - error;
return voltage;
}

View File

@ -1,95 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <string.h>
#include "inttypes.h"
#include "sdkconfig.h"
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#include "esp_types.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_check.h"
#include "hal/adc_types.h"
#define CONFIG_ADC_SUPPRESS_DEPRECATE_WARN 1
#include "esp_adc_cal.h"
#include "esp_adc_cal_internal_legacy.h"
#include "driver/adc.h"
const __attribute__((unused)) static char *TAG = "ADC_CALI";
esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel,
const esp_adc_cal_characteristics_t *chars,
uint32_t *voltage)
{
// Check parameters
ESP_RETURN_ON_FALSE(chars != NULL, ESP_ERR_INVALID_ARG, TAG, "No characteristic input");
ESP_RETURN_ON_FALSE(voltage != NULL, ESP_ERR_INVALID_ARG, TAG, "No output buffer");
esp_err_t ret = ESP_OK;
int adc_reading;
if (chars->adc_num == ADC_UNIT_1) {
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(0), ESP_ERR_INVALID_ARG, TAG, "Invalid channel");
adc_reading = adc1_get_raw(channel);
} else {
ESP_RETURN_ON_FALSE(channel < SOC_ADC_CHANNEL_NUM(1), ESP_ERR_INVALID_ARG, TAG, "Invalid channel");
ret = adc2_get_raw(channel, chars->bit_width, &adc_reading);
}
if (ret == ESP_OK) {
*voltage = esp_adc_cal_raw_to_voltage((uint32_t)adc_reading, chars);
}
return ret;
}
#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
/*------------------------------------------------------------------------------
* Private API
*----------------------------------------------------------------------------*/
int32_t esp_adc_cal_get_reading_error(const esp_adc_error_calc_param_t *param, uint8_t atten)
{
if (param->v_cali_input == 0) {
return 0;
}
uint64_t v_cali_1 = param->v_cali_input;
uint8_t term_num = param->term_num;
int32_t error = 0;
uint64_t coeff = 0;
uint64_t variable[term_num];
uint64_t term[term_num];
memset(variable, 0, term_num * sizeof(uint64_t));
memset(term, 0, term_num * sizeof(uint64_t));
/**
* For atten0 ~ 2:
* error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2);
*
* For atten3:
* error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
*/
variable[0] = 1;
coeff = (*param->coeff)[atten][0][0];
term[0] = variable[0] * coeff / (*param->coeff)[atten][0][1];
error = (int32_t)term[0] * (*param->sign)[atten][0];
for (int i = 1; i < term_num; i++) {
variable[i] = variable[i - 1] * v_cali_1;
coeff = (*param->coeff)[atten][i][0];
term[i] = variable[i] * coeff;
ESP_LOGV(TAG, "big coef is %llu, big term%d is %llu, coef_id is %d", coeff, i, term[i], i);
term[i] = term[i] / (*param->coeff)[atten][i][1];
error += (int32_t)term[i] * (*param->sign)[atten][i];
ESP_LOGV(TAG, "term%d is %llu, error is %"PRId32, i, term[i], error);
}
return error;
}
#endif //#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3

View File

@ -1,49 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#define ESP_ADC_CAL_CURVE_FITTING_SUPPORTED 1
#define COEFF_GROUP_NUM 4
#define TERM_MAX 5
#endif
#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
/**
* Calculation parameters used for curve fitting calibration algorithm error
*
* @note For atten0 ~ 2, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2); For atten3, error = (K0 * X^0) + (K1 * X^1) + (K2 * X^2) + (K3 * X^3) + (K4 * X^4);
* Where X is the `v_cali_input`.
*/
typedef struct {
uint64_t v_cali_input; //Input to calculate the error
uint8_t term_num; //Term number of the algorithm formula
const uint64_t (*coeff)[COEFF_GROUP_NUM][TERM_MAX][2]; //Coeff of each term. See `adc_error_coef_atten` for details (and the magic number 2)
const int32_t (*sign)[COEFF_GROUP_NUM][TERM_MAX]; //Sign of each term
} esp_adc_error_calc_param_t;
/**
* Calculate the curve fitting error
*
* @param param see `esp_adc_error_calc_param_t`
* @param atten ADC attenuation
*/
int32_t esp_adc_cal_get_reading_error(const esp_adc_error_calc_param_t *param, uint8_t atten);
#endif //#if ESP_ADC_CAL_CURVE_FITTING_SUPPORTED
#ifdef __cplusplus
}
#endif

View File

@ -1,113 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "hal/adc_types.h"
#include "driver/adc_types_legacy.h"
#include "esp_adc_cal_types_legacy.h"
#if !CONFIG_ADC_SUPPRESS_DEPRECATE_WARN
#warning "legacy adc calibration driver is deprecated, please migrate to use esp_adc/adc_cali.h and esp_adc/adc_cali_scheme.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
/**
* @brief Checks if ADC calibration values are burned into eFuse
*
* This function checks if ADC reference voltage or Two Point values have been
* burned to the eFuse of the current ESP32
*
* @param value_type Type of calibration value (ESP_ADC_CAL_VAL_EFUSE_VREF or ESP_ADC_CAL_VAL_EFUSE_TP)
* @note in ESP32S2, only ESP_ADC_CAL_VAL_EFUSE_TP is supported. Some old ESP32S2s do not support this, either.
* In which case you have to calibrate it manually, possibly by performing your own two-point calibration on the chip.
*
* @return
* - ESP_OK: The calibration mode is supported in eFuse
* - ESP_ERR_NOT_SUPPORTED: Error, eFuse values are not burned
* - ESP_ERR_INVALID_ARG: Error, invalid argument (ESP_ADC_CAL_VAL_DEFAULT_VREF)
*/
esp_err_t esp_adc_cal_check_efuse(esp_adc_cal_value_t value_type);
/**
* @brief Characterize an ADC at a particular attenuation
*
* This function will characterize the ADC at a particular attenuation and generate
* the ADC-Voltage curve in the form of [y = coeff_a * x + coeff_b].
* Characterization can be based on Two Point values, eFuse Vref, or default Vref
* and the calibration values will be prioritized in that order.
*
* @note
* For ESP32, Two Point values and eFuse Vref calibration can be enabled/disabled using menuconfig.
* For ESP32s2, only Two Point values calibration and only ADC_WIDTH_BIT_13 is supported. The parameter default_vref is unused.
*
*
* @param[in] adc_num ADC to characterize (ADC_UNIT_1 or ADC_UNIT_2)
* @param[in] atten Attenuation to characterize
* @param[in] bit_width Bit width configuration of ADC
* @param[in] default_vref Default ADC reference voltage in mV (Only in ESP32, used if eFuse values is not available)
* @param[out] chars Pointer to empty structure used to store ADC characteristics
*
* @return
* - ESP_ADC_CAL_VAL_EFUSE_VREF: eFuse Vref used for characterization
* - ESP_ADC_CAL_VAL_EFUSE_TP: Two Point value used for characterization (only in Linear Mode)
* - ESP_ADC_CAL_VAL_DEFAULT_VREF: Default Vref used for characterization
*/
esp_adc_cal_value_t esp_adc_cal_characterize(adc_unit_t adc_num,
adc_atten_t atten,
adc_bits_width_t bit_width,
uint32_t default_vref,
esp_adc_cal_characteristics_t *chars);
/**
* @brief Convert an ADC reading to voltage in mV
*
* This function converts an ADC reading to a voltage in mV based on the ADC's
* characteristics.
*
* @note Characteristics structure must be initialized before this function
* is called (call esp_adc_cal_characterize())
*
* @param[in] adc_reading ADC reading
* @param[in] chars Pointer to initialized structure containing ADC characteristics
*
* @return Voltage in mV
*/
uint32_t esp_adc_cal_raw_to_voltage(uint32_t adc_reading, const esp_adc_cal_characteristics_t *chars);
/**
* @brief Reads an ADC and converts the reading to a voltage in mV
*
* This function reads an ADC then converts the raw reading to a voltage in mV
* based on the characteristics provided. The ADC that is read is also
* determined by the characteristics.
*
* @note The Characteristics structure must be initialized before this
* function is called (call esp_adc_cal_characterize())
*
* @param[in] channel ADC Channel to read
* @param[in] chars Pointer to initialized ADC characteristics structure
* @param[out] voltage Pointer to store converted voltage
*
* @return
* - ESP_OK: ADC read and converted to mV
* - ESP_ERR_INVALID_ARG: Error due to invalid arguments
* - ESP_ERR_INVALID_STATE: Reading result is invalid. Try to read again.
*/
esp_err_t esp_adc_cal_get_voltage(adc_channel_t channel, const esp_adc_cal_characteristics_t *chars, uint32_t *voltage);
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#ifdef __cplusplus
}
#endif

View File

@ -1,49 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "sdkconfig.h"
#include "driver/adc_types_legacy.h"
#ifdef __cplusplus
extern "C" {
#endif
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
/**
* @brief Type of calibration value used in characterization
*/
typedef enum {
ESP_ADC_CAL_VAL_EFUSE_VREF = 0, /**< Characterization based on reference voltage stored in eFuse*/
ESP_ADC_CAL_VAL_EFUSE_TP = 1, /**< Characterization based on Two Point values stored in eFuse*/
ESP_ADC_CAL_VAL_DEFAULT_VREF = 2, /**< Characterization based on default reference voltage*/
ESP_ADC_CAL_VAL_EFUSE_TP_FIT = 3, /**< Characterization based on Two Point values and fitting curve coefficients stored in eFuse */
ESP_ADC_CAL_VAL_MAX,
ESP_ADC_CAL_VAL_NOT_SUPPORTED = ESP_ADC_CAL_VAL_MAX,
} esp_adc_cal_value_t;
/**
* @brief Structure storing characteristics of an ADC
*
* @note Call esp_adc_cal_characterize() to initialize the structure
*/
typedef struct {
adc_unit_t adc_num; /**< ADC unit*/
adc_atten_t atten; /**< ADC attenuation*/
adc_bits_width_t bit_width; /**< ADC bit width */
uint32_t coeff_a; /**< Gradient of ADC-Voltage curve*/
uint32_t coeff_b; /**< Offset of ADC-Voltage curve*/
uint32_t vref; /**< Vref used by lookup table*/
const uint32_t *low_curve; /**< Pointer to low Vref curve of lookup table (NULL if unused)*/
const uint32_t *high_curve; /**< Pointer to high Vref curve of lookup table (NULL if unused)*/
uint8_t version; /**< ADC Calibration */
} esp_adc_cal_characteristics_t;
#endif //#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,7 @@
# sdkconfig replacement configurations for deprecated options formatted as
# CONFIG_DEPRECATED_OPTION CONFIG_NEW_OPTION
CONFIG_ADC_DISABLE_DAC CONFIG_ADC_DISABLE_DAC_OUTPUT
CONFIG_ADC_CAL_EFUSE_TP_ENABLE CONFIG_ADC_CALI_EFUSE_TP_ENABLE
CONFIG_ADC_CAL_EFUSE_VREF_ENABLE CONFIG_ADC_CALI_EFUSE_VREF_ENABLE
CONFIG_ADC_CAL_LUT_ENABLE CONFIG_ADC_CALI_LUT_ENABLE

View File

@ -49,7 +49,6 @@ typedef enum {
ADC_ATTEN_DB_2_5 = 1, ///<The input voltage of ADC will be attenuated extending the range of measurement by about 2.5 dB
ADC_ATTEN_DB_6 = 2, ///<The input voltage of ADC will be attenuated extending the range of measurement by about 6 dB
ADC_ATTEN_DB_12 = 3, ///<The input voltage of ADC will be attenuated extending the range of measurement by about 12 dB
ADC_ATTEN_DB_11 __attribute__((deprecated)) = ADC_ATTEN_DB_12, ///<This is deprecated, it behaves the same as `ADC_ATTEN_DB_12`
} adc_atten_t;
/**
@ -243,25 +242,6 @@ typedef struct {
uint32_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
#endif
#if CONFIG_IDF_TARGET_ESP32S2
/**
* @brief ADC digital controller (DMA mode) clock system setting.
* Calculation formula: controller_clk = (`APLL` or `APB`) / (div_num + div_a / div_b + 1).
*
* @note: The clocks of the DAC digital controller use the ADC digital controller clock divider.
*/
typedef struct {
bool use_apll; /*!<true: use APLL clock; false: use APB clock. */
uint32_t div_num; /*!<Division factor. Range: 0 ~ 255.
Note: When a higher frequency clock is used (the division factor is less than 9),
the ADC reading value will be slightly offset. */
uint32_t div_b; /*!<Division factor. Range: 1 ~ 63. */
uint32_t div_a; /*!<Division factor. Range: 0 ~ 63. */
} adc_digi_clk_t;
#endif
#ifdef __cplusplus

View File

@ -118,7 +118,7 @@ The following binary size optimizations apply to a particular component or a fun
ADC
@@@
- Disabling ADC calibration features :ref:`CONFIG_ADC_CAL_EFUSE_TP_ENABLE`, :ref:`CONFIG_ADC_CAL_EFUSE_VREF_ENABLE`, :ref:`CONFIG_ADC_CAL_LUT_ENABLE` will save a small amount of binary size if ADC driver is used, at expense of accuracy.
- Disabling ADC calibration features :ref:`CONFIG_ADC_CALI_EFUSE_TP_ENABLE`, :ref:`CONFIG_ADC_CALI_EFUSE_VREF_ENABLE`, :ref:`CONFIG_ADC_CALI_LUT_ENABLE` will save a small amount of binary size if ADC driver is used, at expense of accuracy.
.. only:: SOC_BT_SUPPORTED

View File

@ -185,9 +185,9 @@ Other functions that take the :cpp:type:`adc_cali_handle_t` as the first positio
Kconfig Options
^^^^^^^^^^^^^^^
- :ref:`CONFIG_ADC_CAL_EFUSE_TP_ENABLE` - disable this to decrease the code size, if the calibration eFuse value is not set to :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP`.
- :ref:`CONFIG_ADC_CAL_EFUSE_VREF_ENABLE` - disable this to decrease the code size, if the calibration eFuse value is not set to :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF`.
- :ref:`CONFIG_ADC_CAL_LUT_ENABLE` - disable this to decrease the code size, if you do not calibrate the ADC raw results under :c:macro:`ADC_ATTEN_DB_12`.
- :ref:`CONFIG_ADC_CALI_EFUSE_TP_ENABLE` - disable this to decrease the code size, if the calibration eFuse value is not set to :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP`.
- :ref:`CONFIG_ADC_CALI_EFUSE_VREF_ENABLE` - disable this to decrease the code size, if the calibration eFuse value is not set to :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF`.
- :ref:`CONFIG_ADC_CALI_LUT_ENABLE` - disable this to decrease the code size, if you do not calibrate the ADC raw results under :c:macro:`ADC_ATTEN_DB_12`.
.. _adc-minimize-noise:

View File

@ -15,6 +15,9 @@ RTC Subsystem Control
RTC control APIs have been moved from ``driver/rtc_cntl.h`` to ``esp_private/rtc_ctrl.h``.
.. _deprecate_adc_driver:
ADC
---
@ -30,7 +33,7 @@ The ADC continuous mode driver has been moved from ``driver`` component to ``esp
- The include path has been changed from ``driver/adc.h`` to ``esp_adc/adc_continuous.h``.
Attempting to use the legacy include path ``driver/adc.h`` of either driver triggers the build warning below by default. However, the warning can be suppressed by enabling the :ref:`CONFIG_ADC_SUPPRESS_DEPRECATE_WARN` Kconfig option.
Attempting to use the legacy include path ``driver/adc.h`` of either driver triggers the build warning below by default.
.. code-block:: text
@ -45,7 +48,7 @@ The ADC calibration driver has been redesigned.
Legacy driver is still available by including ``esp_adc_cal.h``. However, if users still would like to use the include path of the legacy driver, users should add ``esp_adc`` component to the list of component requirements in CMakeLists.txt.
Attempting to use the legacy include path ``esp_adc_cal.h`` triggers the build warning below by default. However, the warning can be suppressed by enabling the :ref:`CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN` Kconfig option.
Attempting to use the legacy include path ``esp_adc_cal.h`` triggers the build warning below by default.
.. code-block:: text

View File

@ -11,6 +11,12 @@ All drivers' ``io_loop_back`` configuration have been removed
Different driver objects can share the same GPIO number, enabling more complex functionalities. For example, you can bind the TX and RX channels of the RMT peripheral to the same GPIO to simulate 1-Wire bus read and write timing. In previous versions, you needed to configure the ``io_loop_back`` setting in the driver to achieve this "loopback" functionality. Now, this configuration has been removed. Simply configuring the same GPIO number in different drivers will achieve the same functionality.
ADC
---
The legacy ADC driver ``driver/adc.h`` is deprecated since version 5.0 (see :ref:`deprecate_adc_driver`). Starting from version 6.0, the legacy driver is completely removed. The new driver is placed in the :component:`esp_adc`, and the header file path is ``esp_adc/adc_oneshot.h``, ``esp_adc/adc_continuous.h``, ``esp_adc/adc_cali.h`` and ``esp_adc/adc_cali_scheme.h``.
RMT
---
@ -65,7 +71,8 @@ The legacy timer group driver ``driver/timer.h`` is deprecated since version 5.0
Legacy I2S Driver is Removed
------------------------------------
The legacy i2s driver ``driver/i2s.h`` is deprecated since version 5.0 (see :ref:`deprecate_i2s_legacy_driver`). Starting from version 6.0, the legacy driver is completely removed. The new driver is placed in the :component:`esp_driver_i2s`, and the header file path is ``driver/i2s_std.h``, ``driver/i2s_pdm.h`` and ``driver/i2s_tdm.h``.
- The legacy i2s driver ``driver/i2s.h`` is deprecated since version 5.0 (see :ref:`deprecate_i2s_legacy_driver`). Starting from version 6.0, the legacy driver is completely removed. The new driver is placed in the :component:`esp_driver_i2s`, and the header file path is ``driver/i2s_std.h``, ``driver/i2s_pdm.h`` and ``driver/i2s_tdm.h``.
- API ``i2s_set_adc_mode``, ``i2s_adc_enable`` and ``i2s_adc_disable`` are deprecated since version 5.0. Starting from version 6.0, these APIs are completely removed.
.. only:: SOC_PCNT_SUPPORTED

View File

@ -118,7 +118,7 @@ ESP-IDF 构建系统会编译项目和 ESP-IDF 中所有源文件,但只有程
ADC
@@@
- 如果使用 ADC 驱动程序,禁用 :ref:`CONFIG_ADC_CAL_EFUSE_TP_ENABLE`:ref:`CONFIG_ADC_CAL_EFUSE_VREF_ENABLE`:ref:`CONFIG_ADC_CAL_LUT_ENABLE` 可以减小一小部分二进制文件的大小,但准确性会降低。
- 如果使用 ADC 驱动程序,禁用 :ref:`CONFIG_ADC_CALI_EFUSE_TP_ENABLE`:ref:`CONFIG_ADC_CALI_EFUSE_VREF_ENABLE`:ref:`CONFIG_ADC_CALI_LUT_ENABLE` 可以减小一小部分二进制文件的大小,但准确性会降低。
.. only:: SOC_BT_SUPPORTED

View File

@ -185,9 +185,9 @@ ADC 校准驱动程序会提供 ADC 校准方案。对于驱动程序来说,
Kconfig 选项
^^^^^^^^^^^^^^^
- :ref:`CONFIG_ADC_CAL_EFUSE_TP_ENABLE` - 如果校准相关的 eFuse 值没有配置为 :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP`,则可以禁用该选项,减小代码大小。
- :ref:`CONFIG_ADC_CAL_EFUSE_VREF_ENABLE` - 如果校准相关的 eFuse 值没有配置为 :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF`,则可以禁用该选项,减小代码大小。
- :ref:`CONFIG_ADC_CAL_LUT_ENABLE` - 如果校准 ADC 原始结果时,衰减没有设置成 :c:macro:`ADC_ATTEN_DB_12`,则可以禁用该选项,减小代码大小。
- :ref:`CONFIG_ADC_CALI_EFUSE_TP_ENABLE` - 如果校准相关的 eFuse 值没有配置为 :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_TP`,则可以禁用该选项,减小代码大小。
- :ref:`CONFIG_ADC_CALI_EFUSE_VREF_ENABLE` - 如果校准相关的 eFuse 值没有配置为 :cpp:type:`ADC_CALI_LINE_FITTING_EFUSE_VAL_EFUSE_VREF`,则可以禁用该选项,减小代码大小。
- :ref:`CONFIG_ADC_CALI_LUT_ENABLE` - 如果校准 ADC 原始结果时,衰减没有设置成 :c:macro:`ADC_ATTEN_DB_12`,则可以禁用该选项,减小代码大小。
.. _adc-minimize-noise:

View File

@ -15,6 +15,8 @@ RTC 子系统控制
RTC 控制 API 已经从 ``driver/rtc_cntl.h`` 移动到了 ``esp_private/rtc_ctrl.h``
.. _deprecate_adc_driver:
ADC
-----------------
@ -30,7 +32,7 @@ ADC 单次模式的驱动已更新。
- 头文件引用路径由 ``driver/adc.h`` 更新为 ``esp_adc/adc_continuous.h``
但是,引用两种模式的旧版路径 ``driver/adc.h`` 会默认触发如下编译警告,可通过配置 Kconfig 选项 :ref:`CONFIG_ADC_SUPPRESS_DEPRECATE_WARN` 关闭该警告
但是,引用两种模式的旧版路径 ``driver/adc.h`` 会默认触发如下编译警告。
.. code-block:: text
@ -45,7 +47,7 @@ ADC 校准驱动已更新。
旧版驱动仍然可用,其头文件引用路径为 ``esp_adc_cal.h``。如果用户要使用旧版路径,需要将组件 ``esp_adc`` 添加到文件 CMakeLists.txt 的组件需求表中。
默认情况下,引用路径 ``esp_adc_cal.h`` 会默认触发如下编译警告,可通过配置 Kconfig 选项 :ref:`CONFIG_ADC_CALI_SUPPRESS_DEPRECATE_WARN` 关闭该警告
默认情况下,引用路径 ``esp_adc_cal.h`` 会默认触发如下编译警告。
.. code-block:: text

View File

@ -11,6 +11,11 @@
不同的驱动对象可以共享同一个 GPIO 编号,联合起来可以实现更加复杂的功能。比如将 RMT 外设的 TX 通道和 RX 通道绑定在同一个 GPIO 上,进而模拟单总线的读写时序。在以前的版本中,你需要在驱动的配置中额外设置 ``io_loop_back`` 来实现这种“回环”功能,现在,这个配置已经被移除。不同的驱动只需要在配置中设置相同的 GPIO 编号就能实现这个功能。
ADC
---
旧版的 ADC 驱动 ``driver/adc.h`` 在 5.0 的版本中就已经被弃用 (参考 :ref:`deprecate_adc_driver`)。从 6.0 版本开始,旧版驱动被完全移除。新驱动位于 :component:`esp_adc` 组件中,头文件引用路径为 ``esp_adc/adc_oneshot.h``, ``esp_adc/adc_continuous.h``, ``esp_adc/adc_cali.h````esp_adc/adc_cali_scheme.h``
RMT
---
@ -65,7 +70,8 @@ I2C 从机在 v5.4 上已经被重新设计。在当前版本上,老的 I2C
旧版 I2S 驱动被移除
----------------------
旧版的 I2S 驱动 ``driver/i2s.h`` 在 5.0 的版本中就已经被弃用(请参考 :ref:`deprecate_i2s_legacy_driver`)。从 6.0 版本开始,旧版驱动被完全移除。新驱动位于 :component:`esp_driver_i2s` 组件中,头文件引用路径为 ``driver/i2s_std.h``, ``driver/i2s_pdm.h`` and ``driver/i2s_tdm.h``
- 旧版的 I2S 驱动 ``driver/i2s.h`` 在 5.0 的版本中就已经被弃用(请参考 :ref:`deprecate_i2s_legacy_driver`)。从 6.0 版本开始,旧版驱动被完全移除。新驱动位于 :component:`esp_driver_i2s` 组件中,头文件引用路径为 ``driver/i2s_std.h``, ``driver/i2s_pdm.h`` and ``driver/i2s_tdm.h``
- ``i2s_set_adc_mode``, ``i2s_adc_enable````i2s_adc_disable`` 在 5.0 版本中就已经被弃用。从 6.0 版本开始,这三个接口被完全移除。
.. only:: SOC_PCNT_SUPPORTED

View File

@ -509,3 +509,6 @@
-
re_variables: ['driver/dac.h']
hint_variables: ['legacy DAC', 'driver/dac_oneshot.h, driver/dac_continuous.h, driver/dac_cosine.h', 'esp_driver_dac']
-
re_variables: ['driver/adc.h']
hint_variables: ['legacy ADC', 'esp_adc/adc_oneshot.h, esp_adc/adc_continuous.h, esp_adc/adc_cali.h, esp_adc/adc_cali_scheme.h', 'esp_adc']