Skip to content

Commit 9fc837f

Browse files
committed
Major functionality update
Added support for F4 and G4 boards. Serial aliased to SerialTinyUSB. USB initialisation, task polling, CDC flushing, and DFU bootloader entry added. added .txt file with board info to paste to boards.txt
1 parent 8eb026d commit 9fc837f

4 files changed

Lines changed: 423 additions & 115 deletions

File tree

README.md

Lines changed: 102 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,61 @@
11
# TinyUSB for STM32 (Arduino)
22

3-
This port adds STM32F4 support to the [Adafruit TinyUSB Arduino Library](https://github.com/adafruit/Adafruit_TinyUSB_Arduino), enabling advanced USB device functionality (MIDI, HID, MSC, etc.) on STM32 microcontrollers.
3+
> **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.
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.
6+
7+
## What's New
8+
9+
Whilst this port should still be considered experimental, it is now a lot more fleshed out than previous versions:
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**.
425
526
## Compatibility
627
728
### Tested and Working
8-
- STM32F411 BlackPill (WeAct Studio)
29+
| Board | MCU | Family |
30+
|---|---|---|
31+
| WeAct STM32F411 BlackPill | STM32F411 | F4 |
32+
| STM32F103 BluePill | STM32F103 | F1 |
33+
| WeAct STM32G431 | STM32G431 | G4 |
934
10-
### Should Work (but untested)
11-
- Other STM32F4 series (F401, F405, F407, F446, etc.) - uses same USB peripheral
12-
- STM32F7 series - similar OTG_FS peripheral
35+
### Should Work (untested)
36+
- **STM32F4 series:** F401, F405, F407, F446 and other F4xx variants — same OTG_FS peripheral
37+
- **STM32F1 series:** Other F103 variants — same USB peripheral
38+
- **STM32G4 series:** G474, G491, G4A1 — same USB peripheral
1339
14-
### Won't Work Without Modification
15-
- STM32F0, F1, F3 series - different USB peripheral architecture
16-
- STM32L series - may need different configuration
17-
- STM32H7 - may need clock configuration changes
40+
### Not Supported (yet)
41+
- STM32F0, F2, F3 — different USB peripheral architecture
42+
- STM32L, STM32H7 — would need clock configuration changes
1843
1944
**If you test on other boards, please report your results!**
2045
2146
## Features
2247
- ✅ USB MIDI
2348
- ✅ USB CDC (Virtual Serial Port)
24-
- ✅ USB HID (Keyboard/Mouse/Gamepad)
49+
- ✅ USB HID (Keyboard / Mouse / Gamepad)
2550
- ✅ USB MSC (Mass Storage)
2651
- ✅ Multiple USB classes simultaneously
52+
- ✅ No sketch boilerplate — USB initialises and polls automatically
53+
- ✅ `Serial` works without any `#define` in your sketch
54+
- ✅ Arduino IDE "touch 1200" DFU bootloader entry
55+
56+
## How It Works
57+
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 bootloader magic value to a backup register, and issuing a system reset.
2759
2860
## Prerequisites
2961
1. [Arduino IDE](https://www.arduino.cc/en/software)
@@ -42,9 +74,8 @@ libraries/Adafruit_TinyUSB_Library/src/arduino/ports/
4274
```
4375
4476
### Step 3: Edit tusb_config.h
45-
Open `libraries/Adafruit_TinyUSB_Library/src/tusb_config.h`
77+
Open `Arduino/libraries/Adafruit_TinyUSB_Library/src/tusb_config.h` and find the platform detection block (around line 30–40):
4678
47-
Find the platform detection section (around line 30-40). You'll see a series of `#elif` statements like this:
4879
```cpp
4980
#if defined(ARDUINO_ARCH_SAMD)
5081
#include "arduino/ports/samd/tusb_config_samd.h"
@@ -61,121 +92,107 @@ Find the platform detection section (around line 30-40). You'll see a series of
6192
#endif
6293
```
6394

64-
**Add the following lines BEFORE the `#else` statement** (not after the `#endif`!):
65-
```cpp
66-
#elif defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32)
67-
#include "arduino/ports/stm32/tusb_config_stm32.h"
68-
```
95+
Add the following lines **before** the `#else`:
6996

70-
Your final code should look like this:
7197
```cpp
72-
#if defined(ARDUINO_ARCH_SAMD)
73-
#include "arduino/ports/samd/tusb_config_samd.h"
74-
#elif defined(ARDUINO_NRF52_ADAFRUIT)
75-
#include "arduino/ports/nrf/tusb_config_nrf.h"
76-
#elif defined(ARDUINO_ARCH_RP2040)
77-
#include "arduino/ports/rp2040/tusb_config_rp2040.h"
78-
#elif defined(ARDUINO_ARCH_ESP32)
79-
// do nothing since we force include "arduino/ports/esp32/tusb_config_esp32.h" in tusb_option.h
80-
#elif defined(ARDUINO_ARCH_CH32) || defined(CH32V20x) || defined(CH32V30x)
81-
#include "arduino/ports/ch32/tusb_config_ch32.h"
8298
#elif defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32)
8399
#include "arduino/ports/stm32/tusb_config_stm32.h"
84-
#else
85-
#error TinyUSB Arduino Library does not support your core yet
86-
#endif
87100
```
88101

89-
90102
### Step 4: Edit boards.txt
91-
Open your STM32 core's `boards.txt` file, typically located at:
103+
Open your STM32 core's `boards.txt`, typically at:
92104
```
93105
Arduino15/packages/STMicroelectronics/hardware/stm32/[version]/boards.txt
94106
```
95107

96-
Add these lines to your board configuration (example shown for Generic F4):
108+
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:
109+
110+
**STM32F4 (e.g. Generic F4):**
111+
```
112+
GenF4.menu.usb.TinyUSB=Adafruit TinyUSB
113+
GenF4.menu.usb.TinyUSB.build.usb_flags={build.extra_flags} -DARDUINO_ARCH_TINYUSB
114+
```
115+
116+
**STM32F1 (e.g. Generic F1):**
97117
```
98-
GenF4.menu.usb.TinyUSBMIDI=Adafruit TinyUSB
99-
GenF4.menu.usb.TinyUSBMIDI.build.usb_flags={build.extra_flags} -DARDUINO_ARCH_TINYUSB
118+
GenF1.menu.usb.TinyUSB=Adafruit TinyUSB
119+
GenF1.menu.usb.TinyUSB.build.usb_flags={build.extra_flags} -DARDUINO_ARCH_TINYUSB
100120
```
101121

102-
**Note:** Adjust `GenF4` to match your specific board identifier if different.
122+
**STM32G4 (e.g. Generic G4):**
123+
```
124+
GenG4.menu.usb.TinyUSB=Adafruit TinyUSB
125+
GenG4.menu.usb.TinyUSB.build.usb_flags={build.extra_flags} -DARDUINO_ARCH_TINYUSB
126+
```
103127

104128
### Step 5: Restart Arduino IDE
105129
Close and reopen Arduino IDE for changes to take effect.
106130

107131
### Step 6: Select TinyUSB
108-
In Arduino IDE, go to **Tools > USB** and select **"Adafruit TinyUSB"**
132+
In Arduino IDE, go to **Tools > USB** and select **"Adafruit TinyUSB"**.
133+
134+
## Usage
109135

110-
## Usage Example
136+
Sketches require no USB initialisation boilerplate. `Serial` works normally. Here is a minimal CDC echo example — the entire sketch is just application code:
111137

112-
Here's a simple USB MIDI example:
113138
```cpp
114-
#define Serial SerialTinyUSB //Alias to allow Serial Communication throguh TinyUSB
115139
#include <Adafruit_TinyUSB.h>
116-
#include <MIDI.h>
117-
118-
Adafruit_USBD_MIDI usb_midi;
119-
MIDI_CREATE_INSTANCE(Adafruit_USBD_MIDI, usb_midi, MIDI);
120140

121141
void setup() {
122-
if (!TinyUSBDevice.isInitialized()) {
123-
TinyUSBDevice.begin(0);
124-
}
125-
126-
usb_midi.setStringDescriptor("My STM32 MIDI Device");
127-
MIDI.begin(MIDI_CHANNEL_OMNI);
142+
Serial.begin(115200);
143+
// optional delay
144+
while (!TinyUSBDevice.mounted()) delay(1);
145+
Serial.println("Hello from STM32!");
128146
}
129147

130148
void loop() {
131-
MIDI.read();
132-
133-
// Send a MIDI note every second
134-
static uint32_t last_note = 0;
135-
if (millis() - last_note > 1000) {
136-
MIDI.sendNoteOn(60, 127, 1);
137-
delay(100);
138-
MIDI.sendNoteOff(60, 0, 1);
139-
last_note = millis();
149+
if (Serial.available()) {
150+
Serial.write(Serial.read());
140151
}
141152
}
142153
```
143154

144-
## Technical Details
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()`.
145156
146-
### Key Implementation Notes
147-
- **VBUS Sensing:** Disabled to allow proper enumeration on bus-powered devices
148-
- **USB Peripheral:** Uses STM32F4's OTG_FS controller
149-
- **IRQ Handler:** Forwards USB interrupts to TinyUSB stack
150-
- **Clock Configuration:** Assumes STM32duino core provides correct 48MHz USB clock
157+
## File Descriptions
151158

152-
### File Descriptions
153-
- **Adafruit_TinyUSB_stm32.cpp** - Platform-specific USB initialization and IRQ handling
154-
- **tusb_config_stm32.h** - TinyUSB configuration for STM32F4
159+
- **`Adafruit_TinyUSB_stm32.cpp`** — Hardware initialisation, IRQ handlers, automatic task polling, and DFU bootloader entry for F1, F4, and G4 families
160+
- **`tusb_config_stm32.h`** — TinyUSB configuration and class enable flags for STM32
155161

156162
## Known Limitations
157-
- Only tested on STM32F411 (other F4 variants should work but are untested)
158-
- Requires the official STM32duino core (other cores may not work)
159-
- DFU bootloader entry not yet implemented
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
160166

161167
## Troubleshooting
162168

163-
**Device not enumerating:**
164-
- Verify you selected "Adafruit TinyUSB" from Tools > USB menu
165-
- Check that USB D+ (PA12) and D- (PA11) pins are not being used for other purposes
166-
- Try a different USB cable (some cables are charge-only)
169+
**Device not enumerating / "USB device malfunctioned":**
170+
- 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
167174

168175
**Compilation errors:**
169-
- Make sure you installed the Adafruit TinyUSB library via Library Manager
170-
- Restart Arduino IDE after making the modifications
171-
- Verify file paths are correct
176+
- Confirm the Adafruit TinyUSB library is installed via Library Manager
177+
- Make sure USB support in board setting is set to `Adafruit TinyUSB`
178+
- Restart Arduino IDE after making changes to `tusb_config.h` or `boards.txt`
179+
- Verify the `stm32` folder is in the correct location under `ports/`
180+
181+
**"Touch 1200" / DFU upload not working:**
182+
- Confirm your board's upload method is set to STM32CubeProgrammer (DFU)
183+
- Check that the correct DFU drivers are installed on your system (use [Zadig](https://zadig.akeo.ie/) on Windows if needed)
172184

173185
## Contributing
174-
Issues and pull requests welcome! If you test this on other STM32F4 boards, please report your results.
186+
Issues and pull requests welcome! If you test this on other STM32 boards or families, please report your results.
175187

176-
## Credits
177-
- Based on the [Adafruit TinyUSB Arduino Library](https://github.com/adafruit/Adafruit_TinyUSB_Arduino)
178-
- Port structure inspired by existing CH32, SAMD, and RP2040 implementations
188+
## Hardware Support Requests
189+
190+
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+
192+
Get in touch via Ko-fi — use the Commissions feature to describe what you need:
193+
**[ko-fi.com/yourname](https://ko-fi.com/yourname)**
179194

180-
## License
181-
MIT License (same as TinyUSB and Adafruit TinyUSB Library)
195+
> ☕ General donations to keep the project going are also very welcome!
196+
197+
## Credits
198+
Based on the [Adafruit TinyUSB Arduino Library](https://github.com/adafruit/Adafruit_TinyUSB_Arduino).

0 commit comments

Comments
 (0)