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.

5 min read
Đọc bằng English Tiếng Việt
STM32 / Firmware cover

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:

PostContent
2 - USB Transfer TypesThe host-centric model and the four transfer types
3 - USB DescriptorHow the host identifies a device
4 - Key Input PipelineFrom GPIO to key events, producing clean input before USB gets involved
5 - HID Keyboard BaselineA real keyboard, from keypress to host-side output
6 - CDC Debug ChannelAdding a second interface to watch logs over USB without a debugger
7 - Vendor Request and BulkCustom commands and reading large blocks of data over USB
8 - Composite Debug ToolThe 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:

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:

✉️ contact@duonghao.dev.

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.

Feedback