【问题标题】:ESP32 FreeRTOS pin interrup ISR handler core 0 panic (C++)ESP32 FreeRTOS 引脚中断 ISR 处理程序 core 0 panic (C++)
【发布时间】:2023-02-10 22:07:36
【问题描述】:

目前我正在尝试附加一个引脚中断,其 ISR 是调用xTaskResumeFromISRxQueueSendFromISR。 ISR 被正确调用,但执行的代码导致核心 0 恐慌.

以下是实施细节。

平台IO:平台= espressif32 @ 6.0.1,框架= arduino,板= esp32dev

头文件(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;
};

源文件(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 ######
}

错误
错误:核心 0 恐慌(LoadProhibited)。异常未处理。
Worker::isrHandler() 中的 0x400d1d00:0x3ffbeaac 在 ...

但是,如果您替换 xTaskResumeFromISR,例如与digitalWrite(..)

需要解决上面的问题。

【问题讨论】:

    标签: arduino esp32 freertos arduino-c++ platformio


    【解决方案1】:

    您的来电:

    gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, NULL);
    

    为 ISR 处理程序的上下文数据分配一个空指针。因此,当您的静态 ISR 被调用时:

    void IRAM_ATTR Worker::staticIsrHandler(void* arg) {
      reinterpret_cast<Worker*>(arg)->isrHandler();
    }
    

    arg 是空指针,导致此处访问_taskHandle失败:

    void IRAM_ATTR Worker::isrHandler() {
      xTaskResumeFromISR(_taskHandle); 
    }
    

    如果您将 gpio_isr_handler_add 呼叫替换为以下内容:

    gpio_isr_handler_add(static_cast<gpio_num_t>(_pinExtInterrupt), staticIsrHandler, this);
    

    一切都应该工作。

    【讨论】: