Currently I am trying to attach a pin interrupt whose ISR is to call xTaskResumeFromISR
or xQueueSendFromISR
. The ISR gets called correctly, but the code to execute results in a core 0 panic.
Here are the implementation details.
PlatformIO: platform = espressif32 @ 6.0.1, framework = arduino, board = esp32dev
Header file (Worker.h)
#pragma once
#include <Arduino.h>
class Worker {
public:
Worker(uint8_t pinExtInterrupt);
bool startTask(void);
protected:
// static wrapper for task creation
static void staticRun(void *arg) {
reinterpret_cast<Worker *>(arg)->run();
}
// actual task's logic
void run(void);
// static interrupt handler
static void staticIsrHandler(void* arg);
// actual interrupt handler
void isrHandler();
TaskHandle_t _taskHandle = nullptr;
uint8_t _pinExtInterrupt;
};
Source file (Worker.cpp)
#include "Worker.h"
Worker::Worker(uint8_t pinExtInterrupt) {
_pinExtInterrupt = pinExtInterrupt;
pinMode(pinExtInterrupt, INPUT);
}
bool Worker::startTask(void) {
BaseType_t xReturned = xTaskCreate(staticRun, "Worker", 2048, this, 5, &_taskHandle);
gpio_set_intr_type(static_cast<gpio_num_t>(_pinExtInterrupt), GPIO_INTR_NEGEDGE);
gpio_install_isr_service(0);
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
return true;
}
void Worker::run(void) {
for (;;) {
vTaskSuspend(NULL);
// LOGIC
}
}
void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
reinterpret_cast<Worker*>(arg)->isrHandler();
}
void IRAM_ATTR Worker::isrHandler() {
xTaskResumeFromISR(_taskHandle); // ###### THIS LINE THROWS THE EXCEPTION ######
}
Error
Error: Core 0 panic'ed (LoadProhibited). Exception was unhandled.
0x400d1d00:0x3ffbeaac in Worker::isrHandler() at ...
But what works is if you replace xTaskResumeFromISR
e.g. with digitalWrite(..)
.
Need to fix the problem above.
Your call here:
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
assigns a null pointer for the ISR handler's context data. As a result, when your static ISR is called:
void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
reinterpret_cast<Worker*>(arg)->isrHandler();
}
arg is a null pointer, causing the access to _taskHandle
to fail here:
void IRAM_ATTR Worker::isrHandler() {
xTaskResumeFromISR(_taskHandle);
}
If you replace your gpio_isr_handler_add
call with the following:
gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, this);
everything should work.