This is an automated email from the ASF dual-hosted git repository. masayuki pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 024364ebbd0b0cac0cd467a7ad232616f8c22c45 Author: Gustavo Henrique Nihei <[email protected]> AuthorDate: Fri Mar 18 17:35:05 2022 -0300 xtensa/esp32s3: Add support for GPIO pin interrupts Signed-off-by: Gustavo Henrique Nihei <[email protected]> --- arch/xtensa/include/esp32s3/irq.h | 27 ++-- arch/xtensa/src/esp32s3/Kconfig | 6 + arch/xtensa/src/esp32s3/esp32s3_gpio.c | 223 +++++++++++++++++++++++++++++++++ arch/xtensa/src/esp32s3/esp32s3_gpio.h | 82 ++++++++++-- arch/xtensa/src/esp32s3/esp32s3_irq.c | 5 + 5 files changed, 323 insertions(+), 20 deletions(-) diff --git a/arch/xtensa/include/esp32s3/irq.h b/arch/xtensa/include/esp32s3/irq.h index fecdb3c..b379a22 100644 --- a/arch/xtensa/include/esp32s3/irq.h +++ b/arch/xtensa/include/esp32s3/irq.h @@ -26,6 +26,12 @@ #define __ARCH_XTENSA_INCLUDE_ESP32S3_IRQ_H /**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> + +/**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -309,19 +315,20 @@ #define ESP32S3_NIRQ_PERIPH ESP32S3_NPERIPHERALS -/* Second level GPIO interrupts. GPIO interrupts are decoded and dispatched - * as a second level of decoding: The first level dispatches to the GPIO - * interrupt handler. The second to the decoded GPIO interrupt handler. +#ifdef CONFIG_ESP32S3_GPIO_IRQ + +/* Second level GPIO interrupts. GPIO interrupts are decoded and dispatched + * as a second level of decoding: The first level dispatches to the GPIO + * interrupt handler. The second to the decoded GPIO interrupt handler. */ -#ifdef CONFIG_ESP32S3_GPIO_IRQ -# define ESP32S3_NIRQ_GPIO 40 -# define ESP32S3_FIRST_GPIOIRQ (XTENSA_NIRQ_INTERNAL + ESP32S3_NIRQ_PERIPH) -# define ESP32S3_LAST_GPIOIRQ (ESP32S3_FIRST_GPIOIRQ + ESP32S3_NIRQ_GPIO - 1) -# define ESP32S3_PIN2IRQ(p) ((p) + ESP32S3_FIRST_GPIOIRQ) -# define ESP32S3_IRQ2PIN(i) ((i) - ESP32S3_FIRST_GPIOIRQ) +# define ESP32S3_NIRQ_GPIO 49 +# define ESP32S3_FIRST_GPIOIRQ (XTENSA_NIRQ_INTERNAL + ESP32S3_NIRQ_PERIPH) +# define ESP32S3_LAST_GPIOIRQ (ESP32S3_FIRST_GPIOIRQ + ESP32S3_NIRQ_GPIO - 1) +# define ESP32S3_PIN2IRQ(p) ((p) + ESP32S3_FIRST_GPIOIRQ) +# define ESP32S3_IRQ2PIN(i) ((i) - ESP32S3_FIRST_GPIOIRQ) #else -# define ESP32S3_NIRQ_GPIO 0 +# define ESP32S3_NIRQ_GPIO 0 #endif /* Total number of interrupts */ diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig index ab7a142..d9896ab 100644 --- a/arch/xtensa/src/esp32s3/Kconfig +++ b/arch/xtensa/src/esp32s3/Kconfig @@ -511,6 +511,12 @@ config ESP32S3_SPIRAM_IGNORE_NOTFOUND endmenu # SPI RAM Configuration +config ESP32S3_GPIO_IRQ + bool "GPIO pin interrupts" + default n + ---help--- + Enable support for interrupting GPIO pins. + menu "UART Configuration" depends on ESP32S3_UART diff --git a/arch/xtensa/src/esp32s3/esp32s3_gpio.c b/arch/xtensa/src/esp32s3/esp32s3_gpio.c index c8f499d..c10948a 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_gpio.c +++ b/arch/xtensa/src/esp32s3/esp32s3_gpio.c @@ -49,6 +49,10 @@ * Private Data ****************************************************************************/ +#ifdef CONFIG_ESP32S3_GPIO_IRQ +static int g_gpio_cpuint; +#endif + /**************************************************************************** * Private Functions ****************************************************************************/ @@ -75,6 +79,94 @@ static inline bool is_valid_gpio(uint32_t pin) } /**************************************************************************** + * Name: gpio_dispatch + * + * Description: + * Second level dispatch for GPIO interrupt handling. + * + * Input Parameters: + * irq - GPIO IRQ number. + * status - Value from the GPIO interrupt status clear register. + * regs - Saved CPU context. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_GPIO_IRQ +static void gpio_dispatch(int irq, uint32_t status, uint32_t *regs) +{ + uint32_t mask; + int i; + + /* Check each bit in the status register */ + + for (i = 0; i < 32 && status != 0; i++) + { + /* Check if there is an interrupt pending for this pin */ + + mask = UINT32_C(1) << i; + if ((status & mask) != 0) + { + /* Yes... perform the second level dispatch */ + + irq_dispatch(irq + i, regs); + + /* Clear the bit in the status so that we might execute this loop + * sooner. + */ + + status &= ~mask; + } + } +} +#endif + +/**************************************************************************** + * Name: gpio_interrupt + * + * Description: + * GPIO interrupt handler. + * + * Input Parameters: + * irq - Identifier of the interrupt request. + * context - Context data from the ISR. + * arg - Opaque pointer to the internal driver state structure. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned + * on failure. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_GPIO_IRQ +static int gpio_interrupt(int irq, void *context, void *arg) +{ + uint32_t status; + + /* Read and clear the lower GPIO interrupt status */ + + status = getreg32(GPIO_STATUS_REG); + putreg32(status, GPIO_STATUS_W1TC_REG); + + /* Dispatch pending interrupts in the lower GPIO status register */ + + gpio_dispatch(ESP32S3_FIRST_GPIOIRQ, status, (uint32_t *)context); + + /* Read and clear the upper GPIO interrupt status */ + + status = getreg32(GPIO_STATUS1_REG); + putreg32(status, GPIO_STATUS1_W1TC_REG); + + /* Dispatch pending interrupts in the lower GPIO status register */ + + gpio_dispatch(ESP32S3_FIRST_GPIOIRQ + 32, status, (uint32_t *)context); + return OK; +} +#endif + +/**************************************************************************** * Public Functions ****************************************************************************/ @@ -275,6 +367,137 @@ bool esp32s3_gpioread(int pin) } /**************************************************************************** + * Name: esp32s3_gpioirqinitialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * GPIO pins. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_GPIO_IRQ +void esp32s3_gpioirqinitialize(void) +{ + int cpu; + + /* Setup the GPIO interrupt. */ + + cpu = up_cpu_index(); + + g_gpio_cpuint = esp32s3_setup_irq(cpu, ESP32S3_PERIPH_GPIO_INT_CPU, 1, + ESP32S3_CPUINT_LEVEL); + DEBUGASSERT(g_gpio_cpuint >= 0); + + /* Attach and enable the interrupt handler */ + + DEBUGVERIFY(irq_attach(ESP32S3_IRQ_GPIO_INT_CPU, gpio_interrupt, NULL)); + up_enable_irq(ESP32S3_IRQ_GPIO_INT_CPU); +} +#endif + +/**************************************************************************** + * Name: esp32s3_gpioirqenable + * + * Description: + * Enable the interrupt for the specified GPIO IRQ. + * + * Input Parameters: + * irq - Identifier of the interrupt request. + * intrtype - Interrupt type, select from gpio_intrtype_t. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_GPIO_IRQ +void esp32s3_gpioirqenable(int irq, gpio_intrtype_t intrtype) +{ + uintptr_t regaddr; + uint32_t regval; + int pin; + + DEBUGASSERT(irq >= ESP32S3_FIRST_GPIOIRQ && irq <= ESP32S3_LAST_GPIOIRQ); + + /* Convert the IRQ number to a pin number */ + + pin = ESP32S3_IRQ2PIN(irq); + + /* Disable the GPIO interrupt during the configuration. */ + + up_disable_irq(ESP32S3_IRQ_GPIO_INT_CPU); + + /* Get the address of the GPIO PIN register for this pin */ + + regaddr = GPIO_REG(pin); + regval = getreg32(regaddr); + regval &= ~(GPIO_PIN0_INT_ENA_M | GPIO_PIN0_INT_TYPE_M); + + /* Set the pin ENA field. + * On ESP32-S3, CPU0 and CPU1 share the same interrupt enable bit. + */ + + regval |= GPIO_PIN0_INT_ENA_M; + regval |= (uint32_t)intrtype << GPIO_PIN0_INT_TYPE_S; + putreg32(regval, regaddr); + + /* Configuration done. Re-enable the GPIO interrupt. */ + + up_enable_irq(ESP32S3_IRQ_GPIO_INT_CPU); +} +#endif + +/**************************************************************************** + * Name: esp32s3_gpioirqdisable + * + * Description: + * Disable the interrupt for the specified GPIO IRQ. + * + * Input Parameters: + * irq - Identifier of the interrupt request. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_GPIO_IRQ +void esp32s3_gpioirqdisable(int irq) +{ + uintptr_t regaddr; + uint32_t regval; + int pin; + + DEBUGASSERT(irq >= ESP32S3_FIRST_GPIOIRQ && irq <= ESP32S3_LAST_GPIOIRQ); + + /* Convert the IRQ number to a pin number */ + + pin = ESP32S3_IRQ2PIN(irq); + + /* Disable the GPIO interrupt during the configuration. */ + + up_disable_irq(ESP32S3_IRQ_GPIO_INT_CPU); + + /* Reset the pin ENA and TYPE fields */ + + regaddr = GPIO_REG(pin); + regval = getreg32(regaddr); + regval &= ~(GPIO_PIN0_INT_ENA_M | GPIO_PIN0_INT_TYPE_M); + putreg32(regval, regaddr); + + /* Configuration done. Re-enable the GPIO interrupt. */ + + up_enable_irq(ESP32S3_IRQ_GPIO_INT_CPU); +} +#endif + +/**************************************************************************** * Name: esp32s3_gpio_matrix_in * * Description: diff --git a/arch/xtensa/src/esp32s3/esp32s3_gpio.h b/arch/xtensa/src/esp32s3/esp32s3_gpio.h index 35367d2..7d2c203 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_gpio.h +++ b/arch/xtensa/src/esp32s3/esp32s3_gpio.h @@ -93,15 +93,6 @@ # define OUTPUT_FUNCTION_5 (OUTPUT_FUNCTION | FUNCTION_5) # define OUTPUT_FUNCTION_6 (OUTPUT_FUNCTION | FUNCTION_6) -/* Interrupt type used with esp32s3_gpioirqenable() */ - -#define DISABLED 0x00 -#define RISING 0x01 -#define FALLING 0x02 -#define CHANGE 0x03 -#define ONLOW 0x04 -#define ONHIGH 0x05 - /**************************************************************************** * Public Types ****************************************************************************/ @@ -111,7 +102,16 @@ /* Must be big enough to hold the above encodings */ typedef uint16_t gpio_pinattr_t; -typedef uint8_t gpio_intrtype_t; + +typedef enum gpio_intrtype_e +{ + GPIO_INTR_DISABLE = 0, /* Disable GPIO interrupt */ + GPIO_INTR_POSEDGE = 1, /* Rising edge */ + GPIO_INTR_NEGEDGE = 2, /* Falling edge */ + GPIO_INTR_ANYEDGE = 3, /* Both rising and falling edge */ + GPIO_INTR_LOW_LEVEL = 4, /* Input low level trigger */ + GPIO_INTR_HIGH_LEVEL = 5 /* Input high level trigger */ +} gpio_intrtype_t; /**************************************************************************** * Public Data @@ -131,6 +131,27 @@ extern "C" ****************************************************************************/ /**************************************************************************** + * Name: esp32s3_gpioirqinitialize + * + * Description: + * Initialize logic to support a second level of interrupt decoding for + * GPIO pins. + * + * Input Parameters: + * None. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_GPIO_IRQ +void esp32s3_gpioirqinitialize(void); +#else +# define esp32s3_gpioirqinitialize() +#endif + +/**************************************************************************** * Name: esp32s3_configgpio * * Description: @@ -190,6 +211,47 @@ void esp32s3_gpiowrite(int pin, bool value); bool esp32s3_gpioread(int pin); /**************************************************************************** + * Name: esp32s3_gpioirqenable + * + * Description: + * Enable the interrupt for the specified GPIO IRQ. + * + * Input Parameters: + * irq - Identifier of the interrupt request. + * intrtype - Interrupt type, select from gpio_intrtype_t. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_GPIO_IRQ +void esp32s3_gpioirqenable(int irq, gpio_intrtype_t intrtype); +#else +# define esp32s3_gpioirqenable(irq,intrtype) +#endif + +/**************************************************************************** + * Name: esp32s3_gpioirqdisable + * + * Description: + * Disable the interrupt for the specified GPIO IRQ. + * + * Input Parameters: + * irq - Identifier of the interrupt request. + * + * Returned Value: + * None. + * + ****************************************************************************/ + +#ifdef CONFIG_ESP32S3_GPIO_IRQ +void esp32s3_gpioirqdisable(int irq); +#else +# define esp32s3_gpioirqdisable(irq) +#endif + +/**************************************************************************** * Name: esp32s3_gpio_matrix_in * * Description: diff --git a/arch/xtensa/src/esp32s3/esp32s3_irq.c b/arch/xtensa/src/esp32s3/esp32s3_irq.c index 5e98d4b..c9f1d8e 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_irq.c +++ b/arch/xtensa/src/esp32s3/esp32s3_irq.c @@ -38,6 +38,7 @@ #include "xtensa.h" +#include "esp32s3_gpio.h" #include "esp32s3_irq.h" #ifdef CONFIG_SMP #include "esp32s3_smp.h" @@ -446,6 +447,10 @@ void up_irqinitialize(void) xtensa_attach_fromcpu1_interrupt(); #endif + /* Initialize GPIO interrupt support */ + + esp32s3_gpioirqinitialize(); + #ifndef CONFIG_SUPPRESS_INTERRUPTS /* And finally, enable interrupts. Also clears PS.EXCM */
