Skip to content

Add STM32U3 Device#3325

Merged
HiFiPhile merged 2 commits intohathach:masterfrom
tswan22:master
Nov 7, 2025
Merged

Add STM32U3 Device#3325
HiFiPhile merged 2 commits intohathach:masterfrom
tswan22:master

Conversation

@tswan22
Copy link
Contributor

@tswan22 tswan22 commented Nov 1, 2025

Describe the PR
Added the USB device for the STM32U3 using stm32_fsdev.

Additional context

  • Essentially the same as the STM32U0 and STM32U5 (stm32_fsdev) and others.
  • I am not sure if this addition also handles USB host, but it is possible on this MCU. I left the column empty in the README.
  • This was tested on a custom PCB so I did not add any hw/bsp
  • I have only tested it with CDC device.
  • In #2824 it was mentioned there is quite a bit of duplication for the fsdev code. I have followed suit but I can adjust if needed.
  • I have set FSDEV_HAS_SBUF_ISO 1 in fsdev_stm32.h though this has not been tested.
    • I see it is 0 in STM32U0 but 1 in STM32U5. This ultimately translates to FSDEV_USE_SBUF_ISO 1 which is used in dcd_stm32_fsdev.c, but I don't quite know what it does. Since STM32U3 is between the others in terms of capability I figured it would be capable of it.

Family Code
I am not using the tinyusb hw/bsp setup in my project but I do have a minimum setup code which I will add here, I am not sure if I should add this somewhere else but it may be useful for anyone adding a board in the future. Sorry the GPIO config does not use HAL since it is generated from another tool, but it can likely be replaced with HAL_GPIO_Init(...).

#include "tusb.h"
#include "stm32u3xx_hal_pwr.h"
#include "stm32u3xx_hal_rcc.h"

void USB_FS_IRQHandler(void)
{
    tud_int_handler(0);
}

size_t board_get_unique_id(uint8_t id[], size_t max_len) // from STM32U5
{
    (void) max_len;
    volatile uint32_t *stm32_uuid = (volatile uint32_t *) UID_BASE;
    uint32_t *id32 = (uint32_t *) (uintptr_t) id;
    uint8_t const len = 12;

    id32[0] = stm32_uuid[0];
    id32[1] = stm32_uuid[1];
    id32[2] = stm32_uuid[2];

    return len;
}

void usb_setup()
{
    HAL_PWREx_EnableVddUSB();
    __HAL_RCC_USB1_CLK_ENABLE();

    LL_RCC_HSI48_Enable();
    while(LL_RCC_HSI48_IsReady() != 1);

    LL_RCC_SetICLKClockSource(LL_RCC_ICLK_CLKSOURCE_HSI48);
    while (LL_RCC_GetICLKClockSource(LL_RCC_ICLK_CLKSOURCE) != LL_RCC_ICLK_CLKSOURCE_HSI48);
    LL_RCC_SetUSBClockSource(LL_RCC_USB1_CLKSOURCE_ICLK);

    __HAL_RCC_CRS_CLK_ENABLE();
    RCC_CRSInitTypeDef RCC_CRSInitStruct = {0};
    RCC_CRSInitStruct.Prescaler = RCC_CRS_SYNC_DIV1;
    RCC_CRSInitStruct.Source = RCC_CRS_SYNC_SOURCE_USB;
    RCC_CRSInitStruct.Polarity = RCC_CRS_SYNC_POLARITY_RISING;
    RCC_CRSInitStruct.ReloadValue = __HAL_RCC_CRS_RELOADVALUE_CALCULATE(48000000,1000);
    RCC_CRSInitStruct.ErrorLimitValue = 34;
    RCC_CRSInitStruct.HSI48CalibrationValue = 32;
    HAL_RCCEx_CRSConfig(&RCC_CRSInitStruct);

    // Don't think this is actually necessary since USB DM/DP are not AF
    // GPIOB 11: USB_DM
    GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODE11_Msk) | (0x2 << GPIO_MODER_MODE11_Pos); // AF
    GPIOA->OTYPER = (GPIOA->OTYPER & ~GPIO_OTYPER_OT11_Msk) | (0x0 << GPIO_OTYPER_OT11_Pos); // PUSH_PULL
    GPIOA->OSPEEDR = (GPIOA->OSPEEDR & ~GPIO_OSPEEDR_OSPEED11_Msk) | (0x3 << GPIO_OSPEEDR_OSPEED11_Pos); // VERY-HIGH
    GPIOA->PUPDR = (GPIOA->PUPDR & ~GPIO_PUPDR_PUPD11_Msk) | (0x0 << GPIO_PUPDR_PUPD11_Pos); // NONE
    GPIOA->AFR[1] = (GPIOA->AFR[1] & ~GPIO_AFRH_AFSEL11_Msk) | (0xA << GPIO_AFRH_AFSEL11_Pos); // AF10
    // GPIOA 12: USB_DP
    GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODE12_Msk) | (0x2 << GPIO_MODER_MODE12_Pos); // AF
    GPIOA->OTYPER = (GPIOA->OTYPER & ~GPIO_OTYPER_OT12_Msk) | (0x0 << GPIO_OTYPER_OT12_Pos); // PUSH_PULL
    GPIOA->OSPEEDR = (GPIOA->OSPEEDR & ~GPIO_OSPEEDR_OSPEED12_Msk) | (0x3 << GPIO_OSPEEDR_OSPEED12_Pos); // VERY-HIGH
    GPIOA->PUPDR = (GPIOA->PUPDR & ~GPIO_PUPDR_PUPD12_Msk) | (0x0 << GPIO_PUPDR_PUPD12_Pos); // NONE
    GPIOA->AFR[1] = (GPIOA->AFR[1] & ~GPIO_AFRH_AFSEL12_Msk) | (0xA << GPIO_AFRH_AFSEL12_Pos); // AF10
}

@HiFiPhile
Copy link
Collaborator

Thank you, LGTM.

@HiFiPhile HiFiPhile requested a review from Copilot November 7, 2025 09:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for the STM32U3 microcontroller family to TinyUSB. The STM32U3 uses the FSDEV (Full-Speed Device) USB peripheral similar to other STM32 U-series microcontrollers.

Key Changes

  • Added STM32U3 MCU option definition (OPT_MCU_STM32U3 = 321)
  • Configured STM32U3 to use the stm32_fsdev driver with 2KB PMA buffer, 32-bit bus, and 8 endpoints
  • Added STM32U3 USB interrupt configuration (USB_FS_IRQn)

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/tusb_option.h Added OPT_MCU_STM32U3 definition (value 321) to the STM32 MCU enumeration
src/common/tusb_mcu.h Configured STM32U3 to use FSDEV driver with 8 endpoints
src/portable/st/stm32_fsdev/fsdev_stm32.h Added STM32U3 register mappings and USB_FS_IRQn interrupt configuration
README.rst Updated supported CPU table to include STM32U3 with device support using stm32_fsdev driver

Copy link
Owner

@hathach hathach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you LGTM as well

@HiFiPhile HiFiPhile merged commit 1634d11 into hathach:master Nov 7, 2025
115 of 121 checks passed
@hathach hathach mentioned this pull request Nov 12, 2025
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants