March 7, 2025

Black Pill boards - F411 USB -- Enumeration -- Run the code

I just finished adding some debug to the Hydra F411 code to show me what goes on during enumeration. It now announces Reset events, and next I would like it to announce each setup packet (and eventually the response packet also).

I remember in the past having some trouble during enumeration when I started generating much debug. The problem is that sending serial characters takes time and the host was observing strict timeouts. We will see if this proves to be a problem. After a bit of work we get the following, displaying all setup packets as 8 bytes long.

interrupt: reset
Rx setup 8006000100004000
interrupt: reset
Rx setup 0005270000000000
Rx setup 8006000100001200
Rx setup 8006000600000A00
Rx setup 8006000600000A00
Rx setup 8006000600000A00
Rx setup 8006000200000900
Rx setup 8006000200004300
Rx setup 800600030000FF00
Rx setup 800602030904FF00
Rx setup 800601030904FF00
Rx setup 800603030904FF00
Rx setup 0009010000000000
Rx setup 2120000000000700
Notice we get the two resets described in the previous page. To display the setup packets I added another routine "usb_dump()".

The setup packets are all being handled by USBD_SetupStage() in library/usbd_core.c.
This dispatches to either USBD_StdDevReq() or USBD_StdIfReq() -- in our case.
These routines are in library/usbd_req.c -- we have looked at this before.

These routines respond by calling USBD_CtlSendData() in library/usbd_ioreq.c I put debug there and see what I get:

interrupt: reset
interrupt - enumeration done
Rx setup (8) 8006000100004000
Setup device request
Tx ctrl (8) 1201000200000040

interrupt: reset
interrupt - enumeration done
Rx setup (8) 00052C0000000000
Setup device request
Rx setup (8) 8006000100001200
Setup device request
Tx ctrl (18) 120100020000004083044057000201020301

Rx setup (8) 8006000600000A00
Setup device request
Rx setup (8) 8006000600000A00
Setup device request
Rx setup (8) 8006000600000A00
Setup device request

Rx setup (8) 8006000200000900
Setup device request
Tx ctrl (9) 09024300020100C032
Rx setup (8) 8006000200004300
Setup device request
Tx ctrl (67) 09024300020100C03209040000010202010005240010010524010001042402020524060001070582030800FF09040100020A0000000705010240000007058102400000
Rx setup (8) 800600030000FF00
Setup device request
Tx ctrl (4) 04030904
Rx setup (8) 800602030904FF00
Setup device request
Tx ctrl (66) 4203530054004D003300320020005600690072007400750061006C00200043006F006D0050006F0072007400200069006E0020004600530020004D006F0064006500
Rx setup (8) 800601030904FF00
Setup device request
Tx ctrl (38) 2603410043004D0045002000620061007200200061006E00640020006700720069006C006C00
Rx setup (8) 800603030904FF00
Setup device request
Tx ctrl (26) 1A03300030003000300030003000300030003000350030004300

Rx setup (8) 0009010000000000
Setup device request
Rx setup (8) 2120000000000700
Setup interface request
Notice that not all setup packets seem to get a response (indicated by a Tx message). The following page gives the structure of setup packets: Here again is the sequence we see:
Rx setup 8006000100004000
Rx setup 0005270000000000
Rx setup 8006000100001200
Rx setup 8006000600000A00
Rx setup 8006000600000A00
Rx setup 8006000600000A00
Rx setup 8006000200000900
Rx setup 8006000200004300
Rx setup 800600030000FF00
Rx setup 800602030904FF00
Rx setup 800601030904FF00
Rx setup 800603030904FF00
Rx setup 0009010000000000
Rx setup 2120000000000700
Notice that in all but the last, the first byte is either 0x80 or 0x00. That high bit indicates data direction. When it is set, data is expected from the device. All the other bits are zero, indicating these are standard device packets. The second byte is the request, and here is what we see:
06 - get descriptor
05 - set address
09 - set configuration
The last packet is different. Here 0x21 indicates a class interface packet. This is something I'm not ready to talk about yet.

Notice the last 2 bytes in each of these packets. It is a byte swapped (little endian) count of how many bytes follow in a "data stage". In the case where the host might send data, this count is zero and everything necessary is in the 8 bytes of setup.

And when the host asks for data, it doesn't always get as much as it asks for. For example, the very first packet indicates a len of 0x40 (64), but only gets 8. When it repeats the request after the second reset, it asks for 0x12 (18) and gets exactly that.

The first real exchange

Here is the exchange after the second reset when we get the entire 18 bytes and deal with this for real.
Rx setup (8) 8006000100001200
Tx ctrl (18) 120100020000004083044057000201020301
In the setup packet itself, the middle 4 bytes are worth examining, but end up not being particularly interesting:
0001 - wValue -- (type and index) -- documentation is foggy
0000 - wIndex -- zero here indicates no language ID
Let's look at that 18 byte response:
Tx ctrl (18) 120100020000004083044057000201020301
We have:
12 - total length of the reply.
01 - descriptor type (1 for device)
0002 - BCD for USB spec
00 - device class (0 = to be defined by the interface)
00 - subclass
00 - protocol
40 - max packet size for endpoint 0
8304 - vendor (little endian)
4057 - product (little endian)
0002 - device (BCD)
01 - manufacturer (string index)
02 - product (string index)
03 - serial number (string index)
01 - number of configurations
Note that when linux detects this, it reports:
idVendor=0483, idProduct=5740, bcdDevice= 2.00

Set address

This is a nice tidy setup (control) packet with no data stage.
00052c0000000000
The address is the two bytes 2c00. The value 0x2c is 44. Linux reports this device as "bus: 2, device: 44". The address is chosen by the host (linux in my case) and changes every time the device is plugged in.

repeated 3 times

Next we see this packet from the host repeated 3 times, and getting no reply. This asks for type 6 and expects 10 bytes.
8006000600000A00

Get device configuration, type 2 (Configuration)

An aside here first. I have given up on the friendly web site tutorials and gone back to the USB 2.0 specification document. A lot of this document deals with stuff you can just ignore (like all the electrical details and packet structure). Most of what the software person cares about is in chapter 9 (page 239). In fact it was table 9-5 that finally answered the question of what "type 2" was. Here is the exchange. Note that the host expects 9 bytes.
Rx setup (8) 8006000200000900
Tx ctrl (9) 09024300020100C032
The response packet:
09 - total size of this response packet
02 - this is a type 2 (Configuration - as requested)
4300 - total length (??)
02 - number of interfaces
01 - config value
00 - config index.
C0 - attributes
32 - max power
You can find this in library/usbd_cdc_core.c
Why the strange total length? And why two interfaces?
The next exchange explains the 0x43 length.

Get device configuration, type 2 -- a second time

Rx setup (8) 8006000200004300
Tx ctrl (67) 09024300020100C03209040000010202010005240010010524010001042402020524060001070582030800FF09040100020A0000000705010240000007058102400000
Wow, that is a big response. 67 bytes. We could grind through the spec documents working all of that out, but it is already in a nice form in library/usbd_cdc_core.c if you go to that file and find usbd_cdc_CfgDesc.

The rest of enumeration

The next one is USBD_LangIDDesc from vcp/usbd_desc.c
Rx setup (8) 800600030000FF00
Tx ctrl (4) 04030904
The following holds a string: "STM32 Virtual ComPort in FS Mode"
Rx setup (8) 800602030904FF00
Tx ctrl (66) 4203530054004D003300320020005600690072007400750061006C00200043006F006D0050006F0072007400200069006E0020004600530020004D006F0064006500
And here is another string: "ACME bar and grill"
Rx setup (8) 800601030904FF00
Tx ctrl (38) 2603410043004D0045002000620061007200200061006E00640020006700720069006C006C00
And another string follows (the serial number): "00000000050C"
Rx setup (8) 800603030904FF00
Tx ctrl (26) 1A03300030003000300030003000300030003000350030004300
And next is a self contained thing from the host to us. This is "set configuration". The value to set is 0100 (byte swapped) or in other words "1". It is saying that if you have multiple configurations, please set number 1. We only claim to have one configuration, so this should be easy.
Rx setup (8) 0009010000000000
Setup device request

That last packet -- interface request

In the first byte, bit 0x80 is not sent, so this is coming from the host to us. It shows a 7 byte count for the data phase at the end of the packet, so I missed that information in my debug capture.
Rx setup (8) 2120000000000700
Setup interface request
Almost certainly this is selecting which interface is to be used. (We did claim to have two interfaces.)

Closing remarks

The intelligent reader will realize that all that has been described in this page is entirely hardware independent. Any USB device, regardless of what hardware it is running on must enumerate, and if it implements a VCP, the packet exchange must look pretty much as described here.

At a deeper level is the whole business of handling endpoints. If we have 67 bytes that needs to be sent, how do we handle that. Or more accurately, how does the hardware in our particular USB device handle that. Stay tuned for a discussion of endpoints.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org