May 25, 2013
I am entirely ignoring USB 3.0, just for the record.

You may want to go back and read my section on hardware basics before reading this.

Protocols

There are three layers: You should just rely on the bus controller to handle the physical layer. The Application layer is what provides the unique functionality of the device. The middle layer is the device independent USB protocol.

Understanding the middle layer is the crucial part if you want to develop USB devices (or drivers for USB devices). On the host side, a library like libusb handles the middle layer - on the device side, something like LUFA exists for lucky people developing devices with AVR chips inside.

Transactions

It is important to understand that the host initiates every transaction! USB is what is called a polled bus and devices speak only when spoken to. This is what ensures order on the half duplex USB cable.

Each transaction is initiated by the host and involves the transfer of 3 packets:

There are IN and OUT transactions, both are initiated by the host. In other words, the host always sends the Token Packet. Note that in addition to transactions initiated by the host in response to application software, a host is always sending "start of frame" packets. They contain an 11 bit frame number and are sent every 1ms on a full speed bus and every 125 microseconds on a high speed bus with very tight timing requirements.

Data packets can carry at most 1024 bytes:

There are devices, functions, endpoints, and pipes. Communications looks to the client as a pipe (a logical connection between a host and one or more endpoints). There are stream and messages pipes.

Transfer Modes

There are four transfer modes (and consequently four endpoint types). It is entirely possible to have a device that does everything it needs to do using control transfers.

Note that a device that wants to interrupt must queue the interrupt and wait until the host polls before it can signal the interrupt. All transfers are initiated by the host!

Device Classes

There are a set of defined USB Class codes; 255 of them are possible. A few are as follows: A value of 0 indicates undefined; a value of 0xff indicates vendor specific.

The plain talk here is that classes exist to standardize certain sorts of USB devices so a common device driver can support them. If your USB device advertises itself as belonging to a certain class and does what it is supposed to do, then a standard driver can be applied. As an example, if you do the right things as a CDC class device, your device will appear as /dev/ttyUSB0 or /dev/ttyACM0 and you can talk to it like a serial port without writing any driver code.

What lots of people do in the real world is to set up their USB device as a HID class device, even though it is by no means a mouse or keyboard. The HID class seems to be a pliable generic framework to set up a diversity of simple devices, and lots of people us it this way.

Pipes and Endpoints

Endpoints are very important. The endpoint field is four bits, which limits a device to 16 IN and 16 OUT endpoints (32 in all!). To talk to a device, you have to first specify the device by bus and device address. Once you have done this, you send and receive data to and from endpoints in the device. An endpoint is a data buffer on the device. An endpoint has 3 properties: its number, its direction, and its size per transaction (the buffer size). There are no bidirectional endpoints. Endpoint 0 is always available for either IN or OUT control transactions, (there are separate IN and OUT endpoints) and is used to configure the device. It is quite possible to have a device that uses the endpoint 0 pair for everything, but this is somewhat unusual. Usually a device will set up one or more additional endpoints.

IN endpoints are distinct from OUT endpoints. IN endpoints always seem to have 0x80 added to their endpoint number. So a device with IN endpoint 1 configured would have that endpoint addressed as endpoint 0x81. The same device with OUT endpoint 1, would have that endpoint addressed as endpoint 0x01. Whether or not a given programming API adds the 0x80 (128) for you or expects you to do it can lead to some confusion.

The USB 2.0 specification talks about devices, functions, interfaces and pipes. Any good standard needs lots of carefully defined terms that you don't always need to worry about, and USB is certainly no exception. A simple garden variety USB device will have one function and one interface. It is possible to have a multi-function USB device with several interfaces. In any event, an interface consists of a collection of endpoints. All this makes for a lot of abstract talk, but the bottom line is that to communicate with a USB device, you need to know what endpoints it has and what each of them is for.

A pipe is a virtual connection between a host controller and a specific endpoint. You never actually think about a pipe (and maybe that is the point of it). You communicate with a specified endpoint without any concern for hubs along the way. There are stream and message pipes. Messages pipes are well specified by the USB protocol. Stream pipes can be adapted to suit the task at hand (i.e can be vendor specific).


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org