WLED: Core 1 panic'ed (Cache disabled but cached memory region accessed) / Usermod

What happened?

Trying to make a usermod to read PWM input from a RC receiver to change presets. Managed to read the PWM input and print it to serial. But when I add addPreset(1) the ESP32 hang with the following error message in serial console:

Guru Meditation Error: Core  1 panic'ed (Cache disabled but cached memory region accessed)
Core 1 register dump:
PC      : 0x4010f064  PS      : 0x00060034  A0      : 0x40085140  A1      : 0x3ffbffe0  
A2      : 0x00000004  A3      : 0x3ffc93b8  A4      : 0x00000000  A5      : 0x00000010  
A6      : 0x000420bc  A7      : 0x3ffb8798  A8      : 0x800819a4  A9      : 0x00000001  
A10     : 0x00000000  A11     : 0x00000000  A12     : 0x8009048d  A13     : 0x3ffb18e0  
A14     : 0x00000000  A15     : 0x3ffb191c  SAR     : 0x0000001a  EXCCAUSE: 0x00000007  
EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  
Core 1 was running in ISR context:
EPC1    : 0x4009055a  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x4010f064

ELF file SHA256: 0000000000000000

Backtrace: 0x4010f061:0x3ffbffe0 0x4008513d:0x3ffc0000 0x40090557:0x3ffb1940 0x40090ce9:0x3ffb1960 0x40088cfc:0x3ffb1980 0x4019fb76:0x3ffb19f

Really don’t know why. Please advise.

To Reproduce Bug

Compile usermod and change to ThePreset 3 in current usermod.

Expected Behavior

The ESP32 hang with the error message.

Install Method

Self-Compiled

What version of WLED?

WLED 0.14.0

Which microcontroller/board are you seeing the problem on?

ESP32

Relevant log/trace output

Guru Meditation Error: Core  1 panic'ed (Cache disabled but cached memory region accessed)
Core 1 register dump:
PC      : 0x4010f064  PS      : 0x00060034  A0      : 0x40085140  A1      : 0x3ffbffe0  
A2      : 0x00000004  A3      : 0x3ffc93b8  A4      : 0x00000000  A5      : 0x00000010  
A6      : 0x000420bc  A7      : 0x3ffb8798  A8      : 0x800819a4  A9      : 0x00000001  
A10     : 0x00000000  A11     : 0x00000000  A12     : 0x8009048d  A13     : 0x3ffb18e0  
A14     : 0x00000000  A15     : 0x3ffb191c  SAR     : 0x0000001a  EXCCAUSE: 0x00000007  
EXCVADDR: 0x00000000  LBEG    : 0x4000c2e0  LEND    : 0x4000c2f6  LCOUNT  : 0xffffffff  
Core 1 was running in ISR context:
EPC1    : 0x4009055a  EPC2    : 0x00000000  EPC3    : 0x00000000  EPC4    : 0x4010f064

ELF file SHA256: 0000000000000000

Backtrace: 0x4010f061:0x3ffbffe0 0x4008513d:0x3ffc0000 0x40090557:0x3ffb1940 0x40090ce9:0x3ffb1960 0x40088cfc:0x3ffb1980 0x4019fb76:0x3ffb19f

Anything else?

This is the code of the current usermod:

#pragma once

#include "wled.h"

class PWM_input : public Usermod {
  private:
    static volatile long StartTimeChan1;
    static volatile long CurrentTimeChan1;
    static volatile long PulsesChan1;
    static int PulseWidthChan1;
    static int ThePreset;

    static volatile long StartTimeChan2;
    static volatile long CurrentTimeChan2;
    static volatile long PulsesChan2;
    static int PulseWidthChan2;
    static int PulseOptionChan2;

  public:
    #define RCPinChan1 5
    #define RCPinChan2 4



    void setup() override {
      Serial.begin(9600);
      pinMode(RCPinChan1, INPUT_PULLUP);
      pinMode(RCPinChan2, INPUT_PULLUP);

      attachInterrupt(digitalPinToInterrupt(RCPinChan1), PulseTimerChan1, CHANGE);
      attachInterrupt(digitalPinToInterrupt(RCPinChan2), PulseTimerChan2, CHANGE);
    }

    void loop() override {
      if (PulsesChan1 < 2100){
        PulseWidthChan1 = PulsesChan1;
      }
       if ((PulseWidthChan1 < 2100) && (PulseWidthChan1 > 1750) && (ThePreset != 1)) {
          Serial.println(PulseWidthChan1);
          ThePreset = 1;
          Serial.println("The preset is now ");
          Serial.println(ThePreset);
//          applyPreset(1);
        }
       if ((PulseWidthChan1 < 1700) && (PulseWidthChan1 > 1550) && (ThePreset != 2)) {
          Serial.println(PulseWidthChan1);
          ThePreset = 2;
          Serial.println("The preset is now ");
          Serial.println(ThePreset);
//          applyPreset(2);
       }
       if ((PulseWidthChan1 < 1500) && (PulseWidthChan1 > 1250) && (ThePreset != 3)) {
          Serial.println(PulseWidthChan1);
          ThePreset = 3;
          Serial.println("The preset is now ");
          Serial.println(ThePreset);
          applyPreset(3)
       }
       if ((PulseWidthChan1 < 1200) && (PulseWidthChan1 > 900) && (ThePreset != 4)) {
          Serial.println(PulseWidthChan1);
          ThePreset = 4;
          Serial.println("The preset is now ");
          Serial.println(ThePreset);
//          applyPreset(4);
        }
    }
    
    static void PulseTimerChan1() {
      CurrentTimeChan1 = micros();
      if (CurrentTimeChan1 > StartTimeChan1){
        PulsesChan1 = CurrentTimeChan1 - StartTimeChan1;
        StartTimeChan1 = CurrentTimeChan1;
      }
    }

    static void PulseTimerChan2() {
      CurrentTimeChan2 = micros();
      if (CurrentTimeChan2 > StartTimeChan2){
        PulsesChan2 = CurrentTimeChan2 - StartTimeChan2;
        StartTimeChan2 = CurrentTimeChan2;
      }
    }
};

// Initialize static variables
volatile long PWM_input::StartTimeChan1 = 0;
volatile long PWM_input::StartTimeChan2 = 0;
volatile long PWM_input::CurrentTimeChan1 = 0;
volatile long PWM_input::CurrentTimeChan2 = 0;
volatile long PWM_input::PulsesChan1 = 0;
volatile long PWM_input::PulsesChan2 = 0;
int PWM_input::PulseWidthChan1 = 0;
int PWM_input::PulseWidthChan2 = 0;
int PWM_input::ThePreset = 0;
int PWM_input::PulseOptionChan2 = 0;

Code of Conduct

  • I agree to follow this project’s Code of Conduct

About this issue

  • Original URL
  • State: closed
  • Created 6 months ago
  • Comments: 15

Most upvoted comments

One last hint

CurrentTimeChan2 = micros(); if (CurrentTimeChan2 > StartTimeChan2){

micros() will roll over very often, so doing if (now > start) may not give you what you want. Rewriting the condition to if (now - start > 0) makes it a bit more robust against overflow, if you also use unsigned long and not long. The best solution however is to forget about arduino micros(), and use esp_timer_get_time() instead -> “uint64_t start = esp_timer_get_time();”.

This is still the way I want to fix it. But what should be global/static? I have two ISR’s, which are static. But when I give them IRAM_ATTR I get the dangerous relocation. How do I make those global? (Sorry, really new at this stuff…)

Its some time since I wrote ISR stuff for esp32, so I don’t have all the details, sorry.

In principle, you would move your ISR functions out of the scope of your usermod instance - “static” class members are not the same as static functions. So define them at the beginning of your file, before class PWM_input : public Usermod {. This also means that all variables you need for communication (like StartTimeChan2) must be defined before class PWM_input, to make them global. You can still prefix all your globals with “static”, to avoid name clashes with the WLED core.

Cool, that was exactly what I was doing right now. And yes… the IRAM_ATTR gives no compile errors. Not working either yet, but hey, at least we have some new progression. Sort of… 😉

Thanks!

Could it be due to this: #2518 (comment)

That’s for newer core. We never switched to it for classic ESP32.