1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-25 06:23:53 +01:00

cpu/esp32: replace deprecated ADC peripheral driver

This commit is contained in:
Gunar Schorcht 2025-04-05 12:30:38 +02:00
parent b5314db4a3
commit 4c74f54eb0
21 changed files with 390 additions and 223 deletions

View File

@ -129,6 +129,7 @@ INCLUDES += -I$(ESP32_SDK_DIR)/components
INCLUDES += -I$(ESP32_SDK_DIR)/components/bootloader_support/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/deprecated
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_adc/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_adc/$(CPU_FAM)/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_common/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_driver_gpio/include
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_driver_uart/include

View File

@ -818,19 +818,6 @@ Attenuation | Voltage Range | Symbol
@note The reference voltage Vref can vary from device to device in the range
of 1.0V and 1.2V.
The Vref of a device can be read at a predefined GPIO with the function
#adc_line_vref_to_gpio. The results of the ADC input can then be adjusted
accordingly.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
extern int adc_line_vref_to_gpio(adc_t line, gpio_t gpio);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For the GPIO that can be used with this function, see:
- \ref esp32_adc_channels_esp32 "ESP32"
- \ref esp32_adc_channels_esp32c3 "ESP32-C3"
- \ref esp32_adc_channels_esp32s2 "ESP32-S2"
- \ref esp32_adc_channels_esp32s3 "ESP32-S3"
@note ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
therefore not available as ADC channels if the modules `esp_wifi` or
`esp_now` are used.

View File

@ -110,7 +110,6 @@ The maximum number of ADC channels #ADC_NUMOF_MAX is 18
- ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
therefore not available as ADC channels if the modules `esp_wifi` or
`esp_now` are used.
- Vref can be read with function #adc_line_vref_to_gpio at GPIO25.
## DAC Channels {#esp32_dac_channels_esp32}

View File

@ -80,10 +80,13 @@ total:
The maximum number of ADC channels #ADC_NUMOF_MAX is 6.
@note
- ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
therefore not available as ADC channels if the modules `esp_wifi` or
- According to the ESP32-C2 Errata Sheet, ADC2 with GPIO5 as ADC channel may
not work correctly. By default it is still possible to use it anyway.
Set `CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3` to 0 if you do not want to use
it and want to activate the configuration check for this channel.
- ADC2 is also used by the WiFi module. GPIO5 connected to ADC2 is
therefore not available as ADC channels if the modules `esp_wifi*` or
`esp_now` are used.
- Vref can be read with function #adc_line_vref_to_gpio at GPIO5.
## I2C Interfaces {#esp32_i2c_interfaces_esp32c3}

View File

@ -170,8 +170,6 @@ total:
- ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
therefore not available as ADC channels if the modules `esp_wifi` or
`esp_now` are used.
- Vref can be read with function #adc_line_vref_to_gpio at any ADC2 channel,
that is at GPIO11 ... GPIO20.
- GPIO3 is a strapping pin und shouldn't be used as ADC channel
## DAC Channels {#esp32_dac_channels_esp32s2}

View File

@ -182,8 +182,6 @@ total:
- ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
therefore not available as ADC channels if the modules `esp_wifi` or
`esp_now` are used.
- Vref can be read with function #adc_line_vref_to_gpio at any ADC2 channel,
that is at GPIO11 ... GPIO20.
- GPIO3 is a strapping pin und shouldn't be used as ADC channel
## I2C Interfaces {#esp32_i2c_interfaces_esp32s3}

View File

@ -2,9 +2,12 @@ MODULE = esp_idf_adc
# source files to be compiled for this module
ESP32_SDK_SRC = \
components/driver/deprecated/adc_legacy.c \
components/esp_adc/adc_cali.c \
components/esp_adc/adc_common.c \
components/esp_adc/adc_oneshot.c \
components/esp_hw_support/adc_share_hw_ctrl.c \
components/hal/adc_hal_common.c \
components/hal/adc_oneshot_hal.c \
components/soc/$(CPU_FAM)/adc_periph.c \
#
@ -20,11 +23,23 @@ ifeq (esp32s2,$(CPU_FAM))
ESP32_SDK_SRC += components/efuse/esp32s2/esp_efuse_rtc_table.c
endif
ifneq (,$(filter esp32 esp32s2,$(CPU_FAM)))
ESP32_SDK_SRC += components/esp_adc/$(CPU_FAM)/adc_cali_line_fitting.c
else
ESP32_SDK_SRC += components/esp_adc/adc_cali_curve_fitting.c
endif
ifneq (,$(filter esp32h2 esp32s3 esp32c3 esp32c6,$(CPU_FAM)))
ESP32_SDK_SRC += components/esp_adc/$(CPU_FAM)/curve_fitting_coefficients.c
endif
include $(RIOTBASE)/Makefile.base
ESP32_SDK_BIN = $(BINDIR)/$(MODULE)
INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/deprecated
CFLAGS += -Wno-unused-but-set-variable
INCLUDES += -I$(ESP32_SDK_DIR)/components/esp_adc/interface
include ../esp_idf.mk
include ../esp_idf_cflags.mk

View File

@ -54,16 +54,19 @@ typedef enum {
* @brief Attenuation of 11 dB is depcricated and has to be mapped
*
* The define ensures the compatibility with older versions.
*
* @deprecated `ADC_ATTENUATION_11_DB` is deprecated, use
* `ADC_ATTENUATION_12_DB` instead.
*/
#define ADC_ATTENUATION_11_DB ADC_ATTENUATION_12_DB
/**
* @brief Set the attenuation for the ADC line. Default attenuation is 11 dB.
* @brief Set the attenuation for the ADC line. Default attenuation is 12 dB.
*
* For each ADC line, an attenuation of the input signal can be defined
* separately. This results in different full ranges of the measurable voltage
* at the input. The attenuation can be set to 0 dB, 3 dB, 6 dB and 12 dB,
* with 11 dB being the standard attenuation. Since an ADC input is measured
* with 12 dB being the standard attenuation. Since an ADC input is measured
* against a reference voltage Vref of 1.1 V, approximately the following
* measurement ranges are given when using a corresponding attenuation:
*
@ -71,41 +74,71 @@ typedef enum {
*
* Attenuation | Voltage Range | Symbol
* ----------------|-------------------|----------------------
* 0 dB | 0 ... 1.1V (Vref) | ADC_ATTEN_DB_0
* 2.5 dB | 0 ... 1.5V | ADC_ATTEN_DB_2_5
* 6 dB | 0 ... 2.2V | ADC_ATTEN_DB_6
* 12 dB (default) | 0 ... 3.3V | ADC_ATTEN_DB_12
* 0 dB | 0 ... 1.1V (Vref) | `ADC_ATTEN_DB_0`
* 2.5 dB | 0 ... 1.5V | `ADC_ATTEN_DB_2_5`
* 6 dB | 0 ... 2.2V | `ADC_ATTEN_DB_6`
* 12 dB (default) | 0 ... 3.3V | `ADC_ATTEN_DB_12`
*
* </center>
*
* @note: The reference voltage Vref can vary from ADC unit to ADC unit in
* the range of 1.0V and 1.2V. The Vref of a unit can be routed with
* function *adc_vref_to_gpio* to a GPIO pin.
* @pre #adc_init must have been executed for the line before.
* @note The function has to be executed before @ref adc_sample if required.
* The configured attenuation is then used for all subsequent samples.
*
* @param line ADC line for which the attenuation is set
* @param atten Attenuation, see type definition of *adc_attenuation_t
* @return 0 on success
* @return -1 on error
* @param [in] line ADC line for which the attenuation is set
* @param [in] atten Attenuation, see type definition of @ref adc_attenuation_t
* @retval 0 on success
* @retval -1 on error
*/
int adc_set_attenuation(adc_t line, adc_atten_t atten);
/**
* @brief Output reference voltage of a ADC line to GPIO n
* @brief Get the voltage for a given sample value
*
* The Vref of the ADC unit of the given ADC line is routed to a GPIO pin n.
* The function converts the given sample value as read from the channel
* according to the attenuation set with @ref adc_set_attenuation and the
* resolution used to read the sample with @ref adc_sample. It uses a predefined
* calibration scheme and the calibration parameters that have been burned
* into the eFuses of the ESP32x SoC. If the calibration parameters have not
* been burned into the eFuses and the initialization of the calibration
* fails, a linear conversion according to the predefined voltage
* ranges is used as a fallback.
*
* @note In the case that the initialization of the calibration fails,
* the function returns `-EINVAL` and the value in parameter `voltage`
* is expected to be inaccurate.
* @note For ESP32, the valid voltages start at around 140 mV.
*
* @param [in] line ADC line
* @param [in] sample sample sample as read by adc_read
* @param [out] voltage voltage in mV
* @retval 0 on success
* @retval -EINVAL if the initialization of the calibration failed
*/
int adc_raw_to_voltage(adc_t line, int sample, int *voltage);
#if !DOXYGEN
/**
* @brief Output reference voltage of a ADC line to a GPIO pin
*
* The Vref of the ADC unit for the given ADC line is routed to a GPIO pin.
* This allows to measure the Vref used by the ADC unit to adjusted the
* results of the conversions accordingly.
*
* @warning The function is not supported any longer, use
* @ref adc_raw_to_voltage to get the voltage for a sample value.
*
* @note
* - The given GPIO must be a valid ADC channel of ADC2 unit.
* - For ESP32 and ESP32C3, the given ADC line has to be a channel of ADC2 unit.
* - For ESP32, only the internal reference voltage of ADC2 is given.
*
* @param line ADC line for which Vref of its ADC unit is routed to the GPIO
* @param gpio GPIO to which Vref is routed (ADC2 channel GPIOs only)
* @param [in] line ADC line for which Vref of its ADC unit is routed to the GPIO
* @param [in] gpio GPIO to which Vref is routed (ADC2 channel GPIOs only)
*
* @return 0 on success
* @return -1 on error
* @retval 0 on success
* @retval -1 on error
*/
__attribute__((__deprecated__))
int adc_line_vref_to_gpio(adc_t line, gpio_t gpio);
#if defined(CPU_FAM_ESP32)
@ -114,14 +147,19 @@ int adc_line_vref_to_gpio(adc_t line, gpio_t gpio);
*
* This function is deprecated and will be removed in future versions.
*
* @return 0 on success
* @return -1 on invalid ADC line
* @warning The function is not supported any longer, use
* @ref adc_raw_to_voltage to get the voltage for a sample value.
*
* @retval 0 on success
* @retval -1 on invalid ADC line
*/
__attribute__((__deprecated__))
static inline int adc_vref_to_gpio25(void)
{
return adc_vref_to_gpio(ADC_UNIT_2, GPIO25);
}
#endif
#endif /* !DOXYGEN */
#ifdef __cplusplus
}

View File

@ -32,11 +32,12 @@ extern "C" {
#define RTCIO_GPIO(n) n /* n-th RTCIO GPIO */
#define RTCIO_NA UINT8_MAX /* RTCIO pin not available */
#define ADC_UNIT_MAX ((adc_unit_t)255) /* Invalid ADC unit ID */
#define ADC_UNIT_INV ((adc_unit_t)255) /* Invalid ADC unit ID */
#define ADC_CHANNEL_INV SOC_ADC_MAX_CHANNEL_NUM /* Invalid ADC channel ID */
#define ADC_CHANNEL_MAX SOC_ADC_MAX_CHANNEL_NUM /* Invalid ADC channel ID */
#define ADC1_CHANNEL_MAX (SOC_ADC_CHANNEL_NUM(ADC_UNIT_1)) /* Number of channels of ADC1 */
#define ADC2_CHANNEL_MAX (SOC_ADC_CHANNEL_NUM(ADC_UNIT_2)) /* Number of channels of ADC2 */
#define ADC_CHANNEL_MAX(u) ((u == ADC_UNIT_1) ? ADC1_CHANNEL_MAX : ADC2_CHANNEL_MAX)
/**
* @brief ADC hardware descriptor (for internal use only)

View File

@ -338,18 +338,6 @@ union gpio_conf_esp32 {
* @note The reference voltage Vref can vary from device to device in the range
* of 1.0V and 1.2V.
*
* The Vref of a device can be read at a predefined GPIO with the function
* #adc_line_vref_to_gpio. The results of the ADC input can then be adjusted
* accordingly.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
* extern int adc_line_vref_to_gpio(adc_t line, gpio_t gpio);
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* For the GPIO that can be used with this function, see:
*
* - \ref esp32_adc_channels_esp32 "ESP32"
* - \ref esp32_adc_channels_esp32c3 "ESP32-C3"
* - \ref esp32_adc_channels_esp32s3 "ESP32-S3"
*
* @{
*/

View File

@ -96,7 +96,6 @@ extern "C" {
* - ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
* therefore not available as ADC channels if the modules `esp_wifi` or
* `esp_now` are used.
* - Vref can be read with function #adc_line_vref_to_gpio at GPIO25.
*/
/**

View File

@ -72,10 +72,9 @@ extern "C" {
* The maximum number of ADC channels #ADC_NUMOF_MAX is 6.
*
* @note
* - ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
* ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
* therefore not available as ADC channels if the modules `esp_wifi` or
* `esp_now` are used.
* - Vref can be read with function #adc_line_vref_to_gpio at GPIO5.
*/
/**

View File

@ -95,8 +95,6 @@ extern "C" {
* - ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
* therefore not available as ADC channels if the modules `esp_wifi` or
* `esp_now` are used.
* - Vref can be read with function #adc_line_vref_to_gpio at an ADC2 channel,
* that is at GPIO11 ... GPIO20.
* - GPIO3 is a strapping pin und shouldn't be used as ADC channel
*/

View File

@ -95,8 +95,6 @@ extern "C" {
* - ADC2 is also used by the WiFi module. The GPIOs connected to ADC2 are
* therefore not available as ADC channels if the modules `esp_wifi` or
* `esp_now` are used.
* - Vref can be read with function #adc_line_vref_to_gpio at an ADC2 channel,
* that is at GPIO11 ... GPIO20.
* - GPIO3 is a strapping pin und shouldn't be used as ADC channel
*/

View File

@ -111,9 +111,9 @@ extern "C" {
/**
* ESP32 specific ADC calibration
*/
#define CONFIG_ADC_CAL_EFUSE_TP_ENABLE 1
#define CONFIG_ADC_CAL_EFUSE_VREF_ENABLE 1
#define CONFIG_ADC_CAL_LUT_ENABLE 1
#define CONFIG_ADC_CALI_EFUSE_TP_ENABLE 1
#define CONFIG_ADC_CALI_EFUSE_VREF_ENABLE 1
#define CONFIG_ADC_CALI_LUT_ENABLE 1
/**
* ESP32 specific PHY configuration

View File

@ -158,6 +158,13 @@ extern "C" {
# define CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3 1
#endif
/* According to the ESP32-C3 Errata Sheet ADC2 does not work correctly.
* To use ADC2 and GPIO5 as ADC channel, CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3
* has to be set (default). */
#ifndef CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3
#define CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3 1
#endif
#ifdef __cplusplus
}
#endif

View File

@ -27,6 +27,7 @@
*/
#include <assert.h>
#include <errno.h>
#include "board.h"
#include "periph/adc.h"
@ -36,92 +37,76 @@
#include "esp_common.h"
#include "gpio_arch.h"
#include "driver/adc.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_private/adc_share_hw_ctrl.h"
#include "hal/adc_hal_common.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/* forward declarations of internal functions */
static bool _adc_conf_check(void);
static void _adc1_ctrl_init(void);
static void _adc2_ctrl_init(void);
/* external variable declarations */
extern const gpio_t _gpio_rtcio_map[];
extern const int _adc_vrange_min_max[];
/*
* Structure for mapping RIOT's ADC resolutions to ESP-IDF resolutions
* of the according ESP32x SoC.
*/
typedef struct {
adc_bits_width_t res; /* used ESP-IDF resolution */
unsigned shift; /* bit shift number for results */
adc_bitwidth_t hw_res; /* used ESP-IDF resolution */
unsigned shift; /* bit shift number for results */
} _adc_esp_res_map_t;
#define ADC_BITWIDTH_MAX ((adc_bitwidth_t)255)
/*
* Table for resolution mapping
* With the exception of the ESP32, all ESP32x SoCs only support one resolution.
* Therefore, we only use this one resolution and shift the results accordingly.
*/
_adc_esp_res_map_t _adc_esp_res_map[] = {
#if defined(CPU_FAM_ESP32)
{ .res = ADC_WIDTH_BIT_9, .shift = 3 }, /* ADC_RES_6BIT */
{ .res = ADC_WIDTH_BIT_9, .shift = 1 }, /* ADC_RES_8BIT */
{ .res = ADC_WIDTH_BIT_10, .shift = 0 }, /* ADC_RES_10BIT */
{ .res = ADC_WIDTH_BIT_12, .shift = 0 }, /* ADC_RES_12BIT */
{ .res = ADC_WIDTH_MAX }, /* ADC_RES_14BIT */
{ .res = ADC_WIDTH_MAX }, /* ADC_RES_16BIT */
#elif SOC_ADC_RTC_MAX_BITWIDTH == 12
{ .res = ADC_WIDTH_BIT_12, .shift = 6 }, /* ADC_RES_6BIT */
{ .res = ADC_WIDTH_BIT_12, .shift = 4 }, /* ADC_RES_8BIT */
{ .res = ADC_WIDTH_BIT_12, .shift = 2 }, /* ADC_RES_10BIT */
{ .res = ADC_WIDTH_BIT_12, .shift = 0 }, /* ADC_RES_12BIT */
{ .res = ADC_WIDTH_MAX }, /* ADC_RES_14BIT */
{ .res = ADC_WIDTH_MAX }, /* ADC_RES_16BIT */
static const _adc_esp_res_map_t _adc_esp_res_map[] = {
#if SOC_ADC_RTC_MAX_BITWIDTH == 12
{ .hw_res = ADC_BITWIDTH_12, .shift = 6 }, /* ADC_RES_6BIT */
{ .hw_res = ADC_BITWIDTH_12, .shift = 4 }, /* ADC_RES_8BIT */
{ .hw_res = ADC_BITWIDTH_12, .shift = 2 }, /* ADC_RES_10BIT */
{ .hw_res = ADC_BITWIDTH_12, .shift = 0 }, /* ADC_RES_12BIT */
{ .hw_res = ADC_BITWIDTH_MAX }, /* ADC_RES_14BIT */
{ .hw_res = ADC_BITWIDTH_MAX }, /* ADC_RES_16BIT */
#elif SOC_ADC_RTC_MAX_BITWIDTH == 13
{ .res = ADC_WIDTH_BIT_13, .shift = 7 }, /* ADC_RES_6BIT */
{ .res = ADC_WIDTH_BIT_13, .shift = 5 }, /* ADC_RES_8BIT */
{ .res = ADC_WIDTH_BIT_13, .shift = 3 }, /* ADC_RES_10BIT */
{ .res = ADC_WIDTH_BIT_13, .shift = 1 }, /* ADC_RES_12BIT */
{ .res = ADC_WIDTH_MAX }, /* ADC_RES_14BIT */
{ .res = ADC_WIDTH_MAX }, /* ADC_RES_16BIT */
{ .hw_res = ADC_BITWIDTH_13, .shift = 7 }, /* ADC_RES_6BIT */
{ .hw_res = ADC_BITWIDTH_13, .shift = 5 }, /* ADC_RES_8BIT */
{ .hw_res = ADC_BITWIDTH_13, .shift = 3 }, /* ADC_RES_10BIT */
{ .hw_res = ADC_BITWIDTH_13, .shift = 1 }, /* ADC_RES_12BIT */
{ .hw_res = ADC_BITWIDTH_MAX }, /* ADC_RES_14BIT */
{ .hw_res = ADC_BITWIDTH_MAX }, /* ADC_RES_16BIT */
#endif
};
static bool _adc_module_initialized = false;
static adc_oneshot_unit_handle_t _adc_handle[SOC_ADC_PERIPH_NUM] = { };
static inline void _adc1_ctrl_init(void)
{
/* nothing to do for the moment */
}
static adc_oneshot_chan_cfg_t _adc_channel_cfg[ADC_NUMOF] = { };
static adc_cali_handle_t _adc_channel_cali[ADC_NUMOF] = { };
static const _adc_esp_res_map_t *_adc_channel_res[ADC_NUMOF] = { };
static inline void _adc2_ctrl_init(void)
{
/* nothing to do for the moment */
}
static bool _adc_driver_initialized = false;
/* forward declarations of internal functions */
static void _adc_driver_init(void);
static void _adc_channel_config(adc_t line, adc_bitwidth_t width, adc_atten_t att);
static void _adc_ctrl_init(adc_unit_t unit);
int adc_init(adc_t line)
{
DEBUG("[adc] line=%u\n", line);
DEBUG("[adc] %s: line=%u\n", __func__, line);
if (line >= ADC_NUMOF) {
return -1;
}
assert(line < ADC_NUMOF);
if (!_adc_module_initialized) {
/* do some configuration checks */
if (!_adc_conf_check()) {
return -1;
}
_adc_module_initialized = true;
}
/* initialize the ADC driver if needed including configuration sanity checks */
_adc_driver_init();
/* get the RTCIO pin number for the given GPIO defined as ADC channel */
uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]];
/* check whether the GPIO is avalid ADC channel pin */
if (rtcio == RTCIO_NA) {
return -1;
}
/* check whether the pin is not used for other purposes */
if (gpio_get_pin_usage(_adc_hw[rtcio].gpio) != _GPIO) {
LOG_TAG_ERROR("adc", "GPIO%d is used for %s and cannot be used as "
@ -130,27 +115,8 @@ int adc_init(adc_t line)
return -1;
}
if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) {
/* ensure compatibility of given adc_channel_t with adc1_channel_t */
assert(_adc_hw[rtcio].adc_channel < (adc_channel_t)ADC1_CHANNEL_MAX);
/* initialize the ADC1 unit if needed */
_adc1_ctrl_init();
/* set the attenuation and configure its associated GPIO pin mux */
adc1_config_channel_atten((adc1_channel_t)_adc_hw[rtcio].adc_channel,
ADC_ATTEN_DB_12);
}
else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) {
/* ensure compatibility of given adc_channel_t with adc2_channel_t */
assert(_adc_hw[rtcio].adc_channel < (adc_channel_t)ADC2_CHANNEL_MAX);
/* initialize the ADC2 unit if needed */
_adc2_ctrl_init();
/* set the attenuation and configure its associated GPIO pin mux */
adc2_config_channel_atten((adc2_channel_t)_adc_hw[rtcio].adc_channel,
ADC_ATTEN_DB_12);
}
else {
return -1;
}
/* initialize the corresponding ADC unit if needed */
_adc_ctrl_init(_adc_hw[rtcio].adc_ctrl);
/* set pin usage type */
gpio_set_pin_usage(_adc_hw[rtcio].gpio, _ADC);
@ -160,31 +126,29 @@ int adc_init(adc_t line)
int32_t adc_sample(adc_t line, adc_res_t res)
{
DEBUG("[adc] line=%u res=%u\n", line, res);
DEBUG("[adc] %s: line=%u res=%u\n", __func__, line, res);
if (_adc_esp_res_map[res].res == ADC_WIDTH_MAX) {
assert(_adc_driver_initialized);
assert(line < ADC_NUMOF);
if (_adc_esp_res_map[res].hw_res == ADC_BITWIDTH_MAX) {
return -1;
}
uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]];
int raw;
assert(rtcio != RTCIO_NA);
if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) {
adc1_config_width(_adc_esp_res_map[res].res);
/* ensure compatibility of given adc_channel_t with adc1_channel_t */
assert(_adc_hw[rtcio].adc_channel < (adc_channel_t)ADC1_CHANNEL_MAX);
raw = adc1_get_raw((adc1_channel_t)_adc_hw[rtcio].adc_channel);
if (raw < 0) {
return -1;
}
if (_adc_channel_res[line] != &_adc_esp_res_map[res]) {
/* reconfigure the channel if the resolution is changed */
_adc_channel_res[line] = &_adc_esp_res_map[res];
_adc_channel_config(line, _adc_esp_res_map[res].hw_res,
_adc_channel_cfg[line].atten);
}
else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) {
/* ensure compatibility of given adc_channel_t with adc2_channel_t */
assert(_adc_hw[rtcio].adc_channel < (adc_channel_t)ADC2_CHANNEL_MAX);
if (adc2_get_raw((adc2_channel_t)_adc_hw[rtcio].adc_channel,
_adc_esp_res_map[res].res, &raw) < 0) {
return -1;
}
int raw = 0;
if (adc_oneshot_read(_adc_handle[_adc_hw[rtcio].adc_ctrl],
_adc_hw[rtcio].adc_channel, &raw) != ESP_OK) {
return -1;
}
return raw >> _adc_esp_res_map[res].shift;
@ -192,73 +156,177 @@ int32_t adc_sample(adc_t line, adc_res_t res)
int adc_set_attenuation(adc_t line, adc_atten_t atten)
{
DEBUG("[adc] line=%u atten=%u\n", line, atten);
DEBUG("[adc] %s: line=%u atten=%u\n", __func__, line, atten);
assert(_adc_driver_initialized);
assert(line < ADC_NUMOF);
assert(atten < SOC_ADC_ATTEN_NUM);
_adc_channel_config(line, _adc_channel_cfg[line].bitwidth, atten);
return 0;
}
int adc_raw_to_voltage(adc_t line, int raw, int *voltage)
{
DEBUG("[adc] %s: line=%u\n", __func__, line);
assert(line < ADC_NUMOF);
assert(voltage);
assert(_adc_channel_res[line]);
/* scale the raw value to the resolution used internally */
raw = raw << _adc_channel_res[line]->shift;
if (_adc_channel_cali[line]) {
adc_cali_raw_to_voltage(_adc_channel_cali[line], raw, voltage);
return 0;
}
else {
/* default values for the case the calibration does not work */
int min = _adc_vrange_min_max[(_adc_channel_cfg[line].atten << 1)];
int max = _adc_vrange_min_max[(_adc_channel_cfg[line].atten << 1) + 1];
*voltage = raw * (max - min) / 4096 + min;
return -EINVAL;
}
}
__attribute__((__deprecated__))
int adc_line_vref_to_gpio(adc_t line, gpio_t gpio)
{
LOG_TAG_ERROR("adc", "%s is no longer supported\n", __func__);
assert(0);
return 0;
}
static void _adc_driver_init(void)
{
if (_adc_driver_initialized) {
return;
}
/* do some configuration checks */
for (unsigned i = 0; i < ADC_NUMOF; i++) {
uint8_t rtcio = _gpio_rtcio_map[adc_channels[i]];
/* check whether the GPIO is a valid ADC channel pin */
if (rtcio == RTCIO_NA) {
LOG_TAG_ERROR("adc", "GPIO%d cannot be configured as ADC line\n",
adc_channels[i]);
assert(0);
}
if (_adc_hw[rtcio].adc_ctrl >= SOC_ADC_PERIPH_NUM) {
LOG_TAG_ERROR("adc", "Invalid ADC unit %u for ADC line %u\n",
_adc_hw[rtcio].adc_ctrl, adc_channels[i]);
assert(0);
}
if (_adc_hw[rtcio].adc_channel >= ADC_CHANNEL_MAX(_adc_hw[rtcio].adc_ctrl)) {
LOG_TAG_ERROR("adc", "Invalid ADC channel %u for ADC line %u\n",
_adc_hw[rtcio].adc_channel, adc_channels[i]);
assert(0);
}
#if CPU_FAM_ESP32C3
/* According to the ESP32-C3 Errata Sheet ADC2 does not work correctly. To
* use ADC2 and GPIO5 as ADC channel, CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3
* has to be set (default). */
if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) {
if (!IS_ACTIVE(CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3)) {
LOG_TAG_ERROR("adc", "ADC2 cannot be used on ESP32-C3 if "
"CONFIG_ADC_ONESHOT_FORCE_USE_ADC2_ON_C3 "
"is not set (ADC line %u)\n", i);
assert(0);
}
/* throw at least a warning */
LOG_TAG_WARNING("adc", "ADC line %u on ADC2 may not work correctly "
"on ESP32-C3, see errata sheet\n", i);
}
#endif
}
/* set the default bitwidth and the attenuation for all channels to 12 dB */
for (unsigned i = 0; i < ADC_NUMOF; i++) {
_adc_channel_cfg[i].bitwidth = ADC_BITWIDTH_DEFAULT;
_adc_channel_cfg[i].atten = ADC_ATTEN_DB_12;
}
_adc_driver_initialized = true;
}
static void _adc_ctrl_init(adc_unit_t unit)
{
DEBUG("[adc] %s: unit=%u\n", __func__, unit);
assert(unit < SOC_ADC_PERIPH_NUM);
if (_adc_handle[unit] != NULL) {
/* unit is already initialized */
return;
}
adc_oneshot_unit_init_cfg_t unit_cfg = {
.unit_id = unit,
.ulp_mode = ADC_ULP_MODE_DISABLE,
};
if (adc_oneshot_new_unit(&unit_cfg, &_adc_handle[unit]) != ESP_OK) {
LOG_TAG_ERROR("adc", "Could not initialize ADC unit %u\n", unit);
}
}
static void _adc_channel_config(adc_t line, adc_bitwidth_t width, adc_atten_t att)
{
DEBUG("[adc] %s: line=%u width=%d atten=%u\n", __func__, line, width, att);
uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]];
assert(rtcio != RTCIO_NA);
_adc_channel_cfg[line].bitwidth = width;
_adc_channel_cfg[line].atten = att;
if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) {
/* ensure compatibility of given adc_channel_t with adc1_channel_t */
assert(_adc_hw[rtcio].adc_channel < (adc_channel_t)ADC1_CHANNEL_MAX);
return adc1_config_channel_atten((adc1_channel_t)_adc_hw[rtcio].adc_channel, atten);
}
else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) {
/* ensure compatibility of given adc_channel_t with adc2_channel_t */
assert(_adc_hw[rtcio].adc_channel < (adc_channel_t)ADC2_CHANNEL_MAX);
return adc2_config_channel_atten((adc2_channel_t)_adc_hw[rtcio].adc_channel, atten);
if (adc_oneshot_config_channel(_adc_handle[_adc_hw[rtcio].adc_ctrl],
_adc_hw[rtcio].adc_channel,
&_adc_channel_cfg[line]) != ESP_OK) {
LOG_TAG_ERROR("adc", "Could not config ADC line %u\n", line);
return;
}
return -1;
}
int adc_line_vref_to_gpio(adc_t line, gpio_t gpio)
{
uint8_t rtcio_vref = _gpio_rtcio_map[adc_channels[line]];
uint8_t rtcio_out = _gpio_rtcio_map[gpio];
/* both the ADC line and the GPIO for the output must be ADC channels */
assert(rtcio_vref != RTCIO_NA);
assert(rtcio_out != RTCIO_NA);
/* avoid compilation problems with NDEBUG defined */
(void)rtcio_out;
/* the GPIO for the output must be a channel of ADC2 */
assert(_adc_hw[rtcio_out].adc_ctrl == ADC_UNIT_2);
/* given ADC line has to be a channel of ADC2 */
assert(_adc_hw[rtcio_vref].adc_ctrl == ADC_UNIT_2);
esp_err_t res = ESP_OK;
if (_adc_hw[rtcio_vref].adc_ctrl == ADC_UNIT_1) {
res = adc_vref_to_gpio(ADC_UNIT_1, gpio);
}
else if (_adc_hw[rtcio_vref].adc_ctrl == ADC_UNIT_2) {
res = adc_vref_to_gpio(ADC_UNIT_2, gpio);
if (_adc_channel_cali[line]) {
/* delete allocated calibration scheme if necessary */
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
adc_cali_delete_scheme_curve_fitting(_adc_channel_cali[line]);
#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
adc_cali_delete_scheme_line_fitting(_adc_channel_cali[line]);
#endif
_adc_channel_cali[line] = NULL;
}
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
adc_cali_curve_fitting_config_t cfg = {
.unit_id = _adc_hw[rtcio].adc_ctrl,
.chan = _adc_hw[rtcio].adc_channel,
.atten = _adc_channel_cfg[line].atten,
.bitwidth = _adc_channel_cfg[line].bitwidth,
};
int res = adc_cali_create_scheme_curve_fitting(&cfg, &_adc_channel_cali[line]);
if (res != ESP_OK) {
LOG_TAG_ERROR("adc", "Could not route Vref of ADC line %d to GPIO%d\n",
line, gpio);
return -1;
DEBUG("[adc] %s: init calibration scheme failed %d\n", __func__, res);
return;
}
else {
LOG_TAG_ERROR("adc", "Vref of ADC%d can now be measured at GPIO %d\n",
_adc_hw[rtcio_vref].adc_ctrl, gpio);
return 0;
#elif ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
adc_cali_line_fitting_config_t cfg = {
.unit_id = _adc_hw[rtcio].adc_ctrl,
.atten = _adc_channel_cfg[line].atten,
.bitwidth = _adc_channel_cfg[line].bitwidth,
#if CONFIG_IDF_TARGET_ESP32
.default_vref = 1100,
#endif
};
int res = adc_cali_create_scheme_line_fitting(&cfg, &_adc_channel_cali[line]);
if (res != ESP_OK) {
DEBUG("[adc] %s: init calibration scheme failed %d\n", __func__, res);
return;
}
}
static bool _adc_conf_check(void)
{
for (unsigned i = 0; i < ADC_NUMOF; i++) {
if (_gpio_rtcio_map[adc_channels[i]] == RTCIO_NA) {
LOG_TAG_ERROR("adc", "GPIO%d cannot be used as ADC line\n",
adc_channels[i]);
return false;
}
}
return true;
#endif
}
void adc_print_config(void)

View File

@ -107,7 +107,23 @@ const gpio_t _gpio_rtcio_map[] = {
RTCIO_GPIO(3), /* GPIO39 SENSOR_VN */
};
/**
* @brief Default voltage range of ADC results for different attenuations
*
* These values are used by function adc_get_vrange_min_max if software
* calibration doesn't work for any reason and the voltage range can't be
* determined by software.
*/
const int _adc_vrange_min_max[] = {
0, 950, /* min, max @ ADC_ATTEN_DB_0 */
0, 1250, /* min, max @ ADC_ATTEN_DB_2_5 */
0, 1750, /* min, max @ ADC_ATTEN_DB_6 */
0, 2450, /* min, max @ ADC_ATTEN_DB_12 */
};
_Static_assert(ARRAY_SIZE(_adc_hw) == SOC_RTCIO_PIN_COUNT,
"size of _adc_hw does not match SOC_RTCIO_PIN_COUNT");
_Static_assert(ARRAY_SIZE(_gpio_rtcio_map) == SOC_GPIO_PIN_COUNT,
"size of _gpio_rtcio_map does not match SOC_GPIO_PIN_COUNT");
_Static_assert(ARRAY_SIZE(_adc_vrange_min_max) == (SOC_ADC_ATTEN_NUM * 2),
"size of _adc_vrange_min_max does not match SOC_ADC_ATTEN_NUM");

View File

@ -71,5 +71,24 @@ const gpio_t _gpio_rtcio_map[] = {
RTCIO_NA, /* GPIO21 */
};
/**
* @brief Default voltage range of ADC results for different attenuations
*
* These values are used by function adc_get_vrange_min_max if software
* calibration doesn't work for any reason and the voltage range can't be
* determined by software.
*
* Table 5-6 in [ESP32-C3 Datasheet]
* (https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf).
*/
const int _adc_vrange_min_max[] = {
0, 750, /* min, max @ ADC_ATTEN_DB_0 */
0, 1050, /* min, max @ ADC_ATTEN_DB_2_5 */
0, 1300, /* min, max @ ADC_ATTEN_DB_6 */
0, 2500, /* min, max @ ADC_ATTEN_DB_12 */
};
_Static_assert(ARRAY_SIZE(_gpio_rtcio_map) == SOC_GPIO_PIN_COUNT,
"size of _gpio_rtcio_map does not match SOC_GPIO_PIN_COUNT");
_Static_assert(ARRAY_SIZE(_adc_vrange_min_max) == (SOC_ADC_ATTEN_NUM * 2),
"size of _adc_vrange_min_max does not match SOC_ADC_ATTEN_NUM");

View File

@ -38,7 +38,7 @@
*/
const _adc_hw_desc_t _adc_hw[] = {
/* rtcio, gpio, adc_ctrl, adc_channel, pad_name */
{ RTCIO_GPIO(0), GPIO0, ADC_UNIT_MAX, ADC_CHANNEL_MAX, "GPIO0" },
{ RTCIO_GPIO(0), GPIO0, ADC_UNIT_INV, ADC_CHANNEL_INV, "GPIO0" },
{ RTCIO_GPIO(1), ADC1_CHANNEL_0_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_0, "TOUCH1" },
{ RTCIO_GPIO(2), ADC1_CHANNEL_1_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_1, "TOUCH2" },
{ RTCIO_GPIO(3), ADC1_CHANNEL_2_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_2, "TOUCH3" },
@ -59,7 +59,7 @@ const _adc_hw_desc_t _adc_hw[] = {
{ RTCIO_GPIO(18), ADC2_CHANNEL_7_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_7, "DAC2" },
{ RTCIO_GPIO(19), ADC2_CHANNEL_8_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_8, "USB_D-" },
{ RTCIO_GPIO(20), ADC2_CHANNEL_9_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_9, "USB_D+" },
{ RTCIO_GPIO(21), GPIO21, ADC_UNIT_MAX, ADC_CHANNEL_MAX, "GPIO21" },
{ RTCIO_GPIO(21), GPIO21, ADC_UNIT_INV, ADC_CHANNEL_INV, "GPIO21" },
};
/**
@ -118,7 +118,23 @@ const gpio_t _gpio_rtcio_map[] = {
RTCIO_NA, /* GPIO46 */
};
/**
* @brief Default voltage range of ADC results for different attenuations
*
* These values are used by function adc_get_vrange_min_max if software
* calibration doesn't work for any reason and the voltage range can't be
* determined by software.
*/
const int _adc_vrange_min_max[] = {
0, 750, /* min, max @ ADC_ATTEN_DB_0 */
0, 1050, /* min, max @ ADC_ATTEN_DB_2_5 */
0, 1300, /* min, max @ ADC_ATTEN_DB_6 */
0, 2500, /* min, max @ ADC_ATTEN_DB_12 */
};
_Static_assert(ARRAY_SIZE(_adc_hw) == SOC_RTCIO_PIN_COUNT,
"size of _adc_hw does not match SOC_RTCIO_PIN_COUNT");
_Static_assert(ARRAY_SIZE(_gpio_rtcio_map) == SOC_GPIO_PIN_COUNT,
"size of _gpio_rtcio_map does not match SOC_GPIO_PIN_COUNT");
_Static_assert(ARRAY_SIZE(_adc_vrange_min_max) == (SOC_ADC_ATTEN_NUM * 2),
"size of _adc_vrange_min_max does not match SOC_ADC_ATTEN_NUM");

View File

@ -38,7 +38,7 @@
*/
const _adc_hw_desc_t _adc_hw[] = {
/* rtcio, gpio, adc_ctrl, adc_channel, pad_name */
{ RTCIO_GPIO(0), GPIO0, ADC_UNIT_MAX, ADC_CHANNEL_MAX, "GPIO0" },
{ RTCIO_GPIO(0), GPIO0, ADC_UNIT_INV, ADC_CHANNEL_INV, "GPIO0" },
{ RTCIO_GPIO(1), ADC1_CHANNEL_0_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_0, "TOUCH1" },
{ RTCIO_GPIO(2), ADC1_CHANNEL_1_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_1, "TOUCH2" },
{ RTCIO_GPIO(3), ADC1_CHANNEL_2_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_2, "TOUCH3" },
@ -59,7 +59,7 @@ const _adc_hw_desc_t _adc_hw[] = {
{ RTCIO_GPIO(18), ADC2_CHANNEL_7_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_7, "GPIO18" },
{ RTCIO_GPIO(19), ADC2_CHANNEL_8_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_8, "USB_D-" },
{ RTCIO_GPIO(20), ADC2_CHANNEL_9_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_9, "USB_D+" },
{ RTCIO_GPIO(21), GPIO21, ADC_UNIT_MAX, ADC_CHANNEL_MAX, "GPIO21" },
{ RTCIO_GPIO(21), GPIO21, ADC_UNIT_INV, ADC_CHANNEL_INV, "GPIO21" },
};
/**
@ -120,7 +120,26 @@ const gpio_t _gpio_rtcio_map[] = {
RTCIO_NA, /* GPIO48 */
};
/**
* @brief Default voltage range of ADC results for different attenuations
*
* These values are used by function adc_get_vrange_min_max if software
* calibration doesn't work for any reason and the voltage range can't be
* determined by software.
*
* Table 5-5 in [ESP32-S3 Datasheet]
* (https://www.espressif.com/sites/default/files/documentation/esp32-s3_datasheet_en.pdf).
*/
const int _adc_vrange_min_max[] = {
0, 850, /* min, max @ ADC_ATTEN_DB_0 */
0, 1100, /* min, max @ ADC_ATTEN_DB_2_5 */
0, 1600, /* min, max @ ADC_ATTEN_DB_6 */
0, 2900, /* min, max @ ADC_ATTEN_DB_12 */
};
_Static_assert(ARRAY_SIZE(_adc_hw) == SOC_RTCIO_PIN_COUNT,
"size of _adc_hw does not match SOC_RTCIO_PIN_COUNT");
_Static_assert(ARRAY_SIZE(_gpio_rtcio_map) == SOC_GPIO_PIN_COUNT,
"size of _gpio_rtcio_map does not match SOC_GPIO_PIN_COUNT");
_Static_assert(ARRAY_SIZE(_adc_vrange_min_max) == (SOC_ADC_ATTEN_NUM * 2),
"size of _adc_vrange_min_max does not match SOC_ADC_ATTEN_NUM");