Tuesday, August 25, 2026

Understanding the USB Protocol

 

Understanding the USB Protocol

A Practical Developer's Guide, from Signaling to Firmware

From electrical signaling to enumeration traces and firmware implementation: a from-scratch, byte-level explanation of the USB protocol for embedded and firmware developers.


 

Table of Contents

Table of Contents.............................................................................................................................. 2

1. Introduction................................................................................................................................... 4

2. Architecture Overview................................................................................................................... 4

3. The Physical Layer.......................................................................................................................... 4

3.1 Differential Signaling................................................................................................................. 4

3.2 NRZI Encoding........................................................................................................................... 5

3.3 Bit Stuffing................................................................................................................................ 5

3.4 Speed Classes........................................................................................................................... 5

4. Packets: The Basic Unit of Communication...................................................................................... 6

4.1 The PID Byte............................................................................................................................. 6

5. Token Packets................................................................................................................................ 6

6. Data Packets.................................................................................................................................. 7

7. Handshake Packets........................................................................................................................ 7

8. Transactions................................................................................................................................... 7

8.1 IN Transaction (device → host).................................................................................................. 8

8.2 OUT Transaction (host → device).............................................................................................. 8

8.3 SETUP Transaction.................................................................................................................... 8

9. Byte-Level Packet Walkthrough...................................................................................................... 8

9.1 An Actual Token Packet............................................................................................................. 8

9.2 A Complete IN Transaction on the Wire..................................................................................... 9

9.3 A Complete OUT Transaction on the Wire.................................................................................. 9

10. Frames and Bus Bandwidth........................................................................................................... 9

11. Transfer Types............................................................................................................................ 10

11.1 Control Transfers in Detail...................................................................................................... 10

12. USB Device States....................................................................................................................... 10

13. Endpoint Addressing................................................................................................................... 11

14. The 8-Byte SETUP Request, Decoded.......................................................................................... 11

15. Descriptors, Byte by Byte............................................................................................................ 12

15.1 Device Descriptor (18 bytes).................................................................................................. 12

15.2 Configuration Descriptor (9 bytes header).............................................................................. 13

15.3 Interface Descriptor (9 bytes)................................................................................................ 13

15.4 Endpoint Descriptor (7 bytes)................................................................................................ 14

15.5 HID Descriptor (9 bytes, one report descriptor)...................................................................... 14

16. A Complete Descriptor Tree Example.......................................................................................... 15

17. Standard Device Requests........................................................................................................... 15

17.1 Common Standard Requests................................................................................................. 16

18. The Complete Enumeration Trace............................................................................................... 16

19. Life After Enumeration................................................................................................................ 17

20. USB Device Classes..................................................................................................................... 18

21. Composite Devices..................................................................................................................... 18

22. USB Topology............................................................................................................................. 19

23. Power........................................................................................................................................ 19

24. Error Handling............................................................................................................................. 19

25. High-Speed Details...................................................................................................................... 20

26. USB On-The-Go and Host Mode.................................................................................................. 21

27. A Minimal Firmware Implementation.......................................................................................... 21

28. Reading an Enumeration Trace.................................................................................................... 22

29. Common Enumeration Failures................................................................................................... 23

30. Summary.................................................................................................................................... 23

 


 

PART 1 — How USB Works   (Physical layer → packets → transactions → transfers)

1. Introduction

Universal Serial Bus (USB) is the standard that connects almost every peripheral to a computer today: mice, keyboards, storage devices, audio interfaces, and countless embedded gadgets. For application developers, USB is invisible — plug in a device and it works. For firmware developers, USB is a protocol that has to be implemented, byte by byte, inside a microcontroller.

This tutorial explains USB from the ground up, and then goes further than most introductions by working through real byte-level examples: an actual token packet, an actual SETUP request, an actual device descriptor, and a full enumeration trace. The goal is to give you a mental model solid enough to read a USB peripheral's reference manual, follow a USB analyzer capture, or write a bare-metal USB device driver.

USB is a host-centric bus. There is exactly one host and one or more devices. Devices never initiate communication on their own; the host always starts every transaction. This single design decision shapes almost everything else about the protocol.

The tutorial is organized into five parts: how the bus works electrically and at the packet level; how a device becomes recognized by the host; how bulk data actually moves once a device is set up; what a firmware implementation needs to provide; and how to read and debug a real enumeration trace.

2. Architecture Overview

It helps to think of a USB device's firmware as being organized into a small number of layers, each responsible for a different level of abstraction:

        Physical / signaling layer — turns bits into voltage transitions on the D+ and D- wires, and back again.

        Packet layer — groups bits into well-formed packets with identifiers, addresses, and error-checking codes.

        Protocol layer (transactions and transfers) — combines packets into meaningful exchanges: "read this data", "here is data for you", "that request is not supported".

        Device / class layer — the application logic that decides what the device actually does: a mouse reporting movement, a mass-storage device serving disk blocks, and so on.

A microcontroller with a built-in USB peripheral typically handles the physical layer and much of the packet layer in hardware, leaving the firmware responsible for protocol-level decisions and the device/class behavior. Part 4 of this tutorial returns to exactly where that line is usually drawn.

3. The Physical Layer

3.1 Differential Signaling

USB (at Low Speed and Full Speed) uses two wires, D+ and D-, driven as a differential pair. Instead of comparing a single signal wire to ground, the receiver compares D+ to D- directly, which makes the signal far more resistant to electrical noise.

The bus has a small number of defined states, based on the relative voltages of D+ and D-:

        J state — the idle / logic-high differential state for the device's current speed.

        K state — the opposite differential state, used to encode transitions.

        Single-Ended Zero (SE0) — both D+ and D- are pulled low at the same time; used to signal a Reset or the End-Of-Packet condition.

        Single-Ended One (SE1) — both lines high at once; not valid during normal operation, and normally indicates an error or disconnect.

Which physical line represents a logic "1" versus "0" depends on the device's speed class (Low Speed and Full Speed use opposite pull-up conventions), which is also how the host initially detects a newly attached device's speed — by seeing whether D+ or D- is pulled high through a 1.5 kΩ resistor inside the device.

3.2 NRZI Encoding

USB does not send raw bits as direct voltage levels the way a UART might. Instead it uses Non-Return-to-Zero Inverted (NRZI) encoding: a logical "0" bit causes a transition (J to K, or K to J); a logical "1" bit causes no transition — the line stays in its current state.

NRZI keeps the signal largely self-clocking, since transitions let the receiver's clock-recovery circuit stay locked to the sender. A long run of "1" bits produces no transitions at all, which would let the receiver's clock drift — solved by bit stuffing.

3.3 Bit Stuffing

To guarantee a transition often enough for clock recovery to stay locked, the transmitter inserts an extra "0" bit after every six consecutive "1" bits in the data stream, before NRZI encoding is applied. The receiver applies the same rule in reverse, discarding a stuffed bit after every run of six "1"s it decodes. Bit stuffing is transparent to firmware — it never sees the stuffed bits — but it is why a raw oscilloscope capture of a packet doesn't map one-to-one with the packet's logical bits.

3.4 Speed Classes

Speed

Data Rate

Typical Use

Low Speed (LS)

1.5 Mbit/s

Simple HID devices: keyboards, mice

Full Speed (FS)

12 Mbit/s

Most general-purpose peripherals

High Speed (HS)

480 Mbit/s

USB 2.0 storage, cameras, audio interfaces

The speed class is signaled electrically as soon as the device is attached, letting the host controller configure its own transceiver before any packets are exchanged. Part 4 covers why High Speed needs a further negotiation step beyond this initial pull-up detection.

4. Packets: The Basic Unit of Communication

Every exchange on the bus is built from packets, each with the same overall shape: a SYNC field (a fixed bit pattern letting the receiver's clock-recovery circuitry lock on), a PID byte (identifying the packet type), packet-specific fields, and an EOP (End Of Packet, a defined Single-Ended-Zero condition).

4.1 The PID Byte

The PID byte is actually only 4 meaningful bits, sent twice: once normally and once bitwise-inverted, giving 8 transmitted bits. This redundancy lets the receiver immediately detect a corrupted PID. The table below gives the byte value of every defined PID — the value you'd see in a register or FIFO dump, written the normal way (MSB on the left). How that byte's bits actually get put on the wire, bit by bit, is a separate question covered in Section 9.

PID Name

Category

4-bit Code

Transmitted Byte

OUT

Token

0001

0xE1

IN

Token

1001

0x69

SOF

Token

0101

0xA5

SETUP

Token

1101

0x2D

DATA0

Data

0011

0xC3

DATA1

Data

1011

0x4B

DATA2 (HS only)

Data

0111

0x87

MDATA (HS only)

Data

1111

0x0F

ACK

Handshake

0010

0xD2

NAK

Handshake

1010

0x5A

STALL

Handshake

1110

0x1E

NYET (HS only)

Handshake

0110

0x96

PING (HS only)

Special

0100

0xB4

SPLIT (HS only)

Special

1000

0x78

PRE / ERR

Special

1100

0x3C

Note: These byte values are what a raw endpoint FIFO dump or a USB peripheral's PID register will show. They are constant across every USB device in the world — they're part of the specification, not something a device chooses. A logic analyzer trace of the wire itself will instead show these same bits in their LSB-first transmission order, as Section 9.1 shows for the IN token's PID.

5. Token Packets

A token packet is always sent by the host and marks the start of a transaction. It contains a PID, a 7-bit ADDR (device address 0–127), a 4-bit ENDP (endpoint number 0–15), and a 5-bit CRC covering ADDR and ENDP together.

Token

Meaning

OUT

Host is about to send data to the device.

IN

Host is requesting the device send data to it.

SETUP

Host is starting a control transfer with a standard 8-byte request.

SOF

Start-of-Frame — a periodic timing/heartbeat packet, carrying an 11-bit frame number instead of ADDR/ENDP.

6. Data Packets

A data packet carries the payload — from 0 up to the endpoint's configured maximum packet size. It consists of the PID (DATA0 or DATA1), the payload bytes, and a 16-bit CRC covering the payload.

USB alternates between DATA0 and DATA1 PIDs across successive data packets on the same endpoint ("data toggle"). If the device expects DATA1 but the host resends DATA0 — because it never saw an ACK for a previous attempt — the mismatch reveals a retransmission, letting a duplicate be discarded safely without any explicit sequence-number field.

7. Handshake Packets

A handshake packet is the simplest kind — just a PID and nothing else — and it reports the outcome of a transaction:

Handshake

Meaning

ACK

Data was received correctly.

NAK

Device is not currently ready to send or accept data; the host should retry later. Not an error.

STALL

The endpoint cannot process the request at all — often an unsupported request or a real error condition.

NYET

"Not Yet" — High-Speed only; data received, but the device can't accept more yet (used in split transactions).

NAK is routine — a keyboard endpoint NAKs almost every time the host polls it, since there's usually no new key event to report. STALL is closer to an error and typically requires software intervention (often an explicit CLEAR_FEATURE(ENDPOINT_HALT) request) to clear.

8. Transactions

A transaction is one token packet plus the data and/or handshake packets that follow it — the smallest complete unit of USB communication.

8.1 IN Transaction (device → host)

        Host sends an IN token.

        Device responds with a DATA packet (or a NAK/STALL handshake if it has nothing to send, or an error).

        If data was sent, the host responds with an ACK once it has received the data correctly.

8.2 OUT Transaction (host → device)

        Host sends an OUT token.

        Host sends a DATA packet.

        Device responds with ACK, NAK, or STALL.

8.3 SETUP Transaction

        Host sends a SETUP token.

        Host sends a DATA0 packet containing an 8-byte standard request structure.

        Device must respond with ACK — a SETUP transaction cannot be NAK'd.

SETUP transactions always use DATA0, and the device must accept them, because SETUP is how the host begins a control transfer, and every USB device must always be ready to respond to control transfers on endpoint 0.

9. Byte-Level Packet Walkthrough

This section works through what actually goes on the wire — as opposed to what firmware sees — for a token packet and for complete IN and OUT transactions.

9.1 An Actual Token Packet

Take an IN token addressed to device 5, endpoint 1. Fields, in transmission order (each sent LSB-first):

Field

Size

Value

Binary (as transmitted, LSB first)

SYNC

8 bits

fixed pattern

00000001

PID

8 bits

IN = 0x69

10010110

ADDR

7 bits

5

1010000

ENDP

4 bits

1

1000

CRC5

5 bits

computed over ADDR+ENDP

(hardware-generated)

EOP

~3 bit times

SE0, SE0, J

Note: CRC5 is intentionally shown as "hardware-generated" rather than a specific bit pattern here: on every real USB peripheral (host or device side) this field is generated and checked automatically by hardware, per the algorithm in USB 2.0 specification Chapter 8. Firmware essentially never touches it directly, so this tutorial won't risk giving you a hand-derived value to memorize — the important part is knowing which 11 bits it protects and where it sits in the packet.

Firmware never sees SYNC, the raw NRZI-encoded bits, bit-stuffing, or CRC5/CRC16 directly — a real USB peripheral strips all of that in hardware and simply tells firmware "a valid IN token addressed to endpoint 1 arrived" (usually via an interrupt flag and an endpoint/address register), or silently discards the packet if a CRC check failed.

9.2 A Complete IN Transaction on the Wire

Suppose the host wants to read 4 bytes from endpoint 1 of device 5, and the device currently has data ready:

        1. Host → Device: IN token (PID 0x69, ADDR=5, ENDP=1, CRC5)

        2. Device → Host: DATA1 packet (PID 0x4B, 4 payload bytes, CRC16)

        3. Host → Device: ACK handshake (PID 0xD2)

If the device had nothing ready, step 2 would instead be a NAK handshake (PID 0x5A) and the transaction would end there — the host simply tries again on its next scheduled poll of that endpoint.

9.3 A Complete OUT Transaction on the Wire

        1. Host → Device: OUT token (PID 0xE1, ADDR=5, ENDP=2, CRC5)

        2. Host → Device: DATA0 or DATA1 packet (PID depends on toggle state, payload bytes, CRC16)

        3. Device → Host: ACK (0xD2), NAK (0x5A), or STALL (0x1E) handshake

Comparing 9.2 and 9.3 side by side is a good way to internalize the core asymmetry in USB: for an IN transaction the device is the one sending data; for an OUT transaction the host is.

10. Frames and Bus Bandwidth

The host periodically broadcasts a Start-of-Frame (SOF) token to every device on the bus — every 1 ms at Full/Low Speed, or every 125 µs (a "microframe") at High Speed. SOF gives devices a shared sense of timing, which matters for isochronous transfers like audio, and marks the boundary the host uses to schedule transactions.

Because the bus is shared, the host controller performs bandwidth allocation: deciding how many transactions of each type fit inside a single frame. Isochronous and interrupt endpoints reserve a slice of every frame's bandwidth when the device is configured; control and bulk transfers use whatever is left over.

11. Transfer Types

A transfer is a higher-level exchange made up of one or more transactions, matched to the kind of data being moved. Every endpoint other than endpoint 0 (always control) is configured for exactly one of the following.

Transfer Type

Reliability

Timing Guarantee

Typical Use

Control

Guaranteed (retried on error)

None specific

Device configuration, standard requests

Bulk

Guaranteed (retried on error)

None (best-effort)

Mass storage, printers — large, non-urgent data

Interrupt

Guaranteed (retried on error)

Bounded latency, polled at a fixed interval

Mice, keyboards, joysticks — small, time-sensitive data

Isochronous

Not guaranteed (no retries)

Fixed bandwidth and timing each frame

Audio, video streaming — timing matters more than perfection

11.1 Control Transfers in Detail

Control transfers are built from up to three stages:

        Setup stage — a single SETUP transaction carrying the 8-byte request.

        Data stage (optional) — zero or more IN or OUT transactions carrying the request payload, in one consistent direction.

        Status stage — a single transaction, in the opposite direction from the data stage (or an IN if there was no data stage), confirming completion. Its data packet always carries zero bytes.

Part 2 walks through a full control transfer, byte for byte, as part of the enumeration trace.

PART 2 — How a Device Becomes Recognized   (States → EP0 → descriptors → enumeration)

12. USB Device States

State

Description

Attached

Physically connected, but the bus hasn't been reset yet.

Powered

Receiving power (relevant mainly for bus-powered devices, once VBUS is detected).

Default

Has just seen a bus reset; responds at address 0 only, using default endpoint 0 parameters.

Address

Has been assigned a unique address via SET_ADDRESS, but not yet configured.

Configured

Has accepted a SET_CONFIGURATION request; all endpoints are active and it is ready for normal use.

Suspended

The bus has been idle for a defined period; device should reduce power consumption.

13. Endpoint Addressing

It's easy to conflate "endpoint number" and "endpoint address", but USB treats them as related, distinct concepts.

        Endpoint number — a 4-bit value (0–15) identifying the logical channel inside the device. Endpoint 0 is always the default control endpoint.

        Direction — IN (device → host) or OUT (host → device). Endpoint 0 is unique in being bidirectional using the same number for both directions.

        Endpoint address — the byte used in descriptors and in software to refer to a specific direction of a specific endpoint number: bit 7 is the direction bit (1 = IN, 0 = OUT), bits 6:4 are reserved (0), and bits 3:0 are the endpoint number.

So a device can have, at most, one OUT endpoint and one IN endpoint per endpoint number (0 through 15) — they are addressed independently even though they share a number.

Endpoint Address (hex)

Binary

Meaning

0x00

0000 0000

Endpoint 0 OUT (part of the default control pipe)

0x80

1000 0000

Endpoint 0 IN (part of the default control pipe)

0x01

0000 0001

Endpoint 1 OUT

0x81

1000 0001

Endpoint 1 IN

0x82

1000 0010

Endpoint 2 IN

Endpoint 0 is special for three reasons: every device must implement it, it is always control-type, and it is the only endpoint guaranteed to be active before the device is configured — which is exactly why the entire enumeration process happens over endpoint 0.

14. The 8-Byte SETUP Request, Decoded

Every SETUP transaction carries the same 8-byte structure. Here is a real, complete example — a GET_DESCRIPTOR request asking for the full 18-byte device descriptor — decoded field by field:

80 06 00 01 00 00 12 00

Bytes

Field

Value

Meaning

80

bmRequestType

1000 0000b

Bit 7=1: device-to-host. Bits 6:5=00: Standard request. Bits 4:0=00000: recipient is the Device.

06

bRequest

6

GET_DESCRIPTOR

00 01

wValue

0x0100

Low byte 0x00 = descriptor index 0. High byte 0x01 = descriptor type 1 (DEVICE).

00 00

wIndex

0x0000

Not used for a device descriptor request; set to 0.

12 00

wLength

0x0012 = 18

Host will read up to 18 bytes in the data stage — exactly the size of a device descriptor.

Note: Multi-byte fields (wValue, wIndex, wLength) are little-endian, so "12 00" means 0x0012, not 0x1200. This is a very common source of off-by-a-factor-of-256 bugs when hand-assembling SETUP packets.

A shorter variant is common early in enumeration, when the host doesn't yet know the device's max packet size and just wants the first 8 bytes: bmRequestType/bRequest/wValue/wIndex stay the same, but wLength becomes 0x0008:

80 06 00 01 00 00 08 00

15. Descriptors, Byte by Byte

Descriptors are structured, self-describing blocks of data a device presents to the host so it can be understood without any prior knowledge of the specific device. Every descriptor starts with the same two-field header — a length byte and a type byte — which lets a host walk a chain of descriptors even if it doesn't recognize every one.

15.1 Device Descriptor (18 bytes)

Offset

Field

Size

Meaning

0

bLength

1

Always 18 (0x12) for a device descriptor.

1

bDescriptorType

1

1 = DEVICE.

2–3

bcdUSB

2

USB spec version in BCD, e.g. 0x0200 = USB 2.00.

4

bDeviceClass

1

Device class (0 = defined per-interface, common for composite devices).

5

bDeviceSubClass

1

Subclass, meaning depends on bDeviceClass.

6

bDeviceProtocol

1

Protocol, meaning depends on class/subclass.

7

bMaxPacketSize0

1

Max packet size for endpoint 0 (8, 16, 32, or 64).

8–9

idVendor

2

USB-IF assigned Vendor ID (VID).

10–11

idProduct

2

Vendor-assigned Product ID (PID).

12–13

bcdDevice

2

Device release number in BCD.

14

iManufacturer

1

Index of the manufacturer string descriptor (0 = none).

15

iProduct

1

Index of the product string descriptor (0 = none).

16

iSerialNumber

1

Index of the serial number string descriptor (0 = none).

17

bNumConfigurations

1

Number of possible configurations.

15.2 Configuration Descriptor (9 bytes header)

Offset

Field

Size

Meaning

0

bLength

1

Always 9 (0x09).

1

bDescriptorType

1

2 = CONFIGURATION.

2–3

wTotalLength

2

Total length of this descriptor plus every interface/endpoint/class descriptor that follows it in the same response.

4

bNumInterfaces

1

Number of interfaces in this configuration.

5

bConfigurationValue

1

Value used by SET_CONFIGURATION to select this configuration.

6

iConfiguration

1

String descriptor index (0 = none).

7

bmAttributes

1

Bit 6 = self-powered, bit 5 = remote wakeup supported. Bit 7 is always set for historical reasons.

8

bMaxPower

1

Maximum bus current draw, in 2 mA units (e.g. 50 = 100 mA).

15.3 Interface Descriptor (9 bytes)

Offset

Field

Size

Meaning

0

bLength

1

Always 9 (0x09).

1

bDescriptorType

1

4 = INTERFACE.

2

bInterfaceNumber

1

Zero-based index of this interface.

3

bAlternateSetting

1

Alternate setting index (0 for the default).

4

bNumEndpoints

1

Number of endpoints used by this interface, excluding endpoint 0.

5

bInterfaceClass

1

USB class code (e.g. 0x03 = HID, 0x08 = Mass Storage).

6

bInterfaceSubClass

1

Meaning depends on class.

7

bInterfaceProtocol

1

Meaning depends on class/subclass.

8

iInterface

1

String descriptor index (0 = none).

15.4 Endpoint Descriptor (7 bytes)

Offset

Field

Size

Meaning

0

bLength

1

Always 7 (0x07).

1

bDescriptorType

1

5 = ENDPOINT.

2

bEndpointAddress

1

Direction bit + endpoint number, as covered in Section 13.

3

bmAttributes

1

Bits 1:0 select transfer type: 00 Control, 01 Isochronous, 10 Bulk, 11 Interrupt.

4–5

wMaxPacketSize

2

Maximum packet size this endpoint accepts/sends.

6

bInterval

1

Polling interval (interrupt/isochronous) — units depend on speed class.

15.5 HID Descriptor (9 bytes, one report descriptor)

Offset

Field

Size

Meaning

0

bLength

1

9 (0x09) for a HID descriptor with one class descriptor entry.

1

bDescriptorType

1

0x21 = HID.

2–3

bcdHID

2

HID class spec version in BCD.

4

bCountryCode

1

Localized hardware, or 0 if not country-specific.

5

bNumDescriptors

1

Number of class descriptors that follow (usually 1).

6

bDescriptorType

1

0x22 = Report.

7–8

wDescriptorLength

2

Length in bytes of the HID Report Descriptor.

The Report Descriptor itself (pointed to by the HID descriptor above) is a separate, compact tag-based structure describing exactly what an input report contains — buttons, axes, their ranges and units — letting a generic OS-level HID driver interpret arbitrary devices without device-specific code.

16. A Complete Descriptor Tree Example

Putting the previous section's tables together, here is what the device and configuration descriptors of a minimal single-button HID mouse actually contain, laid out as the host would receive them:

Descriptor

Key Fields

Device

bcdUSB=0x0200, bDeviceClass=0x00, bMaxPacketSize0=64, idVendor/idProduct = vendor-assigned, bNumConfigurations=1

Configuration

wTotalLength = 9+9+9+7 = 34 bytes total, bNumInterfaces=1, bmAttributes=0x80 (bus-powered), bMaxPower=50 (100 mA)

Interface 0

bInterfaceClass=0x03 (HID), bInterfaceSubClass=0x01 (Boot), bInterfaceProtocol=0x02 (Mouse), bNumEndpoints=1

HID

bcdHID=0x0111, bNumDescriptors=1, wDescriptorLength = length of the report descriptor below

Endpoint

bEndpointAddress=0x81 (EP1 IN), bmAttributes=0x03 (Interrupt), wMaxPacketSize=4, bInterval=10

When the host issues GET_DESCRIPTOR(Configuration) with a large enough wLength, it receives all five of these descriptors concatenated in exactly this order, in a single data stage: the 9-byte configuration descriptor, followed immediately by the 9-byte interface descriptor, the 9-byte HID descriptor, and the 7-byte endpoint descriptor — 34 bytes total, matching wTotalLength. This concatenation, rather than separate requests for each piece, is why wTotalLength exists: it tells the host exactly how many bytes to read in one data stage to get the whole tree.

17. Standard Device Requests

Every SETUP transaction carries the 8-byte structure introduced in Section 14, regardless of what the request does.

Field

Size

Purpose

bmRequestType

1 byte

Direction, type (standard/class/vendor), and recipient (device/interface/endpoint)

bRequest

1 byte

Which request this is, e.g. GET_DESCRIPTOR or SET_ADDRESS

wValue

2 bytes

Request-specific parameter (e.g. descriptor type & index)

wIndex

2 bytes

Request-specific parameter (often an interface or endpoint number)

wLength

2 bytes

Number of bytes expected in the data stage, if any

17.1 Common Standard Requests

Request

Purpose

GET_STATUS

Query remote-wakeup / self-powered / halt status

CLEAR_FEATURE / SET_FEATURE

Clear or set a specific feature, e.g. ENDPOINT_HALT

SET_ADDRESS

Assign the device its bus address (enumeration step)

GET_DESCRIPTOR / SET_DESCRIPTOR

Read (or, rarely, write) a descriptor

GET_CONFIGURATION / SET_CONFIGURATION

Query or select the active configuration

GET_INTERFACE / SET_INTERFACE

Query or select an alternate interface setting

SYNCH_FRAME

Used with isochronous endpoints to report frame synchronization

Class-specific requests (like HID's SET_IDLE, SET_REPORT, and GET_REPORT) reuse the same 8-byte structure, distinguished by the type bits inside bmRequestType, so the same control-transfer machinery handles both standard and class requests without special-casing at the transaction level.

18. The Complete Enumeration Trace

Enumeration is the sequence that happens automatically whenever a device is plugged in, before it becomes usable. At a high level, it follows this sequence:

RESET -> GET_DESCRIPTOR(Device,8) -> SET_ADDRESS -> GET_DESCRIPTOR(Device,18)   -> GET_DESCRIPTOR(Config,9) -> GET_DESCRIPTOR(Config,full) -> SET_CONFIGURATION

Expanded into individual steps, with the actual control transfers involved:

        1. Attach & speed detection — the device asserts its pull-up resistor; the host's root hub detects it and determines speed class from which line is pulled high.

        2. Bus reset — the host holds D+ and D- low (SE0) for a defined minimum duration. The device resets internal state and starts responding at address 0.

        3. Partial GET_DESCRIPTOR(Device) — SETUP payload 80 06 00 01 00 00 08 00, requesting just 8 bytes, primarily to learn bMaxPacketSize0 (byte offset 7 of the device descriptor).

        4. SET_ADDRESS — SETUP payload 00 05 05 00 00 00 00 00 (bRequest=0x05, wValue=0x0005 assigning address 5). The device must ACK this at address 0, then respond at the new address for everything after the status stage — the address change itself only takes effect after the status stage completes.

        5. Full GET_DESCRIPTOR(Device) — SETUP payload 80 06 00 01 00 00 12 00, now addressed to the new device address, reading all 18 bytes.

        6. Partial GET_DESCRIPTOR(Configuration) — SETUP payload 80 06 00 02 00 00 09 00 (wValue high byte 0x02 = CONFIGURATION), reading just the 9-byte header to learn wTotalLength.

        7. Full GET_DESCRIPTOR(Configuration) — same request with wLength set to wTotalLength from step 6, returning the whole descriptor tree from Section 16 in one data stage.

        8. (Optional) GET_DESCRIPTOR(String) — bmRequestType=80, bRequest=06, wValue high byte 0x03 = STRING, to fetch human-readable manufacturer/product/serial text, if the earlier descriptors' string indices were non-zero.

        9. SET_CONFIGURATION — SETUP payload 00 09 01 00 00 00 00 00 (bRequest=0x09, wValue=configuration value from Section 15.2). The device activates its endpoints and moves to the Configured state.

        10. Class-specific setup — for the HID mouse example, the host typically also issues GET_DESCRIPTOR(Report) to fetch the report descriptor, and SET_IDLE (a HID class request) before beginning normal interrupt-endpoint polling.

Every one of these is a full control transfer (setup stage + optional data stage + status stage) built from the transactions covered in Section 8 — enumeration is really just several control transfers in a row, each depending on information learned from the one before it.

PART 3 — How Data Is Actually Moved   (Bulk / Interrupt / Isochronous / Control, once a device is configured)

19. Life After Enumeration

Once a device is configured, the host's driver stack takes over, and communication settles into the pattern determined by each endpoint's transfer type from Section 11:

        A HID mouse's interrupt IN endpoint gets polled by the host on a fixed schedule (its bInterval); most polls return NAK because there's no new movement to report.

        A mass-storage device's bulk endpoints move large blocks of data with no fixed timing — the host just issues as many transactions as the bus has room for.

        An isochronous audio endpoint gets exactly one transaction's worth of bandwidth reserved every frame, whether or not there's actually new audio data ready — dropped samples are preferred over a broken timing guarantee.

        Endpoint 0 continues handling any further control transfers throughout the device's life — class requests, vendor requests, and any standard requests the host issues later (like re-reading GET_STATUS).

The transaction and packet mechanics don't change after enumeration; what changes is which transfer type is in play and how the host's driver schedules it.

PART 4 — Implementing USB Firmware   (Classes → composite devices → topology → power → errors → HS → OTG)

20. USB Device Classes

A USB class is a standardized protocol layered on top of control/bulk/interrupt/isochronous transfers, letting a generic, OS-provided driver talk to any compliant device without vendor-specific code. bInterfaceClass (Section 15.3) is what tells the host which driver to load.

Class

Class Code

Typical Devices

Why It Matters to the Host

HID

0x03

Keyboards, mice, joysticks, custom controllers

One generic driver interprets any device via its Report Descriptor — no per-device driver needed.

CDC / ACM

0x02

USB-to-serial adapters, virtual COM ports

Lets a microcontroller show up as a familiar serial port to any OS.

Mass Storage

0x08

Flash drives, external SSDs, SD readers

Wraps SCSI commands (via the Bulk-Only Transport protocol) so any OS's existing storage stack works unmodified.

Audio

0x01

USB microphones, speakers, audio interfaces

Standardizes sample formats and isochronous streaming so no per-device audio driver is needed.

Vendor-Specific

0xFF

Anything without a fitting standard class

Requires a custom driver; used when no standard class matches the device's actual behavior.

Classes matter because they determine how much host-side software you have to write. A HID or CDC device can often be talking to a stock OS driver within minutes of writing correct descriptors; a vendor-specific device needs a custom driver or user-space library on every platform you want to support.

21. Composite Devices

A single physical USB device can expose more than one function by declaring multiple interfaces inside one configuration — this is a composite device. A keyboard-with-integrated-trackpad, for example, typically exposes two HID interfaces from one device: one behaving as a boot keyboard, another as a boot mouse, each with its own interface descriptor, its own class/subclass/protocol, and its own endpoint(s), all inside a single configuration descriptor's descriptor tree.

The host enumerates the device exactly as described in Section 18 — it's still one device descriptor and one (or more) configuration descriptors — but once GET_DESCRIPTOR(Configuration) returns the full tree, the OS loads a separate driver instance against each interface independently, based on that interface's own class code. Section 15.3's bNumInterfaces field is how the host first learns there's more than one function to bind drivers to.

22. USB Topology

USB is physically a tiered-star topology, not a bus in the electrical-signal sense its name suggests:

        Host controller — the silicon (in a PC, SBC, or MCU acting as a host) that owns the bus and schedules every transaction.

        Root hub — logically a hub built into the host controller itself; every physical port on your computer is a downstream port of the root hub.

        External hubs — devices that are themselves USB devices (they enumerate and have their own address) but also provide additional downstream ports, letting the tree branch further.

        Devices — leaf nodes of the tree; a device cannot have anything downstream of it (only a hub can).

The specification allows up to 5 tiers of hubs between the root hub and a device (a limit driven by signal-timing budgets, more relevant at Low/Full Speed). Every device on the tree, no matter how many hubs deep, gets its own unique 7-bit address (1–127) assigned during its own enumeration — address 0 is reserved for whatever device is currently mid-enumeration and hasn't been assigned one yet.

23. Power

        VBUS — the +5 V supply line every USB connector carries. A device only starts drawing meaningful current, and asserting its speed pull-up, once VBUS is present.

        Bus-powered vs. self-powered — declared in the configuration descriptor's bmAttributes (Section 15.2). A bus-powered device draws all its power from VBUS and must stay within the limit it declared in bMaxPower; a self-powered device has its own supply and typically declares a minimal VBUS draw.

        Current limits — an unconfigured device is limited to 100 mA (bMaxPower = 50, in 2 mA units) until it's configured; a configured device may request up to 500 mA at Full/High Speed (bMaxPower = 250) without needing a special high-power negotiation.

        Suspend current — after the bus has been idle for the defined suspend timeout, a device must reduce its total current draw substantially (typically to a few mA) regardless of its normal operating current, to comply with the specification's suspend power budget.

        Remote wakeup — an optional capability (declared via bmAttributes bit 5) letting a suspended device signal the host to resume the bus — e.g. a keyboard waking a sleeping PC on a keypress — by driving a defined resume signaling sequence rather than waiting passively.

24. Error Handling

USB is designed to detect errors at the packet level and recover automatically wherever possible, rather than relying on the application layer to notice something went wrong.

Error

Detected By

Typical Recovery

CRC error

CRC5 (token) or CRC16 (data) mismatch at the receiver

Packet is silently dropped; no handshake is returned, which the sender interprets as a timeout and retries.

Bit-stuff error

An invalid/unexpected bit pattern breaks the bit-stuffing rule

Treated like a corrupted packet — dropped, triggering the same timeout-based retry.

Timeout

Expected response (data or handshake) doesn't arrive within the defined turnaround window

Sender retries the transaction, typically up to a bus-defined retry limit before giving up and reporting an error upstream.

Babble

A device keeps driving the bus past the point it should have stopped (e.g. past EOP)

Host controller disables the port; often surfaces to the OS as a device error requiring re-enumeration.

Data toggle mismatch

Received DATA0/DATA1 PID doesn't match the expected toggle state

Receiver silently discards the packet as a duplicate but still ACKs it, since the sender clearly didn't see the previous ACK.

A recurring theme is that most of this is handled by hardware or the host controller driver, invisibly to device firmware — firmware generally only needs to worry about STALL conditions it deliberately signals, and about NAK, which (as covered in Section 7) isn't really an error at all.

25. High-Speed Details

The 1.5 kΩ pull-up described in Section 3 only ever signals Low Speed or Full Speed capability — it cannot, by itself, put a device into High-Speed mode, because a High-Speed-capable device must still be backward compatible with Full-Speed-only hosts and hubs.

Instead, High Speed is negotiated after the initial Full-Speed-style reset, through a sequence called chirp:

        The device, if High-Speed capable, drives a Chirp-K signal for a defined duration immediately after detecting the host's reset.

        If the host (or the hub it's attached through) is also High-Speed capable, it responds with an alternating sequence of Chirp-K / Chirp-J signals.

        Once the device detects at least three of these alternating K-J chirp pairs from the host, it switches its transceiver to High-Speed signaling levels and termination, and the reset completes in High-Speed mode.

        If the device never sees the host's chirp response, it falls back to operating at Full Speed — the negotiation is designed to fail safe toward compatibility rather than toward a broken link.

This is also why a High-Speed device plugged into an old Full-Speed-only host, or downstream of a Full-Speed-only hub, works correctly at Full Speed rather than failing outright: the chirp handshake simply never completes, and both sides settle on the speed they actually share.

26. USB On-The-Go and Host Mode

USB On-The-Go (OTG) extends the strict host/device split so a single port on a small device — a phone, or a microcontroller with a USB peripheral capable of host mode — can act as either a host or a device, without needing two separate connectors.

        ID pin — OTG connectors add a fifth pin beyond the standard four; whether it's grounded (Micro-A/USB-C configured as host) or floating (Micro-B/USB-C configured as device) tells the controller which role to start in.

        Dual-role device (DRD) — a device capable of switching roles, either based on the ID pin or dynamically via negotiation.

        Session Request Protocol (SRP) — lets a device without its own strong power source ask an attached host to turn on VBUS and start a session, rather than requiring the host to always be powered and waiting.

        Host Negotiation Protocol (HNP) — lets the two ends of an OTG link swap which one is acting as host, after a session is already established, without physically unplugging anything.

For embedded developers, this matters most when a microcontroller's USB peripheral needs to read from a USB flash drive, a USB-to-serial gadget, or a MIDI keyboard directly — i.e. the microcontroller itself needs to act as the host, driving SOF, issuing tokens, and managing device addresses, rather than just responding to a PC as a device (everything described in Parts 1–3 of this tutorial, but with the roles reversed).

27. A Minimal Firmware Implementation

It helps to be explicit about where the dividing line usually falls between what a microcontroller's built-in USB peripheral does in hardware, and what firmware still has to provide, for a simple USB device (e.g. the HID mouse used as a running example in Part 2).

Layer

Typically Handled By Hardware

Typically Left to Firmware

Physical

NRZI encode/decode, bit stuffing/unstuffing, differential transceiver, speed-class pull-up

Nothing — this layer is essentially always fully automatic on integrated USB peripherals.

Packet

SYNC, PID generation/checking, CRC5/CRC16 generation/checking, EOP detection

Nothing on most peripherals, though some very low-cost or bit-banged implementations require firmware to do parts of this in software.

Transaction

Token/data/handshake sequencing for a given endpoint, per-endpoint FIFOs, automatic ACK/NAK based on FIFO state, data toggle tracking

Deciding when data is ready to push into a TX FIFO, and reading data out of an RX FIFO promptly enough to avoid stalling.

Protocol / requests

Delivering received SETUP packets and endpoint interrupts to firmware

Parsing bmRequestType/bRequest/wValue/wIndex/wLength, deciding how to respond, and building/queuing the correct response descriptor bytes.

Device / class

Nothing — entirely application logic

Maintaining the device's own state machine (Section 12), storing the descriptor tables from Part 2, implementing class-specific requests (e.g. HID's SET_IDLE), and producing the actual application data (e.g. mouse movement reports).

Concretely, a minimal HID mouse firmware's main responsibilities usually come down to: storing the descriptor byte tables from Section 16 in flash; handling endpoint-0 SETUP interrupts by matching bRequest/wValue against the standard requests from Section 17 and queuing the appropriate descriptor bytes or handshake; implementing SET_ADDRESS and SET_CONFIGURATION by updating the device's own state (Section 12); and, once configured, periodically pushing a 4-byte HID report (buttons + X/Y deltas) into endpoint 1's IN FIFO whenever the host polls it and new movement is available.

PART 5 — Practical USB Debugging   (Reading a trace and recognizing common failures)

28. Reading an Enumeration Trace

When a USB protocol analyzer (hardware, or a software capture of host-side traffic) shows an enumeration, it will look like a sequence of the same control transfers listed in Section 18, each broken into its packets. A healthy trace has a very recognizable rhythm:

        A short burst of activity around the reset, then a SETUP token + DATA0 + (device) ACK for the 8-byte device descriptor request.

        A gap while the device processes, then IN tokens with DATA1/DATA0 responses alternating, each ACK'd, until 8 bytes have been transferred, followed by a zero-length status transaction.

        A SET_ADDRESS control transfer, notably still addressed to device 0.

        Every subsequent control transfer now addressed to the new device address, repeating for the full device descriptor, then the configuration descriptor (partial, then full), then optionally strings, then SET_CONFIGURATION.

If you're staring at a real capture, the fastest way to orient yourself is to find the SET_ADDRESS transaction first — everything before it is addressed to device 0, and everything after it is addressed to the new device number, which makes the trace much easier to read top to bottom.

29. Common Enumeration Failures

Symptom

Likely Cause

Device isn't detected at all

Pull-up resistor missing/misconfigured, VBUS not present, or a hardware/wiring fault on D+/D-.

Device resets in a loop

Firmware crashing or hanging while handling the first SETUP packet, or an incorrect bMaxPacketSize0 causing the host to misread the 8-byte partial descriptor response.

"Unknown device" / descriptor request fails

Malformed device descriptor (wrong bLength/bDescriptorType), or firmware not responding to the control transfer's status stage.

Device enumerates but OS loads no driver

bInterfaceClass/SubClass/Protocol don't match any driver the OS recognizes, or wTotalLength in the configuration descriptor doesn't match the actual bytes returned.

Device works, then randomly disconnects

Power budget exceeded (drawing more current than bMaxPower declared), or a babble/timeout condition from a firmware bug in endpoint handling under load.

Mouse/keyboard enumerates but never reports input

Interrupt endpoint never gets new data pushed into its IN FIFO, or the endpoint descriptor's wMaxPacketSize doesn't match what firmware actually writes.

In nearly every case, comparing a failing trace against the healthy rhythm from Section 28 — and against the exact byte layouts from Sections 14 through 17 — turns "it doesn't work" into a specific, fixable mismatch.

30. Summary

USB is built as a stack of increasingly abstract concepts, each resting on the one below it: electrical differential signaling becomes NRZI-encoded bits, bits become packets identified by their PID, packets combine into transactions, transactions combine into transfers suited to different kinds of data, and a structured sequence of control transfers — enumeration — lets any compliant device introduce itself to any compliant host without prior knowledge of one another.

With the byte-level examples in Parts 2 and 3, the state and power model in Part 4, and the debugging habits in Part 5, a USB reference manual, a protocol analyzer trace, or a microcontroller's USB peripheral registers should read far less like magic and far more like a direct, if detailed, implementation of the ideas covered in this tutorial.


No comments:

Post a Comment