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
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.
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)
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:
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.
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.
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?
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 ?
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
...
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)