summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Leech <andrew.leech@planetinnovation.com.au>2025-10-28 16:20:31 +1100
committerDamien George <damien@micropython.org>2025-10-31 10:52:11 +1100
commit9bb266e31162ba80ec06a6bc9a6b94b9cbafa9b2 (patch)
treee0260ed1414475c9d8659e831f357e079472c4dc
parent6b0e1c2701490260cb81bbe884f42a9c18bea020 (diff)
stm32/usb: Add support for using TinyUSB stack.
This commit adapts the stm32 port to allow switching from STM USB stack to TinyUSB stack. Using TinyUSB improves consistancy with other MicroPython ports and brings in the ability to use the runtime USB definition support recently added to other TinyUSB based ports. By default the existing STM USB stack is used. TinyUSB can be enabled in a board configuration with: #define MICROPY_HW_TINYUSB_STACK (1) Or, it can be enabled from the command line with: make -C ports/stm32 CFLAGS_EXTRA='-DMICROPY_HW_TINYUSB_STACK=1' Signed-off-by: Andrew Leech <andrew@alelec.net>
-rw-r--r--ports/stm32/Makefile22
-rw-r--r--ports/stm32/main.c21
-rw-r--r--ports/stm32/modmachine.c7
-rw-r--r--ports/stm32/modos.c6
-rw-r--r--ports/stm32/modpyb.c2
-rw-r--r--ports/stm32/mpconfigboard_common.h71
-rw-r--r--ports/stm32/mphalport.c28
-rw-r--r--ports/stm32/mphalport.h8
-rw-r--r--ports/stm32/stm32_it.c39
-rw-r--r--ports/stm32/usb.c4
-rw-r--r--ports/stm32/usbd.c42
-rw-r--r--ports/stm32/usbd_conf.c40
-rw-r--r--ports/stm32/usbd_conf.h4
-rwxr-xr-xtools/ci.sh2
14 files changed, 256 insertions, 40 deletions
diff --git a/ports/stm32/Makefile b/ports/stm32/Makefile
index 8b35c82a2..5105b35b1 100644
--- a/ports/stm32/Makefile
+++ b/ports/stm32/Makefile
@@ -58,7 +58,7 @@ MBOOT_TEXT0_ADDR ?= 0x08000000
include $(TOP)/py/py.mk
include $(TOP)/extmod/extmod.mk
-GIT_SUBMODULES += lib/libhydrogen lib/stm32lib
+GIT_SUBMODULES += lib/libhydrogen lib/stm32lib lib/tinyusb
CROSS_COMPILE ?= arm-none-eabi-
LD_DIR=boards
@@ -110,6 +110,8 @@ INC += -I$(STM32LIB_CMSIS_ABS)/Include
INC += -I$(STM32LIB_HAL_ABS)/Inc
INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/inc
#INC += -I$(USBHOST_DIR)
+INC += -I$(TOP)/lib/tinyusb/src
+INC += -I$(TOP)/shared/tinyusb/
INC += -Ilwip_inc
CFLAGS += $(INC) -Wall -Wpointer-arith -Werror -Wdouble-promotion -Wfloat-conversion -std=gnu99 -nostdlib $(CFLAGS_EXTRA)
@@ -213,6 +215,10 @@ SHARED_SRC_C += $(addprefix shared/,\
runtime/stdout_helpers.c \
runtime/sys_stdio_mphal.c \
timeutils/timeutils.c \
+ tinyusb/mp_usbd.c \
+ tinyusb/mp_usbd_cdc.c \
+ tinyusb/mp_usbd_descriptor.c \
+ tinyusb/mp_usbd_runtime.c \
)
ifeq ($(MICROPY_FLOAT_IMPL),double)
@@ -242,7 +248,9 @@ SRC_C += \
boardctrl.c \
main.c \
stm32_it.c \
+ usbd.c \
usbd_conf.c \
+ usb.c \
usbd_desc.c \
usbd_cdc_interface.c \
usbd_hid_interface.c \
@@ -277,7 +285,6 @@ SRC_C += \
can.c \
fdcan.c \
pyb_can.c \
- usb.c \
eth.c \
eth_phy.c \
gccollect.c \
@@ -460,6 +467,16 @@ USBDEV_SRC_C += $(addprefix $(USBDEV_DIR)/,\
class/src/usbd_msc_scsi.c \
)
+# TinyUSB Stack source
+-include $(TOP)/lib/tinyusb/src/tinyusb.mk
+TINYUSB_SRC_C := $(addprefix lib/tinyusb/, \
+ $(TINYUSB_SRC_C) \
+ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \
+ src/portable/synopsys/dwc2/dcd_dwc2.c \
+ src/portable/synopsys/dwc2/dwc2_common.c \
+ src/portable/synopsys/dwc2/hcd_dwc2.c \
+ )
+
ifeq ($(MICROPY_SSL_MBEDTLS),1)
LIB_SRC_C += mbedtls/mbedtls_port.c
endif
@@ -499,6 +516,7 @@ OBJ += $(addprefix $(BUILD)/, $(SHARED_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(HAL_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(USBDEV_SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(TINYUSB_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_CXX:.cpp=.o))
OBJ += $(GEN_PINS_SRC:.c=.o)
diff --git a/ports/stm32/main.c b/ports/stm32/main.c
index 1c59b6479..d56b4c407 100644
--- a/ports/stm32/main.c
+++ b/ports/stm32/main.c
@@ -88,6 +88,11 @@
#include "pyb_can.h"
#include "subghz.h"
+#if MICROPY_HW_TINYUSB_STACK
+#include "usbd_conf.h"
+#include "shared/tinyusb/mp_usbd.h"
+#endif
+
#if MICROPY_PY_THREAD
static pyb_thread_t pyb_thread_main;
#endif
@@ -275,14 +280,12 @@ static bool init_sdcard_fs(void) {
}
}
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_ENABLE_USB && !MICROPY_HW_TINYUSB_STACK
if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) {
// if no USB MSC medium is selected then use the SD card
pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_SDCARD;
}
- #endif
- #if MICROPY_HW_ENABLE_USB
// only use SD card as current directory if that's what the USB medium is
if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_SDCARD)
#endif
@@ -606,8 +609,13 @@ soft_reset:
#endif
#if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_TINYUSB_STACK
+ pyb_usbd_init();
+ mp_usbd_init();
+ #else
pyb_usb_init0();
#endif
+ #endif
#if MICROPY_PY_MACHINE_I2S
machine_i2s_init0();
@@ -631,7 +639,7 @@ soft_reset:
}
#endif
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_STM_USB_STACK
// if the SD card isn't used as the USB MSC medium then use the internal flash
if (pyb_usb_storage_medium == PYB_USB_STORAGE_MEDIUM_NONE) {
pyb_usb_storage_medium = PYB_USB_STORAGE_MEDIUM_FLASH;
@@ -665,7 +673,7 @@ soft_reset:
// or whose initialisation can be safely deferred until after running
// boot.py.
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_STM_USB_STACK
// init USB device to default setting if it was not already configured
if (!(pyb_usb_flags & PYB_USB_FLAG_USB_MODE_CALLED)) {
#if MICROPY_HW_USB_MSC
@@ -770,6 +778,9 @@ soft_reset_exit:
#else
MP_STATE_PORT(pyb_stdio_uart) = NULL;
#endif
+ #if MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE && MICROPY_HW_TINYUSB_STACK
+ mp_usbd_deinit();
+ #endif
MICROPY_BOARD_END_SOFT_RESET(&state);
diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c
index 8123cd801..c1ac6e086 100644
--- a/ports/stm32/modmachine.c
+++ b/ports/stm32/modmachine.c
@@ -47,6 +47,7 @@
#include "rtc.h"
#include "i2c.h"
#include "spi.h"
+#include "shared/tinyusb/mp_usbd.h"
#if defined(STM32G0)
// G0 has BOR and POR combined
@@ -297,9 +298,13 @@ MP_NORETURN static void mp_machine_reset(void) {
// Activate the bootloader without BOOT* pins.
MP_NORETURN void mp_machine_bootloader(size_t n_args, const mp_obj_t *args) {
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_STM_USB_STACK
pyb_usb_dev_deinit();
#endif
+ #if MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE && MICROPY_HW_TINYUSB_STACK
+ mp_usbd_deinit();
+ #endif
+
#if MICROPY_HW_ENABLE_STORAGE
storage_flush();
#endif
diff --git a/ports/stm32/modos.c b/ports/stm32/modos.c
index 7949cf87c..cd918fe71 100644
--- a/ports/stm32/modos.c
+++ b/ports/stm32/modos.c
@@ -52,7 +52,7 @@ bool mp_os_dupterm_is_builtin_stream(mp_const_obj_t stream) {
#if MICROPY_PY_MACHINE_UART
|| type == &machine_uart_type
#endif
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_STM_USB_STACK
|| type == &pyb_usb_vcp_type
#endif
;
@@ -64,7 +64,7 @@ void mp_os_dupterm_stream_detached_attached(mp_obj_t stream_detached, mp_obj_t s
uart_attach_to_repl(MP_OBJ_TO_PTR(stream_detached), false);
}
#endif
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_STM_USB_STACK
if (mp_obj_get_type(stream_detached) == &pyb_usb_vcp_type) {
usb_vcp_attach_to_repl(MP_OBJ_TO_PTR(stream_detached), false);
}
@@ -75,7 +75,7 @@ void mp_os_dupterm_stream_detached_attached(mp_obj_t stream_detached, mp_obj_t s
uart_attach_to_repl(MP_OBJ_TO_PTR(stream_attached), true);
}
#endif
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_STM_USB_STACK
if (mp_obj_get_type(stream_attached) == &pyb_usb_vcp_type) {
usb_vcp_attach_to_repl(MP_OBJ_TO_PTR(stream_attached), true);
}
diff --git a/ports/stm32/modpyb.c b/ports/stm32/modpyb.c
index 3d8696e3c..a985fa39d 100644
--- a/ports/stm32/modpyb.c
+++ b/ports/stm32/modpyb.c
@@ -167,7 +167,7 @@ static const mp_rom_map_elem_t pyb_module_globals_table[] = {
// Deprecated (use network.country instead).
{ MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&mod_network_country_obj) },
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_STM_USB_STACK
{ MP_ROM_QSTR(MP_QSTR_usb_mode), MP_ROM_PTR(&pyb_usb_mode_obj) },
#if MICROPY_HW_USB_HID
{ MP_ROM_QSTR(MP_QSTR_hid_mouse), MP_ROM_PTR(&pyb_usb_hid_mouse_obj) },
diff --git a/ports/stm32/mpconfigboard_common.h b/ports/stm32/mpconfigboard_common.h
index f36cdec8e..47eb7f036 100644
--- a/ports/stm32/mpconfigboard_common.h
+++ b/ports/stm32/mpconfigboard_common.h
@@ -250,12 +250,50 @@
#error "Old USBD_xxx configuration option used, renamed to MICROPY_HW_USB_xxx"
#endif
+// Select whether TinyUSB or legacy STM stack is used to provide USB.
+#ifndef MICROPY_HW_TINYUSB_STACK
+#define MICROPY_HW_TINYUSB_STACK (0)
+#endif
+
+// Central definition for STM USB stack (when not using TinyUSB)
+#define MICROPY_HW_STM_USB_STACK (MICROPY_HW_ENABLE_USB && !MICROPY_HW_TINYUSB_STACK)
+
+#if MICROPY_HW_TINYUSB_STACK
+#ifndef MICROPY_HW_ENABLE_USBDEV
+#define MICROPY_HW_ENABLE_USBDEV (1)
+#endif
+
+#ifndef MICROPY_HW_USB_CDC
+#define MICROPY_HW_USB_CDC (1)
+#endif
+
+#ifndef MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE
+#define MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE (1) // Support machine.USBDevice
+#endif
+#endif
+
+// Configure maximum number of CDC VCP interfaces, and whether MSC/HID are supported
+#ifndef MICROPY_HW_USB_CDC_NUM
+#define MICROPY_HW_USB_CDC_NUM (1)
+#endif
+#ifndef MICROPY_HW_USB_MSC
+#define MICROPY_HW_USB_MSC (MICROPY_HW_STM_USB_STACK)
+#endif
+#ifndef MICROPY_HW_USB_HID
+#define MICROPY_HW_USB_HID (MICROPY_HW_STM_USB_STACK)
+#endif
+
// Default VID and PID values to use for the USB device. If MICROPY_HW_USB_VID
// is defined by a board then all needed PID options must also be defined. The
// VID and PID can also be set dynamically in pyb.usb_mode().
// Windows needs a different PID to distinguish different device configurations.
#ifndef MICROPY_HW_USB_VID
#define MICROPY_HW_USB_VID (0xf055)
+
+// USB PID for TinyUSB Stack.
+#define MICROPY_HW_USB_PID (0x9802)
+
+// USB PID table for STM USB stack.
#define MICROPY_HW_USB_PID_CDC_MSC (0x9800)
#define MICROPY_HW_USB_PID_CDC_HID (0x9801)
#define MICROPY_HW_USB_PID_CDC (0x9802)
@@ -369,6 +407,8 @@
#endif
#define MICROPY_HW_MAX_LPUART (0)
+#define CFG_TUSB_MCU OPT_MCU_STM32F4
+
// Configuration for STM32F7 series
#elif defined(STM32F7)
@@ -384,6 +424,8 @@
#define MICROPY_HW_MAX_UART (8)
#define MICROPY_HW_MAX_LPUART (0)
+#define CFG_TUSB_MCU OPT_MCU_STM32F7
+
// Configuration for STM32G0 series
#elif defined(STM32G0)
@@ -394,6 +436,8 @@
#define MICROPY_HW_MAX_UART (6)
#define MICROPY_HW_MAX_LPUART (2)
+#define CFG_TUSB_MCU OPT_MCU_STM32G0
+
// Configuration for STM32G4 series
#elif defined(STM32G4)
@@ -404,6 +448,8 @@
#define MICROPY_HW_MAX_UART (5) // UART1-5 + LPUART1
#define MICROPY_HW_MAX_LPUART (1)
+#define CFG_TUSB_MCU OPT_MCU_STM32G4
+
// Configuration for STM32H5 series
#elif defined(STM32H5)
@@ -414,6 +460,8 @@
#define MICROPY_HW_MAX_UART (12)
#define MICROPY_HW_MAX_LPUART (1)
+#define CFG_TUSB_MCU OPT_MCU_STM32H5
+
// Configuration for STM32H7A3/B3 series
#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || \
defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
@@ -425,6 +473,8 @@
#define MICROPY_HW_MAX_UART (10)
#define MICROPY_HW_MAX_LPUART (1)
+#define CFG_TUSB_MCU OPT_MCU_STM32H7
+
// Configuration for STM32H7 series
#elif defined(STM32H7)
@@ -435,6 +485,8 @@
#define MICROPY_HW_MAX_UART (8)
#define MICROPY_HW_MAX_LPUART (1)
+#define CFG_TUSB_MCU OPT_MCU_STM32H7
+
#if defined(MICROPY_HW_ANALOG_SWITCH_PA0) \
|| defined(MICROPY_HW_ANALOG_SWITCH_PA1) \
|| defined(MICROPY_HW_ANALOG_SWITCH_PC2) \
@@ -454,6 +506,8 @@
#define MICROPY_HW_MAX_UART (5)
#define MICROPY_HW_MAX_LPUART (1)
+#define CFG_TUSB_MCU OPT_MCU_STM32L0
+
// Configuration for STM32L1 series
#elif defined(STM32L1)
#define MP_HAL_UNIQUE_ID_ADDRESS (UID_BASE)
@@ -464,6 +518,8 @@
#define MICROPY_HW_MAX_UART (5)
#define MICROPY_HW_MAX_LPUART (0)
+#define CFG_TUSB_MCU OPT_MCU_STM32L1
+
// Configuration for STM32L4 series
#elif defined(STM32L4)
@@ -474,6 +530,8 @@
#define MICROPY_HW_MAX_UART (5)
#define MICROPY_HW_MAX_LPUART (1)
+#define CFG_TUSB_MCU OPT_MCU_STM32L4
+
// Configuration for STM32N6 series
#elif defined(STM32N6)
@@ -508,6 +566,8 @@
#define MICROPY_HW_MAX_UART (1)
#define MICROPY_HW_MAX_LPUART (1)
+#define CFG_TUSB_MCU OPT_MCU_STM32WB
+
#ifndef MICROPY_HW_STM32WB_FLASH_SYNCRONISATION
#define MICROPY_HW_STM32WB_FLASH_SYNCRONISATION (1)
#endif
@@ -715,17 +775,6 @@
#define MICROPY_HW_USB_IS_MULTI_OTG (1)
#endif
-// Configure maximum number of CDC VCP interfaces, and whether MSC/HID are supported
-#ifndef MICROPY_HW_USB_CDC_NUM
-#define MICROPY_HW_USB_CDC_NUM (1)
-#endif
-#ifndef MICROPY_HW_USB_MSC
-#define MICROPY_HW_USB_MSC (MICROPY_HW_ENABLE_USB)
-#endif
-#ifndef MICROPY_HW_USB_HID
-#define MICROPY_HW_USB_HID (MICROPY_HW_ENABLE_USB)
-#endif
-
// Pin definition header file
#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stm32.h"
diff --git a/ports/stm32/mphalport.c b/ports/stm32/mphalport.c
index b13ed0ee1..51fb32ae8 100644
--- a/ports/stm32/mphalport.c
+++ b/ports/stm32/mphalport.c
@@ -8,6 +8,17 @@
#include "usb.h"
#include "uart.h"
+#if MICROPY_HW_TINYUSB_STACK
+#include "shared/tinyusb/mp_usbd_cdc.h"
+
+#ifndef MICROPY_HW_STDIN_BUFFER_LEN
+#define MICROPY_HW_STDIN_BUFFER_LEN 512
+#endif
+
+static uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN];
+ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array), 0, 0 };
+#endif
+
// this table converts from HAL_StatusTypeDef to POSIX errno
const byte mp_hal_status_to_errno_table[4] = {
[HAL_OK] = 0,
@@ -26,6 +37,9 @@ MP_NORETURN void mp_hal_raise(HAL_StatusTypeDef status) {
MP_WEAK uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
uintptr_t ret = 0;
+ #if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
+ ret |= mp_usbd_cdc_poll_interfaces(poll_flags);
+ #endif
if (MP_STATE_PORT(pyb_stdio_uart) != NULL) {
mp_obj_t pyb_stdio_uart = MP_OBJ_FROM_PTR(MP_STATE_PORT(pyb_stdio_uart));
int errcode;
@@ -53,6 +67,13 @@ MP_WEAK int mp_hal_stdin_rx_chr(void) {
if (dupterm_c >= 0) {
return dupterm_c;
}
+ #if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
+ mp_usbd_cdc_poll_interfaces(0);
+ int c = ringbuf_get(&stdin_ringbuf);
+ if (c != -1) {
+ return c;
+ }
+ #endif
MICROPY_EVENT_POLL_HOOK
}
}
@@ -64,6 +85,13 @@ MP_WEAK mp_uint_t mp_hal_stdout_tx_strn(const char *str, size_t len) {
uart_tx_strn(MP_STATE_PORT(pyb_stdio_uart), str, len);
did_write = true;
}
+ #if MICROPY_HW_USB_CDC && MICROPY_HW_TINYUSB_STACK
+ mp_uint_t cdc_res = mp_usbd_cdc_tx_strn(str, len);
+ if (cdc_res > 0) {
+ did_write = true;
+ ret = MIN(cdc_res, ret);
+ }
+ #endif
#if 0 && defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
lcd_print_strn(str, len);
#endif
diff --git a/ports/stm32/mphalport.h b/ports/stm32/mphalport.h
index 4d98ce9f1..098a848fb 100644
--- a/ports/stm32/mphalport.h
+++ b/ports/stm32/mphalport.h
@@ -1,6 +1,8 @@
// We use the ST Cube HAL library for most hardware peripherals
#include STM32_HAL_H
#include "pin.h"
+#include "py/ringbuf.h"
+#include "shared/runtime/interrupt_char.h"
extern uint8_t mp_hal_unique_id_address[12];
@@ -41,6 +43,8 @@ static inline int mp_hal_status_to_neg_errno(HAL_StatusTypeDef status) {
return -mp_hal_status_to_errno_table[status];
}
+extern ringbuf_t stdin_ringbuf;
+
MP_NORETURN void mp_hal_raise(HAL_StatusTypeDef status);
void mp_hal_set_interrupt_char(int c); // -1 to disable
@@ -148,3 +152,7 @@ enum {
void mp_hal_generate_laa_mac(int idx, uint8_t buf[6]);
void mp_hal_get_mac(int idx, uint8_t buf[6]);
void mp_hal_get_mac_ascii(int idx, size_t chr_off, size_t chr_len, char *dest);
+
+static inline void mp_hal_wake_main_task_from_isr(void) {
+ // Defined for tinyusb support, nothing needs to be done here.
+}
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index 470df4758..19778020d 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -80,7 +80,13 @@
#include "uart.h"
#include "storage.h"
#include "dma.h"
+
+#if MICROPY_HW_TINYUSB_STACK
+#include "tusb.h"
+#include "shared/tinyusb/mp_usbd.h"
+#else
#include "usb.h"
+#endif
#if defined(MICROPY_HW_USB_FS)
extern PCD_HandleTypeDef pcd_fs_handle;
@@ -145,7 +151,7 @@ void HardFault_C_Handler(ExceptionRegisters_t *regs) {
powerctrl_mcu_reset();
}
- #if MICROPY_HW_ENABLE_USB
+ #if MICROPY_HW_STM_USB_STACK
// We need to disable the USB so it doesn't try to write data out on
// the VCP and then block indefinitely waiting for the buffer to drain.
pyb_usb_flags = 0;
@@ -299,7 +305,11 @@ void DebugMon_Handler(void) {
#if MICROPY_HW_USB_FS
void USB_UCPD1_2_IRQHandler(void) {
+ #if MICROPY_HW_TINYUSB_STACK
+ tud_int_handler(0);
+ #else
HAL_PCD_IRQHandler(&pcd_fs_handle);
+ #endif
}
#endif
@@ -307,7 +317,11 @@ void USB_UCPD1_2_IRQHandler(void) {
#if MICROPY_HW_USB_FS
void USB_DRD_FS_IRQHandler(void) {
+ #if MICROPY_HW_TINYUSB_STACK
+ tud_int_handler(0);
+ #else
HAL_PCD_IRQHandler(&pcd_fs_handle);
+ #endif
}
#endif
@@ -315,7 +329,11 @@ void USB_DRD_FS_IRQHandler(void) {
#if MICROPY_HW_USB_FS
void USB_IRQHandler(void) {
+ #if MICROPY_HW_TINYUSB_STACK
+ tud_int_handler(0);
+ #else
HAL_PCD_IRQHandler(&pcd_fs_handle);
+ #endif
}
#endif
@@ -323,7 +341,11 @@ void USB_IRQHandler(void) {
#if MICROPY_HW_USB_FS
void USB_LP_IRQHandler(void) {
+ #if MICROPY_HW_TINYUSB_STACK
+ tud_int_handler(0);
+ #else
HAL_PCD_IRQHandler(&pcd_fs_handle);
+ #endif
}
#endif
@@ -337,7 +359,11 @@ void USB_LP_IRQHandler(void) {
#if MICROPY_HW_USB_FS
void OTG_FS_IRQHandler(void) {
IRQ_ENTER(OTG_FS_IRQn);
+ #if MICROPY_HW_TINYUSB_STACK
+ tud_int_handler(0);
+ #else
HAL_PCD_IRQHandler(&pcd_fs_handle);
+ #endif
IRQ_EXIT(OTG_FS_IRQn);
}
#endif
@@ -345,13 +371,21 @@ void OTG_FS_IRQHandler(void) {
#if defined(STM32N6)
void USB1_OTG_HS_IRQHandler(void) {
IRQ_ENTER(USB1_OTG_HS_IRQn);
+ #if MICROPY_HW_TINYUSB_STACK
+ tud_int_handler(0);
+ #else
HAL_PCD_IRQHandler(&pcd_hs_handle);
+ #endif
IRQ_EXIT(USB1_OTG_HS_IRQn);
}
#else
void OTG_HS_IRQHandler(void) {
IRQ_ENTER(OTG_HS_IRQn);
+ #if MICROPY_HW_TINYUSB_STACK
+ tud_int_handler(0);
+ #else
HAL_PCD_IRQHandler(&pcd_hs_handle);
+ #endif
IRQ_EXIT(OTG_HS_IRQn);
}
#endif
@@ -414,6 +448,9 @@ static void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) {
/* ungate PHY clock */
__HAL_PCD_UNGATE_PHYCLOCK(pcd_handle);
}
+ #if MICROPY_HW_TINYUSB_STACK
+ tud_int_handler(0);
+ #endif
}
#endif
diff --git a/ports/stm32/usb.c b/ports/stm32/usb.c
index 81025e48b..15d563713 100644
--- a/ports/stm32/usb.c
+++ b/ports/stm32/usb.c
@@ -45,7 +45,7 @@
#include "sdcard.h"
#include "usb.h"
-#if MICROPY_HW_ENABLE_USB
+#if MICROPY_HW_STM_USB_STACK
// Work out which USB device to use as the main one (the one with the REPL)
#if !defined(MICROPY_HW_USB_MAIN_DEV)
@@ -1156,4 +1156,4 @@ MP_REGISTER_ROOT_POINTER(mp_obj_t pyb_hid_report_desc);
#endif
MP_REGISTER_ROOT_POINTER(mp_obj_t pyb_usb_vcp_irq[MICROPY_HW_USB_CDC_NUM]);
-#endif // MICROPY_HW_ENABLE_USB
+#endif // MICROPY_HW_STM_USB_STACK
diff --git a/ports/stm32/usbd.c b/ports/stm32/usbd.c
new file mode 100644
index 000000000..35275cd1b
--- /dev/null
+++ b/ports/stm32/usbd.c
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Andrew Leech
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mpconfig.h"
+
+#if MICROPY_HW_ENABLE_USBDEV && MICROPY_HW_TINYUSB_STACK
+
+#include "mp_usbd.h"
+#include "py/mpconfig.h"
+#include "string.h"
+#include "mphalport.h"
+
+void mp_usbd_port_get_serial_number(char *serial_buf) {
+ uint8_t *id = (uint8_t *)MP_HAL_UNIQUE_ID_ADDRESS;
+ MP_STATIC_ASSERT(12 * 2 <= MICROPY_HW_USB_DESC_STR_MAX);
+ mp_usbd_hex_str(serial_buf, id, 12);
+}
+
+#endif
diff --git a/ports/stm32/usbd_conf.c b/ports/stm32/usbd_conf.c
index 2cf79e09e..18f350d4a 100644
--- a/ports/stm32/usbd_conf.c
+++ b/ports/stm32/usbd_conf.c
@@ -37,6 +37,12 @@
#if MICROPY_HW_USB_FS || MICROPY_HW_USB_HS
+#if BUILDING_MBOOT
+// TinyUSB not used in mboot
+#undef MICROPY_HW_TINYUSB_STACK
+#endif
+
+// These handles are also used in Interrupt / Wakeup handlers.
#if MICROPY_HW_USB_FS
PCD_HandleTypeDef pcd_fs_handle;
#endif
@@ -56,18 +62,17 @@ PCD_HandleTypeDef pcd_hs_handle;
#define OTG_HS_IRQn USB1_OTG_HS_IRQn
#endif
-/*******************************************************************************
- PCD BSP Routines
-*******************************************************************************/
-
-/**
- * @brief Initializes the PCD MSP.
- * @param hpcd: PCD handle
- * @retval None
- */
-void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
+#if MICROPY_HW_TINYUSB_STACK
+void pyb_usbd_init(void)
+#else
+void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd)
+#endif
+{
#if MICROPY_HW_USB_FS
- if (hpcd->Instance == USB_OTG_FS) {
+ #if MICROPY_HW_STM_USB_STACK
+ if (hpcd->Instance == USB_OTG_FS)
+ #endif
+ {
// Configure USB GPIO's.
#if defined(STM32G0) || defined(STM32G4)
@@ -139,7 +144,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
#endif
// Enable VDDUSB
- #if defined(STM32H5)
+ #if defined(STM32H5) || defined(STM32WB)
HAL_PWREx_EnableVddUSB();
#elif defined(STM32L4)
if (__HAL_RCC_PWR_IS_CLK_DISABLED()) {
@@ -172,12 +177,17 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
#endif
+ #if MICROPY_HW_STM_USB_STACK
return;
+ #endif
}
#endif
#if MICROPY_HW_USB_HS
- if (hpcd->Instance == USB_OTG_HS) {
+ #if MICROPY_HW_STM_USB_STACK
+ if (hpcd->Instance == USB_OTG_HS)
+ #endif
+ {
#if MICROPY_HW_USB_HS_IN_FS
// Configure USB GPIO's.
@@ -319,6 +329,8 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) {
#endif // MICROPY_HW_USB_HS
}
+#if MICROPY_HW_STM_USB_STACK
+
/**
* @brief DeInitializes the PCD MSP.
* @param hpcd: PCD handle
@@ -798,6 +810,8 @@ void HAL_PCDEx_SetConnectionState(PCD_HandleTypeDef *hpcd, uint8_t state) {
}
#endif
+#endif // MICROPY_HW_STM_USB_STACK
+
#endif // MICROPY_HW_USB_FS || MICROPY_HW_USB_HS
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/ports/stm32/usbd_conf.h b/ports/stm32/usbd_conf.h
index e61e7ce7e..cb0457982 100644
--- a/ports/stm32/usbd_conf.h
+++ b/ports/stm32/usbd_conf.h
@@ -64,6 +64,10 @@
#define USBD_HS_NUM_TX_FIFO (9)
#define USBD_HS_NUM_FIFO (1 + USBD_HS_NUM_TX_FIFO)
+#if MICROPY_HW_TINYUSB_STACK
+void pyb_usbd_init(void);
+#endif
+
#endif // MICROPY_INCLUDED_STM32_USBD_CONF_H
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/tools/ci.sh b/tools/ci.sh
index 5d401843b..42d231c45 100755
--- a/tools/ci.sh
+++ b/tools/ci.sh
@@ -511,7 +511,7 @@ function ci_stm32_nucleo_build {
# Test building various MCU families, some with additional options.
make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC
- make ${MAKEOPTS} -C ports/stm32 BOARD=STM32H573I_DK
+ make ${MAKEOPTS} -C ports/stm32 BOARD=STM32H573I_DK CFLAGS_EXTRA='-DMICROPY_HW_TINYUSB_STACK=1'
make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI COPT=-O2 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1'
make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L073RZ
make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L476RG DEBUG=1