33 IoT improper recovery from deep Sleep with external Interrupt

Hi,

To check the deep sleep utility of a Nano 33IoT, I have modified a code available at Arduino nano 33 IoT SLEEP and external Interruption

The Interrupt works almost correctly ... Whereas the BUILTIN LED (Pin D13) flashes according to the code the serial monitor does not show any printouts at all. As I'm testing this code to use the deep sleep command in a more extensive application, I have some concerns about using it.

Does anybody have some documentation regarding the Nano 33 IoT deep sleep command, whatsoever?

Thanks in advance - The Code as follows.

boolean flag = false;

void setup() 
{
  Serial.begin(9600);
  delay(1000);
  Serial.println("Starting ... ");
  pinMode(LED_BUILTIN, OUTPUT);                                 // Set digital pin D13 to an input with an internal pull-down resistor
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  pinMode(3, INPUT);                                            // Set digital pin D2 to an input with an internal pull-down resistor
  delay(1000);
  Serial.println("LED SEQUENCE FINISHED ... ");
  attachInterrupt(digitalPinToInterrupt(3), interrupt, HIGH);  
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;                           // Set up the CPU to enter low power STANDBY mode on running the WFI() function (Wait For Interrupt)
  __WFI();
  
}

void loop() 
{
  Serial.println("Within the Main Loop ... ");
  if(flag){Serial.println("If here, ISR complete ...  ");Serial.println("--------------------------");flag=false;}
  digitalWrite(LED_BUILTIN, HIGH);     
  delay(1000);                                  // Wait for 1 second
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
  digitalWrite(LED_BUILTIN, HIGH);     
  delay(1000);                                  // Wait for 1 second
  digitalWrite(LED_BUILTIN, LOW);
  __WFI(); 
}

void interrupt()
{
  flag = true;
}

THX for your comment. However, when getting back to the main loop, after recovering from the interrupt, no printouts

Hi Delta_G, thanks for your advice. However, even if we try brute force ways, it will never work, as it happens in fact, now!

After a deep search, I discovered that the Nano 33IoT (SAMD21G18A) needs a core PATCH when standby "wakeup" is used with interrupts. The following link has this "small letter" message at the very end of the information displayed ...

link:

Message:
####Notes: External interrupt during standby on ATSAMD21G18A requires a patch to the Arduino SAMD Core in order for it to work. Fix is provided by this particular pull request.

Will try a solution, according to the hints in this link. Will comment back when sorted.

Thanks anyway - Have a great day!

Hi @Bowsprit

Here's how to set-up the SAMD21 for deep sleep:

// Set Up Deep Sleep Mode--------------------------------------------------------------
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;// | SCB_SCR_SLEEPONEXIT_Msk;  // Put the SAMD21 in deep sleep upon executing the __WFI() function
NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_SLEEPPRM_DISABLED;        // Disable auto power reduction during sleep - SAMD21 Errata 1.14.2

...and to place the microcontroller into deep sleep:

// Due to a hardware bug on the SAMD21, the SysTick interrupts become active before the flash has powered up from sleep, causing a hard fault
// To prevent this the SysTick interrupts are disabled before entering sleep mode
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;           // Disable SysTick interrupts
__DSB();                                              // Complete outstanding memory operations - not required for SAMD21 ARM Cortex M0+
__WFI();                                              // Put the SAMD21 into deep sleep, Zzzzzzzz...  
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;            // Enable SysTick interrupts

Hi MartinL, THX for your support on the subject - Will give it a try and come back with a thumbs up when sorted!
Cheers

Hi Delta_G, THX for this reminder - Dead right!

Will try MartinL's code. When done, will come back with the way I sorted out the issue. THX again!
Cheers

@MartinL, I prepared the following code including your suggestions. In principle, the code works pretty well, regarding the interrupts and awakening of the Arduino nano 33 IoT that I am using. However, the serial monitor does not show any text at all, after coming back from the awakening ... is there any trick for this or am I just MONKEYING over?

The code



volatile boolean flag = false;

void setup() 
{
  while(!Serial);
  Serial.begin(9600);
  Serial.println("Starting ... ");
  delay(1000);
  pinMode(13,OUTPUT);
  pinMode(3,INPUT);

    for ( int n = 0; n < 2; n++) 
    {
      Serial.println(" .............. Counting to 2 ... ");
      digitalWrite(LED_BUILTIN, HIGH);
      delay(400);
      digitalWrite(LED_BUILTIN, LOW);
      delay(200); 
    }

  //delay(1000);
  attachInterrupt(digitalPinToInterrupt(3), interrupt, HIGH);  
  
  // -------------------------------- Set Up Deep Sleep Mode ----------------------------
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;                           // Set up the CPU to enter low power STANDBY (Deep Sleep) mode on running the WFI() function (Wait For Interrupt)
  NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_SLEEPPRM_DISABLED;       // Disable auto power reduction during sleep - SAMD21 Errata 1.14.2
  // ------------------------------------------------------------------------------------  


  // ------------------------- Place the microcontroller into deep sleep ------------------
  // Due to a hardware bug on the SAMD21, the SysTick interrupts become active before the flash has powered up from sleep, causing a hard fault
  // To prevent this the SysTick interrupts are disabled before entering sleep mode
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;           // Disable SysTick interrupts
  __WFI();                                              // Put the SAMD21 into deep sleep, Zzzzzzzz...  
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;            // Enable SysTick interrupts
  // ---------------------------------------------------------------------------------------
  
}

void loop() 
{
  Serial.println("Within the Main Loop ... ");
  //delay(1000);
  
  //digitalWrite(LED_BUILTIN, HIGH);
    for ( int z = 0; z < 3; z++) 
    {
      Serial.println(" .............. Counting to 3 ... ");
      digitalWrite(LED_BUILTIN, HIGH);
      delay(200);
      digitalWrite(LED_BUILTIN, LOW);
      delay(1000); 
    }
  delay(1000);
  //digitalWrite(LED_BUILTIN, LOW);
  Serial.print("... Flag is ... ");Serial.println(flag);
  if(flag)
  {
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("........................................................................  If here, ISR complete ...  ");
    for ( int r = 0; r < 4; r++) 
    {
      Serial.println(" .............. Counting to 4 ... ");
      digitalWrite(LED_BUILTIN, HIGH);
      delay(100);
      digitalWrite(LED_BUILTIN, LOW);
      delay(300); 
    }
    Serial.println("--------------------------");
    flag=false;
    delay(1000);
    Serial.print("......................................................... Flag just before going to sleep 'zzzzz' is ... ");Serial.println(flag);
  }
  //__WFI();
}

void interrupt()
{
    flag = true;
}

Thanks in advance!

Hi @Bowsprit

Yes, there is.

Here's a code example that uses a button (interrupt) to wake up the SAMD21 from sleep. It then writes to the native serial port before going back to sleep once more. The pattern repeats for each press of the button:

void setup(void) {
  pinMode(A1, INPUT_PULLUP);                      // Intialise button input pin and activate internal pull-up resistor
  pinMode(LED_BUILTIN, OUTPUT);                   // Initialise the LED_BUILTIN output
  attachInterrupt(A1, dummyFunc, LOW);            // Activate a LOW level interrupt on the button pin
  NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;    // Prevent the flash memory from powering down in sleep mode
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;              // Select standby sleep mode
  SerialUSB.begin(115200);                        // Intialise the native USB port
  while (!SerialUSB);                             // Wait for the console to open
}

void loop() {
  digitalWrite(LED_BUILTIN, LOW);                 // Turn off the LED
  SerialUSB.println(F("Sleeping Zzzz...wait for button to wake"));  // Send sleep message to the console
  USBDevice.detach();                             // Detach the native USB port
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;     // Disable SysTick interrupts
  __DSB();                                        // Ensure remaining memory accesses are complete
  __WFI();                                        // Enter sleep mode and Wait For Interrupt (WFI)
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;      // Enable SysTick interrupts
  USBDevice.attach();                             // Re-attach the native USB port
  digitalWrite(LED_BUILTIN, HIGH);                // Turn on the LED
  delay(500);                                     // Wait for half a second (seems to be necessary to give time for the USB port to re-attach)
  while(!SerialUSB);                              // Wait for the console to re-open
  SerialUSB.println();                            // Add a newline
  SerialUSB.println(F("Button depress...waking up")); // Send a wake up message
  delay(500);                                     // Wait half a second
}

void dummyFunc() {}

Dear @MartinL, Thank you so much for your VALUABLE and PRECISE HINT. I have been able to sort out all the issues , I was facing previous to your advice.

I´m leaving the code I prepared, so anybody having issues with a SAMD21 SLEEPING requirement, can be efficient with the use of time. I felt this morning as I was MONKEYING arround, instead of aiming at the correct solution. A little nested though, but it works as expected.

Special comment - Something I discovered, that perhaps I certainly read on the fly, is that the Serial Monitor for Arduino IDE version 1.X is not able to restart when any sleep interrupt is placed into the MicroController. Hence, each time you want to check the Serial Monitor you will have to stop the Serial Monitor, before you press the Interrupt Button, and rapidly restart a new Serial monitor connection.

Thanks again - Best wishes for a week starting shortly!

THE CODE

/*
 * Skectch to test the deep sleep characteristic of an Arduino IoT33 (SAMD21 microcontroller family) 
 * Author - JPVP
 * May 21-2023 
 * Enjoy!
*/

volatile boolean flag = false;
int RoundCounter = 0;
int MicroSW_time = 0;
int last_MicroSW_time = 0;

void setup() 
{
  while(!Serial);
  Serial.begin(9600);
  Serial.println("Sketch ID - TaestLateNight1.2");
  Serial.println("+++++++++++++++++++++++++++++");
  Serial.println("");
  Serial.println("Starting the Test for the sleepe Arduino Nano 33 IOT ( SAMD21 )... ");
  delay(1000);
  pinMode(13,OUTPUT);
  pinMode(3,INPUT);

  for ( int n = 0; n < 2; n++) 
  {
    Serial.println("Checking the LED Counting up to 2 ... ");
    digitalWrite(LED_BUILTIN, HIGH);
    delay(400);
    digitalWrite(LED_BUILTIN, LOW);
    delay(200); 
  }

  attachInterrupt(digitalPinToInterrupt(3), interrupt, HIGH);  

  Serial.flush();
  
  // -------------------------------- Set Up Deep Sleep Mode -------------------------------
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;                                    // Set up the CPU to enter low power STANDBY (Deep Sleep) mode on running the WFI() function (Wait For Interrupt)
  NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_SLEEPPRM_DISABLED;                // Disable auto power reduction during sleep - SAMD21 Errata 1.14.2
  NVMCTRL->CTRLB.bit.SLEEPPRM = NVMCTRL_CTRLB_SLEEPPRM_DISABLED_Val;    // Prevent the flash memory from powering down in sleep mode
  // ---------------------------------------------------------------------------------------  

  USBDevice.detach();  // Consider deleting when fully in operation
  
  // ------------------------- Place the microcontroller into deep sleep ------------------
  // Due to a hardware bug on the SAMD21, the SysTick interrupts become active before the flash has powered up from sleep, causing a hard fault
  // To prevent this the SysTick interrupts are disabled before entering sleep mode
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;                           // Disable SysTick interrupts
  __WFI();                                                              // Put the SAMD21 into deep sleep, Zzzzzzzz ...  
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;                            // Enable SysTick interrupts
  // ---------------------------------------------------------------------------------------

  USBDevice.attach();  // Consider deleting when fully in operation
}

void loop() 
{
  Serial.println("Within the Main Loop ... ");
  //SerialUSB.println("Printing thtrough the SerialUSB");
  
  for ( int z = 0; z < 3; z++) 
  {
    Serial.println("Checking the LED Counting up to 3 arround the Main Loop ... ");
    digitalWrite(LED_BUILTIN, HIGH);
    delay(200);
    digitalWrite(LED_BUILTIN, LOW);
    delay(1000); 
  }
  delay(800);
  Serial.print("Flag is ... ");Serial.println(flag);
  if(flag)
  {
    Serial.begin(9600);
    Serial.flush();
    //SerialUSB.begin(9600);
    //SerialUSB.flush();
    
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("If here, ISR is complete! ");
    for ( int r = 0; r < 4; r++) 
    {
      Serial.println("Checking the LED Counting up to 4 within the ISR ... ");
      digitalWrite(LED_BUILTIN, HIGH);
      delay(100);
      digitalWrite(LED_BUILTIN, LOW);
      delay(300); 
    }
    Serial.println("----------------------------------------------------");
    flag=false;
    delay(1000);
    Serial.print("Flag just before going to sleep 'zzzzz' is ... ");Serial.println(flag);
    Serial.print("Interrupt RoundCounter [N°of times BUTTON at GPIO D3 is pressed] ... ");Serial.println(RoundCounter);
   
    USBDevice.detach();  // Consider deleting when full in operation
  
    // ------------------------- Place the microcontroller into deep sleep ------------------ 
    // Due to a hardware bug on the SAMD21, the SysTick interrupts become active before the flash has powered up from sleep, causing a hard fault
    // To prevent this the SysTick interrupts are disabled before entering sleep mode
    SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;           // Disable SysTick interrupts
    __WFI();                                              // Put the SAMD21 into deep sleep, Zzzzzzzz...  
    SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;            // Enable SysTick interrupts
    // ---------------------------------------------------------------------------------------

    USBDevice.attach(); // Consider deleting when full in operation  
  }

}

void interrupt()
{
  flag = true;
  // -----------  ISR debouncer ----------
  MicroSW_time = millis();
  if(MicroSW_time - last_MicroSW_time > 150)
  {
     RoundCounter = RoundCounter +1;
     last_MicroSW_time = MicroSW_time;
  }       
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.