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 next post in this series is Android USB Host + Arduino: How to communicate without rooting your Android Tablet or Phone.

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 (0x2341) and product (0x0001) 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:

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:
   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 = 0x20 (as defined in CDCClassCommon.h) and with bmRequestType = 0x21. 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 = 0x22 = 34 and the second one bRequest = CDC_REQ_SetLineEncoding = 0x20 = 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.

11 Replies to “Arduino USB transfers”

    1. Hi Antoine,

      For FTDI chips the procedure is basically the same, however, the firmware running on those chips is not available. In the end, it all comes down to sending different control transfers for initialization.

      Fortunately there is also an open source library called libftdi for communicating with FTDI chips.

      Have a look at our earlier post Creating a Serial to USB driver using the Android USB-Host API. In the Android sources you will find the right control transfers for an FTDI device 🙂


    1. Hi Ricardo JL !

      I want to use that library for a proyect, but I don´t know how to write/read properly, it didn’t work for me. I am wondering if you know where I can find some examples of simple communication. I have proved the example that they have on git but it only reads and don’t writes. I want to learn more about how to use it but I don’t know where!

      Thank youu !!

  1. I have quite tiny awareness of coding nevertheless a PHP world wide web software?s skill to screen info info from a databases is a person of its most vital, main functions. The speed at which this info is retrieved from the database is created manifest to the conclusion consumer as total site effectiveness, so, whichever way you can, you test to make your database phone calls as efficient as possible, this involves striving to get as considerably info as achievable in as few queries as probable, however guaranteeing your queries accomplish optimally. On the other hand, as miami– or world-wide-web application realizes improved site visitors, your databases?s general performance quickly will become a bottleneck and a lot of what is currently being continuously displayed demands a substantial number of queries versus the database, causing your database to attain read through ability.This is in which you want to make use of caching to quickly cache data that is repetitively essential to provide prevalent information for your website software, if you have any tips or recommendations please share.

  2. Dear Andreas Rudolf,
    Interesting Thoughts Toshiba laptops have noted of major memory concerns on its laptops. The laptops which are attacked by this memory problem, are likely to crash, the method may possibly get locked up and also all your crucial data can get corrupted. Manu personal computer are seen to get influenced by the memory problem. That is why Toshiba has declared to build a downloadable file for testing the infected memory process. If you are utilizing a Toshiba laptop computer and if there is some memory difficulty, you can substitute the weakened elements of your laptop. For resolving any type of issue, the distant computer system aid can be of good assist.

  3. G’Day! Andreas Rudolf,
    Interesting Post I want to make something that can do some basic mechanical things (like making a motor spin)
    Where can i go to read up on that kind of stuff?
    I know there’s this Arduino USB Board but I’d rather have something that doesn’t have to be mailed (I live in Shanghai).
    All the Best

  4. Hi, great info, thank you. Is there a way that I can use an arduino to transfer a file to a usb device like a gps navigator? Usually you would use usb to transfer to the arduino, but I want to transfer from the arduino.

    1. Hi Johan,

      All USB communication must be initiated by a USB host, there is no USB communication between USB device and USB device.
      The Arduino only has a USB device microcontroller. And I am pretty certain that devices like GPS navigator also only have USB device controllers on them.

      Some devices like digital cameras have a feature called USB on the go (OTG). In the normal case, they act as a USB device (much like a USB stick) that you insert into your host computer; in that case, the computer acts as the USB host. However, they can also act as the USB host, so that you can connect a USB stick to the camera, and the camera can then save data to the USB stick.

      But again, I am pretty sure that most GPS navigators are USB device only. Also, you can not make the Arduino UNO a USB host just by changing the firmware, because USB host functionality requires a special on-board hardware controller. The Arduino DUE on the other hand theoretically has USB host functionality. See here for more information:

      Best Regards

Leave a Reply

Your email address will not be published. Required fields are marked *