diff --git a/cpu/esp32/Kconfig.esp32 b/cpu/esp32/Kconfig.esp32 index 260874d7e8..d339a71184 100644 --- a/cpu/esp32/Kconfig.esp32 +++ b/cpu/esp32/Kconfig.esp32 @@ -18,6 +18,9 @@ config CPU_FAM_ESP32 select HAS_ESP_HW_COUNTER select HAS_ESP_WIFI_ENTERPRISE select HAS_PERIPH_GPIO_LL + select HAS_PERIPH_GPIO_LL_IRQ + select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH + select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW select HAS_PUF_SRAM select PACKAGE_ESP32_SDK if TEST_KCONFIG diff --git a/cpu/esp32/Kconfig.esp32c3 b/cpu/esp32/Kconfig.esp32c3 index a68b951d66..b3a8ed8976 100644 --- a/cpu/esp32/Kconfig.esp32c3 +++ b/cpu/esp32/Kconfig.esp32c3 @@ -19,6 +19,9 @@ config CPU_FAM_ESP32C3 select HAS_ESP_BLE_ESP32C3 select HAS_ESP_WIFI_ENTERPRISE select HAS_PERIPH_GPIO_LL + select HAS_PERIPH_GPIO_LL_IRQ + select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH + select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW select HAS_PUF_SRAM select PACKAGE_ESP32_SDK if TEST_KCONFIG diff --git a/cpu/esp32/Kconfig.esp32s2 b/cpu/esp32/Kconfig.esp32s2 index 28c652301d..25755f8ef7 100644 --- a/cpu/esp32/Kconfig.esp32s2 +++ b/cpu/esp32/Kconfig.esp32s2 @@ -14,6 +14,9 @@ config CPU_FAM_ESP32S2 select HAS_ESP_HW_COUNTER select HAS_ESP_WIFI_ENTERPRISE select HAS_PERIPH_GPIO_LL + select HAS_PERIPH_GPIO_LL_IRQ + select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH + select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW select HAS_PUF_SRAM select PACKAGE_ESP32_SDK if TEST_KCONFIG diff --git a/cpu/esp32/Kconfig.esp32s3 b/cpu/esp32/Kconfig.esp32s3 index 387dcbe1d4..4d9730aaad 100644 --- a/cpu/esp32/Kconfig.esp32s3 +++ b/cpu/esp32/Kconfig.esp32s3 @@ -20,6 +20,9 @@ config CPU_FAM_ESP32S3 select HAS_ESP_HW_COUNTER select HAS_ESP_WIFI_ENTERPRISE select HAS_PERIPH_GPIO_LL + select HAS_PERIPH_GPIO_LL_IRQ + select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_HIGH + select HAS_PERIPH_GPIO_LL_IRQ_LEVEL_TRIGGERED_LOW select HAS_PUF_SRAM select PACKAGE_ESP32_SDK if TEST_KCONFIG diff --git a/cpu/esp32/Makefile.features b/cpu/esp32/Makefile.features index bcbd3163fb..21cf627c88 100644 --- a/cpu/esp32/Makefile.features +++ b/cpu/esp32/Makefile.features @@ -18,6 +18,9 @@ include $(RIOTCPU)/esp_common/Makefile.features FEATURES_PROVIDED += arch_esp32 FEATURES_PROVIDED += esp_wifi_enterprise FEATURES_PROVIDED += periph_gpio_ll +FEATURES_PROVIDED += periph_gpio_ll_irq +FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_high +FEATURES_PROVIDED += periph_gpio_ll_irq_level_triggered_low FEATURES_PROVIDED += puf_sram ifeq (xtensa,$(CPU_ARCH)) diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index aaa275f164..a3d419bbb4 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -207,6 +207,16 @@ typedef enum { #define GPIO_DRIVE_20 GPIO_DRIVE_STRONG /**< 20 mA (default) */ #define GPIO_DRIVE_30 GPIO_DRIVE_STRONGEST /**< 30 mA */ +#define HAVE_GPIO_IRQ_TRIG_T +typedef enum { + GPIO_TRIGGER_NONE = 0, + GPIO_TRIGGER_EDGE_RISING = 1, + GPIO_TRIGGER_EDGE_FALLING = 2, + GPIO_TRIGGER_EDGE_BOTH = 3, + GPIO_TRIGGER_LEVEL_LOW = 4, + GPIO_TRIGGER_LEVEL_HIGH = 5 +} gpio_irq_trig_t; + /* END: GPIO LL overwrites */ #endif /* ndef DOXYGEN */ diff --git a/cpu/esp32/periph/gpio_ll_irq.c b/cpu/esp32/periph/gpio_ll_irq.c new file mode 100644 index 0000000000..cd461a15dc --- /dev/null +++ b/cpu/esp32/periph/gpio_ll_irq.c @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2021 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 + * @ingroup drivers_periph_gpio_ll_irq + * @{ + * + * @file + * @brief IRQ implementation of the GPIO Low-Level API for ESP32 + * + * @author Gunar Schorcht + * @} + */ + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#include +#include + +#include "log.h" +#include "periph/gpio_ll_irq.h" + +#include "esp/common_macros.h" +#include "esp_intr_alloc.h" +#include "hal/gpio_hal.h" +#include "hal/gpio_types.h" +#include "rom/ets_sys.h" + +#if __xtensa__ +#include "xtensa/xtensa_api.h" +#endif + +#include "esp_idf_api/gpio.h" + +#include "irq_arch.h" + +#if MODULE_PERIPH_GPIO_IRQ +/* variables that have to be used together with periph/gpio_irq */ +extern bool gpio_int_enabled_table[]; +extern bool gpio_isr_service_installed; +#else +bool gpio_int_enabled_table[GPIO_PIN_NUMOF] = { }; +bool gpio_isr_service_installed = false; +#endif + +extern void IRAM gpio_int_handler(void* arg); + +int gpio_ll_irq(gpio_port_t port, uint8_t pin, gpio_irq_trig_t trig, + gpio_ll_cb_t cb, void *arg) +{ + assert(port); + assert(arg); + assert(GPIO_PORT_NUM(port) < GPIO_PORT_NUMOF); + assert(pin < GPIO_PORT_PIN_NUMOF(port)); + + unsigned state = irq_disable(); + + gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin); + + DEBUG("%s gpio=%u port=%u pin=%u trig=%d cb=%p arg=%p\n", + __func__, gpio, GPIO_PORT_NUM(port), pin, trig, cb, arg); + + /* install GPIO ISR of ESP-IDF if not yet done */ + if (!gpio_isr_service_installed && + esp_idf_gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1) != ESP_OK) { + return -1; + } + gpio_isr_service_installed = true; + + /* set the interrupt type for the pin */ + if (esp_idf_gpio_set_intr_type(gpio, trig) != ESP_OK) { + return -1; + } + + /* add interrupt handler for the pin */ + if (esp_idf_gpio_isr_handler_add(gpio, cb, arg) != ESP_OK) { + return -1; + } + + /* unmask and clear pending interrupts for the pin */ + gpio_ll_irq_unmask_and_clear(port, pin); + + irq_restore(state); + + return 0; +} + +void gpio_ll_irq_mask(gpio_port_t port, uint8_t pin) +{ + gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin); + + DEBUG("%s gpio=%u port=%u pin=%u\n", + __func__, gpio, GPIO_PORT_NUM(port), pin); + + if (esp_idf_gpio_intr_disable(gpio) == ESP_OK) { + gpio_int_enabled_table[gpio] = false; + } +} + +void gpio_ll_irq_unmask(gpio_port_t port, uint8_t pin) +{ + gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin); + + DEBUG("%s gpio=%u port=%u pin=%u\n", + __func__, gpio, port, pin); + + if (esp_idf_gpio_intr_enable(gpio) == ESP_OK) { + gpio_int_enabled_table[gpio] = true; + } +} + +void gpio_ll_irq_unmask_and_clear(gpio_port_t port, uint8_t pin) +{ + _esp32_port_t *p = (_esp32_port_t *)port; + gpio_t gpio = GPIO_PIN(GPIO_PORT_NUM(port), pin); + + DEBUG("%s gpio=%u port=%u pin=%u\n", + __func__, gpio, GPIO_PORT_NUM(port), pin); + + *p->status_w1tc = BIT(pin); + if (esp_idf_gpio_intr_enable(gpio) == ESP_OK) { + gpio_int_enabled_table[gpio] = true; + } +}