USB Enumeration

USB enumeration is a bit complicated so I thought it'd be good to document a few of the packets...

I'm working on a stm32 USB driver in Zig (for my little Zuric project) and well it's turned out to be quite a learning process. This is on linux, I'm not sure if windows does anything differently.

Initial detection

When a "full speed" device is first plugged in and connected (by enabling the pulling up) linux will send a setup packet requesting the device descriptor to determine the max endpoint size.

USB Device Config Packet

The device needs to reply with the first part of the device descriptor.

USB Device Config Response

Instead of reading the whole thing the host will send back an empty ack and then force a bus reset.

USB Device Config Packet Ack

Then a it'll reset.

USB Reset

Device Enumeration

A few ms after the reset it will send another setup packet to set the device address.

Set address

USB Set address

The device then needs to send an ack response while still un addressed so the response is to addr still 0.

USB Set address ack

After the ack status is pulled the firmware needs to update the address. All future requests will be to the address it set.

Device Descriptor

The host will do another request with the new address to pull the device descriptor.

USB Get device descriptor

Note: When the first and second bytes are 0x80 and 0x06 the 4th byte is the descriptor type (eg 0x01). See the references for the setup packet layout.

This time it will do multiple requests (as needed) to pull the entire descriptor. For full speed it will be 3 packets.

USB Get device descriptor

USB Get device descriptor

USB Get device descriptor

Device Qualifier

Next the host will request the device qualifier (if any). I'm not sure if this always occurs or is only based on the configuration being used.

USB Get device qualifier

In my case there is none so the response is a "Stall". (There happens to be a SOF packet in this screenshot, that can be ignored).

USB Get device qualifier stall

The host may retry a few times.

Device Configuration

After that it'll the host will pull the configuration.

USB Get config

It needs 2 packets.

USB Get config response



Zig is awesome at catching programming errors.

Breakpoint 1, panic (err=..., stack=<optimized out>) at startup.zig:72
72      pub fn panic(err: []const u8, stack: ?*std.builtin.StackTrace) noreturn {
(gdb) p err
$3 = {ptr = 0x8003f68 <__unnamed_98> "index out of bounds", len = 19}
(gdb) bt
#0  panic (err=..., stack=<optimized out>) at startup.zig:72
#1  0x0800245e in usb.Device.irqHandler (self=<optimized out>) at <omitted>/usb.zig:432
#2  <omitted>
#3  USB_LP_IRQHandler () at startup.zig:239
#4  <signal handler called>