November 15, 2023

Let's learn USB! -- Enumeration again

There are some tight timing constraints during enumeration. I discovered that when I inserted "printf" statements into the papoon interrupt handler that enumeration would fail, due to the delay caused by transmitting characters. So I put together an enumeration logging facility that would capture the enumeration traffic, then dump it all out after enumeration finished.

Just as a note, here are the addresses in PMA memory for Rx and Tx data

Rx 40006380
Tx 40006300
Here is the enumeration capture:
0 Enum Reset
1 Enum Reset
2 Enum Rx S 8210 EA60 8 8006000100004000
3 Enum Tx   8000 62A0 18 120100020200004083044057000201020301
4 Enum Rx   8010 A230 0
5 Enum Reset
6 Enum Rx S 8010 EA60 8 00050A0000000000
7 Enum Tx   8000 72A0 0
8 Enum Rx S 8010 EA60 8 8006000100001200
9 Enum Tx   8000 62A0 18 120100020200004083044057000201020301
10 Enum Rx   8010 A230 0
11 Enum Rx S 8010 EA60 8 8006000600000A00
12 Enum Tx   8000 72A0 0
13 Enum Rx   8010 A210 0
14 Enum Rx S 8010 EA60 8 8006000600000A00
15 Enum Tx   8000 72A0 0
16 Enum Rx S 8010 EA60 8 8006000200000900
17 Enum Tx   8000 62A0 9 09024300020100C032
18 Enum Rx   8010 A230 0
19 Enum Rx S 8010 EA60 8 8006000200004300
20 Enum Tx   8000 62A0 64 09024300020100C03209040000010202010005240010010524010001042402020524060001070582030800FF09040100020A0000000705030240000007058102
21 Enum Tx   8000 62E0 3 400000
22 Enum Rx   8010 A270 0
23 Enum Rx S 8010 EA60 8 800600030000FF00
24 Enum Tx   8000 62A0 4 04030904
25 Enum Rx   8010 A230 0
26 Enum Rx S 8010 EA60 8 800602030904FF00
27 Enum Tx   8000 62A0 46 2E03530054004D003300320020005600690072007400750061006C00200043004F004D00200050006F0072007400
28 Enum Rx   8010 A230 0
29 Enum Rx S 8010 EA60 8 800601030904FF00
30 Enum Tx   8000 62A0 38 2603530054004D006900630072006F0065006C0065006300740072006F006E00690063007300
31 Enum Rx   8010 A230 0
32 Enum Rx S 8010 EA60 8 800603030904FF00
33 Enum Tx   8000 62A0 52 34033800370031003700340037003200380035003300350031003800380035003000300036003600660066006600340038000000
34 Enum Rx   8010 A230 0
35 Enum Rx S 8010 EA60 8 0009010000000000
36 Enum Tx   8000 72A0 0
37 Enum Rx S 8010 EA60 8 2120000000000700
38 Enum Rx   8010 A270 7 80250000000008
39 Enum Tx   8000 32A0 0
The "S" indicates that the "setup" bit was set in the endpoint register. It seems to be set for every received packet during enumeration, which makes sense. Except for that last packet! Whic has size 0 and is received on the 0 endpoint making it some kind of control packet.

Then I give the value of the "istr", and then the endpoint register, followed by the count, then the data.

I was somewhat concerned that with the F103 and only 20K of ram that I might run out of memory, but this seemed to work just fine. I ought to think about ways to find out if I exhaust memory in ways other than having weird confusing bugs show up.

Size 0 packets

One thing of note in the above is a fair number of "zero length" transfers in both directions. My guess is that some other bits or bit is signalling something in these cases, but we shall see. Perhaps these are just spurious interrupts that end up being ignored. So far a mystery, and I will ignore them for now.

Setup packets

Setup packets are 8 bytes in size. Every packet received in the capture above is 8 bytes in size and has the "SETUP" bit set, and hence is a setup packet. The trick now is to figure out what they mean.
Here is the first one received, and the response.
2 Enum Rx S 8210 EA60  8 8006000100004000
3 Enum Tx   8000 62A0 18 120100020200004083044057000201020301

The first byte in a setup packet is the request type. In our first packet this byte is 0x80. The high bit is supposed to indicate the transfer direction -- for the data phase. So if it is set (as it is in our first packet) it means "device to host" -- which I guess means it wants data. Then we get a type field (0 is "standard") and then a recipient field (0 is "device).

The recipient field is not a silly device or host, but can be:

The next byte is the request. In our first packet this is 0x06. This is "get descriptor", and since "device" was indicated in the first byte, this is "get device descriptor".

The next 2 bytes are "value" (Here: 0x0001).
The next 2 bytes are "index" (Here: 0x0000).
The next 2 bytes are "length" (Here: 0x4000).

Value of 1 means "device", so we have "GET DESCRIPTOR" for device. The index of zero is usual (or it could indicate "language"). And the length of 64 would seem to be a maximum size of 64?

Supposedly byte order in USB is little endian, but I am unsure.

The 18 bytes response can be found in usb_dev_cdc_acm.cxx as const uint8_t UsbDev::_DEVICE_DESC[] in a form that can be examined in a more or less readable form.

More setup packets

We have seen the first one, let's analyze more setup packets. The next two (after the reset) look like so:
6 Enum Rx S 8010 EA60 8 00050A0000000000
8 Enum Rx S 8010 EA60 8 8006000100001200
The second one is just a repeat of the one we already analyzed above (with a different 18 byte length for some reason) and it gets the same response. What about the first? The transfer direction is now host to device, and the request is 5 rather than 6 which is "set address" with value=0x0a00, index=0, length=0

Then we see these three:

11 Enum Rx S 8010 EA60 8 8006000600000A00
14 Enum Rx S 8010 EA60 8 8006000600000A00
16 Enum Rx S 8010 EA60 8 8006000200000900
17 Enum Tx   8000 62A0 9 09024300020100C032
These are all "get descriptor", the first two get no response. These have value of 6 which is "device qualifier". I guess it asks twice just to be sure.

The last has value = 2, which asks for configuration. It does get a response. Note that it gives a length of 9 and gets a response of size 9.

Then we get the following exchange:

19 Enum Rx S 8010 EA60 8 8006000200004300
20 Enum Tx   8000 62A0 64 09024300020100C03209040000010202010005240010010524010001042402020524060001070582030800FF09040100020A0000000705030240000007058102
21 Enum Tx   8000 62E0 3 400000
This again asks for configuration, the only difference being the length field which is now 67 (64+3). How does it know to ask for 67 bytes?

Since packets on full speed USB are limited to 64 bytes in size, the response comes in two pieces. The first is 64 bytes in length, and the extra 3 bytes come along in a second packet.
This monster can be found in usb_dev_cdc_acm.cxx as uint8_t UsbDev::_CONFIG_DESC[]

This big packet has all the information about endpoints.

Jumping ahead to the end game

Enumeration ends with the host sending these 3 packets:
35 Enum Rx S 8010 EA60 8 0009010000000000
37 Enum Rx S 8010 EA60 8 2120000000000700
38 Enum Rx   8010 A270 7 80250000000008
The first "0009" is "set configuration".
the 0x21 in the second indicates that it is a class rather than standard request.

The last packet is not a setup packet at all! It is received on the 0 endpoint, so it is a control packet of some kind.

Conclusions

I am still somewhat puzzled about USB byte order. The official statement is that it is LSB first (i.e. little endian), but when you read carefully you find they are talking about bit order on the wire being LSB first.

I have yet to see clear statments about USB byte order and I see conflicting things even in the setup packets captured above. First of all, the request field looks fine as a little endian value. The value is 6 and we see 06_00. The "value" field though is peculiar. The value is 1 and we see 00_01. When we get to the length field, thing seem nicely little endian again with 67 being represented as 43_00.

Aha! Here is something that may provide some clarification. I am looking at wiresharks "analysis" of the 8 byte config packet. It breaks it up like this:

1 byte - 0x80 - request type
1 byte - 0x06 - request
1 byte - 0x00 - descriptor index
1 byte - 0x01 - descriptor type
2 byte - 0    - language
2 byte = 0x12 - length
Now this makes sense! It matches the data and it makes sense. Why does the crappy documentation not explain this?

This has just sort of been a "recon" of the whole enumeration business. It has been enough for me to get some idea of what goes on and to know what questions to ask to probe further.

What I am going to need to do is to learn how to find information in the official USB documents in order to move ahead any further. It is not that terrible!! What you do is to download usb_20.pdf, which is a 573 page document. You can ignore most of it. What we are after is in chapter 9. Section 9.3 gives details about the device request packet.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org