Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/esp32: use ESP-IDF interrupt handling API #18261

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion cpu/esp32/include/irq_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,22 @@ extern "C" {
#define CPU_INUM_GPIO 2 /**< Level interrupt with low priority 1 */
#define CPU_INUM_CAN 3 /**< Level interrupt with low priority 1 */
#define CPU_INUM_UART 5 /**< Level interrupt with low priority 1 */
#define CPU_INUM_RTC 9 /**< Level interrupt with low priority 1 */
#define CPU_INUM_RTT 9 /**< Level interrupt with low priority 1 */
#define CPU_INUM_I2C 12 /**< Level interrupt with low priority 1 */
#define CPU_INUM_WDT 13 /**< Level interrupt with low priority 1 */
#define CPU_INUM_SOFTWARE 17 /**< Level interrupt with low priority 1 */
#define CPU_INUM_ETH 18 /**< Level interrupt with low priority 1 */
#define CPU_INUM_TIMER 19 /**< Level interrupt with medium priority 2 */
#define CPU_INUM_FRC2 20 /**< Level interrupt with medium priority 2 */
#define CPU_INUM_SYSTIMER 20 /**< Level interrupt with medium priority 2 */
#define CPU_INUM_CACHEERR 25 /**< Level interrupt with high priority 4 */
/** @} */

/**
* @brief Initialize architecture specific interrupt handling
*/
void esp_irq_init(void);

#ifdef __cplusplus
}
#endif
Expand Down
137 changes: 95 additions & 42 deletions cpu/esp32/irq_arch.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -19,58 +19,101 @@
*/

#include "irq_arch.h"

#include "esp_attr.h"
#include "esp_err.h"
#include "esp32/rom/ets_sys.h"
#include "soc/dport_reg.h"
#include "xtensa/xtensa_api.h"
#include "freertos/FreeRTOS.h"
#include "hal/interrupt_controller_types.h"
#include "hal/interrupt_controller_ll.h"
#include "rom/ets_sys.h"
#include "soc/periph_defs.h"
#include "esp_intr_alloc.h"

#define ENABLE_DEBUG 0
#include "debug.h"

struct _irq_alloc_table_t {
int src; /* peripheral interrupt source */
uint32_t intr; /* interrupt number */
#ifndef ETS_CAN_INTR_SOURCE
#define ETS_CAN_INTR_SOURCE ETS_TWAI_INTR_SOURCE
#endif

typedef struct intr_handle_data_t {
int src; /* peripheral interrupt source */
uint8_t intr; /* interrupt number */
uint8_t level;
} intr_handle_data_t;

/* TODO change to a clearer approach */
static const struct intr_handle_data_t _irq_data_table[] = {
{ ETS_FROM_CPU_INTR0_SOURCE, CPU_INUM_SOFTWARE, 1 },
{ ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT, 1 },
{ ETS_TG0_T0_LEVEL_INTR_SOURCE, CPU_INUM_RTT, 1 },
#if defined(MCU_ESP32) || defined(MCU_ESP32S2) || defined(MCU_ESP32S3)
benpicco marked this conversation as resolved.
Show resolved Hide resolved
{ ETS_TG0_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 },
#endif
#if defined(MCU_ESP32) || defined(MCU_ESP32S2)
{ ETS_TG0_LACT_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 },
#endif
#if !defined(MCU_ESP32C2)
{ ETS_TG1_T0_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 },
#endif
#if defined(MCU_ESP32) || defined(MCU_ESP32S2) || defined(MCU_ESP32S3)
{ ETS_TG1_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 },
#endif
{ ETS_UART0_INTR_SOURCE, CPU_INUM_UART, 1 },
{ ETS_UART1_INTR_SOURCE, CPU_INUM_UART, 1 },
#if defined(MCU_ESP32) || defined(MCU_ESP32S2) || defined(MCU_ESP32S3)
{ ETS_UART2_INTR_SOURCE, CPU_INUM_UART, 1 },
#endif
{ ETS_GPIO_INTR_SOURCE, CPU_INUM_GPIO, 1 },
{ ETS_I2C_EXT0_INTR_SOURCE, CPU_INUM_I2C, 1 },
#if defined(MCU_ESP32) || defined(MCU_ESP32S2) || defined(MCU_ESP32S3)
{ ETS_I2C_EXT1_INTR_SOURCE, CPU_INUM_I2C, 1 },
#endif
#if defined(MCU_ESP32)
{ ETS_ETH_MAC_INTR_SOURCE, CPU_INUM_ETH, 1 },
#endif
#if !defined(MCU_ESP32C2)
{ ETS_TWAI_INTR_SOURCE, CPU_INUM_CAN, 1 },
{ ETS_TIMER2_INTR_SOURCE, CPU_INUM_FRC2, 2 },
#endif
#if !defined(MCU_ESP32)
{ ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE, CPU_INUM_SYSTIMER, 2 },
#endif
};

static const struct _irq_alloc_table_t _irq_alloc_table[] = {
{ ETS_FROM_CPU_INTR0_SOURCE, CPU_INUM_SOFTWARE },
{ ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT },
{ ETS_TG0_LACT_LEVEL_INTR_SOURCE, CPU_INUM_RTC },
{ ETS_TG0_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER },
{ ETS_TG1_T0_LEVEL_INTR_SOURCE, CPU_INUM_TIMER },
{ ETS_TG1_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER },
{ ETS_UART0_INTR_SOURCE, CPU_INUM_UART },
{ ETS_UART1_INTR_SOURCE, CPU_INUM_UART },
{ ETS_UART2_INTR_SOURCE, CPU_INUM_UART },
{ ETS_GPIO_INTR_SOURCE, CPU_INUM_GPIO },
{ DPORT_PRO_RTC_CORE_INTR_MAP_REG, CPU_INUM_RTC },
{ ETS_I2C_EXT0_INTR_SOURCE, CPU_INUM_I2C },
{ ETS_I2C_EXT1_INTR_SOURCE, CPU_INUM_I2C },
{ ETS_ETH_MAC_INTR_SOURCE, CPU_INUM_ETH },
{ ETS_CAN_INTR_SOURCE, CPU_INUM_CAN },
{ ETS_TIMER2_INTR_SOURCE, CPU_INUM_FRC2 },
};
#define IRQ_DATA_TABLE_SIZE ARRAY_SIZE(_irq_data_table)

typedef void (*intr_handler_t)(void *arg);
void esp_irq_init(void)
{
#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
/* to avoid to do it in every component, we initialize levels here once */
for (unsigned i = 0; i < IRQ_DATA_TABLE_SIZE; i++) {
intr_cntrl_ll_set_int_level(_irq_data_table[i].intr, _irq_data_table[i].level);
}
#endif
}

#define IRQ_ALLOC_TABLE_SIZE ARRAY_SIZE(_irq_alloc_table)
#define ESP_INTR_FLAG_INTRDISABLED (1<<11)
void esp_intr_enable_source(int inum)
{
intr_cntrl_ll_enable_interrupts(BIT(inum));
}

typedef unsigned intr_handle_t;
void esp_intr_disable_source(int inum)
{
intr_cntrl_ll_disable_interrupts(BIT(inum));
}

esp_err_t esp_intr_enable(intr_handle_t handle)
{
assert(handle < IRQ_ALLOC_TABLE_SIZE);
const struct _irq_alloc_table_t *entry = &_irq_alloc_table[handle];
xt_ints_on(BIT(entry->intr));
assert(handle != NULL);
esp_intr_enable_source(handle->intr);
return ESP_OK;
}

esp_err_t esp_intr_disable(intr_handle_t handle)
{
assert(handle < IRQ_ALLOC_TABLE_SIZE);
const struct _irq_alloc_table_t *entry = &_irq_alloc_table[handle];
xt_ints_off(BIT(entry->intr));
assert(handle != NULL);
esp_intr_disable_source(handle->intr);
return ESP_OK;
}

Expand All @@ -88,29 +131,34 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler,
void *arg, intr_handle_t *ret_handle)
{
unsigned i;
for (i = 0; i < IRQ_ALLOC_TABLE_SIZE; i++) {
if (_irq_alloc_table[i].src == source) {
for (i = 0; i < IRQ_DATA_TABLE_SIZE; i++) {
if (_irq_data_table[i].src == source) {
break;
}
}

if (i == IRQ_ALLOC_TABLE_SIZE) {
if (i == IRQ_DATA_TABLE_SIZE) {
return ESP_ERR_NOT_FOUND;
}

/* route the interrupt source to the CPU interrupt */
intr_matrix_set(PRO_CPU_NUM, _irq_alloc_table[i].src, _irq_alloc_table[i].intr);
intr_matrix_set(PRO_CPU_NUM, _irq_data_table[i].src, _irq_data_table[i].intr);

/* set the interrupt handler */
xt_set_interrupt_handler(_irq_alloc_table[i].intr, handler, arg);
intr_cntrl_ll_set_int_handler(_irq_data_table[i].intr, handler, arg);

#ifdef SOC_CPU_HAS_FLEXIBLE_INTC
/* set interrupt level given by flags */
intr_cntrl_ll_set_int_level(_irq_data_table[i].intr, esp_intr_flags_to_level(flags));
#endif

/* enable the interrupt if ESP_INTR_FLAG_INTRDISABLED is not set */
if ((flags & ESP_INTR_FLAG_INTRDISABLED) == 0) {
xt_ints_on(BIT(_irq_alloc_table[i].intr));
intr_cntrl_ll_enable_interrupts(BIT(_irq_data_table[i].intr));
}

if (ret_handle) {
*((intr_handle_t *)ret_handle) = i;
*((intr_handle_t *)ret_handle) = (const intr_handle_t)&_irq_data_table[i];
}

return ESP_OK;
Expand All @@ -120,3 +168,8 @@ esp_err_t esp_intr_free(intr_handle_t handle)
{
return esp_intr_disable(handle);
}

int esp_intr_get_cpu(intr_handle_t handle)
{
return PRO_CPU_NUM;
}
10 changes: 5 additions & 5 deletions cpu/esp32/periph/rtt_hw_rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@ static void _rtc_init(void)
static void _rtc_poweron(void)
{
/* route all interrupt sources to the same RTT level type interrupt */
intr_matrix_set(PRO_CPU_NUM, ETS_RTC_CORE_INTR_SOURCE, CPU_INUM_RTC);
intr_matrix_set(PRO_CPU_NUM, ETS_RTC_CORE_INTR_SOURCE, CPU_INUM_RTT);

/* set interrupt handler and enable the CPU interrupt */
xt_set_interrupt_handler(CPU_INUM_RTC, _rtc_isr, NULL);
xt_ints_on(BIT(CPU_INUM_RTC));
xt_set_interrupt_handler(CPU_INUM_RTT, _rtc_isr, NULL);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this file only the define CPU_INUM_RTC is renamed to keep it compilable. The changes for ESP-IDF for interrupt handling for this file are in commit 6cca58a.

xt_ints_on(BIT(CPU_INUM_RTT));
}

static void _rtc_poweroff(void)
{
/* reset interrupt handler and disable the CPU interrupt */
xt_ints_off(BIT(CPU_INUM_RTC));
xt_set_interrupt_handler(CPU_INUM_RTC, NULL, NULL);
xt_ints_off(BIT(CPU_INUM_RTT));
xt_set_interrupt_handler(CPU_INUM_RTT, NULL, NULL);
}

uint64_t _rtc_get_counter(void)
Expand Down
10 changes: 5 additions & 5 deletions cpu/esp32/periph/rtt_hw_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@ static void _sys_init(void)
static void _sys_poweron(void)
{
/* route all interrupt sources to the same RTT level type interrupt */
intr_matrix_set(PRO_CPU_NUM, TIMER_SYSTEM_INT_SRC, CPU_INUM_RTC);
intr_matrix_set(PRO_CPU_NUM, TIMER_SYSTEM_INT_SRC, CPU_INUM_RTT);

/* set interrupt handler and enable the CPU interrupt */
xt_set_interrupt_handler(CPU_INUM_RTC, _sys_isr, NULL);
xt_ints_on(BIT(CPU_INUM_RTC));
xt_set_interrupt_handler(CPU_INUM_RTT, _sys_isr, NULL);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For this file only the define CPU_INUM_RTC is renamed to keep it compilable. The changes for ESP-IDF for interrupt handling for this file are in commit 2a9ffee.

xt_ints_on(BIT(CPU_INUM_RTT));
}

static void _sys_poweroff(void)
{
/* reset interrupt handler and disable the CPU interrupt */
xt_ints_off(BIT(CPU_INUM_RTC));
xt_set_interrupt_handler(CPU_INUM_RTC, NULL, NULL);
xt_ints_off(BIT(CPU_INUM_RTT));
xt_set_interrupt_handler(CPU_INUM_RTT, NULL, NULL);
}

static uint64_t _sys_get_counter(void)
Expand Down