Four ways to send and receive data between your IoT device and Android device using USB

I develop IoT devices such as smart home controllers for fun. Those devices are usually based on microcontrollers such as ATMEGA/ATTINY and lack meaningful input/output options. After investigating numerous ways of communicating with those devices I decided to use an Android device as a controller. This worked well, so I would highly recommend if you develop a smart device – a sensor, a controller or an IoT device – consider making it communicate with Android devices. This way an Android app you develop could read and process the data from the sensor, or you can even use Android device as a controller for your IoT device.

This has a number of benefits comparing to other options – such as using a separate touch screen – and the price and availability being the most. Android tablets are widely available, and a cheap noname Android tablet could be purchased for around $20. Despite the price tag it would still pack decent processing power and memory (comparing to your IoT device), a color touch screen, battery backup and a number of connectivity interfaces. It is also supported by the mature development community. Thus the number of Android devices on market and the easiness of development makes it an attractive option from technical and business perspective.

While a typical Android tablet packs a number of hardware interfaces which could be used to communicate with Android, this article would focus on using the USB interface because it has obvious advantages:

Communication is digital, so there is no need to encode/decode the data, deal with synchronization and so on;

Communication is wired, so it is relatively secure, and couldn’t be easily tampered with or eavesdropped upon;

Offers very good data throughput, possibly in megabits per second;

It is possible to charge the Android device, and communicate with it at the same time – which is good for Android devices working as controllers, which need to stay connected permanently;

It is available on any modern Android (3.2 for USB Accessory mode, 4.0+ for USB Host mode) and is implemented virtually everywhere, even on cheap $20 Chinese tablets;

You only need one cable between your device and Android (unlike communicating through audio jack, for example);

Other interfaces such as WiFI remain available for other communication;

However there are also some disadvantages which need to be considered as well:

Despite being widespread, USB support is not guaranteed to be present on every single Android devices. Thus if your solution need to communicate with many different Android devices, some of them might be unable to do so.

A pop-up dialog requiring user interaction is shown when your device is first connected to Android device. This in turn makes fully unattended installation impossible.

In USB Host communication mode in most cases you will not be able to charge the device and communicate with it at the same time. While USB Host powered by a device is part of USB OTG specification, in my experience almost no devices (and certainly no Android tablets) support this mode.

This solution is Android-specific and will not work on iPhone or Windows phone, shall you decide later to support them.

Still if those disadvantages are not an issue for you, you should certainly try using USB for the communication. There are several use cases how you can do this, and I will describe them below.

Android as USB Host, microcontroller paired with USB-RS232 chip

In this use case your Android device works as USB Host, and a dedicated chip (such as FT232 or CH340T) works as USB slave device connected to USB port. Your microcontroller is connected to this chip using its hardware or software serial lines, and communicates with Android using Serial module. This is the same model Arduino-based devices are using to communicate with PC.

Easy to implement – it is the best solution for prototyping, you can have a working communication in minutes and need to know nothing about USB internals or how the bus works;

Easy to debug – you can connect your microcontroller to PC USB, and use screen, minicom or any other serial terminal program for debugging. Same way you can connect a pair of USB-Serial converters to Android and your PC (flipping TXD and RXD between them), and debug your Android module by using PC to emulate the controller output.

Reliable data transfer, since all USB communication is handled by a dedicated chip with its own oscillator and buffer. Thus you can even use microcontrollers without oscillators, as well as perform heavy tasks with interrupts disabled without data loss.

Proper USB device implementation with electric bus compatibility, which is important if you want to be certified to use the USB logo.

Your device could be powered by Android device battery;

Cons:

You have no control over USB identifiers because they are hardcoded into the USB-Serial chip. Thus your device would present itself as a “generic USB-Serial adapter” and would require extra communication on top of it so your application would recognize a device;

Encoding the data into serial, then USB, then back to serial adds unnecessary transition steps, and makes it more difficult to transfer binary data;

This solution requires a separate IC with a crystal. It takes power, uses space on PCB and is not cheap – those chips go around $1 a piece.

Conclusion: this solution is very good for prototyping and for situations where the cost, size and power consumption of the final device is not much of a concern.

Android as USB Host, microcontroller implements hardware USB slave

In this scenario your Android device works as USB Host, and a microcontroller featuring the hardware USB interface (such as Atmel AT90USB family) communicates with Android device using USB control protocol or bulk transfer. You can use USB Control messages if your communication is not data transfer intensive (for example you’re controlling relays or engines, or receive sensor data). If you need to transfer significant amounts of data, you implement bulk transfers.

You have full control of USB, including access to the device configuration and identifiers. Thus you can implement any kind of USB device, from printers and controllers to sound cards and mass storage;

You can use the fastest USB communication if you need it;

Data transfer is reliable, since all USB communication is implemented inside the chip;

Your device can also work with other computers, such as PC;

Hardware serial interface remains available for debugging, logging or other communications;

More difficult to implement. You need to know at least on the basic level how the USB works, what is the device descriptor, vendor and product IDs, Control requests and Bulk Transfer.

USB operation typically requires a crystal or oscillator of a specific frequency (which should be an even divider of 48MHz). Thus if your project requires a specific different crystal, such as 12.736MHz, you cannot use this solution;

Controllers with hardware USB implementation are generally more expensive. However they usually have more memory available, and offer more functionality.

Conclusion: this solution works the best for mass production, when the you need to emulate different kinds of devices, and when you need the best throughput.

Android as USB Host, microcontroller implements software USB Slave

This solution is very similar to the above, but in this case a microcontroller would use a software USB implementation. The same communication rules apply, as described in the above solution – you can use USB Control messages if your communication is not data transfer intensive, and you can use bulk transfers for large amounts of data.

Software implementation: You fully control the USB implementation on both ends. On microcontroller side you use a V-USB library, available from https://www.obdev.at/vusb/. This library comes with a large set of examples for several device classes.

Pretty much any controller can be used with a very simple circuit (two resistors and two Zener diodes). There is no need for the controller to have hardware USB support. Even ATTINY85 works in this configuration, and there is no need for a crystal. This makes the solution cheap.

You have full control of USB, including access to the device configuration and identifiers. Thus you can implement any kind of USB device, from printers and controllers to sound cards and mass storage;

Strict timing requirements make it impossible to perform operations with interrupts disabled;

The USB implementation is software-driven and thus is not timed perfectly. Thus it is not fully electrically compatible with USB, and the products using it will not be able to bear the USB logo

Only V-USB library supports this mode, and it is licensed under GPLv2. Commercial licensing is also available, but it might make more sense to invest instead into hardware USB support.

Conclusion: this solution is very suitable for hobby projects. It also could be used for the projects where the cost is the most important, and you don’t care about USB compatibility or failures. It is not suitable for situations where you rely on your device being able to do stateful communication.

In this scenario your Android device works as USB Accessory, and a microcontroller featuring the USB interface with USB Host support (such as Atmel AT90USB647) communicates with Android device using Android Accessory communication protocol. This protocol is similar to Serial communication in terms of it operates on a character stream. It doesn’t seem like there is any support for USB Bulk Transfer mode.

Software Implementation: You need to implement the Android Accessory USB protocol on the microcontroller side. For this you use one of USB libraries such as LUFA available from http://www.fourwalledcubicle.com/LUFA.php.

You have very limited access to the USB. While you can still control things like vendor IDs and device configuration, the restrictions imposed on you through Android Accessory USB interface, severely limit you.

Your device will only work with Android; there is no way to make this work for PCs as a typical PC expects an USB device, not an USB host.

USB operation typically requires a crystal or oscillator of a specific frequency (which should be an even divider of 48MHz). Thus if your project requires a specific different crystal, such as 12.736MHz, you cannot use this solution;

Very few controllers implement hardware USB with USB Host mode, and those tend to be the most expensive, typically around $5 and higher per IC. However they usually have more memory available, and offer more functionality.

Reconnects are not very reliable, and the USB read interface on Android is still buggy. Notably a bug regarding closing the USB handle was only fixed recently after being reported back in 2011.

Conclusion: this solution should be used when your device is permanently connected to Android, and you need to charge it through USB interface.