diff --git a/cpu/esp32/include/irq_arch.h b/cpu/esp32/include/irq_arch.h index 40aa23992e..915bd5d9cf 100644 --- a/cpu/esp32/include/irq_arch.h +++ b/cpu/esp32/include/irq_arch.h @@ -35,24 +35,33 @@ extern "C" { * * @{ */ -#define CPU_INUM_RMT 1 /**< Level interrupt with low priority 1 */ + +/* On Xtensa-based ESP32x SoCs, interrupt 0 is reserved for the WiFi interface + * and interrupt 1 is available. However, since interrupt 0 is not available on + * RISC-V-based ESP32x SoCs, interrupt 1 is used for the WiFi interface instead. + * Therefore, we use interrupt 1 for the RMT peripheral on Xtensa-based ESP32x + * SoCs, but we use interrupt 11 for the RMT peripheral on RISC-V-based ESP32x + * SoCs. Interrupt 11 is reserved for profiling on Xtensa-based ESP32x SoCs. */ +#if defined(__XTENSA__) +# define CPU_INUM_RMT 1 /**< Level interrupt with low priority 1 */ +#else +# define CPU_INUM_RMT 11 /**< Level interrupt with low priority 1 */ +#endif #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 4 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_USB 8 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_BLE 5 /**< Level interrupt with low priority 1 */ #define CPU_INUM_RTT 9 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_SERIAL_JTAG 10 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_SERIAL_JTAG 10 /**< Edge 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_UART 13 /**< Level interrupt with low priority 1 */ +#define CPU_INUM_CAN 17 /**< Level interrupt with low priority 1 */ #define CPU_INUM_ETH 18 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_LCD 18 /**< Level interrupt with low priority 1 */ -#define CPU_INUM_TIMER 19 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_USB 18 /**< Level interrupt with low priority 1 */ #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_BLE 21 /**< Level interrupt with medium priority 2 */ -#define CPU_INUM_SDMMC 23 /**< Level interrupt with medium priority 2 */ -#define CPU_INUM_CACHEERR 25 /**< Level interrupt with high priority 4 */ +#define CPU_INUM_SDMMC 21 /**< Level interrupt with medium priority 2 */ +#define CPU_INUM_TIMER 22 /**< Edge interrupt with medium priority 2 */ +#define CPU_INUM_WDT 23 /**< Level interrupt with medium priority 3 */ +#define CPU_INUM_SOFTWARE 29 /**< Software interrupt with medium priority 3 */ /** @} */ /** diff --git a/cpu/esp32/irq_arch.c b/cpu/esp32/irq_arch.c index f84b92410f..cfb2448582 100644 --- a/cpu/esp32/irq_arch.c +++ b/cpu/esp32/irq_arch.c @@ -19,14 +19,17 @@ */ #include "irq_arch.h" +#include "log.h" #include "esp_attr.h" +#include "esp_bit_defs.h" +#include "esp_cpu.h" #include "esp_err.h" #include "freertos/FreeRTOS.h" -#include "hal/interrupt_controller_types.h" -#include "hal/interrupt_controller_ll.h" #include "rom/ets_sys.h" +#include "soc/interrupts.h" #include "soc/periph_defs.h" +#include "soc/soc.h" #include "esp_intr_alloc.h" #define ENABLE_DEBUG 0 @@ -44,83 +47,84 @@ typedef struct intr_handle_data_t { /* TODO change to a clearer approach */ static const struct intr_handle_data_t _irq_data_table[] = { +#ifndef __XTENSA__ { ETS_FROM_CPU_INTR0_SOURCE, CPU_INUM_SOFTWARE, 1 }, +#endif { ETS_TG0_WDT_LEVEL_INTR_SOURCE, CPU_INUM_WDT, 1 }, { ETS_TG0_T0_LEVEL_INTR_SOURCE, CPU_INUM_RTT, 1 }, -#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) +#if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1 { ETS_TG0_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 }, #endif -#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) - { ETS_TG0_LACT_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 }, -#endif -#if !defined(CPU_FAM_ESP32C2) +#if SOC_TIMER_GROUPS > 1 { ETS_TG1_T0_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 }, -#endif -#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) +# if SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1 { ETS_TG1_T1_LEVEL_INTR_SOURCE, CPU_INUM_TIMER, 2 }, +# endif /* SOC_TIMER_GROUP_TIMERS_PER_GROUP > 1 */ +#endif /* SOC_TIMER_GROUPS > 1 */ +#if defined(CPU_FAM_ESP32) + { ETS_TG0_LACT_LEVEL_INTR_SOURCE, CPU_INUM_SYSTIMER, 2 }, +#elif defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) || defined(CPU_FAM_ESP32C3) + { ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE, CPU_INUM_SYSTIMER, 2 }, +#else +# error "Platform implementation is missing" #endif { ETS_UART0_INTR_SOURCE, CPU_INUM_UART, 1 }, { ETS_UART1_INTR_SOURCE, CPU_INUM_UART, 1 }, -#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) +#if SOC_UART_NUM > 2 { 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(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) +#if SOC_I2C_NUM > 1 { ETS_I2C_EXT1_INTR_SOURCE, CPU_INUM_I2C, 1 }, #endif -#if defined(CPU_FAM_ESP32) +#if defined(SOC_BLE_SUPPORTED) +# if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S3) || defined(CPU_FAM_ESP32C3) + { ETS_RWBLE_INTR_SOURCE, CPU_INUM_BLE, 2 }, +# else +# error "Platform implementation is missing" +# endif +#endif /* SOC_BLE_SUPPORTED */ +#if defined(SOC_EMAC_SUPPORTED) { ETS_ETH_MAC_INTR_SOURCE, CPU_INUM_ETH, 1 }, #endif -#if !defined(CPU_FAM_ESP32C2) +#if defined(SOC_RMT_SUPPORTED) + { ETS_RMT_INTR_SOURCE, CPU_INUM_RMT, 1 }, +#endif +#if defined(SOC_SDMMC_HOST_SUPPORTED) + { ETS_SDIO_HOST_INTR_SOURCE, CPU_INUM_SDMMC, 2 }, +#endif +#if defined(SOC_TWAI_SUPPORTED) { ETS_TWAI_INTR_SOURCE, CPU_INUM_CAN, 1 }, - { ETS_TIMER2_INTR_SOURCE, CPU_INUM_FRC2, 2 }, #endif -#if !defined(CPU_FAM_ESP32) - { ETS_SYSTIMER_TARGET2_EDGE_INTR_SOURCE, CPU_INUM_SYSTIMER, 2 }, -#endif - { ETS_INTERNAL_SW1_INTR_SOURCE, CPU_INUM_BLE, 2 }, -#if defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) +#if defined(SOC_USB_OTG_SUPPORTED) { ETS_USB_INTR_SOURCE, CPU_INUM_USB, 1 }, #endif -#if defined(ETS_USB_SERIAL_JTAG_INTR_SOURCE) +#if defined(SOC_USB_SERIAL_JTAG_SUPPORTED) { ETS_USB_SERIAL_JTAG_INTR_SOURCE, CPU_INUM_SERIAL_JTAG, 1 }, -#endif - { ETS_RMT_INTR_SOURCE, CPU_INUM_RMT, 1 }, -#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) - { ETS_I2S0_INTR_SOURCE, CPU_INUM_LCD, 1 }, -#elif defined(CPU_FAM_ESP32S3) - { ETS_LCD_CAM_INTR_SOURCE, CPU_INUM_LCD, 1 }, -#endif -#if defined(CPU_FAM_ESP32) || defined(CPU_FAM_ESP32S2) || defined(CPU_FAM_ESP32S3) - { ETS_SDIO_HOST_INTR_SOURCE, CPU_INUM_SDMMC, 2 }, #endif }; #define IRQ_DATA_TABLE_SIZE ARRAY_SIZE(_irq_data_table) -#if defined(CPU_FAM_ESP32) && MODULE_ESP_LCD && MODULE_ESP_ETH -#error "esp_eth and esp_lcd can't be used at the same time because of an interrupt conflict" -#endif - 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); + esp_cpu_intr_set_priority(_irq_data_table[i].intr, _irq_data_table[i].level); } #endif } void esp_intr_enable_source(int inum) { - intr_cntrl_ll_enable_interrupts(BIT(inum)); + esp_cpu_intr_enable(BIT(inum)); } void esp_intr_disable_source(int inum) { - intr_cntrl_ll_disable_interrupts(BIT(inum)); + esp_cpu_intr_disable(BIT(inum)); } esp_err_t esp_intr_enable(intr_handle_t handle) @@ -150,6 +154,8 @@ esp_err_t esp_intr_disable(intr_handle_t handle) esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, void *arg, intr_handle_t *ret_handle) { + DEBUG("%s source=%d flags=0x%04"PRIx16" handler=%p arg=%p\n", + __func__, source, (uint16_t)flags, handler, arg); unsigned i; for (i = 0; i < IRQ_DATA_TABLE_SIZE; i++) { if (_irq_data_table[i].src == source) { @@ -158,6 +164,8 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, } if (i == IRQ_DATA_TABLE_SIZE) { + LOG_ERROR("%s source=%d not found in interrupt allocation table\n", + __func__, source); return ESP_ERR_NOT_FOUND; } @@ -165,16 +173,16 @@ esp_err_t esp_intr_alloc(int source, int flags, intr_handler_t handler, intr_matrix_set(PRO_CPU_NUM, _irq_data_table[i].src, _irq_data_table[i].intr); /* set the interrupt handler */ - intr_cntrl_ll_set_int_handler(_irq_data_table[i].intr, handler, arg); + esp_cpu_intr_set_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)); + esp_cpu_intr_set_priority(_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) { - intr_cntrl_ll_enable_interrupts(BIT(_irq_data_table[i].intr)); + esp_cpu_intr_enable(BIT(_irq_data_table[i].intr)); } if (ret_handle) { @@ -204,3 +212,24 @@ int esp_intr_get_cpu(intr_handle_t handle) { return PRO_CPU_NUM; } + +static volatile uint32_t esp_intr_noniram_state; +static uint32_t esp_intr_noniram_call_counter = 0; + +void IRAM_ATTR esp_intr_noniram_disable(void) +{ + if (esp_intr_noniram_call_counter == 0) { + esp_intr_noniram_state = irq_disable(); + } + esp_intr_noniram_call_counter++; +} + +void IRAM_ATTR esp_intr_noniram_enable(void) +{ + if (esp_intr_noniram_call_counter) { + esp_intr_noniram_call_counter--; + if (esp_intr_noniram_call_counter == 0) { + irq_restore(esp_intr_noniram_state); + } + }; +} diff --git a/cpu/esp32/startup.c b/cpu/esp32/startup.c index 8c96a17caa..e373e2b54e 100644 --- a/cpu/esp32/startup.c +++ b/cpu/esp32/startup.c @@ -304,8 +304,11 @@ static NORETURN void IRAM system_init (void) extern void board_init(void); board_init(); - /* route a software interrupt source to CPU as trigger for thread yields */ +#ifndef __XTENSA__ + /* route a software interrupt source to CPU as trigger for thread yields, + * we use an internal software interrupt on Xtensa-based ESP32x SoCs */ intr_matrix_set(PRO_CPU_NUM, ETS_FROM_CPU_INTR0_SOURCE, CPU_INUM_SOFTWARE); +#endif /* set thread yield handler and enable the software interrupt */ intr_cntrl_ll_set_int_handler(CPU_INUM_SOFTWARE, thread_yield_isr, NULL); intr_cntrl_ll_enable_interrupts(BIT(CPU_INUM_SOFTWARE)); diff --git a/cpu/esp_common/esp-riscv/irq_arch.c b/cpu/esp_common/esp-riscv/irq_arch.c index 1f152d4aa8..4a04cc025d 100644 --- a/cpu/esp_common/esp-riscv/irq_arch.c +++ b/cpu/esp_common/esp-riscv/irq_arch.c @@ -21,8 +21,7 @@ #include "irq_arch.h" #include "esp_attr.h" -#include "hal/interrupt_controller_types.h" -#include "hal/interrupt_controller_ll.h" +#include "esp_cpu.h" #include "soc/periph_defs.h" #define ENABLE_DEBUG 0 diff --git a/cpu/esp_common/esp-xtensa/thread_arch.c b/cpu/esp_common/esp-xtensa/thread_arch.c index 59ab91d57b..c37ea4685c 100644 --- a/cpu/esp_common/esp-xtensa/thread_arch.c +++ b/cpu/esp_common/esp-xtensa/thread_arch.c @@ -286,6 +286,9 @@ void IRAM_ATTR thread_yield_higher(void) ets_soft_int_type = ETS_SOFT_INT_YIELD; WSR(BIT(ETS_SOFT_INUM), interrupt); critical_exit(); +#elif defined(__XTENSA__) + /* generate the software interrupt to switch the context */ + WSR(BIT(CPU_INUM_SOFTWARE), interrupt); #elif defined(DPORT_CPU_INTR_FROM_CPU_0_REG) /* generate the software interrupt to switch the context */ DPORT_WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, DPORT_CPU_INTR_FROM_CPU_0);