Problema Reset: SD + SimpleSDAudio.h + WDT

ciao a tutti.
Ho Assemblato un piccolo progetto basato sulla libreria simpleSdAudio.h
Tramite arduino e shield Sd leggo dei file audio e li mando in uscita ad una micro cassa ( Ho anche utilizzato un 74AC14 per amplificare il segnale e non sovraccaricare l'uscita dell'ATMEGA).
Per selezionare il file audio da leggere ho utilizzato un shield tilt sensor di modo che quando questo riceve un piccolo colpo, tramite la funzione random e uno switch-case, scelgo il file da eseguire.
Il tilt sensor manda a 1 l'uscita quando riceve un colpo.
Ho scelto di alimentare arduino tramite 2 pile stile e circuito boost per portare la tensione a 5V (500mA ma sto nei limiti alla grande).
Ora il tilt sensor potrebbe non ricevere mai un colpo. Per questo ho scelto di mandare arduino in sleep mode dopo 20 secondi, in modo tale da risparmiare energia.. Al primo avvio ( scheda appena alimentata o pulsante di reset premuto), aspetto 20 secondi ... arduino va in POWER DOWN MODE.....poi do un colpo sul tilt sensor e arduino si sveglia. subito dopo il risveglio ho impostato un reset forzato tramite il Watch dog timer. Posso andare avanti così infinite volte che il tutto funziona perfettamente.
Se entro i 20 secondi dal primo avvio, do un colpo al tilt sensor parte il suono selezionato e viene riprodotto perfettamente.
posso anche passare da una suono all'altra senza problemi semplicemente dando altri colpi al tilt sensor dopo un'attesa di 5 secondi. se invece aspetto 20 secondi, arduino va in sleep, ma non riesco più a risvegliarlo.
A qualcuno andrebbe di aiutarmi a capire dove sta il problema?
Proprio non ce ne vengo a capo.
posto il Codice assemblato.
Grazie mille

#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <SimpleSDAudio.h>
#define BUTTON  2
int val = 0;                                  // variable to store the read value
int randNumber= 0;
long previousMillis = 0;        // salvo il mills precedente 
int sec=0;

long interval = 1000;           // interval at which to blink (milliseconds)

void pin2Interrupt(void)
{
  /* This will bring us back from sleep. */
  
  /* We detach the interrupt to stop it from 
   * continuously firing while the interrupt pin
   * is low.
   */
  detachInterrupt(0);
}

void enterSleep(void)
{
    /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, RISING);
  delay(100);
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  sleep_mode();
  /* The program will continue from here. */
  
  /* First thing to do is disable sleep. */
  sleep_disable();
  
 delay(1000); 
 reset(); // reset con wdt
}

void reset() {
  wdt_enable(WDTO_250MS);
  while(1);
}


void setup()
{ 
  wdt_disable();
  // SdPlay.setSDCSPin(10); // Enable if your SD card CS-Pin is not at Pin 4... 
  SdPlay.init(SSDA_MODE_FULLRATE | SSDA_MODE_MONO | SSDA_MODE_AUTOWORKER);
  pinMode(BUTTON, INPUT);
}
void loop(void) {
  /*OROLOGIO UTILIZZANDO LA FUNZIONE MILLS. vOGLIO MANDARE IN SLEEP ARDUINO OGNI 
  20 SECONDI SE NON HO RICEVUTO ALCUN INGRESSO*/
 unsigned long currentMillis = millis();

 if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    sec++;
    previousMillis = currentMillis;   
    if (sec==20){
    sec= 0;
    enterSleep();
    delay(50);
    }
 }
//-------------------------
    
   val = digitalRead(BUTTON);   // read the input pin
     if (val == 1)
     {
      sec=0;
      randomSeed(millis());      // imposta millis() come base per 
                                // generare un numero 
                               // casuale da 1 a 3 
      randNumber = random(1,4); // numero casuale da 1 a 3
      switch (randNumber) 
             {
              case 1:
                     SdPlay.setFile("EXAMPLE.AFM"); 
                     SdPlay.play();
                     delay(5000);
                     while(!SdPlay.isStopped()) 
                          {
                           val = digitalRead(BUTTON);
                           if (val == 1)
                              {
                              sec=0;
                              SdPlay.stop();
                              val = digitalRead(BUTTON);
                              break;
                              }// no SdPlay.worker() required anymore :-)
                           }//do something when var equals 1
                      SdPlay.stop();
                      break;
             case 2:
                     SdPlay.setFile("SCRUBS.AFM"); 
                     SdPlay.play();
                     delay(5000);
                     while(!SdPlay.isStopped()) 
                          {
	                   val = digitalRead(BUTTON);
                           if (val == 1)
                              {
                              sec=0; 
                              SdPlay.stop();
                              val = digitalRead(BUTTON);
                              break;
                              }
                            }
                        SdPlay.stop();       
                        break;
               case 3:
                         SdPlay.setFile("NELLANOT.AFM"); 
                         SdPlay.play();
                         delay(5000);
                         while(!SdPlay.isStopped()) 
                              {
	                      val = digitalRead(BUTTON);
                              if (val == 1)
                              {
                                    sec=0; 
                                    SdPlay.stop();
                                    val = digitalRead(BUTTON);
                                    break;
                               }
                               }
                         SdPlay.stop();      
                         break;
              }
       }
   }

In power down gli INT esterni funzionano solo in LOW level. Staccando il clock di sistema (questo è ciò che succede quando metti in sleep il chip, togli il clock a diverse periferiche secondo la tabella 10.1 del datasheet), anche i GPIO vengono fermati e l'unico stato che riescono eventualmente a leggere in sleep è proprio un segnale LOW. Devi quindi invertire la logica, mettere una pull-up sul pin e fare in modo che ti arrivi al pin un segnale LOW

Ciao. ti ringrazio molto per la risposta.
Leggendo il datasheet a pag 40, proprio all'inizio, mi sembra di capire che anche un cambiamento del pin può risvegliare arduino.
Comunque all'inizio del programma il wake up funziona benissimo.
Ho risolto cambiando il codice in questo modo:
Ho spostato la funzione detachInterrupt(0); subito dopo la chiamata dello sleep
l'ho quindi rimossa dalla funzione pin2interupt.
Non capisco come mai ora il tutto funziona egregiamente

#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/power.h>
#include <SimpleSDAudio.h>
#define BUTTON  2
int val = 0;  // variable to store the read value
int randNumber= 0;
long previousMillis = 0;        // will store last time LED was updated
int sec=0;

// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)

//void(* resetFunc) (void) = 0; //declare reset function @ address 0

void pin2Interrupt(void)
{
  /* This will bring us back from sleep. */
  
  /* We detach the interrupt to stop it from 
   * continuously firing while the interrupt pin
   * is low.
   */
  //detachInterrupt(0);
}

void enterSleep(void)
{
  
  /* Setup pin2 as an interrupt and attach handler. */
  attachInterrupt(0, pin2Interrupt, RISING);
  delay(100);
  
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  
  sleep_enable();
  
  sleep_mode();
  
  /* The program will continue from here. */
  
  /* First thing to do is disable sleep. */
  sleep_disable();
  //resetFunc();  //call reset
  delay(1000); 
   reset(); // reset con wdt
}

void reset() {
  wdt_enable(WDTO_250MS);
  while(1);
}


void setup()
{ 
  wdt_disable();
  // SdPlay.setSDCSPin(10); // Enable if your SD card CS-Pin is not at Pin 4... 
  SdPlay.init(SSDA_MODE_FULLRATE | SSDA_MODE_MONO | SSDA_MODE_AUTOWORKER);
  pinMode(BUTTON, INPUT);
}
void loop(void) {
  /*OROLOGIO UTILIZZANDO LA FUNZIONE MILLS. vOGLIO MANDARE IN SLEEP ARDUINO OGNI 
  20 SECONDI SE NON HO RICEVUTO ALCUN INGRESSO*/
 unsigned long currentMillis = millis();

 if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    sec++;
    previousMillis = currentMillis;   
    if (sec==20){
    sec= 0;
    enterSleep();
    [b]detachInterrupt(0);[/b]
    delay(50);
    }
 }
//-------------------------
    
   val = digitalRead(BUTTON);   // read the input pin
     if (val == 1)
     {
      sec=0;
      randomSeed(millis());      // imposta millis() come base per 
                                // generare un numero 
                               // casuale da 1 a 3 
      randNumber = random(1,4); // numero casuale da 1 a 3
      switch (randNumber) 
             {
              case 1:
                     SdPlay.setFile("EXAMPLE.AFM"); 
                     SdPlay.play();
                     delay(5000);
                     while(!SdPlay.isStopped()) 
                          {
                           val = digitalRead(BUTTON);
                           if (val == 1)
                              {
                              sec=0;
                              SdPlay.stop();
                              val = digitalRead(BUTTON);
                              break;
                              }
                           }
                      SdPlay.stop();
                      break;
             case 2:
                     SdPlay.setFile("SCRUBS.AFM"); 
                     SdPlay.play();
                     delay(5000);
                     while(!SdPlay.isStopped()) 
                          {
	                   val = digitalRead(BUTTON);
                           if (val == 1)
                              {
                              sec=0; 
                              SdPlay.stop();
                              val = digitalRead(BUTTON);
                              break;
                              }
                            }
                        SdPlay.stop();       
                        break;
               case 3:
                         SdPlay.setFile("NELLANOT.AFM"); 
                         SdPlay.play();
                         delay(5000);
                         while(!SdPlay.isStopped()) 
                              {
	                      val = digitalRead(BUTTON);
                              if (val == 1)
                              {
                                    sec=0; 
                                    SdPlay.stop();
                                    val = digitalRead(BUTTON);
                                    break;
                               }
                               }
                         SdPlay.stop();      
                         break;
              }
       }
   }

Gli interrupt di cambio di stato sono i PCINT, non gli INT.
Però rileggendo a pag. 71, cap. 13, vedo che gli INTx "sentono" anche il RISING ed il FALLING, scusami ma mi ricordavo solo del LOW incaponendomi su questa convinzione e non esaminando bene il tuo sketch :sweat_smile:

Ma scherzi!? ci mancherebbe!!!
Ti ringrazio in tutti i casi per l'aiuto. Sto anche capendo qualcosa in più.
Ora che ho risolto il problema del risveglio, sto lavorando sempre in ottica per rendere la scheda più efficiente dal punto di vista energetico.
Ho spostato il progetto su circuito minimal a 8Mhz con oscillatore interno. ( ho seguito la famosa guida del prof e programmazione ISP tramite arduino UNO su breadbord)
Attualmente i 5V mi stanno diventando inutili.
Come posso alimentare arduino a 3.3V? avete qualche consiglio?

L'Arduino non puoi alimentarlo a 3V3, l'elettronica di bordo è fatta per lavorare a 5V.
Se però parliamo di chip in standalone, allora puoi abbassare la tensione a 3V3 senza problemi. Per risparmiare energia puoi studiarti il Micrologio, un progetto che ho realizzato tempo fa basato su un Atmega 1 MHz tenuto per la maggior parte del tempo in sleep profondo mediante una serie di accorgimenti. Se guardi nel codice vedrai come vado ad accendere/spengere le periferiche via via che entro ed esco dallo sleep. Ricordati che lo sleep toglie solo il segnale del clock alle periferiche (tipo seriale, timers, watchdog, Adc ecc) ma non vengono spente per cui anche in sleep continuano a consumare una minima corrente.