[resolved] Serial hangs after wake-up (Micro)

Serial hangs in my Arduino Micro sketch after going into power-down mode. The device wakes up on INT6, but with the USB seemingly stuck: getting java errors and the COM port remains busy indefinitely (until hard reset). Not sure what's going on.

code:

#include <avr/sleep.h>

const int led = 13;
const int intPin =7;

void setup()
{
  pinMode(led,OUTPUT);
  pinMode(intPin,INPUT);
  // set pin 7 pullup resistors
  digitalWrite(intPin,HIGH);
  // set up sleep mode
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  // start the serial interface
  Serial.begin(9600);
}

void loop()
{
  if (Serial.available())
  {
    char ch=Serial.read();
    if (ch=='z')
    {
      Serial.println("going to sleep");
      Serial.flush();
      delay(100);
      sleep_now();
    }
  }
  // blink some led
  digitalWrite(led,HIGH);
  delay(250);
  digitalWrite(led,LOW);
  delay(250);
}

void sleep_now()
{
  sleep_enable();
  // INT6 in ATmega32u4 is INT.4 in micro 
  attachInterrupt(4,wakeUp_isr,LOW);
  sleep_mode();
  //we come back here after wakeup
  sleep_disable();
  delay(1000);
  Serial.print("awake");
  // trouble... at this point TX LED goes high and stays high
  // rest of blink code in main() keeps running fine but serial throws errors
}

void wakeUp_isr()
{
  detachInterrupt(4);
}

when attempting to send serial after wakeup (with the IDE terminal) I get many error messages starting with:

java.io.IOException: Input/output error in writeArray

Thanks!

Try doing Serial.end () before doing to sleep and Serial.begin () after waking up.

For the java errors it's the last 10 or 20 lines that helps post not the first few in the listing (its a stack dump). It may help to post them!.

Mark

The error messages seem to stem from the fact that the COM port that the IDE is looking at disappears - try any Arduino board, if you have the Serial Monitor window open then unplug the board, the same error messages appear (based on what you have said).

I wonder if you have to reset the USB port of the Micro after you wake back up?

//Before sleep, detach the USB port
USBDevice.detach();
...
//After sleep, reattach USB port.
USBDevice.attach();
while(!Serial); //wait for serial to become available.

Not got a Micro or Leonardo, so cant try it.

Nick- this doesn't change the behavior.
BTW this code works perfectly fine on Uno.
posting below the errors (in full). I tried talking to the serial port in MATLAB but get generic fail error after wakeup.
Tom- I tried your suggestion by itself and also in combination with Nick's. No luck:

void sleep_now()
{  
  Serial.end();
  USBDevice.detach();
  sleep_enable();
  // INT6 in ATmega32u4 is INT.4 in micro 
  attachInterrupt(4,wakeUp_isr,LOW);
  sleep_mode();
  //we come back here after wakeup
  sleep_disable();
  delay(1000);
  USBDevice.attach();
  delay(100);
  Serial.begin(9600);
  Serial.print("awake");
}

java.io.IOException: Input/output error in writeArray
at gnu.io.RXTXPort.writeArray(Native Method)
at gnu.io.RXTXPort$SerialOutputStream.write(RXTXPort.java:1124)
at processing.app.Serial.write(Serial.java:517)
at processing.app.Serial.write(Serial.java:540)
at processing.app.SerialMonitor.send(SerialMonitor.java:200)
at processing.app.SerialMonitor.access$100(SerialMonitor.java:32)
at processing.app.SerialMonitor$3.actionPerformed(SerialMonitor.java:89)
at javax.swing.JTextField.fireActionPerformed(JTextField.java:492)
at javax.swing.JTextField.postActionEvent(JTextField.java:705)
at javax.swing.JTextField$NotifyAction.actionPerformed(JTextField.java:820)
at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1636)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2851)
at javax.swing.JComponent.processKeyBindings(JComponent.java:2886)
at javax.swing.JComponent.processKeyEvent(JComponent.java:2814)
at java.awt.Component.processEvent(Component.java:6040)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1848)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:704)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:969)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:841)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:668)
at java.awt.Component.dispatchEventImpl(Component.java:4502)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Window.dispatchEventImpl(Window.java:2475)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

On the boards based on the ATmega32u4 chip you need to wait after doing a Serial.begin.

  Serial.begin(9600); 
  while (!Serial) { }  // wait for Serial to initialize

Nick- Thank you, but this doesn't help: execution goes back to main loop, but nothing is happening on the serial port, and I get same errors as before when trying to write to it. It appears that the cpu does what it needs to do to get the data into the TX buffer, and then continues on. However the USB controller remains stuck and does nothing further.
Does anyone have experience with putting Micro (or Leonardo) into power-down mode and recovering successfully?

As well as shutting down and restarting the serial port on the Arduino, would it be possible to close the corresponding virtual serial port on the host after the Arduino shuts down the serial port, and re-open it after the Arduino has restarted it?

ofernaaman:
Nick- Thank you, but this doesn't help: execution goes back to main loop, but nothing is happening on the serial port, and I get same errors as before when trying to write to it.

Hmm, after a bit of searching I found what Serial.begin and Serial.end do on the Micro:

void Serial_::begin(uint16_t baud_count)
{
}

void Serial_::end(void)
{
}

Not much.

USBDevice.detach(); is empty also. Perhaps this could be the problem, an incomplete CDC library.

Ha ! very interesting. Thank you all for your time. Could you recommend and alternative USB communication library (maybe a driver as well?) that will work for the Micro?

I don't know but all I can suggest is searching for "ATmega32u4 usb library". Quite a few hits there. For example:

Maybe LUFA:

Of course these libraries may or may not address the concept of powering down the processor. I would have thought that for that to work the host would have to be notified (similarly to when you unplug a USB) and maybe there is just one bit that needs to be tweaked in a processor register to make it work. However I don't know which bit that is.

Maybe here:

This looks promising:

USBCON |= (1 << FRZCLK);             // Freeze the USB Clock             
PLLCSR &= ~(1 << PLLE);              // Disable the USB Clock (PPL)
USBCON &=  ~(1 << USBE  );           // Disable the USB

PROGRESS !!
sequence sensitive. I am using MATLAB to test this but I suppose one can do it also from the IDE terminal.

void sleep_now()
{  
  // disable the USB
  USBCON |= _BV(FRZCLK);  //freeze USB clock
  PLLCSR &= ~_BV(PLLE);   // turn off USB PLL
  USBCON &= ~_BV(USBE);   // disable USB
  // this all takes the USB off the host. windows make USB sounds
  // like the USB is physically disconnected.
  // now must close serial port in the host or it gets stuck
  sleep_enable();
  // INT6 in ATmega32u4 is INT.4 in micro 
  attachInterrupt(4,wakeUp_isr,LOW);
  sleep_mode();
  //we come back here after wakeup
  sleep_disable();
  delay(100);
  sei();
  USBDevice.attach(); // keep this 
  // windows make sounds like USB is physically connected
  delay(100);
  // this never reaches the host
  // Serial.print("awake");
  // now re-open the serial port, hope that it is assigned same 'COMxx'
}

This has the same effect of physically removing the USB jack.
Test code in MATLAB:

s=serial('COM9'); % create serial object. Arduino on COM9
fopen(s);         % open serial port
fprintf(s,'d');   % test the serial
fscanf(s)         % Arduino replies "I'm here"
%%
fprintf(s,'z');   % send "go to sleep" command
fscanf(s)         % arduino replies "going to sleep"
fclose(s)         % close serial port
% now wake up the Micro with pin interrupt...
%%
fopen(s);         % open serial port
fprintf(s,'d');   % test port  
fscanf(s)         % Arduino replies "I'm here"

As was suggested by peterH, the serial terminal must be closed after we go to sleep, and opened again only after the USB is back on line. I am going to play with this a bit and see if it is possible to make this work without detaching/re-attaching the USB device.

1 Like

In which case, you could add those extra lines to USBDevice.detach() function to keep things neat.
At the bottom of the file \hardware\arduino\cores\arduino\USBCore.cpp, replace:

void USBDevice_::detach()
{  
}

with this:

void USBDevice_::detach()
{  
  // disable the USB
  USBCON |= _BV(FRZCLK);  //freeze USB clock
  PLLCSR &= ~_BV(PLLE);   // turn off USB PLL
  USBCON &= ~_BV(USBE);   // disable USB
}

That way you can do USBDevice.detach() and it will do what it is supposed to.

1 Like

Thank you all. Detach -> sleep -> wakeup -> attach works, if I populate USBDevice.detach() with the appropriate code.

I try to compile and get this errors

sketch_nov23a:2: error: expected unqualified-id before 'volatile'
sketch_nov23a:2: error: expected `)' before 'volatile'
sketch_nov23a:2: error: expected `)' before 'volatile'
sketch_nov23a:3: error: expected unqualified-id before 'volatile'
sketch_nov23a:3: error: expected `)' before 'volatile'
sketch_nov23a:3: error: expected `)' before 'volatile'
sketch_nov23a:4: error: expected unqualified-id before 'volatile'
sketch_nov23a:4: error: expected `)' before 'volatile'
sketch_nov23a:4: error: expected `)' before 'volatile'
sketch_nov23a:8: error: expected constructor, destructor, or type conversion before ';' token
sketch_nov23a:10: error: expected constructor, destructor, or type conversion before '(' token
sketch_nov23a:11: error: expected constructor, destructor, or type conversion before ';' token
sketch_nov23a:13: error: expected constructor, destructor, or type conversion before ';' token
sketch_nov23a:14: error: expected constructor, destructor, or type conversion before '(' token
sketch_nov23a:15: error: expected `)' before '::' token
sketch_nov23a:16: error: expected constructor, destructor, or type conversion before '.' token
sketch_nov23a:18: error: expected constructor, destructor, or type conversion before '(' token
sketch_nov23a:22: error: expected declaration before '}' token

another way to reset the promicro on windwos start up?

I tried as you &Nick said

  Serial.end();
  Serial1.end();
  USBDevice.detach();
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  cli();  // Do not interrupt before we go to sleep
  attachInterrupt(0, wakeUP, CHANGE);
  EIFR = 1;  // clear existing flag for interrupt 0
  sei();  // Enable interrupt
  sleep_cpu(); //sleep here and wake up here if triggered
  delay(1000);
  Serial.println("wakeup");
  USBDevice.attach();
  Serial.println("wakeup2");
  Serial.begin(115200); //This pipes to the serial monitor
  while (!Serial);
  Serial.println("wakeup3");
  Serial1.begin(115200); //This is the UART, pipes to sensors attached to board
  while (!Serial1);
  Serial.println("wakeup4");

but this is not stable. in some cases, sounds not exact the same as should - like double. Some times sound for detach oR for attach is only one "ding" and in this case board is not recognized by Arduino IDE and I wasnot able open Arduino Serial Monitor. May be if you will use 3rd party monitor it will be more stable ? like putty, terminal1.9b ?

and what is more important why this block in USBCore.cpp still empty :slight_smile: ?

but I would ask more important question for me

HOW we should be ENSURE that EXTERNAL device connected to MICRO is ONLINE ?
in case when device can in the middle of the code be in state online|offline

Because now, even before go to sleep , if I (somewhere in the middle code) will try detirmine if external device is online by

void setup() {
  Serial.begin(115200); //This pipes to the serial monitor
  while (!Serial);
  Serial1.begin(115200); //This is the UART, pipes to sensors attached to board
  while (!Serial1);
}
...
if (!Serial1) []  //If it offline switch power on
...

It always return TRUE.
Please help me!

alexblade:
HOW we should be ENSURE that EXTERNAL device connected to MICRO is ONLINE ?

No way! we cannot be ensure that device still connected to arduino.
Only make call-answer (if device support call-answer)
And analyze answer (if it sent)

while / if(!Serial1) is useless. That construction is only useful for serial on the native usb port (Serial on e.g. the Leonardo).