December 6, 2020

USB - Minimal code for the STM32F411 USB hardware

I have learned enough to try something. Now that I know that the host will reset a USB device and then begin firing information requests at it, I can put together a minimal bit of code to enable the USB device and report to me when something (anything happens).

I am doing all this in the context of my "hydra" project.

So here is the game plan to get started:

Clocks

We scan through the reset and clock enable bits in the F411 RCC. I miss the reset and clock control bits on my first scan because they are labeled OTGFS not USB.

Register 0x14 has a bit to reset the OTG_FS (as they like to call it).
Register 0x34 has a bit to enable the OTG_FS clock.
Register 0x54 has a bit to enable the OTG_FS clock in low power sleep mode.

The clock diagram shows a PLL48CK signal that is controlled by a gate. I have not yet found this control bit.

Registers

The memory map in section 2.3 of the RM shows the USB OTG FS registers at a base address of 0x5000_0000, as though the USB silicon is a special part of the silicon apart from the other registers. And perhaps it is. This is unlike the F103 which has a second address for the dedicated USB ram.

The reference manual information for the device mode registers is totally screwed up and a mass of contradictions. The only way to sort the mess out is to look at some reliable source code.

Give it a whirl

I put together a start at a register template, then run the code. I read the CID register and see the following:
USB cid 5000003C 00001200
The value of 0x1200 is what is expected, so I have the addressing correct and the clock turned on, which is a nice start.

After several hours studying registers, I was able to generate a USB interrupt. Doing this requires the following steps, many of which are the same for any on-chip device that needs to interrupt.

At this point the interrupt is fully armed (and may trigger immediately if it is already pending). I chose the MMIS interrupt (mode mismatch) as I can trigger it by any access to a host register. And I do trigger it by reading the host CSR register.

At this point code will enter a furious interrupt loop unless the interrupt handler does the appropriate thing do clear the interrupt. For the MMIS interrupt, the appropriate thing is to write a "1" to the MMIS bit in the USB interrupt status register. I do just that and now my test gives me a single message when I attempt a read from the host CSR register.

Note that many USB interrupts are cleared simply by reading the interrupt status register.

This concludes my first experiment with the STM32F411 USB hardware.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org