Starting a series on USB Device on STM32
A journey through USB knowledge, from theory to a real project on STM32G0: from protocol fundamentals to a working composite device firmware.
Introduction
When learning USB Device on STM32, the fastest path is usually to grab an example off the internet and paste it into your own project. That gets you a working starting point quickly, but it also creates a trap for beginners. Working backward from a working example creates a real problem. The moment Windows doesn’t recognize your device, you have no idea where to even start looking. Or you hit a wall the first time you need to add a feature that isn’t in any sample code. The problem is that behind that sample lies a whole layer of dense knowledge: enumeration, descriptors, transfer types, endpoints, and more.
This series starts from the USB protocol foundation: understanding the host-centric model, explaining the four transfer types and what each one is actually for, and covering what a descriptor is and how each field shapes the device’s real-world behavior.
Once that foundation is solid, the series moves into building a complete USB device firmware for a computer keyboard: from real keypad input, through HID reports, descriptors, a CDC log channel, vendor requests, bulk dumps, all the way to a Python GUI tool for talking to and configuring the firmware.
Who this series is for
This series is for anyone who’s touched USB on STM32 by copy-pasting a sample and still doesn’t quite understand what’s happening underneath. If you’re hitting USB firmware bugs on STM32 and don’t know where to start debugging, or you want enough confidence to design a composite device from scratch, this content should be useful to you.
Every example in this series runs on an STM32G0B1RE, focused on USB Device Full Speed and the most common classes: CDC, HID, and composite devices. Along the way I’ll also point to a few free tools that make USB device development easier, in case they’re useful to you too.
This series does not cover USB Audio, Video, or Mass Storage, doesn’t touch USB Host or OTG mode, and doesn’t go deep into the electrical signaling layer. If you need those topics, the foundational knowledge here still applies, but the implementation will look quite different.
Topics like pull-up resistors, VBUS detection, or PCB layout may come up when relevant, but they’re not the focus.
Suggested reading order
Here’s the roadmap for the series:
| Post | Content |
|---|---|
| 2 - USB Transfer Types | The host-centric model and the four transfer types |
| 3 - USB Descriptor | How the host identifies a device |
| 4 - Key Input Pipeline | From GPIO to key events, producing clean input before USB gets involved |
| 5 - HID Keyboard Baseline | A real keyboard, from keypress to host-side output |
| 6 - CDC Debug Channel | Adding a second interface to watch logs over USB without a debugger |
| 7 - Vendor Request and Bulk | Custom commands and reading large blocks of data over USB |
| 8 - Composite Debug Tool | The host-side tool for talking to the firmware |
A bit more detail:
- Post 2 is foundational theory on how USB actually works, meant to explain the why, not just the how.
- Post 3 covers how the host identifies a device, which is the groundwork you need before touching the protocol layer of a real implementation.
- Post 4 covers the keyboard’s physical input handling, entirely separate from USB. You can skim it if you only care about USB, though the first few sections of post 5 do reuse terminology and structures introduced there.
- Posts 5 through 8 should be read in order, since each one builds directly on the previous one’s result. Together they trace the full development of a USB device firmware, from design to code to test.
Companion projects
To go along with the series, I’ve put together a few hands-on project write-ups. They record the actual build process along with real measurements, so you have something to compare against when building your own and a clearer picture of how USB really behaves on the STM32G0. Here’s the list of projects in this series:
- STM32G0 USB Lab: Key Input Pipeline - the keypad circuit, scanning, and key handling (post 4)
- STM32G0 USB Lab: Composite Device - USB firmware built up step by step from a single HID class to a full composite device (posts 3, 5, 6, 7)
- STM32G0 USB Lab: Host Debug Tool - the Python tool on the computer side (posts 7, 8)
All three projects live in one GitHub repo so you can follow along easily: stm32g0-usb-device-lab. Each development step is its own tagged commit with its own log and evidence, so you can jump back to the exact firmware state at that point, or build it yourself and compare results.
About this series
The content here is pulled together from the official USB specification, ST’s middleware documentation, and hands-on experience building USB Device firmware on the STM32G0B1RE for a POS system. Every technical figure in this series is backed by real evidence. Nothing here is a rough estimate or a number derived purely from theory.
The code in this series was written for learning purposes, not as a production-ready firmware for a commercial product. Some features or logic may not be as optimized or as fully handled as they would be in a real product, but they’re solid enough to illustrate the concepts and problems covered in each post.
I’ve tried to stay close to real practical problems rather than just paraphrasing the spec, but there may still be gaps or mistakes here and there. If you finish reading and have a question, spot an error, or just want to give feedback, feel free to email me at:
I’ll read it and try to get back to you as soon as I can.
Found this article useful?
Share, give feedback, or support if you find this content valuable.