xtensa/esp32s3: Add support for GPIO pin interrupts

Signed-off-by: Gustavo Henrique Nihei <gustavo.nihei@espressif.com>
This commit is contained in:
Gustavo Henrique Nihei 2022-03-18 17:35:05 -03:00 committed by Masayuki Ishikawa
parent 0e67dc8637
commit 024364ebbd
5 changed files with 323 additions and 20 deletions

View File

@ -25,6 +25,12 @@
#ifndef __ARCH_XTENSA_INCLUDE_ESP32S3_IRQ_H
#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 */

View File

@ -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

View File

@ -49,6 +49,10 @@
* Private Data
****************************************************************************/
#ifdef CONFIG_ESP32S3_GPIO_IRQ
static int g_gpio_cpuint;
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
@ -74,6 +78,94 @@ static inline bool is_valid_gpio(uint32_t pin)
return pin <= 21 || (pin >= 26 && pin < ESP32S3_NPINS);
}
/****************************************************************************
* 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
****************************************************************************/
@ -274,6 +366,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
*

View File

@ -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
@ -130,6 +130,27 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* 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
*
@ -189,6 +210,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
*

View File

@ -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 */