You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add STM32WB55 support and implement reliable cross-family software DFU entry
This update introduces STM32WB55 support and significantly improves software DFU reliability across supported STM32 families.
Added
STM32WB55 support via Nucleo-64 board definitions (e.g. NUCLEO WB55 USB Dongle, P-NUCLEO-WB55)
dfu_boot_stm32wb.c to ensure reliable DFU entry on WB55
Extended STM32G4 testing (WeAct STM32G474)
Improved
Reworked software DFU entry for more consistent behaviour
Added required boards.txt modifications for each supported MCU family
STM32WB55 Notes
Generic WBxx board variants (e.g. Generic WB55CGUx) lack a SystemClock_Config implementation in the STM32 Arduino core. Without proper PLLSAI1Q configuration, the USB peripheral does not receive a valid 48 MHz clock and will fail to enumerate.
As a workaround, TinyUSB is enabled for Nucleo-64 WB55 board definitions, which include a valid USB clock configuration. This also enables TinyUSB on most Nucleo-64 boards using F1/F4/G4 MCUs, although the TinyUSB option may appear for unsupported boards due to this approach.
A proper long-term solution would be adding a generic_clock.c implementation to the generic WB55 variant in the STM32 Arduino core.
DFU Implementation Details
On STM32F1/F4/G4, DFU entry is achieved by disabling interrupts, resetting clocks, remapping system memory, and jumping directly to the bootloader.
On STM32WB55, this approach is unreliable because the bootloader is sensitive to residual peripheral and clock state. Jumping directly from a running sketch can prevent USB DFU from enumerating.
The new WB55 implementation:
Writes a magic value to RTC backup register BKP0R
Triggers NVIC_SystemReset()
Intercepts reset early via a Reset_Handler override
Jumps to the bootloader in a near-clean reset state
Falls through to normal startup when the magic value is absent
This ensures reliable DFU entry while leaving normal boot behaviour unaffected.
- STM32WB55 support, tested on WeAct STM32WB55CGU6 using P-NUCLEO-WB55 / NUCLEO WB55 USB Dongle board definition
7
+
- Nucleo-64 board definition support — most F1/F4/G4 Nucleo-64 variants should work as a side effect
8
+
-`dfu_boot_stm32wb.c` — WB55-specific `Reset_Handler` override for reliable DFU bootloader entry
9
+
- WeAct STM32G474 confirmed working
10
+
- WeAct STM32F405 confirmed working
11
+
12
+
### Changed
13
+
- DFU bootloader entry completely overhauled — previous implementation was not reliable
14
+
- F1/F4/G4: now uses direct jump to ST ROM bootloader after disabling interrupts and resetting clocks
15
+
- WB55: uses magic value in `BKP0R` + `NVIC_SystemReset()`, intercepted by `Reset_Handler` override before `SystemInit()` runs
16
+
-`boards.txt` entries now require four lines per board (two additional lines for `use_1200bps_touch` and `wait_for_upload_port` to enable Arduino IDE auto-upload)
17
+
-`boards_txt_additions.txt` updated to reflect new four-line format and added Nucleo_64 entry
18
+
19
+
### Known Limitations
20
+
- Generic WB55 board definitions lack USB clock configuration and are not supported — use P-NUCLEO-WB55 or NUCLEO WB55 USB Dongle board definition instead. Proper generic support requires adding a clock configuration (PLLSAI1Q 48 MHz USB clock) to the generic WB55 variant in the STM32duino core.
21
+
- STM32F1 DFU entry requires further validation on boards with factory bootloader.
22
+
23
+
---
24
+
25
+
## [v0.2.0] - 2026-02-21
26
+
27
+
### Added
28
+
- STM32F1 support, tested on STM32F103 BluePill
29
+
- STM32F4 support, tested on WeAct STM32F411 BlackPill
30
+
- STM32G4 support, tested on WeAct STM32G431
31
+
- Automatic USB initialisation via `initVariant()` — no sketch boilerplate required
32
+
- Automatic task polling via `HAL_IncTick()` override and `serialEventRun()` hook
33
+
-`Serial` automatically aliased to `SerialTinyUSB`
34
+
- DFU bootloader entry via "touch 1200" auto-reset
35
+
-`TinyUSB_Port_GetSerialNumber()` using factory UID registers for all families
36
+
37
+
38
+
## [v0.1.1] - 2026-01-25
39
+
### Fixed
40
+
- Added missing redirect of `Serial` to `TinyUSBSerial`
41
+
42
+
## [v0.1.0] - 2026-01-25
43
+
44
+
### Added
45
+
- Initial version with STM32F4 support, tested on WeAct STM32F411 BlackPill
> **Note:** An earlier version of this port is integrated into the official Adafruit TinyUSB library. I will submit the updated version once it is ready and hopefully get the changes made in the stm32 core files so that manual editing of boards.txt is not required.
3
+
> **Note:** An earlier version of this port with partial support for the F4 family is integrated into the official Adafruit TinyUSB library. I will submit the updated version once it is ready and hopefully get the changes made in the stm32 core files so that manual editing of boards.txt is not required.
4
4
5
-
This port adds STM32F1, STM32F4, and STM32G4 support to the [Adafruit TinyUSB Arduino Library](https://github.com/adafruit/Adafruit_TinyUSB_Arduino), enabling advanced USB device functionality (MIDI, HID, MSC, CDC, etc.) on STM32 microcontrollers.
5
+
This port adds STM32F1, STM32F4, STM32G4, and STM32WB55 support to the [Adafruit TinyUSB Arduino Library](https://github.com/adafruit/Adafruit_TinyUSB_Arduino), enabling advanced USB device functionality (MIDI, HID, MSC, CDC, etc.) on STM32 microcontrollers.
6
6
7
-
## What's New
7
+
## Overview
8
8
9
-
Whilst this port should still be considered experimental, it is now a lot more fleshed out than previous versions:
9
+
The Adafruit TinyUSB library includes an initial verion of this STM32 port, currently listed as experimental. This repository extends that work — adding support for additional STM32 families, fully automatic USB initialisation and task polling, and reliable DFU bootloader entry, with no boilerplate required in your sketch. `Serial`is automatically aliased to `SerialTinyUSB`. The goal is that sketches written for officially supported cores like RP2040 and SAMD should work on STM32 without modification.
10
10
11
-
```cpp
12
-
// Previously required in setup():
13
-
if (!TinyUSBDevice.isInitialized()) { TinyUSBDevice.begin(0); }
14
-
if (TinyUSBDevice.mounted()) { TinyUSBDevice.detach(); delay(10); TinyUSBDevice.attach(); }
15
-
16
-
// Previously required in loop():
17
-
#ifdef TINYUSB_NEED_POLLING_TASK
18
-
TinyUSBDevice.task();
19
-
#endif
20
-
```
21
-
22
-
This version eliminates all of that. USB initialisation, task polling, CDC flushing, and DFU bootloader entry are all handled automatically — sketches work the same way as on officially supported cores like RP2040 and SAMD. `Serial` is now also automatically aliased to `SerialTinyUSB`, so no `#define` is needed in your sketch, `Serial` commands work like they should. And most importantly no need to press the BOOT and RESET buttons when uploading anymore!
23
-
24
-
Support has been added and tested for three STM32 families: **F1**, **F4**, and **G4**.
11
+
Support has been tested across four STM32 families: **F1**, **F4**, **G4**, and **WB55**. See the [Changelog](CHANGELOG.md) for the full history of what's been added and changed.
- **STM32F4 series:** F401, F405, F407, F446 and other F4xx variants — same OTG_FS peripheral
26
+
-**STM32F4 series:** F401, F407, F446 and other F4xx variants — same OTG_FS peripheral
37
27
-**STM32F1 series:** Other F103 variants — same USB peripheral
38
-
- **STM32G4 series:** G474, G491, G4A1 — same USB peripheral
28
+
-**STM32G4 series:** G491, G4A1 — same USB peripheral
29
+
-**STM32WB55 series:** Other WB55 variants with 32MHz HSE crystal using Nucleo board definition
30
+
-**Nucleo-64 boards:** Most F1/F4/G4 Nucleo-64 variants should work via the Nucleo_64 board definition
39
31
40
-
### Not Supported (yet)
32
+
### Not Supported
41
33
- STM32F0, F2, F3 — different USB peripheral architecture
42
34
- STM32L, STM32H7 — would need clock configuration changes
35
+
- Generic WB55 board definitions — see Known Limitations
43
36
44
37
**If you test on other boards, please report your results!**
45
38
@@ -55,12 +48,12 @@ Support has been added and tested for three STM32 families: **F1**, **F4**, and
55
48
56
49
## How It Works
57
50
58
-
The port implements the three hooks required by the STM32 Arduino core to integrate TinyUSB as a first-class citizen. `initVariant()` is called automatically before `setup()` and handles all USB hardware and stack initialisation. `HAL_IncTick()` is overridden to signal every 1ms SysTick tick, which `yield()` and `serialEventRun()` use to service the TinyUSB task in thread context — ensuring USB events are processed reliably regardless of what the sketch is doing. `TinyUSB_Port_EnterDFU()` handles the Arduino IDE's "touch 1200" auto-reset by disconnecting from USB cleanly, writing the STM32duino bootloadermagic value to a backup register, and issuing a system reset.
51
+
The port implements the hooks required by the STM32 Arduino core to integrate TinyUSB as a first-class citizen. `initVariant()` is called automatically before `setup()` and handles all USB hardware and stack initialisation. `HAL_IncTick()` is overridden to signal every 1ms SysTick tick, which `yield()` and `serialEventRun()` use to service the TinyUSB task in thread context — ensuring USB events are processed reliably regardless of what the sketch is doing. DFU bootloader entry is triggered by the Arduino IDE's "touch 1200" sequence: on F1/F4/G4 the port disables interrupts, resets clocks, and jumps directly to the ST ROM bootloader; on WB55 a magic value is written to a backup register and the chip resets, with a `Reset_Handler` override intercepting the reboot before `SystemInit()` runs to jump to the bootloader from a near-clean state.
Find your board's section and add a TinyUSB USB menu entry. The board identifier prefix (e.g. `GenF4`, `GenF1`, `GenG4`) must match the one already used in that board's section. I have included the lines you need to add in `boards_txt_additions.txt` for ease of use. Examples for each family:
Refer to `boards_txt_additions.txt` (included in this repository) for the exact lines to add and instructions on finding the right prefix for your board. Each board entry now requires four lines — two to enable TinyUSB and two to enable "touch 1200" DFU upload.
Close and reopen Arduino IDE for changes to take effect.
130
79
131
-
### Step 6: Select TinyUSB
80
+
### Step 5: Select TinyUSB
132
81
In Arduino IDE, go to **Tools > USB** and select **"Adafruit TinyUSB"**.
133
82
134
83
## Usage
135
84
136
-
Sketches require no USB initialisation boilerplate. `Serial` works normally. Here is a minimal CDC echo example — the entire sketch is just application code:
137
-
138
-
```cpp
139
-
#include<Adafruit_TinyUSB.h>
140
-
141
-
voidsetup() {
142
-
Serial.begin(115200);
143
-
// optional delay
144
-
while (!TinyUSBDevice.mounted()) delay(1);
145
-
Serial.println("Hello from STM32!");
146
-
}
147
-
148
-
voidloop() {
149
-
if (Serial.available()) {
150
-
Serial.write(Serial.read());
151
-
}
152
-
}
153
-
```
154
-
155
-
> **Note:**`while (!TinyUSBDevice.mounted()) delay(1)` is entirely optional but useful if your sketch needs to send data immediately on startup. It works correctly because `tud_task()` is serviced inside `delay()`.
85
+
Sketches require no USB initialisation boilerplate. `Serial` works normally.
156
86
157
87
## File Descriptions
158
88
159
-
-**`Adafruit_TinyUSB_stm32.cpp`** — Hardware initialisation, IRQ handlers, automatic task polling, and DFU bootloader entry for F1, F4, and G4 families
89
+
-**`Adafruit_TinyUSB_stm32.cpp`** — Hardware initialisation, IRQ handlers, automatic task polling, and DFU bootloader entry for F1, F4, G4, and WB55 families
160
90
-**`tusb_config_stm32.h`** — TinyUSB configuration and class enable flags for STM32
91
+
-**`dfu_boot_stm32wb.c`** — WB55-specific Reset_Handler override for reliable DFU bootloader entry
92
+
-**`boards_txt_additions.txt`** — Reference file with the lines to add to the STM32duino core's `boards.txt`
161
93
162
94
## Known Limitations
163
-
- Only the F1, F4, and G4 families are currently supported — see compatibility table above
164
-
- Requires the official STM32duino core — other STM32 cores are untested
165
-
- DFU bootloader entry requires that your board's upload method in Arduino board settings is configured to use STM32CubeProgrammer in DFU mode
95
+
- Generic WB55 board definitions (e.g. Generic WB55CGUx) are not supported — these variants lack a `SystemClock_Config` implementation in the STM32duino core, so the USB peripheral never receives a valid 48MHz clock. Use the **P-NUCLEO-WB55** or **NUCLEO WB55 USB Dongle** board definition instead. Custom WB55 boards with a 32MHz HSE crystal should also work with these definitions. A proper fix would require a `generic_clock.c` to be added to the generic WB55 variant in the STM32duino core upstream — this may be raised as a separate issue or PR.
96
+
- The "Adafruit TinyUSB" option will appear in the IDE USB menu for unsupported Nucleo-64 variants — this is a side effect of the WB55 workaround.
97
+
- Requires the official STM32duino core — other STM32 cores are untested.
98
+
- DFU bootloader entry requires that your board's upload method is configured to use STM32CubeProgrammer in DFU mode.
166
99
167
100
## Troubleshooting
168
101
169
102
**Device not enumerating / "USB device malfunctioned":**
170
103
- Verify you selected "Adafruit TinyUSB" from Tools > USB
171
-
- Check that USB D+ and D- pins on your board are not used for other purposes
172
-
- Try a different USB cable (or plugging directly into the PC if you are using a hub)
173
-
- On G4 boards, ensure no other USB stack (e.g. the STM32duino built-in CDC) is also enabled
104
+
- Check that D− and D+ pins on your board are not used for other purposes
105
+
- Try a different USB cable (some cables are charge-only)
106
+
- On WB55, ensure you are using the P-NUCLEO-WB55 or NUCLEO WB55 USB Dongle board definition, not a generic WB55 variant
174
107
175
108
**Compilation errors:**
176
-
- Confirm the Adafruit TinyUSB library is installed via Library Manager
109
+
- Confirm the latest version of Adafruit TinyUSB library is installed via Library Manager
177
110
- Make sure USB support in board setting is set to `Adafruit TinyUSB`
178
111
- Restart Arduino IDE after making changes to `tusb_config.h` or `boards.txt`
179
112
- Verify the `stm32` folder is in the correct location under `ports/`
113
+
- Verify `U(S)ART Support` in board options is set to `Enabled (generic 'serial')`
180
114
181
115
**"Touch 1200" / DFU upload not working:**
116
+
- Confirm all four lines are present in `boards.txt` for your board (see `boards_txt_additions.txt`)
182
117
- Confirm your board's upload method is set to STM32CubeProgrammer (DFU)
183
118
- Check that the correct DFU drivers are installed on your system (use [Zadig](https://zadig.akeo.ie/) on Windows if needed)
119
+
- One sketch must be uploaded using manual DFU (or other method) once the port is installed in order to enable the automated DFU push
184
120
185
121
## Contributing
186
122
Issues and pull requests welcome! If you test this on other STM32 boards or families, please report your results.
@@ -189,10 +125,9 @@ Issues and pull requests welcome! If you test this on other STM32 boards or fami
189
125
190
126
Want support for a board or STM32 family not listed here? I'm happy to add it, but I can't afford to buy every STM32 dev board out there. If you send me the board (or cover the cost of it), I'll add support and test it properly.
191
127
192
-
Get in touch via Ko-fi — use the Commissions feature to describe what you need:
0 commit comments