Search code examples
cerror-handlinginterruptesp32backtrace

I'm getting a Guru Meditation error on an ESP32


I'm trying to make a code with interrupts that runs on a ESP32, but I always get a Guru Meditation

Guru Meditation Error: Core 1 panic'ed (Interrupt wdt timeout on CPU1). Core 1 register dump: PC : 0x4008e6b4 PS : 0x00060c35 A0 : 0x8008d64e A1 : 0x3ffbefac
A2 : 0x3ffb8a00 A3 : 0x3ffb8890 A4 : 0x00000004 A5 : 0x00060c23
A6 : 0x00060c23 A7 : 0x00000001 A8 : 0x3ffb8890 A9 : 0x00000018
A10 : 0x3ffb8890 A11 : 0x00000018 A12 : 0x3ffc42d4 A13 : 0x00060c23
A14 : 0x007bf158 A15 : 0x003fffff SAR : 0x0000000e EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x40089c09 LEND : 0x40089c19 LCOUNT : 0xfffffffc
Core 1 was running in ISR context: EPC1 : 0x400dffeb EPC2 : 0x00000000 EPC3 : 0x00000000 EPC4 : 0x00000000 Backtrace:0x4008e6b1:0x3ffbefac |<-CORRUPTED Core 0 register dump: PC : 0x4008e833 PS : 0x00060035 A0 : 0x8008d277 A1 : 0x3ffbeaac
A2 : 0x3ffbf158 A3

I'm using Arduino IDE 2.1.0 so I cannot use the Exception Decoder. Here's my code, it's still in progress.

#include <Wire.h>
#include <AS5600.h>
#include <WiFi.h>
#include <esp_now.h>
 
#define HES 19
#define LimitPins 18

#define TCA9548A_ADDR 0x70
#define N17AS5600 3
#define N23AS5600 2

#define AS5600_ADDR 0x36

volatile bool HESstate = true;
volatile bool LastHESState = true;
volatile int Count = 0;

volatile bool LimiteState = true;
volatile bool LastLimitState = true;

volatile bool N17Direction = false;

volatile int MainLoop = 1;
volatile int StartValue;
volatile int StopValue;
volatile int DistanceN17;

volatile long LastButtonPress = 0;

volatile bool FirstTimeN17 = false;
volatile bool HomeZeroN17 = false;
volatile bool GetTimeN17 = false;

volatile bool FirstTimeN23 = false;
volatile bool HomeZeroN23 = false;

int16_t Angle17;
int16_t Angle23;
int32_t Distance17;
int32_t Distance23;
int32_t OffsetD17;
int32_t OffsetD23;

AS5600 SensorN17;
AS5600 SensorN23;

uint8_t broadcastAddress[] = {0xC8, 0xF0, 0x9E, 0xA6, 0x08, 0xF0};

typedef struct struct_message {
  int MSG;
} struct_message;

struct_message myData;
esp_now_peer_info_t peerInfo;

void TCA9548A(byte bus){
  if(bus > 7) return;
  Wire.beginTransmission(TCA9548A_ADDR);
  Wire.write(1 << bus);
  Wire.endTransmission();
}

void SetupInterrupts(){
  pinMode(HES, INPUT_PULLUP);
  attachInterrupt(HES, HallEffectSensor, FALLING);

  pinMode(LimitPins, INPUT_PULLUP);
  attachInterrupt(LimitPins, LimitSwitches, RISING);
}

void SetupTCA9548A(){
  TCA9548A(N17AS5600);
  SensorN17.begin(21, 22); // .begin(sda, scl) pour ESP32
 
  TCA9548A(N23AS5600);
  SensorN23.begin(21, 22); // .begin(sda, scl) pour ESP32
  OffsetD23 = -1 * SensorN23.getCumulativePosition();
}

void SetupESP_NOW(){
  WiFi.mode(WIFI_STA);

  if(esp_now_init() != ESP_OK){
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
      
  if(esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}

void setup() {
  Serial.begin(9600);
  Wire.begin();

  SetupInterrupts();
  SetupTCA9548A();
  SetupESP_NOW();

  delay(5000);
}

void loop() {
  if(MainLoop == 1){
    myData.MSG = 170; // 170: Nema17 va UP.
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    MainLoop = 11;

    while(GetTimeN17){
      Serial.print("Temps: ");
      Serial.print(StopValue - StartValue);
      Serial.print(" | Vitesse: ");
      Serial.println(DistanceN17 / (StopValue - StartValue));
    }
  }

  if(MainLoop == 2){
    myData.MSG = 171; // 171: Nema17 va DOWN.
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    MainLoop = 22;

    if(!FirstTimeN17){
      StartValue = millis();
      FirstTimeN17 = true;
    }
  }

  if(MainLoop == 9){
    myData.MSG = 179; // 170: Nema17 à l'arrêt.
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    MainLoop = 11;

    if(!HomeZeroN17){
      OffsetD17 = -1 * SensorN17.getCumulativePosition();
      HomeZeroN17 = true;
      MainLoop = 2;
    }
  }

  //LastHESState = true;
  LastLimitState = true;
}

void HallEffectSensor(){
  /*if(LastHESState){
    if(!N23Homed){
      myData.MSG = 239; // 239: Nema23 à l'arrêt.
      esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
      N23Homed = true;
    }
    
    //HESstate = !HESstate;
    LastHESState = false;
  }*/
}

void LimitSwitches(){
  if(LastLimitState){

    switch(MainLoop){
      case 11:
        MainLoop = 9;

      case 22:
        MainLoop = 1;
        StopValue = millis();
        DistanceN17 = SensorN17.getCumulativePosition();
        GetTimeN17 = true;

      default:
        MainLoop = 0;
    }
    LastLimitState = false;
  }
}

The code I'm trying to make is one when I get an external trigger from pins 18 & 19, (I know the pin 19 interrupt part is all commented), the variable MainLoop changes it's value to get access to a certain part of the main loop.

Thanks for those who'll get a look at my problem. Good night.


Solution

  • There are at least two major problems with your code.

    First, interrupt handlers must be defined with the attribute IRAM_ATTR. This forces the system to keep them in memory. Because interrupt handlers are incredibly time-sensitive, the system is not able to read them from flash on demand the way it is other code.

    So

    void HallEffectSensor(){
    

    should be

    void IRAM_ATTR HallEffectSensor(){
    

    and

    void LimitSwitches(){
    

    should be

    void IRAM_ATTR LimitSwitches(){
    

    Second, you're doing way too much work in the interrupt handlers.

    Interrupts do exactly what they're called. They interrupt the flow of your code - unpredictably. That means they can interrupt your code while it's manipulating a data structure or while it's controlling hardware, and the data structure or the hardware controller can be in an inconsistent state when the interrupt handler runs. Or the interrupt handler can change the state in between instructions elsewhere in your program without that being known.

    It's also important that interrupt handlers return as quickly as possible so that other interrupts can be handled.

    Your interrupt handler HallEffectSensor() calls esp_now_send(), which is almost guaranteed to crash the system. It can easily enter the ESP-NOW protocol stack while it's already running. You can't know what the implementation of esp_now_send() is; unless ESP-IDF explicitly says it's safe to call from an interrupt handler you must not call it from one unless you really want your program to crash.

    Likewise your interrupt handler LimitSwitches() calls SensorN17.getCumulativePosition() which is also almost certainly not safe to call from an interrupt handler.

    Instead, unless you really know what you're doing, you should have each interrupt handler set a volatile boolean variable to true to indicate that the interrupt happened, then in loop() check if the variable is true and do the work there. There are more sophisticated ways to do this but none of them involve calling these functions from the actual interrupt handler.

    There may be other issues in your program but it will definitely not run reliably unless you fix these problems.