3

I have an arduino micro and several clone "pro micro"'s both of which are based on the 32u4, i'm trying to make my project have a debug mode which is only active when the serial port is open, the documentation states that using:

if (Serial)

on these boards should only return true if the port is open (on uart based connections it always returns true), i wrote my sketch to take advantage of that but it didn't seem to be working properly, so i stripped back to basics and wrote this sketch:

void setup() {
    // put your setup code here, to run once:
    pinMode(2, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
    if (Serial){
        digitalWrite(2, HIGH);
    }
    else{
        digitalWrite(2, LOW);
    }
}

I connected an LED to pin 2 and then tested it by connecting and disconnecting the arduino from the PC, and opening and closing the com port.

after freshly connecting the arduino to the PC the LED is off, when i open a connection to the virtual com port the LED turns on. however i would expect the LED to go out once the port is closed, but it remains on.

My questions are:
1) have i got an out of date bootloader?
2) if so how do i check?
3) is this intended behavior and if so why?
4) is this a bug in the arduino bootloader or libraries?
5) short of having to change my code to look for serial data to start and stop the debug mode (serial comms are being used for other things in the background) is there any way i can work around this? reading from hidden registers etc?

Edit:
should have mentioned i'm seeing this behavior with or without a call to Serial.begin

James Kent
  • 274
  • 2
  • 9

2 Answers2

9

1) have i got an out of date bootloader?

No. This has nothing to do with the bootloader.

2) if so how do i check?

See above.

3) is this intended behavior and if so why?

In a manner of speaking, yes - see below.

4) is this a bug in the arduino bootloader or libraries?

No. Elsewhere. See below.

5) short of having to change my code to look for serial data to start and stop the debug mode (serial comms are being used for other things in the background) is there any way i can work around this? reading from hidden registers etc?

Yes, you can, but only once you understand exactly what is going on.

The problem with USB serial (AKA CDC/ACM) communication is that there is no way of knowing if the port has been opened by the computer or not. That functionality was just never designed into the protocol.

However, there are two virtual modem signals that the computer can assert that the CDC/ACM device at the other end can examine - one is the equivalent of DTR and the other the equivalent of RTS.

The Arduino's CDC/ACM code examines those, and if either are asserted then it assumes the CDC/ACM port is open. If neither are asserted then it assumes the port is closed.

Now comes the tricky part: You have little or no control over when those signals are asserted or not. There are three separate factors that decide what happens:

  1. The software being run can manually control the signals. The Arduino IDE does this to ensure boards that use DTR to reset (like the Uno, etc) actually do reset.
  2. The drivers on the computer can decide to automatically control the signals when the port is opened or closed
  3. The operating system itself can control the signals when the port is opened or closed.

Some software will control the RTS/DTR signals properly, some won't. Some drivers will control the signals for you, some won't. Some operating systems (such as Linux) will, unless otherwise instructed, default to automatically controlling the modem lines properly. Others, like Windows, won't.

So the only way you can be sure that these signals are being controlled properly is to manually control them from your own software used for debugging, or to find a specific terminal emulator that controls the lines properly.

Majenko
  • 105,851
  • 5
  • 82
  • 139
2

I am experiencing the same problem. My environment is Windows 10 on the host side and Arduino 1.6.7 with a genuine Arduino Micro board.

In the OP's sketch, after compiling and uploading, the light does not go on until you open the serial monitor. This is as expected and shows that the Arduino side has some way of knowing that the serial monitor has started.

However if you close the serial monitor, the light stays on. It also stays on if you unplug the USB cable. It goes off when you plug the cable back in and goes back on when you restart the serial monitor.

With some further experimentation and poking around the code, I found that _usbLineInfo.lineState > 0 and thus Serial returns True if either DTR or RTS from the host is nonzero. DTR goes to 0 when the serial monitor is closed but RTS stays HIGH so Serial stays True.

The fix is to use the (undocumented) method Serial.dtr(). This is True only if the serial monitor is running.

[edit] If your system has external power so that it should keep working with the USB cable unplugged, testing Serial.dtr() works as long as you you always close the serial monitor before unplugging the USB cable. However it will remain True if the cable is unplugged before closing the serial monitor.

To detect the cable being unplugged, add the line

USBCON |= 1<<OTGPADE;

to setup(). This enables detection of an unplugged USB cable. Then in your loop

(USBSTA & (1<<VBUS))

will be True if the USB cable is plugged in and has power.

Jim Harman
  • 111
  • 4