arduino-libraries / ArduinoLowPower

Powersave features for SAMD boards
GNU Lesser General Public License v2.1
81 stars 57 forks source link

Serial not working after wakeup #7

Open tatulea opened 5 years ago

tatulea commented 5 years ago

Hi,

I am using a button to put Arduino in sleep mode and wake it up, but the Serial is not working anymore after it is waking up. What should I do?

#include "ArduinoLowPower.h"

volatile bool just_wakeup = true;

// Pin used to trigger a wakeup
const int pin = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(pin, INPUT_PULLUP);
}

void loop() {
  if (just_wakeup) {
    just_wakeup = false;
    delay(3000);
    Serial.begin(115200);
  }
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  Serial.println("test");

  if (digitalRead(pin) == LOW) {
    Serial.end();
    delay(500);
    LowPower.attachInterruptWakeup(pin, wakeup_handler, FALLING );
    LowPower.deepSleep();
  }
}

void wakeup_handler() {
  just_wakeup = true;
  detachInterrupt(pin);
}
facchinm commented 5 years ago

Hi @tatulea, wakeup/standby with the USB connected is super tricky since it depends on the operating system/USB controller the board is connected to. Would you mind sharing your PC or Mac configuration (both software and hardware) so I can try reproducing it? Thanks

tatulea commented 5 years ago

Hi,

I am using Windows 10 and Arduino IDE. The PC is a HP EliteDesk 800 with intel I5-6500.

grezco commented 5 years ago

Hello,

I have the same problem with MKR WiFi1010 (and MKR1000) - Win10

sashkaw commented 5 years ago

Hello,

I also have the same problem with the Arduino WiFi MKR 1010 and MacBook Pro running OS X Yosemite.

facchinm commented 5 years ago

@tatulea @grezco @durasno can you take a look at https://github.com/arduino-libraries/ArduinoLowPower/pull/8 ? Let me know if the proposed behaviour could work for you.

grezco commented 5 years ago

Hi @facchinm,

For me, it's the same problem. At the wake up, the com port is present but even after closed serial monitors and reopened after a successful resume, I don't have serial print event.

facchinm commented 5 years ago

@grezco which operating system/PC are you using?

grezco commented 5 years ago

Windows 7 and Windows 10

sashkaw commented 5 years ago

@tatulea @grezco @durasno can you take a look at #8 ? Let me know if the proposed behaviour could work for you.

Hi @facchinm,

The below script (based on the TimedWakeup example) seems to be working relatively well (after brief testing with Arduino WiFi MKR 1010, MacBook Pro + OS X Yosemite) with the changes from #8. The added delay is from a LowPowerLab/LowPower SAMD21 example sketch.



void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  // Uncomment this function if you wish to attach function dummy when RTC wakes up the chip
  LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, dummy, CHANGE);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);

  while(!SerialUSB);
  delay(1000); 
  SerialUSB.println("Just woke up!");

  // Triggers a 2000 ms sleep (the device will be woken up only by the registered wakeup sources and by internal RTC)
  // The power consumption of the chip will drop consistently
  LowPower.sleep(2000);
}

void dummy() {
  // This function will be called once on device wakeup
  // You can do some little operations here (like changing variables which will be used in the loop)
  // Remember to avoid calling delay() and long running functions since this functions executes in interrupt context
}
grezco commented 5 years ago

Hi @durasno,

The same script testing with WiFi MKR 1010 and Windows10 with the changes from #8 Don't work for me.

sashkaw commented 5 years ago

Hi @grezco,

If it helps I wait for the led to flash and then repeatedly try to open the serial monitor until text displays. Past that I unfortunately don't have much advice to offer.

grezco commented 5 years ago

Hi @facchinm With the script above, with arduino/ArduinoCore-samd#361 if I send a char by serial monitor, I freeze IDE (Wndows 10).

polygamma commented 5 years ago

You may want to take a look at this: https://github.com/arduino-libraries/ArduinoLowPower/pull/9

grezco commented 5 years ago

Hi @polygamma, Nothing better with #9 for me. After wake up, in all case, I need to unplug / reconnected USB of MKR WiFi1010 device to be abble to see the serial message.

polygamma commented 5 years ago

@grezco with the following example, you never see the second message?

#include "ArduinoLowPower.h" // https://www.arduino.cc/en/Reference/ArduinoLowPower
#include "RTCZero.h" // https://www.arduino.cc/en/Reference/RTC

/*
 * initial setup, will be run once at the start of the whole routine
 */
void setup() {
  // init serial connection
  Serial.begin(9600);
  while (!Serial) {}
  RTCZero().begin(false);
}

/*
 * will be run forever, after initial setup() call
 */
void loop() {
  Serial.println("I am being printed, because the device has not been sleeping, yet");

  // deep sleep of 5 seconds
  LowPower.sleep(1000 * 5);

  Serial.println("I am never being printed, because of a deadlock");
}

Notice the RTCZero().begin(false); call, if you want to avoid that one, install the latest RTCZero version from the master branch, found here including this commit.

Running that snippet, having my commits included, yields the wanted output of:

I am being printed, because the device has not been sleeping, yet I am never being printed, because of a deadlock I am being printed, because the device has not been sleeping, yet I am never being printed, because of a deadlock ...

at least for me...

grezco commented 5 years ago

@polygamma, No I never see the second message.

polygamma commented 5 years ago

Since you wrote in https://github.com/arduino-libraries/ArduinoLowPower/issues/7#issuecomment-425667428 that you are using Windows 10, I tried the snippet with my fixes on Win10, too. Sorry, have to confirm, that my changes do not help, if you are using Win 10. Anyway: When using Arch Linux, and probably any Linux distribution, it does indeed fix the problems.

grezco commented 5 years ago

@polygamma, thanks for the time spent trying to solve my problem.

Until I find a solution, I use

  USBDevice.detach();
  LowPower.sleep(1000 * 5);
  USBDevice.attach();

and reopen the serial monitor when the port appear.

facchinm commented 5 years ago

@grezco @polygamma @durasno thank you all for testing on different platforms; being able to reproduce the behaviour is crucial to get a solution. @grezco are you testing with https://github.com/arduino-libraries/ArduinoLowPower/pull/8 applied? Because it implements (almost) the same solution you are using; I'd hate to insert OS-specific code based on the machine you are working with (these kind of solution never work in the real world)

grezco commented 5 years ago

Hi @facchinm As previously said, #8 don't work (for me) with Windows10 and MKR1000. With Arduino SAMD core - Pull Request #361, the serial port don't disappear in the device manager of Windows 10. But after wake up, in all case, I'm not abble to see the serial message (unless I unplugged / reconnects USB).

facchinm commented 5 years ago

@grezco so what did you mean with

Until I find a solution, I use ...

if you are unable to see the serial message? Does adding the extra lines change the behaviour over #8 or not?

grezco commented 5 years ago

@facchinm, #8 don't change the behaviour when I use (or not) USBDevice.detach(); With, or without #8, I need to unplug / reconnected USB of MKR WiFi1010 device or use USBDevice.detach to be able to see the serial message after the wake up.

#include ArduinoLowPower.h" // https://www.arduino.cc/en/Reference/ArduinoLowPower
#include "RTCZero.h" // https://www.arduino.cc/en/Reference/RTC

void setup() {
  // init serial connection
  Serial.begin(9600);
  while (!Serial) {}
  RTCZero().begin(false);
}

void loop() { 
  Serial.println("I am being printed, because the device has not been sleeping, yet");
  delay(10);
  USBDevice.detach();
  LowPower.sleep(1000 * 5); 
  USBDevice.attach();
  delay(5000);
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
  Serial.println("Wake up MCU");
}
fabik111 commented 5 years ago

Hi guys, I had the same problem with MKR1000 and I've solved using the library version on GitHub (the version on Library Manager not works) and adding these lines of code on your project: USBDevice.detach(); LowPower.deepSleep(); USBDevice.attach();

pchatill commented 5 years ago

Hi. Same problem for me: Serial not working after wakeup . "USBDevice.detach(); LowPower.sleep(); USBDevice.attach();" helped me a lot, But I need to close the sérial monitor and re-open (IDE 1.8.8 , windows 10). And I miss some informations on serial port if I don't do that quickly enough Is there a way do to that automatically? And is that planned to modify the library? Thanks a lot for answers. Patrick

facchinm commented 5 years ago

Hi @pchatill , it was proposed for inclusion in the IDE (https://github.com/arduino/Arduino/pull/8046). That PR is already included in Beta builds of the IDE but has some problems with non arduino boards (esp8266 and similar) so we decided to postopone the merge in master. Testing it would greatly speedup merge ;)

pchatill commented 5 years ago

Thanks for your response facchinm. I tried with IDE beta 1.8.9. It seems not necessary with this version to add :USBDevice.detach(); USBDevice.attach(); But it's always necessary to close serial monitor and reopen it. The difference is that the serial monitor output is cleared when Arduino sleep. The other difference is that the serial monitor looks active again when arduino wake-up (Autoscroll function active for example) but no data displayed ...

facchinm commented 5 years ago

The beta should be numbered 1.9.0 , please double check if you are using that one :wink: Beside that, are you on Windows?

pchatill commented 5 years ago

Sorry for the mistake: Yes I tried with Arduino 1.9.0-beta. Yes windows 10

pchatill commented 5 years ago

Hi facchim. Do you have any news about the problem? Thanks a lot...

netless-ww commented 4 years ago

I have found the following code using the Arduino low power library is a partial solution - at least it gives you a delay to close & reopen the USB serial port, after the SAMD wakes up.

I'm using a 16x2 LCD to see what is happening while the serial port is unavailable - remove if you wish. Also the code is a bit messy with commented out sections where I have been trying other low power libraries.

The method uses theUSBDevice.detach() -- LowPower.deepSleep() -- USBDevice.attach() combination, together with a delay while(!Serial) {} to give you time to close & reopen the Serial port.

Note: delay(1000); after restarting the USBDevice is very important. The value of Serial is initially returned as 1, and will drop straight through the while delay - after the one second delay however, the value of Serial changes back to 0 and is captured in the while loop until a new Serial window is opened and the value of Serial changes back to 1.

Still not an ideal solution, but at least you get a working Serial window back without losing any output.

Incidentally, the LowPower.deepSleep(); library command also does a USBDevice.detach() -- USBDevice.attach() internally - without the external USBDevice.detach() -- USBDevice.attach() sequence, this will keep your existing Serial communication open (no need to restart) and can receive commands, but will not display any output to the serial monitor. Perhaps this is because there is no 1 second delay & the serial port not being closed and reopened.

There are lots of funny timing issues going on here - I would appreciate it if anyone can shed more light on this.

// **** INCLUDES *****
#include "ArduinoLowPower.h"
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>

LiquidCrystal_PCF8574 lcd(0x27);  // set the LCD address to 0x27 for a 16 chars and 2 line display

// External interrupt on pin 0 (use pin 0 to 24, except pin 4 on Arduino Zero)
const int pin = 12;
unsigned char count = 3;

void setup()
{
    // Wait for serial USB port to open
    Serial.begin(9600);
       delay(2000);
    Serial.println("***** ATSAMD21 Standby Mode Example *****");

  lcd.begin(16, 2);               // initialize the lcd
  lcd.setBacklight(HIGH);
  printMessages(1, 0, 0);    //print  Found LCD
  delay(2000);                   //small delay before the screen is cleared
  lcd.home(); lcd.clear();

    // ***** IMPORTANT *****
    // Delay is required to allow the USB interface to be active during
    // sketch upload process
    Serial.println("Entering standby mode in:");
    for (count; count > 0; count--)
    {
      Serial.print(count);  
      Serial.println(" s");
      delay(1000);
  }
  // ********************
  // External interrupt on pin (example: press of an active low button)
  // A pullup resistor is used to hold the signal high when no button press
  pinMode(pin, INPUT_PULLUP);
  LowPower.attachInterruptWakeup(pin, blink, LOW);
}

void loop() 
{
    Serial.println("Entering standby mode.");
    Serial.println("Apply low signal to wake the processor.");
    Serial.println("Zzzz...");
  Serial.print("SCB_SCR_SLEEPDEEP_Msk  ");
  Serial.println(SCB_SCR_SLEEPDEEP_Msk, BIN);
  Serial.print("~SCB_SCR_SLEEPDEEP_Msk  ");
  Serial.println(~SCB_SCR_SLEEPDEEP_Msk, BIN);
  //Serial.println(GCLK->CLKCTRL.reg, BIN);
  printMessages(0, 0, 0);
  printMessages(0, 0, 1);

    // Detach USB interface
       USBDevice.detach();

  // Enter standby mode
  // LowPower.standby();
  /* This is all LowPower.standby() does
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  __DSB();
  __WFI();
  */
  LowPower.deepSleep(5000); 
  //LowPower.idle(IDLE_2);

  lcd.setCursor(0, 0); lcd.print(F("Awake"));

  // Attach USB interface
     USBDevice.attach();
  // It appears the Serial is returned as 1 after the attach command
  // However it also appears to revert to 0 after 1 sec of inactivity
  // Thus being trapped in the following while statement until the new 
  // serial monitor is opened. If the following delay is omitted the
  // following while loop will pass straight through, without waiting for
  // the new serial monitor to open!!   

     delay(1000); 

  // Force delay until the old serial monitor is closed and a new one
  // is opened, changing Serial from 0 back to 1
  int s = Serial;
  lcd.setCursor(8, 0); lcd.print(s);

  while(!Serial) {lcd.setCursor(10, 0); lcd.print(s);s++;}  //Close OLD & open NEW Serial connection 
                                                                                     //during this delay

  lcd.setCursor(8, 1); lcd.print(Serial);
  lcd.setCursor(0, 1); lcd.print(F("Serial"));

  Serial.println("Awake!");
  Serial.println("Serial Communication Restored!");
  Serial.println("Send any character to enter standby mode again");

  // Wait for user response
  // Serial.available is 0 while there are no characters in the USB pipline,
  // causing the while to loop indefinitely.
  // As soon as a character is typed, Serial.available changes to 1 and 
  // characters are read from the USB pipline until it is empty and
  // Serial.available returns to 0 and the second while loop terminates.
  while(!Serial.available());
  while(Serial.available() > 0)
  {
        Serial.read();
    }

}

void blink(void)
{

}
/***************************************************************************/
//Print messages to the LCD

  void printMessages(uint8_t messNo, uint8_t messCol, uint8_t messRow ) {
  lcd.setCursor(messCol, messRow);                 //set up cursor possition

  if (messNo == 0)  lcd.print(F("                "));
  if (messNo == 1)  lcd.print(F("Found LCD       "));
}
AndreasWaldherr commented 3 years ago

Hi netless-ww, thanks a lot for sharing your test results. Your workaround does the job also for my Arduino MKR WAN 1310 LoRa Module :-)

Andreas

adamgarbo commented 3 years ago

When using the rtc.standby() function from the RTCZero library and manually detaching/attaching the USBDevice, I am able to reliably reestablish communication with the serial port of a SAMD21-based microcontroller after sleep (Adafruit Feather M0). I am curious why this is not possible with the ArduinoLowPower's LowPower.deepSleep(), given the functionality is essentially the same.

As a side note, the measured quiescent current draw of the rtc.standby() function is equivalent to LowPower.deepSleep().

// Close serial port
Serial.end();   

// Safely detach USB prior to sleeping
USBDevice.detach();   

// Sleep until next alarm match
rtc.standbyMode(); 

// Re-attach USB
USBDevice.attach(); 

// Open serial port 
Serial.begin(115200);