Arduino USB transfers

In this post we will show you how to communicate between the Arduino Uno and your computer using plain USB bulk and control transfers, not relying on a serial communication interface. Our development computer runs Ubuntu 11.10 (Oneiric Ocelot).

This is a follow up to Programming the Arduino Uno with Eclipse on Linux.

The Arduino Uno has an on-board USB-to-serial converter (ATMega8u2 or ATMega16u2 since rev. 3). The preloaded firmware on this converter presents itself as an USB Communication Device Class (CDC). Usually, no further software driver is needed on the host computer. You can simply plug in the Arduino Uno to your computer, and you will be able to communicate with the Arduino’s main microcontroller, the ATMega328, over an emulated serial communication interface.

For many applications, a serial communication interface is just fine. You can use minicom, gtkterm or a similar terminal application to send and receive data from your microcontroller. Or even use a python serial library and start off from there. In some circumstances however, you might not have the possibility to open a serial communication. Android for instance does not have a native serial communication interface, instead it features an USB host API. In this case, you must rely solely on USB control and bulk transfers.

When you connect an Arduino Uno to your linux computer with an USB cable, you will notice that a new device node /dev/ttyACM0 or similar is created. For this purpose, check out the last few lines from dmesg right after connecting the Arduino Uno.
$ dmesg | tail
...
[] usb 1-5.2: new full speed USB device number 43 using ehci_hcd
[] cdc_acm 1-5.2:1.0: ttyACM0: USB ACM device

In the above example, the Arduino Uno is assigned to USB device number 43, and a new device node /dev/ttyACM0 is created. This device node is automatically created by the module cdc_acm and represents a serial communication interface which you can use with minicom, gtkterm, etc. However, we are not going to do that. We want to find out how to talk to this device using USB transfers, right? ;-)

Further investigations with the vendor (0×2341) and product (0×0001) id …
lsusb -v -d 2341:0001
… yield more interesting information about this device. For instance, bNumInterfaces = 2 shows that there are two available interfaces. This stems from the mentioned pre-loaded Arduino firmware. There you will see two projects:

  • arduino-usbdfu is the Arduino USB DFU bootloader firmware, which is used for flashing the ATmega8u2 or ATmega16u2 respectively.
  • arduino-usbserial is the real firmware of the USB-to-serial converter. This is where the magic happens :-)

Again, looking at the output of …
lsusb -v -d 2341:0001
… you will see two interface descriptors. The first one with bInterfaceNumber=0 is the DFU bootloader, and the second one with bInterfaceNumber=1 is our usb-serial firmware interface descriptor. You can double-check that in arduino-usbdfu/Descriptors.c and arduino-usbserial/Descriptors.c respectively.

The starting point of the usb-serial project is in firmwares/arduino-usbserial/Arduino-usbserial.c. At the top, a variable VirtualSerial_CDC_Interface is initialized, and it is then passed in the main’s for-loop:
...
CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
USB_USBTask();

The function CDC_Device_USBTask() is part of the LUFA-lib (Lighweight USB Framework Library), and is defined in CDCClassDevice.c. Likewise, this source file can be considered as the heart-piece of the usb-serial firmware. There we find all important functions such as CDC_Device_SendByte and CDC_Device_ReceiveByte. You will notice that almost every function returns immediately if no LineEncoding/Baudrate has been set. Luckily, the function CDC_Device_ProcessControlRequest (also in CDCClassDevice.c) unravels the mysteries of setting the LineEncoding, Baudrate, LineState, etc. Here is a shortened excerpt:

void CDC_Device_ProcessControlRequest() {
 switch (USB_ControlRequest.bRequest){
  case CDC_REQ_SetLineEncoding:
  if (USB_ControlRequest.bmRequestType == (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE)){
   CDCInterfaceInfo->State.LineEncoding.BaudRateBPS = Endpoint_Read_32_LE();
   CDCInterfaceInfo->State.LineEncoding.CharFormat  = Endpoint_Read_8();
   CDCInterfaceInfo->State.LineEncoding.ParityType  = Endpoint_Read_8();
   CDCInterfaceInfo->State.LineEncoding.DataBits    = Endpoint_Read_8();
  }
...

Now we’re cooking :-) . To set the LineEncoding we therefore need to send an USB control request with bRequest = CDC_REQ_SetLineEncoding = 0×20 (as defined in CDCClassCommon.h) and with bmRequestType = 0×21. Also, the data must hold 7 bytes with corresponding values.

Once you know which requests to look for, it is pretty straightforward. Use an USB sniffer like wireshark and observe what happens when you plug in your Arduino board. With wireshark, you can also search for a specific bmRequestType by applying a filter like:
usb.bmRequestType == 0x21

As it turns out, there are two important control transfers when connecting the Arduino board to the computer. The first one has bRequest = CDC_REQ_SetControlLineState = 0×22 = 34 and the second one bRequest = CDC_REQ_SetLineEncoding = 0×20 = 32.

If you want to try it for yourself, download and run this python script (with sudo). This script will initialize the usb-serial-converter with USB control transfers and then send single bytes from your computer to the Arduino Uno using bulk transfers. Just make sure to remove the cdc_acm module beforehand by issuing:
$ sudo rmmod cdc_acm
As this module will otherwise lock access to the USB device. Also, you will need appropriate software running on your Arduino board. You may download this source code and flash it onto the device. This will set the duty cycle of a PWM signal on PIN3 according to the byte received from the computer. Also it will light up the on-board LED if the received byte is an odd value and shut it off when an even value is received.

Programming the Arduino Uno with Eclipse on Linux

This is the first of a series of three posts. The ultimate goal is to setup a communication interface between an Arduino Uno board and an Android tablet over USB. Everything will be as user-friendly as possible, i.e. no root will be required on your Android tablet.

The Arduino Uno is a popular and affordable hardware platform which comes with its own IDE and core libraries for programming. If you like the Arduino IDE you may skip this post, however, if you feel more comfortable developing in Eclipse this might help you out.
We are using Ubuntu 11.10 (oneiric ocelot) and Eclipse 3.6.1 (helios), although this should not play an important role (as it turns out, Eclipse Indigo might need a few tweaks, check the end of this post). Also, setting up Eclipse for programming the Arduino Uno Atmega328P is pretty straightforward. Nevertheless, here is a quick how-to:

  1. Install avrdude and AVR libraries:
    sudo apt-get install gcc-avr avr-libc avrdude
  2. Start Eclipse and install CDT Plugin (C/C++ Development Tools):
    • Help -> Install New Software…
    • Work with: (your current Eclipse version)
      i.e. “Helios – http://download.eclipse.org/releases/helios”
    • Download the “pending” software package (don’t worry, download starts automatically ;-) )
    • Choose “Programming Languages” and select “C/C++ Development Tools”
    • Accept and continue by restarting Eclipse
  3. Install AVR Eclipse Plugin:
    • Help -> Install New Software…
    • Add new repository: http://avr-eclipse.sourceforge.net/updatesite/
    • Re-download the “pending” software package, download will be faster since it is probably cached :-D
    • Download AVR Eclipse Plugin and restart Eclipse
  4. Create new C project named “BlinkBlink”:
    • Project Type AVR Cross Target Application (Empty Project, AVR-GCC Toolchain)
    • Click next…
    • Untick “Debug” (in Debug mode, no hex-files are generated and avrdude can’t flash the device)
    • Click Advanced settings…
    • AVR -> AVRDude -> Programmer configuration…
    • Create a new programmer and name it “Arduino Uno”. Make sure this newly created programmer configuration is selected for the current project.
      • Programmer Hardware: Arduino
      • Override default port: /dev/ttyACM0 or similar
      • Override default baudrate: 115200
    • AVR -> Target Hardware:
      • MCU Type: ATmega328P (or load from MCU)
      • MCU Clock Frequency: 16000000 (default external clock source of Arduino Uno)
  5. Click Apply and OK to leave the properties window and click Finish to create the new project in the workspace.
  6. Create a new source file main.c and copy the contents from this link.
  7. Project -> Build Project
  8. Click on the AVR Button within Eclipse to upload the generated hex file from BlinkBlink/Release/BlinkBlink.hex.
    Your Arduino Uno’s LED should be blinking on and off repeatedly. If somehow it doesn’t work, right-click your Project and select Properties. Make sure all AVR and Programmer settings are active as mentioned above.

Update: if you are using Eclipse Indigo, some specific AVR symbols such as DDRB (data direction register of port b) may not be recognized.
To solve this problem go to preferences…

  • C/C++
  • Language Mappings
  • Add the following mappings:
    • Content Type: C Header File / Language: GNU C
    • Content Type: C Source File / Language: GNU C

Your Language Mapping preference window should look like the following screenshot:

If it still does not work, also try adding this line at the beginning of your main.c source file:
#include <avr/iom128.h>

Creating a Serial to USB driver using the Android USB-Host API

Lately we have received many concerns about using the serial interface on Android (Honeycomb with USB-Host). The way to usually communicate with a USB-Serial device in Linux, is to create a virtual serial interface and use it like a normal serial interface. For instance if you connect an FTDI controller via USB, a device /dev/ttyUSBX will be created.

USB-Serial Connection connects streams to Bulk Endpoints

However, behind the scenes you are actually communicating with the device using plain USB Bulk transfers. This job is done by the USB-Serial driver for you (ftdi_sio for instance). If you like to avoid using the kernel driver for some reason you can do this by using a library based on libusb called “libftdi”.

If you look at the source code you will notice that this library manages the connection (depending on the chip type) to the serial controller. Part of this task for instance is resetting TX/RX or setting the baudrate, which is not entirely trivial as it turns out.

Reading data is pretty simple (if your IN packet returns more than two bytes there is data ready). While when sending data you have to be sure not to write more than the max packet size defined by the controller. For details see the source code of libftdi.

Looking at Android there is a core problem with serial devices. As shown in a previous article it is pretty complicated to get started with building the driver. However, the even more painful part is, that there is no API-featured way to receive permissions for the /dev/USBX device node! So root is required.

But Hey! With libftdi, or it’s implementation it is now possible to write your own driver using the Android USB Host API. In the attached example application a connection to a VNC2 Controller is opened and each seconds one byte is transferred. For the example LEDs on the board are toggled. Using the Bulk OUT EP a rs232 “write” is emulated.

Download the Android source
Note that you should change the VID_PID String according to your device “VVVV:PPPP”.
Also note that if you would like to test if this works on your computer you should first remove the ftdi_sio driver using:
$ sudo rmmod ftdi_sio.

Debugging on your Ubuntu machine:
It’s probably much easier to debug on your workstation. Recently I found pyusb pretty helpful:
$ sudo apt-get install python-usb.
Here is a python script that will get you started: main.py.

Honeycomb Tablet optimized version of the Android Oscilloscope

The ultimate goal of our Bachelors Thesis one year ago was to deliver a “market-read” version of our oscilloscope project where you can just install an app from the market and connect the oscilloscope over USB.

Before the “Tablet Age” our idea was to set up the OTG port of a phone for host mode. However, this requires rooting the phone as well as adding a voltage supply to the connector. Not a very elegant solution.

When the first tablets with honeycomb arrived (3.0) we managed to use the host port on a rooted device to get our oscilloscope working. Still, root was required.

With Honeycomb 3.1 it was not only possible to acquire permission of the USB device it also became possible to program USB with the Java API rather than to go native with libusb.

Therefore we have written a tablet optimized version of our oscilloscope. With the all new user interface comes the ability to connect to our USB oscilloscope. You can get the application from the Android Market with your 3.0 and up tablet. Get the source code: HoneyOsciPrime.tar.gz, or the APK HoneyOsciPrime.apk. You can always download our Layout Files here and build your own oscilloscope or contact us for support.

Acer A500 running OsciPrime

Screenshot of the new Honeycomb OsciPrime App

Creating a remote Scroll Wheel for your Linux Machine using Android, Bluetooth and uinput

Scrolling long documents can be tiring for your index finger on a mouse wheel or on a touch pad. What if you could use your phones touch screen to scroll a document on your computer? While maybe not the most ergonomically solution it may well be a good example of how to work with bluetooth, uinput and Android.

Setup
Android Phone ( >= 2.1)
Ubuntu Laptop with Bluetooth
Two great Tutorials:
Bluez: http://people.csail.mit.edu/albert/bluez-intro/x604.html
uinput: http://thiemonge.org/getting-started-with-uinput

Concept
The application consists of two parts:

  • A client side on the phone that serves as touch pad to scroll.
  • A server part on the computer that receives commands from the phone and emulates scroll movement for uinput.

The Client is a simple Android Activity spawning a Bluetooth Thread. Touch events then result in a Bluetooth packet that tell the server if the user moved up or down. The source code is very straight forward; only Thread synchronization is a bit tricky as well as the way how the application is stopped (locks etc.).

The Server application connects the world of Bluetooth (RFCOMM/SDP) with the uinput event input system. Basically the server registers an SDP entry and then listens on an RFCOMM channel for incoming connections. As soon as a connection is established a new input device is created and scroll events are sent. Note that you probably need to be root (or use sudo) on the Linux machine to feed uinput new events.

Instructions

  • Pair your Android phone with the Linux device
  • Start the server on your Linux device: $ sudo ./btserver (make sure BT is turned on, else there could be a segfault -> working on that)
  • Install and start the app on the phone. In the menus select your Linux device.

Building Dependencies
To build the dev-libbluetooth package was necessary on our Ubuntu machine.

The code is available under GPL. Have fun playing around with it :)
Note: It’s very straight forward to create a remote control for your Linux machine with the sources. Key presses can be emulated very easily with uinput.

Source Code
Android Sources
Android APK
Server code for Linux
Our App on the Android Market

Leave a comment if you like what we did or have some improvements :)