mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-13 09:34:41 +02:00
Merge branch 'bugfix/crosscore_int_iram' into 'master'
Place cross-core interrupt into IRAM, sanity check handler address passed into esp_intr_alloc Cross-core interrupt handler was not marked with IRAM_ATTR. The reason why this caused an exception is probably due to some tasks running at highest priority (these are not blocked by spi_flash_disable_caches_interrupts_and_other_cpu mechanism). This change puts the interrupt handler into IRAM and adds a sanity check into `esp_intr_alloc`. Reported on Github: https://github.com/espressif/esp-idf/issues/211 See merge request !404
This commit is contained in:
@@ -44,7 +44,7 @@ static volatile uint32_t reason[ portNUM_PROCESSORS ];
|
|||||||
ToDo: There is a small chance the CPU already has yielded when this ISR is serviced. In that case, it's running the intended task but
|
ToDo: There is a small chance the CPU already has yielded when this ISR is serviced. In that case, it's running the intended task but
|
||||||
the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably just schedule the task again, but have to check that.
|
the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably just schedule the task again, but have to check that.
|
||||||
*/
|
*/
|
||||||
static void esp_crosscore_isr(void *arg) {
|
static void IRAM_ATTR esp_crosscore_isr(void *arg) {
|
||||||
uint32_t myReasonVal;
|
uint32_t myReasonVal;
|
||||||
//A pointer to the correct reason array item is passed to this ISR.
|
//A pointer to the correct reason array item is passed to this ISR.
|
||||||
volatile uint32_t *myReason=arg;
|
volatile uint32_t *myReason=arg;
|
||||||
@@ -73,11 +73,13 @@ void esp_crosscore_int_init() {
|
|||||||
portENTER_CRITICAL(&reasonSpinlock);
|
portENTER_CRITICAL(&reasonSpinlock);
|
||||||
reason[xPortGetCoreID()]=0;
|
reason[xPortGetCoreID()]=0;
|
||||||
portEXIT_CRITICAL(&reasonSpinlock);
|
portEXIT_CRITICAL(&reasonSpinlock);
|
||||||
|
esp_err_t err;
|
||||||
if (xPortGetCoreID()==0) {
|
if (xPortGetCoreID()==0) {
|
||||||
esp_intr_alloc(ETS_FROM_CPU_INTR0_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()], NULL);
|
err = esp_intr_alloc(ETS_FROM_CPU_INTR0_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()], NULL);
|
||||||
} else {
|
} else {
|
||||||
esp_intr_alloc(ETS_FROM_CPU_INTR1_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()], NULL);
|
err = esp_intr_alloc(ETS_FROM_CPU_INTR1_SOURCE, ESP_INTR_FLAG_IRAM, esp_crosscore_isr, (void*)&reason[xPortGetCoreID()], NULL);
|
||||||
}
|
}
|
||||||
|
assert(err == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void esp_crosscore_int_send_yield(int coreId) {
|
void esp_crosscore_int_send_yield(int coreId) {
|
||||||
|
@@ -124,6 +124,9 @@ esp_err_t esp_intr_reserve(int intno, int cpu);
|
|||||||
*
|
*
|
||||||
* The interrupt will always be allocated on the core that runs this function.
|
* The interrupt will always be allocated on the core that runs this function.
|
||||||
*
|
*
|
||||||
|
* If ESP_INTR_FLAG_IRAM flag is used, and handler address is not in IRAM or
|
||||||
|
* RTC_FAST_MEM, then ESP_ERR_INVALID_ARG is returned.
|
||||||
|
*
|
||||||
* @param source The interrupt source. One of the ETS_*_INTR_SOURCE interrupt mux
|
* @param source The interrupt source. One of the ETS_*_INTR_SOURCE interrupt mux
|
||||||
* sources, as defined in soc/soc.h, or one of the internal
|
* sources, as defined in soc/soc.h, or one of the internal
|
||||||
* ETS_INTERNAL_*_INTR_SOURCE sources as defined in this header.
|
* ETS_INTERNAL_*_INTR_SOURCE sources as defined in this header.
|
||||||
|
@@ -446,6 +446,12 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
|
|||||||
if ((flags&ESP_INTR_FLAG_SHARED) && (!handler || source<0)) return ESP_ERR_INVALID_ARG;
|
if ((flags&ESP_INTR_FLAG_SHARED) && (!handler || source<0)) return ESP_ERR_INVALID_ARG;
|
||||||
//Statusreg should have a mask
|
//Statusreg should have a mask
|
||||||
if (intrstatusreg && !intrstatusmask) return ESP_ERR_INVALID_ARG;
|
if (intrstatusreg && !intrstatusmask) return ESP_ERR_INVALID_ARG;
|
||||||
|
//If the ISR is marked to be IRAM-resident, the handler must not be in the cached region
|
||||||
|
if ((flags&ESP_INTR_FLAG_IRAM) &&
|
||||||
|
(ptrdiff_t) handler >= 0x400C0000 &&
|
||||||
|
(ptrdiff_t) handler < 0x50000000 ) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
//Default to prio 1 for shared interrupts. Default to prio 1, 2 or 3 for non-shared interrupts.
|
//Default to prio 1 for shared interrupts. Default to prio 1, 2 or 3 for non-shared interrupts.
|
||||||
if ((flags&ESP_INTR_FLAG_LEVELMASK)==0) {
|
if ((flags&ESP_INTR_FLAG_LEVELMASK)==0) {
|
||||||
|
@@ -201,3 +201,30 @@ TEST_CASE("Intr_alloc test, shared ints", "[esp32]")
|
|||||||
{
|
{
|
||||||
timer_test(ESP_INTR_FLAG_SHARED);
|
timer_test(ESP_INTR_FLAG_SHARED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Can allocate IRAM int only with an IRAM handler", "[esp32]")
|
||||||
|
{
|
||||||
|
void dummy(void* arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
IRAM_ATTR void dummy_iram(void* arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
RTC_IRAM_ATTR void dummy_rtc(void* arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
intr_handle_t ih;
|
||||||
|
esp_err_t err = esp_intr_alloc(ETS_INTERNAL_PROFILING_INTR_SOURCE,
|
||||||
|
ESP_INTR_FLAG_IRAM, &dummy, NULL, &ih);
|
||||||
|
TEST_ASSERT_EQUAL_INT(ESP_ERR_INVALID_ARG, err);
|
||||||
|
err = esp_intr_alloc(ETS_INTERNAL_PROFILING_INTR_SOURCE,
|
||||||
|
ESP_INTR_FLAG_IRAM, &dummy_iram, NULL, &ih);
|
||||||
|
TEST_ESP_OK(err);
|
||||||
|
err = esp_intr_free(ih);
|
||||||
|
TEST_ESP_OK(err);
|
||||||
|
err = esp_intr_alloc(ETS_INTERNAL_PROFILING_INTR_SOURCE,
|
||||||
|
ESP_INTR_FLAG_IRAM, &dummy_rtc, NULL, &ih);
|
||||||
|
TEST_ESP_OK(err);
|
||||||
|
err = esp_intr_free(ih);
|
||||||
|
TEST_ESP_OK(err);
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user