November 23, 2023

Let's learn USB! -- "set address" during enumeration

What could be simpler you say? During enumeration, the host selects an address and sends it to you in a "set address" message. You stick that address into the appropriate register and you are done.

It is tricky, and not that simple. Here is how I understand it. You cannot just set the address the moment you receive it. The device needs to respond to the "set address" command using the same address used to send the message. This smells like a race, and the device always wins if the new address is sent as soon as the message is received.

The device needs to wait until the "Data IN" phase of the transaction. Here we are talking about the USB stuff we thought we didn't need to talk about. But ignore the terminology for now, the thing to do is as follows. Hold on to that address for a while. In fact, send a ZLP (zero length packet) and when you see the CTR packet for that transmission, then set the address!

What I see in my linux logs when I set the address immediately is:

device not accepting address 14, error -32
If I just comment out the setting of the address in the DADDR register, this error goes away. Linux apparently gets the ACK and is convinced that you properly received the address.

More trouble

The timing seems very touchy as far as setting the address and subsequent transactions during enumeration. Any kind of printf() activity causes enumeration to fail.
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org