Arduino Nano intermittently does not wake up from sleep mode

Hi guys,

I have a strange phenomen I would like to hear if you had the same and if anyone has suggestions how to make the code robust.

I have an Arduino Nano (basically), I want to send it to sleep mode to save power and then wake it up again with a press of the button on D12. Usually it works, but if I make changes to the code, even someplace else not related to sleep mode, it suddenly misbeahaves. It can always go to sleep mode, but sometimes refuses to wake up from it. Problem is I have a battery operated setup and the whole system is encased, therefore if the device goes to sleep but cannot wake up, I have to disassemble the whole build to access the reset pin (it's USB charged with no switch to kill power).

I'm pretty sure the root cause is a kind of race condition/timing, because it's intermittent. But I do not understand it, please help me.

Here is what I programmed the sleep mode handler:

  1. I program the pin change interrupt on D12 in the setup() like this:
  // pin change interrupt masks (see below list)
  PCMSK0 |= bit (PCINT4);    // pin 12 Main button
  1. Then I have a sleep mode handler latern on embedded into the loop(). If the device goes into sleep mode entry, following code is executed:
  else if (SaberState == S_SLEEP) {
          Serial.println("LoL");

      // repeat the interupt mask again here, it is already done in the setup() function
      // but for an unknown reason sometimes the device fails to wake up...
      PCMSK0 |= bit (PCINT4);    // pin 12 Main button
      delay(300);
      Serial.println("LoL");
      ADCSRA = 0;  // reduces another ~100uA!
      SleepModeEntry();

      // .. and the code will continue from here

      SleepModeExit();
      SaberState = S_STANDBY;
      PrevSaberState = S_SLEEP;
      ADCSRA = 135; // old_ADCSRA;   // re-enable ADC conversion
      // play boot sound
      SinglePlay_Sound(11);
      delay(20);
  }

The 2 functions to enter and leave sleep modes are here:

void sleepNow()         // here we put the arduino to sleep
{

    power_all_disable ();   // turn off all modules -> no measurable effect
     
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);   // sleep mode is set here

    sleep_enable();          // enables the sleep bit in the mcucr register
                             // so sleep is possible. just a safety pin 

    // turn off brown-out enable in software -> no measurable effect
    MCUCR = bit (BODS) | bit (BODSE);
    MCUCR = bit (BODS); 
  
    PCIFR  |= bit (PCIF0) | bit (PCIF1) | bit (PCIF2);   // clear any outstanding interrupts
    PCICR  |= bit (PCIE0) | bit (PCIE1) | bit (PCIE2);   // enable pin change interrupts

    sleep_mode();            // here the device is actually put to sleep!!
                             // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP

    sleep_disable();         // first thing after waking from sleep:
                             // disable sleep...
    detachInterrupt(0);      // disables interrupt 0 on pin 2 so the 
                             // wakeUpNow code will not be executed 
                             // during normal running time.

}

void SleepModeEntry() {
  // switch off all LS channels
  for (uint8_t i = 0; i < sizeof(ledPins); i++) {
    digitalWrite(ledPins[i], LOW);
  }
  // pin change interrupt masks (see below list)
  //PCMSK2 |= bit (PCINT20);   // pin 4 Aux button
  PCMSK0 |= bit (PCINT4);    // pin 12 Main button
  mpu.setSleepEnabled(true);
  Disable_MP3(true);
  mpu.setSleepEnabled(true); // included as dummy, for an unknown reason if it's not here and the dfplayer.sleep() is commented out, sound is disabled
  //dfplayer.sleep();
  pinMode(DFPLAYER_RX, OUTPUT);
  digitalWrite(DFPLAYER_RX, LOW);
  pinMode(DFPLAYER_TX, OUTPUT);
  digitalWrite(DFPLAYER_TX, LOW);
  delay (300);
  Disable_FTDI(true);
  sleepNow();     // sleep function called here
}

void SleepModeExit() {

  // cancel sleep as a precaution
  sleep_disable();
  power_all_enable ();   // enable modules again
  Disable_FTDI(false);
  mpu.setSleepEnabled(false);
  delay (300);
  Disable_MP3(false);
  pinMode(DFPLAYER_RX, OUTPUT);
  pinMode(DFPLAYER_TX, INPUT);
  delay (300);
  // only wake up the device if the main button is pressed for at least 1 sec
  //delay(1000);
  //if (digitalRead(MAIN_BUTTON) == LOW) {
    setup(); // redo all initializations
  //}
  //else { // Anti-Wake up Protection triggers, go back to slee mode
  //  SleepModeEntry();
  //}
}

I followed the instructions for sleep mode setup and wake-up from here:Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors

The whole project and code can be found here (last stable version, whereby some users already had issue with the sleep mode):