Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
1 task done
barrymossel opened this issue Jan 5, 2024 · 15 comments
Closed
1 task done
Labels
question usermod usermod related

Comments

@barrymossel
Copy link

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
@barrymossel barrymossel added the bug label Jan 5, 2024
@blazoncek
Copy link
Collaborator

Please use debug build and exception decoder.

@barrymossel
Copy link
Author

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

Will look into debug!

@blazoncek
Copy link
Collaborator

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

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

@blazoncek blazoncek added usermod usermod related and removed bug labels Jan 5, 2024
@blazoncek
Copy link
Collaborator

Using ISR requires special programming. Consult Espressif documentation.

@barrymossel
Copy link
Author

Tried to use IRAM_ATTR but keep getting dangerous relocation: l32r: literal placed after use.

So now I tried something else for testing purposes (using the blocking pulseIn).

#pragma once

#include "wled.h"

//This is an empty v2 usermod template. Please see the file usermod_v2_example.h in the EXAMPLE_v2 usermod folder for documentation on the functions you can use!

class PWM_input : public Usermod {
  private:
    #define RCPin1 5
//    #define RCPin2 4
    int RCValue1;
//    int RCValue2;
    int ThePreset;
  public:
    void setup() {
      Serial.begin(9600);
      pinMode(RCPin1, INPUT);
//      pinMode(RCPin2, INPUT);
    }

    void loop() {
      RCValue1 = pulseIn(RCPin1, HIGH);
//      Serial.println(RCValue1);
//      RCValue2 = pulseIn(RCPin2, HIGH);
//      Serial.println(RCValue2);
       if ((RCValue1 < 2100) && (RCValue1 > 1750) && (ThePreset != 1)) {
          Serial.println("RCValue1");
          Serial.println(RCValue1);
          ThePreset = 1;
          Serial.println("The preset is now ");
          Serial.println(ThePreset);
//          applyPreset(1);
        }
       if ((RCValue1 < 1700) && (RCValue1 > 1550) && (ThePreset != 2)) {
          Serial.println("RCValue1");
          Serial.println(RCValue1);
          ThePreset = 2;
          Serial.println("The preset is now ");
          Serial.println(ThePreset);
//          applyPreset(2);
       }
       if ((RCValue1 < 1500) && (RCValue1 > 1250) && (ThePreset != 3)) {
          Serial.println("RCValue1");
          Serial.println(RCValue1);
          ThePreset = 3;
          Serial.println("The preset is now ");
          Serial.println(ThePreset);
          applyPreset(3);
       }
       if ((RCValue1 < 1200) && (RCValue1 > 900) && (ThePreset != 4)) {
          Serial.println("RCValue1");
          Serial.println(RCValue1);
          ThePreset = 4;
          Serial.println("The preset is now ");
          Serial.println(ThePreset);
//          applyPreset(4);
        }
    }
};

Compiles ok, but WLED won't start. When I comment out applyPreset=3 it WLED starts and reading the PWM input works as well... Really not sure where to look anymore now.
Why do both methods not work???

@barrymossel
Copy link
Author

Hmmm, adding a delay(500) at the end of the setup seemed to fix it. But apparently only once.

@softhack007
Copy link
Collaborator

softhack007 commented Jan 5, 2024

Hi, a few thoughts, maybe it help you with writing your usermod.

RCValue1 = pulseIn(RCPin1, HIGH);

This is blocking the WLED main loop for up to one second. Your usermod should not block for more than 50ms, otherwise strange things will happen (like watchdog abort).
It may work better if you use the timeout parameter, like RCValue1 = pulseIn(RCPin1, HIGH, 50);

adding a delay(500) at the end of the setup

bad idea, see above. Try to keep the "blocking time" of your usermod as low as possible.

attachInterrupt(digitalPinToInterrupt(RCPinChan1), PulseTimerChan1, CHANGE);

If you want to use an ISR, it must have IRAM_ATTR. The "dangerous relocation: l32r" warning could mean you can't use a class method as interrupt handler function. The usermod object is instantiated at run-time, so the linker does not have the address at link-time for putting your interrupt handler into the IRAM section. It might work better if you use a global (maybe static) function.

Cache disabled but cached memory region accessed

This is why IRAM_ATTR is strictly necessary for any ISR.

void loop() override {

why do you need override?

@barrymossel
Copy link
Author

barrymossel commented Jan 5, 2024

Hi, a few thoughts, maybe it help you with writing your usermod.
Thanks!

RCValue1 = pulseIn(RCPin1, HIGH);

This is blocking the WLED main loop for up to one second. Your usermod should not block for more than 50ms, otherwise strange things will happen (like watchdog abort). It may work better if you use the timeout parameter, like RCValue1 = pulseIn(RCPin1, HIGH, 50);

This was just for testing purposes. And it actually looked like to work. Almost. ;-)

adding a delay(500) at the end of the setup

bad idea, see above. Try to keep the "blocking time" of your usermod as low as possible.

This was because of something I noticed in other usermods (applyPreset looked to break stuff at startup). But again for testing purposes. And actually the first time I did it, everything work like expected. For once. After a new compile it was broken and I couldn't reproduce...

attachInterrupt(digitalPinToInterrupt(RCPinChan1), PulseTimerChan1, CHANGE);

If you want to use an ISR, it must have IRAM_ATTR. The "dangerous relocation: l32r" warning could mean you can't use a class method as interrupt handler function. The usermod object is instantiated at run-time, so the linker does not have the address at link-time for putting your interrupt handler into the IRAM section. It might work better if you use a global (maybe static) function.

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...)

void loop() override {

why do you need override?

I really don't know and did remove it already. ;-)

@softhack007
Copy link
Collaborator

softhack007 commented Jan 5, 2024

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 you'd define ISR functions at the beginning of the 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.

@barrymossel
Copy link
Author

barrymossel commented Jan 5, 2024

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!

@softhack007
Copy link
Collaborator

softhack007 commented Jan 5, 2024

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();".

@barrymossel
Copy link
Author

barrymossel commented Jan 5, 2024

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 you'd define ISR functions at the beginning of the 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.

This is so frustrating. With your help I managed to make it work. But two lines were in the wrong order. I applied the preset before I changed the variable which the applyPreset used. No problem. Changed it, and compiled again. But after flashing nothing (WLED) works anymore. Had that before and it looked liked the bootloader was gone. After installing WLED through the browser it works again. But flashing the bin from platformio afterwards, breaks it again...? All I changed was:

From:

    void loop() {
      if (PulsesChan1 < 2100){
        PulseWidthChan1 = PulsesChan1;
      }
        if ((PulseWidthChan1 < 2100) && (PulseWidthChan1 > 1750) && (PulseOptionChan1 != 1)) {
          Serial.println("Optie 1");
          Serial.println(PulseWidthChan1);
          applyPreset(PulseOptionChan1);
          PulseOptionChan1 = 1;
        } 
        if ((PulseWidthChan1 < 1700) && (PulseWidthChan1 > 1500) && (PulseOptionChan1 != 2)) {
          Serial.println("Optie 2");
          Serial.println(PulseWidthChan1);
          applyPreset(PulseOptionChan1);
          PulseOptionChan1 = 2;
        }
        if ((PulseWidthChan1 < 1450) && (PulseWidthChan1 > 1250) && (PulseOptionChan1 != 3)) {
          Serial.println("Optie 3");
          Serial.println(PulseWidthChan1);
          PulseOptionChan1 = 3;
          applyPreset(PulseOptionChan1);
        } 
        if ((PulseWidthChan1 < 1200) && (PulseWidthChan1 > 900) && (PulseOptionChan1 != 4)) {
          Serial.println("Optie 4");
          Serial.println(PulseWidthChan1);
          PulseOptionChan1 = 4;
          applyPreset(PulseOptionChan1);
        }
    }

to:

    void loop() {
      if (PulsesChan1 < 2100){
        PulseWidthChan1 = PulsesChan1;
      }
        if ((PulseWidthChan1 < 2100) && (PulseWidthChan1 > 1750) && (PulseOptionChan1 != 1)) {
          Serial.println("Optie 1");
          Serial.println(PulseWidthChan1);
          PulseOptionChan1 = 1;
          applyPreset(PulseOptionChan1);
        } 
        if ((PulseWidthChan1 < 1700) && (PulseWidthChan1 > 1500) && (PulseOptionChan1 != 2)) {
          Serial.println("Optie 2");
          Serial.println(PulseWidthChan1);
          PulseOptionChan1 = 2;
          applyPreset(PulseOptionChan1);
        }
        if ((PulseWidthChan1 < 1450) && (PulseWidthChan1 > 1250) && (PulseOptionChan1 != 3)) {
          Serial.println("Optie 3");
          Serial.println(PulseWidthChan1);
          PulseOptionChan1 = 3;
          applyPreset(PulseOptionChan1);
        } 
        if ((PulseWidthChan1 < 1200) && (PulseWidthChan1 > 900) && (PulseOptionChan1 != 4)) {
          Serial.println("Optie 4");
          Serial.println(PulseWidthChan1);
          PulseOptionChan1 = 4;
          applyPreset(PulseOptionChan1);
        }
    }

@barrymossel
Copy link
Author

And again this crap:

rst:0x10 (RTCWDT_RTC_RESET),boot:0x12 (SPI_FAST_FLASH_BOOT)
invalid header: 0xffffffff
invalid header: 0xffffffff
invalid header: 0xffffffff
invalid header: 0xffffffff
invalid header: 0xffffffff
invalid header: 0xffffffff

While it worked before... Not sure what to do now? Tried everything from erasing, overwriting through the web based install.

@barrymossel
Copy link
Author

barrymossel commented Jan 5, 2024

Don't know why it works now. But it did.

https://www.youtube.com/watch?v=i5QmDhw-LAM

Still don't know why platformio is compiling as it should and WLED won't run. Either with the reboot loop or without anything on serial nor wifi nor AP...

@barrymossel
Copy link
Author

And even with 8 presets. Really cool imo: https://www.youtube.com/watch?v=Q7T4zfhyXw0&t

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question usermod usermod related
Projects
None yet
Development

No branches or pull requests

3 participants