diff --git a/components/driver/include/driver/rmt.h b/components/driver/include/driver/rmt.h index 1c136689b7..24df1ac8ed 100644 --- a/components/driver/include/driver/rmt.h +++ b/components/driver/include/driver/rmt.h @@ -568,15 +568,14 @@ esp_err_t rmt_config(rmt_config_t* rmt_param); * @brief register RMT interrupt handler, the handler is an ISR. * * The handler will be attached to the same CPU core that this function is running on. - * @note - * If you already called rmt_driver_install to use system RMT driver, + * @note If you already called rmt_driver_install to use system RMT driver, * please do not register ISR handler again. * * @param fn Interrupt handler function. * @param arg Parameter for handler function * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. - * @param If non-zero, a handle to later clean up the ISR gets stored here. + * @param handle If non-zero, a handle to later clean up the ISR gets stored here. * * @return * - ESP_OK Success diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index dd69dce275..951ada929a 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -381,7 +381,8 @@ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, /** - * @brief Free UART interrupt handler registered by uart_isr_register. + * @brief Free UART interrupt handler registered by uart_isr_register. Must be called on the same core as + * uart_isr_register was called. * * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 * diff --git a/docs/api/intr_alloc.rst b/docs/api/intr_alloc.rst index e4e9bdb4ad..4d2f21abac 100644 --- a/docs/api/intr_alloc.rst +++ b/docs/api/intr_alloc.rst @@ -29,7 +29,33 @@ interrupt for DevA is still pending, but because the int line never went low (De even when the int for DevB was cleared) the interrupt is never serviced.) +Multicore issues +---------------- +Peripherals that can generate interrupts can be divided in two types: external peripherals, outside the Xtensa +cores in the ESP32, and internal peripherals, inside the ESP32. Interrupt handling differs slightly between +these two types of peripherals. + +Each Xtensa core has its own set of internal peripherals: three timer comparators, a performance monitor and two +software interrupts. These peripherals can only be configured from the core they are associated with. When +generating an interrupt, the interrupt they generate is hard-wired to their associated core; it's not possible +to have e.g. an internal timer comparator of one core generate an interrupt on another core. That is why these +sources can only be managed using a task running on that specific core. Internal interrupt sources are still +allocatable using esp_intr_alloc as normal, but they cannot be shared and will always have a fixed interrupt +level (namely, the one associated in hardware with the peripheral). Internal interrupt sources are defined +in esp_intr_alloc.h as ETS_INTERNAL_*_INTR_SOURCE. + +The remaining interrupt slots in both cores are wired to an interrupt multiplexer, which can be used to +route any external interrupt source to any of these interrupt slots. Allocating an external interrupt will always +allocate it on the core that does the allocation, and freeing the interrupt should always happen on the same +core. Disabling and enabling the interrupt from another core is allowed, however. External interrupts can +share an interrupt slot bu passing ESP_INTR_FLAG_SHARED as a flag to esp_intr_alloc. External interrupt sources +are defined in soc/soc.h as ETS_*_INTR_SOURCE. + +Care should be taken when allocating an interrupt using a task not pinned to a certain core; while running +code not in a critical secion, these tasks can migrate between cores at any moment, possibly making an +interrupt operation fail because of the reasons mentioned above. It is advised to always use +xTaskCreatePinnedToCore with a specific CoreID argument to create tasks that will handle interrupts. Application Example ------------------- @@ -58,6 +84,7 @@ Macros .. doxygendefine:: ESP_INTR_FLAG_SHARED .. doxygendefine:: ESP_INTR_FLAG_EDGE .. doxygendefine:: ESP_INTR_FLAG_IRAM +.. doxygendefine:: ESP_INTR_FLAG_INTRDISABLED Type Definitions ^^^^^^^^^^^^^^^^ diff --git a/examples/13_timer_group/main/timer_group.c b/examples/13_timer_group/main/timer_group.c index f61f39b2c5..9db471054d 100644 --- a/examples/13_timer_group/main/timer_group.c +++ b/examples/13_timer_group/main/timer_group.c @@ -157,7 +157,7 @@ void tg0_timer0_init() /*Enable timer interrupt*/ timer_enable_intr(timer_group, timer_idx); /*Set ISR handler*/ - timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM); + timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM, NULL); /*Start timer counter*/ timer_start(timer_group, timer_idx); } @@ -187,7 +187,7 @@ void tg0_timer1_init() /*Enable timer interrupt*/ timer_enable_intr(timer_group, timer_idx); /*Set ISR handler*/ - timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM); + timer_isr_register(timer_group, timer_idx, timer_group0_isr, (void*) timer_idx, ESP_INTR_FLAG_IRAM, NULL); /*Start timer counter*/ timer_start(timer_group, timer_idx); } diff --git a/examples/16_pcnt/main/pcnt_test.c b/examples/16_pcnt/main/pcnt_test.c index 31d8f28870..cc844dcd81 100644 --- a/examples/16_pcnt/main/pcnt_test.c +++ b/examples/16_pcnt/main/pcnt_test.c @@ -176,7 +176,7 @@ static void pcnt_init(void) /*Reset counter value*/ pcnt_counter_clear(PCNT_TEST_UNIT); /*Register ISR handler*/ - pcnt_isr_register(pcnt_intr_handler, NULL, 0); + pcnt_isr_register(pcnt_intr_handler, NULL, 0, NULL); /*Enable interrupt for PCNT unit*/ pcnt_intr_enable(PCNT_TEST_UNIT); /*Resume counting*/