Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extmod/machine_usb_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

#if MICROPY_HW_ENABLE_USB_RUNTIME_DEVICE

#include "mp_usbd.h"
#include "shared/tinyusb/mp_usbd.h"
#include "py/mperrno.h"
#include "py/objstr.h"

Expand Down
2 changes: 1 addition & 1 deletion ports/stm32/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ 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 += -Itinyusb_port
INC += -Ilwip_inc

CFLAGS += $(INC) -Wall -Wpointer-arith -Werror -Wdouble-promotion -Wfloat-conversion -std=gnu99 $(CFLAGS_EXTRA)
Expand Down
6 changes: 6 additions & 0 deletions ports/stm32/factoryreset.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,15 @@ static const char fresh_boot_py[] =
"import pyb\r\n"
"#pyb.main('main.py') # main script to run after this one\r\n"
#if MICROPY_HW_ENABLE_USB
#if MICROPY_HW_TINYUSB_STACK
"#usb = machine.USBDevice()\r\n"
"#usb.builtin_driver = machine.USBDevice.BUILTIN_DEFAULT # CDC + MSC\r\n"
"#usb.active(True)\r\n"
#else
"#pyb.usb_mode('VCP+MSC') # act as a serial and a storage device\r\n"
"#pyb.usb_mode('VCP+HID') # act as a serial device and a mouse\r\n"
#endif
#endif
#if MICROPY_PY_NETWORK
"#import network\r\n"
"#network.country('US') # ISO 3166-1 Alpha-2 code, eg US, GB, DE, AU or XX for worldwide\r\n"
Expand Down
2 changes: 1 addition & 1 deletion ports/stm32/stm32_it.c
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ void USB1_OTG_HS_IRQHandler(void) {
void OTG_HS_IRQHandler(void) {
IRQ_ENTER(OTG_HS_IRQn);
#if MICROPY_HW_TINYUSB_STACK
tud_int_handler(0);
tud_int_handler(1); // OTG_HS is always RHPORT1 on F4/F7/H7 (not N6, which uses USB1_OTG_HS_IRQHandler)
#else
HAL_PCD_IRQHandler(&pcd_hs_handle);
#endif
Expand Down
51 changes: 51 additions & 0 deletions ports/stm32/tinyusb_port/tusb_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2026 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.
*/
#ifndef MICROPY_INCLUDED_STM32_TINYUSB_PORT_TUSB_CONFIG_H
#define MICROPY_INCLUDED_STM32_TINYUSB_PORT_TUSB_CONFIG_H

#include "py/mpconfig.h"

// STM32F4/F7/H7 boards with USB_HS use OTG_HS on RHPORT1, not RHPORT0.
// Disable RHPORT0 and put RHPORT1 in device mode (HS, or FS when the
// HS controller uses the internal FS PHY via MICROPY_HW_USB_HS_IN_FS).
// Other configs are handled either by the board (e.g. N6 sets RHPORT0
// to HS in mpconfigboard_common.h) or by the shared default in
// shared/tinyusb/tusb_config.h (RHPORT0 in FS device mode).

// These families place OTG_HS on RHPORT1. Extend the list if a new family
// also uses OTG_HS on RHPORT1 rather than RHPORT0.
#if MICROPY_HW_USB_HS && (defined(STM32F4) || defined(STM32F7) || defined(STM32H7))
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_NONE)
#if MICROPY_HW_USB_HS_IN_FS
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | OPT_MODE_FULL_SPEED)
#else
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED)
#endif
#endif

#include "shared/tinyusb/tusb_config.h"

#endif // MICROPY_INCLUDED_STM32_TINYUSB_PORT_TUSB_CONFIG_H
20 changes: 15 additions & 5 deletions ports/stm32/usbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,25 @@

#if MICROPY_HW_ENABLE_USBDEV && MICROPY_HW_TINYUSB_STACK

#include "mp_usbd.h"
#include "py/mpconfig.h"
#include "string.h"
#include <string.h>
#include "shared/tinyusb/mp_usbd.h"
#include "mphalport.h"

void mp_usbd_port_get_serial_number(char *serial_buf) {
// Use the same algorithm as the ST DFU bootloader so that the serial
// number is consistent across all USB modes.
MP_STATIC_ASSERT(12 <= MICROPY_HW_USB_DESC_STR_MAX); // 6 derived bytes x 2 hex digits + NUL
static const char hexdig[] = "0123456789ABCDEF";
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);
uint8_t bytes[] = {
id[11], (uint8_t)(id[10] + id[2]), id[9],
(uint8_t)(id[8] + id[0]), id[7], id[6],
};
for (int i = 0; i < 6; i++) {
serial_buf[i * 2] = hexdig[bytes[i] >> 4];
serial_buf[i * 2 + 1] = hexdig[bytes[i] & 0x0f];
}
serial_buf[12] = '\0';
}

#endif
13 changes: 13 additions & 0 deletions shared/tinyusb/mp_usbd_cdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@

#if MICROPY_HW_USB_CDC && MICROPY_HW_ENABLE_USBDEV && !MICROPY_EXCLUDE_SHARED_TINYUSB_USBD_CDC

// TinyUSB has no public API for endpoint stall detection/clearing; this
// private header is the intended interface for class drivers (all built-in
// TinyUSB class drivers include it for the same purpose).
#include "device/usbd_pvt.h"

static uint8_t cdc_itf_pending; // keep track of cdc interfaces which need attention to poll
static int8_t cdc_connected_flush_delay = 0;

Expand Down Expand Up @@ -176,10 +181,18 @@ void MICROPY_WRAP_TUD_CDC_LINE_STATE_CB(tud_cdc_line_state_cb)(uint8_t itf, bool
#if MICROPY_HW_USB_CDC && !MICROPY_EXCLUDE_SHARED_TINYUSB_USBD_CDC
if (dtr) {
// A host application has started to open the cdc serial port.
// USBD_CDC_EP_IN is the IN endpoint for itf 0; only clear stall for itf 0.
if (itf == 0 && usbd_edpt_stalled(TUD_OPT_RHPORT, USBD_CDC_EP_IN)) {
usbd_edpt_clear_stall(TUD_OPT_RHPORT, USBD_CDC_EP_IN);
}
// Wait a few ms for host to be ready then send tx buffer.
// High speed connection SOF fires at 125us, full speed at 1ms.
cdc_connected_flush_delay = (tud_speed_get() == TUSB_SPEED_HIGH) ? 128 : 16;
tud_sof_cb_enable(true);
} else {
// Host has closed the cdc serial port. Discard pending TX data to
// avoid a full FIFO blocking writes on the next connection.
tud_cdc_n_write_clear(itf);
}
#endif
#if MICROPY_HW_USB_CDC_DTR_RTS_BOOTLOADER
Expand Down
Loading