stm32/tinyusb: Add High-Speed USB support and fix CDC/VBUS issues.#18933
Conversation
|
Code size report: |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #18933 +/- ##
=======================================
Coverage 98.47% 98.47%
=======================================
Files 176 176
Lines 22831 22831
=======================================
Hits 22483 22483
Misses 348 348 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
That 4KB buffer size offers great performance. |
|
@kwagyeman yeah initially I thought there was something really wrong with my tests showing it as way too fast for a board without the ULPI - I didn't actually realize the N6 has HS built in! maybe it's not so bad once you figure out how to program it... |
4c3e95f to
1e59002
Compare
|
@andrewleech - I added this to our work queue list. |
|
I ended up with some "general tinyusb correctness" commits in here too that aren't strictly related to HS support, I can split them into separate PR's if preferred though testing worked better with them altogether |
dpgeorge
left a comment
There was a problem hiding this comment.
This looks good, thanks!
Just a comment about putting the config elsewhere in stm32.
|
|
||
| #if !defined(CFG_TUSB_RHPORT0_MODE) && !defined(CFG_TUSB_RHPORT1_MODE) | ||
| #define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE) | ||
| // Configure RHPORT modes based on board USB PHY configuration. |
There was a problem hiding this comment.
This code is highly stm32 port specific. I think the way it should be handled is how alif and nrf ports do it: they have a custom tusb_config.h file that includes this common one, and overrides/adds additional config options as needed by the port.
To make that work, I think you need to remove the INC += -I$(TOP)/shared/tinyusb/ from stm32's Makefile.
Maybe put the new file in as ports/stm32/tinyusb_port/tusb_config.h following alif, then add INC += -Itinyusb_port to the Makefile.
There was a problem hiding this comment.
Done - moved to ports/stm32/tinyusb_port/tusb_config.h following the alif pattern. The shared file is restored to its original default.
|
FWIW I've been seeing plenty of errors on MacOS/M4, which eventually lead to a bus reset, which in turn leads to an assert in TinyUSB (due to race condition, I think). I was trying to figure out if it was our firmware causing this when I saw this PR. I could cherry-pick this and see if any fixes here fix the issue. Errors look like: This might have been a hub issue, I tested again yesterday and didn't see any errors. |
1e59002 to
a60b5c5
Compare
| * The MIT License (MIT) | ||
| * | ||
| * Copyright (c) 2022 Blake W. Garner | ||
| * Copyright (c) 2022 Ibrahim Abdelkader <iabdalkader@openmv.io> |
There was a problem hiding this comment.
Who is Blake Garner??
I think this copyright can just be your name.
There was a problem hiding this comment.
Fixed, sorry about that. The AI tool fabricated the name rather than looking up the actual author. Copyright is now correct.
I've got a "private review" workflow for code reviewing via draft prs on my fork before pushing upstream which has helped me catch most of these weird issues, but follow up changes on an existing PR don't have that workflow. I'll have to figure out a better phone-based review workflow sorry.
There was a problem hiding this comment.
Andrew's secret alias, revealed!
There was a problem hiding this comment.
I engineered a solution for myself: https://github.com/andrewleech/serve-review
| IRQ_ENTER(USB1_OTG_HS_IRQn); | ||
| #if MICROPY_HW_TINYUSB_STACK | ||
| tud_int_handler(0); | ||
| tud_int_handler(TUD_OPT_RHPORT); |
There was a problem hiding this comment.
I think this file is missing USB2_OTG_HS_IRQHandler *for N6
There was a problem hiding this comment.
Actually, this should just be:
void USB1_OTG_HS_IRQHandler(void) {
#if MICROPY_HW_TINYUSB_STACK
tud_int_handler(0);
void USB2_OTG_HS_IRQHandler(void) {
#if MICROPY_HW_TINYUSB_STACK
tud_int_handler(1);There was a problem hiding this comment.
Added USB2_OTG_HS_IRQHandler with hardcoded rhport 1, and changed USB1 to hardcoded 0. Also kept TUD_OPT_RHPORT for the non-N6 OTG_HS_IRQHandler since F4/F7/H7 only have one HS controller.
There was a problem hiding this comment.
Updated - I've removed USB2_OTG_HS_IRQHandler again on reflection. USB2_OTG_HS_IRQn is never enabled in usbd_conf.c for N6 and TinyUSB is configured with RHPORT0, so dispatching to tud_int_handler(1) would hit an uninitialised port. If N6 boards need USB2 with TinyUSB then usbd_conf.c would need to initialise RHPORT1 too, at which point the handler belongs alongside that work. Happy to re-add it if there's a specific N6 config I'm missing.
105a90a to
2fae783
Compare
projectgus
left a comment
There was a problem hiding this comment.
Hi @andrewleech,
Thanks for implementing this! I have some minor comments, but overall it looks good to me.
Some of the USB class drivers may need some additional optimisation now we're up against 480Mbps line rates. 😁
2e5b8dc to
f6345b7
Compare
projectgus
left a comment
There was a problem hiding this comment.
Changes look good to me, thanks @andrewleech!
Implements mapping from MICROPY_HW_USB_MAIN_DEV to TinyUSB RHPORT configuration, enabling board-specific USB PHY selection for TinyUSB stack. Adds support for HS-in-FS mode (High Speed controller running at Full Speed) which is the default for STM32 boards without external ULPI PHY. Thi STM32F4/F7/H7 high-speed RHPORT mode selection is placed in ports/stm32/tinyusb_port/tusb_config.h, following the alif/nrf pattern. Includes py/mpconfig.h to ensure board config macros are available when TinyUSB processes the header. Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
When a host closes and reopens the CDC serial port, the IN endpoint may remain stalled from a prior runtime USB disconnect (e.g. mpremote connect/disconnect cycles). Clear the stall on DTR high so the connection recovers without requiring a device reset. On DTR low (host close), flush the TX FIFO so stale data does not accumulate and block writes on the next connection. Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
The TinyUSB serial descriptor used a raw hex dump of all 12 UID bytes in sequential order (24-char lowercase), while the legacy USB stack and ST's onboard DFU bootloader use a condensed algorithm that selects 6 bytes with two additions (12-char uppercase). This mismatch caused the device to report a different serial number depending on which USB stack was active, breaking tools that identify devices by serial (e.g. udev rules, mpremote, dfu-util). Use the ST DFU bootloader algorithm for consistency. Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
Removes the need for -I$(TOP)/shared/tinyusb/ in the stm32 Makefile by using an explicit path in the two files that include mp_usbd.h outside of the shared/tinyusb/ directory itself. Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
f6345b7 to
d2e0d20
Compare
Summary
The STM32 port's TinyUSB integration only supports the FS controller. Boards with a HS controller (PYBD_SF6, STM32F429DISC, OLIMEX_H407, or ULPI-based designs) cannot use TinyUSB — the RHPORT configuration is hardcoded to RHPORT 0 / full-speed only.
This PR adds proper RHPORT mode selection in
tusb_config.hbased onMICROPY_HW_USB_HSandMICROPY_HW_USB_HS_IN_FSboard config, routes HS IRQ handlers to the correct RHPORT (including STM32N6 which maps HS to RHPORT 0), and adds VBUS sensing configuration for the HS-in-FS path on STM32F4/F7 (mirroring the existing FS path, with support for both VBDEN and legacy NOVBUSSENS register variants).Additional issues found and fixed during testing (each is a separate commit and can be split into its own PR if preferred):
CDC reconnect stall: When a host closes and reopens the CDC serial port (e.g. repeated mpremote connect/disconnect cycles), the IN endpoint can remain stalled from a prior runtime USB disconnect. The device becomes unresponsive until reset. Fixed by clearing endpoint stall on DTR high. Additionally, on DTR low (host close) the TX FIFO is now flushed so stale data from a previous session does not accumulate and block writes on the next connection.
DFU bootloader serial number mismatch: The TinyUSB serial descriptor uses a raw hex dump of all 12 UID bytes (24-char lowercase), while the legacy USB stack and ST's onboard DFU bootloader use a condensed algorithm that selects 6 bytes with two additions (12-char uppercase). This causes the device to report a different serial number depending on which USB stack is active, breaking tools that identify devices by serial (udev rules, mpremote, dfu-util). Fixed by using the ST DFU bootloader algorithm.
TinyUSB-specific boot.py template: The factory reset boot.py template references
pyb.usb_mode()which does not exist on the TinyUSB stack. A TinyUSB-specific template is added that usesmachine.USBDevicewithBUILTIN_DEFAULT.Testing
Built with
CFLAGS_EXTRA=-DMICROPY_HW_TINYUSB_STACK=1for:machine.USBDeviceAPI, filesystem accessmachine.USBDeviceAPI, filesystem accessULPI boards (STM32H747I_DISCO) are tested on hardware as part of the original development in #18303 — this branch is split out from that work.
CDC serial throughput (OPENMV_N6, HS link at 480 Mbit/s)
Compared TinyUSB vs legacy USB stack using
tests/serial_test.pymethodology.Read (device → host):
Write (host → device):
TinyUSB read is 6-12x faster. Write is 2.5-4.5x slower due to a pre-existing limitation in the TinyUSB CDC stdin path —
mp_hal_stdin_rx_chr()reads byte-by-byte through a 512-byte ringbuffer, causing backpressure on the USB OUT endpoint. This affects all TinyUSB ports, not just HS, and is being tracked separately.Trade-offs and Alternatives
The RHPORT configuration uses
#ifndefguards so boards like STM32N6 that pre-defineCFG_TUSB_RHPORT0_MODEinmpconfigboard_common.hpass through unchanged. This avoids needing per-family#ifchains but means any future HS-capable family (e.g. STM32U5) needs its own board-level override.