diff --git a/cpu/esp32/Makefile.include b/cpu/esp32/Makefile.include index 4b5c99beeb..1acf46ed5f 100644 --- a/cpu/esp32/Makefile.include +++ b/cpu/esp32/Makefile.include @@ -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 diff --git a/cpu/esp32/doc.txt b/cpu/esp32/doc.txt index e5822b97b0..5a89f7c6d5 100644 --- a/cpu/esp32/doc.txt +++ b/cpu/esp32/doc.txt @@ -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. diff --git a/cpu/esp32/doc_esp32.txt b/cpu/esp32/doc_esp32.txt index 3cb89d508d..ba4d198066 100644 --- a/cpu/esp32/doc_esp32.txt +++ b/cpu/esp32/doc_esp32.txt @@ -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} diff --git a/cpu/esp32/doc_esp32c3.txt b/cpu/esp32/doc_esp32c3.txt index 34ba34f11d..d29e89db2e 100644 --- a/cpu/esp32/doc_esp32c3.txt +++ b/cpu/esp32/doc_esp32c3.txt @@ -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} diff --git a/cpu/esp32/doc_esp32s2.txt b/cpu/esp32/doc_esp32s2.txt index 1d4123e1b4..2e6d7bf6d7 100644 --- a/cpu/esp32/doc_esp32s2.txt +++ b/cpu/esp32/doc_esp32s2.txt @@ -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} diff --git a/cpu/esp32/doc_esp32s3.txt b/cpu/esp32/doc_esp32s3.txt index 9661713cdc..d5cdd640d1 100644 --- a/cpu/esp32/doc_esp32s3.txt +++ b/cpu/esp32/doc_esp32s3.txt @@ -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} diff --git a/cpu/esp32/esp-idf/adc/Makefile b/cpu/esp32/esp-idf/adc/Makefile index a0ea1ca775..d8c952c280 100644 --- a/cpu/esp32/esp-idf/adc/Makefile +++ b/cpu/esp32/esp-idf/adc/Makefile @@ -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 diff --git a/cpu/esp32/include/adc_arch.h b/cpu/esp32/include/adc_arch.h index f532d8d398..20da6acecf 100644 --- a/cpu/esp32/include/adc_arch.h +++ b/cpu/esp32/include/adc_arch.h @@ -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` * * * - * @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 } diff --git a/cpu/esp32/include/adc_arch_private.h b/cpu/esp32/include/adc_arch_private.h index 80f699f967..d20f1c7417 100644 --- a/cpu/esp32/include/adc_arch_private.h +++ b/cpu/esp32/include/adc_arch_private.h @@ -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) diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 13aab8f928..cfe8cd707c 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -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" - * * @{ */ diff --git a/cpu/esp32/include/periph_cpu_esp32.h b/cpu/esp32/include/periph_cpu_esp32.h index 26cd9ef722..edbf1c8b48 100644 --- a/cpu/esp32/include/periph_cpu_esp32.h +++ b/cpu/esp32/include/periph_cpu_esp32.h @@ -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. */ /** diff --git a/cpu/esp32/include/periph_cpu_esp32c3.h b/cpu/esp32/include/periph_cpu_esp32c3.h index 83f87ad17c..d3d3542de9 100644 --- a/cpu/esp32/include/periph_cpu_esp32c3.h +++ b/cpu/esp32/include/periph_cpu_esp32c3.h @@ -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. */ /** diff --git a/cpu/esp32/include/periph_cpu_esp32s2.h b/cpu/esp32/include/periph_cpu_esp32s2.h index bffce78cfe..3890489cd1 100644 --- a/cpu/esp32/include/periph_cpu_esp32s2.h +++ b/cpu/esp32/include/periph_cpu_esp32s2.h @@ -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 */ diff --git a/cpu/esp32/include/periph_cpu_esp32s3.h b/cpu/esp32/include/periph_cpu_esp32s3.h index 32c68f6b7a..42bcca221b 100644 --- a/cpu/esp32/include/periph_cpu_esp32s3.h +++ b/cpu/esp32/include/periph_cpu_esp32s3.h @@ -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 */ diff --git a/cpu/esp32/include/sdkconfig_esp32.h b/cpu/esp32/include/sdkconfig_esp32.h index 481d3e0fc6..ea7af01f72 100644 --- a/cpu/esp32/include/sdkconfig_esp32.h +++ b/cpu/esp32/include/sdkconfig_esp32.h @@ -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 diff --git a/cpu/esp32/include/sdkconfig_esp32c3.h b/cpu/esp32/include/sdkconfig_esp32c3.h index 8262606731..6d78cec43b 100644 --- a/cpu/esp32/include/sdkconfig_esp32c3.h +++ b/cpu/esp32/include/sdkconfig_esp32c3.h @@ -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 diff --git a/cpu/esp32/periph/adc.c b/cpu/esp32/periph/adc.c index fc5dfb5339..b82a415e24 100644 --- a/cpu/esp32/periph/adc.c +++ b/cpu/esp32/periph/adc.c @@ -27,6 +27,7 @@ */ #include +#include #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) diff --git a/cpu/esp32/periph/adc_arch_esp32.c b/cpu/esp32/periph/adc_arch_esp32.c index 192ae2065b..f3860dd96d 100644 --- a/cpu/esp32/periph/adc_arch_esp32.c +++ b/cpu/esp32/periph/adc_arch_esp32.c @@ -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"); diff --git a/cpu/esp32/periph/adc_arch_esp32c3.c b/cpu/esp32/periph/adc_arch_esp32c3.c index 2961a83efa..0db3a1afb2 100644 --- a/cpu/esp32/periph/adc_arch_esp32c3.c +++ b/cpu/esp32/periph/adc_arch_esp32c3.c @@ -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"); diff --git a/cpu/esp32/periph/adc_arch_esp32s2.c b/cpu/esp32/periph/adc_arch_esp32s2.c index 7570dfaa79..3f11f33260 100644 --- a/cpu/esp32/periph/adc_arch_esp32s2.c +++ b/cpu/esp32/periph/adc_arch_esp32s2.c @@ -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"); diff --git a/cpu/esp32/periph/adc_arch_esp32s3.c b/cpu/esp32/periph/adc_arch_esp32s3.c index ea2e82a47c..cc9ce27d0e 100644 --- a/cpu/esp32/periph/adc_arch_esp32s3.c +++ b/cpu/esp32/periph/adc_arch_esp32s3.c @@ -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");