Thursday, February 27, 2014

Arduino Micro (Leonardo): Detecting if you are still plugged into USB

   I'm a fan of the Arduino Micro's direct USB interface. It's so simple you just plug in your baud rate and you're ready to send and receive serial data from your computer using Serial commands.

/***************************************************\
|Name: Example of detecting USB Serial              |
|Programmer: Michael James Salino-Hugg              |
|Date: February 27,2014                             |
|Description: Turns on pin 13 LED when USB Serial   |
|             is connected and prints out "Serial   |
|             is connected" every second.           | 
|             Turns pin 13 LED off when there is no |
|             USB Serial connection.                |
\***************************************************/
void setup(){
   pinMode(13,OUTPUT);
   USBCON|=(1<<OTGPADE); //enables VBUS pad
   Serial.begin(9600);
}

void loop(){
   if(Serial){  //checks state of VBUS
      digitalWrite(13,HIGH);
      Serial.println("Serial is connected");
   }
   else {
      digitalWrite(13,LOW);
   }
   delay(1000);
}

   However, I have run into one problem with this USB connection. It is as follows. You have your Arduino setup to run one algorithm when it is connected to a computer through USB serial connection and another algorithm when it is not connected to the serial connection. You currently have it connected to the USB and what to disconnect and return to the other algorithm. There are 3 possible scenarios for disconnecting the Arduino from the computer.

  1. The user uses the Serial.end() command the Arduino to terminate the connection. It recognizes that connection is no longer set up using an returns to the correct algorithm.
  2. The user uses their terminal emulator (or terminal) to disconnect the connection. The Arduino recognizes that the connection has been terminated and returns to the correct algorithm.
  3. The user just pulls out the USB cable from either the computer or the Arduino. The Arduino never gets the notice that the connection is being terminated and just keeps running the algorithm it runs when it is connected to the computer despite the fact that it's not.
I would have to say that scenario 3 (the only one with the problem) is the most likely for an average user. I even end up doing this one all the time, and I know very well that I shouldn't. How can you prevent this? You can test this third scenario with the code above. When you unplug the Arduino Micro's USB cable after having a USB Serial connection the pin 13 light will stay on.

   One possible solution is very simple but only if you know your way around the ATMega32U4 (the microprocessor on Arduino Micro) datasheet and Arduino Micro circuit schematic. 

   Looking at the schematic for the Micro, we see that the 5V line from the USB (VUSB) connects directly to the microprocessor at a pin labeled VBUS. Time to pull up the datasheet!

On page 262-263, section 21.11 we see that VBUS can be used to detect if that line is above 1.4 volts This is exactly what we need. We can detect whether we're plugged into a USB port since this pin will be provided 5Vs if it is connected.

To use this we must first enable the VBUS Pad. From section 21.12 of the datasheet we see that OTGPADE (bit 4) of register USBCON. Then we can check VBUS (bit 0) in register USBSTA to see if this line is high or low.

The following code turns on the LED on the top of the Arduino when connected to a USB port, and off when only powered through its VIN or 5V pins:
/***************************************************\
|Name: Detecting VBUS                               |
|Programmer: Michael James Salino-Hugg              |
|Date: February 27,2014                             |
|Description: Turns on pin 13 LED, establishes a    |
|             serial connection, and prints "Serial |
|             is connected" every second when VBUS  |
|             is high. It also ends the serial      |
|             connection and turns off the pin 13   |
|             LED when VBUS is low.                 |
\***************************************************/

void setup(){
   pinMode(13,OUTPUT);
   USBCON|=(1<<OTGPADE); //enables VBUS pad
}

void loop(){
   if(USBSTA&(1<<VBUS)){  //checks state of VBUS
      if(!Serial)
         Serial.begin(9600);
      digitalWrite(13,HIGH);
      Serial.println("Serial is connected");
   }
   else {
      if(Serial)
         Serial.end();
      digitalWrite(13,LOW);
   }
   delay(1000);
}

Test this code out the same way. It will always recognize that it's no longer connected to the USB port and end its USB Serial communication.

3 comments:

  1. I finally found a solution for my Arduino Micro project ! Thank you very much, your code is very helpful for me !

    Alex

    ReplyDelete
  2. Having mostly worked with atmega328 and atmega644 Arduino clones I recently got a couple atmega32u4's. I wanted to be able to print a startup message to the usb serial but needed a way to tell when the usb serial was actually connected since the serial device goes away and /usr/bin/tip exits...

    I found your page and using the usb status register is slick. However it didn't help for a number of reasons. First, I'm using a clone of the Sparkfun clone of the Arduino Pro Micro. And for whatever reason it has the VBUS pin wired to the UVCC pin. This seems to cause the VBUS bit to be set anytime the chip is powered up.

    Looking further at the board schematic I realized I could plug a 10K resistor between the RAW pin and an digital input pin since it would only be powered if the usb connector was powered. That worked but the USB can easily be powered up with no usb connection to a host computer so it still didn't solve my problem.

    Finally I looked at hardware/arduino/cores/arduino/CDC.cpp and noticed that you can use test Serial directly and it returns true/false depending on the internal line state. This works perfectly.

    void
    loop()
    {
    static boolean init = 0;

    /* Defer startup message until the USB serial is connected */
    if (!init && Serial) {
    hello();
    init = 1;
    }
    [...]

    I'm also using it to suppress debugging messages when the usb serial is not connected.

    ReplyDelete