October 29, 2023
ST's HAL and LL libraries (and their inclusion in the "CubeMX", etc. IDEs) are bloated, inefficient, convoluted disasters masquerading as official, vendor-vetted software.I find it gratifying to find someone else saying things like this about it.As "insane" as the current ST Cube/HAL/LL code is, the older "STM32_USB-FS-Device_Lib" is much worse. Again I invite readers to see for themselves, but basically the code defies attempts at static analysis.
Beyond this disaster of bad code, another disaster, at least as severe, lurks. This is the lack of good documentation. Many of the STM32 microcontrollers use a USB subsystem designed by Synopsys, and in many places refered to as the Designware USB controller. Any device that advertises "USB OTG" almost certainly uses the Designware controller. Documentation for this is unavailable to mere mortals. Hence if you want to write your own low level code, you will need to reverse engineer existing drivers (such as drivers with names like "dw_usb.c" in the linux sources). Here "dw" is short for "DesignWare". If you are working with OTG or USB 3.0, you are almost certainly working with the designware controller. But the STM32F103 has not stepped into this arena.
The STM32F103 has a USB-2.0 "full speed" (12 Mbps) controller that is device only. The section on this in RM0008 (the 1136 page reference manual) is section 23, from pages 622 to 651. This seems suspiciously short, but it may all be there in a mere 30 pages!
The datasheet shows the USB registers at 0x4000_5c00 and USB/CAN sram (512 bytes) at 0x4000_6000.
Now in 2023, there are at least 2 more civilized options for a USB library that are at least worth taking a look at:
The Papoon project (aka "not insane" USB) looks like nice code, but as it is C++ I doubt that I will ever do more than study it. It is strictly for the STM32F103.The Tiny USB project is more general, and is all good old C. It supports a long list of microcontrollers, including quite a few different STM32 variants and the RP2040.
I am much more likely to begin my foray into low level (bare metal) USB with the RP2040. This gives me simple and easy to run and study examples using TinyUSB. The bootrom uses TinyUSB and there is full source code for that. And there is very nice documentation.
As shipped, these devices do not support USB in any way. There are USB boot loaders available for these devices, and you can flash a USB boot loader into them (using OpenOCD or the serial loader). After doing this, you can then use the USB loader to load subsequent software. I have done this (see below) not because I actually want to use the USB loader, but so that I can study it as an example of USB programming.
The way I use the STM32 is to simply use OpenOCD and a STlink-V2 to load my software via the SWD interface and find that wonderful. The Arduino gang seems to like the USB approach.
Note that the Roger Clark bootloader might be a good information source for USB programming. Or maybe not -- it is based on the wretched ST/Cube USB drivers.I also have a book that has been on my shelf for years, "USB Complete, fourth edition" by Jan Axelson. This book is now out in a fifth edition. I find the book to be OK, with my main complaint being that he talks only about the Windows operating systems as a host. This is generally not a crucial issue and can just be ignored. The real problem with this book is that it never gets down and dirty and talks about the actual traffic on the wire. You can use this book for high level concepts, then go online for nitty gritty details:
The reference manual for the STM32F10x series discusses the USB hardware in section 23 on pages 625 to 657.
The datasheet says we get USB 2.0 at "full speed". The USB subsystem needs to be fed a 48 Mhz clock. Full speed is 12 Mb/s. Some USB 2.0 supports "high speed" at 480 Mb/s, but not this device. This is hardly an issue for the serial console I have in mind.
The word is that my old friend Wireshark can do this.
But consider that if we develop a "pure USB" console device, baud rates will be irrelevant and we won't be passing data through any kind of serial bottleneck as we do with a USB to serial gadget. Not that 115200 baud has ever proven to be any kind of limitation, but at "Full speed" we could be running at 12,000,000 baud - ignoring USB protocol overhead.
This helps to explain why wireshark does not show literal "on the wire" packet traffic. That sort of detail is completely hidden. The only way to see it would be to have some kind of hardware protocol analyzer, and I actually don't think that would serve any purpose for me anyway. It might be the sort of thing a person designing actual USB chips might need.
At the level we work at, we set up receive and transmit buffers for each endpoint, then wait for interrupts to inform us that data has been received or sent. The business of wrapping them up as USB transactions is taken care of by the USB silicon.
Tom's Computer Info / tom@mmto.org