-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Guru Meditation Error: Core 1 panic'ed (Cache disabled but cached memory region accessed) ESP32 ARDUINO IDE #855
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
Comments
Fwiw, this looks like it is caused by interrupt firing while cache is disabled, see #489. |
the code that was triggered by the interrupt did not have the IRAM_ATTR attribute. Most O/S library function cannot be called from an ISR. Review your code, make sure that every function it calls is local. and has the IRAM_ATTR attribute. For example, you Cannot call Serial.print() from an ISR. Chuck. |
sorry to say but i didnt get how to fix the issue as i am using arduino ide |
Read through this info for a more detailed discussion: The function you attach to the interrupt: static volatile uint16_t intTriggerCount=0; // this variable will be changed in the ISR, and Read in main loop
// static: says this variable is only visible to function in this file, its value will persist, it is a global variable
// volatile: tells the compiler that this variables value must not be stored in a CPU register, it must exist
// in memory at all times. This means that every time the value of intTriggeredCount must be read or
// changed, it has be read from memory, updated, stored back into RAM, that way, when the ISR
// is triggered, the current value is in RAM. Otherwise, the compiler will find ways to increase efficiency
// of access. One of these methods is to store it in a CPU register, but if it does that,(keeps the current
// value in a register, when the interrupt triggers, the Interrupt access the 'old' value stored in RAM,
// changes it, then returns to whatever part of the program it interrupted. Because the foreground task,
// (the one that was interrupted) has no idea the RAM value has changed, it uses the value it 'know' is
// correct (the one in the register).
void IRAM_ATTR isr(){ //IRAM_ATTR tells the complier, that this code Must always be in the
// ESP32's IRAM, the limited 128k IRAM. use it sparingly.
intTriggeredCount++;
}
void setup(){
Serial.begin(115200);
pinMode(5,INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(5),isr,FALLING);
}
void loop(){
// magic happens her
static uint16_t old_Value=0; // this variable is only visible inside loop(),
// but it is persistent, It is only init'ed
// once, and each time through loop() it remembers its prior value
if(old_Value != intTriggeredCount){
old_Value = intTriggeredCount; // something to compare against
Serial.printf(" Someone grounded pin 5 again, it is the %d's time! Better call the Cops!",intTriggeredCount);
} Chuck. |
thanks stickbreaker |
Closed due it was solved =) |
@stickbreaker @igrr : I logged an issue #1352 . Could you kindly look at it to see if its similar to #855 ? The IRAM_ATTR solution mentioned here didn't work though. |
Beware, not only the ISR (Interrupt) has to be in IRAM! I made the mistake of using a normal function in my ISR and my ESP32 kept panicing when my code wanted to use the Preferences library (saving data to flash memory). I fixed it by also writing Edit: It still happened and I found that you can't use |
@freemind64 Please edit your post, put three backticks(left apostrophe) on a separate line before your code, and three backticks on a new line after your code. It makes it easier to read. Chuck. |
sorry, I couldn't edit that code. the main issue are these function: void IRAM_ATTR doEncoderA() when I test encoder in a separate program , it doesn't show any error . but in this one : when I want to start calibration process, esp32 begin to reset with error in this topic. |
//====================================
void doEncoderA() {
// look for a low-to-high on channel A
if (digitalRead(encoder0PinA) == HIGH) {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
else // must be a high-to-low edge on channel A
{
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}
void doEncoderB() {
// look for a low-to-high on channel B
if (digitalRead(encoder0PinB) == HIGH) {
// check channel A to see which way encoder is turning
if (digitalRead(encoder0PinA) == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
// Look for a high-to-low on channel B
else {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinA) == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}
//==================================== These two functions need to be resident in IRAM whenever the interrupt occurs. The ESP32 stores code in FLASH ROM, but it has to copy it into RAM before it can execute it. It uses a small RAM cache (64kB) as a buffer scratch pad, normal code is automatically copied from FLASH to ICACHE when needed, but interrupt code is assumed to always be present in RAM. So, You must tell the compiler to place these functions, and all the code they execute into IRAM. This is accomplished by: void ATTR IRAM doEncoderA() {
//cut
void ATTR IRAM doEncoderB() {
//cut Something else you might consider, I have see comments about pin interrupts triggering on CHANGE even though you have specified RISING or FALLING. I have not had time to test these conjectures, but since it would effect your code you might want to test it. static volatile bool lastState0A=false; //persistent, will be changed during interrupt
static volatile bool lastState0B=false;
static volatile int encoder0Pos=0; // Why did you define pos as a FLOAT? it is an integer value?
void ATTR IRAM doEncoderA() {
bool currentState = digitalRead(encoder0PinA);
if(currentState == lastState) return; // glitch nothing to do
lastState0A = currentState; // Store current pin0 State
// look for a low-to-high on channel A
if (currentState == HIGH) {
// check channel B to see which way encoder is turning
if (lastState0B == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
else{ // must be a high-to-low edge on channel A
// check channel B to see which way encoder is turning
if (lastState0B == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
} Chuck. |
Using this and define encoder0Pos as an int solved my problem. |
@freemind64 The major difference between integer and float data types is speed of execution. A float is a complex structure, that stores an approximation of a number. It usually cannot exactly record a value. simple explanation of internal FLOAT storage better explanation of FLOAT storage Both of these explanations show how complex FLOATs are. Think about how you would code a function to update the bit value of a FLOAT directly, it is tough. So, unless you need decimal value approximations, use integer types for performance. Chuck. |
@stickbreaker again another problem that might be about this issue.
even serial print didn't work. |
@freemind64 use three backtick's ``` on a line by themselves to bracket your code. What was the while loop supposed to do? Did it not compile? Did it not loop? If you want my help you are going to have to make it easy for me. Why would you expect me to correctly guess what you expected the code to do? Without even telling me what you observed the code doing? You do realize that vowels do not cost extra? What are you trying to achieve with: void gc() {
void doEncoderA();
void doEncoderB(); Full text of function:, Snarky comments added by me void gc() {
void doEncoderA();
void doEncoderB();
int dpr = 0; // depreciation rate
int z = 0; // last letter of the alphabet
encoder0Pos = (int)(gp / anglm); // reduce gross product by angular mass
gpr = gp; // set gross product rate to gross product
prr = pr * 10000; // set prior rate to prior times ten thousand?
Serial.print("encoder0Pos:"); Serial.println(encoder0Pos);
if (prr < gpr) { // if prior rate less than gross product rate then cow it.
cw();
do {
gpr = (int)(abs(encoder0Pos) * anglm) ;
dpr = gpr - prr;
Serial.println("pr < gp");
Serial.print("gp:"); Serial.println(gpr);
Serial.print("dp:"); Serial.println(dpr);
yield();
} while (dpr == 0);
stp();
Serial.println(gpr);
}
if (prr > gpr) {
ccw();
Serial.println("pr > gp");
while (prr != gpr); {
gpr = (int)(abs(encoder0Pos) * anglm);
// dpr = prr - gpr;
Serial.println("pr > gp");
Serial.print("gp:"); Serial.println(gpr);
Serial.print("dp:"); Serial.println(dpr);
yield();
}
Serial.print("gp:"); Serial.println(gpr);
stp();
}
Serial.print("encoder0Pos:"); Serial.println(encoder0Pos);
encoder0Pos = 0;
EEPROM.writeInt(30, gp);
EEPROM.commit();
}
//============================= Chuck. |
ok.
|
@freemind64 static volatile int32_t currentPos=0; // init to 0
static volatile bool motorRunning=false; // motor is not moving
static volatile bool lastStateA = false;
static volatile bool lastStateB = false;
#define clockWiseLimitPin 15 //when gpio15 is low, limitswitch is active.
#define counterClockWiseLimitPin 16 //when gpio16 is low, limitswitch is active.
#define encoderAPin 17
#define encoderBPin 18
bool ATTR IRAM stopRotation(){ //IRAM because this function can also be called from Interrupt
// actually control the motor here. If successful, mark motorRunning state.
motorRunning = false;
return !motorRunning;
}
bool rotateClockWise(){
// actually control the motor here. If successful, mark motorRunning state.
motorRunning = true;
return motorRunning;
}
void ATTR IRAM encoderA(){ // a/b rotation encoder,
bool currentState = digitalRead(encoderAPin); //
if ( lastStateA == currentState) return; // spurious interrupt, ignore it
lastStateA = currentState;
if ( currentState ) { //pin went high
if( !lastStateB ) { // clockWise rotation, because B is Low
currentPos++; // increment position
if( !digitalRead(clockWiseLimitPin)) { // limit is active, stop motor
stopRotation();
}
}
else { // counterClockWise rotation
currentPos--; // decrement position
if( !digitalRead(counterClockWiseLimitPin)) { // limit is active stop motor
stopRotation();
}
}
}
else { // pin went low
if( lastStateB ){ // clockWise Rotation, because B is high and A went Low
currentPos++;
if( !digitalRead(clockWiseLimitPin)) { // limit is active, stop motor
stopRotation();
}
}
else { // counterClockWise rotation
currentPos--;
if( !digitalRead(counterClockWiseLimitPin)) { // limit is active stop motor
stopRotation();
}
}
}
}
bool gotoPosition(int32_t newPos, uint32_t timeOut){
uint32_t tick=millis(); // movement starting tick, in milliseconds
bool successfulMove = false;
If (newPos > currentPos){ // move clockwise
if (!rotateClockWise()) { // motor failed when attempting clockwise rotation
// this failure could be because the motor is at the clockWise limit also
return false;
}
while(((millis()-tick)<timeOut) && (newPos > currentPos) && motorRunning){
// motorRunning is volatile, updated if rotation limit exceeded.
// currentPos is volatile, updated by encoder interrupts.
// timeOut will handle millis() overflow
yield(); // wait for motor to move enough
}
if (!stopRotation()){ // Motor stop failed
return false;
}
successfulMove = (currentPos <= newPos);
}
else if ( newPos < currentPos){
if (!rotateCounterClockWise()) { // motor failed when attempt counterClockWise rotation
return false;
}
while(((millis()-tick)<timeout) && (newPos < currentPos) && motorRunning){
yield();
}
if (!stopRotation()){ // Motor stop failed
return false;
}
successfulMove = (currentPos<=newPos);
}
else { // newPos == currentPos, so nothing to do
successfulMove = true;
}
return successfulMove;
} Calculate the new position before you pass it to the function, all the angular scaling should happen Short, simple and descriptive. Don't use abbreviate variable names. Think about how you would support this code in 10 years. I have code I wrote in 1986 in Pascal on a Chuck. |
thanks Chuck. It was helpful, just you have to know entire rotation from close to open, when you want to write control loop to reach new position.
we need a calibration process to know entire rotation , then we know current position as you wrote in your code.
they control rotation or limits of motor because they are different. In Arduino-IDE we must use this IRAM_ATTR ,your code is ATTR IRAM. |
@freemind64 You call them close limit switch and open limit switch. I don't know your circuit, so I just created two LOW active switches that activate when a clockwise or counterclockwise limit is reached. I just wanted to show that the limits switches should be monitored inside the encoder interrupt routine. That way the limits are enforced immediately, if a limit is reached the motor should stop. Also, you should add a limit check before you start moving the motor. If the motor is at a clockwise limit, you should not move the motor clockwise. Have the Good catch on the IRAM. Chuck. |
@stickbreaker , the code was ok and worked for me , just to complete the issue .
encoder position :
and control function :<thanks to chuck @stickbreaker >
|
Hi, @stickbreaker
Crash error. |
@human890209, the esp32 has to disable the iCache(instruction Cache, the RAM buffer used to execute code stored in the external FLASH chip) whenever it needs to programmatically access the Data in the FLASH chip(SPIFFS, NVS, PREFERENCES). The problem occurs because changing data in the FLASH is a 3 step process, first read the PAGE(4kB) into the iCache buffer, that needs to be changed. Second, tell the FLASH chip to erase the selected PAGE(takes about 32ms for the chips hardware to accomplish). Third, apply the changes to the iCache buffer image, then write this updated page(4kB) back to the FLASH. During this entire sequence NO code can be executed from iCache, only code in IRAM, or ROM is available. Your ISR(interrupt service routine) must not call any code in iCache. You have to Verify all code you call is in IRAM. AND IRAM is only 128kB total. IRAM is used by the FreeRTOS core, and all of the hardware drivers. So, only a small amount is free for user code. Chuck |
Hi, @stickbreaker
I see these 2 lines in the table which is displayed after compiling. I see about 46k of IRAM usage. Are all the drivers and FreeRTOS codes in this 46k or it's only a total sum of user code?
|
@human890209 should be all of the resident code, this is the recipe from 'tools/sdk/ld/esp32.common.ld'
The more code placed in IRAM the less RAM available for data. Chuck. |
Hi folks, I have same problem and I did set up my function like this: But I am getting error: error: expected initializer before 'IRAM' Thanks. |
@markosole it's missing a underscore, the correct is |
Thanks a lot that works now. Here is sample which may be handy for someone.
Thanks guys. |
@felixqueisler I have the same problem with the preferences library, that´s why I want to ask if you could share the code you talked about in your post? This is the first time i have encountered such a problem as i am fairly new to ESP32, that´s also why i couldn´t quite understand the solutions posted in this thread. Please, your help would be greatly appreciated. |
You have an interrupt function defined... Inside that function you only do the bare minimum. You check for a condition and when it's true you either set a boolean = true or an integer ++; In the main loop you then check for those flags to execute more code and then set the flag false or -- or 0. |
yes there is definitely a problem with analogRead from an ISR (e.g. void IRAM_ATTR onTimer())
and in the timer ISR:
Stoping the timer does nothing |
From @jt040-jetnet on November 21, 2017 10:21
i am using esp32 in arduino core
i am using touch key feature in interrupt
getting below error and my esp32 gets restart ,
please suggest how to fix it,
Guru Meditation Error: Core 1 panic'ed (Cache disabled but cached memory region accessed)
Register dump:
PC : 0x400d13f4 PS : 0x00060034 A0 : 0x40082388 A1 : 0x3ffc0bf0
A2 : 0x00000000 A3 : 0x3ffc3590 A4 : 0x00000001 A5 : 0x40086408
A6 : 0x00000003 A7 : 0x00060e23 A8 : 0x80081142 A9 : 0x04000c01
A10 : 0x00060e23 A11 : 0x00000000 A12 : 0x00060023 A13 : 0x3ffc0bd0
A14 : 0x3ffc0c18 A15 : 0x00000001 SAR : 0x0000001e EXCCAUSE: 0x00000007
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff
Backtrace: 0x400d13f4:0x3ffc0bf0 0x40082385:0x3ffc0c10 0x4008f54f:0x00000000
Rebooting...
ets Jun 8 2016 00:22:57
rst:0x3 (SW_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0010,len:4
load:0x3fff0014,len:716
load:0x40078000,len:0
load:0x40078000,len:11572
entry 0x40078a14
Copied from original issue: espressif/esp-idf#1299
The text was updated successfully, but these errors were encountered: