Deep sleep and native USB serial on Feather M0

Hi, All:

I have so far not been able to use the native serial USB port on the Adafruit Feather M0 if deep sleep modes are selected. The ArduinoLowPower library examples fail on the Feather M0, which I believe is because Adafruit and Arduino differ in how "Serial" is identified in the board manager.

Using Arduino IDE 1.8.19.

I've tried quite a number of experiments, without success. The closest I have come is with this simple RTC deep sleep example from the RTCZero library. It works as expected, with the LED blinking every 5 seconds.

/*
  Simple RTC Alarm for Adafruit Feather M0 modified from 
  RTCzero library example at https://github.com/arduino-libraries/RTCZero
  By: CaveMoa
  Date: 30/12/15
*/

#include <RTCZero.h>

/* Create an rtc object */
RTCZero rtc;
int AlarmTime;

void setup()
{
  rtc.begin();
  
}

void loop()
{

  // Simple indication of being awake
  digitalWrite(13, HIGH);   // turn the LED on 
  delay(100);              
  digitalWrite(13, LOW);    // turn the LED off
  delay(100);
  digitalWrite(13, HIGH);   // turn the LED on 
  delay(100);
  digitalWrite(13, LOW);    // turn the LED off
  

  AlarmTime += 5; // Adds 5 seconds to alarm time
  AlarmTime = AlarmTime % 60; // checks for roll over 60 seconds and corrects
  rtc.setAlarmSeconds(AlarmTime); // Wakes at next alarm time, i.e. every 5 secs
  
  rtc.enableAlarm(rtc.MATCH_SS); // Match seconds only
  rtc.attachInterrupt(alarmMatch); // Attach function to interupt
  rtc.standbyMode();    // Sleep until next alarm match
  
}

void alarmMatch() // Do something when interrupt called
{}

If I enable and use Serial by adding just three lines as follows, "awake" is printed once, but then nothing is ever again emitted by the Serial port (regardless of whether I use the serial monitor or a terminal program).

However, the LEDs continue to blink, and the COM port remains visible in the Windows 10 Device Manager, unless the "reset" button is double-pressed, whereupon the port becomes COM16.

I've posted this on the Adafruit forum and so far, no one seems to know what the problem is. If anyone knows of an example of successfully combining deep sleep with native USB serial on the Adafruit Feather M0, I would love to see it!

/*
  Simple RTC Alarm for Adafruit Feather M0 modified from 
  RTCzero library example at https://github.com/arduino-libraries/RTCZero
  By: CaveMoa
  Date: 30/12/15
*/

#include <RTCZero.h>

/* Create an rtc object */
RTCZero rtc;
int AlarmTime;

void setup()
{
  rtc.begin();
  Serial.begin(115200);
  while(!Serial);
}

void loop()
{

  // Simple indication of being awake
  digitalWrite(13, HIGH);   // turn the LED on 
  delay(100);              
  digitalWrite(13, LOW);    // turn the LED off
  delay(100);
  digitalWrite(13, HIGH);   // turn the LED on 
  delay(100);
  digitalWrite(13, LOW);    // turn the LED off

  Serial.println("awake");

  AlarmTime += 5; // Adds 5 seconds to alarm time
  AlarmTime = AlarmTime % 60; // checks for roll over 60 seconds and corrects
  rtc.setAlarmSeconds(AlarmTime); // Wakes at next alarm time, i.e. every 5 secs
  
  rtc.enableAlarm(rtc.MATCH_SS); // Match seconds only
  rtc.attachInterrupt(alarmMatch); // Attach function to interupt
  rtc.standbyMode();    // Sleep until next alarm match
  
}

void alarmMatch() // Do something when interrupt called
{}
1 Like

Update: It seems that on Adafruit SAMD M0 products, the native USB serial connection does not survive deep sleep mode. USB detach/attach is required, and the Arduino serial monitor does not work properly after the transition.

The following fix "sort of" works, sometimes, if a serial terminal program is used to monitor the native USB serial.

Since deep sleep is normally used with battery power, and battery powered Arduinos don't necessarily need native USB serial, the best solution is to avoid mixing deep sleep and native USB serial. But that is a pain for debugging!

/*
  Simple RTC Alarm for Adafruit Feather M0 modified from
  RTCzero library example at https://github.com/arduino-libraries/RTCZero
  By: CaveMoa
  Date: 30/12/15
*/

#include <RTCZero.h>

/* Create an rtc object */
RTCZero rtc;
int AlarmTime;

void setup()
{
  rtc.begin();
  Serial.begin(115200);
  while (!Serial);
}

void loop()
{

  // Simple indication of being awake
  digitalWrite(13, HIGH);   // turn the LED on
  delay(100);
  digitalWrite(13, LOW);    // turn the LED off
  delay(100);
  digitalWrite(13, HIGH);   // turn the LED on
  delay(100);
  digitalWrite(13, LOW);    // turn the LED off
  Serial.println("awake");

  AlarmTime += 5; // Adds 5 seconds to alarm time
  AlarmTime = AlarmTime % 60; // checks for roll over 60 seconds and corrects
  rtc.setAlarmSeconds(AlarmTime); // Wakes at next alarm time, i.e. every 5 secs

  rtc.enableAlarm(rtc.MATCH_SS); // Match seconds only
  rtc.attachInterrupt(alarmMatch); // Attach function to interupt
  Serial.end();
  USBDevice.detach(); // Safely detach the USB prior to sleeping
  rtc.standbyMode();    // Sleep until next alarm match
  USBDevice.attach();   // Re-attach the USB, audible sound on windows machines

}

void alarmMatch() // Do something when interrupt called
{}
1 Like

Do the debugging through one of the M0's available hardware UARTs. connected to the PC with a 3.3V UART to USB Converter. Because the converter is powered by the PC, the USB Serial port is never lost. This will work with CoolTerm, TeraTerm, PuTTy, etc.

1 Like

Thanks for the suggestion, which would certainly work for other projects. In the current project, Serial1 is taken by a Bluetooth UART with a central role.

It seems possible that two other pins could be coerced into performing as another serial UART, but many are already taken by the radio, display and buttons. I'll check into it!

1 Like

@gfvalvo Adafruit and Sparkfun have good tutorials, and I was able to squeeze in Serial2 on D10 and D11. So thanks for prodding! This will work fine for debugging the project.

Working demo for Serial2 echoing back and forth with native USB serial on the SAMD21G18 (M0):

#include <Arduino.h>   // required before wiring_private.h
#include "wiring_private.h" // pinPeripheral() function

Uart Serial2 (&sercom1, 11, 10, SERCOM_RX_PAD_0, UART_TX_PAD_2);
void SERCOM1_Handler()
{
  Serial2.IrqHandler();
}

void setup() {
  Serial.begin(115200);

  Serial2.begin(115200);
  
  // Assign pins 10 & 11 SERCOM functionality
  pinPeripheral(10, PIO_SERCOM);  //Serial2 TX
  pinPeripheral(11, PIO_SERCOM);  //Serial2 RX
}

// echo back and forth
void loop() {
  if (Serial.available()) Serial2.write(Serial.read());
  if (Serial2.available()) Serial.write(Serial2.read());
  
}

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