diff --git a/cpu/esp32/Kconfig b/cpu/esp32/Kconfig
index fb6255945e48..ad210220066d 100644
--- a/cpu/esp32/Kconfig
+++ b/cpu/esp32/Kconfig
@@ -17,7 +17,6 @@ config CPU_FAM_ESP32
select HAS_CPU_ESP32
select HAS_ESP_HW_COUNTER
select HAS_ESP_WIFI_ENTERPRISE
- select HAS_PERIPH_ADC_CTRL
select HAS_PUF_SRAM
select PACKAGE_ESP32_SDK if TEST_KCONFIG
@@ -81,11 +80,6 @@ config HAS_ESP_SPI_RAM
Indicates that an external RAM is connected via the FSPI interface in
the board.
-config HAS_PERIPH_ADC_CTRL
- bool
- help
- Indicates that an ESP32 ADC controller peripheral is present.
-
## Common CPU symbols
config CPU_CORE
default "xtensa-lx6" if CPU_CORE_XTENSA_LX6
diff --git a/cpu/esp32/Makefile.dep b/cpu/esp32/Makefile.dep
index f6ffdc9f99b5..ac05471ff7a9 100644
--- a/cpu/esp32/Makefile.dep
+++ b/cpu/esp32/Makefile.dep
@@ -60,16 +60,17 @@ ifneq (,$(filter esp_idf_nvs_flash,$(USEMODULE)))
USEMODULE += mtd
endif
-ifneq (,$(filter periph_rtc,$(USEMODULE)))
- FEATURES_OPTIONAL += esp_rtc_timer_32k
+ifneq (,$(filter esp_idf_wifi,$(USEMODULE)))
+ # add additional modules required by esp_idf_wifi
+ USEMODULE += esp_idf_adc
endif
-ifneq (,$(filter esp_rtc_timer_32k,$(FEATURES_USED)))
- USEMODULE += esp_rtc_timer_32k
+ifneq (,$(filter periph_rtc,$(USEMODULE)))
+ FEATURES_OPTIONAL += esp_rtc_timer_32k
endif
-ifneq (,$(filter periph_adc periph_dac,$(USEMODULE)))
- FEATURES_REQUIRED += periph_adc_ctrl
+ifneq (,$(filter esp_rtc_timer_32k,$(FEATURES_USED)))
+ USEMODULE += esp_rtc_timer_32k
endif
ifneq (,$(filter periph_gpio,$(USEMODULE)))
@@ -113,6 +114,10 @@ ifneq (,$(filter mtd,$(USEMODULE)))
USEMODULE += esp_idf_spi_flash
endif
+ifneq (,$(filter periph_adc,$(USEMODULE)))
+ USEMODULE += esp_idf_adc
+endif
+
ifneq (,$(filter periph_rtc,$(USEMODULE)))
USEMODULE += rtt_rtc
endif
diff --git a/cpu/esp32/Makefile.features b/cpu/esp32/Makefile.features
index 1add7ad52efa..5b38766fa0bb 100644
--- a/cpu/esp32/Makefile.features
+++ b/cpu/esp32/Makefile.features
@@ -7,7 +7,6 @@ include $(RIOTCPU)/esp_common/Makefile.features
FEATURES_PROVIDED += arch_esp32
FEATURES_PROVIDED += esp_wifi_enterprise
FEATURES_PROVIDED += esp_hw_counter
-FEATURES_PROVIDED += periph_adc_ctrl
FEATURES_PROVIDED += puf_sram
ifneq (,$(filter esp32-wrover%,$(CPU_MODEL)))
diff --git a/cpu/esp32/doc.txt b/cpu/esp32/doc.txt
index 4ccc18f10f2c..86ac27471f02 100644
--- a/cpu/esp32/doc.txt
+++ b/cpu/esp32/doc.txt
@@ -704,15 +704,15 @@ 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 with the `#adc_vref_to_gpio25` function at GPIO 25.
+ Vref of a device can be read with the `#adc_line_vref_to_gpio` function at GPIO 25.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
-extern int adc_vref_to_gpio25 (void);
+extern int adc_line_vref_to_gpio(adc_t line, gpio_t gpio);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For that purpose GPIO25 is initialized automatically as ADC channel and is connected internally to
Vref to measure the current voltage. Once the initialization is finished and the function returns
with success, the current voltage can be read from GPIO25. The results of the ADC input can then be
-adjusted accordingly. The `#adc_vref_to_gpio25` function can be used to determine the current
+adjusted accordingly. The `#adc_line_vref_to_gpio` function can be used to determine the current
voltage at ESP32.
[Back to table of contents](#esp32_toc)
diff --git a/cpu/esp32/esp-idf-api/adc.c b/cpu/esp32/esp-idf-api/adc.c
new file mode 100644
index 000000000000..46a11f535b23
--- /dev/null
+++ b/cpu/esp32/esp-idf-api/adc.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 Gunar Schorcht
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup cpu_esp32_esp_idf_api
+ * @{
+ *
+ * @file
+ * @brief Interface for the ESP-IDF ADC HAL API
+ *
+ * @author Gunar Schorcht
+ * @}
+ */
+
+#include
+
+#include "driver/adc.h"
+
+void esp_idf_adc_power_acquire(void)
+{
+ adc_power_acquire();
+}
+
+void esp_idf_adc_power_release(void)
+{
+ adc_power_release();
+}
+
+esp_err_t esp_idf_adc1_config_width(adc_bits_width_t width_bit)
+{
+ return adc1_config_width(width_bit);
+}
+
+esp_err_t esp_idf_adc1_config_channel_atten(adc_channel_t channel,
+ adc_atten_t atten)
+{
+ return adc1_config_channel_atten(channel, atten);
+}
+
+int esp_idf_adc1_get_raw(adc1_channel_t channel)
+{
+ return adc1_get_raw(channel);
+}
+
+esp_err_t esp_idf_adc2_config_channel_atten(adc_channel_t channel,
+ adc_atten_t atten)
+{
+ return adc2_config_channel_atten(channel, atten);
+}
+
+esp_err_t esp_idf_adc2_get_raw(adc2_channel_t channel,
+ adc_bits_width_t width_bit, int *raw_out)
+{
+ return adc2_get_raw(channel, width_bit, raw_out);
+}
+
+esp_err_t esp_idf_adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio)
+{
+ return adc_vref_to_gpio(adc_unit, gpio);
+}
diff --git a/cpu/esp32/esp-idf-api/dac.c b/cpu/esp32/esp-idf-api/dac.c
new file mode 100644
index 000000000000..33ff6cdd9f7b
--- /dev/null
+++ b/cpu/esp32/esp-idf-api/dac.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 Gunar Schorcht
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup cpu_esp32_esp_idf_api
+ * @{
+ *
+ * @file
+ * @brief Interface for the ESP-IDF DAC HAL API
+ *
+ * @author Gunar Schorcht
+ * @}
+ */
+
+#include
+
+#include "driver/dac_common.h"
+
+esp_err_t esp_idf_dac_output_voltage(dac_channel_t channel, uint8_t dac_value)
+{
+ return dac_output_voltage(channel, dac_value);
+}
+
+esp_err_t esp_idf_dac_output_enable(dac_channel_t channel)
+{
+ return dac_output_enable(channel);
+}
+
+esp_err_t esp_idf_dac_output_disable(dac_channel_t channel)
+{
+ return dac_output_disable(channel);
+}
diff --git a/cpu/esp32/esp-idf/Kconfig b/cpu/esp32/esp-idf/Kconfig
index fe7498c16b37..86b10841dd04 100644
--- a/cpu/esp32/esp-idf/Kconfig
+++ b/cpu/esp32/esp-idf/Kconfig
@@ -17,6 +17,7 @@ config MODULE_ESP_IDF
help
Espressif IoT Development Framework.
+rsource "adc/Kconfig"
rsource "common/Kconfig"
rsource "efuse/Kconfig"
rsource "eth/Kconfig"
diff --git a/cpu/esp32/esp-idf/Makefile b/cpu/esp32/esp-idf/Makefile
index c33857881d36..9dccfe8d6cca 100644
--- a/cpu/esp32/esp-idf/Makefile
+++ b/cpu/esp32/esp-idf/Makefile
@@ -4,6 +4,10 @@ export ESP_IDF_PATH = $(shell pwd)
# Add a list of subdirectories, that should also be built:
+ifneq (,$(filter esp_idf_adc,$(USEMODULE)))
+ DIRS += adc
+endif
+
ifneq (,$(filter esp_idf_common,$(USEMODULE)))
DIRS += common
endif
diff --git a/cpu/esp32/esp-idf/adc/Kconfig b/cpu/esp32/esp-idf/adc/Kconfig
new file mode 100644
index 000000000000..c58ed528aeef
--- /dev/null
+++ b/cpu/esp32/esp-idf/adc/Kconfig
@@ -0,0 +1,16 @@
+# Copyright (c) 2022 Gunar Schorcht
+#
+# This file is subject to the terms and conditions of the GNU Lesser
+# General Public License v2.1. See the file LICENSE in the top level
+# directory for more details.
+#
+
+config MODULE_ESP_IDF_ADC
+ bool
+ depends on TEST_KCONFIG
+ depends on MODULE_ESP_IDF
+
+ default y if MODULE_PERIPH_ADC
+
+ help
+ ESP-IDF code for ADC peripherals.
diff --git a/cpu/esp32/esp-idf/adc/Makefile b/cpu/esp32/esp-idf/adc/Makefile
new file mode 100644
index 000000000000..c0d17f9e8766
--- /dev/null
+++ b/cpu/esp32/esp-idf/adc/Makefile
@@ -0,0 +1,25 @@
+MODULE = esp_idf_adc
+
+# source files to be compiled for this module
+ESP32_SDK_SRC = \
+ components/driver/adc.c \
+ components/driver/adc_common.c \
+ components/hal/adc_hal.c \
+ components/soc/$(CPU)/adc_periph.c \
+ #
+
+ifneq (,$(filter esp32c3 esp32s3,$(CPU)))
+ ESP32_SDK_SRC += components/driver/$(CPU)/adc2_init_cal.c
+ INCLUDES += -I$(ESP32_SDK_DIR)/components/driver/include/driver
+endif
+
+ifneq (,$(filter esp32c3 esp32h2 esp32s3,$(CPU)))
+ ESP32_SDK_SRC += components/efuse/$(CPU)/esp_efuse_rtc_calib.c
+endif
+
+include $(RIOTBASE)/Makefile.base
+
+ESP32_SDK_BIN = $(BINDIR)/$(MODULE)
+
+include ../esp_idf.mk
+include ../esp_idf_cflags.mk
diff --git a/cpu/esp32/esp-idf/wifi/Kconfig b/cpu/esp32/esp-idf/wifi/Kconfig
index 7609e8dbe93a..f971e02809dc 100644
--- a/cpu/esp32/esp-idf/wifi/Kconfig
+++ b/cpu/esp32/esp-idf/wifi/Kconfig
@@ -9,5 +9,8 @@ config MODULE_ESP_IDF_WIFI
bool
depends on TEST_KCONFIG
depends on MODULE_ESP_IDF
+
+ select MODULE_ESP_IDF_ADC
+
help
ESP-IDF code required for accessing the WiFi interface.
diff --git a/cpu/esp32/include/adc_arch.h b/cpu/esp32/include/adc_arch.h
index ec167c250815..7601ea11262c 100644
--- a/cpu/esp32/include/adc_arch.h
+++ b/cpu/esp32/include/adc_arch.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 Gunar Schorcht
+ * Copyright (C) 2022 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@@ -11,7 +11,14 @@
* @{
*
* @file
- * @brief Architecture specific ADC functions for ESP32
+ * @brief Architecture specific ADC definitions and functions for ESP32
+ *
+ * All ESP32x SoCs have two SAR ADC units each. However, these have
+ * functionalities as well as specific properties that vary between the
+ * ESP32x SoC and therefore require different handling for each ESP32x SoC.
+ * This is already taken into account in the high-level API of the ESP-IDF.
+ * To avoid having to reimplement these specifics and the different handling,
+ * the high-level API of the ESP-IDF is used directly for the ADC peripherals.
*
* @author Gunar Schorcht
* @}
@@ -24,17 +31,25 @@
extern "C" {
#endif
-#include "periph/gpio.h"
#include "periph/adc.h"
+#include "periph/gpio.h"
+
+#include "hal/adc_types.h"
+
+#include "esp_idf_api/adc.h"
/**
* @brief Attenuations that can be set for ADC lines
+ *
+ * Event though ESP-IDF type `adc_atten_t` and `ADC_ATTEN_DB_*` are used
+ * now, the `adc_attenuation_t` type with constants `ADC_ATTENUATION_*_DB` are
+ * kept for compatibility.
*/
typedef enum {
- ADC_ATTENUATION_0_DB = 0, /**< full-range is about 1.1 V (Vref) */
- ADC_ATTENUATION_3_DB, /**< full-range is about 1.5 V */
- ADC_ATTENUATION_6_DB, /**< full-range is about 2.2 V */
- ADC_ATTENUATION_11_DB /**< full-range is about 3.3 V */
+ ADC_ATTENUATION_0_DB = ADC_ATTEN_DB_0, /**< full-range is about 1.1 V (Vref) */
+ ADC_ATTENUATION_3_DB = ADC_ATTEN_DB_2_5, /**< full-range is about 1.5 V */
+ ADC_ATTENUATION_6_DB = ADC_ATTEN_DB_6, /**< full-range is about 2.2 V */
+ ADC_ATTENUATION_11_DB = ADC_ATTEN_DB_11, /**< full-range is about 3.3 V */
} adc_attenuation_t;
/**
@@ -51,32 +66,57 @@ typedef enum {
*
* Attenuation | Voltage Range | Symbol
* ----------------|-------------------|----------------------
- * 0 dB | 0 ... 1.1V (Vref) | ADC_ATTENUATION_0_DB
- * 3 dB | 0 ... 1.5V | ADC_ATTENUATION_3_DB
- * 6 dB | 0 ... 2.2V | ADC_ATTENUATION_6_DB
- * 11 dB (default) | 0 ... 3.3V | ADC_ATTENUATION_11_DB
+ * 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
+ * 11 dB (default) | 0 ... 3.3V | ADC_ATTEN_DB_11
*
*
*
- * Please 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 with the
- * function *adc_vref_to_gpio25* at the pin GPIO 25. The results of the ADC
- * input can then be adjusted accordingly.
+ * @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.
*
* @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 invalid ADC line
+ * @return 0 on success
+ * @return -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
+ *
+ * The Vref of the ADC unit of the given ADC line is routed to a GPIO pin n.
+ * This allows to measure the Vref used by the ADC unit to adjusted the
+ * results of the conversions accordingly.
+ *
+ * @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.
+ *
+ * @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)
+ *
+ * @return 0 on success
+ * @return -1 on error
*/
-int adc_set_attenuation(adc_t line, adc_attenuation_t atten);
+int adc_line_vref_to_gpio(adc_t line, gpio_t gpio);
+#if defined(MCU_ESP32)
/**
* @brief Output ADC reference voltage to GPIO25
*
+ * This function is deprecated and will be removed in future versions.
+ *
* @return 0 on success
* @return -1 on invalid ADC line
*/
-int adc_vref_to_gpio25 (void);
+static inline int adc_vref_to_gpio25 (void)
+{
+ return esp_idf_adc_vref_to_gpio(ADC_UNIT_2, GPIO25);
+}
+#endif
#ifdef __cplusplus
}
diff --git a/cpu/esp32/include/adc_arch_private.h b/cpu/esp32/include/adc_arch_private.h
new file mode 100644
index 000000000000..f0b36854eefd
--- /dev/null
+++ b/cpu/esp32/include/adc_arch_private.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 Gunar Schorcht
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup cpu_esp32
+ * @{
+ *
+ * @file
+ * @brief Architecture specific internal ADC functions for ESP32
+ *
+ * @author Gunar Schorcht
+ * @}
+ */
+
+#ifndef ADC_ARCH_PRIVATE_H
+#define ADC_ARCH_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hal/adc_types.h"
+#include "periph/gpio.h"
+
+#ifndef DOXYGEN /* hide implementation details from doxygen */
+
+#define RTCIO_GPIO(n) n /* n-th RTCIO GPIO */
+#define RTCIO_NA UINT8_MAX /* RTCIO pin not available */
+
+/**
+ * @brief ADC hardware descriptor (for internal use only)
+ */
+typedef struct {
+ uint8_t rtc_gpio; /**< RTC GPIO number */
+ gpio_t gpio; /**< GPIO */
+ adc_unit_t adc_ctrl; /**< ADC controller */
+ adc_channel_t adc_channel; /**< channel of ADC controller */
+ char* pad_name; /**< symbolic name of pad */
+} _adc_hw_desc_t;
+
+/**
+ * @brief ADC hardware descriptor table (for internal use only)
+ *
+ * @note The index of entries in the table MUST correspond to the
+ * RTCIO GPIO number.
+ */
+extern const _adc_hw_desc_t _adc_hw[];
+
+/**
+ * @brief GPIO to RTC IO map (for internal use only)
+ */
+extern const gpio_t _gpio_rtcio_map[];
+
+#endif /* !DOXYGEN */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ADC_ARCH_PRIVATE_H */
diff --git a/cpu/esp32/include/adc_ctrl.h b/cpu/esp32/include/adc_ctrl.h
deleted file mode 100644
index 856fa7cd4022..000000000000
--- a/cpu/esp32/include/adc_ctrl.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2019 Gunar Schorcht
- *
- * This file is subject to the terms and conditions of the GNU Lesser
- * General Public License v2.1. See the file LICENSE in the top level
- * directory for more details.
- */
-
-/**
- * @ingroup cpu_esp32
- * @{
- *
- * @file
- * @brief ADC controller functions used by ADC and DAC peripherals
- *
- * @author Gunar Schorcht
- * @}
- */
-
-#ifndef ADC_CTRL_H
-#define ADC_CTRL_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "periph/gpio.h"
-
-/**
- * @brief ADC controllers
- */
-enum {
- ADC1_CTRL, /**< ADC1 controller */
- ADC2_CTRL /**< ADC2 controller */
-};
-
-/**
- * @brief RTC IO pin type (does not correspond to RTC gpio num order)
- */
-enum {
-
- RTCIO_TOUCH0 = 0, /**< touch sensor 0 */
- RTCIO_TOUCH1, /**< touch sensor 1 */
- RTCIO_TOUCH2, /**< touch sensor 2 */
- RTCIO_TOUCH3, /**< touch sensor 3 */
- RTCIO_TOUCH4, /**< touch sensor 4 */
- RTCIO_TOUCH5, /**< touch sensor 5 */
- RTCIO_TOUCH6, /**< touch sensor 6 */
- RTCIO_TOUCH7, /**< touch sensor 7 */
- RTCIO_TOUCH8, /**< touch sensor 8, 32K_XP */
- RTCIO_TOUCH9, /**< touch sensor 9, 32K_XN */
-
- RTCIO_ADC_ADC1, /**< VDET_1 */
- RTCIO_ADC_ADC2, /**< VDET_2 */
-
- RTCIO_SENSOR_SENSE1, /**< SENSOR_VP */
- RTCIO_SENSOR_SENSE2, /**< SENSOR_CAPP */
- RTCIO_SENSOR_SENSE3, /**< SENSOR_CAPN */
- RTCIO_SENSOR_SENSE4, /**< SENSOR_VN */
-
- RTCIO_DAC1, /**< DAC output */
- RTCIO_DAC2, /**< DAC output */
-
- RTCIO_NA, /**< RTC pad not available */
-};
-
-/**
- * @brief ADC pin hardware information type (for internal use only)
- */
-struct _adc_hw_t {
- gpio_t gpio; /**< GPIO */
- uint8_t rtc_gpio; /**< corresponding RTC GPIO */
- uint8_t adc_ctrl; /**< ADC controller */
- uint8_t adc_channel; /**< channel of ADC controller */
- char* pad_name; /**< symbolic name of pad */
-};
-
-/**
- * @brief RTC hardware map
- *
- * The index corresponds to RTC pin type _rtcio_pin_t (Table 19 in Technical
- * Reference)
- */
-extern const struct _adc_hw_t _adc_hw[];
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ADC_CTRL_H */
diff --git a/cpu/esp32/include/esp_idf_api/adc.h b/cpu/esp32/include/esp_idf_api/adc.h
new file mode 100644
index 000000000000..5ddaac5f0424
--- /dev/null
+++ b/cpu/esp32/include/esp_idf_api/adc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 Gunar Schorcht
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup cpu_esp32_esp_idf_api
+ * @{
+ *
+ * @file
+ * @brief Interface for the ESP-IDF ADC HAL API
+ *
+ * @author Gunar Schorcht
+ * @}
+ */
+
+#ifndef ESP_IDF_API_ADC_H
+#define ESP_IDF_API_ADC_H
+
+#include "esp_err.h"
+#include "hal/adc_types.h"
+#include "hal/gpio_types.h"
+
+#ifndef DOXYGEN /* Hide implementation details from doxygen */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name ESP-IDF interface mapper functions
+ * @{
+ */
+/** @} */
+void esp_idf_adc_power_acquire(void);
+void esp_idf_adc_power_release(void);
+
+esp_err_t esp_idf_adc1_config_width(adc_bits_width_t width_bit);
+esp_err_t esp_idf_adc1_config_channel_atten(adc_channel_t channel,
+ adc_atten_t atten);
+int esp_idf_adc1_get_raw(adc_channel_t channel);
+
+esp_err_t esp_idf_adc2_config_channel_atten(adc_channel_t channel,
+ adc_atten_t atten);
+esp_err_t esp_idf_adc2_get_raw(adc_channel_t channel,
+ adc_bits_width_t width_bit, int *raw_out);
+esp_err_t esp_idf_adc_vref_to_gpio(adc_unit_t adc_unit, gpio_num_t gpio);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* ESP_IDF_API_ADC_H */
diff --git a/cpu/esp32/include/esp_idf_api/dac.h b/cpu/esp32/include/esp_idf_api/dac.h
new file mode 100644
index 000000000000..8ee0b7de9c48
--- /dev/null
+++ b/cpu/esp32/include/esp_idf_api/dac.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 Gunar Schorcht
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser
+ * General Public License v2.1. See the file LICENSE in the top level
+ * directory for more details.
+ */
+
+/**
+ * @ingroup cpu_esp32_esp_idf_api
+ * @{
+ *
+ * @file
+ * @brief Interface for the ESP-IDF DAC HAL API
+ *
+ * @author Gunar Schorcht
+ * @}
+ */
+
+#ifndef ESP_IDF_API_DAC_H
+#define ESP_IDF_API_DAC_H
+
+#include "esp_err.h"
+#include "hal/dac_types.h"
+
+#ifndef DOXYGEN /* Hide implementation details from doxygen */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @name ESP-IDF interface wrapper functions
+ * @{
+ */
+esp_err_t esp_idf_dac_output_voltage(dac_channel_t channel, uint8_t dac_value);
+esp_err_t esp_idf_dac_output_enable(dac_channel_t channel);
+esp_err_t esp_idf_dac_output_disable(dac_channel_t channel);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* DOXYGEN */
+#endif /* ESP_IDF_API_DAC_H */
diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h
index a1b1c6097d27..27df8c8f2597 100644
--- a/cpu/esp32/include/periph_cpu.h
+++ b/cpu/esp32/include/periph_cpu.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 Gunar Schorcht
+ * Copyright (C) 2022 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@@ -243,24 +243,6 @@ typedef enum {
* @{
*/
-#ifndef DOXYGEN
-/**
- * @brief Possible ADC resolution settings
- */
-#define HAVE_ADC_RES_T
-typedef enum {
- ADC_RES_6BIT = 0xf0, /**< ADC resolution: 6 bit is not supported */
- ADC_RES_8BIT = 0xf1, /**< ADC resolution: 8 bit is not supported */
- ADC_RES_9BIT = 0, /**< ADC resolution: 9 bit */
- ADC_RES_10BIT = 1, /**< ADC resolution: 10 bit */
- ADC_RES_11BIT = 2, /**< ADC resolution: 11 bit */
- ADC_RES_12BIT = 3, /**< ADC resolution: 12 bit */
- ADC_RES_14BIT = 0xf2, /**< ADC resolution: 14 bit is not supported */
- ADC_RES_16BIT = 0xf3, /**< ADC resolution: 16 bit is not supported */
-} adc_res_t;
-/** @} */
-#endif /* ndef DOXYGEN */
-
/**
* @brief Number of ADC channels that could be used at maximum
*
@@ -268,7 +250,7 @@ typedef enum {
* therefore not usable. The maximum number of ADC channels (ADC_NUMOF_MAX)
* is therefore set to 16.
*/
-#define ADC_NUMOF_MAX 16
+#define ADC_NUMOF_MAX (SOC_ADC_CHANNEL_NUM(0) + SOC_ADC_CHANNEL_NUM(1))
/** @} */
@@ -299,7 +281,7 @@ typedef enum {
/**
* @brief Number of DAC channels that could be used at maximum.
*/
-#define DAC_NUMOF_MAX 2
+#define DAC_NUMOF_MAX (SOC_DAC_PERIPH_NUM)
/** @} */
diff --git a/cpu/esp32/periph/Kconfig b/cpu/esp32/periph/Kconfig
index dd1baac47460..3003eb3a45ae 100644
--- a/cpu/esp32/periph/Kconfig
+++ b/cpu/esp32/periph/Kconfig
@@ -14,11 +14,6 @@ config MODULE_ESP_RTC_TIMER_32K
help
Use RTC timer with external 32.768 kHz crystal as RTT.
-config MODULE_PERIPH_ADC_CTRL
- bool
- depends on HAS_PERIPH_ADC_CTRL
- default y if MODULE_PERIPH_ADC || MODULE_PERIPH_DAC
-
config MODULE_PERIPH_RTT_HW_SYS
bool
default y if MODULE_PERIPH_RTT
diff --git a/cpu/esp32/periph/Makefile b/cpu/esp32/periph/Makefile
index ad23cff8259e..c0f49828dd1c 100644
--- a/cpu/esp32/periph/Makefile
+++ b/cpu/esp32/periph/Makefile
@@ -1,5 +1,9 @@
MODULE = periph
+ifneq (,$(filter periph_adc periph_dac,$(USEMODULE)))
+ SRC += adc_arch.c
+endif
+
ifneq (,$(filter periph_gpio,$(USEMODULE)))
SRC += gpio_arch.c
endif
diff --git a/cpu/esp32/periph/adc.c b/cpu/esp32/periph/adc.c
index 1b88ac05604a..8acb739bf7ef 100644
--- a/cpu/esp32/periph/adc.c
+++ b/cpu/esp32/periph/adc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 Gunar Schorcht
+ * Copyright (C) 2022 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
@@ -14,61 +14,115 @@
* @file
* @brief Low-level ADC driver implementation
*
+ * All ESP32x SoCs have two SAR ADC units each. However, these have
+ * functionalities as well as specific properties that vary between the
+ * ESP32x SoC and therefore require different handling for each ESP32x SoC.
+ * This is already taken into account in the high-level API of the ESP-IDF.
+ * To avoid having to reimplement these specifics and the different handling,
+ * the high-level API of the ESP-IDF is used directly for the ADC peripherals.
+ *
* @author Gunar Schorcht
*
* @}
*/
+#include
+
#include "board.h"
#include "periph/adc.h"
#include "adc_arch.h"
-#include "adc_ctrl.h"
+#include "adc_arch_private.h"
#include "esp_common.h"
#include "gpio_arch.h"
-#include "soc/rtc_io_struct.h"
-#include "soc/rtc_cntl_struct.h"
-#include "soc/sens_reg.h"
-#include "soc/sens_struct.h"
+
+#include "esp_idf_api/adc.h"
#define ENABLE_DEBUG 0
#include "debug.h"
-/* declaration of external functions */
-extern void _adc1_ctrl_init(void);
-extern void _adc2_ctrl_init(void);
-
/* forward declarations of internal functions */
static bool _adc_conf_check(void);
-static void _adc_module_init(void);
-static bool _adc_module_initialized = false;
+static void _adc1_ctrl_init(void);
+static void _adc2_ctrl_init(void);
/* external variable declarations */
extern const gpio_t _gpio_rtcio_map[];
+/*
+ * 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_esp_res_map_t;
+
+/*
+ * Table for resolution mapping
+ */
+_adc_esp_res_map_t _adc_esp_res_map[] = {
+#if defined(MCU_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_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 */
+#elif SOC_ADC_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 */
+#endif
+};
+
+static bool _adc_module_initialized = false;
+
+static inline void _adc1_ctrl_init(void)
+{
+ /* nothing to do for the moment */
+}
+
+static inline void _adc2_ctrl_init(void)
+{
+ /* nothing to do for the moment */
+}
+
int adc_init(adc_t line)
{
- CHECK_PARAM_RET (line < ADC_NUMOF, -1)
+ DEBUG("[adc] line=%u\n", line);
+
+ if (line >= ADC_NUMOF) {
+ return -1;
+ }
if (!_adc_module_initialized) {
/* do some configuration checks */
if (!_adc_conf_check()) {
return -1;
}
- _adc_module_init();
_adc_module_initialized = true;
}
+ /* get the RTCIO pin number for the given GPIO defined as ADC channel */
uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]];
- if (_adc_hw[rtcio].adc_ctrl == ADC1_CTRL) {
- _adc1_ctrl_init();
- }
- if (_adc_hw[rtcio].adc_ctrl == ADC2_CTRL) {
- _adc2_ctrl_init();
+ /* check whether the GPIO is avalid ADC channel pin */
+ if (rtcio == RTCIO_NA) {
+ return -1;
}
- /* try to initialize the pin as ADC input */
+ /* 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 "
"ADC input\n", _adc_hw[rtcio].gpio,
@@ -76,73 +130,25 @@ int adc_init(adc_t line)
return -1;
}
- uint8_t idx;
-
- /* disable the pad output */
- RTCIO.enable_w1tc.val = BIT(_adc_hw[rtcio].rtc_gpio);
-
- /* route pads to RTC and if possible, disable input, pull-up/pull-down */
- switch (rtcio) {
- case RTCIO_SENSOR_SENSE1: /* GPIO36, RTC0 */
- RTCIO.sensor_pads.sense1_mux_sel = 1; /* route to RTC */
- RTCIO.sensor_pads.sense1_fun_sel = 0; /* function ADC1_CH0 */
- break;
- case RTCIO_SENSOR_SENSE2: /* GPIO37, RTC1 */
- RTCIO.sensor_pads.sense2_mux_sel = 1; /* route to RTC */
- RTCIO.sensor_pads.sense2_fun_sel = 0; /* function ADC1_CH1 */
- break;
- case RTCIO_SENSOR_SENSE3: /* GPIO38, RTC2 */
- RTCIO.sensor_pads.sense3_mux_sel = 1; /* route to RTC */
- RTCIO.sensor_pads.sense3_fun_sel = 0; /* function ADC1_CH2 */
- break;
- case RTCIO_SENSOR_SENSE4: /* GPIO39, RTC3 */
- RTCIO.sensor_pads.sense4_mux_sel = 1; /* route to RTC */
- RTCIO.sensor_pads.sense4_fun_sel = 0; /* function ADC1_CH3 */
- break;
-
- case RTCIO_TOUCH0: /* GPIO4, RTC10 */
- case RTCIO_TOUCH1: /* GPIO0, RTC11 */
- case RTCIO_TOUCH2: /* GPIO2, RTC12 */
- case RTCIO_TOUCH3: /* GPIO15, RTC13 */
- case RTCIO_TOUCH4: /* GPIO13, RTC14 */
- case RTCIO_TOUCH5: /* GPIO12, RTC15 */
- case RTCIO_TOUCH6: /* GPIO14, RTC16 */
- case RTCIO_TOUCH7: /* GPIO27, RTC17 */
- case RTCIO_TOUCH8: /* GPIO33, RTC8 */
- case RTCIO_TOUCH9: /* GPIO32, RTC9 */
- idx = rtcio - RTCIO_TOUCH0;
- RTCIO.touch_pad[idx].mux_sel = 1; /* route to RTC */
- RTCIO.touch_pad[idx].fun_sel = 0; /* function ADC2_CH0..ADC2_CH9 */
- RTCIO.touch_pad[idx].fun_ie = 0; /* input disabled */
- RTCIO.touch_pad[idx].rue = 0; /* pull-up disabled */
- RTCIO.touch_pad[idx].rde = 0; /* pull-down disabled */
- RTCIO.touch_pad[idx].xpd = 0; /* touch sensor powered off */
- break;
-
- case RTCIO_ADC_ADC1: /* GPIO34, RTC4 */
- RTCIO.adc_pad.adc1_mux_sel = 1; /* route to RTC */
- RTCIO.adc_pad.adc1_fun_sel = 0; /* function ADC1_CH6 */
- break;
- case RTCIO_ADC_ADC2: /* GPIO35, RTC5 */
- RTCIO.adc_pad.adc2_mux_sel = 1; /* route to RTC */
- RTCIO.adc_pad.adc2_fun_sel = 0; /* function ADC1_CH7 */
- break;
-
- case RTCIO_DAC1: /* GPIO25, RTC6 */
- case RTCIO_DAC2: /* GPIO26, RTC7 */
- idx = rtcio - RTCIO_DAC1;
- RTCIO.pad_dac[idx].mux_sel = 1; /* route to RTC */
- RTCIO.pad_dac[idx].fun_sel = 0; /* function ADC2_CH8, ADC2_CH9 */
- RTCIO.pad_dac[idx].fun_ie = 0; /* input disabled */
- RTCIO.pad_dac[idx].rue = 0; /* pull-up disabled */
- RTCIO.pad_dac[idx].rde = 0; /* pull-down disabled */
- RTCIO.pad_dac[idx].xpd_dac = 0; /* DAC powered off */
- break;
-
- default: return -1;
+ if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) {
+ /* initialize the ADC1 unit if needed */
+ _adc1_ctrl_init();
+ /* set the attenuation and configure its associated GPIO pin mux */
+ esp_idf_adc1_config_channel_atten(_adc_hw[rtcio].adc_channel,
+ ADC_ATTEN_DB_11);
+ }
+ else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) {
+ /* initialize the ADC2 unit if needed */
+ _adc2_ctrl_init();
+ /* set the attenuation and configure its associated GPIO pin mux */
+ esp_idf_adc2_config_channel_atten(_adc_hw[rtcio].adc_channel,
+ ADC_ATTEN_DB_11);
+ }
+ else {
+ return -1;
}
- /* set pin usage type */
+ /* set pin usage type */
gpio_set_pin_usage(_adc_hw[rtcio].gpio, _ADC);
return 0;
@@ -150,96 +156,84 @@ int adc_init(adc_t line)
int32_t adc_sample(adc_t line, adc_res_t res)
{
- CHECK_PARAM_RET (line < ADC_NUMOF, -1)
- CHECK_PARAM_RET (res <= ADC_RES_12BIT, -1)
-
- uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]];
-
- if (_adc_hw[rtcio].adc_ctrl == ADC1_CTRL) {
- /* set the resolution for the measurement */
- SENS.sar_start_force.sar1_bit_width = res;
- SENS.sar_read_ctrl.sar1_sample_bit = res;
-
- /* enable the pad in the pad enable bitmap */
- SENS.sar_meas_start1.sar1_en_pad = (1 << _adc_hw[rtcio].adc_channel);
- while (SENS.sar_slave_addr1.meas_status != 0) {}
+ DEBUG("[adc] line=%u res=%u\n", line, res);
- /* start measurement by toggling the start bit and wait until the
- measurement has been finished */
- SENS.sar_meas_start1.meas1_start_sar = 0;
- SENS.sar_meas_start1.meas1_start_sar = 1;
- while (SENS.sar_meas_start1.meas1_done_sar == 0) {}
-
- /* read out the result and return */
- return SENS.sar_meas_start1.meas1_data_sar;
+ if (_adc_esp_res_map[res].res == ADC_WIDTH_MAX) {
+ return -1;
}
- else {
- /* set the resolution for the measurement */
- SENS.sar_start_force.sar2_bit_width = res;
- SENS.sar_read_ctrl2.sar2_sample_bit = res;
-
- /* enable the pad in the pad enable bitmap */
- SENS.sar_meas_start2.sar2_en_pad = (1 << _adc_hw[rtcio].adc_channel);
- /* start measurement by toggling the start bit and wait until the
- measurement has been finished */
- SENS.sar_meas_start2.meas2_start_sar = 0;
- SENS.sar_meas_start2.meas2_start_sar = 1;
- while (SENS.sar_meas_start2.meas2_done_sar == 0) {}
+ uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]];
+ int raw;
- /* read out the result and return */
- return SENS.sar_meas_start2.meas2_data_sar;
+ if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) {
+ esp_idf_adc1_config_width(_adc_esp_res_map[res].res);
+ raw = esp_idf_adc1_get_raw(_adc_hw[rtcio].adc_channel);
+ if (raw < 0) {
+ return -1;
+ }
+ }
+ else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) {
+ if (esp_idf_adc2_get_raw(_adc_hw[rtcio].adc_channel,
+ _adc_esp_res_map[res].res, &raw) < 0) {
+ return -1;
+ }
}
+
+ return raw >> _adc_esp_res_map[res].shift;
}
-int adc_set_attenuation(adc_t line, adc_attenuation_t atten)
+int adc_set_attenuation(adc_t line, adc_atten_t atten)
{
- CHECK_PARAM_RET (line < ADC_NUMOF, -1)
+ DEBUG("[adc] line=%u atten=%u\n", line, atten);
uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]];
- if (_adc_hw[rtcio].adc_ctrl == ADC1_CTRL) {
- SENS.sar_atten1 &= ~(0x3 << (_adc_hw[rtcio].adc_channel << 1));
- SENS.sar_atten1 |= (atten << (_adc_hw[rtcio].adc_channel << 1));
+ assert(rtcio != RTCIO_NA);
+
+ if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_1) {
+ return esp_idf_adc1_config_channel_atten(_adc_hw[rtcio].adc_channel,
+ atten);
}
- else {
- SENS.sar_atten2 &= ~(0x3 << (_adc_hw[rtcio].adc_channel << 1));
- SENS.sar_atten2 |= (atten << (_adc_hw[rtcio].adc_channel << 1));
+ else if (_adc_hw[rtcio].adc_ctrl == ADC_UNIT_2) {
+ return esp_idf_adc2_config_channel_atten(_adc_hw[rtcio].adc_channel,
+ atten);
}
- return 0;
+
+ return -1;
}
-int adc_vref_to_gpio25 (void)
+int adc_line_vref_to_gpio(adc_t line, gpio_t gpio)
{
- /* determine ADC line for GPIO25 */
- adc_t line = ADC_UNDEF;
- for (unsigned i = 0; i < ADC_NUMOF; i++) { \
- if (adc_channels[i] == GPIO25) { \
- line = i;
- break;
- }
- }
+ uint8_t rtcio_vref = _gpio_rtcio_map[adc_channels[line]];
+ uint8_t rtcio_out = _gpio_rtcio_map[gpio];
- if (line == ADC_UNDEF) {
- LOG_TAG_ERROR("adc", "Have no ADC line for GPIO25\n");
- return -1;
- }
+ /* 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;
- if (adc_init(line) == 0)
- {
- uint8_t rtcio = _gpio_rtcio_map[adc_channels[line]];
- RTCCNTL.bias_conf.dbg_atten = 0;
- RTCCNTL.test_mux.dtest_rtc = 1;
- RTCCNTL.test_mux.ent_rtc = 1;
- SENS.sar_start_force.sar2_en_test = 1;
- SENS.sar_meas_start2.sar2_en_pad = (1 << _adc_hw[rtcio].adc_channel);
- LOG_TAG_INFO("adc", "You can now measure Vref at GPIO25\n");
- return 0;
+ /* the GPIO for the output must be a channel of ADC2 */
+ assert(_adc_hw[rtcio_out].adc_ctrl == ADC_UNIT_2);
+
+ esp_err_t res = ESP_OK;
+
+ if (_adc_hw[rtcio_vref].adc_ctrl == ADC_UNIT_1) {
+ res = esp_idf_adc_vref_to_gpio(ADC_UNIT_1, gpio);
}
- else {
- LOG_TAG_ERROR("adc", "Could not init GPIO25 as Vref output\n");
+ else if (_adc_hw[rtcio_vref].adc_ctrl == ADC_UNIT_2) {
+ res = esp_idf_adc_vref_to_gpio(ADC_UNIT_2, gpio);
+ }
+ if (res != ESP_OK) {
+ LOG_TAG_ERROR("adc", "Could not route Vref of ADC line %d to GPIO%d\n",
+ line, gpio);
return -1;
}
+ 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;
+ }
}
static bool _adc_conf_check(void)
@@ -255,18 +249,6 @@ static bool _adc_conf_check(void)
return true;
}
-static void _adc_module_init(void)
-{
- RTCIO.enable_w1tc.val = ~0x0;
-
- /* always power on */
- SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU;
-
- /* disable temperature sensor */
- SENS.sar_tctrl.tsens_power_up_force = 1; /* controlled by SW */
- SENS.sar_tctrl.tsens_power_up = 0; /* power down */
-}
-
void adc_print_config(void)
{
printf("\tADC\t\tpins=[ ");
diff --git a/cpu/esp32/periph/adc_arch.c b/cpu/esp32/periph/adc_arch.c
new file mode 100644
index 000000000000..1a9182be2152
--- /dev/null
+++ b/cpu/esp32/periph/adc_arch.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 Gunar Schorcht
+ *
+ * This file is subject to the terms and conditions of the GNU Lesser General
+ * Public License v2.1. See the file LICENSE in the top level directory for more
+ * details.
+ */
+
+/**
+ * @ingroup cpu_esp32
+ * @{
+ *
+ * @file
+ * @brief Architecture-specific ADC/DAC definitions for ESP32 variant (family)
+ *
+ * @author Gunar Schorcht
+ *
+ * @}
+ */
+
+#include "board.h"
+
+#include "adc_arch_private.h"
+#include "esp_common.h"
+#include "soc/adc_channel.h"
+
+
+#define ENABLE_DEBUG 0
+#include "debug.h"
+
+/**
+ * @brief ADC hardware descriptor table (for internal use only)
+ *
+ * Reference: Technical Reference Manual, Section 4.11 Table 19
+ * https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf
+ *
+ * @note The index of entries in the table MUST correspond to the
+ * RTCIO GPIO number.
+ */
+const _adc_hw_desc_t _adc_hw[] = {
+ /* rtcio, gpio, adc_ctrl, adc_channel, pad_name */
+ { RTCIO_GPIO(0), ADC1_CHANNEL_0_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_0, "SENSOR_VP" },
+ { RTCIO_GPIO(1), ADC1_CHANNEL_1_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_1, "SENSOR_CAPP" },
+ { RTCIO_GPIO(2), ADC1_CHANNEL_2_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_2, "SENSOR_CAPN" },
+ { RTCIO_GPIO(3), ADC1_CHANNEL_3_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_3, "SENSOR_VN" },
+ { RTCIO_GPIO(4), ADC1_CHANNEL_6_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_6, "VDET_1" },
+ { RTCIO_GPIO(5), ADC1_CHANNEL_7_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_7, "VDET_2" },
+ { RTCIO_GPIO(6), ADC2_CHANNEL_8_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_8, "GPIO25" },
+ { RTCIO_GPIO(7), ADC2_CHANNEL_9_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_9, "GPIO26" },
+ { RTCIO_GPIO(8), ADC1_CHANNEL_5_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_5, "32K_XN" },
+ { RTCIO_GPIO(9), ADC1_CHANNEL_4_GPIO_NUM, ADC_UNIT_1, ADC_CHANNEL_4, "32K_XP" },
+ { RTCIO_GPIO(10), ADC2_CHANNEL_0_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_0, "GPIO4" },
+ { RTCIO_GPIO(11), ADC2_CHANNEL_1_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_1, "GPIO0" },
+ { RTCIO_GPIO(12), ADC2_CHANNEL_2_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_2, "GPIO2" },
+ { RTCIO_GPIO(13), ADC2_CHANNEL_3_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_3, "MTDO" },
+ { RTCIO_GPIO(14), ADC2_CHANNEL_4_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_4, "MTCK" },
+ { RTCIO_GPIO(15), ADC2_CHANNEL_5_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_5, "MTDI" },
+ { RTCIO_GPIO(16), ADC2_CHANNEL_6_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_6, "MTMS" },
+ { RTCIO_GPIO(17), ADC2_CHANNEL_7_GPIO_NUM, ADC_UNIT_2, ADC_CHANNEL_7, "GPIO27" },
+};
+
+/**
+ * @brief GPIO to RTC IO map (for internal use only)
+ *
+ * Reference: Technical Reference Manual, Section 4.11 Table 19
+ * https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf
+ */
+const gpio_t _gpio_rtcio_map[] = {
+ RTCIO_GPIO(11), /* GPIO0 */
+ RTCIO_NA, /* GPIO1 */
+ RTCIO_GPIO(12), /* GPIO2 */
+ RTCIO_NA, /* GPIO3 */
+ RTCIO_GPIO(10), /* GPIO4 */
+ RTCIO_NA, /* GPIO5 */
+ RTCIO_NA, /* GPIO6 */
+ RTCIO_NA, /* GPIO7 */
+ RTCIO_NA, /* GPIO8 */
+ RTCIO_NA, /* GPIO9 */
+ RTCIO_NA, /* GPIO10 */
+ RTCIO_NA, /* GPIO11 */
+ RTCIO_GPIO(15), /* GPIO12 MTDI */
+ RTCIO_GPIO(14), /* GPIO13 MTCK */
+ RTCIO_GPIO(16), /* GPIO14 MTMS */
+ RTCIO_GPIO(13), /* GPIO15 MTDO */
+ RTCIO_NA, /* GPIO16 */
+ RTCIO_NA, /* GPIO17 */
+ RTCIO_NA, /* GPIO18 */
+ RTCIO_NA, /* GPIO19 */
+ RTCIO_NA, /* GPIO20 */
+ RTCIO_NA, /* GPIO21 */
+ RTCIO_NA, /* GPIO22 */
+ RTCIO_NA, /* GPIO23 */
+ RTCIO_NA, /* GPIO24 */
+ RTCIO_GPIO(6), /* GPIO25 */
+ RTCIO_GPIO(7), /* GPIO26 */
+ RTCIO_GPIO(17), /* GPIO27 */
+ RTCIO_NA, /* GPIO28 */
+ RTCIO_NA, /* GPIO29 */
+ RTCIO_NA, /* GPIO30 */
+ RTCIO_NA, /* GPIO31 */
+ RTCIO_GPIO(9), /* GPIO32 32K_XP */
+ RTCIO_GPIO(8), /* GPIO33 32K_XN */
+ RTCIO_GPIO(4), /* GPIO34 VDET_1 */
+ RTCIO_GPIO(5), /* GPIO35 VDET_2 */
+ RTCIO_GPIO(0), /* GPIO36 SENSOR_VP */
+ RTCIO_GPIO(1), /* GPIO37 SENSOR_CAPP */
+ RTCIO_GPIO(2), /* GPIO38 SENSOR_CAPN */
+ RTCIO_GPIO(3), /* GPIO39 SENSOR_VN */
+};
diff --git a/cpu/esp32/periph/adc_ctrl.c b/cpu/esp32/periph/adc_ctrl.c
deleted file mode 100644
index 2c7655157897..000000000000
--- a/cpu/esp32/periph/adc_ctrl.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2019 Gunar Schorcht
- *
- * This file is subject to the terms and conditions of the GNU Lesser General
- * Public License v2.1. See the file LICENSE in the top level directory for more
- * details.
- */
-
-/**
- * @ingroup cpu_esp32
- * @{
- *
- * @file
- * @brief ADC controller functions used by ADC and DAC peripherals
- *
- * @author Gunar Schorcht
- *
- * @}
- */
-
-#include "board.h"
-
-#include "adc_ctrl.h"
-#include "esp_common.h"
-#include "soc/rtc_io_struct.h"
-#include "soc/rtc_cntl_struct.h"
-#include "soc/sens_reg.h"
-#include "soc/sens_struct.h"
-
-#define ENABLE_DEBUG 0
-#include "debug.h"
-
-/**
- * @brief RTC hardware map
- *
- * The index corresponds to RTC pin type _rtcio_pin_t (Table 19 in Technical
- * Reference)
- */
-const struct _adc_hw_t _adc_hw[] =
-{
- /* gpio rtc_gpio adc_ctrl adc_channel, pad_name */
- { GPIO4, 10, ADC2_CTRL, 0, "GPIO4" }, /* RTCIO_TOUCH0 */
- { GPIO0, 11, ADC2_CTRL, 1, "GPIO0" }, /* RTCIO_TOUCH1 */
- { GPIO2, 12, ADC2_CTRL, 2, "GPIO2" }, /* RTCIO_TOUCH2 */
- { GPIO15, 13, ADC2_CTRL, 3, "MTDO" }, /* RTCIO_TOUCH3 */
- { GPIO13, 14, ADC2_CTRL, 4, "MTCK" }, /* RTCIO_TOUCH4 */
- { GPIO12, 15, ADC2_CTRL, 5, "MTDI" }, /* RTCIO_TOUCH5 */
- { GPIO14, 16, ADC2_CTRL, 6, "MTMS" }, /* RTCIO_TOUCH6 */
- { GPIO27, 17, ADC2_CTRL, 7, "GPIO27" }, /* RTCIO_TOUCH7 */
- { GPIO33, 8, ADC1_CTRL, 5, "32K_XN" }, /* RTCIO_TOUCH8 */
- { GPIO32, 9, ADC1_CTRL, 4, "32K_XP" }, /* RTCIO_TOUCH9 */
- { GPIO34, 4, ADC1_CTRL, 6, "VDET_1" }, /* RTCIO_ADC_ADC1 */
- { GPIO35, 5, ADC1_CTRL, 7, "VDET_2" }, /* RTCIO_ADC_ADC2 */
- { GPIO36, 0, ADC1_CTRL, 0, "SENSOR_VP" }, /* RTCIO_SENSOR_SENSE1 */
- { GPIO37, 1, ADC1_CTRL, 1, "SENSOR_CAPP" }, /* RTCIO_SENSOR_SENSE2 */
- { GPIO38, 2, ADC1_CTRL, 2, "SENSOR_CAPN" }, /* RTCIO_SENSOR_SENSE3 */
- { GPIO39, 3, ADC1_CTRL, 3, "SENSOR_VN" }, /* RTCIO_SENSOR_SENSE4 */
- { GPIO25, 6, ADC2_CTRL, 8, "GPIO25" }, /* RTCIO_DAC1 */
- { GPIO26, 7, ADC2_CTRL, 9, "GPIO26" } /* RTCIO_DAC2 */
-};
-
-/* maps GPIO pin to RTC pin, this index is used to access ADC hardware table
- (Table 19 in Technical Reference) */
-const gpio_t _gpio_rtcio_map[] = {
- RTCIO_TOUCH1, /* GPIO0 */
- RTCIO_NA , /* GPIO1 */
- RTCIO_TOUCH2, /* GPIO2 */
- RTCIO_NA, /* GPIO3 */
- RTCIO_TOUCH0, /* GPIO4 */
- RTCIO_NA, /* GPIO5 */
- RTCIO_NA, /* GPIO6 */
- RTCIO_NA, /* GPIO7 */
- RTCIO_NA, /* GPIO8 */
- RTCIO_NA, /* GPIO9 */
- RTCIO_NA, /* GPIO10 */
- RTCIO_NA, /* GPIO11 */
- RTCIO_TOUCH5, /* GPIO12 MTDI */
- RTCIO_TOUCH4, /* GPIO13 MTCK */
- RTCIO_TOUCH6, /* GPIO14 MTMS */
- RTCIO_TOUCH3, /* GPIO15 MTDO */
- RTCIO_NA, /* GPIO16 */
- RTCIO_NA, /* GPIO17 */
- RTCIO_NA, /* GPIO18 */
- RTCIO_NA, /* GPIO19 */
- RTCIO_NA, /* GPIO20 */
- RTCIO_NA, /* GPIO21 */
- RTCIO_NA, /* GPIO22 */
- RTCIO_NA, /* GPIO23 */
- RTCIO_NA, /* GPIO24 */
- RTCIO_DAC1, /* GPIO25 */
- RTCIO_DAC2, /* GPIO26 */
- RTCIO_TOUCH7, /* GPIO27 */
- RTCIO_NA, /* GPIO28 */
- RTCIO_NA, /* GPIO29 */
- RTCIO_NA, /* GPIO30 */
- RTCIO_NA, /* GPIO31 */
- RTCIO_TOUCH9, /* GPIO32 32K_XP */
- RTCIO_TOUCH8, /* GPIO33 32K_XN */
- RTCIO_ADC_ADC1, /* GPIO34 VDET_1 */
- RTCIO_ADC_ADC2, /* GPIO35 VDET_2 */
- RTCIO_SENSOR_SENSE1, /* GPIO36 SENSOR_VP */
- RTCIO_SENSOR_SENSE2, /* GPIO37 SENSOR_CAPP */
- RTCIO_SENSOR_SENSE3, /* GPIO38 SENSOR_CAPN */
- RTCIO_SENSOR_SENSE4, /* GPIO39 SENSOR_VN */
-};
-
-/* flags to indicate whether the according controller is already initialized */
-static bool _adc1_ctrl_initialized = false;
-static bool _adc2_ctrl_initialized = false;
-
-void _adc1_ctrl_init(void)
-{
- /* return if already initialized */
- if (_adc1_ctrl_initialized) {
- return;
- }
-
- /* always power on */
- SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU;
-
- /* power off LN amp */
- SENS.sar_meas_wait2.sar2_rstb_wait = 2;
- SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0;
- SENS.sar_meas_ctrl.amp_short_ref_fsm = 0;
- SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0;
- SENS.sar_meas_wait1.sar_amp_wait1 = 1;
- SENS.sar_meas_wait1.sar_amp_wait2 = 1;
- SENS.sar_meas_wait2.sar_amp_wait3 = 1;
- SENS.sar_meas_wait2.force_xpd_amp = SENS_FORCE_XPD_AMP_PD;
-
- /* SAR ADC1 controller configuration */
- SENS.sar_read_ctrl.sar1_dig_force = 0; /* SAR ADC1 controlled by RTC */
- SENS.sar_meas_start1.meas1_start_force = 1; /* SAR ADC1 started by SW */
- SENS.sar_meas_start1.sar1_en_pad_force = 1; /* pad enable bitmap controlled by SW */
- SENS.sar_touch_ctrl1.xpd_hall_force = 1; /* XPD HALL is controlled by SW */
- SENS.sar_touch_ctrl1.hall_phase_force = 1; /* HALL PHASE is controlled by SW */
- SENS.sar_read_ctrl.sar1_data_inv = 1; /* invert data */
- SENS.sar_atten1 = 0xffffffff; /* set attenuation to 11 dB for all pads
- (input range 0 ... 3,3 V) */
- /* power off built-in hall sensor */
- RTCIO.hall_sens.xpd_hall = 0;
-
- /* set default resolution */
- SENS.sar_start_force.sar1_bit_width = ADC_RES_12BIT;
- SENS.sar_read_ctrl.sar1_sample_bit = ADC_RES_12BIT;
-
- _adc1_ctrl_initialized = true;
-}
-
-void _adc2_ctrl_init(void)
-{
- /* return if already initialized */
- if (_adc2_ctrl_initialized) {
- return;
- }
-
- /* SAR ADC2 controller configuration */
- SENS.sar_read_ctrl2.sar2_dig_force = 0; /* SAR ADC2 controlled by RTC not DIG*/
- SENS.sar_meas_start2.meas2_start_force = 1; /* SAR ADC2 started by SW */
- SENS.sar_meas_start2.sar2_en_pad_force = 1; /* pad enable bitmap controlled by SW */
- SENS.sar_read_ctrl2.sar2_data_inv = 1; /* invert data */
- SENS.sar_atten2 = 0xffffffff; /* set attenuation to 11 dB for all pads
- (input range 0 ... 3,3 V) */
- /* set default resolution */
- SENS.sar_start_force.sar2_bit_width = ADC_RES_12BIT;
- SENS.sar_read_ctrl2.sar2_sample_bit = ADC_RES_12BIT;
-
- _adc2_ctrl_initialized = true;
-}
diff --git a/cpu/esp32/periph/dac.c b/cpu/esp32/periph/dac.c
index d17fff3a22c0..4ee55d92ac7d 100644
--- a/cpu/esp32/periph/dac.c
+++ b/cpu/esp32/periph/dac.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 Gunar Schorcht
+ * Copyright (C) 2022 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser General
* Public License v2.1. See the file LICENSE in the top level directory for more
@@ -22,108 +22,73 @@
#include "board.h"
#include "periph/dac.h"
-#include "adc_arch.h"
-#include "adc_ctrl.h"
#include "esp_common.h"
-#include "gpio_arch.h"
-#include "soc/rtc_io_struct.h"
-#include "soc/rtc_cntl_struct.h"
-#include "soc/sens_reg.h"
-#include "soc/sens_struct.h"
+#include "soc/dac_periph.h"
+#include "esp_idf_api/dac.h"
#define ENABLE_DEBUG 0
#include "debug.h"
-/* declaration of external functions */
-extern void _adc2_ctrl_init(void);
-
/* forward declarations of internal functions */
static bool _dac_conf_check(void);
static bool _dac_module_initialized = false;
-/* external variable declarations */
-extern const gpio_t _gpio_rtcio_map[];
+/* RIOT DAC line to ESP-IDF channel map, filled during initialization */
+dac_channel_t _dac_channels[DAC_NUMOF] = { DAC_CHANNEL_MAX };
-int8_t dac_init (dac_t line)
+int8_t dac_init(dac_t line)
{
- CHECK_PARAM_RET (line < DAC_NUMOF, DAC_NOLINE)
-
if (!_dac_module_initialized) {
- /* do some configuration checks */
+ /* do some configuration checks and fill _dac_channel */
if (!_dac_conf_check()) {
return DAC_NOLINE;
}
_dac_module_initialized = true;
}
- _adc2_ctrl_init();
-
- uint8_t rtcio = _gpio_rtcio_map[dac_channels[line]];
- uint8_t idx;
-
- /* try to initialize the pin as DAC output */
- if (gpio_get_pin_usage(_adc_hw[rtcio].gpio) != _GPIO) {
- LOG_TAG_ERROR("dac", "GPIO%d is used for %s and cannot be used as "
- "DAC output\n", _adc_hw[rtcio].gpio,
- gpio_get_pin_usage_str(_adc_hw[rtcio].gpio));
+ if ((line >= DAC_NUMOF) || (_dac_channels[line] == DAC_CHANNEL_MAX)) {
+ LOG_TAG_ERROR("dac", "Line %u is an invalid DAC line\n", line);
return DAC_NOLINE;
}
- /* disable the output of the pad */
- RTCIO.enable_w1tc.val = BIT(_adc_hw[rtcio].rtc_gpio);
-
- switch (rtcio) {
- case RTCIO_DAC1: /* GPIO25, RTC6 */
- case RTCIO_DAC2: /* GPIO26, RTC7 */
- idx = rtcio - RTCIO_DAC1;
- RTCIO.pad_dac[idx].mux_sel = 1; /* route to RTC */
- RTCIO.pad_dac[idx].fun_sel = 0; /* function ADC2_CH8, ADC2_CH9 */
- RTCIO.pad_dac[idx].fun_ie = 0; /* input disabled */
- RTCIO.pad_dac[idx].rue = 0; /* pull-up disabled */
- RTCIO.pad_dac[idx].rde = 0; /* pull-down disabled */
-
- RTCIO.pad_dac[idx].dac_xpd_force = 1; /* use RTC pad not the FSM*/
- RTCIO.pad_dac[idx].xpd_dac = 1; /* DAC powered on */
- break;
-
- default: return DAC_NOLINE;
- }
-
- /* set pin usage type */
- gpio_set_pin_usage(_adc_hw[rtcio].gpio, _DAC);
-
- /* don't use DMA */
- SENS.sar_dac_ctrl1.dac_dig_force = 0;
-
- /* disable CW generators and invert DAC signal */
- SENS.sar_dac_ctrl1.sw_tone_en = 0;
- SENS.sar_dac_ctrl2.dac_cw_en1 = 0;
- SENS.sar_dac_ctrl2.dac_cw_en2 = 0;
+ dac_poweron(line);
+ dac_set(line, 0);
return DAC_OK;
}
-void dac_set (dac_t line, uint16_t value)
+void dac_set(dac_t line, uint16_t value)
{
- CHECK_PARAM (line < DAC_NUMOF);
- RTCIO.pad_dac[_gpio_rtcio_map[dac_channels[line]] - RTCIO_DAC1].dac = value >> 8;
+ assert(line < DAC_NUMOF);
+ assert(_dac_channels[line] != DAC_CHANNEL_MAX);
+ esp_idf_dac_output_voltage(_dac_channels[line],
+ value >> (16 - SOC_DAC_RESOLUTION));
}
-void dac_poweroff (dac_t line)
+void dac_poweroff(dac_t line)
{
- CHECK_PARAM (line < DAC_NUMOF);
+ assert(line < DAC_NUMOF);
+ assert(_dac_channels[line] != DAC_CHANNEL_MAX);
+ esp_idf_dac_output_disable(_dac_channels[line]);
}
-void dac_poweron (dac_t line)
+void dac_poweron(dac_t line)
{
- CHECK_PARAM (line < DAC_NUMOF);
+ assert(line < DAC_NUMOF);
+ assert(_dac_channels[line] != DAC_CHANNEL_MAX);
+ esp_idf_dac_output_enable(_dac_channels[line]);
}
static bool _dac_conf_check(void)
{
for (unsigned i = 0; i < DAC_NUMOF; i++) {
- if (_gpio_rtcio_map[dac_channels[i]] != RTCIO_DAC1 &&
- _gpio_rtcio_map[dac_channels[i]] != RTCIO_DAC2) {
+ for (unsigned j = 0; i < SOC_DAC_PERIPH_NUM; j++) {
+ if (dac_channels[i] == dac_periph_signal.dac_channel_io_num[j]) {
+ _dac_channels[i] = j;
+ break;
+ }
+ }
+ if (_dac_channels[i] == DAC_CHANNEL_MAX) {
LOG_TAG_ERROR("dac", "GPIO%d cannot be used as DAC line\n",
dac_channels[i]);
return false;