December 7, 2020

USB - Hardware setup for the STM32F411 USB subsystem

How do we initialize the chip? That is what this is all about.

I am restricting myself in two ways to make this somewhat simpler. I am ignoring the OTG aspects of the USB device (the host to device mode switching). This means ignoring the HNP and SRP functionality. And this means I am ignoring host mode and all the host mode registers.

Also this particular device (the F411) does not support high speed, so I can ignore any high speed or dma setup. I will always use the built in PHY (only high speed might use an outboard PHY). Someday we may work on code for the F405 chip, which does support high speed and DMA, but we won't worry about that yet.

The business of setting up endpoint FIFOs is less of an issue than I expected. We have 8 endpoints, but we don't set all of them up. We have 1024+256 bytes of FIFO ram (320 words of 32 bits). The USB engine cares only about those 32 bit words. We can give as much FIFO ram to each endpoint as we want, and we can give some of them zero and leave them disabled.

Device initialization is mostly setting up the endpoint ram and setting up interrupts.

After doing this, I have an interrupt handler set up that reads and displays the "is" (interrupt status) register. It turns out that just reading this register clears most (but not all) interrupts. Those it does not clear simply by reading the status register must be cleared by writing a one to their bit in the status register.

Running the code gives an unexpected result. The device decides to transition from device to host mode and I get the mismatch interrupt immediately since I am reading and displaying various device registers (a bit of serendipity). This stumped me for a while, but after a nights rest, I remembered the "force device mode" bit in the USB configuration register, set it, and this behavior stopped. It sort of makes sense that the device wanted to transition to host mode with no USB cable connected. Setting this bit will cause the device to stay in "device mode" and gives me the behavior I want. Now I get a single interrupt when the device starts up. Namely a suspend interrupt.

Plug it in!

Now for something new. Find a USB cable and see what happens when we plug it in. It goes into one of those nasty interrupt loops. I figure out which interrupt this is and clear it in the handler. I always views this as things happening in a good direction when I am working with a new device (it is far worse to be wanting a device to interrupt and it not doing so).

On the linux side, I see:

new full-speed USB device number 49 using xhci_hcd
Now I get an SOF interrupt, and it persists even when I write the one to clear it. We are in some kind of nasty interrupt loop again. (Actually we aren't -- see the next page). Plainly, the USB device wants something else to be done. When we unplug the device we get a suspend interrupt.

This is a good place for this section to end, we now have the device doing things that make sense, insofar as we understand the device at this point.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org