Connecting Arduino to Android via USB cable

Contents


  1. Introduction
  2. Toolkit
  3. The Arduino firmware
  4. The Android application
  5. Source Links
  6. About Android and USB Host
  7. Reference

Introduction


In this you can learn how to communicate between your Android application and the Arduino using nothing but the Android USB host API. In this example Android device will act as the USB host, while your Arduino board will act as the USB device. This example consists of two parts:

  • The Android application that makes use of the USB API. A simple Android app that let’s you regulate the brightness of an LED on the Arduino using a slider. It also features a button to “enumerate” the USB device.
  • Firmware for the Arduino that does some serial I/O with the Android app. Very basic firmware for the Arduino. An interrupt is generated when a new byte is received. The received data controls the brightness of the Arduino’s on-board LED.

Toolkit


  • 1x Android device that supports USB host mode
  • 1x Arduino board
  • 1x USB cable

arduino board
Figure 1 - Arduino board

The Arduino firmware


In the main loop the firmware asserts and clears the LED pin of the Arduino (PB5). Here is a shortened excerpt:

   {	
  int main(void)
   //initialization
   initIO();
   uart_init();
   sei();

   uint8_t i = 0;
   volatile uint8_t pause;

   for(;;){//this is the main loop
       pause = data;
       PORTB |= (1 << LED);
       for(i = 0; i < pause; i++)
           _delay_us(10);
       PORTB &= ~(1 << LED);
       for(i = 0; i < 255-pause; i++)
           _delay_us(10);
   }

During a period of 2550[us], the LED is asserted for a duration of pause*10 [us] and cleared for (255-pause)*10[us]. Simply put, this is a very simple software PWM. During that time, “data” and consequently “pause” may be changed within an interrupt routine form the serial USART port. This happens when the Android side sends data to the Arduino. The interrupt routine is extremely basic:

ISR(USART_RX_vect) {//attention to the name and argument here, won't work otherwise
  data = UDR0;//UDR0 needs to be read
  }

The RX data has to be read in the ISR (interrupt service routine) from UDR0; have a look at the Atmega328P reference manual for further details. Since we are doing no multi-buffering shenanigans the handling is extremely simple (no need to call cli() or anything). The rest of the code is initialization of the I/O pins and UART functionality.

Download the complete example here: Led example code.zip

The Android application


The Android application uses the basic knowledge of the preceding blog post Arduino USB transfers. During USB initialization, the Arduino USB serial converter is set up and after that, communication is done using the bulk IN endpoint of the very same serial converter. With both the aforementioned firmware installed your Arduino board and the Android application installed on your phone or tablet, you will be able to control the brightness of the Arduino Uno’s built-in LED with a slider on your Android device.

The source code is available here:UsbController.zip

android application
Figure 2 - Android application

(You may need to change the PID value in UsbControllerActivity.java on line 38, if you have an Arduino Uno Rev3 or higher. You can check the VID/PID value with ‘lsusb’ after connecting the Arduino to your computer.)
Many parts of the code are probably familiar to Android SW engineers. The most interesting section is in the class UsbController where the Arduino device is set up and communication is initiated.

So let’s have a closer look at the inner class UsbRunnable within UsbController:

private class UsbRunnable implements Runnable {
   private final UsbDevice mDevice;

   UsbRunnable(UsbDevice dev) {
       mDevice = dev;
   }

   @Override
   public void run() {//here the main USB functionality is implemented
       UsbDeviceConnection conn = mUsbManager.openDevice(mDevice);
       if (!conn.claimInterface(mDevice.getInterface(1), true)) {
           return;
       }
       // Arduino USB serial converter setup
       conn.controlTransfer(0x21, 34, 0, 0, null, 0, 0);
       conn.controlTransfer(0x21, 32, 0, 0, new byte[] { (byte) 0x80,
               0x25, 0x00, 0x00, 0x00, 0x00, 0x08 }, 7, 0);

       UsbEndpoint epIN = null;
       UsbEndpoint epOUT = null;

       UsbInterface usbIf = mDevice.getInterface(1);
       for (int i = 0; i < usbIf.getEndpointCount(); i++) {
           if (usbIf.getEndpoint(i).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
               if (usbIf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
                   epIN = usbIf.getEndpoint(i);
               else
                   epOUT = usbIf.getEndpoint(i);
           }
       }

       for (;;) {// this is the main loop for transferring
           synchronized (sSendLock) {//ok there should be a OUT queue, no guarantee that the byte is sent actually
               try {
                   sSendLock.wait();
               } catch (InterruptedException e) {
                   if (mStop) {
                       mConnectionHandler.onUsbStopped();
                       return;
                   }
                   e.printStackTrace();
               }
           }
           conn.bulkTransfer(epOUT, new byte[] { mData }, 1, 0);

           if (mStop) {
               mConnectionHandler.onUsbStopped();
               return;
           }
       }
   }
  }

After the USB interface has been claimed the Arduino USB serial converter is initialized by issuing the following control transfers:

conn.controlTransfer(0x21, 34, 0, 0, null, 0, 0);
conn.controlTransfer(0x21, 32, 0, 0, new byte[] { (byte) 0x80,
0x25, 0x00, 0x00, 0x00, 0x00, 0x08 }, 7, 0);

The first call sets the control line state, the second call sets the line encoding (9600, 8N1). For communication, an additional thread is used to send data without blocking the Activity’s main UI thread. By notifying sSendLock of the UsbController the data will be transferred. After submission, the thread will go into “wait” again. This way, even if submission takes more time than expected, the Activity’s main thread will not be blocked and hence the app will not become unresponsive. Also note that in the Android Manifest none of the XML-style device filters are needed, since enumeration happens by the user in the app when pressing the “enumerate” button. Device filters – and therefore automatic activity launch when connecting the Arduino – are not used in this example in order to make the code simpler to comprehend. However, this could be easily implemented with a few lines of additional code.

All code you find in this post can be used under GPL for your own projects. The following section “About Android and USB Host” again concludes why USB-Host is becoming more and more important for mobile devices and points out main differences between Android ADK (Android Accessory Development Kit) and the Android USB Host API.

Since we got requested a lot if the FTDI Usb-Serial converter will work too, here ist the control transfer code that needs to be exchanged.

conn.controlTransfer(0x40, 0, 0, 0, null, 0, 0);// reset
conn.controlTransfer(0x40, 0, 1, 0, null, 0, 0);// clear Rx
conn.controlTransfer(0x40, 0, 2, 0, null, 0, 0);// clear Tx
conn.controlTransfer(0x40, 0x03, 0x4138, 0, null, 0, 0);

Android App: UsbController.zip
Arduino main: Led example code.zip

(You may need to change the PID value in UsbControllerActivity.java on line 38, if you have an Arduino Uno Rev3 or higher.)
(You can check the VID/PID value with ‘lsusb’ after connecting the Arduino to your computer.)

About Android and USB Host


Lately it has become more and more popular to use tablets or mobile phones to communicate with the outside world over USB. After all, many devices now feature a full USB Host, either with a USB-OTG converter or even with a full sized USB Type A interface.
Also, the future promises even more host availability on mobile phones. This opens up an entire range of new possibilities for already existing hardware as well as newly designed hardware for phones. Not too long ago, Android received its own USB API.
It was at the Google I/O in summer 2011 when the “Android Open Accessory Development Kit” was announced and released. However it lacked of a few crucial points. The API implied that there is an external USB host, acting as a “master” if you will.
On the one hand, this means that an already existing USB device mode gadget cannot work with your Android device. Therefore, if a manufacturer wanted to support Android phones it was necessary to create new hardware as well as new firmware.
Secondly, the new hardware had to be designed to power itself and also deliver power the Android device; this implied that mobile gadgets require their own power source. And secondly, there was another issue: only devices running Android 2.3.4+ were shipped with the new API.
Even then, it was up to the manufacturer to actually include the required stack in the OS. But wait, there is another way to communicate over USB.
At the same time (Google I/O) the Android USB Host API has been published for Android 3.1+. Starting with the second half of 2011, Android devices appeared which supported USB OTG (although devices with Android version < 3.1 were not supporting the API).
With an appropriate adapter it has become possible for Android to act as USB Host. This meant that already present USB hardware has become compatible with the OS.
As long as the kernel on the Android device supported the USB standard driver of the hardware (mass storage, input, etc.), Android would be able to use it and therefore open up a new range of extra devices compatible with the system.
However, there are many devices that have not been “compatible” from the beginning. For instance, let’s say your common RFID reader. It most likely uses a USB-serial port and probably comes with a Linux or Windows driver as well as some software.
Most Android tablets will come without the usb-serial driver for your RFID reader however. Therefore, if you want to load your driver you will need to root your tablet, determine the version of your current kernel, find the kernel sources online, hope that everything compiles to have your driver ready and then load it onto your tablet.
In the end, when you finally have your kernel driver running, you will be required to write C code as well as some JNI glue to communicate with your Activity or Service in Android. All in all, this approach is not very straightforward.

Reference


More information