USB for Microcontrollers — Part 1: Basic USB Concepts

Manuel Bl.
6 min readOct 1, 2020

--

Photo by Vishnu Mohanan on Unsplash

USB is the most convenient choice to connect an MCU-based device with an application running on a laptop or desktop computer. This tutorial introduces the relevant USB concepts and implements two sample projects.

The sample projects consist of microcontroller firmware and code for a computer. A device driver is not required if done correctly. Follow along to learn how to do it.

Introduction to USB

Before diving into a specific project, the basic concepts of USB need to be understood. USB is a versatile communication standard and has been enhanced with new features regularly. Today it covers a wide range of devices from low-speed devices like keyboards to high-speed devices like SSDs and cameras, can provide or source power at up to 100W, transfer high-resolution video signals, and all of this at the same time. With the new features, complexity has increased too. This tutorial focuses on a full-speed USB 2.0 device, the most relevant category for microcontrollers. For the most part, USB 2.0 concepts still hold for newer USB standards and thus are relevant beyond these examples.

Host and Device

USB defines two basic roles:

  • Host: The host is usually a desktop PC, server or laptop. It controls the USB communication and provides power to devices. It is usually possible to connect several devices to a host.
  • Device: A device can be anything like a keyboard, printer, external disk, a microcontroller project etc. It is connected to a single host and responds to communication from the host.
Host and devices

A device may not start communication; it may only transmit if asked by the host. The host will ask the device at least every millisecond if it has data to transmit.

Endpoints

Endpoints are the basis for communication between host and device. Each USB device offers one or more endpoints. Endpoints are communication channels. Each message sent over USB is addressed to or originates from a specific endpoint.

Each device offers at least endpoint 0, a control endpoint. A control endpoints exchanges control messages and is bidirectional. The host uses endpoint 0 to query descriptive information about the device and to configure it.

Another type of endpoints are bulk data endpoints. They are used to transfer large amounts of data and they are unidirectional. Bulk data endpoints implement data streams called pipes, i.e. it is a stream protocol and not a message protocol. Thus, there is no concept of message boundaries even though data streams are built upon a message protocol at a lower level.

In USB terminology, the endpoint direction is named from the host’s perspective. Thus, IN always refers to transfers from a device to the host and OUT always refers to transfers from the host to a device. This is confusing when implementing the firmware for a device.

IN and OUT direction

Overall, there are four endpoint types:

  • Control transfer: a low throughput endpoint for control information. It is used for querying device information and configuring the device.
  • Bulk transfer: endpoint for transferring large amounts of data. It has low priority but can achieve high throughput by using all the bandwidth not needed for other types. It is used for serial data connection, data transfer for mass storage devices etc.
  • Interrupt transfer: a low throughput endpoint with high priority for status updates. It is used for notifying about keystrokes on a keyboard, mouse movements etc.
  • Isochronous transfer: a high priority, fixed bandwidth endpoint. It is used for transferring real-time data such as real-time audio.

The tutorial projects will use control and bulk transfer endpoints, the two most common endpoint types.

Interfaces and Configurations

Interfaces group endpoints. Each endpoint belongs to a single interface. For example, if a device performs two functions, it could have two interfaces to describe which endpoint belongs to which function. Each device must have at least one interface.

Configurations describe settings or modes of a device, e.g. high-power and low-power configuration, regular mode and firmware update mode. The host selects a configuration and activates it. Only one configuration can be activated at a time. Each configuration will provide different interfaces and endpoints.

Descriptors

Descriptors describe a USB device. They provide information such as vendor, power requirements, supported protocols, configuration details, interface details and endpoint details. When a USB device is plugged in, the host will read the descriptors using the control transfer endpoint 0. Based on the descriptor information, it will decide how to make the device available on the host, e.g. which device drivers to activate.

The descriptor is a data structure organized hierarchically to represent the device, configuration, interface and endpoint details:

Hierarchical descriptor organization

Note all interfaces will have endpoint 0 as well even though it is not specified in the descriptor. Furthermore, configuration numbering starts at 1.

Vendor and Product ID

Among other things, the device descriptor contains the vendor ID (VID) and product ID (PID), two 16-bit IDs. They will be essential later for connecting to the correct device from the host.

The USB Implementors Forum assigns a unique vendor ID to an organization, which can then create products using the its vendor ID in combination with any product ID. Getting a vendor ID isn’t cheap: Either you pay an annual membership fee of USD 5,000 or reduced membership plus a one-time fee of USD 6,000.

For a private project or a project still under development, you can get away with using a yet unused vendor ID. Open-source projects can get a unique VID/PID combination from http://pid.codes/ or from Openmoko for free.

Vendor and product IDs can be looked up in several places, e.g. https://www.the-sz.com/products/usbid/. While vendor IDs are centrally managed by the USB Implementors Forum, product IDs can be freely assigned by each vendor. These databases collect them from different source but naturally have an incomplete picture of product IDs.

USB Classes

The device and the interface descriptor contain class information (divided into class, sub class and protocol). This information declares what functionality the device has and what protocol it uses to communicate (on top of bare USB). The host will then load the appropriate device driver.

Several classes are standardized. They include classes for keyboards, mice, printers, serial adapters, camera, external storage devices, microphones and loudspeakers. Most operating systems will provide device drivers for these classes out of the box. So, if such a device is plugged in, it will immediately work, independent of the vendor it is from.

If you have a device that would be useful if it was treated like a keyboard, an external disk etc., implement such a standardized protocol. However, this tutorial will show how to implement a custom protocol (called vendor-specific in the USB standard). Custom protocols make sense if the device is always used together with a specific application on the host that is able to speak this protocol.

There is much more to USB than can be covered in this tutorial. For a more detailed introduction, I highly recommend USB in a NutShell and UBS Made Simple.

Enough about the theory. Let’s get cracking…

Part 2: Firmware

--

--