Arduino core for ESP32 Wiki content

Change global variables from ISR

If a global variable is changed from within a ISR a Guru Meditation Error: Core 1 panic'ed (Cache disabled but cached memory region accessed) can be triggered causing the application to fail and force the ESP32 to reboot. The proper programming is to declare the variable as static volatile and to mark the ISR code with the compiler flag IRAM_ATTR

Example code:

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);
  }
}