From a4d0df7fcf4ab39034b73c8641e669dcd277cb50 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 24 Nov 2025 00:17:58 +0100 Subject: [PATCH 01/21] bsp/stm32c0: use external clock, increase stack size Signed-off-by: HiFiPhile --- .../stm32c071nucleo/STM32C071RBTx_FLASH.ld | 2 +- .../boards/stm32c071nucleo/board.cmake | 1 + hw/bsp/stm32c0/boards/stm32c071nucleo/board.h | 32 ++++++++---------- .../stm32c0/boards/stm32c071nucleo/board.mk | 2 +- .../stm32c071nucleo/stm32c071xx_flash.icf | 33 +++++++++++++++++++ hw/bsp/stm32c0/family.cmake | 1 - hw/bsp/stm32c0/stm32c0xx_hal_conf.h | 2 +- 7 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 hw/bsp/stm32c0/boards/stm32c071nucleo/stm32c071xx_flash.icf diff --git a/hw/bsp/stm32c0/boards/stm32c071nucleo/STM32C071RBTx_FLASH.ld b/hw/bsp/stm32c0/boards/stm32c071nucleo/STM32C071RBTx_FLASH.ld index 8acd49f9d..6c7e203f1 100644 --- a/hw/bsp/stm32c0/boards/stm32c071nucleo/STM32C071RBTx_FLASH.ld +++ b/hw/bsp/stm32c0/boards/stm32c071nucleo/STM32C071RBTx_FLASH.ld @@ -36,7 +36,7 @@ ENTRY(Reset_Handler) _Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_Min_Stack_Size = 0xc00; /* required amount of stack */ /* Memories definition */ MEMORY diff --git a/hw/bsp/stm32c0/boards/stm32c071nucleo/board.cmake b/hw/bsp/stm32c0/boards/stm32c071nucleo/board.cmake index 2a319a73c..ed70cffbf 100644 --- a/hw/bsp/stm32c0/boards/stm32c071nucleo/board.cmake +++ b/hw/bsp/stm32c0/boards/stm32c071nucleo/board.cmake @@ -2,6 +2,7 @@ set(MCU_VARIANT stm32c071xx) set(JLINK_DEVICE stm32c071rb) set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/STM32C071RBTx_FLASH.ld) +set(LD_FILE_IAR ${CMAKE_CURRENT_LIST_DIR}/stm32c071xx_flash.icf) function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC diff --git a/hw/bsp/stm32c0/boards/stm32c071nucleo/board.h b/hw/bsp/stm32c0/boards/stm32c071nucleo/board.h index 751df2251..460b42a21 100644 --- a/hw/bsp/stm32c0/boards/stm32c071nucleo/board.h +++ b/hw/bsp/stm32c0/boards/stm32c071nucleo/board.h @@ -64,36 +64,30 @@ static inline void board_clock_init(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; - RCC_CRSInitTypeDef RCC_CRSInitStruct = {0}; + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; - /* -1- Enable HSIUSB48 Oscillator */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48; - RCC_OscInitStruct.HSI48State = RCC_HSI48_ON; + __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1); + /** Initializes the RCC Oscillators according to the specified parameters + * in the RCC_OscInitTypeDef structure. + */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; HAL_RCC_OscConfig(&RCC_OscInitStruct); - /* -2- Initializes the CPU, AHB and APB buses clocks */ + /** Initializes the CPU, AHB and APB buses clocks + */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1; - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSIUSB48; + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1); - - __HAL_RCC_CRS_CLK_ENABLE(); - - // Configures CRS - 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); + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB; + PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_HSE; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); } - #endif /* BOARD_H_ */ diff --git a/hw/bsp/stm32c0/boards/stm32c071nucleo/board.mk b/hw/bsp/stm32c0/boards/stm32c071nucleo/board.mk index 67a9b59a8..fd22fc8d4 100644 --- a/hw/bsp/stm32c0/boards/stm32c071nucleo/board.mk +++ b/hw/bsp/stm32c0/boards/stm32c071nucleo/board.mk @@ -7,7 +7,7 @@ LD_FILE_GCC = $(BOARD_PATH)/STM32C071RBTx_FLASH.ld # IAR SRC_S_IAR += $(ST_CMSIS)/Source/Templates/iar/startup_stm32c071xx.s -LD_FILE_IAR = $(ST_CMSIS)/Source/Templates/iar/linker/stm32c071xx_flash.icf +LD_FILE_IAR = $(BOARD_PATH)/stm32c071xx_flash.icf # For flash-jlink target JLINK_DEVICE = stm32c071rb diff --git a/hw/bsp/stm32c0/boards/stm32c071nucleo/stm32c071xx_flash.icf b/hw/bsp/stm32c0/boards/stm32c071nucleo/stm32c071xx_flash.icf new file mode 100644 index 000000000..684f41dc6 --- /dev/null +++ b/hw/bsp/stm32c0/boards/stm32c071nucleo/stm32c071xx_flash.icf @@ -0,0 +1,33 @@ +/*###ICF### Section handled by ICF editor, don't touch! ****/ +/*-Editor annotation file-*/ +/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ +/*-Specials-*/ +define symbol __ICFEDIT_intvec_start__ = 0x08000000; +/*-Memory Regions-*/ +define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; +define symbol __ICFEDIT_region_ROM_end__ = 0x0801FFFF; +define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; +define symbol __ICFEDIT_region_RAM_end__ = 0x20005FFF; +/*-Sizes-*/ +define symbol __ICFEDIT_size_cstack__ = 0xc00; +define symbol __ICFEDIT_size_heap__ = 0x200; +/**** End of ICF editor section. ###ICF###*/ + +define memory mem with size = 4G; +define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; +define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; + +define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; +define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; + +initialize by copy { readwrite }; +do not initialize { section .noinit }; + +place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; + +place in ROM_region { readonly }; +place in RAM_region { readwrite, + block CSTACK, block HEAP }; + +export symbol __ICFEDIT_region_RAM_start__; +export symbol __ICFEDIT_region_RAM_end__; diff --git a/hw/bsp/stm32c0/family.cmake b/hw/bsp/stm32c0/family.cmake index 90d5322b7..f68e80895 100644 --- a/hw/bsp/stm32c0/family.cmake +++ b/hw/bsp/stm32c0/family.cmake @@ -24,7 +24,6 @@ set(STARTUP_FILE_GNU ${ST_CMSIS}/Source/Templates/gcc/startup_${MCU_VARIANT}.s) set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) set(STARTUP_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/startup_${MCU_VARIANT}.s) set(LD_FILE_Clang ${LD_FILE_GNU}) -set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf) #------------------------------------ # BOARD_TARGET diff --git a/hw/bsp/stm32c0/stm32c0xx_hal_conf.h b/hw/bsp/stm32c0/stm32c0xx_hal_conf.h index 678b6ee0d..874251c7f 100644 --- a/hw/bsp/stm32c0/stm32c0xx_hal_conf.h +++ b/hw/bsp/stm32c0/stm32c0xx_hal_conf.h @@ -92,7 +92,7 @@ extern "C" { * (when HSE is used as system clock source, directly or through the PLL). */ #if !defined (HSE_VALUE) -#define HSE_VALUE (8000000U) /*!< Value of the External oscillator in Hz */ +#define HSE_VALUE (48000000U) /*!< Value of the External oscillator in Hz */ #endif /* HSE_VALUE */ #if !defined (HSE_STARTUP_TIMEOUT) From fb631c9a402478702fcce7168a5f1cc3b231e959 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 24 Nov 2025 00:26:05 +0100 Subject: [PATCH 02/21] hcd: add fsdev driver Signed-off-by: HiFiPhile --- examples/host/device_info/only.txt | 1 + examples/host/msc_file_explorer/only.txt | 1 + hw/bsp/stm32c0/family.c | 4 +- hw/bsp/stm32c0/family.cmake | 1 + hw/bsp/stm32c0/family.mk | 1 + src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 20 +- src/portable/st/stm32_fsdev/fsdev_at32.h | 16 +- src/portable/st/stm32_fsdev/fsdev_ch32.h | 9 +- src/portable/st/stm32_fsdev/fsdev_stm32.h | 15 +- src/portable/st/stm32_fsdev/fsdev_type.h | 41 +- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 833 ++++++++++++++++++ 11 files changed, 917 insertions(+), 25 deletions(-) create mode 100644 src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c diff --git a/examples/host/device_info/only.txt b/examples/host/device_info/only.txt index 61a08f68d..069f92d83 100644 --- a/examples/host/device_info/only.txt +++ b/examples/host/device_info/only.txt @@ -13,6 +13,7 @@ mcu:MSP432E4 mcu:RP2040 mcu:RX65X mcu:RAXXX +mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 mcu:STM32H7 diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt index cba58f8e8..a7bebf1d9 100644 --- a/examples/host/msc_file_explorer/only.txt +++ b/examples/host/msc_file_explorer/only.txt @@ -13,6 +13,7 @@ mcu:MSP432E4 mcu:RX65X mcu:RAXXX mcu:MAX3421 +mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 mcu:STM32H7 diff --git a/hw/bsp/stm32c0/family.c b/hw/bsp/stm32c0/family.c index 09704b527..b04a9cea5 100644 --- a/hw/bsp/stm32c0/family.c +++ b/hw/bsp/stm32c0/family.c @@ -37,13 +37,13 @@ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ void USB_DRD_FS_IRQHandler(void) { - tud_int_handler(0); + tusb_int_handler(0, true); } // Startup code generated by STM32CubeIDE uses USB_IRQHandler, while // stm32c071xx.s from cmsis_device_c0 uses USB_DRD_FS_IRQHandler. void USB_IRQHandler(void) { - USB_DRD_FS_IRQHandler(); + tusb_int_handler(0, true); } //--------------------------------------------------------------------+ diff --git a/hw/bsp/stm32c0/family.cmake b/hw/bsp/stm32c0/family.cmake index f68e80895..6e04b20f4 100644 --- a/hw/bsp/stm32c0/family.cmake +++ b/hw/bsp/stm32c0/family.cmake @@ -66,6 +66,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c ${TOP}/src/portable/st/typec/typec_stm32.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) diff --git a/hw/bsp/stm32c0/family.mk b/hw/bsp/stm32c0/family.mk index bdb34454e..fd03ad537 100644 --- a/hw/bsp/stm32c0/family.mk +++ b/hw/bsp/stm32c0/family.mk @@ -29,6 +29,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 381aa0b40..db1a5784a 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -123,8 +123,6 @@ #error "Unknown USB IP" #endif -#include "fsdev_type.h" - //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -848,6 +846,24 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { ep_write(ep_idx, ep_reg, true); } +void dcd_int_enable(uint8_t rhport) { + fsdev_int_enable(rhport); +} + +void dcd_int_disable(uint8_t rhport) { + fsdev_int_disable(rhport); +} + +#if defined(USB_BCDR_DPPU) || defined(SYSCFG_PMC_USB_PU) +void dcd_connect(uint8_t rhport) { + fsdev_connect(rhport); +} + +void dcd_disconnect(uint8_t rhport) { + fsdev_disconnect(rhport); +} +#endif + //--------------------------------------------------------------------+ // PMA read/write //--------------------------------------------------------------------+ diff --git a/src/portable/st/stm32_fsdev/fsdev_at32.h b/src/portable/st/stm32_fsdev/fsdev_at32.h index deb1de2a8..03490ee24 100644 --- a/src/portable/st/stm32_fsdev/fsdev_at32.h +++ b/src/portable/st/stm32_fsdev/fsdev_at32.h @@ -168,7 +168,7 @@ enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; #error "Unsupported MCU" #endif -void dcd_int_enable(uint8_t rhport) { +void fsdev_int_enable(uint8_t rhport) { (void)rhport; #if (CFG_TUSB_MCU == OPT_MCU_AT32F403A_407) || (CFG_TUSB_MCU == OPT_MCU_AT32F413) // AT32F403A/407 devices allow to remap the USB interrupt vectors from @@ -187,7 +187,7 @@ void dcd_int_enable(uint8_t rhport) { } } -void dcd_int_disable(uint8_t rhport) { +void fsdev_int_disable(uint8_t rhport) { (void)rhport; #if (CFG_TUSB_MCU == OPT_MCU_AT32F403A_407) || (CFG_TUSB_MCU == OPT_MCU_AT32F413) // AT32F403A/407 devices allow to remap the USB interrupt vectors from @@ -206,20 +206,20 @@ void dcd_int_disable(uint8_t rhport) { } } -void dcd_disconnect(uint8_t rhport) { +void fsdev_disconnect(uint8_t rhport) { (void) rhport; /* disable usb phy */ - FSDEV_REG->CNTR |= USB_CNTR_PDWN; + *(volatile uint32_t*)(FSDEV_REG_BASE + 0x40) |= USB_CNTR_PDWN; /* D+ 1.5k pull-up disable, USB->cfg_bit.puo = TRUE; */ - *(uint32_t *)(FSDEV_REG_BASE+0x60) |= (1u<<1); + *(volatile uint32_t *)(FSDEV_REG_BASE+0x60) |= (1u<<1); } -void dcd_connect(uint8_t rhport) { +void fsdev_connect(uint8_t rhport) { (void) rhport; /* enable usb phy */ - FSDEV_REG->CNTR &= ~USB_CNTR_PDWN; + *(volatile uint32_t*)(FSDEV_REG_BASE + 0x40) &= ~USB_CNTR_PDWN; /* Dp 1.5k pull-up enable, USB->cfg_bit.puo = 0; */ - *(uint32_t *)(FSDEV_REG_BASE+0x60) &= ~(1u<<1); + *(volatile uint32_t *)(FSDEV_REG_BASE+0x60) &= ~(1u<<1); } #endif diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h index ceebb6dab..547f3bd1b 100644 --- a/src/portable/st/stm32_fsdev/fsdev_ch32.h +++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h @@ -168,6 +168,7 @@ #define USB_EPRX_DTOG2 ((uint16_t)0x2000U) /*!< EndPoint RX Data TOGgle bit1 */ #define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK) +#include "fsdev_type.h" //--------------------------------------------------------------------+ // @@ -184,26 +185,26 @@ enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; #error "Unsupported MCU" #endif -void dcd_int_enable(uint8_t rhport) { +void fsdev_int_enable(uint8_t rhport) { (void)rhport; for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) { NVIC_EnableIRQ(fsdev_irq[i]); } } -void dcd_int_disable(uint8_t rhport) { +void fsdev_int_disable(uint8_t rhport) { (void)rhport; for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) { NVIC_DisableIRQ(fsdev_irq[i]); } } -void dcd_disconnect(uint8_t rhport) { +void fsdev_disconnect(uint8_t rhport) { (void) rhport; EXTEN->EXTEN_CTR &= ~EXTEN_USBD_PU_EN; } -void dcd_connect(uint8_t rhport) { +void fsdev_connect(uint8_t rhport) { (void) rhport; EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN; } diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h index 30ffadc35..d47d23f14 100644 --- a/src/portable/st/stm32_fsdev/fsdev_stm32.h +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -321,6 +321,8 @@ #define FSDEV_USE_SBUF_ISO 0 #endif +#include "fsdev_type.h" + //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ @@ -372,7 +374,7 @@ static const IRQn_Type fsdev_irq[] = { }; enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; -void dcd_int_enable(uint8_t rhport) { +void fsdev_int_enable(uint8_t rhport) { (void)rhport; // forces write to RAM before allowing ISR to execute @@ -395,7 +397,7 @@ void dcd_int_enable(uint8_t rhport) { } } -void dcd_int_disable(uint8_t rhport) { +void fsdev_int_disable(uint8_t rhport) { (void)rhport; #if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP) @@ -420,28 +422,27 @@ void dcd_int_disable(uint8_t rhport) { // Define only on MCU with internal pull-up. BSP can define on MCU without internal PU. #if defined(USB_BCDR_DPPU) -void dcd_disconnect(uint8_t rhport) { +void fsdev_disconnect(uint8_t rhport) { (void)rhport; USB->BCDR &= ~(USB_BCDR_DPPU); } -void dcd_connect(uint8_t rhport) { +void fsdev_connect(uint8_t rhport) { (void)rhport; USB->BCDR |= USB_BCDR_DPPU; } #elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151 -void dcd_disconnect(uint8_t rhport) { +void fsdev_disconnect(uint8_t rhport) { (void)rhport; SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU); } -void dcd_connect(uint8_t rhport) { +void fsdev_connect(uint8_t rhport) { (void)rhport; SYSCFG->PMC |= SYSCFG_PMC_USB_PU; } #endif - #endif /* TUSB_FSDEV_STM32_H */ diff --git a/src/portable/st/stm32_fsdev/fsdev_type.h b/src/portable/st/stm32_fsdev/fsdev_type.h index cf36576bb..2b340d64a 100644 --- a/src/portable/st/stm32_fsdev/fsdev_type.h +++ b/src/portable/st/stm32_fsdev/fsdev_type.h @@ -174,6 +174,14 @@ typedef enum { #define EP_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) #define EP_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 0 : 8))) +#define CH_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) +#define CH_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) + +void fsdev_int_enable(uint8_t rhport); +void fsdev_int_disable(uint8_t rhport); +void fsdev_connect(uint8_t rhport); +void fsdev_disconnect(uint8_t rhport); + //--------------------------------------------------------------------+ // Endpoint Helper // - CTR is write 0 to clear @@ -186,13 +194,13 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) { TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value, bool need_exclusive) { if (need_exclusive) { - dcd_int_disable(0); + fsdev_int_disable(0); } FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value; if (need_exclusive) { - dcd_int_enable(0); + fsdev_int_enable(0); } } @@ -216,6 +224,35 @@ TU_ATTR_ALWAYS_INLINE static inline bool ep_is_iso(uint32_t reg) { return (reg & USB_EP_TYPE_MASK) == USB_EP_ISOCHRONOUS; } +//--------------------------------------------------------------------+ +// Channel Helper +// - Direction is opposite to endpoint direction +//--------------------------------------------------------------------+ + +TU_ATTR_ALWAYS_INLINE static inline uint32_t ch_read(uint32_t ch_id) { + return ep_read(ch_id); +} + +TU_ATTR_ALWAYS_INLINE static inline void ch_write(uint32_t ch_id, uint32_t value, bool need_exclusive) { + ep_write(ch_id, value, need_exclusive); +} + +TU_ATTR_ALWAYS_INLINE static inline void ch_write_clear_ctr(uint32_t ch_id, tusb_dir_t dir) { + uint32_t reg = FSDEV_REG->ep[ch_id].reg; + reg |= USB_EP_CTR_TX | USB_EP_CTR_RX; + reg &= USB_EPREG_MASK; + reg &= ~(1 << (USB_EP_CTR_TX_Pos + (dir == TUSB_DIR_IN ? 8 : 0))); + ep_write(ch_id, reg, false); +} + +TU_ATTR_ALWAYS_INLINE static inline void ch_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) { + *reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 8 : 0))); +} + +TU_ATTR_ALWAYS_INLINE static inline void ch_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) { + *reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 8 : 0))); +} + //--------------------------------------------------------------------+ // BTable Helper //--------------------------------------------------------------------+ diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c new file mode 100644 index 000000000..1c08f64d6 --- /dev/null +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -0,0 +1,833 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2025 HiFiPhile (Zixun LI) + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +/********************************************** + * This driver provides USB Host controller support for STM32 MCUs with "USB A"/"PCD"/"HCD" peripheral. + * This covers these MCU families: + * + * C0 2048 byte buffer; 32-bit bus; host mode + * G0 2048 byte buffer; 32-bit bus; host mode + * H5 2048 byte buffer; 32-bit bus; host mode + * U535, U545 2048 byte buffer; 32-bit bus; host mode + * + */ + +#include "tusb_option.h" + +#if CFG_TUH_ENABLED && defined(TUP_USBIP_FSDEV) && \ + TU_CHECK_MCU(OPT_MCU_STM32C0, OPT_MCU_STM32G0, OPT_MCU_STM32H5, OPT_MCU_STM32U5) + +#include "host/hcd.h" +#include "host/usbh.h" + +#if defined(TUP_USBIP_FSDEV_STM32) + #include "fsdev_stm32.h" +#else + #error "Unknown USB IP" +#endif + +//--------------------------------------------------------------------+ +// MACRO CONSTANT TYPEDEF +//--------------------------------------------------------------------+ + +// Debug level for FSDEV +#define FSDEV_DEBUG 1 + +// Max number of endpoints application can open, can be larger than FSDEV_EP_COUNT +#ifndef CFG_TUH_FSDEV_ENDPOINT_MAX + #define CFG_TUH_FSDEV_ENDPOINT_MAX 16u +#endif + +TU_VERIFY_STATIC(CFG_TUH_FSDEV_ENDPOINT_MAX <= 255, "currently only use 8-bit for index"); + +enum { + HCD_XFER_ERROR_MAX = 3 +}; + +// Host driver struct for each opened endpoint +typedef struct { + uint8_t *buffer; + uint16_t buflen; + uint16_t max_packet_size; + uint8_t dev_addr; + uint8_t ep_addr; + uint8_t ep_type; + uint8_t interval; + bool low_speed; + bool allocated; + bool next_setup; +} hcd_endpoint_t; + +// Additional info for each channel when it is active +typedef struct { + hcd_endpoint_t* edpt[2]; // OUT/IN + uint16_t queued_len[2]; + uint8_t dev_addr; + uint8_t ep_num; + uint8_t ep_type; + bool allocated[2]; + uint8_t retry[2]; + uint8_t result; +} hcd_xfer_t; + +// Root hub port state +static struct { + bool connected; +} _hcd_port; + +typedef struct { + hcd_xfer_t xfer[FSDEV_EP_COUNT]; + hcd_endpoint_t edpt[CFG_TUH_FSDEV_ENDPOINT_MAX]; +} hcd_data_t; + +hcd_data_t _hcd_data; + +//--------------------------------------------------------------------+ +// Prototypes +//--------------------------------------------------------------------+ + +static uint8_t endpoint_alloc(void); +static uint8_t endpoint_find(uint8_t dev_addr, uint8_t ep_addr); +static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len); +static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type); +static bool hcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes); +static bool hcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes); +static bool edpt_xfer_kickoff(uint8_t ep_id); +static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir); +static void edpoint_close(uint8_t ep_id); +static void port_status_handler(uint8_t rhport, bool in_isr); +//--------------------------------------------------------------------+ +// Inline Functions +//--------------------------------------------------------------------+ + +static inline void endpoint_dealloc(hcd_endpoint_t* edpt) { + edpt->allocated = false; +} + +static inline void channel_dealloc(hcd_xfer_t* xfer, tusb_dir_t dir) { + xfer->allocated[dir] = false; +} + +//--------------------------------------------------------------------+ +// Controller API +//--------------------------------------------------------------------+ + +// Optional HCD configuration, called by tuh_configure() +bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { + (void) rhport; + (void) cfg_id; + (void) cfg_param; + return false; +} + +// Initialize controller to host mode +bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { + (void) rh_init; + + // Follow the RM mentions to use a special ordering of PDWN and FRES + for (volatile uint32_t i = 0; i < 200; i++) { + asm("NOP"); + } + + // Perform USB peripheral reset + FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; + for (volatile uint32_t i = 0; i < 200; i++) { + asm("NOP"); + } + + FSDEV_REG->CNTR &= ~USB_CNTR_PDWN; + + // Wait startup time + for (volatile uint32_t i = 0; i < 200; i++) { + asm("NOP"); + } + + FSDEV_REG->CNTR = USB_CNTR_HOST; // Enable USB in Host mode + +#if !defined(FSDEV_BUS_32BIT) + // BTABLE register does not exist on 32-bit bus devices + FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; +#endif + + FSDEV_REG->ISTR = 0; // Clear pending interrupts + + // Reset channels to disabled + for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { + ch_write(i, 0u, false); + } + + tu_memclr(&_hcd_data, sizeof(_hcd_data)); + + // Enable interrupts for host mode + FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | + USB_CNTR_WKUPM | USB_CNTR_ERRM | USB_CNTR_PMAOVRM; + + // Initialize port state + _hcd_port.connected = false; + + fsdev_connect(rhport); + + return true; +} + +static void port_status_handler(uint8_t rhport, bool in_isr) { + uint32_t const fnr_reg = FSDEV_REG->FNR; + uint32_t const istr_reg = FSDEV_REG->ISTR; + // SE0 detected USB Disconnected state + if ((fnr_reg & (USB_FNR_RXDP | USB_FNR_RXDM)) == 0U) { + _hcd_port.connected = false; + hcd_event_device_remove(rhport, in_isr); + return; + } + + if (!_hcd_port.connected) { + // J-state or K-state detected & LastState=Disconnected + if (((fnr_reg & USB_FNR_RXDP) != 0U) || ((istr_reg & USB_ISTR_LS_DCONN) != 0U)) { + _hcd_port.connected = true; + hcd_event_device_attach(rhport, in_isr); + } + } else { + // J-state or K-state detected & lastState=Connected: a Missed disconnection is detected + if (((fnr_reg & USB_FNR_RXDP) != 0U) || ((istr_reg & USB_ISTR_LS_DCONN) != 0U)) { + _hcd_port.connected = false; + hcd_event_device_remove(rhport, in_isr); + } + } +} + +// Handle CTR interrupt for the TX/OUT direction +static void handle_ctr_tx(uint32_t ch_id) { + uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; + + uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; + uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; + + uint8_t ep_id = endpoint_find(daddr, ep_num); + TU_VERIFY(ep_id != TUSB_INDEX_INVALID_8, ); + + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + TU_VERIFY(xfer->allocated[TUSB_DIR_OUT],); + + // Manage Correct Transaction + if ((ch_reg & USB_CH_ERRTX) == 0U) { + // Acked + if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_ACK_SBUF) { + if (edpt->buflen != xfer->queued_len[TUSB_DIR_OUT]) { + uint16_t const len = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); + uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_TX); + hcd_write_packet_memory(pma_addr, &(edpt->buffer[xfer->queued_len[TUSB_DIR_OUT]]), len); + btable_set_count(ch_id, BTABLE_BUF_TX, len); + xfer->queued_len[TUSB_DIR_OUT] += len; + + ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_VALID); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // only change TX Status, reserve other toggle bits + ch_write(ch_id, ch_reg, false); + } else { + channel_dealloc(xfer, TUSB_DIR_OUT); + hcd_event_xfer_complete(daddr, ep_num, xfer->queued_len[TUSB_DIR_OUT], XFER_RESULT_SUCCESS, true); + } + } else if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_NAK) { + // NAKed + if (edpt->ep_type != TUSB_XFER_INTERRUPT) { + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // will change TX Status, reserved other toggle bits + ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_VALID); + ch_write(ch_id, ch_reg, false); + } + } else if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_STALL) { + // STALLed + channel_dealloc(xfer, TUSB_DIR_OUT); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // will change TX Status, reserved other toggle bits + ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); + ch_write(ch_id, ch_reg, false); + hcd_event_xfer_complete(daddr, ep_num, xfer->queued_len[TUSB_DIR_OUT], XFER_RESULT_STALLED, true); + } + } else { + // Error + TU_LOG(FSDEV_DEBUG, "handle_ctr_tx error epreg=0x%08X ch=%u ep=0x%02X daddr=%u queued=%u/%u\r\n", + ch_reg, ch_id, ep_num, daddr, xfer->queued_len[TUSB_DIR_OUT], edpt->buflen); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // will change TX Status, reserved other toggle bits + ch_reg &=~USB_CH_ERRTX; + if (xfer->retry[TUSB_DIR_OUT] < HCD_XFER_ERROR_MAX) { + // Retry + xfer->retry[TUSB_DIR_OUT]++; + } else { + // Failed after retries + channel_dealloc(xfer, TUSB_DIR_OUT); + ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); + hcd_event_xfer_complete(daddr, ep_num, xfer->queued_len[TUSB_DIR_OUT], XFER_RESULT_FAILED, true); + } + ch_write(ch_id, ch_reg, false); + } +} + +// Handle CTR interrupt for the RX/IN direction +static void handle_ctr_rx(uint32_t ch_id) { + uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; + uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; + + uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; + + uint8_t ep_id = endpoint_find(daddr, ep_num | TUSB_DIR_IN_MASK); + TU_VERIFY(ep_id != TUSB_INDEX_INVALID_8, ); + + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + TU_VERIFY(xfer->allocated[TUSB_DIR_IN],); + + // Manage Correct Transaction + if ((ch_reg & USB_CH_ERRRX) == 0U) { + // Acked + if ((ch_reg & USB_CH_RX_STRX) == USB_CH_RX_ACK_SBUF) { + uint16_t const rx_count = btable_get_count(ch_id, BTABLE_BUF_RX); + uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX); + + hcd_read_packet_memory(edpt->buffer + xfer->queued_len[TUSB_DIR_IN], pma_addr, rx_count); + xfer->queued_len[TUSB_DIR_IN] += rx_count; + + if ((rx_count < edpt->max_packet_size) || (xfer->queued_len[TUSB_DIR_IN] >= edpt->buflen)) { + // all bytes received or short packet + channel_dealloc(xfer, TUSB_DIR_IN); + hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len[TUSB_DIR_IN], XFER_RESULT_SUCCESS, true); + } else { + // Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always + uint16_t const cnt = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_IN], edpt->max_packet_size); + btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, cnt); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change RX Status, reserved other toggle bits + ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_VALID); + ch_write(ch_id, ch_reg, false); + } + } else if ((ch_reg & USB_CH_RX_STRX) == USB_CH_RX_NAK) { + // NAKed + if (edpt->ep_type != TUSB_XFER_INTERRUPT) { + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change TX Status, reserved other toggle bits + ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_VALID); + ch_write(ch_id, ch_reg, false); + } + } else { + // STALLed + channel_dealloc(xfer, TUSB_DIR_IN); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change TX Status, reserved other toggle bits + ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED); + ch_write(ch_id, ch_reg, false); + hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len[TUSB_DIR_IN], XFER_RESULT_STALLED, true); + } + } else { + // Error + TU_LOG(FSDEV_DEBUG, "handle_ctr_tx error epreg=0x%08X ch=%u ep=0x%02X daddr=%u queued=%u/%u\r\n", + ch_reg, ch_id, ep_num, daddr, xfer->queued_len[TUSB_DIR_IN], edpt->buflen); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change RX Status, reserved other toggle bits + ch_reg &=~USB_CH_ERRRX; + if (xfer->retry[TUSB_DIR_IN] < HCD_XFER_ERROR_MAX) { + // Retry + xfer->retry[TUSB_DIR_IN]++; + } else { + // Failed after retries + channel_dealloc(xfer, TUSB_DIR_IN); + ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED); + hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len[TUSB_DIR_IN], XFER_RESULT_FAILED, true); + } + ch_write(ch_id, ch_reg, false); + } +} + +// Interrupt Handler +void hcd_int_handler(uint8_t rhport, bool in_isr) { + uint32_t int_status = FSDEV_REG->ISTR; + + /* Port Change Detected (Connection/Disconnection) */ + if (int_status & USB_ISTR_DCON) { + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_DCON; + port_status_handler(rhport, in_isr); + } + + // Handle transfer complete (CTR) + while (FSDEV_REG->ISTR & USB_ISTR_CTR) { + uint32_t const ch_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID; + uint32_t const ch_reg = ch_read(ch_id); + + if (ch_reg & USB_EP_CTR_RX) { + #ifdef FSDEV_BUS_32BIT + /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf + * https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf + * From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers + * Description: + * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses + * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. + * Workaround: + * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay + * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode + * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code + * also takes time, so we'll wait 60 cycles (count = 20). + * - Since Low Speed mode is not supported/popular, we will ignore it for now. + * + * Note: this errata may also apply to G0, U5, H5 etc. + */ + volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver + while (cycle_count > 0U) { + cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) + } + #endif + + ch_write_clear_ctr(ch_id, TUSB_DIR_IN); + handle_ctr_rx(ch_id); + } + + if (ch_reg & USB_EP_CTR_TX) { + ch_write_clear_ctr(ch_id, TUSB_DIR_OUT); + handle_ctr_tx(ch_id); + } + } + + if (int_status & USB_ISTR_ERR) { + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_ERR; + // TODO: Handle error + } + + if (int_status & USB_ISTR_PMAOVR) { + TU_BREAKPOINT(); + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_PMAOVR; + } +} + +// Enable USB interrupt +void hcd_int_enable(uint8_t rhport) { + fsdev_int_enable(rhport); +} + +// Disable USB interrupt +void hcd_int_disable(uint8_t rhport) { + fsdev_int_disable(rhport); +} + +// Get frame number (1ms) +uint32_t hcd_frame_number(uint8_t rhport) { + (void) rhport; + return FSDEV_REG->FNR & USB_FNR_FN; +} + +//--------------------------------------------------------------------+ +// Port API +//--------------------------------------------------------------------+ + +// Get the current connect status of roothub port +bool hcd_port_connect_status(uint8_t rhport) { + (void) rhport; + return _hcd_port.connected; +} + +// Reset USB bus on the port +void hcd_port_reset(uint8_t rhport) { + (void) rhport; + FSDEV_REG->CNTR |= USB_CNTR_FRES; +} + +// Complete bus reset sequence +void hcd_port_reset_end(uint8_t rhport) { + (void) rhport; + FSDEV_REG->CNTR &= ~USB_CNTR_FRES; +} + +// Get port link speed +tusb_speed_t hcd_port_speed_get(uint8_t rhport) { + (void) rhport; + if ((FSDEV_REG->ISTR & USB_ISTR_LS_DCONN) != 0U) { + return TUSB_SPEED_LOW; + } else { + return TUSB_SPEED_FULL; + } +} + +// HCD closes all opened endpoints belonging to this device +void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { + (void) rhport; + + // Close all endpoints for this device + for(uint32_t i = 0; i < CFG_TUH_FSDEV_ENDPOINT_MAX; i++) { + hcd_endpoint_t* edpt = &_hcd_data.edpt[i]; + if (edpt->allocated && edpt->dev_addr == dev_addr) { + edpoint_close(i); + } + } + +} + +//--------------------------------------------------------------------+ +// Endpoints API +//--------------------------------------------------------------------+ + +// Open an endpoint +bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const *ep_desc) { + (void) rhport; + + uint8_t const ep_addr = ep_desc->bEndpointAddress; + uint16_t const packet_size = tu_edpt_packet_size(ep_desc); + uint8_t const ep_type = ep_desc->bmAttributes.xfer; + + uint8_t const ep_id = endpoint_alloc(); + TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; + edpt->dev_addr = dev_addr; + edpt->ep_addr = ep_addr; + edpt->ep_type = ep_type; + edpt->max_packet_size = packet_size; + edpt->interval = ep_desc->bInterval; + edpt->low_speed = (hcd_port_speed_get(rhport) == TUSB_SPEED_FULL && tuh_speed_get(dev_addr) == TUSB_SPEED_LOW); + + // EP0 is bi-directional, so we need to open both OUT and IN channels + if (ep_addr == 0) { + uint8_t const ep_id_in = endpoint_alloc(); + TU_ASSERT(ep_id_in < CFG_TUH_FSDEV_ENDPOINT_MAX); + + _hcd_data.edpt[ep_id_in] = *edpt; // copy from OUT endpoint + _hcd_data.edpt[ep_id_in].ep_addr = 0 | TUSB_DIR_IN_MASK; + } + + return true; +} + +bool hcd_edpt_close(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + + uint8_t const ep_id = endpoint_find(dev_addr, ep_addr); + TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + + edpoint_close(ep_id); + + if (ep_addr == 0) { + uint8_t const ep_id_in = endpoint_find(dev_addr, 0 | TUSB_DIR_IN_MASK); + TU_ASSERT(ep_id_in < CFG_TUH_FSDEV_ENDPOINT_MAX); + + edpoint_close(ep_id_in); + } + + return false; +} + +// Submit a transfer +bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) { + (void) rhport; + + TU_LOG(FSDEV_DEBUG, "hcd_edpt_xfer addr=%u ep=0x%02X len=%u\r\n", dev_addr, ep_addr, buflen); + + uint8_t const ep_id = endpoint_find(dev_addr, ep_addr); + TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + + hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; + + edpt->buffer = buffer; + edpt->buflen = buflen; + + return edpt_xfer_kickoff(ep_id); +} + +// Abort a queued transfer +bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + + uint8_t const ep_id = endpoint_find(dev_addr, ep_addr); + TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + + for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { + hcd_xfer_t* xfer = &_hcd_data.xfer[i]; + + if (xfer->allocated[dir] && + xfer->dev_addr == dev_addr && + xfer->ep_num == tu_edpt_number(ep_addr)) { + + channel_dealloc(xfer, dir); + + uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir); // will change Status, reserved other toggle bits + ch_change_status(&ch_reg, dir, EP_STAT_DISABLED); + ch_write(i, ch_reg, true); + + } + } + + return true; +} + +// Submit a special transfer to send 8-byte Setup Packet +bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) { + (void) rhport; + + uint8_t const ep_id = endpoint_find(dev_addr, 0); + TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + + hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; + edpt->next_setup = true; + + return hcd_edpt_xfer(rhport, dev_addr, 0, (uint8_t*)(uintptr_t) setup_packet, 8); +} + +// Clear stall, data toggle is also reset to DATA0 +bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { + (void) rhport; + (void) dev_addr; + (void) ep_addr; + + return true; +} + +//--------------------------------------------------------------------+ +// Helper Functions +//--------------------------------------------------------------------+ + +static uint8_t endpoint_alloc(void) { + for (uint32_t i = 0; i < CFG_TUH_FSDEV_ENDPOINT_MAX; i++) { + hcd_endpoint_t* edpt = &_hcd_data.edpt[i]; + if (!edpt->allocated) { + edpt->allocated = true; + return i; + } + } + return TUSB_INDEX_INVALID_8; +} + +static uint8_t endpoint_find(uint8_t dev_addr, uint8_t ep_addr) { + for (uint32_t i = 0; i < (uint32_t)CFG_TUH_FSDEV_ENDPOINT_MAX; i++) { + hcd_endpoint_t* edpt = &_hcd_data.edpt[i]; + if (edpt->allocated && edpt->dev_addr == dev_addr && edpt->ep_addr == ep_addr) { + return i; + } + } + return TUSB_INDEX_INVALID_8; +} + +// close an opened endpoint +static void edpoint_close(uint8_t ep_id) { + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; + endpoint_dealloc(edpt); + + // disable active channel belong to this endpoint + for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { + hcd_xfer_t* xfer = &_hcd_data.xfer[i]; + + if (xfer->allocated[TUSB_DIR_OUT] && xfer->edpt[TUSB_DIR_OUT] == edpt) { + channel_dealloc(xfer, TUSB_DIR_OUT); + + uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits + ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); + ch_write(i, ch_reg, true); + + } + if (xfer->allocated[TUSB_DIR_IN] && xfer->edpt[TUSB_DIR_IN] == edpt) { + channel_dealloc(xfer, TUSB_DIR_IN); + + uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change TX Status, reserved other toggle bits + ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED); + ch_write(i, ch_reg, true); + + } + } +} + +// Allocate PMA buffer +static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len) { + (void) len; + // Simple static allocation as we are unlikely to handle ISO endpoints in host mode + // We just give each channel a buffer of max packet size (64 bytes) + + uint16_t addr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT; + addr += channel * 64 * 2 + (dir == TUSB_DIR_IN ? 64 : 0); + + TU_ASSERT(addr <= FSDEV_PMA_SIZE, 0xFFFF); + + return addr; +} + +// Allocate hardware channel +static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type) { + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const dir = tu_edpt_dir(ep_addr); + + // Find channel allocate for same ep_num but other direction + tusb_dir_t const other_dir = (dir == TUSB_DIR_IN) ? TUSB_DIR_OUT : TUSB_DIR_IN; + for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { + if (!_hcd_data.xfer[i].allocated[dir] && + _hcd_data.xfer[i].allocated[other_dir] && + _hcd_data.xfer[i].dev_addr == dev_addr && + _hcd_data.xfer[i].ep_num == ep_num && + _hcd_data.xfer[i].ep_type == ep_type) { + _hcd_data.xfer[i].allocated[dir] = true; + _hcd_data.xfer[i].queued_len[dir] = 0; + _hcd_data.xfer[i].retry[dir] = 0; + return i; + } + } + + // Find free channel + for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { + if (!_hcd_data.xfer[i].allocated[0] && !_hcd_data.xfer[i].allocated[1]) { + _hcd_data.xfer[i].dev_addr = dev_addr; + _hcd_data.xfer[i].ep_num = ep_num; + _hcd_data.xfer[i].ep_type = ep_type; + _hcd_data.xfer[i].allocated[dir] = true; + _hcd_data.xfer[i].queued_len[dir] = 0; + _hcd_data.xfer[i].retry[dir] = 0; + return i; + } + } + + // Allocation failed + return TUSB_INDEX_INVALID_8; +} + +// kick-off transfer with an endpoint +static bool edpt_xfer_kickoff(uint8_t ep_id) { + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; + uint8_t ch_id = channel_alloc(edpt->dev_addr, edpt->ep_addr, edpt->ep_type); + TU_ASSERT(ch_id != TUSB_INDEX_INVALID_8); // all channel are in used + + tusb_dir_t const dir = tu_edpt_dir(edpt->ep_addr); + + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + xfer->edpt[dir] = edpt; + + return channel_xfer_start(ch_id, dir); +} + +static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) { + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + hcd_endpoint_t* edpt = xfer->edpt[dir]; + + uint32_t ch_reg = ch_read(ch_id) & ~USB_EPREG_MASK; + ch_reg |= tu_edpt_number(edpt->ep_addr) | edpt->dev_addr << USB_CHEP_DEVADDR_Pos | + USB_EP_CTR_TX | USB_EP_CTR_RX; + + // Set type + switch (edpt->ep_type) { + case TUSB_XFER_BULK: + ch_reg |= USB_EP_BULK; + break; + case TUSB_XFER_INTERRUPT: + ch_reg |= USB_EP_INTERRUPT; + break; + + case TUSB_XFER_CONTROL: + ch_reg |= USB_EP_CONTROL; + break; + + default: + // Note: ISO endpoint is unsupported + TU_ASSERT(false); + } + + /* Create a packet memory buffer area. */ + uint16_t pma_addr = hcd_pma_alloc(ch_id, dir, edpt->max_packet_size); + btable_set_addr(ch_id, dir == TUSB_DIR_OUT ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr); + + if (dir == TUSB_DIR_OUT) { + uint16_t const len = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); + + hcd_write_packet_memory(pma_addr, &(edpt->buffer[xfer->queued_len[TUSB_DIR_OUT]]), len); + btable_set_count(ch_id, BTABLE_BUF_TX, len); + + xfer->queued_len[TUSB_DIR_OUT] += len; + if (edpt->next_setup) { + // Setup packet uses IN token + edpt->next_setup = false; + ch_reg |= USB_EP_SETUP; + } + + ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_VALID); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // only change TX Status, reserve other toggle bits + + } else { + btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, edpt->max_packet_size); + ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_VALID); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change RX Status, reserved other toggle bits + } + + ch_write(ch_id, ch_reg, true); + + return true; +} + +//--------------------------------------------------------------------+ +// PMA read/write +//--------------------------------------------------------------------+ + +// Write to packet memory area (PMA) from user memory +static bool hcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) { + if (nbytes == 0) return true; + uint32_t n_write = nbytes / FSDEV_BUS_SIZE; + + fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(dst); + const uint8_t *src8 = src; + + while (n_write--) { + pma_buf->value = fsdevbus_unaligned_read(src8); + src8 += FSDEV_BUS_SIZE; + pma_buf++; + } + + // Handle odd bytes + uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); + if (odd) { + fsdev_bus_t temp = 0; + for (uint16_t i = 0; i < odd; i++) { + temp |= *src8++ << (i * 8); + } + pma_buf->value = temp; + } + + return true; +} + +// Read from packet memory area (PMA) to user memory +static bool hcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) { + if (nbytes == 0) return true; + uint32_t n_read = nbytes / FSDEV_BUS_SIZE; + + fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(src); + uint8_t *dst8 = (uint8_t *)dst; + + while (n_read--) { + fsdevbus_unaligned_write(dst8, (fsdev_bus_t) pma_buf->value); + dst8 += FSDEV_BUS_SIZE; + pma_buf++; + } + + // Handle odd bytes + uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); + if (odd) { + fsdev_bus_t temp = pma_buf->value; + while (odd--) { + *dst8++ = (uint8_t)(temp & 0xfful); + temp >>= 8; + } + } + + return true; +} + +#endif From 03bd8c26d6b72b5e53c0d4b9787a6396ee295927 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Mon, 24 Nov 2025 21:03:04 +0100 Subject: [PATCH 03/21] fsdev: reorganize functions Signed-off-by: HiFiPhile --- examples/host/bare_api/only.txt | 1 + examples/host/cdc_msc_hid/only.txt | 1 + examples/host/cdc_msc_hid_freertos/only.txt | 1 + hw/bsp/at32f403a_407/family.cmake | 1 + hw/bsp/at32f403a_407/family.mk | 1 + hw/bsp/at32f413/family.cmake | 1 + hw/bsp/at32f413/family.mk | 1 + hw/bsp/ch32v20x/family.cmake | 1 + hw/bsp/ch32v20x/family.mk | 1 + hw/bsp/stm32c0/family.cmake | 1 + hw/bsp/stm32c0/family.mk | 1 + hw/bsp/stm32f0/family.cmake | 1 + hw/bsp/stm32f0/family.mk | 1 + hw/bsp/stm32f1/family.cmake | 1 + hw/bsp/stm32f1/family.mk | 1 + hw/bsp/stm32f3/family.cmake | 1 + hw/bsp/stm32f3/family.mk | 1 + hw/bsp/stm32g0/family.cmake | 1 + hw/bsp/stm32g0/family.mk | 2 + hw/bsp/stm32g4/family.cmake | 1 + hw/bsp/stm32g4/family.mk | 1 + hw/bsp/stm32h5/family.cmake | 1 + hw/bsp/stm32h5/family.mk | 2 + hw/bsp/stm32l0/family.cmake | 1 + hw/bsp/stm32l0/family.mk | 1 + hw/bsp/stm32l4/family.cmake | 1 + hw/bsp/stm32l4/family.mk | 1 + hw/bsp/stm32u0/family.cmake | 1 + hw/bsp/stm32u0/family.mk | 1 + hw/bsp/stm32u5/family.cmake | 2 + hw/bsp/stm32u5/family.mk | 6 +- hw/bsp/stm32wb/family.cmake | 1 + hw/bsp/stm32wb/family.mk | 1 + lib/rt-thread/SConscript | 3 +- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 190 +------- src/portable/st/stm32_fsdev/fsdev_at32.h | 10 +- src/portable/st/stm32_fsdev/fsdev_ch32.h | 10 +- src/portable/st/stm32_fsdev/fsdev_common.c | 241 ++++++++++ .../{fsdev_type.h => fsdev_common.h} | 93 ++-- src/portable/st/stm32_fsdev/fsdev_stm32.h | 14 +- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 426 ++++++++---------- tools/iar_template.ipcf | 4 +- 42 files changed, 548 insertions(+), 484 deletions(-) create mode 100644 src/portable/st/stm32_fsdev/fsdev_common.c rename src/portable/st/stm32_fsdev/{fsdev_type.h => fsdev_common.h} (85%) diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt index cba58f8e8..a7bebf1d9 100644 --- a/examples/host/bare_api/only.txt +++ b/examples/host/bare_api/only.txt @@ -13,6 +13,7 @@ mcu:MSP432E4 mcu:RX65X mcu:RAXXX mcu:MAX3421 +mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 mcu:STM32H7 diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt index cba58f8e8..a7bebf1d9 100644 --- a/examples/host/cdc_msc_hid/only.txt +++ b/examples/host/cdc_msc_hid/only.txt @@ -13,6 +13,7 @@ mcu:MSP432E4 mcu:RX65X mcu:RAXXX mcu:MAX3421 +mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 mcu:STM32H7 diff --git a/examples/host/cdc_msc_hid_freertos/only.txt b/examples/host/cdc_msc_hid_freertos/only.txt index ef0a1ac96..8da7a47d6 100644 --- a/examples/host/cdc_msc_hid_freertos/only.txt +++ b/examples/host/cdc_msc_hid_freertos/only.txt @@ -9,6 +9,7 @@ mcu:MIMXRT11XX mcu:MSP432E4 mcu:RX65X mcu:MAX3421 +mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 mcu:STM32H7 diff --git a/hw/bsp/at32f403a_407/family.cmake b/hw/bsp/at32f403a_407/family.cmake index 498b89c1a..7aaa9ede8 100644 --- a/hw/bsp/at32f403a_407/family.cmake +++ b/hw/bsp/at32f403a_407/family.cmake @@ -61,6 +61,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${AT32_FAMILY}_clock.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${AT32_FAMILY}_int.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/at32f403a_407/family.mk b/hw/bsp/at32f403a_407/family.mk index c82d402ca..f458881a3 100644 --- a/hw/bsp/at32f403a_407/family.mk +++ b/hw/bsp/at32f403a_407/family.mk @@ -16,6 +16,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_gpio.c \ $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_misc.c \ $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_usart.c \ diff --git a/hw/bsp/at32f413/family.cmake b/hw/bsp/at32f413/family.cmake index 02692daf5..33718bd1c 100644 --- a/hw/bsp/at32f413/family.cmake +++ b/hw/bsp/at32f413/family.cmake @@ -61,6 +61,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${AT32_FAMILY}_clock.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${AT32_FAMILY}_int.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/at32f413/family.mk b/hw/bsp/at32f413/family.mk index 9c5d867de..abcd15d11 100644 --- a/hw/bsp/at32f413/family.mk +++ b/hw/bsp/at32f413/family.mk @@ -16,6 +16,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_gpio.c \ $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_misc.c \ $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_usart.c \ diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake index d8c7c5327..59a96f70d 100644 --- a/hw/bsp/ch32v20x/family.cmake +++ b/hw/bsp/ch32v20x/family.cmake @@ -93,6 +93,7 @@ function(family_configure_example TARGET RTOS) ${TOP}/src/portable/wch/dcd_ch32_usbfs.c ${TOP}/src/portable/wch/hcd_ch32_usbfs.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk index 16fc537ac..7042ecbb7 100644 --- a/hw/bsp/ch32v20x/family.mk +++ b/hw/bsp/ch32v20x/family.mk @@ -47,6 +47,7 @@ SRC_C += \ src/portable/wch/dcd_ch32_usbfs.c \ src/portable/wch/hcd_ch32_usbfs.c \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(SDK_SRC_DIR)/Core/core_riscv.c \ $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_gpio.c \ $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_misc.c \ diff --git a/hw/bsp/stm32c0/family.cmake b/hw/bsp/stm32c0/family.cmake index 6e04b20f4..dc1a2bb13 100644 --- a/hw/bsp/stm32c0/family.cmake +++ b/hw/bsp/stm32c0/family.cmake @@ -67,6 +67,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c ${TOP}/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${TOP}/src/portable/st/typec/typec_stm32.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) diff --git a/hw/bsp/stm32c0/family.mk b/hw/bsp/stm32c0/family.mk index fd03ad537..71209bf2e 100644 --- a/hw/bsp/stm32c0/family.mk +++ b/hw/bsp/stm32c0/family.mk @@ -30,6 +30,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/hw/bsp/stm32f0/family.cmake b/hw/bsp/stm32f0/family.cmake index ee73ae872..a926a9739 100644 --- a/hw/bsp/stm32f0/family.cmake +++ b/hw/bsp/stm32f0/family.cmake @@ -65,6 +65,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/stm32f0/family.mk b/hw/bsp/stm32f0/family.mk index 9b8305874..b5efdcb8d 100644 --- a/hw/bsp/stm32f0/family.mk +++ b/hw/bsp/stm32f0/family.mk @@ -30,6 +30,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/hw/bsp/stm32f1/family.cmake b/hw/bsp/stm32f1/family.cmake index 064f32096..9e94d86c6 100644 --- a/hw/bsp/stm32f1/family.cmake +++ b/hw/bsp/stm32f1/family.cmake @@ -62,6 +62,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/stm32f1/family.mk b/hw/bsp/stm32f1/family.mk index ca95f2315..d4b6dfa6c 100644 --- a/hw/bsp/stm32f1/family.mk +++ b/hw/bsp/stm32f1/family.mk @@ -27,6 +27,7 @@ LDFLAGS_GCC += \ # ------------------------ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ ${ST_CMSIS}/Source/Templates/system_stm32${ST_FAMILY}xx.c \ ${ST_HAL_DRIVER}/Src/stm32${ST_FAMILY}xx_hal.c \ ${ST_HAL_DRIVER}/Src/stm32${ST_FAMILY}xx_hal_cortex.c \ diff --git a/hw/bsp/stm32f3/family.cmake b/hw/bsp/stm32f3/family.cmake index 7c9e97e62..3cbb4e1cd 100644 --- a/hw/bsp/stm32f3/family.cmake +++ b/hw/bsp/stm32f3/family.cmake @@ -62,6 +62,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/stm32f3/family.mk b/hw/bsp/stm32f3/family.mk index 13734583a..eb4a4e186 100644 --- a/hw/bsp/stm32f3/family.mk +++ b/hw/bsp/stm32f3/family.mk @@ -19,6 +19,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/hw/bsp/stm32g0/family.cmake b/hw/bsp/stm32g0/family.cmake index 572f0e644..0ce85168e 100644 --- a/hw/bsp/stm32g0/family.cmake +++ b/hw/bsp/stm32g0/family.cmake @@ -64,6 +64,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${TOP}/src/portable/st/typec/typec_stm32.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) diff --git a/hw/bsp/stm32g0/family.mk b/hw/bsp/stm32g0/family.mk index d735ca92d..e376f7f06 100644 --- a/hw/bsp/stm32g0/family.mk +++ b/hw/bsp/stm32g0/family.mk @@ -29,6 +29,8 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/hw/bsp/stm32g4/family.cmake b/hw/bsp/stm32g4/family.cmake index 7e8b319b8..85201ce61 100644 --- a/hw/bsp/stm32g4/family.cmake +++ b/hw/bsp/stm32g4/family.cmake @@ -62,6 +62,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${TOP}/src/portable/st/typec/typec_stm32.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) diff --git a/hw/bsp/stm32g4/family.mk b/hw/bsp/stm32g4/family.mk index 0abd73532..a153194ce 100644 --- a/hw/bsp/stm32g4/family.mk +++ b/hw/bsp/stm32g4/family.mk @@ -29,6 +29,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ src/portable/st/typec/typec_stm32.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ diff --git a/hw/bsp/stm32h5/family.cmake b/hw/bsp/stm32h5/family.cmake index 6e63c4072..d6f356ddf 100644 --- a/hw/bsp/stm32h5/family.cmake +++ b/hw/bsp/stm32h5/family.cmake @@ -66,6 +66,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${TOP}/src/portable/st/typec/typec_stm32.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) diff --git a/hw/bsp/stm32h5/family.mk b/hw/bsp/stm32h5/family.mk index 792edb2bb..ec5f82d61 100644 --- a/hw/bsp/stm32h5/family.mk +++ b/hw/bsp/stm32h5/family.mk @@ -36,6 +36,8 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/hw/bsp/stm32l0/family.cmake b/hw/bsp/stm32l0/family.cmake index b6b0139a0..3f6622f71 100644 --- a/hw/bsp/stm32l0/family.cmake +++ b/hw/bsp/stm32l0/family.cmake @@ -66,6 +66,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/stm32l0/family.mk b/hw/bsp/stm32l0/family.mk index 921b1b413..0ae881fdf 100644 --- a/hw/bsp/stm32l0/family.mk +++ b/hw/bsp/stm32l0/family.mk @@ -27,6 +27,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/hw/bsp/stm32l4/family.cmake b/hw/bsp/stm32l4/family.cmake index 5bc28dd5d..b1659d47a 100644 --- a/hw/bsp/stm32l4/family.cmake +++ b/hw/bsp/stm32l4/family.cmake @@ -67,6 +67,7 @@ function(family_configure_example TARGET RTOS) ${TOP}/src/portable/synopsys/dwc2/hcd_dwc2.c ${TOP}/src/portable/synopsys/dwc2/dwc2_common.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/stm32l4/family.mk b/hw/bsp/stm32l4/family.mk index 01d059236..fd11fd226 100644 --- a/hw/bsp/stm32l4/family.mk +++ b/hw/bsp/stm32l4/family.mk @@ -34,6 +34,7 @@ SRC_C += \ src/portable/synopsys/dwc2/hcd_dwc2.c \ src/portable/synopsys/dwc2/dwc2_common.c \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/hw/bsp/stm32u0/family.cmake b/hw/bsp/stm32u0/family.cmake index 4f9b03109..2d3819cba 100644 --- a/hw/bsp/stm32u0/family.cmake +++ b/hw/bsp/stm32u0/family.cmake @@ -67,6 +67,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/stm32u0/family.mk b/hw/bsp/stm32u0/family.mk index d5a850050..5f25906d3 100644 --- a/hw/bsp/stm32u0/family.mk +++ b/hw/bsp/stm32u0/family.mk @@ -27,6 +27,7 @@ LDFLAGS_GCC += \ SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_stm32$(ST_FAMILY)xx.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_cortex.c \ diff --git a/hw/bsp/stm32u5/family.cmake b/hw/bsp/stm32u5/family.cmake index 70e0c313c..58dc63ae3 100644 --- a/hw/bsp/stm32u5/family.cmake +++ b/hw/bsp/stm32u5/family.cmake @@ -66,6 +66,8 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${TOP}/src/portable/synopsys/dwc2/dcd_dwc2.c ${TOP}/src/portable/synopsys/dwc2/hcd_dwc2.c ${TOP}/src/portable/synopsys/dwc2/dwc2_common.c diff --git a/hw/bsp/stm32u5/family.mk b/hw/bsp/stm32u5/family.mk index 3694b1ca0..79f181a68 100644 --- a/hw/bsp/stm32u5/family.mk +++ b/hw/bsp/stm32u5/family.mk @@ -39,10 +39,12 @@ SRC_C += \ ifeq ($(MCU_VARIANT),stm32u545xx) SRC_C += \ - src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c else ifeq ($(MCU_VARIANT),stm32u535xx) SRC_C += \ - src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c else SRC_C += \ src/portable/synopsys/dwc2/dcd_dwc2.c \ diff --git a/hw/bsp/stm32wb/family.cmake b/hw/bsp/stm32wb/family.cmake index 1a96e3d7e..6703a9b19 100644 --- a/hw/bsp/stm32wb/family.cmake +++ b/hw/bsp/stm32wb/family.cmake @@ -67,6 +67,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${TARGET} PUBLIC diff --git a/hw/bsp/stm32wb/family.mk b/hw/bsp/stm32wb/family.mk index a80ff6f5b..0b1a51cec 100644 --- a/hw/bsp/stm32wb/family.mk +++ b/hw/bsp/stm32wb/family.mk @@ -20,6 +20,7 @@ LDFLAGS_GCC += -specs=nosys.specs -specs=nano.specs SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ + src/portable/st/stm32_fsdev/fsdev_common.c \ $(ST_CMSIS)/Source/Templates/system_${ST_PREFIX}.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal.c \ $(ST_HAL_DRIVER)/Src/${ST_PREFIX}_hal_cortex.c \ diff --git a/lib/rt-thread/SConscript b/lib/rt-thread/SConscript index 99517a090..e7b6f2dc4 100644 --- a/lib/rt-thread/SConscript +++ b/lib/rt-thread/SConscript @@ -18,7 +18,8 @@ if GetDepend(["PKG_TINYUSB_DEVICE_ENABLE"]): # BSP if GetDepend(["SOC_FAMILY_STM32"]): src += ["../../src/portable/synopsys/dwc2/dcd_dwc2.c", - "../../src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c"] + "../../src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c", + "../../src/portable/st/stm32_fsdev/fsdev_common.c"] if GetDepend(["SOC_NRF52840"]): src += ["../../src/portable/nordic/nrf5x/dcd_nrf5x.c"] diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index db1a5784a..3762b33f9 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -112,16 +112,7 @@ !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0) #include "device/dcd.h" - -#if defined(TUP_USBIP_FSDEV_STM32) - #include "fsdev_stm32.h" -#elif defined(TUP_USBIP_FSDEV_CH32) - #include "fsdev_ch32.h" -#elif defined(TUP_USBIP_FSDEV_AT32) - #include "fsdev_at32.h" -#else - #error "Unknown USB IP" -#endif +#include "fsdev_common.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF @@ -162,11 +153,6 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir); static uint16_t ep_buf_ptr; ///< Points to first free memory location static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf); static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type); -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes); -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes); - -static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes); -static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes); static void edpt0_open(uint8_t rhport); @@ -307,7 +293,7 @@ static void handle_ctr_setup(uint32_t ep_id) { uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX); uint8_t setup_packet[8] TU_ATTR_ALIGNED(4); - dcd_read_packet_memory(setup_packet, rx_addr, rx_count); + fsdev_read_packet_memory(setup_packet, rx_addr, rx_count); // Clear CTR RX if another setup packet arrived before this, it will be discarded ep_write_clear_ctr(ep_id, TUSB_DIR_OUT); @@ -345,9 +331,9 @@ static void handle_ctr_rx(uint32_t ep_id) { uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id); if (xfer->ff) { - dcd_read_packet_memory_ff(xfer->ff, pma_addr, rx_count); + fsdev_read_packet_memory_ff(xfer->ff, pma_addr, rx_count); } else { - dcd_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count); + fsdev_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count); } xfer->queued_len += rx_count; @@ -742,9 +728,9 @@ static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) { uint16_t addr_ptr = (uint16_t) btable_get_addr(ep_ix, buf_id); if (xfer->ff) { - dcd_write_packet_memory_ff(xfer->ff, addr_ptr, len); + fsdev_write_packet_memory_ff(xfer->ff, addr_ptr, len); } else { - dcd_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); + fsdev_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len); } xfer->queued_len += len; @@ -864,168 +850,4 @@ void dcd_disconnect(uint8_t rhport) { } #endif -//--------------------------------------------------------------------+ -// PMA read/write -//--------------------------------------------------------------------+ - -// Write to packet memory area (PMA) from user memory -// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT -// - Uses unaligned for RAM (since M0 cannot access unaligned address) -static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) { - if (nbytes == 0) return true; - uint32_t n_write = nbytes / FSDEV_BUS_SIZE; - - fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst); - const uint8_t *src8 = src; - - while (n_write--) { - pma_buf->value = fsdevbus_unaligned_read(src8); - src8 += FSDEV_BUS_SIZE; - pma_buf++; - } - - // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit - uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); - if (odd) { - fsdev_bus_t temp = 0; - for(uint16_t i = 0; i < odd; i++) { - temp |= *src8++ << (i * 8); - } - pma_buf->value = temp; - } - - return true; -} - -// Read from packet memory area (PMA) to user memory. -// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT -// - Uses unaligned for RAM (since M0 cannot access unaligned address) -static bool dcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) { - if (nbytes == 0) return true; - uint32_t n_read = nbytes / FSDEV_BUS_SIZE; - - fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src); - uint8_t *dst8 = (uint8_t *)dst; - - while (n_read--) { - fsdevbus_unaligned_write(dst8, (fsdev_bus_t ) pma_buf->value); - dst8 += FSDEV_BUS_SIZE; - pma_buf++; - } - - // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit - uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); - if (odd) { - fsdev_bus_t temp = pma_buf->value; - while (odd--) { - *dst8++ = (uint8_t) (temp & 0xfful); - temp >>= 8; - } - } - - return true; -} - -// Write to PMA from FIFO -static bool dcd_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) { - if (wNBytes == 0) return true; - - // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies - tu_fifo_buffer_info_t info; - tu_fifo_get_read_info(ff, &info); - - uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin); - uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap); - uint16_t const cnt_total = cnt_lin + cnt_wrap; - - // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, - // last lin byte will be combined with wrapped part To ensure PMA is always access aligned - uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); - uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); - uint8_t const *src8 = (uint8_t const*) info.ptr_lin; - - // write even linear part - dcd_write_packet_memory(dst, src8, lin_even); - dst += lin_even; - src8 += lin_even; - - if (lin_odd == 0) { - src8 = (uint8_t const*) info.ptr_wrap; - } else { - // Combine last linear bytes + first wrapped bytes to form fsdev bus width data - fsdev_bus_t temp = 0; - uint16_t i; - for(i = 0; i < lin_odd; i++) { - temp |= *src8++ << (i * 8); - } - - src8 = (uint8_t const*) info.ptr_wrap; - for(; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { - temp |= *src8++ << (i * 8); - } - - dcd_write_packet_memory(dst, &temp, FSDEV_BUS_SIZE); - dst += FSDEV_BUS_SIZE; - } - - // write the rest of the wrapped part - dcd_write_packet_memory(dst, src8, cnt_wrap); - - tu_fifo_advance_read_pointer(ff, cnt_total); - return true; -} - -// Read from PMA to FIFO -static bool dcd_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) { - if (wNBytes == 0) return true; - - // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies - // Check for first linear part - tu_fifo_buffer_info_t info; - tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO - - uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin); - uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap); - uint16_t cnt_total = cnt_lin + cnt_wrap; - - // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, - // last lin byte will be combined with wrapped part To ensure PMA is always access aligned - - uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); - uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); - uint8_t *dst8 = (uint8_t *) info.ptr_lin; - - // read even linear part - dcd_read_packet_memory(dst8, src, lin_even); - dst8 += lin_even; - src += lin_even; - - if (lin_odd == 0) { - dst8 = (uint8_t *) info.ptr_wrap; - } else { - // Combine last linear bytes + first wrapped bytes to form fsdev bus width data - fsdev_bus_t temp; - dcd_read_packet_memory(&temp, src, FSDEV_BUS_SIZE); - src += FSDEV_BUS_SIZE; - - uint16_t i; - for (i = 0; i < lin_odd; i++) { - *dst8++ = (uint8_t) (temp & 0xfful); - temp >>= 8; - } - - dst8 = (uint8_t *) info.ptr_wrap; - for (; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { - *dst8++ = (uint8_t) (temp & 0xfful); - temp >>= 8; - } - } - - // read the rest of the wrapped part - dcd_read_packet_memory(dst8, src, cnt_wrap); - - tu_fifo_advance_write_pointer(ff, cnt_total); - return true; -} - #endif diff --git a/src/portable/st/stm32_fsdev/fsdev_at32.h b/src/portable/st/stm32_fsdev/fsdev_at32.h index 03490ee24..6877dc131 100644 --- a/src/portable/st/stm32_fsdev/fsdev_at32.h +++ b/src/portable/st/stm32_fsdev/fsdev_at32.h @@ -150,8 +150,6 @@ #define USB_EPRX_DTOG2 ((uint16_t)0x2000U) /*!< EndPoint RX Data TOGgle bit1 */ #define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK) -#include "fsdev_type.h" - //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ @@ -168,7 +166,7 @@ enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; #error "Unsupported MCU" #endif -void fsdev_int_enable(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_enable(uint8_t rhport) { (void)rhport; #if (CFG_TUSB_MCU == OPT_MCU_AT32F403A_407) || (CFG_TUSB_MCU == OPT_MCU_AT32F413) // AT32F403A/407 devices allow to remap the USB interrupt vectors from @@ -187,7 +185,7 @@ void fsdev_int_enable(uint8_t rhport) { } } -void fsdev_int_disable(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) { (void)rhport; #if (CFG_TUSB_MCU == OPT_MCU_AT32F403A_407) || (CFG_TUSB_MCU == OPT_MCU_AT32F413) // AT32F403A/407 devices allow to remap the USB interrupt vectors from @@ -206,7 +204,7 @@ void fsdev_int_disable(uint8_t rhport) { } } -void fsdev_disconnect(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) { (void) rhport; /* disable usb phy */ *(volatile uint32_t*)(FSDEV_REG_BASE + 0x40) |= USB_CNTR_PDWN; @@ -214,7 +212,7 @@ void fsdev_disconnect(uint8_t rhport) { *(volatile uint32_t *)(FSDEV_REG_BASE+0x60) |= (1u<<1); } -void fsdev_connect(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) { (void) rhport; /* enable usb phy */ *(volatile uint32_t*)(FSDEV_REG_BASE + 0x40) &= ~USB_CNTR_PDWN; diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h index 547f3bd1b..ee0057cb4 100644 --- a/src/portable/st/stm32_fsdev/fsdev_ch32.h +++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h @@ -168,8 +168,6 @@ #define USB_EPRX_DTOG2 ((uint16_t)0x2000U) /*!< EndPoint RX Data TOGgle bit1 */ #define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK) -#include "fsdev_type.h" - //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ @@ -185,26 +183,26 @@ enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; #error "Unsupported MCU" #endif -void fsdev_int_enable(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_enable(uint8_t rhport) { (void)rhport; for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) { NVIC_EnableIRQ(fsdev_irq[i]); } } -void fsdev_int_disable(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) { (void)rhport; for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) { NVIC_DisableIRQ(fsdev_irq[i]); } } -void fsdev_disconnect(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) { (void) rhport; EXTEN->EXTEN_CTR &= ~EXTEN_USBD_PU_EN; } -void fsdev_connect(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) { (void) rhport; EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN; } diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c new file mode 100644 index 000000000..d021a6abf --- /dev/null +++ b/src/portable/st/stm32_fsdev/fsdev_common.c @@ -0,0 +1,241 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Ha Thach (tinyusb.org) + * Copyright (c) 2025, HiFiPhile (Zixun LI) + * + * 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. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if defined(TUP_USBIP_FSDEV) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED) + +#include "fsdev_common.h" + +//--------------------------------------------------------------------+ +// PMA read/write +//--------------------------------------------------------------------+ + +// Write to packet memory area (PMA) from user memory +// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT +// - Uses unaligned for RAM (since M0 cannot access unaligned address) +bool fsdev_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) { + if (nbytes == 0) return true; + uint32_t n_write = nbytes / FSDEV_BUS_SIZE; + + fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst); + const uint8_t *src8 = src; + + while (n_write--) { + pma_buf->value = fsdevbus_unaligned_read(src8); + src8 += FSDEV_BUS_SIZE; + pma_buf++; + } + + // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit + uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); + if (odd) { + fsdev_bus_t temp = 0; + for(uint16_t i = 0; i < odd; i++) { + temp |= *src8++ << (i * 8); + } + pma_buf->value = temp; + } + + return true; +} + +// Read from packet memory area (PMA) to user memory. +// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT +// - Uses unaligned for RAM (since M0 cannot access unaligned address) +bool fsdev_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) { + if (nbytes == 0) return true; + uint32_t n_read = nbytes / FSDEV_BUS_SIZE; + + fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src); + uint8_t *dst8 = (uint8_t *)dst; + + while (n_read--) { + fsdevbus_unaligned_write(dst8, (fsdev_bus_t ) pma_buf->value); + dst8 += FSDEV_BUS_SIZE; + pma_buf++; + } + + // odd bytes e.g 1 for 16-bit or 1-3 for 32-bit + uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); + if (odd) { + fsdev_bus_t temp = pma_buf->value; + while (odd--) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; + } + } + + return true; +} + +// Write to PMA from FIFO +bool fsdev_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) { + if (wNBytes == 0) return true; + + // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + tu_fifo_buffer_info_t info; + tu_fifo_get_read_info(ff, &info); + + uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin); + uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap); + uint16_t const cnt_total = cnt_lin + cnt_wrap; + + // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, + // last lin byte will be combined with wrapped part To ensure PMA is always access aligned + uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); + uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); + uint8_t const *src8 = (uint8_t const*) info.ptr_lin; + + // write even linear part + fsdev_write_packet_memory(dst, src8, lin_even); + dst += lin_even; + src8 += lin_even; + + if (lin_odd == 0) { + src8 = (uint8_t const*) info.ptr_wrap; + } else { + // Combine last linear bytes + first wrapped bytes to form fsdev bus width data + fsdev_bus_t temp = 0; + uint16_t i; + for(i = 0; i < lin_odd; i++) { + temp |= *src8++ << (i * 8); + } + + src8 = (uint8_t const*) info.ptr_wrap; + for(; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { + temp |= *src8++ << (i * 8); + } + + fsdev_write_packet_memory(dst, &temp, FSDEV_BUS_SIZE); + dst += FSDEV_BUS_SIZE; + } + + // write the rest of the wrapped part + fsdev_write_packet_memory(dst, src8, cnt_wrap); + + tu_fifo_advance_read_pointer(ff, cnt_total); + return true; +} + +// Read from PMA to FIFO +bool fsdev_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) { + if (wNBytes == 0) return true; + + // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies + // Check for first linear part + tu_fifo_buffer_info_t info; + tu_fifo_get_write_info(ff, &info); // We want to read from the FIFO + + uint16_t cnt_lin = tu_min16(wNBytes, info.len_lin); + uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.len_wrap); + uint16_t cnt_total = cnt_lin + cnt_wrap; + + // We want to read from the FIFO and write it into the PMA, if LIN part is ODD and has WRAPPED part, + // last lin byte will be combined with wrapped part To ensure PMA is always access aligned + + uint16_t lin_even = cnt_lin & ~(FSDEV_BUS_SIZE - 1); + uint16_t lin_odd = cnt_lin & (FSDEV_BUS_SIZE - 1); + uint8_t *dst8 = (uint8_t *) info.ptr_lin; + + // read even linear part + fsdev_read_packet_memory(dst8, src, lin_even); + dst8 += lin_even; + src += lin_even; + + if (lin_odd == 0) { + dst8 = (uint8_t *) info.ptr_wrap; + } else { + // Combine last linear bytes + first wrapped bytes to form fsdev bus width data + fsdev_bus_t temp; + fsdev_read_packet_memory(&temp, src, FSDEV_BUS_SIZE); + src += FSDEV_BUS_SIZE; + + uint16_t i; + for (i = 0; i < lin_odd; i++) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; + } + + dst8 = (uint8_t *) info.ptr_wrap; + for (; i < FSDEV_BUS_SIZE && cnt_wrap > 0; i++, cnt_wrap--) { + *dst8++ = (uint8_t) (temp & 0xfful); + temp >>= 8; + } + } + + // read the rest of the wrapped part + fsdev_read_packet_memory(dst8, src, cnt_wrap); + + tu_fifo_advance_write_pointer(ff, cnt_total); + return true; +} + +//--------------------------------------------------------------------+ +// BTable Helper +//--------------------------------------------------------------------+ + +/* Aligned buffer size according to hardware */ +uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) { + /* The STM32 full speed USB peripheral supports only a limited set of + * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ + uint16_t block_in_bytes; + if (size > 62) { + block_in_bytes = 32; + *blsize = 1; + *num_block = tu_div_ceil(size, 32); + } else { + block_in_bytes = 2; + *blsize = 0; + *num_block = tu_div_ceil(size, 2); + } + + return (*num_block) * block_in_bytes; +} + +void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) { + uint8_t blsize, num_block; + (void) pma_align_buffer_size(wCount, &blsize, &num_block); + + /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ + uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10); + if (bl_nb == 0) { + // zlp but 0 is invalid value, set blsize to 1 (32 bytes) + // Note: lower value can cause PMAOVR on setup with ch32v203 + bl_nb = 1 << 15; + } + +#ifdef FSDEV_BUS_32BIT + uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; + count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu); + FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; +#else + FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb; +#endif +} + +#endif diff --git a/src/portable/st/stm32_fsdev/fsdev_type.h b/src/portable/st/stm32_fsdev/fsdev_common.h similarity index 85% rename from src/portable/st/stm32_fsdev/fsdev_type.h rename to src/portable/st/stm32_fsdev/fsdev_common.h index 2b340d64a..e363245ec 100644 --- a/src/portable/st/stm32_fsdev/fsdev_type.h +++ b/src/portable/st/stm32_fsdev/fsdev_common.h @@ -1,8 +1,9 @@ /* * The MIT License (MIT) * - * Copyright(c) N Conrad - * Copyright(c) 2024, hathach (tinyusb.org) + * Copyright (c) N Conrad + * Copyright (c) 2024, hathach (tinyusb.org) + * Copyright (c) 2025, HiFiPhile (Zixun LI) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,14 +26,32 @@ * This file is part of the TinyUSB stack. */ -#ifndef TUSB_FSDEV_TYPE_H -#define TUSB_FSDEV_TYPE_H +#ifndef TUSB_FSDEV_COMMON_H +#define TUSB_FSDEV_COMMON_H -#ifdef __cplusplus - extern "C" { +#include "common/tusb_common.h" + +#if CFG_TUD_ENABLED +#include "device/dcd.h" #endif -#include "stdint.h" +#if CFG_TUH_ENABLED +#include "host/hcd.h" +#endif + +#if defined(TUP_USBIP_FSDEV_STM32) + #include "fsdev_stm32.h" +#elif defined(TUP_USBIP_FSDEV_CH32) + #include "fsdev_ch32.h" +#elif defined(TUP_USBIP_FSDEV_AT32) + #include "fsdev_at32.h" +#else + #error "Unknown USB IP" +#endif + +#ifdef __cplusplus +extern "C" { +#endif // If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it // Both of these MUST be a multiple of 2, and are in byte units. @@ -177,11 +196,6 @@ typedef enum { #define CH_STAT_MASK(_dir) (3u << (USB_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) #define CH_DTOG_MASK(_dir) (1u << (USB_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) -void fsdev_int_enable(uint8_t rhport); -void fsdev_int_disable(uint8_t rhport); -void fsdev_connect(uint8_t rhport); -void fsdev_disconnect(uint8_t rhport); - //--------------------------------------------------------------------+ // Endpoint Helper // - CTR is write 0 to clear @@ -298,47 +312,32 @@ TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_ } /* Aligned buffer size according to hardware */ -TU_ATTR_ALWAYS_INLINE static inline uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) { - /* The STM32 full speed USB peripheral supports only a limited set of - * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ - uint16_t block_in_bytes; - if (size > 62) { - block_in_bytes = 32; - *blsize = 1; - *num_block = tu_div_ceil(size, 32); - } else { - block_in_bytes = 2; - *blsize = 0; - *num_block = tu_div_ceil(size, 2); - } +uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block); - return (*num_block) * block_in_bytes; -} +void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount); -TU_ATTR_ALWAYS_INLINE static inline void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) { - uint8_t blsize, num_block; - (void) pma_align_buffer_size(wCount, &blsize, &num_block); +//--------------------------------------------------------------------+ +// PMA (Packet Memory Area) Access +//--------------------------------------------------------------------+ - /* Encode into register. When BLSIZE==1, we need to subtract 1 block count */ - uint16_t bl_nb = (blsize << 15) | ((num_block - blsize) << 10); - if (bl_nb == 0) { - // zlp but 0 is invalid value, set blsize to 1 (32 bytes) - // Note: lower value can cause PMAOVR on setup with ch32v203 - bl_nb = 1 << 15; - } +// Write to packet memory area (PMA) from user memory +// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT +// - Uses unaligned for RAM (since M0 cannot access unaligned address) +bool fsdev_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes); -#ifdef FSDEV_BUS_32BIT - uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; - count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu); - FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; -#else - FSDEV_BTABLE->ep16[ep_id][buf_id].count = bl_nb; -#endif +// Read from packet memory area (PMA) to user memory. +// - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT +// - Uses unaligned for RAM (since M0 cannot access unaligned address) +bool fsdev_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes); -} +// Write to PMA from FIFO +bool fsdev_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes); + +// Read from PMA to FIFO +bool fsdev_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes); #ifdef __cplusplus - } +} #endif -#endif +#endif /* TUSB_FSDEV_COMMON_H */ diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h index d47d23f14..71370b189 100644 --- a/src/portable/st/stm32_fsdev/fsdev_stm32.h +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -321,8 +321,6 @@ #define FSDEV_USE_SBUF_ISO 0 #endif -#include "fsdev_type.h" - //--------------------------------------------------------------------+ // //--------------------------------------------------------------------+ @@ -374,7 +372,7 @@ static const IRQn_Type fsdev_irq[] = { }; enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) }; -void fsdev_int_enable(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_enable(uint8_t rhport) { (void)rhport; // forces write to RAM before allowing ISR to execute @@ -397,7 +395,7 @@ void fsdev_int_enable(uint8_t rhport) { } } -void fsdev_int_disable(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) { (void)rhport; #if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP) @@ -422,24 +420,24 @@ void fsdev_int_disable(uint8_t rhport) { // Define only on MCU with internal pull-up. BSP can define on MCU without internal PU. #if defined(USB_BCDR_DPPU) -void fsdev_disconnect(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) { (void)rhport; USB->BCDR &= ~(USB_BCDR_DPPU); } -void fsdev_connect(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) { (void)rhport; USB->BCDR |= USB_BCDR_DPPU; } #elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151 -void fsdev_disconnect(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) { (void)rhport; SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU); } -void fsdev_connect(uint8_t rhport) { +TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) { (void)rhport; SYSCFG->PMC |= SYSCFG_PMC_USB_PU; } diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 1c08f64d6..b3c08ba23 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -30,6 +30,7 @@ * * C0 2048 byte buffer; 32-bit bus; host mode * G0 2048 byte buffer; 32-bit bus; host mode + * U3 2048 byte buffer; 32-bit bus; host mode * H5 2048 byte buffer; 32-bit bus; host mode * U535, U545 2048 byte buffer; 32-bit bus; host mode * @@ -42,19 +43,14 @@ #include "host/hcd.h" #include "host/usbh.h" - -#if defined(TUP_USBIP_FSDEV_STM32) - #include "fsdev_stm32.h" -#else - #error "Unknown USB IP" -#endif +#include "fsdev_common.h" //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ // Debug level for FSDEV -#define FSDEV_DEBUG 1 +#define FSDEV_DEBUG 3 // Max number of endpoints application can open, can be larger than FSDEV_EP_COUNT #ifndef CFG_TUH_FSDEV_ENDPOINT_MAX @@ -76,9 +72,12 @@ typedef struct { uint8_t ep_addr; uint8_t ep_type; uint8_t interval; - bool low_speed; - bool allocated; - bool next_setup; + struct TU_ATTR_PACKED { + uint8_t low_speed : 1; + uint8_t allocated : 1; + uint8_t next_setup : 1; + uint8_t pid : 1; + }; } hcd_endpoint_t; // Additional info for each channel when it is active @@ -88,7 +87,7 @@ typedef struct { uint8_t dev_addr; uint8_t ep_num; uint8_t ep_type; - bool allocated[2]; + uint8_t allocated[2]; uint8_t retry[2]; uint8_t result; } hcd_xfer_t; @@ -113,24 +112,35 @@ static uint8_t endpoint_alloc(void); static uint8_t endpoint_find(uint8_t dev_addr, uint8_t ep_addr); static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len); static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type); -static bool hcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes); -static bool hcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes); static bool edpt_xfer_kickoff(uint8_t ep_id); static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir); static void edpoint_close(uint8_t ep_id); static void port_status_handler(uint8_t rhport, bool in_isr); +static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); +static void ch_handle_nak(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); +static void ch_handle_stall(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); +static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); + //--------------------------------------------------------------------+ // Inline Functions //--------------------------------------------------------------------+ static inline void endpoint_dealloc(hcd_endpoint_t* edpt) { - edpt->allocated = false; + edpt->allocated = 0; } static inline void channel_dealloc(hcd_xfer_t* xfer, tusb_dir_t dir) { - xfer->allocated[dir] = false; + xfer->allocated[dir] = 0; } +// Write channel state in specified direction +static inline void channel_write_status(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir, ep_stat_t state, bool need_exclusive) { + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir); + ch_change_status(&ch_reg, dir, state); + ch_write(ch_id, ch_reg, need_exclusive); +} + + //--------------------------------------------------------------------+ // Controller API //--------------------------------------------------------------------+ @@ -218,139 +228,153 @@ static void port_status_handler(uint8_t rhport, bool in_isr) { } } -// Handle CTR interrupt for the TX/OUT direction -static void handle_ctr_tx(uint32_t ch_id) { - uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; +//--------------------------------------------------------------------+ +// Interrupt Helper Functions +//--------------------------------------------------------------------+ +// Handle ACK response +static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; - uint8_t ep_id = endpoint_find(daddr, ep_num); - TU_VERIFY(ep_id != TUSB_INDEX_INVALID_8, ); + uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0)); + if (ep_id == TUSB_INDEX_INVALID_8) return; hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - TU_VERIFY(xfer->allocated[TUSB_DIR_OUT],); - // Manage Correct Transaction - if ((ch_reg & USB_CH_ERRTX) == 0U) { - // Acked - if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_ACK_SBUF) { - if (edpt->buflen != xfer->queued_len[TUSB_DIR_OUT]) { - uint16_t const len = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); - uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_TX); - hcd_write_packet_memory(pma_addr, &(edpt->buffer[xfer->queued_len[TUSB_DIR_OUT]]), len); - btable_set_count(ch_id, BTABLE_BUF_TX, len); - xfer->queued_len[TUSB_DIR_OUT] += len; - - ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_VALID); - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // only change TX Status, reserve other toggle bits - ch_write(ch_id, ch_reg, false); - } else { - channel_dealloc(xfer, TUSB_DIR_OUT); - hcd_event_xfer_complete(daddr, ep_num, xfer->queued_len[TUSB_DIR_OUT], XFER_RESULT_SUCCESS, true); - } - } else if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_NAK) { - // NAKed - if (edpt->ep_type != TUSB_XFER_INTERRUPT) { - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // will change TX Status, reserved other toggle bits - ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_VALID); - ch_write(ch_id, ch_reg, false); - } - } else if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_STALL) { - // STALLed + if (dir == TUSB_DIR_OUT) { + // OUT/TX direction + if (edpt->buflen != xfer->queued_len[TUSB_DIR_OUT]) { + // More data to send + uint16_t const len = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); + uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_TX); + fsdev_write_packet_memory(pma_addr, &(edpt->buffer[xfer->queued_len[TUSB_DIR_OUT]]), len); + btable_set_count(ch_id, BTABLE_BUF_TX, len); + xfer->queued_len[TUSB_DIR_OUT] += len; + channel_write_status(ch_id, ch_reg, TUSB_DIR_OUT, EP_STAT_VALID, false); + } else { + // Transfer complete channel_dealloc(xfer, TUSB_DIR_OUT); - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // will change TX Status, reserved other toggle bits - ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); - ch_write(ch_id, ch_reg, false); - hcd_event_xfer_complete(daddr, ep_num, xfer->queued_len[TUSB_DIR_OUT], XFER_RESULT_STALLED, true); + edpt->pid = (ch_reg & USB_CHEP_DTOG_TX) ? 1 : 0; + hcd_event_xfer_complete(daddr, ep_num, xfer->queued_len[TUSB_DIR_OUT], XFER_RESULT_SUCCESS, true); } } else { - // Error - TU_LOG(FSDEV_DEBUG, "handle_ctr_tx error epreg=0x%08X ch=%u ep=0x%02X daddr=%u queued=%u/%u\r\n", - ch_reg, ch_id, ep_num, daddr, xfer->queued_len[TUSB_DIR_OUT], edpt->buflen); - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // will change TX Status, reserved other toggle bits - ch_reg &=~USB_CH_ERRTX; - if (xfer->retry[TUSB_DIR_OUT] < HCD_XFER_ERROR_MAX) { - // Retry - xfer->retry[TUSB_DIR_OUT]++; + // IN/RX direction + uint16_t const rx_count = btable_get_count(ch_id, BTABLE_BUF_RX); + uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX); + + fsdev_read_packet_memory(edpt->buffer + xfer->queued_len[TUSB_DIR_IN], pma_addr, rx_count); + xfer->queued_len[TUSB_DIR_IN] += rx_count; + + if ((rx_count < edpt->max_packet_size) || (xfer->queued_len[TUSB_DIR_IN] >= edpt->buflen)) { + // Transfer complete (short packet or all bytes received) + channel_dealloc(xfer, TUSB_DIR_IN); + edpt->pid = (ch_reg & USB_CHEP_DTOG_RX) ? 1 : 0; + hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len[TUSB_DIR_IN], XFER_RESULT_SUCCESS, true); } else { - // Failed after retries - channel_dealloc(xfer, TUSB_DIR_OUT); - ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); - hcd_event_xfer_complete(daddr, ep_num, xfer->queued_len[TUSB_DIR_OUT], XFER_RESULT_FAILED, true); + // More data expected + uint16_t const cnt = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_IN], edpt->max_packet_size); + btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, cnt); + channel_write_status(ch_id, ch_reg, TUSB_DIR_IN, EP_STAT_VALID, false); } - ch_write(ch_id, ch_reg, false); + } +} + +// Handle NAK response +static void ch_handle_nak(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { + uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; + uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; + + uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0)); + if (ep_id == TUSB_INDEX_INVALID_8) return; + + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; + // Retry non-periodic transfer immediately, + // Periodic transfer will be retried by next frame automatically + if (edpt->ep_type == TUSB_XFER_CONTROL || edpt->ep_type == TUSB_XFER_BULK) { + channel_write_status(ch_id, ch_reg, dir, EP_STAT_VALID, false); + } +} + +// Handle STALL response +static void ch_handle_stall(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { + uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; + uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; + + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + channel_dealloc(xfer, dir); + + channel_write_status(ch_id, ch_reg, dir, EP_STAT_DISABLED, false); + + hcd_event_xfer_complete(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0), + xfer->queued_len[dir], XFER_RESULT_STALLED, true); +} + +// Handle error response +static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { + uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; + uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; + + uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0)); + if (ep_id == TUSB_INDEX_INVALID_8) return; + + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir); + ch_reg &= ~(dir == TUSB_DIR_OUT ? USB_CH_ERRTX : USB_CH_ERRRX); + + if (xfer->retry[dir] < HCD_XFER_ERROR_MAX) { + // Retry + xfer->retry[dir]++; + ch_change_status(&ch_reg, dir, EP_STAT_VALID); + } else { + // Failed after retries + channel_dealloc(xfer, dir); + ch_change_status(&ch_reg, dir, EP_STAT_DISABLED); + hcd_event_xfer_complete(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0), + xfer->queued_len[dir], XFER_RESULT_FAILED, true); + } + ch_write(ch_id, ch_reg, false); +} + +// Handle CTR interrupt for the TX/OUT direction +static void handle_ctr_tx(uint32_t ch_id) { + uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + TU_VERIFY(xfer->allocated[TUSB_DIR_OUT] == 1,); + + if ((ch_reg & USB_CH_ERRTX) == 0U) { + // No error + if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_ACK_SBUF) { + ch_handle_ack(ch_id, ch_reg, TUSB_DIR_OUT); + } else if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_NAK) { + ch_handle_nak(ch_id, ch_reg, TUSB_DIR_OUT); + } else if ((ch_reg & USB_CH_TX_STTX) == USB_CH_TX_STALL) { + ch_handle_stall(ch_id, ch_reg, TUSB_DIR_OUT); + } + } else { + ch_handle_error(ch_id, ch_reg, TUSB_DIR_OUT); } } // Handle CTR interrupt for the RX/IN direction static void handle_ctr_rx(uint32_t ch_id) { uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; - uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; + hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + TU_VERIFY(xfer->allocated[TUSB_DIR_IN] == 1,); - uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; - - uint8_t ep_id = endpoint_find(daddr, ep_num | TUSB_DIR_IN_MASK); - TU_VERIFY(ep_id != TUSB_INDEX_INVALID_8, ); - - hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; - hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - TU_VERIFY(xfer->allocated[TUSB_DIR_IN],); - - // Manage Correct Transaction if ((ch_reg & USB_CH_ERRRX) == 0U) { - // Acked + // No error if ((ch_reg & USB_CH_RX_STRX) == USB_CH_RX_ACK_SBUF) { - uint16_t const rx_count = btable_get_count(ch_id, BTABLE_BUF_RX); - uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX); - - hcd_read_packet_memory(edpt->buffer + xfer->queued_len[TUSB_DIR_IN], pma_addr, rx_count); - xfer->queued_len[TUSB_DIR_IN] += rx_count; - - if ((rx_count < edpt->max_packet_size) || (xfer->queued_len[TUSB_DIR_IN] >= edpt->buflen)) { - // all bytes received or short packet - channel_dealloc(xfer, TUSB_DIR_IN); - hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len[TUSB_DIR_IN], XFER_RESULT_SUCCESS, true); - } else { - // Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always - uint16_t const cnt = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_IN], edpt->max_packet_size); - btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, cnt); - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change RX Status, reserved other toggle bits - ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_VALID); - ch_write(ch_id, ch_reg, false); - } + ch_handle_ack(ch_id, ch_reg, TUSB_DIR_IN); } else if ((ch_reg & USB_CH_RX_STRX) == USB_CH_RX_NAK) { - // NAKed - if (edpt->ep_type != TUSB_XFER_INTERRUPT) { - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change TX Status, reserved other toggle bits - ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_VALID); - ch_write(ch_id, ch_reg, false); - } - } else { - // STALLed - channel_dealloc(xfer, TUSB_DIR_IN); - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change TX Status, reserved other toggle bits - ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED); - ch_write(ch_id, ch_reg, false); - hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len[TUSB_DIR_IN], XFER_RESULT_STALLED, true); + ch_handle_nak(ch_id, ch_reg, TUSB_DIR_IN); + } else if ((ch_reg & USB_CH_RX_STRX) == USB_CH_RX_STALL){ + ch_handle_stall(ch_id, ch_reg, TUSB_DIR_IN); } } else { - // Error - TU_LOG(FSDEV_DEBUG, "handle_ctr_tx error epreg=0x%08X ch=%u ep=0x%02X daddr=%u queued=%u/%u\r\n", - ch_reg, ch_id, ep_num, daddr, xfer->queued_len[TUSB_DIR_IN], edpt->buflen); - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change RX Status, reserved other toggle bits - ch_reg &=~USB_CH_ERRRX; - if (xfer->retry[TUSB_DIR_IN] < HCD_XFER_ERROR_MAX) { - // Retry - xfer->retry[TUSB_DIR_IN]++; - } else { - // Failed after retries - channel_dealloc(xfer, TUSB_DIR_IN); - ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED); - hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len[TUSB_DIR_IN], XFER_RESULT_FAILED, true); - } - ch_write(ch_id, ch_reg, false); + ch_handle_error(ch_id, ch_reg, TUSB_DIR_IN); } } @@ -468,7 +492,7 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) { // Close all endpoints for this device for(uint32_t i = 0; i < CFG_TUH_FSDEV_ENDPOINT_MAX; i++) { hcd_endpoint_t* edpt = &_hcd_data.edpt[i]; - if (edpt->allocated && edpt->dev_addr == dev_addr) { + if (edpt->allocated == 1 && edpt->dev_addr == dev_addr) { edpoint_close(i); } } @@ -496,7 +520,8 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const edpt->ep_type = ep_type; edpt->max_packet_size = packet_size; edpt->interval = ep_desc->bInterval; - edpt->low_speed = (hcd_port_speed_get(rhport) == TUSB_SPEED_FULL && tuh_speed_get(dev_addr) == TUSB_SPEED_LOW); + edpt->pid = 0; + edpt->low_speed = (hcd_port_speed_get(rhport) == TUSB_SPEED_FULL && tuh_speed_get(dev_addr) == TUSB_SPEED_LOW) ? 1 : 0; // EP0 is bi-directional, so we need to open both OUT and IN channels if (ep_addr == 0) { @@ -525,7 +550,7 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { edpoint_close(ep_id_in); } - return false; + return true; } // Submit a transfer @@ -556,17 +581,12 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { hcd_xfer_t* xfer = &_hcd_data.xfer[i]; - if (xfer->allocated[dir] && + if (xfer->allocated[dir] == 1 && xfer->dev_addr == dev_addr && xfer->ep_num == tu_edpt_number(ep_addr)) { - channel_dealloc(xfer, dir); - - uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir); // will change Status, reserved other toggle bits - ch_change_status(&ch_reg, dir, EP_STAT_DISABLED); - ch_write(i, ch_reg, true); - + uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; + channel_write_status(i, ch_reg, dir, EP_STAT_DISABLED, true); } } @@ -582,6 +602,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; edpt->next_setup = true; + edpt->pid = 0; return hcd_edpt_xfer(rhport, dev_addr, 0, (uint8_t*)(uintptr_t) setup_packet, 8); } @@ -592,6 +613,12 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { (void) dev_addr; (void) ep_addr; + uint8_t const ep_id = endpoint_find(dev_addr, 0); + TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + + hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; + edpt->pid = 0; + return true; } @@ -602,8 +629,8 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { static uint8_t endpoint_alloc(void) { for (uint32_t i = 0; i < CFG_TUH_FSDEV_ENDPOINT_MAX; i++) { hcd_endpoint_t* edpt = &_hcd_data.edpt[i]; - if (!edpt->allocated) { - edpt->allocated = true; + if (edpt->allocated == 0) { + edpt->allocated = 1; return i; } } @@ -613,7 +640,7 @@ static uint8_t endpoint_alloc(void) { static uint8_t endpoint_find(uint8_t dev_addr, uint8_t ep_addr) { for (uint32_t i = 0; i < (uint32_t)CFG_TUH_FSDEV_ENDPOINT_MAX; i++) { hcd_endpoint_t* edpt = &_hcd_data.edpt[i]; - if (edpt->allocated && edpt->dev_addr == dev_addr && edpt->ep_addr == ep_addr) { + if (edpt->allocated == 1 && edpt->dev_addr == dev_addr && edpt->ep_addr == ep_addr) { return i; } } @@ -628,24 +655,14 @@ static void edpoint_close(uint8_t ep_id) { // disable active channel belong to this endpoint for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { hcd_xfer_t* xfer = &_hcd_data.xfer[i]; - - if (xfer->allocated[TUSB_DIR_OUT] && xfer->edpt[TUSB_DIR_OUT] == edpt) { + uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; + if (xfer->allocated[TUSB_DIR_OUT] == 1 && xfer->edpt[TUSB_DIR_OUT] == edpt) { channel_dealloc(xfer, TUSB_DIR_OUT); - - uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits - ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED); - ch_write(i, ch_reg, true); - + channel_write_status(i, ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED, true); } - if (xfer->allocated[TUSB_DIR_IN] && xfer->edpt[TUSB_DIR_IN] == edpt) { + if (xfer->allocated[TUSB_DIR_IN] == 1 && xfer->edpt[TUSB_DIR_IN] == edpt) { channel_dealloc(xfer, TUSB_DIR_IN); - - uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change TX Status, reserved other toggle bits - ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED); - ch_write(i, ch_reg, true); - + channel_write_status(i, ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED, true); } } } @@ -654,10 +671,10 @@ static void edpoint_close(uint8_t ep_id) { static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len) { (void) len; // Simple static allocation as we are unlikely to handle ISO endpoints in host mode - // We just give each channel a buffer of max packet size (64 bytes) + // We just give each channel two buffers of max packet size (64 bytes) for IN and OUT uint16_t addr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT; - addr += channel * 64 * 2 + (dir == TUSB_DIR_IN ? 64 : 0); + addr += channel * TUSB_EPSIZE_BULK_FS * 2 + (dir == TUSB_DIR_IN ? TUSB_EPSIZE_BULK_FS : 0); TU_ASSERT(addr <= FSDEV_PMA_SIZE, 0xFFFF); @@ -672,12 +689,12 @@ static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type) // Find channel allocate for same ep_num but other direction tusb_dir_t const other_dir = (dir == TUSB_DIR_IN) ? TUSB_DIR_OUT : TUSB_DIR_IN; for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { - if (!_hcd_data.xfer[i].allocated[dir] && - _hcd_data.xfer[i].allocated[other_dir] && + if (_hcd_data.xfer[i].allocated[dir] == 0 && + _hcd_data.xfer[i].allocated[other_dir] == 1 && _hcd_data.xfer[i].dev_addr == dev_addr && _hcd_data.xfer[i].ep_num == ep_num && _hcd_data.xfer[i].ep_type == ep_type) { - _hcd_data.xfer[i].allocated[dir] = true; + _hcd_data.xfer[i].allocated[dir] = 1; _hcd_data.xfer[i].queued_len[dir] = 0; _hcd_data.xfer[i].retry[dir] = 0; return i; @@ -686,11 +703,11 @@ static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type) // Find free channel for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { - if (!_hcd_data.xfer[i].allocated[0] && !_hcd_data.xfer[i].allocated[1]) { + if (_hcd_data.xfer[i].allocated[0] == 0 && _hcd_data.xfer[i].allocated[1] == 0) { _hcd_data.xfer[i].dev_addr = dev_addr; _hcd_data.xfer[i].ep_num = ep_num; _hcd_data.xfer[i].ep_type = ep_type; - _hcd_data.xfer[i].allocated[dir] = true; + _hcd_data.xfer[i].allocated[dir] = 1; _hcd_data.xfer[i].queued_len[dir] = 0; _hcd_data.xfer[i].retry[dir] = 0; return i; @@ -748,86 +765,37 @@ static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) { if (dir == TUSB_DIR_OUT) { uint16_t const len = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); - hcd_write_packet_memory(pma_addr, &(edpt->buffer[xfer->queued_len[TUSB_DIR_OUT]]), len); + fsdev_write_packet_memory(pma_addr, &(edpt->buffer[xfer->queued_len[TUSB_DIR_OUT]]), len); btable_set_count(ch_id, BTABLE_BUF_TX, len); xfer->queued_len[TUSB_DIR_OUT] += len; - if (edpt->next_setup) { - // Setup packet uses IN token - edpt->next_setup = false; - ch_reg |= USB_EP_SETUP; - } - - ch_change_status(&ch_reg, TUSB_DIR_OUT, EP_STAT_VALID); - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_OUT); // only change TX Status, reserve other toggle bits - } else { btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, edpt->max_packet_size); - ch_change_status(&ch_reg, TUSB_DIR_IN, EP_STAT_VALID); - ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(TUSB_DIR_IN); // will change RX Status, reserved other toggle bits } + if (edpt->low_speed == 1) { + ch_reg |= USB_CHEP_LSEP; + } else { + ch_reg &= ~USB_CHEP_LSEP; + } + + if (tu_edpt_number(edpt->ep_addr) == 0) { + edpt->pid = 1; + } + + if (edpt->next_setup) { + // Setup packet uses IN token + edpt->next_setup = false; + ch_reg |= USB_EP_SETUP; + edpt->pid = 0; + } + + ch_change_status(&ch_reg, dir, EP_STAT_VALID); + ch_change_dtog(&ch_reg, dir, edpt->pid); + ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir) | CH_DTOG_MASK(dir); ch_write(ch_id, ch_reg, true); return true; } -//--------------------------------------------------------------------+ -// PMA read/write -//--------------------------------------------------------------------+ - -// Write to packet memory area (PMA) from user memory -static bool hcd_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) { - if (nbytes == 0) return true; - uint32_t n_write = nbytes / FSDEV_BUS_SIZE; - - fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(dst); - const uint8_t *src8 = src; - - while (n_write--) { - pma_buf->value = fsdevbus_unaligned_read(src8); - src8 += FSDEV_BUS_SIZE; - pma_buf++; - } - - // Handle odd bytes - uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); - if (odd) { - fsdev_bus_t temp = 0; - for (uint16_t i = 0; i < odd; i++) { - temp |= *src8++ << (i * 8); - } - pma_buf->value = temp; - } - - return true; -} - -// Read from packet memory area (PMA) to user memory -static bool hcd_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) { - if (nbytes == 0) return true; - uint32_t n_read = nbytes / FSDEV_BUS_SIZE; - - fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(src); - uint8_t *dst8 = (uint8_t *)dst; - - while (n_read--) { - fsdevbus_unaligned_write(dst8, (fsdev_bus_t) pma_buf->value); - dst8 += FSDEV_BUS_SIZE; - pma_buf++; - } - - // Handle odd bytes - uint16_t odd = nbytes & (FSDEV_BUS_SIZE - 1); - if (odd) { - fsdev_bus_t temp = pma_buf->value; - while (odd--) { - *dst8++ = (uint8_t)(temp & 0xfful); - temp >>= 8; - } - } - - return true; -} - #endif diff --git a/tools/iar_template.ipcf b/tools/iar_template.ipcf index 2581a4702..caddda826 100644 --- a/tools/iar_template.ipcf +++ b/tools/iar_template.ipcf @@ -217,7 +217,9 @@ $TUSB_DIR$/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c - $TUSB_DIR$/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h + $TUSB_DIR$/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c + $TUSB_DIR$/src/portable/st/stm32_fsdev/fsdev_common.c + $TUSB_DIR$/src/portable/st/stm32_fsdev/fsdev_common.h $TUSB_DIR$/src/portable/st/typec/typec_stm32.c From adcfc4bd269b93a93f4f329541351a89368cf761 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 25 Nov 2025 22:40:55 +0100 Subject: [PATCH 04/21] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 6a6f07825..7723935dd 100644 --- a/README.rst +++ b/README.rst @@ -229,7 +229,7 @@ Supported CPUs | +----+------------------------+--------+------+-----------+------------------------+-------------------+ | | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | | | +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | C0, G0, H5 | ✔ | | ✖ | stm32_fsdev | | +| | C0, G0, H5 | ✔ | ✔ | ✖ | stm32_fsdev | Tested on C0 | | +-----------------------------+--------+------+-----------+------------------------+-------------------+ | | G4 | ✔ | ✖ | ✖ | stm32_fsdev | | | +----+------------------------+--------+------+-----------+------------------------+-------------------+ From a445e8c3b31629f2d14b3380c15bceb667d546b6 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 25 Nov 2025 23:02:17 +0100 Subject: [PATCH 05/21] hcd/fsdev: more refactor Signed-off-by: HiFiPhile --- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 123 +++++++++--------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index b3c08ba23..2d05b2633 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -89,8 +89,7 @@ typedef struct { uint8_t ep_type; uint8_t allocated[2]; uint8_t retry[2]; - uint8_t result; -} hcd_xfer_t; +} hcd_channel_t; // Root hub port state static struct { @@ -98,7 +97,7 @@ static struct { } _hcd_port; typedef struct { - hcd_xfer_t xfer[FSDEV_EP_COUNT]; + hcd_channel_t channel[FSDEV_EP_COUNT]; hcd_endpoint_t edpt[CFG_TUH_FSDEV_ENDPOINT_MAX]; } hcd_data_t; @@ -129,8 +128,8 @@ static inline void endpoint_dealloc(hcd_endpoint_t* edpt) { edpt->allocated = 0; } -static inline void channel_dealloc(hcd_xfer_t* xfer, tusb_dir_t dir) { - xfer->allocated[dir] = 0; +static inline void channel_dealloc(hcd_channel_t* ch, tusb_dir_t dir) { + ch->allocated[dir] = 0; } // Write channel state in specified direction @@ -241,40 +240,40 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { if (ep_id == TUSB_INDEX_INVALID_8) return; hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; - hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + hcd_channel_t* channel = &_hcd_data.channel[ch_id]; if (dir == TUSB_DIR_OUT) { // OUT/TX direction - if (edpt->buflen != xfer->queued_len[TUSB_DIR_OUT]) { + if (edpt->buflen != channel->queued_len[TUSB_DIR_OUT]) { // More data to send - uint16_t const len = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); + uint16_t const len = tu_min16(edpt->buflen - channel->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_TX); - fsdev_write_packet_memory(pma_addr, &(edpt->buffer[xfer->queued_len[TUSB_DIR_OUT]]), len); + fsdev_write_packet_memory(pma_addr, &(edpt->buffer[channel->queued_len[TUSB_DIR_OUT]]), len); btable_set_count(ch_id, BTABLE_BUF_TX, len); - xfer->queued_len[TUSB_DIR_OUT] += len; + channel->queued_len[TUSB_DIR_OUT] += len; channel_write_status(ch_id, ch_reg, TUSB_DIR_OUT, EP_STAT_VALID, false); } else { // Transfer complete - channel_dealloc(xfer, TUSB_DIR_OUT); + channel_dealloc(channel, TUSB_DIR_OUT); edpt->pid = (ch_reg & USB_CHEP_DTOG_TX) ? 1 : 0; - hcd_event_xfer_complete(daddr, ep_num, xfer->queued_len[TUSB_DIR_OUT], XFER_RESULT_SUCCESS, true); + hcd_event_xfer_complete(daddr, ep_num, channel->queued_len[TUSB_DIR_OUT], XFER_RESULT_SUCCESS, true); } } else { // IN/RX direction uint16_t const rx_count = btable_get_count(ch_id, BTABLE_BUF_RX); uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX); - fsdev_read_packet_memory(edpt->buffer + xfer->queued_len[TUSB_DIR_IN], pma_addr, rx_count); - xfer->queued_len[TUSB_DIR_IN] += rx_count; + fsdev_read_packet_memory(edpt->buffer + channel->queued_len[TUSB_DIR_IN], pma_addr, rx_count); + channel->queued_len[TUSB_DIR_IN] += rx_count; - if ((rx_count < edpt->max_packet_size) || (xfer->queued_len[TUSB_DIR_IN] >= edpt->buflen)) { + if ((rx_count < edpt->max_packet_size) || (channel->queued_len[TUSB_DIR_IN] >= edpt->buflen)) { // Transfer complete (short packet or all bytes received) - channel_dealloc(xfer, TUSB_DIR_IN); + channel_dealloc(channel, TUSB_DIR_IN); edpt->pid = (ch_reg & USB_CHEP_DTOG_RX) ? 1 : 0; - hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len[TUSB_DIR_IN], XFER_RESULT_SUCCESS, true); + hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, channel->queued_len[TUSB_DIR_IN], XFER_RESULT_SUCCESS, true); } else { // More data expected - uint16_t const cnt = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_IN], edpt->max_packet_size); + uint16_t const cnt = tu_min16(edpt->buflen - channel->queued_len[TUSB_DIR_IN], edpt->max_packet_size); btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, cnt); channel_write_status(ch_id, ch_reg, TUSB_DIR_IN, EP_STAT_VALID, false); } @@ -302,13 +301,13 @@ static void ch_handle_stall(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; - hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - channel_dealloc(xfer, dir); + hcd_channel_t* channel = &_hcd_data.channel[ch_id]; + channel_dealloc(channel, dir); channel_write_status(ch_id, ch_reg, dir, EP_STAT_DISABLED, false); hcd_event_xfer_complete(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0), - xfer->queued_len[dir], XFER_RESULT_STALLED, true); + channel->queued_len[dir], XFER_RESULT_STALLED, true); } // Handle error response @@ -319,21 +318,21 @@ static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0)); if (ep_id == TUSB_INDEX_INVALID_8) return; - hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; + hcd_channel_t* channel = &_hcd_data.channel[ch_id]; ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir); ch_reg &= ~(dir == TUSB_DIR_OUT ? USB_CH_ERRTX : USB_CH_ERRRX); - if (xfer->retry[dir] < HCD_XFER_ERROR_MAX) { + if (channel->retry[dir] < HCD_XFER_ERROR_MAX) { // Retry - xfer->retry[dir]++; + channel->retry[dir]++; ch_change_status(&ch_reg, dir, EP_STAT_VALID); } else { // Failed after retries - channel_dealloc(xfer, dir); + channel_dealloc(channel, dir); ch_change_status(&ch_reg, dir, EP_STAT_DISABLED); hcd_event_xfer_complete(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0), - xfer->queued_len[dir], XFER_RESULT_FAILED, true); + channel->queued_len[dir], XFER_RESULT_FAILED, true); } ch_write(ch_id, ch_reg, false); } @@ -341,8 +340,8 @@ static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { // Handle CTR interrupt for the TX/OUT direction static void handle_ctr_tx(uint32_t ch_id) { uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; - hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - TU_VERIFY(xfer->allocated[TUSB_DIR_OUT] == 1,); + hcd_channel_t* channel = &_hcd_data.channel[ch_id]; + TU_VERIFY(channel->allocated[TUSB_DIR_OUT] == 1,); if ((ch_reg & USB_CH_ERRTX) == 0U) { // No error @@ -361,8 +360,8 @@ static void handle_ctr_tx(uint32_t ch_id) { // Handle CTR interrupt for the RX/IN direction static void handle_ctr_rx(uint32_t ch_id) { uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; - hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - TU_VERIFY(xfer->allocated[TUSB_DIR_IN] == 1,); + hcd_channel_t* channel = &_hcd_data.channel[ch_id]; + TU_VERIFY(channel->allocated[TUSB_DIR_IN] == 1,); if ((ch_reg & USB_CH_ERRRX) == 0U) { // No error @@ -579,12 +578,12 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { tusb_dir_t const dir = tu_edpt_dir(ep_addr); for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { - hcd_xfer_t* xfer = &_hcd_data.xfer[i]; + hcd_channel_t* channel = &_hcd_data.channel[i]; - if (xfer->allocated[dir] == 1 && - xfer->dev_addr == dev_addr && - xfer->ep_num == tu_edpt_number(ep_addr)) { - channel_dealloc(xfer, dir); + if (channel->allocated[dir] == 1 && + channel->dev_addr == dev_addr && + channel->ep_num == tu_edpt_number(ep_addr)) { + channel_dealloc(channel, dir); uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; channel_write_status(i, ch_reg, dir, EP_STAT_DISABLED, true); } @@ -654,14 +653,14 @@ static void edpoint_close(uint8_t ep_id) { // disable active channel belong to this endpoint for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { - hcd_xfer_t* xfer = &_hcd_data.xfer[i]; + hcd_channel_t* channel = &_hcd_data.channel[i]; uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; - if (xfer->allocated[TUSB_DIR_OUT] == 1 && xfer->edpt[TUSB_DIR_OUT] == edpt) { - channel_dealloc(xfer, TUSB_DIR_OUT); + if (channel->allocated[TUSB_DIR_OUT] == 1 && channel->edpt[TUSB_DIR_OUT] == edpt) { + channel_dealloc(channel, TUSB_DIR_OUT); channel_write_status(i, ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED, true); } - if (xfer->allocated[TUSB_DIR_IN] == 1 && xfer->edpt[TUSB_DIR_IN] == edpt) { - channel_dealloc(xfer, TUSB_DIR_IN); + if (channel->allocated[TUSB_DIR_IN] == 1 && channel->edpt[TUSB_DIR_IN] == edpt) { + channel_dealloc(channel, TUSB_DIR_IN); channel_write_status(i, ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED, true); } } @@ -689,27 +688,27 @@ static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type) // Find channel allocate for same ep_num but other direction tusb_dir_t const other_dir = (dir == TUSB_DIR_IN) ? TUSB_DIR_OUT : TUSB_DIR_IN; for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { - if (_hcd_data.xfer[i].allocated[dir] == 0 && - _hcd_data.xfer[i].allocated[other_dir] == 1 && - _hcd_data.xfer[i].dev_addr == dev_addr && - _hcd_data.xfer[i].ep_num == ep_num && - _hcd_data.xfer[i].ep_type == ep_type) { - _hcd_data.xfer[i].allocated[dir] = 1; - _hcd_data.xfer[i].queued_len[dir] = 0; - _hcd_data.xfer[i].retry[dir] = 0; + if (_hcd_data.channel[i].allocated[dir] == 0 && + _hcd_data.channel[i].allocated[other_dir] == 1 && + _hcd_data.channel[i].dev_addr == dev_addr && + _hcd_data.channel[i].ep_num == ep_num && + _hcd_data.channel[i].ep_type == ep_type) { + _hcd_data.channel[i].allocated[dir] = 1; + _hcd_data.channel[i].queued_len[dir] = 0; + _hcd_data.channel[i].retry[dir] = 0; return i; } } // Find free channel for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { - if (_hcd_data.xfer[i].allocated[0] == 0 && _hcd_data.xfer[i].allocated[1] == 0) { - _hcd_data.xfer[i].dev_addr = dev_addr; - _hcd_data.xfer[i].ep_num = ep_num; - _hcd_data.xfer[i].ep_type = ep_type; - _hcd_data.xfer[i].allocated[dir] = 1; - _hcd_data.xfer[i].queued_len[dir] = 0; - _hcd_data.xfer[i].retry[dir] = 0; + if (_hcd_data.channel[i].allocated[0] == 0 && _hcd_data.channel[i].allocated[1] == 0) { + _hcd_data.channel[i].dev_addr = dev_addr; + _hcd_data.channel[i].ep_num = ep_num; + _hcd_data.channel[i].ep_type = ep_type; + _hcd_data.channel[i].allocated[dir] = 1; + _hcd_data.channel[i].queued_len[dir] = 0; + _hcd_data.channel[i].retry[dir] = 0; return i; } } @@ -726,15 +725,15 @@ static bool edpt_xfer_kickoff(uint8_t ep_id) { tusb_dir_t const dir = tu_edpt_dir(edpt->ep_addr); - hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - xfer->edpt[dir] = edpt; + hcd_channel_t* channel = &_hcd_data.channel[ch_id]; + channel->edpt[dir] = edpt; return channel_xfer_start(ch_id, dir); } static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) { - hcd_xfer_t* xfer = &_hcd_data.xfer[ch_id]; - hcd_endpoint_t* edpt = xfer->edpt[dir]; + hcd_channel_t* channel = &_hcd_data.channel[ch_id]; + hcd_endpoint_t* edpt = channel->edpt[dir]; uint32_t ch_reg = ch_read(ch_id) & ~USB_EPREG_MASK; ch_reg |= tu_edpt_number(edpt->ep_addr) | edpt->dev_addr << USB_CHEP_DEVADDR_Pos | @@ -763,12 +762,12 @@ static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) { btable_set_addr(ch_id, dir == TUSB_DIR_OUT ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr); if (dir == TUSB_DIR_OUT) { - uint16_t const len = tu_min16(edpt->buflen - xfer->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); + uint16_t const len = tu_min16(edpt->buflen - channel->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); - fsdev_write_packet_memory(pma_addr, &(edpt->buffer[xfer->queued_len[TUSB_DIR_OUT]]), len); + fsdev_write_packet_memory(pma_addr, &(edpt->buffer[channel->queued_len[TUSB_DIR_OUT]]), len); btable_set_count(ch_id, BTABLE_BUF_TX, len); - xfer->queued_len[TUSB_DIR_OUT] += len; + channel->queued_len[TUSB_DIR_OUT] += len; } else { btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, edpt->max_packet_size); } From a965e1fa4bd92104d68ab20beb1bb56a5019e153 Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Wed, 26 Nov 2025 10:36:43 +0100 Subject: [PATCH 06/21] Update doc Signed-off-by: Zixun LI --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 7723935dd..ef19b0ccd 100644 --- a/README.rst +++ b/README.rst @@ -229,7 +229,7 @@ Supported CPUs | +----+------------------------+--------+------+-----------+------------------------+-------------------+ | | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | | | +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | C0, G0, H5 | ✔ | ✔ | ✖ | stm32_fsdev | Tested on C0 | +| | C0, G0, H5 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0 | | +-----------------------------+--------+------+-----------+------------------------+-------------------+ | | G4 | ✔ | ✖ | ✖ | stm32_fsdev | | | +----+------------------------+--------+------+-----------+------------------------+-------------------+ @@ -241,9 +241,9 @@ Supported CPUs | +----+------------------------+--------+------+-----------+------------------------+-------------------+ | | U0 | ✔ | ✖ | ✖ | stm32_fsdev | | | +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | U3 | ✔ | | ✖ | stm32_fsdev | | +| | U3 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0 | | +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | U5 | 535, 545 | ✔ | | ✖ | stm32_fsdev | | +| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0 | | | +------------------------+--------+------+-----------+------------------------+-------------------+ | | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | | | | +------------------------+--------+------+-----------+------------------------+-------------------+ From 270e1492764959c278f1b154b8e42aef4dcd98d8 Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Wed, 26 Nov 2025 14:25:06 +0100 Subject: [PATCH 07/21] reorganize ctr_rx workaround Signed-off-by: Zixun LI --- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 81 ++++++++++++------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 2d05b2633..362d7df7b 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -139,6 +139,53 @@ static inline void channel_write_status(uint8_t ch_id, uint32_t ch_reg, tusb_dir ch_write(ch_id, ch_reg, need_exclusive); } +static inline uint16_t channel_get_rx_count(uint8_t ch_id) { + /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf + * https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf + * From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers + * Description: + * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses + * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. + * Workaround: + * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay + * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode + * + * Note: this errata may also apply to G0, U5, H5 etc. + * + * We choose the delay count based on max CPU frequency (in MHz) to ensure the delay is at least the required time. + */ + +#if CFG_TUSB_MCU == OPT_MCU_STM32H5 + #define FREQUENCY_MHZ 250U +#elif CFG_TUSB_MCU == OPT_MCU_STM32U5 + #define FREQUENCY_MHZ 160U +#elif CFG_TUSB_MCU == OPT_MCU_STM32U3 + #define FREQUENCY_MHZ 96U +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 + #define FREQUENCY_MHZ 64U +#elif CFG_TUSB_MCU == OPT_MCU_STM32C0 + #define FREQUENCY_MHZ 48U +#else + #error "FREQUENCY_MHZ not defined for this STM32 MCU" +#endif + + uint32_t ch_reg = ch_read(ch_id); + if (FSDEV_REG->ISTR & USB_ISTR_LS_DCONN || ch_reg & USB_CHEP_LSEP) { + // Low speed mode: 6.4 us delay -> about 2 cycles per MHz + volatile uint32_t cycle_count = FREQUENCY_MHZ * 2U; + while (cycle_count > 0U) { + cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) + } + } else { + // Full speed mode: 800 ns delay -> about 0.25 cycles per MHz + volatile uint32_t cycle_count = FREQUENCY_MHZ / 4U; + while (cycle_count > 0U) { + cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) + } + } + + return btable_get_count(ch_id, BTABLE_BUF_RX); +} //--------------------------------------------------------------------+ // Controller API @@ -175,12 +222,6 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { } FSDEV_REG->CNTR = USB_CNTR_HOST; // Enable USB in Host mode - -#if !defined(FSDEV_BUS_32BIT) - // BTABLE register does not exist on 32-bit bus devices - FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; -#endif - FSDEV_REG->ISTR = 0; // Clear pending interrupts // Reset channels to disabled @@ -260,7 +301,7 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { } } else { // IN/RX direction - uint16_t const rx_count = btable_get_count(ch_id, BTABLE_BUF_RX); + uint16_t const rx_count = channel_get_rx_count(ch_id); uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX); fsdev_read_packet_memory(edpt->buffer + channel->queued_len[TUSB_DIR_IN], pma_addr, rx_count); @@ -338,7 +379,7 @@ static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { } // Handle CTR interrupt for the TX/OUT direction -static void handle_ctr_tx(uint32_t ch_id) { +static inline void handle_ctr_tx(uint32_t ch_id) { uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; hcd_channel_t* channel = &_hcd_data.channel[ch_id]; TU_VERIFY(channel->allocated[TUSB_DIR_OUT] == 1,); @@ -358,7 +399,7 @@ static void handle_ctr_tx(uint32_t ch_id) { } // Handle CTR interrupt for the RX/IN direction -static void handle_ctr_rx(uint32_t ch_id) { +static inline void handle_ctr_rx(uint32_t ch_id) { uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; hcd_channel_t* channel = &_hcd_data.channel[ch_id]; TU_VERIFY(channel->allocated[TUSB_DIR_IN] == 1,); @@ -393,28 +434,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) { uint32_t const ch_reg = ch_read(ch_id); if (ch_reg & USB_EP_CTR_RX) { - #ifdef FSDEV_BUS_32BIT - /* https://www.st.com/resource/en/errata_sheet/es0561-stm32h503cbebkbrb-device-errata-stmicroelectronics.pdf - * https://www.st.com/resource/en/errata_sheet/es0587-stm32u535xx-and-stm32u545xx-device-errata-stmicroelectronics.pdf - * From H503/U535 errata: Buffer description table update completes after CTR interrupt triggers - * Description: - * - During OUT transfers, the correct transfer interrupt (CTR) is triggered a little before the last USB SRAM accesses - * have completed. If the software responds quickly to the interrupt, the full buffer contents may not be correct. - * Workaround: - * - Software should ensure that a small delay is included before accessing the SRAM contents. This delay - * should be 800 ns in Full Speed mode and 6.4 μs in Low Speed mode - * - Since H5 can run up to 250Mhz -> 1 cycle = 4ns. Per errata, we need to wait 200 cycles. Though executing code - * also takes time, so we'll wait 60 cycles (count = 20). - * - Since Low Speed mode is not supported/popular, we will ignore it for now. - * - * Note: this errata may also apply to G0, U5, H5 etc. - */ - volatile uint32_t cycle_count = 20; // defined as PCD_RX_PMA_CNT in stm32 hal_driver - while (cycle_count > 0U) { - cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) - } - #endif - ch_write_clear_ctr(ch_id, TUSB_DIR_IN); handle_ctr_rx(ch_id); } From 5d56828e43ef5f894c4586e7e7a61c3fbbbbfaf9 Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Thu, 27 Nov 2025 11:02:49 +0100 Subject: [PATCH 08/21] extract core reset Signed-off-by: Zixun LI --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 18 +---------- src/portable/st/stm32_fsdev/fsdev_common.c | 32 ++++++++++++++++++- src/portable/st/stm32_fsdev/fsdev_common.h | 6 +++- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 19 +---------- 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index a6c8d2453..3c4e4fc9b 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -173,23 +173,9 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint //--------------------------------------------------------------------+ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rh_init; - // Follow the RM mentions to use a special ordering of PDWN and FRES - for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us - asm("NOP"); - } - // Perform USB peripheral reset - FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; - for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us - asm("NOP"); - } + fsdev_core_reset(); - FSDEV_REG->CNTR &= ~USB_CNTR_PDWN; - - // Wait startup time, for F042 and F070, this is <= 1 us. - for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us - asm("NOP"); - } FSDEV_REG->CNTR = 0; // Enable USB #if !defined(FSDEV_BUS_32BIT) @@ -197,8 +183,6 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; #endif - FSDEV_REG->ISTR = 0; // Clear pending interrupts - // Reset endpoints to disabled for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { // This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED. diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c index d021a6abf..5c7df6809 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.c +++ b/src/portable/st/stm32_fsdev/fsdev_common.c @@ -31,6 +31,35 @@ #include "fsdev_common.h" +//--------------------------------------------------------------------+ +// Global +//--------------------------------------------------------------------+ + +// Reset the USB Core +void fsdev_core_reset(void) { + // Follow the RM mentions to use a special ordering of PDWN and FRES + for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us + asm("NOP"); + } + + // Perform USB peripheral reset + FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; + for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us + asm("NOP"); + } + + FSDEV_REG->CNTR &= ~USB_CNTR_PDWN; + + // Wait startup time, for F042 and F070, this is <= 1 us. + for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us + asm("NOP"); + } + + // Clear pending interrupts + FSDEV_REG->ISTR = 0; +} + + //--------------------------------------------------------------------+ // PMA read/write //--------------------------------------------------------------------+ @@ -199,7 +228,7 @@ bool fsdev_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) // BTable Helper //--------------------------------------------------------------------+ -/* Aligned buffer size according to hardware */ +// Aligned buffer size according to hardware uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block) { /* The STM32 full speed USB peripheral supports only a limited set of * buffer sizes given by the RX buffer entry format in the USB_BTABLE. */ @@ -217,6 +246,7 @@ uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_bloc return (*num_block) * block_in_bytes; } +// Set RX buffer size void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) { uint8_t blsize, num_block; (void) pma_align_buffer_size(wCount, &blsize, &num_block); diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h index e363245ec..9cf61031d 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.h +++ b/src/portable/st/stm32_fsdev/fsdev_common.h @@ -311,9 +311,13 @@ TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_ #endif } -/* Aligned buffer size according to hardware */ +// Reset the USB Core +void fsdev_core_reset(void); + +// Aligned buffer size according to hardware uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block); +// Set RX buffer size void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount); //--------------------------------------------------------------------+ diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 362d7df7b..168366058 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -203,26 +203,9 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { (void) rh_init; - // Follow the RM mentions to use a special ordering of PDWN and FRES - for (volatile uint32_t i = 0; i < 200; i++) { - asm("NOP"); - } - - // Perform USB peripheral reset - FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; - for (volatile uint32_t i = 0; i < 200; i++) { - asm("NOP"); - } - - FSDEV_REG->CNTR &= ~USB_CNTR_PDWN; - - // Wait startup time - for (volatile uint32_t i = 0; i < 200; i++) { - asm("NOP"); - } + fsdev_core_reset(); FSDEV_REG->CNTR = USB_CNTR_HOST; // Enable USB in Host mode - FSDEV_REG->ISTR = 0; // Clear pending interrupts // Reset channels to disabled for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { From 9742ba734f8ef780fb2b4c94848c4bd534afdafe Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Thu, 27 Nov 2025 11:34:37 +0100 Subject: [PATCH 09/21] Add fsdev_deinit Signed-off-by: Zixun LI --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 8 ++++++++ src/portable/st/stm32_fsdev/fsdev_common.c | 15 +++++++++++++++ src/portable/st/stm32_fsdev/fsdev_common.h | 3 +++ src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 8 ++++++++ 4 files changed, 34 insertions(+) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 3c4e4fc9b..351916147 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -199,6 +199,14 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { return true; } +bool dcd_deinit(uint8_t rhport) { + (void)rhport; + + fsdev_deinit(); + + return true; +} + void dcd_sof_enable(uint8_t rhport, bool en) { (void)rhport; diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c index 5c7df6809..d0f3460b6 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.c +++ b/src/portable/st/stm32_fsdev/fsdev_common.c @@ -59,6 +59,21 @@ void fsdev_core_reset(void) { FSDEV_REG->ISTR = 0; } +// De-initialize the USB Core +void fsdev_deinit(void) { + // Disable all interrupts and force USB reset + FSDEV_REG->CNTR = USB_CNTR_FRES; + + // Clear pending interrupts + FSDEV_REG->ISTR = 0; + + // Put USB peripheral in power down mode + FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; + for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us + asm("NOP"); + } +} + //--------------------------------------------------------------------+ // PMA read/write diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h index 9cf61031d..0c67ee0c7 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.h +++ b/src/portable/st/stm32_fsdev/fsdev_common.h @@ -314,6 +314,9 @@ TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_ // Reset the USB Core void fsdev_core_reset(void); +// De-initialize the USB Core +void fsdev_deinit(void); + // Aligned buffer size according to hardware uint16_t pma_align_buffer_size(uint16_t size, uint8_t* blsize, uint8_t* num_block); diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 168366058..39b9ac2d3 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -226,6 +226,14 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { return true; } +bool hcd_deinit(uint8_t rhport) { + (void)rhport; + + fsdev_deinit(); + + return true; +} + static void port_status_handler(uint8_t rhport, bool in_isr) { uint32_t const fnr_reg = FSDEV_REG->FNR; uint32_t const istr_reg = FSDEV_REG->ISTR; From a25e9e86c83785e8ce91b1c7b485a106195d368a Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Thu, 27 Nov 2025 11:35:25 +0100 Subject: [PATCH 10/21] Remove redundant EP reg clear Signed-off-by: Zixun LI --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 10 +++------- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 5 ----- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 351916147..087639d4b 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -183,14 +183,10 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; #endif - // Reset endpoints to disabled - for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { - // This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED. - ep_write(i, 0u, false); - } - + // Enable interrupts for device mode FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | - USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM; + USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM; + handle_bus_reset(rhport); // Enable pull-up if supported diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 39b9ac2d3..00c71ce6c 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -207,11 +207,6 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { FSDEV_REG->CNTR = USB_CNTR_HOST; // Enable USB in Host mode - // Reset channels to disabled - for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) { - ch_write(i, 0u, false); - } - tu_memclr(&_hcd_data, sizeof(_hcd_data)); // Enable interrupts for host mode From b997ec725812d2f6a573610ba0dd817f271eddea Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Thu, 27 Nov 2025 11:49:30 +0100 Subject: [PATCH 11/21] usbd: clear state and call callback on deinit Signed-off-by: Zixun LI --- src/device/usbd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/device/usbd.c b/src/device/usbd.c index d4dfae4b4..f923dfe08 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -587,6 +587,10 @@ bool tud_deinit(uint8_t rhport) { } } + // Clear device data + tu_varclr(&_usbd_dev); + usbd_control_reset(); + // Deinit device queue & task osal_queue_delete(_usbd_q); _usbd_q = NULL; @@ -598,6 +602,9 @@ bool tud_deinit(uint8_t rhport) { #endif _usbd_rhport = RHPORT_INVALID; + + tud_umount_cb(); + return true; } From 8914f402e5cdf372ade2ed1f4053ce14feffbeda Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Thu, 27 Nov 2025 12:10:27 +0100 Subject: [PATCH 12/21] free previously allocated OUT endpoint if IN allocation failed Signed-off-by: Zixun LI --- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 00c71ce6c..7d3deba34 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -516,7 +516,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const uint8_t const ep_type = ep_desc->bmAttributes.xfer; uint8_t const ep_id = endpoint_alloc(); - TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8); hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; edpt->dev_addr = dev_addr; @@ -530,7 +530,11 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const // EP0 is bi-directional, so we need to open both OUT and IN channels if (ep_addr == 0) { uint8_t const ep_id_in = endpoint_alloc(); - TU_ASSERT(ep_id_in < CFG_TUH_FSDEV_ENDPOINT_MAX); + if (ep_id_in == TUSB_INDEX_INVALID_8) { + // free previously allocated OUT endpoint + endpoint_dealloc(edpt); + TU_ASSERT(false); + } _hcd_data.edpt[ep_id_in] = *edpt; // copy from OUT endpoint _hcd_data.edpt[ep_id_in].ep_addr = 0 | TUSB_DIR_IN_MASK; @@ -543,13 +547,13 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { (void) rhport; uint8_t const ep_id = endpoint_find(dev_addr, ep_addr); - TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8); edpoint_close(ep_id); if (ep_addr == 0) { uint8_t const ep_id_in = endpoint_find(dev_addr, 0 | TUSB_DIR_IN_MASK); - TU_ASSERT(ep_id_in < CFG_TUH_FSDEV_ENDPOINT_MAX); + TU_ASSERT(ep_id_in != TUSB_INDEX_INVALID_8); edpoint_close(ep_id_in); } @@ -564,7 +568,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b TU_LOG(FSDEV_DEBUG, "hcd_edpt_xfer addr=%u ep=0x%02X len=%u\r\n", dev_addr, ep_addr, buflen); uint8_t const ep_id = endpoint_find(dev_addr, ep_addr); - TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8); hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; @@ -579,7 +583,7 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { (void) rhport; uint8_t const ep_id = endpoint_find(dev_addr, ep_addr); - TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8); tusb_dir_t const dir = tu_edpt_dir(ep_addr); for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { @@ -602,7 +606,7 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet (void) rhport; uint8_t const ep_id = endpoint_find(dev_addr, 0); - TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8); hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; edpt->next_setup = true; @@ -618,7 +622,7 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { (void) ep_addr; uint8_t const ep_id = endpoint_find(dev_addr, 0); - TU_ASSERT(ep_id < CFG_TUH_FSDEV_ENDPOINT_MAX); + TU_ASSERT(ep_id != TUSB_INDEX_INVALID_8); hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id]; edpt->pid = 0; From 07ff25eb1e9871082b92161296725c5d312d3558 Mon Sep 17 00:00:00 2001 From: Zixun LI Date: Thu, 27 Nov 2025 17:17:03 +0100 Subject: [PATCH 13/21] Add max nak config Signed-off-by: Zixun LI --- src/host/usbh.h | 9 +- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 203 ++++++++++++------ 2 files changed, 140 insertions(+), 72 deletions(-) diff --git a/src/host/usbh.h b/src/host/usbh.h index 4b6747848..697c911ff 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -95,18 +95,23 @@ enum { TUH_CFGID_INVALID = 0, TUH_CFGID_RPI_PIO_USB_CONFIGURATION = 100, // cfg_param: pio_usb_configuration_t TUH_CFGID_MAX3421 = 200, + TUH_CFGID_FSDEV = 300, }; typedef struct { - uint8_t max_nak; // max NAK per endpoint per frame to save CPU/SPI bus usage + uint8_t max_nak; // max NAK per endpoint per frame to save CPU/SPI bus usage (0=unlimited) uint8_t cpuctl; // R16: CPU Control Register uint8_t pinctl; // R17: Pin Control Register. FDUPSPI bit is ignored } tuh_configure_max3421_t; +typedef struct { + uint8_t max_nak; // max NAK per endpoint per frame to save CPU usage (0=unlimited) +} tuh_configure_fsdev_t; + typedef union { // For TUH_CFGID_RPI_PIO_USB_CONFIGURATION use pio_usb_configuration_t - tuh_configure_max3421_t max3421; + tuh_configure_fsdev_t fsdev; } tuh_configure_param_t; //--------------------------------------------------------------------+ diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 7d3deba34..ff2f2946e 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -60,48 +60,56 @@ TU_VERIFY_STATIC(CFG_TUH_FSDEV_ENDPOINT_MAX <= 255, "currently only use 8-bit for index"); enum { - HCD_XFER_ERROR_MAX = 3 + HCD_XFER_ERROR_MAX = 3, + HCD_XFER_NAK_MAX = 15, + HCD_XFER_NAK_DEFAULT = 3, }; // Host driver struct for each opened endpoint typedef struct { uint8_t *buffer; uint16_t buflen; + uint16_t queued_len; uint16_t max_packet_size; uint8_t dev_addr; uint8_t ep_addr; uint8_t ep_type; uint8_t interval; struct TU_ATTR_PACKED { - uint8_t low_speed : 1; + uint8_t ls_pre : 1; uint8_t allocated : 1; uint8_t next_setup : 1; uint8_t pid : 1; }; } hcd_endpoint_t; +// Channel direction state +typedef struct { + hcd_endpoint_t* edpt; + struct TU_ATTR_PACKED { + uint8_t allocated : 1; + uint8_t retry : 3; + uint8_t nak : 4; // Max NAK count in current frame + }; +} hcd_channel_dir_t; + // Additional info for each channel when it is active typedef struct { - hcd_endpoint_t* edpt[2]; // OUT/IN - uint16_t queued_len[2]; uint8_t dev_addr; uint8_t ep_num; uint8_t ep_type; - uint8_t allocated[2]; - uint8_t retry[2]; + hcd_channel_dir_t out, in; } hcd_channel_t; -// Root hub port state static struct { - bool connected; -} _hcd_port; - -typedef struct { hcd_channel_t channel[FSDEV_EP_COUNT]; hcd_endpoint_t edpt[CFG_TUH_FSDEV_ENDPOINT_MAX]; -} hcd_data_t; + bool connected; +} _hcd_data; -hcd_data_t _hcd_data; +static tuh_configure_fsdev_t _tuh_cfg = { + .max_nak = HCD_XFER_NAK_DEFAULT, +}; //--------------------------------------------------------------------+ // Prototypes @@ -114,7 +122,6 @@ static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type) static bool edpt_xfer_kickoff(uint8_t ep_id); static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir); static void edpoint_close(uint8_t ep_id); -static void port_status_handler(uint8_t rhport, bool in_isr); static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); static void ch_handle_nak(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); static void ch_handle_stall(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); @@ -129,7 +136,11 @@ static inline void endpoint_dealloc(hcd_endpoint_t* edpt) { } static inline void channel_dealloc(hcd_channel_t* ch, tusb_dir_t dir) { - ch->allocated[dir] = 0; + if (dir == TUSB_DIR_OUT) { + ch->out.allocated = 0; + } else { + ch->in.allocated = 0; + } } // Write channel state in specified direction @@ -194,9 +205,11 @@ static inline uint16_t channel_get_rx_count(uint8_t ch_id) { // Optional HCD configuration, called by tuh_configure() bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) { (void) rhport; - (void) cfg_id; - (void) cfg_param; - return false; + TU_VERIFY(cfg_id == TUH_CFGID_FSDEV && cfg_param != NULL); + + tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param; + _tuh_cfg.max_nak = tu_min8(cfg->fsdev.max_nak, HCD_XFER_NAK_MAX); + return true; } // Initialize controller to host mode @@ -210,11 +223,11 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { tu_memclr(&_hcd_data, sizeof(_hcd_data)); // Enable interrupts for host mode - FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | + FSDEV_REG->CNTR |= USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SOFM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_ERRM | USB_CNTR_PMAOVRM; // Initialize port state - _hcd_port.connected = false; + _hcd_data.connected = false; fsdev_connect(rhport); @@ -229,35 +242,48 @@ bool hcd_deinit(uint8_t rhport) { return true; } -static void port_status_handler(uint8_t rhport, bool in_isr) { +//--------------------------------------------------------------------+ +// Interrupt Helper Functions +//--------------------------------------------------------------------+ + +static inline void sof_handler(void) { + // Reset NAK counters for all active channels + for (uint8_t ch_id = 0; ch_id < FSDEV_EP_COUNT; ch_id++) { + hcd_channel_t* channel = &_hcd_data.channel[ch_id]; + if (channel->out.allocated) { + channel->out.nak = 0; + } + if (channel->in.allocated) { + channel->in.nak = 0; + } + } +} + +static inline void port_status_handler(uint8_t rhport, bool in_isr) { uint32_t const fnr_reg = FSDEV_REG->FNR; uint32_t const istr_reg = FSDEV_REG->ISTR; // SE0 detected USB Disconnected state if ((fnr_reg & (USB_FNR_RXDP | USB_FNR_RXDM)) == 0U) { - _hcd_port.connected = false; + _hcd_data.connected = false; hcd_event_device_remove(rhport, in_isr); return; } - if (!_hcd_port.connected) { + if (!_hcd_data.connected) { // J-state or K-state detected & LastState=Disconnected if (((fnr_reg & USB_FNR_RXDP) != 0U) || ((istr_reg & USB_ISTR_LS_DCONN) != 0U)) { - _hcd_port.connected = true; + _hcd_data.connected = true; hcd_event_device_attach(rhport, in_isr); } } else { // J-state or K-state detected & lastState=Connected: a Missed disconnection is detected if (((fnr_reg & USB_FNR_RXDP) != 0U) || ((istr_reg & USB_ISTR_LS_DCONN) != 0U)) { - _hcd_port.connected = false; + _hcd_data.connected = false; hcd_event_device_remove(rhport, in_isr); } } } -//--------------------------------------------------------------------+ -// Interrupt Helper Functions -//--------------------------------------------------------------------+ - // Handle ACK response static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; @@ -271,38 +297,40 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { if (dir == TUSB_DIR_OUT) { // OUT/TX direction - if (edpt->buflen != channel->queued_len[TUSB_DIR_OUT]) { + if (edpt->buflen != edpt->queued_len) { // More data to send - uint16_t const len = tu_min16(edpt->buflen - channel->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); + uint16_t const len = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size); uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_TX); - fsdev_write_packet_memory(pma_addr, &(edpt->buffer[channel->queued_len[TUSB_DIR_OUT]]), len); + fsdev_write_packet_memory(pma_addr, &(edpt->buffer[edpt->queued_len]), len); btable_set_count(ch_id, BTABLE_BUF_TX, len); - channel->queued_len[TUSB_DIR_OUT] += len; + edpt->queued_len += len; channel_write_status(ch_id, ch_reg, TUSB_DIR_OUT, EP_STAT_VALID, false); + channel->out.nak = 0; } else { // Transfer complete channel_dealloc(channel, TUSB_DIR_OUT); edpt->pid = (ch_reg & USB_CHEP_DTOG_TX) ? 1 : 0; - hcd_event_xfer_complete(daddr, ep_num, channel->queued_len[TUSB_DIR_OUT], XFER_RESULT_SUCCESS, true); + hcd_event_xfer_complete(daddr, ep_num, edpt->queued_len, XFER_RESULT_SUCCESS, true); } } else { // IN/RX direction uint16_t const rx_count = channel_get_rx_count(ch_id); uint16_t pma_addr = (uint16_t) btable_get_addr(ch_id, BTABLE_BUF_RX); - fsdev_read_packet_memory(edpt->buffer + channel->queued_len[TUSB_DIR_IN], pma_addr, rx_count); - channel->queued_len[TUSB_DIR_IN] += rx_count; + fsdev_read_packet_memory(edpt->buffer + edpt->queued_len, pma_addr, rx_count); + edpt->queued_len += rx_count; - if ((rx_count < edpt->max_packet_size) || (channel->queued_len[TUSB_DIR_IN] >= edpt->buflen)) { + if ((rx_count < edpt->max_packet_size) || (edpt->queued_len >= edpt->buflen)) { // Transfer complete (short packet or all bytes received) channel_dealloc(channel, TUSB_DIR_IN); edpt->pid = (ch_reg & USB_CHEP_DTOG_RX) ? 1 : 0; - hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, channel->queued_len[TUSB_DIR_IN], XFER_RESULT_SUCCESS, true); + hcd_event_xfer_complete(daddr, ep_num | TUSB_DIR_IN_MASK, edpt->queued_len, XFER_RESULT_SUCCESS, true); } else { // More data expected - uint16_t const cnt = tu_min16(edpt->buflen - channel->queued_len[TUSB_DIR_IN], edpt->max_packet_size); + uint16_t const cnt = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size); btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, cnt); channel_write_status(ch_id, ch_reg, TUSB_DIR_IN, EP_STAT_VALID, false); + channel->in.nak = 0; } } } @@ -316,10 +344,17 @@ static void ch_handle_nak(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { if (ep_id == TUSB_INDEX_INVALID_8) return; hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; - // Retry non-periodic transfer immediately, + // Retry non-periodic transfer immediately if NAK count not exceeded // Periodic transfer will be retried by next frame automatically if (edpt->ep_type == TUSB_XFER_CONTROL || edpt->ep_type == TUSB_XFER_BULK) { - channel_write_status(ch_id, ch_reg, dir, EP_STAT_VALID, false); + hcd_channel_dir_t* channel_dir = + (dir == TUSB_DIR_OUT) ? &(_hcd_data.channel[ch_id].out) : &(_hcd_data.channel[ch_id].in); + if (channel_dir->nak < HCD_XFER_NAK_MAX) { + channel_dir->nak++; + } + if (channel_dir->nak < _tuh_cfg.max_nak || _tuh_cfg.max_nak == 0) { + channel_write_status(ch_id, ch_reg, dir, EP_STAT_VALID, false); + } } } @@ -328,13 +363,17 @@ static void ch_handle_stall(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { uint8_t const ep_num = ch_reg & USB_EPADDR_FIELD; uint8_t const daddr = (ch_reg & USB_CHEP_DEVADDR_Msk) >> USB_CHEP_DEVADDR_Pos; + uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0)); + if (ep_id == TUSB_INDEX_INVALID_8) return; + + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; hcd_channel_t* channel = &_hcd_data.channel[ch_id]; channel_dealloc(channel, dir); channel_write_status(ch_id, ch_reg, dir, EP_STAT_DISABLED, false); hcd_event_xfer_complete(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0), - channel->queued_len[dir], XFER_RESULT_STALLED, true); + edpt->queued_len, XFER_RESULT_STALLED, true); } // Handle error response @@ -345,21 +384,24 @@ static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { uint8_t ep_id = endpoint_find(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0)); if (ep_id == TUSB_INDEX_INVALID_8) return; + hcd_endpoint_t* edpt = &_hcd_data.edpt[ep_id]; hcd_channel_t* channel = &_hcd_data.channel[ch_id]; ch_reg &= USB_EPREG_MASK | CH_STAT_MASK(dir); ch_reg &= ~(dir == TUSB_DIR_OUT ? USB_CH_ERRTX : USB_CH_ERRRX); - if (channel->retry[dir] < HCD_XFER_ERROR_MAX) { + hcd_channel_dir_t* channel_dir = + (dir == TUSB_DIR_OUT) ? &(_hcd_data.channel[ch_id].out) : &(_hcd_data.channel[ch_id].in); + if (channel_dir->retry < HCD_XFER_ERROR_MAX) { // Retry - channel->retry[dir]++; + channel_dir->retry++; ch_change_status(&ch_reg, dir, EP_STAT_VALID); } else { // Failed after retries channel_dealloc(channel, dir); ch_change_status(&ch_reg, dir, EP_STAT_DISABLED); hcd_event_xfer_complete(daddr, ep_num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0), - channel->queued_len[dir], XFER_RESULT_FAILED, true); + edpt->queued_len, XFER_RESULT_FAILED, true); } ch_write(ch_id, ch_reg, false); } @@ -368,7 +410,7 @@ static void ch_handle_error(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) { static inline void handle_ctr_tx(uint32_t ch_id) { uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; hcd_channel_t* channel = &_hcd_data.channel[ch_id]; - TU_VERIFY(channel->allocated[TUSB_DIR_OUT] == 1,); + TU_VERIFY(channel->out.allocated == 1,); if ((ch_reg & USB_CH_ERRTX) == 0U) { // No error @@ -388,7 +430,7 @@ static inline void handle_ctr_tx(uint32_t ch_id) { static inline void handle_ctr_rx(uint32_t ch_id) { uint32_t ch_reg = ch_read(ch_id) | USB_EP_CTR_TX | USB_EP_CTR_RX; hcd_channel_t* channel = &_hcd_data.channel[ch_id]; - TU_VERIFY(channel->allocated[TUSB_DIR_IN] == 1,); + TU_VERIFY(channel->in.allocated == 1,); if ((ch_reg & USB_CH_ERRRX) == 0U) { // No error @@ -408,7 +450,13 @@ static inline void handle_ctr_rx(uint32_t ch_id) { void hcd_int_handler(uint8_t rhport, bool in_isr) { uint32_t int_status = FSDEV_REG->ISTR; - /* Port Change Detected (Connection/Disconnection) */ + // Start of Frame + if (int_status & USB_ISTR_SOF) { + FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_SOF; + sof_handler(); + } + + // Port Change Detected (Connection/Disconnection) if (int_status & USB_ISTR_DCON) { FSDEV_REG->ISTR = (fsdev_bus_t)~USB_ISTR_DCON; port_status_handler(rhport, in_isr); @@ -464,7 +512,7 @@ uint32_t hcd_frame_number(uint8_t rhport) { // Get the current connect status of roothub port bool hcd_port_connect_status(uint8_t rhport) { (void) rhport; - return _hcd_port.connected; + return _hcd_data.connected; } // Reset USB bus on the port @@ -525,7 +573,7 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const edpt->max_packet_size = packet_size; edpt->interval = ep_desc->bInterval; edpt->pid = 0; - edpt->low_speed = (hcd_port_speed_get(rhport) == TUSB_SPEED_FULL && tuh_speed_get(dev_addr) == TUSB_SPEED_LOW) ? 1 : 0; + edpt->ls_pre = (hcd_port_speed_get(rhport) == TUSB_SPEED_FULL && tuh_speed_get(dev_addr) == TUSB_SPEED_LOW) ? 1 : 0; // EP0 is bi-directional, so we need to open both OUT and IN channels if (ep_addr == 0) { @@ -574,6 +622,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b edpt->buffer = buffer; edpt->buflen = buflen; + edpt->queued_len = 0; return edpt_xfer_kickoff(ep_id); } @@ -588,8 +637,9 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { hcd_channel_t* channel = &_hcd_data.channel[i]; + uint8_t const allocated = (dir == TUSB_DIR_OUT) ? channel->out.allocated : channel->in.allocated; - if (channel->allocated[dir] == 1 && + if (allocated == 1 && channel->dev_addr == dev_addr && channel->ep_num == tu_edpt_number(ep_addr)) { channel_dealloc(channel, dir); @@ -664,11 +714,11 @@ static void edpoint_close(uint8_t ep_id) { for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { hcd_channel_t* channel = &_hcd_data.channel[i]; uint32_t ch_reg = ch_read(i) | USB_EP_CTR_TX | USB_EP_CTR_RX; - if (channel->allocated[TUSB_DIR_OUT] == 1 && channel->edpt[TUSB_DIR_OUT] == edpt) { + if (channel->out.allocated == 1 && channel->out.edpt == edpt) { channel_dealloc(channel, TUSB_DIR_OUT); channel_write_status(i, ch_reg, TUSB_DIR_OUT, EP_STAT_DISABLED, true); } - if (channel->allocated[TUSB_DIR_IN] == 1 && channel->edpt[TUSB_DIR_IN] == edpt) { + if (channel->in.allocated == 1 && channel->in.edpt == edpt) { channel_dealloc(channel, TUSB_DIR_IN); channel_write_status(i, ch_reg, TUSB_DIR_IN, EP_STAT_DISABLED, true); } @@ -697,27 +747,37 @@ static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type) // Find channel allocate for same ep_num but other direction tusb_dir_t const other_dir = (dir == TUSB_DIR_IN) ? TUSB_DIR_OUT : TUSB_DIR_IN; for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { - if (_hcd_data.channel[i].allocated[dir] == 0 && - _hcd_data.channel[i].allocated[other_dir] == 1 && + uint8_t const allocated_dir = (dir == TUSB_DIR_OUT) ? _hcd_data.channel[i].out.allocated : _hcd_data.channel[i].in.allocated; + uint8_t const allocated_other = (other_dir == TUSB_DIR_OUT) ? _hcd_data.channel[i].out.allocated : _hcd_data.channel[i].in.allocated; + if (allocated_dir == 0 && + allocated_other == 1 && _hcd_data.channel[i].dev_addr == dev_addr && _hcd_data.channel[i].ep_num == ep_num && _hcd_data.channel[i].ep_type == ep_type) { - _hcd_data.channel[i].allocated[dir] = 1; - _hcd_data.channel[i].queued_len[dir] = 0; - _hcd_data.channel[i].retry[dir] = 0; + if (dir == TUSB_DIR_OUT) { + _hcd_data.channel[i].out.allocated = 1; + _hcd_data.channel[i].out.retry = 0; + } else { + _hcd_data.channel[i].in.allocated = 1; + _hcd_data.channel[i].in.retry = 0; + } return i; } } // Find free channel for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) { - if (_hcd_data.channel[i].allocated[0] == 0 && _hcd_data.channel[i].allocated[1] == 0) { + if (_hcd_data.channel[i].out.allocated == 0 && _hcd_data.channel[i].in.allocated == 0) { _hcd_data.channel[i].dev_addr = dev_addr; _hcd_data.channel[i].ep_num = ep_num; _hcd_data.channel[i].ep_type = ep_type; - _hcd_data.channel[i].allocated[dir] = 1; - _hcd_data.channel[i].queued_len[dir] = 0; - _hcd_data.channel[i].retry[dir] = 0; + if (dir == TUSB_DIR_OUT) { + _hcd_data.channel[i].out.allocated = 1; + _hcd_data.channel[i].out.retry = 0; + } else { + _hcd_data.channel[i].in.allocated = 1; + _hcd_data.channel[i].in.retry = 0; + } return i; } } @@ -733,16 +793,19 @@ static bool edpt_xfer_kickoff(uint8_t ep_id) { TU_ASSERT(ch_id != TUSB_INDEX_INVALID_8); // all channel are in used tusb_dir_t const dir = tu_edpt_dir(edpt->ep_addr); - hcd_channel_t* channel = &_hcd_data.channel[ch_id]; - channel->edpt[dir] = edpt; + if (dir == TUSB_DIR_OUT) { + channel->out.edpt = edpt; + } else { + channel->in.edpt = edpt; + } return channel_xfer_start(ch_id, dir); } static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) { hcd_channel_t* channel = &_hcd_data.channel[ch_id]; - hcd_endpoint_t* edpt = channel->edpt[dir]; + hcd_endpoint_t* edpt = (dir == TUSB_DIR_OUT) ? channel->out.edpt : channel->in.edpt; uint32_t ch_reg = ch_read(ch_id) & ~USB_EPREG_MASK; ch_reg |= tu_edpt_number(edpt->ep_addr) | edpt->dev_addr << USB_CHEP_DEVADDR_Pos | @@ -771,28 +834,28 @@ static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir) { btable_set_addr(ch_id, dir == TUSB_DIR_OUT ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr); if (dir == TUSB_DIR_OUT) { - uint16_t const len = tu_min16(edpt->buflen - channel->queued_len[TUSB_DIR_OUT], edpt->max_packet_size); + uint16_t const len = tu_min16(edpt->buflen - edpt->queued_len, edpt->max_packet_size); - fsdev_write_packet_memory(pma_addr, &(edpt->buffer[channel->queued_len[TUSB_DIR_OUT]]), len); + fsdev_write_packet_memory(pma_addr, &(edpt->buffer[edpt->queued_len]), len); btable_set_count(ch_id, BTABLE_BUF_TX, len); - channel->queued_len[TUSB_DIR_OUT] += len; + edpt->queued_len += len; } else { btable_set_rx_bufsize(ch_id, BTABLE_BUF_RX, edpt->max_packet_size); } - if (edpt->low_speed == 1) { + if (edpt->ls_pre == 1) { ch_reg |= USB_CHEP_LSEP; } else { ch_reg &= ~USB_CHEP_LSEP; } + // Setup DATA/STATUS phase start with DATA1 if (tu_edpt_number(edpt->ep_addr) == 0) { edpt->pid = 1; } if (edpt->next_setup) { - // Setup packet uses IN token edpt->next_setup = false; ch_reg |= USB_EP_SETUP; edpt->pid = 0; From 2d3aaaf6e12ba62f73ca31d5d239ac4bbc70fde4 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 27 Nov 2025 22:09:29 +0100 Subject: [PATCH 14/21] bsp/stm32h5: support host mode Signed-off-by: HiFiPhile --- examples/host/bare_api/only.txt | 1 + examples/host/cdc_msc_hid/only.txt | 1 + examples/host/cdc_msc_hid_freertos/only.txt | 1 + examples/host/device_info/only.txt | 1 + examples/host/hid_controller/only.txt | 1 + examples/host/midi_rx/only.txt | 1 + examples/host/msc_file_explorer/only.txt | 1 + hw/bsp/stm32g0/family.c | 2 +- hw/bsp/stm32g0/family.cmake | 1 + hw/bsp/stm32h5/boards/stm32h503nucleo/board.h | 47 ++++-- hw/bsp/stm32h5/boards/stm32h563nucleo/board.h | 47 ++++-- .../stm32h5/boards/stm32h573i_dk/board.cmake | 7 + hw/bsp/stm32h5/boards/stm32h573i_dk/board.h | 152 ++++++++++++++++-- hw/bsp/stm32h5/boards/stm32h573i_dk/board.mk | 7 + hw/bsp/stm32h5/family.c | 85 +++++----- hw/bsp/stm32h5/family.cmake | 3 + hw/bsp/stm32h5/family.mk | 1 + hw/bsp/stm32h5/stm32h5xx_hal_conf.h | 2 +- hw/bsp/stm32u5/family.c | 15 +- 19 files changed, 279 insertions(+), 97 deletions(-) diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt index a7bebf1d9..4cd457879 100644 --- a/examples/host/bare_api/only.txt +++ b/examples/host/bare_api/only.txt @@ -16,6 +16,7 @@ mcu:MAX3421 mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt index a7bebf1d9..4cd457879 100644 --- a/examples/host/cdc_msc_hid/only.txt +++ b/examples/host/cdc_msc_hid/only.txt @@ -16,6 +16,7 @@ mcu:MAX3421 mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 diff --git a/examples/host/cdc_msc_hid_freertos/only.txt b/examples/host/cdc_msc_hid_freertos/only.txt index 8da7a47d6..2322d4ecf 100644 --- a/examples/host/cdc_msc_hid_freertos/only.txt +++ b/examples/host/cdc_msc_hid_freertos/only.txt @@ -12,6 +12,7 @@ mcu:MAX3421 mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 diff --git a/examples/host/device_info/only.txt b/examples/host/device_info/only.txt index 069f92d83..5b68f0774 100644 --- a/examples/host/device_info/only.txt +++ b/examples/host/device_info/only.txt @@ -16,6 +16,7 @@ mcu:RAXXX mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 diff --git a/examples/host/hid_controller/only.txt b/examples/host/hid_controller/only.txt index cba58f8e8..b859b4cc0 100644 --- a/examples/host/hid_controller/only.txt +++ b/examples/host/hid_controller/only.txt @@ -15,6 +15,7 @@ mcu:RAXXX mcu:MAX3421 mcu:STM32F4 mcu:STM32F7 +mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 diff --git a/examples/host/midi_rx/only.txt b/examples/host/midi_rx/only.txt index 133a7c9a0..022be899d 100644 --- a/examples/host/midi_rx/only.txt +++ b/examples/host/midi_rx/only.txt @@ -18,6 +18,7 @@ mcu:RX65X mcu:RAXXX mcu:STM32F4 mcu:STM32F7 +mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt index a7bebf1d9..4cd457879 100644 --- a/examples/host/msc_file_explorer/only.txt +++ b/examples/host/msc_file_explorer/only.txt @@ -16,6 +16,7 @@ mcu:MAX3421 mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 diff --git a/hw/bsp/stm32g0/family.c b/hw/bsp/stm32g0/family.c index 7b86aedb4..4b175b0ec 100644 --- a/hw/bsp/stm32g0/family.c +++ b/hw/bsp/stm32g0/family.c @@ -37,7 +37,7 @@ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ void USB_UCPD1_2_IRQHandler(void) { - tud_int_handler(0); + tusb_int_handler(0, true); } //--------------------------------------------------------------------+ diff --git a/hw/bsp/stm32g0/family.cmake b/hw/bsp/stm32g0/family.cmake index 0ce85168e..4b520a0e1 100644 --- a/hw/bsp/stm32g0/family.cmake +++ b/hw/bsp/stm32g0/family.cmake @@ -64,6 +64,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${TOP}/src/portable/st/typec/typec_stm32.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} diff --git a/hw/bsp/stm32h5/boards/stm32h503nucleo/board.h b/hw/bsp/stm32h5/boards/stm32h503nucleo/board.h index c8b5e31f5..b57fab10e 100644 --- a/hw/bsp/stm32h5/boards/stm32h503nucleo/board.h +++ b/hw/bsp/stm32h5/boards/stm32h503nucleo/board.h @@ -37,24 +37,33 @@ extern "C" { #endif -// LED -#define LED_PORT GPIOA -#define LED_PIN GPIO_PIN_5 -#define LED_STATE_ON 1 +#define PINID_LED 0 +#define PINID_BUTTON 1 +#define PINID_UART_TX 2 +#define PINID_UART_RX 3 -// Button -#define BUTTON_PORT GPIOA -#define BUTTON_PIN GPIO_PIN_0 -#define BUTTON_STATE_ACTIVE 0 - -// UART Enable for STLink VCOM -#define UART_DEV USART3 -#define UART_CLK_EN __USART3_CLK_ENABLE -#define UART_GPIO_PORT GPIOA -#define UART_GPIO_AF GPIO_AF13_USART3 - -#define UART_TX_PIN GPIO_PIN_3 -#define UART_RX_PIN GPIO_PIN_4 +static board_pindef_t board_pindef[] = { + { // LED + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_5, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, + .active_state = 1 + }, + { // Button + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_0, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, + .active_state = 0 + }, + { // UART TX + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_3, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = GPIO_AF13_USART3 }, + .active_state = 0 + }, + { // UART RX + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_4, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = GPIO_AF13_USART3 }, + .active_state = 0 + }, +}; //--------------------------------------------------------------------+ // RCC Clock @@ -120,6 +129,10 @@ static inline void SystemClock_Config(void) { __HAL_RCC_USB_CLK_ENABLE(); } +static inline void board_init2(void) { + // Empty for this board +} + #ifdef __cplusplus } #endif diff --git a/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h b/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h index adc3d751a..0af2f8c4f 100644 --- a/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h +++ b/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h @@ -37,24 +37,33 @@ extern "C" { #endif -// LED -#define LED_PORT GPIOG -#define LED_PIN GPIO_PIN_4 -#define LED_STATE_ON 1 +#define PINID_LED 0 +#define PINID_BUTTON 1 +#define PINID_UART_TX 2 +#define PINID_UART_RX 3 -// Button -#define BUTTON_PORT GPIOA -#define BUTTON_PIN GPIO_PIN_0 -#define BUTTON_STATE_ACTIVE 0 - -// UART Enable for STLink VCOM -#define UART_DEV USART1 -#define UART_CLK_EN __USART1_CLK_ENABLE -#define UART_GPIO_PORT GPIOA -#define UART_GPIO_AF GPIO_AF7_USART1 - -#define UART_TX_PIN GPIO_PIN_9 -#define UART_RX_PIN GPIO_PIN_10 +static board_pindef_t board_pindef[] = { + { // LED + .port = GPIOG, + .pin_init = { .Pin = GPIO_PIN_4, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, + .active_state = 1 + }, + { // Button + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_0, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, + .active_state = 0 + }, + { // UART TX + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_9, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = GPIO_AF7_USART1 }, + .active_state = 0 + }, + { // UART RX + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_10, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = GPIO_AF7_USART1 }, + .active_state = 0 + }, +}; //--------------------------------------------------------------------+ // RCC Clock @@ -128,6 +137,10 @@ static inline void SystemClock_Config(void) { } } +static inline void board_init2(void) { + // Empty for this board +} + #ifdef __cplusplus } #endif diff --git a/hw/bsp/stm32h5/boards/stm32h573i_dk/board.cmake b/hw/bsp/stm32h5/boards/stm32h573i_dk/board.cmake index 92d6d98f0..76194ee91 100644 --- a/hw/bsp/stm32h5/boards/stm32h573i_dk/board.cmake +++ b/hw/bsp/stm32h5/boards/stm32h573i_dk/board.cmake @@ -5,4 +5,11 @@ function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC STM32H573xx ) + target_sources(${TARGET} PUBLIC + ${ST_TCPP0203}/tcpp0203.c + ${ST_TCPP0203}/tcpp0203_reg.c + ) + target_include_directories(${TARGET} PUBLIC + ${ST_TCPP0203} + ) endfunction() diff --git a/hw/bsp/stm32h5/boards/stm32h573i_dk/board.h b/hw/bsp/stm32h5/boards/stm32h573i_dk/board.h index d75114397..e95308b67 100644 --- a/hw/bsp/stm32h5/boards/stm32h573i_dk/board.h +++ b/hw/bsp/stm32h5/boards/stm32h573i_dk/board.h @@ -37,24 +37,63 @@ extern "C" { #endif -// LED -#define LED_PORT GPIOI -#define LED_PIN GPIO_PIN_9 -#define LED_STATE_ON 1 +#include "tcpp0203.h" -// Button -#define BUTTON_PORT GPIOC -#define BUTTON_PIN GPIO_PIN_13 -#define BUTTON_STATE_ACTIVE 1 +// VBUS Sense detection +#define OTG_FS_VBUS_SENSE 1 +#define OTG_HS_VBUS_SENSE 0 -// UART Enable for STLink VCOM -#define UART_DEV USART1 -#define UART_CLK_EN __USART1_CLK_ENABLE -#define UART_GPIO_PORT GPIOA -#define UART_GPIO_AF GPIO_AF7_USART1 +#define PINID_LED 0 +#define PINID_BUTTON 1 +#define PINID_UART_TX 2 +#define PINID_UART_RX 3 +#define PINID_TCPP0203_EN 4 +#define PINID_I2C_SCL 5 +#define PINID_I2C_SDA 6 +#define PINID_TCPP0203_INT 7 -#define UART_TX_PIN GPIO_PIN_9 -#define UART_RX_PIN GPIO_PIN_10 +static board_pindef_t board_pindef[] = { + { // LED + .port = GPIOI, + .pin_init = { .Pin = GPIO_PIN_9, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, + .active_state = 1 + }, + { // Button + .port = GPIOC, + .pin_init = { .Pin = GPIO_PIN_13, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, + .active_state = 1 + }, + { // UART TX + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_9, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = GPIO_AF7_USART1 }, + .active_state = 0 + }, + { // UART RX + .port = GPIOA, + .pin_init = { .Pin = GPIO_PIN_10, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = GPIO_AF7_USART1 }, + .active_state = 0 + }, + { // TCPP0203 VCC_EN + .port = GPIOG, + .pin_init = { .Pin = GPIO_PIN_0, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_LOW, .Alternate = 0 }, + .active_state = 1 + }, + { // I2C4 SCL + .port = GPIOB, + .pin_init = { .Pin = GPIO_PIN_8, .Mode = GPIO_MODE_AF_OD, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = GPIO_AF6_I2C4 }, + .active_state = 0 + }, + { // I2C4 SDA + .port = GPIOB, + .pin_init = { .Pin = GPIO_PIN_9, .Mode = GPIO_MODE_AF_OD, .Pull = GPIO_NOPULL, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = GPIO_AF6_I2C4 }, + .active_state = 0 + }, + { // TCPP0203 INT + .port = GPIOG, + .pin_init = { .Pin = GPIO_PIN_1, .Mode = GPIO_MODE_IT_FALLING, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, + .active_state = 0 + }, +}; //--------------------------------------------------------------------+ // RCC Clock @@ -113,6 +152,89 @@ static inline void SystemClock_Config(void) { __HAL_RCC_USB_CLK_ENABLE(); } +//--------------------------------------------------------------------+ +// USB PD +//--------------------------------------------------------------------+ +static I2C_HandleTypeDef i2c_handle = { + .Instance = I2C4, + .Init = { + .Timing = 0x20C0EDFF, // 100kHz @ 250MHz + .OwnAddress1 = 0, + .AddressingMode = I2C_ADDRESSINGMODE_7BIT, + .DualAddressMode = I2C_DUALADDRESS_DISABLE, + .OwnAddress2 = 0, + .OwnAddress2Masks = I2C_OA2_NOMASK, + .GeneralCallMode = I2C_GENERALCALL_DISABLE, + .NoStretchMode = I2C_NOSTRETCH_DISABLE, + } +}; +static TCPP0203_Object_t tcpp0203_obj = { 0 }; + +int32_t board_tcpp0203_init(void) { + // Enable TCPP0203 VCC (GPIO already configured in pindef array) + board_pindef_t* pindef = &board_pindef[PINID_TCPP0203_EN]; + HAL_GPIO_WritePin(pindef->port, pindef->pin_init.Pin, GPIO_PIN_SET); + + // Initialize I2C4 for TCPP0203 (GPIO already configured in pindef array) + __HAL_RCC_I2C4_CLK_ENABLE(); + __HAL_RCC_I2C4_FORCE_RESET(); + __HAL_RCC_I2C4_RELEASE_RESET(); + if (HAL_I2C_Init(&i2c_handle) != HAL_OK) { + return HAL_ERROR; + } + + // Enable interrupt for TCPP0203 FLGn (GPIO already configured in pindef array) + NVIC_SetPriority(EXTI1_IRQn, 12); + NVIC_EnableIRQ(EXTI1_IRQn); + + return 0; +} + +int32_t board_tcpp0203_deinit(void) { + return 0; +} + +int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { + TU_ASSERT (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)); + return 0; +} + +int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { + TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)); + return 0; +} + +static inline void board_init2(void) { + TCPP0203_IO_t io_ctx; + + io_ctx.Address = TCPP0203_I2C_ADDRESS_X68; + io_ctx.Init = board_tcpp0203_init; + io_ctx.DeInit = board_tcpp0203_deinit; + io_ctx.ReadReg = i2c_readreg; + io_ctx.WriteReg = i2c_writereg; + + TU_ASSERT(TCPP0203_RegisterBusIO(&tcpp0203_obj, &io_ctx) == TCPP0203_OK, ); + + TU_ASSERT(TCPP0203_Init(&tcpp0203_obj) == TCPP0203_OK, ); + + TU_ASSERT(TCPP0203_SetPowerMode(&tcpp0203_obj, TCPP0203_POWER_MODE_NORMAL) == TCPP0203_OK, ); +} + +void board_vbus_set(uint8_t rhport, bool state) { + (void) state; + if (rhport == 0) { + TU_ASSERT(TCPP0203_SetGateDriverProvider(&tcpp0203_obj, TCPP0203_GD_PROVIDER_SWITCH_CLOSED) == TCPP0203_OK, ); + } +} + +void EXTI1_IRQHandler(void) { + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1); + if (tcpp0203_obj.IsInitialized) { + TU_ASSERT(TCPP0203_SetPowerMode(&tcpp0203_obj, TCPP0203_POWER_MODE_NORMAL) == TCPP0203_OK, ); + TU_ASSERT(TCPP0203_SetGateDriverProvider(&tcpp0203_obj, TCPP0203_GD_PROVIDER_SWITCH_CLOSED) == TCPP0203_OK, ); + } +} + #ifdef __cplusplus } #endif diff --git a/hw/bsp/stm32h5/boards/stm32h573i_dk/board.mk b/hw/bsp/stm32h5/boards/stm32h573i_dk/board.mk index b24acf89f..49743e7cd 100644 --- a/hw/bsp/stm32h5/boards/stm32h573i_dk/board.mk +++ b/hw/bsp/stm32h5/boards/stm32h573i_dk/board.mk @@ -5,3 +5,10 @@ CFLAGS += \ # For flash-jlink target JLINK_DEVICE = stm32h573ii + +SRC_C += \ + $(ST_TCPP0203)/tcpp0203.c \ + $(ST_TCPP0203)/tcpp0203_reg.c \ + +INC += \ + $(TOP)/$(ST_TCPP0203) \ diff --git a/hw/bsp/stm32h5/family.c b/hw/bsp/stm32h5/family.c index 983944b1c..fdb12e44f 100644 --- a/hw/bsp/stm32h5/family.c +++ b/hw/bsp/stm32h5/family.c @@ -46,20 +46,38 @@ TU_ATTR_UNUSED static void Error_Handler(void) { } +typedef struct { + GPIO_TypeDef* port; + GPIO_InitTypeDef pin_init; + uint8_t active_state; +} board_pindef_t; + #include "board.h" //--------------------------------------------------------------------+ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ void USB_DRD_FS_IRQHandler(void) { - tud_int_handler(0); + tusb_int_handler(0, true); } //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ #ifdef UART_DEV -UART_HandleTypeDef UartHandle; +static UART_HandleTypeDef UartHandle = { + .Instance = UART_DEV, + .Init = { + .BaudRate = CFG_BOARD_UART_BAUDRATE, + .WordLength = UART_WORDLENGTH_8B, + .StopBits = UART_STOPBITS_1, + .Parity = UART_PARITY_NONE, + .HwFlowCtl = UART_HWCONTROL_NONE, + .Mode = UART_MODE_TX_RX, + .OverSampling = UART_OVERSAMPLING_16, + .AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT + } +}; #endif void board_init(void) { @@ -95,51 +113,18 @@ void board_init(void) { NVIC_SetPriority(USB_DRD_FS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); #endif - GPIO_InitTypeDef GPIO_InitStruct; - - // LED - GPIO_InitStruct.Pin = LED_PIN; - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct); - - board_led_write(false); - - // Button - GPIO_InitStruct.Pin = BUTTON_PIN; - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = BUTTON_STATE_ACTIVE ? GPIO_PULLDOWN : GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - HAL_GPIO_Init(BUTTON_PORT, &GPIO_InitStruct); + for (uint8_t i = 0; i < TU_ARRAY_SIZE(board_pindef); i++) { + HAL_GPIO_Init(board_pindef[i].port, &board_pindef[i].pin_init); + } #ifdef UART_DEV UART_CLK_EN(); - - // UART - GPIO_InitStruct.Pin = UART_TX_PIN | UART_RX_PIN; - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; - GPIO_InitStruct.Alternate = UART_GPIO_AF; - HAL_GPIO_Init(UART_GPIO_PORT, &GPIO_InitStruct); - - UartHandle = (UART_HandleTypeDef) { - .Instance = UART_DEV, - .Init.BaudRate = CFG_BOARD_UART_BAUDRATE, - .Init.WordLength = UART_WORDLENGTH_8B, - .Init.StopBits = UART_STOPBITS_1, - .Init.Parity = UART_PARITY_NONE, - .Init.HwFlowCtl = UART_HWCONTROL_NONE, - .Init.Mode = UART_MODE_TX_RX, - .Init.OverSampling = UART_OVERSAMPLING_16, - .AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT - }; HAL_UART_Init(&UartHandle); #endif // USB Pins TODO double check USB clock and pin setup // Configure USB DM and DP pins. This is optional, and maintained only for user guidance. + GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; @@ -153,6 +138,12 @@ void board_init(void) { #if defined (PWR_USBSCR_USB33DEN) HAL_PWREx_EnableVddUSB(); #endif + + board_init2(); + +#if CFG_TUH_ENABLED + board_vbus_set(BOARD_TUH_RHPORT, 1); +#endif } //--------------------------------------------------------------------+ @@ -160,12 +151,22 @@ void board_init(void) { //--------------------------------------------------------------------+ void board_led_write(bool state) { - GPIO_PinState pin_state = (GPIO_PinState) (state ? LED_STATE_ON : (1 - LED_STATE_ON)); - HAL_GPIO_WritePin(LED_PORT, LED_PIN, pin_state); +#ifdef PINID_LED + board_pindef_t* pindef = &board_pindef[PINID_LED]; + GPIO_PinState pin_state = state == pindef->active_state ? GPIO_PIN_SET : GPIO_PIN_RESET; + HAL_GPIO_WritePin(pindef->port, pindef->pin_init.Pin, pin_state); +#else + (void) state; +#endif } uint32_t board_button_read(void) { - return BUTTON_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN); +#ifdef PINID_BUTTON + board_pindef_t* pindef = &board_pindef[PINID_BUTTON]; + return pindef->active_state == HAL_GPIO_ReadPin(pindef->port, pindef->pin_init.Pin); +#else + return 0; +#endif } size_t board_get_unique_id(uint8_t id[], size_t max_len) { diff --git a/hw/bsp/stm32h5/family.cmake b/hw/bsp/stm32h5/family.cmake index d6f356ddf..62839af43 100644 --- a/hw/bsp/stm32h5/family.cmake +++ b/hw/bsp/stm32h5/family.cmake @@ -5,6 +5,7 @@ set(ST_PREFIX stm32${ST_FAMILY}xx) set(ST_HAL_DRIVER ${TOP}/hw/mcu/st/stm32${ST_FAMILY}xx_hal_driver) set(ST_CMSIS ${TOP}/hw/mcu/st/cmsis_device_${ST_FAMILY}) +set(ST_TCPP0203 ${TOP}/hw/mcu/st/stm32-tcpp0203) set(CMSIS_5 ${TOP}/lib/CMSIS_5) # include board specific @@ -44,6 +45,7 @@ function(family_add_board BOARD_TARGET) ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart.c ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_uart_ex.c ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_dma.c + ${ST_HAL_DRIVER}/Src/${ST_PREFIX}_hal_i2c.c ) target_include_directories(${BOARD_TARGET} PUBLIC ${CMAKE_CURRENT_FUNCTION_LIST_DIR} @@ -66,6 +68,7 @@ function(family_configure_example TARGET RTOS) ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c ${TOP}/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + ${TOP}/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c ${TOP}/src/portable/st/stm32_fsdev/fsdev_common.c ${TOP}/src/portable/st/typec/typec_stm32.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} diff --git a/hw/bsp/stm32h5/family.mk b/hw/bsp/stm32h5/family.mk index ec5f82d61..89a2eddd5 100644 --- a/hw/bsp/stm32h5/family.mk +++ b/hw/bsp/stm32h5/family.mk @@ -1,6 +1,7 @@ ST_FAMILY = h5 ST_CMSIS = hw/mcu/st/cmsis_device_$(ST_FAMILY) ST_HAL_DRIVER = hw/mcu/st/stm32$(ST_FAMILY)xx_hal_driver +ST_TCPP0203 = hw/mcu/st/stm32-tcpp0203 include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= cortex-m33 diff --git a/hw/bsp/stm32h5/stm32h5xx_hal_conf.h b/hw/bsp/stm32h5/stm32h5xx_hal_conf.h index d017bb06b..b4c64d56e 100644 --- a/hw/bsp/stm32h5/stm32h5xx_hal_conf.h +++ b/hw/bsp/stm32h5/stm32h5xx_hal_conf.h @@ -43,7 +43,6 @@ extern "C" { /* #define HAL_EXTI_MODULE_ENABLED */ /* #define HAL_FDCAN_MODULE_ENABLED */ /* #define HAL_HCD_MODULE_ENABLED */ -/* #define HAL_I2C_MODULE_ENABLED */ /* #define HAL_I2S_MODULE_ENABLED */ /* #define HAL_IWDG_MODULE_ENABLED */ /* #define HAL_IRDA_MODULE_ENABLED */ @@ -65,6 +64,7 @@ extern "C" { #define HAL_PWR_MODULE_ENABLED #define HAL_CORTEX_MODULE_ENABLED #define HAL_UART_MODULE_ENABLED +#define HAL_I2C_MODULE_ENABLED /* ########################## Register Callbacks selection ############################## */ /** diff --git a/hw/bsp/stm32u5/family.c b/hw/bsp/stm32u5/family.c index 0af497366..26d72d6a0 100644 --- a/hw/bsp/stm32u5/family.c +++ b/hw/bsp/stm32u5/family.c @@ -51,14 +51,21 @@ TU_ATTR_UNUSED static void Error_Handler(void) { //--------------------------------------------------------------------+ // Forward USB interrupt events to TinyUSB IRQ Handler //--------------------------------------------------------------------+ +#ifdef USB_DRD_FS +void USB_IRQHandler(void) { + tusb_int_handler(0, true); +} +#endif +#ifdef USB_OTG_FS void OTG_FS_IRQHandler(void) { - tud_int_handler(0); + tusb_int_handler(0, true); } - +#endif +#ifdef USB_OTG_HS void OTG_HS_IRQHandler(void) { - tud_int_handler(0); + tusb_int_handler(0, true); } - +#endif //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ From 7712205ba847973afd2e7fc37ba6a069ea3c4ceb Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 27 Nov 2025 22:20:06 +0100 Subject: [PATCH 15/21] bsp/stm32h5: increase stack for msc_file_explorer Signed-off-by: HiFiPhile --- hw/bsp/stm32h5/family.cmake | 2 +- hw/bsp/stm32h5/linker/STM32H503xx_FLASH.ld | 2 +- hw/bsp/stm32h5/linker/STM32H523xx_FLASH.ld | 2 +- hw/bsp/stm32h5/linker/STM32H533xx_FLASH.ld | 2 +- hw/bsp/stm32h5/linker/STM32H562xx_FLASH.ld | 2 +- hw/bsp/stm32h5/linker/STM32H563xx_FLASH.ld | 2 +- hw/bsp/stm32h5/linker/STM32H573xx_FLASH.ld | 2 +- hw/bsp/stm32h5/linker/stm32h503xx_flash.icf | 32 +++++++++++++++++++++ hw/bsp/stm32h5/linker/stm32h523xx_flash.icf | 32 +++++++++++++++++++++ hw/bsp/stm32h5/linker/stm32h562xx_flash.icf | 32 +++++++++++++++++++++ hw/bsp/stm32h5/linker/stm32h563xx_flash.icf | 32 +++++++++++++++++++++ hw/bsp/stm32h5/linker/stm32h573xx_flash.icf | 32 +++++++++++++++++++++ 12 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 hw/bsp/stm32h5/linker/stm32h503xx_flash.icf create mode 100644 hw/bsp/stm32h5/linker/stm32h523xx_flash.icf create mode 100644 hw/bsp/stm32h5/linker/stm32h562xx_flash.icf create mode 100644 hw/bsp/stm32h5/linker/stm32h563xx_flash.icf create mode 100644 hw/bsp/stm32h5/linker/stm32h573xx_flash.icf diff --git a/hw/bsp/stm32h5/family.cmake b/hw/bsp/stm32h5/family.cmake index 62839af43..a8780d165 100644 --- a/hw/bsp/stm32h5/family.cmake +++ b/hw/bsp/stm32h5/family.cmake @@ -27,7 +27,7 @@ set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) set(STARTUP_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/startup_${MCU_VARIANT}.s) set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/linker/${MCU_VARIANT_UPPER}_FLASH.ld) set(LD_FILE_Clang ${LD_FILE_GNU}) -set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash.icf) +set(LD_FILE_IAR ${CMAKE_CURRENT_LIST_DIR}/linker/${MCU_VARIANT}_flash.icf) #------------------------------------ # BOARD_TARGET diff --git a/hw/bsp/stm32h5/linker/STM32H503xx_FLASH.ld b/hw/bsp/stm32h5/linker/STM32H503xx_FLASH.ld index abf618233..169ac81b7 100644 --- a/hw/bsp/stm32h5/linker/STM32H503xx_FLASH.ld +++ b/hw/bsp/stm32h5/linker/STM32H503xx_FLASH.ld @@ -46,7 +46,7 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ /* Sections */ diff --git a/hw/bsp/stm32h5/linker/STM32H523xx_FLASH.ld b/hw/bsp/stm32h5/linker/STM32H523xx_FLASH.ld index b799892c6..633fc280e 100644 --- a/hw/bsp/stm32h5/linker/STM32H523xx_FLASH.ld +++ b/hw/bsp/stm32h5/linker/STM32H523xx_FLASH.ld @@ -46,7 +46,7 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ /* Sections */ SECTIONS diff --git a/hw/bsp/stm32h5/linker/STM32H533xx_FLASH.ld b/hw/bsp/stm32h5/linker/STM32H533xx_FLASH.ld index dece7a003..4d010cf9e 100644 --- a/hw/bsp/stm32h5/linker/STM32H533xx_FLASH.ld +++ b/hw/bsp/stm32h5/linker/STM32H533xx_FLASH.ld @@ -46,7 +46,7 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ /* Sections */ SECTIONS diff --git a/hw/bsp/stm32h5/linker/STM32H562xx_FLASH.ld b/hw/bsp/stm32h5/linker/STM32H562xx_FLASH.ld index aee2774a4..aeb799d63 100644 --- a/hw/bsp/stm32h5/linker/STM32H562xx_FLASH.ld +++ b/hw/bsp/stm32h5/linker/STM32H562xx_FLASH.ld @@ -46,7 +46,7 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ /* Sections */ SECTIONS diff --git a/hw/bsp/stm32h5/linker/STM32H563xx_FLASH.ld b/hw/bsp/stm32h5/linker/STM32H563xx_FLASH.ld index 129ed5170..2e8d38319 100644 --- a/hw/bsp/stm32h5/linker/STM32H563xx_FLASH.ld +++ b/hw/bsp/stm32h5/linker/STM32H563xx_FLASH.ld @@ -46,7 +46,7 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ /* Sections */ SECTIONS diff --git a/hw/bsp/stm32h5/linker/STM32H573xx_FLASH.ld b/hw/bsp/stm32h5/linker/STM32H573xx_FLASH.ld index eb98f3163..dd00557c0 100644 --- a/hw/bsp/stm32h5/linker/STM32H573xx_FLASH.ld +++ b/hw/bsp/stm32h5/linker/STM32H573xx_FLASH.ld @@ -46,7 +46,7 @@ MEMORY _estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */ _Min_Heap_Size = 0x200; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ +_Min_Stack_Size = 0x1000; /* required amount of stack */ /* Sections */ SECTIONS diff --git a/hw/bsp/stm32h5/linker/stm32h503xx_flash.icf b/hw/bsp/stm32h5/linker/stm32h503xx_flash.icf new file mode 100644 index 000000000..c5b783b1a --- /dev/null +++ b/hw/bsp/stm32h5/linker/stm32h503xx_flash.icf @@ -0,0 +1,32 @@ +/*###ICF### Section handled by ICF editor, don't touch! ****/ +/*-Editor annotation file-*/ +/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ +/*-Specials-*/ +define symbol __ICFEDIT_intvec_start__ = 0x08000000; +/*-Memory Regions-*/ +define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; +define symbol __ICFEDIT_region_ROM_end__ = 0x0801FFFF; +define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; +define symbol __ICFEDIT_region_RAM_end__ = 0x20007FFF; + +/*-Sizes-*/ +define symbol __ICFEDIT_size_cstack__ = 0x1000; +define symbol __ICFEDIT_size_heap__ = 0x200; +/**** End of ICF editor section. ###ICF###*/ + + +define memory mem with size = 4G; +define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; +define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; + +define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; +define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; + +initialize by copy { readwrite }; +do not initialize { section .noinit }; + +place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; + +place in ROM_region { readonly }; +place in RAM_region { readwrite, + block CSTACK, block HEAP }; diff --git a/hw/bsp/stm32h5/linker/stm32h523xx_flash.icf b/hw/bsp/stm32h5/linker/stm32h523xx_flash.icf new file mode 100644 index 000000000..dc97788ae --- /dev/null +++ b/hw/bsp/stm32h5/linker/stm32h523xx_flash.icf @@ -0,0 +1,32 @@ +/*###ICF### Section handled by ICF editor, don't touch! ****/ +/*-Editor annotation file-*/ +/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ +/*-Specials-*/ +define symbol __ICFEDIT_intvec_start__ = 0x08000000; +/*-Memory Regions-*/ +define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; +define symbol __ICFEDIT_region_ROM_end__ = 0x0807FFFF; +define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; +define symbol __ICFEDIT_region_RAM_end__ = 0x20043FFF; + +/*-Sizes-*/ +define symbol __ICFEDIT_size_cstack__ = 0x1000; +define symbol __ICFEDIT_size_heap__ = 0x200; +/**** End of ICF editor section. ###ICF###*/ + + +define memory mem with size = 4G; +define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; +define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; + +define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; +define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; + +initialize by copy { readwrite }; +do not initialize { section .noinit }; + +place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; + +place in ROM_region { readonly }; +place in RAM_region { readwrite, + block CSTACK, block HEAP }; diff --git a/hw/bsp/stm32h5/linker/stm32h562xx_flash.icf b/hw/bsp/stm32h5/linker/stm32h562xx_flash.icf new file mode 100644 index 000000000..b399851a3 --- /dev/null +++ b/hw/bsp/stm32h5/linker/stm32h562xx_flash.icf @@ -0,0 +1,32 @@ +/*###ICF### Section handled by ICF editor, don't touch! ****/ +/*-Editor annotation file-*/ +/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ +/*-Specials-*/ +define symbol __ICFEDIT_intvec_start__ = 0x08000000; +/*-Memory Regions-*/ +define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; +define symbol __ICFEDIT_region_ROM_end__ = 0x081FFFFF; +define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; +define symbol __ICFEDIT_region_RAM_end__ = 0x2009FFFF; + +/*-Sizes-*/ +define symbol __ICFEDIT_size_cstack__ = 0x1000; +define symbol __ICFEDIT_size_heap__ = 0x200; +/**** End of ICF editor section. ###ICF###*/ + + +define memory mem with size = 4G; +define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; +define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; + +define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; +define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; + +initialize by copy { readwrite }; +do not initialize { section .noinit }; + +place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; + +place in ROM_region { readonly }; +place in RAM_region { readwrite, + block CSTACK, block HEAP }; diff --git a/hw/bsp/stm32h5/linker/stm32h563xx_flash.icf b/hw/bsp/stm32h5/linker/stm32h563xx_flash.icf new file mode 100644 index 000000000..b399851a3 --- /dev/null +++ b/hw/bsp/stm32h5/linker/stm32h563xx_flash.icf @@ -0,0 +1,32 @@ +/*###ICF### Section handled by ICF editor, don't touch! ****/ +/*-Editor annotation file-*/ +/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ +/*-Specials-*/ +define symbol __ICFEDIT_intvec_start__ = 0x08000000; +/*-Memory Regions-*/ +define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; +define symbol __ICFEDIT_region_ROM_end__ = 0x081FFFFF; +define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; +define symbol __ICFEDIT_region_RAM_end__ = 0x2009FFFF; + +/*-Sizes-*/ +define symbol __ICFEDIT_size_cstack__ = 0x1000; +define symbol __ICFEDIT_size_heap__ = 0x200; +/**** End of ICF editor section. ###ICF###*/ + + +define memory mem with size = 4G; +define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; +define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; + +define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; +define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; + +initialize by copy { readwrite }; +do not initialize { section .noinit }; + +place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; + +place in ROM_region { readonly }; +place in RAM_region { readwrite, + block CSTACK, block HEAP }; diff --git a/hw/bsp/stm32h5/linker/stm32h573xx_flash.icf b/hw/bsp/stm32h5/linker/stm32h573xx_flash.icf new file mode 100644 index 000000000..b399851a3 --- /dev/null +++ b/hw/bsp/stm32h5/linker/stm32h573xx_flash.icf @@ -0,0 +1,32 @@ +/*###ICF### Section handled by ICF editor, don't touch! ****/ +/*-Editor annotation file-*/ +/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */ +/*-Specials-*/ +define symbol __ICFEDIT_intvec_start__ = 0x08000000; +/*-Memory Regions-*/ +define symbol __ICFEDIT_region_ROM_start__ = 0x08000000; +define symbol __ICFEDIT_region_ROM_end__ = 0x081FFFFF; +define symbol __ICFEDIT_region_RAM_start__ = 0x20000000; +define symbol __ICFEDIT_region_RAM_end__ = 0x2009FFFF; + +/*-Sizes-*/ +define symbol __ICFEDIT_size_cstack__ = 0x1000; +define symbol __ICFEDIT_size_heap__ = 0x200; +/**** End of ICF editor section. ###ICF###*/ + + +define memory mem with size = 4G; +define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__]; +define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__]; + +define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { }; +define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { }; + +initialize by copy { readwrite }; +do not initialize { section .noinit }; + +place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; + +place in ROM_region { readonly }; +place in RAM_region { readwrite, + block CSTACK, block HEAP }; From f3ac009adbd3cb6fd7a1e993d92b533d2dfa3c18 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Thu, 27 Nov 2025 22:45:31 +0100 Subject: [PATCH 16/21] fix build Signed-off-by: HiFiPhile --- examples/host/midi_rx/only.txt | 1 + hw/bsp/stm32h5/boards/stm32h503nucleo/board.cmake | 3 +++ hw/bsp/stm32h5/boards/stm32h503nucleo/board.h | 5 +++++ hw/bsp/stm32h5/boards/stm32h503nucleo/board.mk | 1 + hw/bsp/stm32h5/boards/stm32h563nucleo/board.h | 5 +++++ tools/get_deps.py | 2 +- 6 files changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/host/midi_rx/only.txt b/examples/host/midi_rx/only.txt index 022be899d..09d725860 100644 --- a/examples/host/midi_rx/only.txt +++ b/examples/host/midi_rx/only.txt @@ -16,6 +16,7 @@ mcu:MSP432E4 mcu:RP2040 mcu:RX65X mcu:RAXXX +mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 mcu:STM32H5 diff --git a/hw/bsp/stm32h5/boards/stm32h503nucleo/board.cmake b/hw/bsp/stm32h5/boards/stm32h503nucleo/board.cmake index 1a44c3f1d..5978758fc 100644 --- a/hw/bsp/stm32h5/boards/stm32h503nucleo/board.cmake +++ b/hw/bsp/stm32h5/boards/stm32h503nucleo/board.cmake @@ -6,4 +6,7 @@ function(update_board TARGET) STM32H503xx HSE_VALUE=24000000 ) + target_compile_definitions(${BOARD_TARGET} PUBLIC + CFG_EXAMPLE_VIDEO_READONLY + ) endfunction() diff --git a/hw/bsp/stm32h5/boards/stm32h503nucleo/board.h b/hw/bsp/stm32h5/boards/stm32h503nucleo/board.h index b57fab10e..9dd2b0466 100644 --- a/hw/bsp/stm32h5/boards/stm32h503nucleo/board.h +++ b/hw/bsp/stm32h5/boards/stm32h503nucleo/board.h @@ -133,6 +133,11 @@ static inline void board_init2(void) { // Empty for this board } +void board_vbus_set(uint8_t rhport, bool state) { + (void) rhport; + (void) state; +} + #ifdef __cplusplus } #endif diff --git a/hw/bsp/stm32h5/boards/stm32h503nucleo/board.mk b/hw/bsp/stm32h5/boards/stm32h503nucleo/board.mk index 0292353ae..497dd894e 100644 --- a/hw/bsp/stm32h5/boards/stm32h503nucleo/board.mk +++ b/hw/bsp/stm32h5/boards/stm32h503nucleo/board.mk @@ -3,6 +3,7 @@ MCU_VARIANT = stm32h503xx CFLAGS += \ -DSTM32H503xx \ -DHSE_VALUE=24000000 \ + -DCFG_EXAMPLE_VIDEO_READONLY \ # For flash-jlink target JLINK_DEVICE = stm32h503rb diff --git a/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h b/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h index 0af2f8c4f..20c91f606 100644 --- a/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h +++ b/hw/bsp/stm32h5/boards/stm32h563nucleo/board.h @@ -141,6 +141,11 @@ static inline void board_init2(void) { // Empty for this board } +void board_vbus_set(uint8_t rhport, bool state) { + (void) rhport; + (void) state; +} + #ifdef __cplusplus } #endif diff --git a/tools/get_deps.py b/tools/get_deps.py index 35f3b3e92..e915bf108 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -141,7 +141,7 @@ deps_optional = { 'stm32h7'], 'hw/mcu/st/stm32-tcpp0203': ['https://github.com/STMicroelectronics/stm32-tcpp0203.git', '9918655bff176ac3046ccf378b5c7bbbc6a38d15', - 'stm32h7rs stm32n6'], + 'stm32h5 stm32h7rs stm32n6'], 'hw/mcu/st/stm32c0xx_hal_driver': ['https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git', 'c283b143bef6bdaacf64240ee6f15eb61dad6125', 'stm32c0'], From c6b94db2990bf9975650c2879f4aabdade6f90d0 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 28 Nov 2025 00:11:08 +0100 Subject: [PATCH 17/21] Use one endpoint for EP0 Signed-off-by: HiFiPhile --- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index ff2f2946e..22a74efbe 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -575,19 +575,6 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const edpt->pid = 0; edpt->ls_pre = (hcd_port_speed_get(rhport) == TUSB_SPEED_FULL && tuh_speed_get(dev_addr) == TUSB_SPEED_LOW) ? 1 : 0; - // EP0 is bi-directional, so we need to open both OUT and IN channels - if (ep_addr == 0) { - uint8_t const ep_id_in = endpoint_alloc(); - if (ep_id_in == TUSB_INDEX_INVALID_8) { - // free previously allocated OUT endpoint - endpoint_dealloc(edpt); - TU_ASSERT(false); - } - - _hcd_data.edpt[ep_id_in] = *edpt; // copy from OUT endpoint - _hcd_data.edpt[ep_id_in].ep_addr = 0 | TUSB_DIR_IN_MASK; - } - return true; } @@ -599,13 +586,6 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) { edpoint_close(ep_id); - if (ep_addr == 0) { - uint8_t const ep_id_in = endpoint_find(dev_addr, 0 | TUSB_DIR_IN_MASK); - TU_ASSERT(ep_id_in != TUSB_INDEX_INVALID_8); - - edpoint_close(ep_id_in); - } - return true; } @@ -624,6 +604,12 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *b edpt->buflen = buflen; edpt->queued_len = 0; + uint8_t const ep_num = tu_edpt_number(ep_addr); + if (ep_num == 0) { + // update ep_dir since control endpoint can switch direction + edpt->ep_addr = ep_addr; + } + return edpt_xfer_kickoff(ep_id); } @@ -696,9 +682,16 @@ static uint8_t endpoint_alloc(void) { } static uint8_t endpoint_find(uint8_t dev_addr, uint8_t ep_addr) { + uint8_t const ep_num = tu_edpt_number(ep_addr); + tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr); + for (uint32_t i = 0; i < (uint32_t)CFG_TUH_FSDEV_ENDPOINT_MAX; i++) { hcd_endpoint_t* edpt = &_hcd_data.edpt[i]; - if (edpt->allocated == 1 && edpt->dev_addr == dev_addr && edpt->ep_addr == ep_addr) { + tusb_dir_t const dir = tu_edpt_dir(edpt->ep_addr); + uint8_t const num = tu_edpt_number(edpt->ep_addr); + // Match both ep_num and ep_dir, or match ep_num 0 (control endpoint) + if (edpt->allocated == 1 && edpt->dev_addr == dev_addr && num == ep_num && + (dir == ep_dir || ep_num == 0)) { return i; } } From 1ffe00b4363fc2d76751270118091fc3a3a1b92b Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 28 Nov 2025 13:18:10 +0100 Subject: [PATCH 18/21] Fix deinit glitch Signed-off-by: HiFiPhile --- src/portable/st/stm32_fsdev/fsdev_common.c | 5 -- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 47 ++++++++++++------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c index 4f95d9d7f..60ef339a6 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.c +++ b/src/portable/st/stm32_fsdev/fsdev_common.c @@ -37,11 +37,6 @@ // Reset the USB Core void fsdev_core_reset(void) { - // Follow the RM mentions to use a special ordering of PDWN and FRES - for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us - asm("NOP"); - } - // Perform USB peripheral reset FSDEV_REG->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN; for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 22a74efbe..212f620ac 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -59,6 +59,20 @@ TU_VERIFY_STATIC(CFG_TUH_FSDEV_ENDPOINT_MAX <= 255, "currently only use 8-bit for index"); +#if CFG_TUSB_MCU == OPT_MCU_STM32H5 + #define CPU_FREQUENCY_MHZ 250U +#elif CFG_TUSB_MCU == OPT_MCU_STM32U5 + #define CPU_FREQUENCY_MHZ 160U +#elif CFG_TUSB_MCU == OPT_MCU_STM32U3 + #define CPU_FREQUENCY_MHZ 96U +#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 + #define CPU_FREQUENCY_MHZ 64U +#elif CFG_TUSB_MCU == OPT_MCU_STM32C0 + #define CPU_FREQUENCY_MHZ 48U +#else + #error "CPU_FREQUENCY_MHZ not defined for this STM32 MCU" +#endif + enum { HCD_XFER_ERROR_MAX = 3, HCD_XFER_NAK_MAX = 15, @@ -122,6 +136,7 @@ static uint8_t channel_alloc(uint8_t dev_addr, uint8_t ep_addr, uint8_t ep_type) static bool edpt_xfer_kickoff(uint8_t ep_id); static bool channel_xfer_start(uint8_t ch_id, tusb_dir_t dir); static void edpoint_close(uint8_t ep_id); +static void port_status_handler(uint8_t rhport, bool in_isr); static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); static void ch_handle_nak(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); static void ch_handle_stall(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir); @@ -166,30 +181,16 @@ static inline uint16_t channel_get_rx_count(uint8_t ch_id) { * We choose the delay count based on max CPU frequency (in MHz) to ensure the delay is at least the required time. */ -#if CFG_TUSB_MCU == OPT_MCU_STM32H5 - #define FREQUENCY_MHZ 250U -#elif CFG_TUSB_MCU == OPT_MCU_STM32U5 - #define FREQUENCY_MHZ 160U -#elif CFG_TUSB_MCU == OPT_MCU_STM32U3 - #define FREQUENCY_MHZ 96U -#elif CFG_TUSB_MCU == OPT_MCU_STM32G0 - #define FREQUENCY_MHZ 64U -#elif CFG_TUSB_MCU == OPT_MCU_STM32C0 - #define FREQUENCY_MHZ 48U -#else - #error "FREQUENCY_MHZ not defined for this STM32 MCU" -#endif - uint32_t ch_reg = ch_read(ch_id); if (FSDEV_REG->ISTR & USB_ISTR_LS_DCONN || ch_reg & USB_CHEP_LSEP) { // Low speed mode: 6.4 us delay -> about 2 cycles per MHz - volatile uint32_t cycle_count = FREQUENCY_MHZ * 2U; + volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ * 2U; while (cycle_count > 0U) { cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) } } else { // Full speed mode: 800 ns delay -> about 0.25 cycles per MHz - volatile uint32_t cycle_count = FREQUENCY_MHZ / 4U; + volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ / 4U; while (cycle_count > 0U) { cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare) } @@ -231,12 +232,24 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) { fsdev_connect(rhport); + // If DCON_STAT is already set, the controller sometimes misses the initial connection interrupt + if (FSDEV_REG->ISTR & USB_ISTR_DCON_STAT) { + // Wait DP/DM stabilize time + volatile uint32_t cycle_count = CPU_FREQUENCY_MHZ / 4U; + while (cycle_count > 0U) { + cycle_count--; + } + port_status_handler(rhport, false); + } + return true; } bool hcd_deinit(uint8_t rhport) { (void)rhport; + fsdev_disconnect(rhport); + fsdev_deinit(); return true; @@ -259,7 +272,7 @@ static inline void sof_handler(void) { } } -static inline void port_status_handler(uint8_t rhport, bool in_isr) { +static void port_status_handler(uint8_t rhport, bool in_isr) { uint32_t const fnr_reg = FSDEV_REG->FNR; uint32_t const istr_reg = FSDEV_REG->ISTR; // SE0 detected USB Disconnected state From ae4e3c032826b4890dde14f01e7f568ae02322f0 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 28 Nov 2025 13:18:38 +0100 Subject: [PATCH 19/21] Fix button Signed-off-by: HiFiPhile --- hw/bsp/stm32h5/boards/stm32h573i_dk/board.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/bsp/stm32h5/boards/stm32h573i_dk/board.h b/hw/bsp/stm32h5/boards/stm32h573i_dk/board.h index e95308b67..5788837ab 100644 --- a/hw/bsp/stm32h5/boards/stm32h573i_dk/board.h +++ b/hw/bsp/stm32h5/boards/stm32h573i_dk/board.h @@ -60,7 +60,7 @@ static board_pindef_t board_pindef[] = { }, { // Button .port = GPIOC, - .pin_init = { .Pin = GPIO_PIN_13, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, + .pin_init = { .Pin = GPIO_PIN_13, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_FREQ_HIGH, .Alternate = 0 }, .active_state = 1 }, { // UART TX From 97c5151b34158f08fbfb51684cbfbc807abd77e5 Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Fri, 28 Nov 2025 13:27:09 +0100 Subject: [PATCH 20/21] Update note Signed-off-by: HiFiPhile --- README.rst | 264 +++++++++++++++++++++++----------------------- src/device/usbd.h | 2 + src/host/usbh.h | 2 + 3 files changed, 136 insertions(+), 132 deletions(-) diff --git a/README.rst b/README.rst index ef19b0ccd..75f93f656 100644 --- a/README.rst +++ b/README.rst @@ -129,138 +129,138 @@ TinyUSB is completely thread-safe by pushing all Interrupt Service Request (ISR) Supported CPUs -------------- -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Manufacturer | Family | Device | Host | Highspeed | Driver | Note | -+==============+=============================+========+======+===========+========================+===================+ -| Allwinner | F1C100s/F1C200s | ✔ | | ✔ | sunxi | musb variant | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Analog | MAX3421E | | ✔ | ✖ | max3421 | via SPI | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | MAX32 650, 666, 690, | ✔ | | ✔ | musb | 1-dir ep | -| | MAX78002 | | | | | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | F415, F435_437, F423, F425 | ✔ | ✔ | | dwc2 | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | F402_F405 | ✔ | ✔ | ✔ | dwc2 | F405 is HS | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Bridgetek | FT90x | ✔ | | ✔ | ft9xx | 1-dir ep | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Broadcom | BCM2711, BCM2837 | ✔ | | ✔ | dwc2 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Dialog | DA1469x | ✔ | ✖ | ✖ | da146xx | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Espressif | S2, S3 | ✔ | ✔ | ✖ | dwc2 | | -| ESP32 +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | P4 | ✔ | ✔ | ✔ | dwc2 | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | H4 | ✔ | ✔ | ✖ | dwc2 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| GigaDevice | GD32VF103 | ✔ | | ✖ | dwc2 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Infineon | XMC4500 | ✔ | ✔ | ✖ | dwc2 | | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+-------------------+ -| MicroChip | SAM | D11, D21, L21, L22 | ✔ | | ✖ | samd | | -| | +-----------------------+--------+------+-----------+------------------------+-------------------+ -| | | D51, E5x | ✔ | | ✖ | samd | | -| | +-----------------------+--------+------+-----------+------------------------+-------------------+ -| | | G55 | ✔ | | ✖ | samg | 1-dir ep | -| | +-----------------------+--------+------+-----------+------------------------+-------------------+ -| | | E70,S70,V70,V71 | ✔ | | ✔ | samx7x | 1-dir ep | -| +-----+-----------------------+--------+------+-----------+------------------------+-------------------+ -| | PIC | 24 | ✔ | | | pic | ci_fs variant | -| | +-----------------------+--------+------+-----------+------------------------+-------------------+ -| | | 32 mm, mk, mx | ✔ | | | pic | ci_fs variant | -| | +-----------------------+--------+------+-----------+------------------------+-------------------+ -| | | dsPIC33 | ✔ | | | pic | ci_fs variant | -| | +-----------------------+--------+------+-----------+------------------------+-------------------+ -| | | 32mz | ✔ | | | pic32mz | musb variant | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+-------------------+ -| MindMotion | mm32 | ✔ | | ✖ | mm32f327x_otg | ci_fs variant | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+-------------------+ -| NordicSemi | nRF 52833, 52840, 5340 | ✔ | ✖ | ✖ | nrf5x | only ep8 is ISO | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Nuvoton | NUC120 | ✔ | ✖ | ✖ | nuc120 | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | NUC121/NUC125 | ✔ | ✖ | ✖ | nuc121 | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | NUC126 | ✔ | ✖ | ✖ | nuc121 | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | NUC505 | ✔ | | ✔ | nuc505 | | -+--------------+---------+-------------------+--------+------+-----------+------------------------+-------------------+ -| NXP | iMXRT | RT 10xx, 11xx | ✔ | ✔ | ✔ | ci_hs, ehci | | -| +---------+-------------------+--------+------+-----------+------------------------+-------------------+ -| | Kinetis | KL | ✔ | ⚠ | ✖ | ci_fs, khci | | -| | +-------------------+--------+------+-----------+------------------------+-------------------+ -| | | K32L2 | ✔ | | ✖ | khci | ci_fs variant | -| +---------+-------------------+--------+------+-----------+------------------------+-------------------+ -| | LPC | 11u, 13, 15 | ✔ | ✖ | ✖ | lpc_ip3511 | | -| | +-------------------+--------+------+-----------+------------------------+-------------------+ -| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40, ohci | | -| | +-------------------+--------+------+-----------+------------------------+-------------------+ -| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs, ehci | | -| | +-------------------+--------+------+-----------+------------------------+-------------------+ -| | | 51u | ✔ | ✖ | ✖ | lpc_ip3511 | | -| | +-------------------+--------+------+-----------+------------------------+-------------------+ -| | | 54, 55 | ✔ | | ✔ | lpc_ip3511 | | -| +---------+-------------------+--------+------+-----------+------------------------+-------------------+ -| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs, ehci | | -| | +-------------------+--------+------+-----------+------------------------+-------------------+ -| | | A15 | ✔ | | | ci_fs | | -+--------------+---------+-------------------+--------+------+-----------+------------------------+-------------------+ -| Raspberry Pi | RP2040, RP2350 | ✔ | ✔ | ✖ | rp2040, pio_usb | | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+-------------------+ -| Renesas | RX | 63N, 65N, 72N | ✔ | ✔ | ✖ | rusb2 | | -| +-----+-----------------------+--------+------+-----------+------------------------+-------------------+ -| | RA | 4M1, 4M3, 6M1 | ✔ | ✔ | ✖ | rusb2 | | -| | +-----------------------+--------+------+-----------+------------------------+-------------------+ -| | | 6M5 | ✔ | ✔ | ✔ | rusb2 | | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+-------------------+ -| Silabs | EFM32GG12 | ✔ | | ✖ | dwc2 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| Sony | CXD56 | ✔ | ✖ | ✔ | cxd56 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| ST STM32 | F0, F3, L0, L1, L5, WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | | -| | +------------------------+--------+------+-----------+------------------------+-------------------+ -| | | 105, 107 | ✔ | ✔ | ✖ | dwc2 | | -| +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | C0, G0, H5 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0 | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | | -| | +------------------------+--------+------+-----------+------------------------+-------------------+ -| | | 4x5, 4x6, 4+ | ✔ | ✔ | ✖ | dwc2 | | -| +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | N6 | ✔ | ✔ | ✔ | dwc2 | | -| +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | U3 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0 | -| +----+------------------------+--------+------+-----------+------------------------+-------------------+ -| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0 | -| | +------------------------+--------+------+-----------+------------------------+-------------------+ -| | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | | -| | +------------------------+--------+------+-----------+------------------------+-------------------+ -| | | 59x,5Ax,5Fx,5Gx | ✔ | ✔ | ✔ | dwc2 | | -+--------------+----+------------------------+--------+------+-----------+------------------------+-------------------+ -| TI | MSP430 | ✔ | ✖ | ✖ | msp430x5xx | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | MSP432E4, TM4C123 | ✔ | | ✖ | musb | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ -| WCH | CH32F20x | ✔ | | ✔ | ch32_usbhs | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | CH32V20x | ✔ | | ✖ | stm32_fsdev/ch32_usbfs | | -| +-----------------------------+--------+------+-----------+------------------------+-------------------+ -| | CH32V305, CH32V307 | ✔ | | ✔ | ch32_usbfs/hs | | -+--------------+-----------------------------+--------+------+-----------+------------------------+-------------------+ ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Manufacturer | Family | Device | Host | Highspeed | Driver | Note | ++==============+=============================+========+======+===========+========================+========================+ +| Allwinner | F1C100s/F1C200s | ✔ | | ✔ | sunxi | musb variant | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Analog | MAX3421E | | ✔ | ✖ | max3421 | via SPI | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | MAX32 650, 666, 690, | ✔ | | ✔ | musb | 1-dir ep | +| | MAX78002 | | | | | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | F415, F435_437, F423, F425 | ✔ | ✔ | | dwc2 | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | F402_F405 | ✔ | ✔ | ✔ | dwc2 | F405 is HS | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Bridgetek | FT90x | ✔ | | ✔ | ft9xx | 1-dir ep | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Broadcom | BCM2711, BCM2837 | ✔ | | ✔ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Dialog | DA1469x | ✔ | ✖ | ✖ | da146xx | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Espressif | S2, S3 | ✔ | ✔ | ✖ | dwc2 | | +| ESP32 +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | P4 | ✔ | ✔ | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | H4 | ✔ | ✔ | ✖ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| GigaDevice | GD32VF103 | ✔ | | ✖ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Infineon | XMC4500 | ✔ | ✔ | ✖ | dwc2 | | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ +| MicroChip | SAM | D11, D21, L21, L22 | ✔ | | ✖ | samd | | +| | +-----------------------+--------+------+-----------+------------------------+------------------------+ +| | | D51, E5x | ✔ | | ✖ | samd | | +| | +-----------------------+--------+------+-----------+------------------------+------------------------+ +| | | G55 | ✔ | | ✖ | samg | 1-dir ep | +| | +-----------------------+--------+------+-----------+------------------------+------------------------+ +| | | E70,S70,V70,V71 | ✔ | | ✔ | samx7x | 1-dir ep | +| +-----+-----------------------+--------+------+-----------+------------------------+------------------------+ +| | PIC | 24 | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+------------------------+------------------------+ +| | | 32 mm, mk, mx | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+------------------------+------------------------+ +| | | dsPIC33 | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+------------------------+------------------------+ +| | | 32mz | ✔ | | | pic32mz | musb variant | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ +| MindMotion | mm32 | ✔ | | ✖ | mm32f327x_otg | ci_fs variant | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ +| NordicSemi | nRF 52833, 52840, 5340 | ✔ | ✖ | ✖ | nrf5x | only ep8 is IO | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Nuvoton | NUC120 | ✔ | ✖ | ✖ | nuc120 | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | NUC121/NUC125 | ✔ | ✖ | ✖ | nuc121 | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | NUC126 | ✔ | ✖ | ✖ | nuc121 | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | NUC505 | ✔ | | ✔ | nuc505 | | ++--------------+---------+-------------------+--------+------+-----------+------------------------+------------------------+ +| NXP | iMXRT | RT 10xx, 11xx | ✔ | ✔ | ✔ | ci_hs, ehci | | +| +---------+-------------------+--------+------+-----------+------------------------+------------------------+ +| | Kinetis | KL | ✔ | ⚠ | ✖ | ci_fs, khci | | +| | +-------------------+--------+------+-----------+------------------------+------------------------+ +| | | K32L2 | ✔ | | ✖ | khci | ci_fs variant | +| +---------+-------------------+--------+------+-----------+------------------------+------------------------+ +| | LPC | 11u, 13, 15 | ✔ | ✖ | ✖ | lpc_ip3511 | | +| | +-------------------+--------+------+-----------+------------------------+------------------------+ +| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40, ohci | | +| | +-------------------+--------+------+-----------+------------------------+------------------------+ +| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs, ehci | | +| | +-------------------+--------+------+-----------+------------------------+------------------------+ +| | | 51u | ✔ | ✖ | ✖ | lpc_ip3511 | | +| | +-------------------+--------+------+-----------+------------------------+------------------------+ +| | | 54, 55 | ✔ | | ✔ | lpc_ip3511 | | +| +---------+-------------------+--------+------+-----------+------------------------+------------------------+ +| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs, ehci | | +| | +-------------------+--------+------+-----------+------------------------+------------------------+ +| | | A15 | ✔ | | | ci_fs | | ++--------------+---------+-------------------+--------+------+-----------+------------------------+------------------------+ +| Raspberry Pi | RP2040, RP2350 | ✔ | ✔ | ✖ | rp2040, pio_usb | | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ +| Renesas | RX | 63N, 65N, 72N | ✔ | ✔ | ✖ | rusb2 | | +| +-----+-----------------------+--------+------+-----------+------------------------+------------------------+ +| | RA | 4M1, 4M3, 6M1 | ✔ | ✔ | ✖ | rusb2 | | +| | +-----------------------+--------+------+-----------+------------------------+------------------------+ +| | | 6M5 | ✔ | ✔ | ✔ | rusb2 | | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ +| Silabs | EFM32GG12 | ✔ | | ✖ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| Sony | CXD56 | ✔ | ✖ | ✔ | cxd56 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| ST STM32 | F0, F3, L0, L1, L5, WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +----+------------------------+--------+------+-----------+------------------------+------------------------+ +| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | | +| | +------------------------+--------+------+-----------+------------------------+------------------------+ +| | | 105, 107 | ✔ | ✔ | ✖ | dwc2 | | +| +----+------------------------+--------+------+-----------+------------------------+------------------------+ +| | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | C0, G0, H5 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0, H5 | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +----+------------------------+--------+------+-----------+------------------------+------------------------+ +| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | | +| | +------------------------+--------+------+-----------+------------------------+------------------------+ +| | | 4x5, 4x6, 4+ | ✔ | ✔ | ✖ | dwc2 | | +| +----+------------------------+--------+------+-----------+------------------------+------------------------+ +| | N6 | ✔ | ✔ | ✔ | dwc2 | | +| +----+------------------------+--------+------+-----------+------------------------+------------------------+ +| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +----+------------------------+--------+------+-----------+------------------------+------------------------+ +| | U3 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0, H5 | +| +----+------------------------+--------+------+-----------+------------------------+------------------------+ +| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0, H5 | +| | +------------------------+--------+------+-----------+------------------------+------------------------+ +| | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | | +| | +------------------------+--------+------+-----------+------------------------+------------------------+ +| | | 59x,5Ax,5Fx,5Gx | ✔ | ✔ | ✔ | dwc2 | | ++--------------+----+------------------------+--------+------+-----------+------------------------+------------------------+ +| TI | MSP430 | ✔ | ✖ | ✖ | msp430x5xx | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | MSP432E4, TM4C123 | ✔ | | ✖ | musb | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ +| WCH | CH32F20x | ✔ | | ✔ | ch32_usbhs | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | CH32V20x | ✔ | | ✖ | stm32_fsdev/ch32_usbfs | | +| +-----------------------------+--------+------+-----------+------------------------+------------------------+ +| | CH32V305, CH32V307 | ✔ | | ✔ | ch32_usbfs/hs | | ++--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ Table Legend ^^^^^^^^^^^^ diff --git a/src/device/usbd.h b/src/device/usbd.h index c446638c3..3cf195452 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -38,6 +38,7 @@ extern "C" { //--------------------------------------------------------------------+ // New API to replace tud_init() to init device stack on specific roothub port +// Must be called in the same task/context as tud_task() if RTOS is used bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init); // Init device stack on roothub port @@ -53,6 +54,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_init (uint8_t rhport) { } // Deinit device stack on roothub port +// Must be called in the same task/context as tud_task() if RTOS is used bool tud_deinit(uint8_t rhport); // Check if device stack is already initialized diff --git a/src/host/usbh.h b/src/host/usbh.h index 697c911ff..d86efbcb2 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -150,6 +150,7 @@ void tuh_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr); bool tuh_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param); // New API to replace tuh_init() to init host stack on specific roothub port +// Must be called in the same task/context as tuh_task() if RTOS is used bool tuh_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init); // Init host stack @@ -165,6 +166,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tuh_init(uint8_t rhport) { } // Deinit host stack on rhport +// Must be called in the same task/context as tuh_task() if RTOS is used bool tuh_deinit(uint8_t rhport); // Check if host stack is already initialized with any roothub ports From 1583864e0b1379cc2f03717f1bed2429e5473407 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 15 Dec 2025 13:28:24 +0700 Subject: [PATCH 21/21] minor clean up --- README.rst | 260 +++++++++--------- examples/host/bare_api/only.txt | 15 +- examples/host/cdc_msc_hid/only.txt | 15 +- examples/host/cdc_msc_hid_freertos/only.txt | 13 +- examples/host/device_info/only.txt | 13 +- examples/host/hid_controller/only.txt | 15 +- examples/host/midi_rx/only.txt | 13 +- examples/host/msc_file_explorer/only.txt | 15 +- hw/bsp/stm32u5/family.mk | 6 +- src/device/usbd.c | 6 +- src/portable/st/stm32_fsdev/fsdev_common.c | 16 +- src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c | 10 +- 12 files changed, 211 insertions(+), 186 deletions(-) diff --git a/README.rst b/README.rst index 75f93f656..da1f49fcd 100644 --- a/README.rst +++ b/README.rst @@ -129,138 +129,134 @@ TinyUSB is completely thread-safe by pushing all Interrupt Service Request (ISR) Supported CPUs -------------- -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Manufacturer | Family | Device | Host | Highspeed | Driver | Note | -+==============+=============================+========+======+===========+========================+========================+ -| Allwinner | F1C100s/F1C200s | ✔ | | ✔ | sunxi | musb variant | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Analog | MAX3421E | | ✔ | ✖ | max3421 | via SPI | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | MAX32 650, 666, 690, | ✔ | | ✔ | musb | 1-dir ep | -| | MAX78002 | | | | | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | F415, F435_437, F423, F425 | ✔ | ✔ | | dwc2 | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | F402_F405 | ✔ | ✔ | ✔ | dwc2 | F405 is HS | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Bridgetek | FT90x | ✔ | | ✔ | ft9xx | 1-dir ep | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Broadcom | BCM2711, BCM2837 | ✔ | | ✔ | dwc2 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Dialog | DA1469x | ✔ | ✖ | ✖ | da146xx | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Espressif | S2, S3 | ✔ | ✔ | ✖ | dwc2 | | -| ESP32 +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | P4 | ✔ | ✔ | ✔ | dwc2 | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | H4 | ✔ | ✔ | ✖ | dwc2 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| GigaDevice | GD32VF103 | ✔ | | ✖ | dwc2 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Infineon | XMC4500 | ✔ | ✔ | ✖ | dwc2 | | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ -| MicroChip | SAM | D11, D21, L21, L22 | ✔ | | ✖ | samd | | -| | +-----------------------+--------+------+-----------+------------------------+------------------------+ -| | | D51, E5x | ✔ | | ✖ | samd | | -| | +-----------------------+--------+------+-----------+------------------------+------------------------+ -| | | G55 | ✔ | | ✖ | samg | 1-dir ep | -| | +-----------------------+--------+------+-----------+------------------------+------------------------+ -| | | E70,S70,V70,V71 | ✔ | | ✔ | samx7x | 1-dir ep | -| +-----+-----------------------+--------+------+-----------+------------------------+------------------------+ -| | PIC | 24 | ✔ | | | pic | ci_fs variant | -| | +-----------------------+--------+------+-----------+------------------------+------------------------+ -| | | 32 mm, mk, mx | ✔ | | | pic | ci_fs variant | -| | +-----------------------+--------+------+-----------+------------------------+------------------------+ -| | | dsPIC33 | ✔ | | | pic | ci_fs variant | -| | +-----------------------+--------+------+-----------+------------------------+------------------------+ -| | | 32mz | ✔ | | | pic32mz | musb variant | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ -| MindMotion | mm32 | ✔ | | ✖ | mm32f327x_otg | ci_fs variant | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ -| NordicSemi | nRF 52833, 52840, 5340 | ✔ | ✖ | ✖ | nrf5x | only ep8 is IO | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Nuvoton | NUC120 | ✔ | ✖ | ✖ | nuc120 | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | NUC121/NUC125 | ✔ | ✖ | ✖ | nuc121 | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | NUC126 | ✔ | ✖ | ✖ | nuc121 | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | NUC505 | ✔ | | ✔ | nuc505 | | -+--------------+---------+-------------------+--------+------+-----------+------------------------+------------------------+ -| NXP | iMXRT | RT 10xx, 11xx | ✔ | ✔ | ✔ | ci_hs, ehci | | -| +---------+-------------------+--------+------+-----------+------------------------+------------------------+ -| | Kinetis | KL | ✔ | ⚠ | ✖ | ci_fs, khci | | -| | +-------------------+--------+------+-----------+------------------------+------------------------+ -| | | K32L2 | ✔ | | ✖ | khci | ci_fs variant | -| +---------+-------------------+--------+------+-----------+------------------------+------------------------+ -| | LPC | 11u, 13, 15 | ✔ | ✖ | ✖ | lpc_ip3511 | | -| | +-------------------+--------+------+-----------+------------------------+------------------------+ -| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40, ohci | | -| | +-------------------+--------+------+-----------+------------------------+------------------------+ -| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs, ehci | | -| | +-------------------+--------+------+-----------+------------------------+------------------------+ -| | | 51u | ✔ | ✖ | ✖ | lpc_ip3511 | | -| | +-------------------+--------+------+-----------+------------------------+------------------------+ -| | | 54, 55 | ✔ | | ✔ | lpc_ip3511 | | -| +---------+-------------------+--------+------+-----------+------------------------+------------------------+ -| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs, ehci | | -| | +-------------------+--------+------+-----------+------------------------+------------------------+ -| | | A15 | ✔ | | | ci_fs | | -+--------------+---------+-------------------+--------+------+-----------+------------------------+------------------------+ -| Raspberry Pi | RP2040, RP2350 | ✔ | ✔ | ✖ | rp2040, pio_usb | | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ -| Renesas | RX | 63N, 65N, 72N | ✔ | ✔ | ✖ | rusb2 | | -| +-----+-----------------------+--------+------+-----------+------------------------+------------------------+ -| | RA | 4M1, 4M3, 6M1 | ✔ | ✔ | ✖ | rusb2 | | -| | +-----------------------+--------+------+-----------+------------------------+------------------------+ -| | | 6M5 | ✔ | ✔ | ✔ | rusb2 | | -+--------------+-----+-----------------------+--------+------+-----------+------------------------+------------------------+ -| Silabs | EFM32GG12 | ✔ | | ✖ | dwc2 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| Sony | CXD56 | ✔ | ✖ | ✔ | cxd56 | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| ST STM32 | F0, F3, L0, L1, L5, WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------------+--------+------+-----------+------------------------+------------------------+ -| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | | -| | +------------------------+--------+------+-----------+------------------------+------------------------+ -| | | 105, 107 | ✔ | ✔ | ✖ | dwc2 | | -| +----+------------------------+--------+------+-----------+------------------------+------------------------+ -| | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | C0, G0, H5 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0, H5 | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------------+--------+------+-----------+------------------------+------------------------+ -| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | | -| | +------------------------+--------+------+-----------+------------------------+------------------------+ -| | | 4x5, 4x6, 4+ | ✔ | ✔ | ✖ | dwc2 | | -| +----+------------------------+--------+------+-----------+------------------------+------------------------+ -| | N6 | ✔ | ✔ | ✔ | dwc2 | | -| +----+------------------------+--------+------+-----------+------------------------+------------------------+ -| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | | -| +----+------------------------+--------+------+-----------+------------------------+------------------------+ -| | U3 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0, H5 | -| +----+------------------------+--------+------+-----------+------------------------+------------------------+ -| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | Host tested on C0, H5 | -| | +------------------------+--------+------+-----------+------------------------+------------------------+ -| | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | | -| | +------------------------+--------+------+-----------+------------------------+------------------------+ -| | | 59x,5Ax,5Fx,5Gx | ✔ | ✔ | ✔ | dwc2 | | -+--------------+----+------------------------+--------+------+-----------+------------------------+------------------------+ -| TI | MSP430 | ✔ | ✖ | ✖ | msp430x5xx | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | MSP432E4, TM4C123 | ✔ | | ✖ | musb | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ -| WCH | CH32F20x | ✔ | | ✔ | ch32_usbhs | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | CH32V20x | ✔ | | ✖ | stm32_fsdev/ch32_usbfs | | -| +-----------------------------+--------+------+-----------+------------------------+------------------------+ -| | CH32V305, CH32V307 | ✔ | | ✔ | ch32_usbfs/hs | | -+--------------+-----------------------------+--------+------+-----------+------------------------+------------------------+ ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Manufacturer | Family | Device | Host | Highspeed | Driver | Note | ++==============+=============================+========+======+===========+========================+====================+ +| Allwinner | F1C100s/F1C200s | ✔ | | ✔ | sunxi | musb variant | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Analog | MAX3421E | | ✔ | ✖ | max3421 | via SPI | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | MAX32 650, 666, 690, | ✔ | | ✔ | musb | 1-dir ep | +| | MAX78002 | | | | | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | Packet SRAM 512 | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | F415, F435_437, F423, F425 | ✔ | ✔ | | dwc2 | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | F402_F405 | ✔ | ✔ | ✔ | dwc2 | F405 is HS | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Bridgetek | FT90x | ✔ | | ✔ | ft9xx | 1-dir ep | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Broadcom | BCM2711, BCM2837 | ✔ | | ✔ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Dialog | DA1469x | ✔ | ✖ | ✖ | da146xx | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Espressif | S2, S3 | ✔ | ✔ | ✖ | dwc2 | | +| ESP32 +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | P4 | ✔ | ✔ | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | H4 | ✔ | ✔ | ✖ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| GigaDevice | GD32VF103 | ✔ | | ✖ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Infineon | XMC4500 | ✔ | ✔ | ✖ | dwc2 | | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+--------------------+ +| MicroChip | SAM | D11, D21, L21, L22 | ✔ | | ✖ | samd | | +| | +-----------------------+--------+------+-----------+------------------------+--------------------+ +| | | D51, E5x | ✔ | | ✖ | samd | | +| | +-----------------------+--------+------+-----------+------------------------+--------------------+ +| | | G55 | ✔ | | ✖ | samg | 1-dir ep | +| | +-----------------------+--------+------+-----------+------------------------+--------------------+ +| | | E70,S70,V70,V71 | ✔ | | ✔ | samx7x | 1-dir ep | +| +-----+-----------------------+--------+------+-----------+------------------------+--------------------+ +| | PIC | 24 | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+------------------------+--------------------+ +| | | 32 mm, mk, mx | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+------------------------+--------------------+ +| | | dsPIC33 | ✔ | | | pic | ci_fs variant | +| | +-----------------------+--------+------+-----------+------------------------+--------------------+ +| | | 32mz | ✔ | | | pic32mz | musb variant | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+--------------------+ +| MindMotion | mm32 | ✔ | | ✖ | mm32f327x_otg | ci_fs variant | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+--------------------+ +| NordicSemi | nRF 52833, 52840, 5340 | ✔ | ✖ | ✖ | nrf5x | only ep8 is ISO | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Nuvoton | NUC120 | ✔ | ✖ | ✖ | nuc120 | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | NUC121/NUC125, NUC126 | ✔ | ✖ | ✖ | nuc121 | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | NUC505 | ✔ | | ✔ | nuc505 | | ++--------------+---------+-------------------+--------+------+-----------+------------------------+--------------------+ +| NXP | iMXRT | RT 10xx, 11xx | ✔ | ✔ | ✔ | ci_hs, ehci | | +| +---------+-------------------+--------+------+-----------+------------------------+--------------------+ +| | Kinetis | KL | ✔ | ⚠ | ✖ | ci_fs, khci | | +| | +-------------------+--------+------+-----------+------------------------+--------------------+ +| | | K32L2 | ✔ | | ✖ | khci | ci_fs variant | +| +---------+-------------------+--------+------+-----------+------------------------+--------------------+ +| | LPC | 11u, 13, 15 | ✔ | ✖ | ✖ | lpc_ip3511 | | +| | +-------------------+--------+------+-----------+------------------------+--------------------+ +| | | 17, 40 | ✔ | ⚠ | ✖ | lpc17_40, ohci | | +| | +-------------------+--------+------+-----------+------------------------+--------------------+ +| | | 18, 43 | ✔ | ✔ | ✔ | ci_hs, ehci | | +| | +-------------------+--------+------+-----------+------------------------+--------------------+ +| | | 51u | ✔ | ✖ | ✖ | lpc_ip3511 | | +| | +-------------------+--------+------+-----------+------------------------+--------------------+ +| | | 54, 55 | ✔ | | ✔ | lpc_ip3511 | | +| +---------+-------------------+--------+------+-----------+------------------------+--------------------+ +| | MCX | N9 | ✔ | | ✔ | ci_fs, ci_hs, ehci | | +| | +-------------------+--------+------+-----------+------------------------+--------------------+ +| | | A15 | ✔ | | | ci_fs | | ++--------------+---------+-------------------+--------+------+-----------+------------------------+--------------------+ +| Raspberry Pi | RP2040, RP2350 | ✔ | ✔ | ✖ | rp2040, pio_usb | | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+--------------------+ +| Renesas | RX | 63N, 65N, 72N | ✔ | ✔ | ✖ | rusb2 | | +| +-----+-----------------------+--------+------+-----------+------------------------+--------------------+ +| | RA | 4M1, 4M3, 6M1 | ✔ | ✔ | ✖ | rusb2 | | +| | +-----------------------+--------+------+-----------+------------------------+--------------------+ +| | | 6M5 | ✔ | ✔ | ✔ | rusb2 | | ++--------------+-----+-----------------------+--------+------+-----------+------------------------+--------------------+ +| Silabs | EFM32GG12 | ✔ | | ✖ | dwc2 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| Sony | CXD56 | ✔ | ✖ | ✔ | cxd56 | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| ST STM32 | F0, F3, L0, L1, L5, WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | | +| +----+------------------------+--------+------+-----------+------------------------+--------------------+ +| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 512 | +| | +------------------------+--------+------+-----------+------------------------+--------------------+ +| | | 105, 107 | ✔ | ✔ | ✖ | dwc2 | | +| +----+------------------------+--------+------+-----------+------------------------+--------------------+ +| | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | C0, G0, H5, U3 | ✔ | ✔ | ✖ | stm32_fsdev | Packet SRAM 2KB | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB | +| +----+------------------------+--------+------+-----------+------------------------+--------------------+ +| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB | +| | +------------------------+--------+------+-----------+------------------------+--------------------+ +| | | 4x5, 4x6, 4+ | ✔ | ✔ | ✖ | dwc2 | | +| +----+------------------------+--------+------+-----------+------------------------+--------------------+ +| | N6 | ✔ | ✔ | ✔ | dwc2 | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB | +| +----+------------------------+--------+------+-----------+------------------------+--------------------+ +| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | Packet SRAM 2KB | +| | +------------------------+--------+------+-----------+------------------------+--------------------+ +| | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | | +| | +------------------------+--------+------+-----------+------------------------+--------------------+ +| | | 59x,5Ax,5Fx,5Gx | ✔ | ✔ | ✔ | dwc2 | | ++--------------+----+------------------------+--------+------+-----------+------------------------+--------------------+ +| TI | MSP430 | ✔ | ✖ | ✖ | msp430x5xx | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | MSP432E4, TM4C123 | ✔ | | ✖ | musb | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ +| WCH | CH32F20x | ✔ | | ✔ | ch32_usbhs | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | CH32V20x | ✔ | | ✖ | stm32_fsdev/ch32_usbfs | | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | CH32V305, CH32V307 | ✔ | | ✔ | ch32_usbfs/hs | | ++--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ Table Legend ^^^^^^^^^^^^ diff --git a/examples/host/bare_api/only.txt b/examples/host/bare_api/only.txt index 4cd457879..52e51242c 100644 --- a/examples/host/bare_api/only.txt +++ b/examples/host/bare_api/only.txt @@ -1,3 +1,5 @@ +family:samd21 +family:samd5x_e5x mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X @@ -5,20 +7,21 @@ mcu:LPC177X_8X mcu:LPC18XX mcu:LPC40XX mcu:LPC43XX -mcu:MIMXRT1XXX +mcu:MAX3421 mcu:MIMXRT10XX mcu:MIMXRT11XX -mcu:RP2040 +mcu:MIMXRT1XXX mcu:MSP432E4 -mcu:RX65X mcu:RAXXX -mcu:MAX3421 +mcu:RP2040 +mcu:RX65X mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32G0 mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 -family:samd21 -family:samd5x_e5x +mcu:STM32U3 +mcu:STM32U5 diff --git a/examples/host/cdc_msc_hid/only.txt b/examples/host/cdc_msc_hid/only.txt index 4cd457879..52e51242c 100644 --- a/examples/host/cdc_msc_hid/only.txt +++ b/examples/host/cdc_msc_hid/only.txt @@ -1,3 +1,5 @@ +family:samd21 +family:samd5x_e5x mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X @@ -5,20 +7,21 @@ mcu:LPC177X_8X mcu:LPC18XX mcu:LPC40XX mcu:LPC43XX -mcu:MIMXRT1XXX +mcu:MAX3421 mcu:MIMXRT10XX mcu:MIMXRT11XX -mcu:RP2040 +mcu:MIMXRT1XXX mcu:MSP432E4 -mcu:RX65X mcu:RAXXX -mcu:MAX3421 +mcu:RP2040 +mcu:RX65X mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32G0 mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 -family:samd21 -family:samd5x_e5x +mcu:STM32U3 +mcu:STM32U5 diff --git a/examples/host/cdc_msc_hid_freertos/only.txt b/examples/host/cdc_msc_hid_freertos/only.txt index 2322d4ecf..4cff741c3 100644 --- a/examples/host/cdc_msc_hid_freertos/only.txt +++ b/examples/host/cdc_msc_hid_freertos/only.txt @@ -1,21 +1,24 @@ +family:espressif +family:samd21 +family:samd5x_e5x mcu:LPC175X_6X mcu:LPC177X_8X mcu:LPC18XX mcu:LPC40XX mcu:LPC43XX -mcu:MIMXRT1XXX +mcu:MAX3421 mcu:MIMXRT10XX mcu:MIMXRT11XX +mcu:MIMXRT1XXX mcu:MSP432E4 mcu:RX65X -mcu:MAX3421 mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32G0 mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 -family:espressif -family:samd21 -family:samd5x_e5x +mcu:STM32U3 +mcu:STM32U5 diff --git a/examples/host/device_info/only.txt b/examples/host/device_info/only.txt index 5b68f0774..becc8252d 100644 --- a/examples/host/device_info/only.txt +++ b/examples/host/device_info/only.txt @@ -1,3 +1,6 @@ +family:espressif +family:samd21 +family:samd5x_e5x mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X @@ -6,20 +9,20 @@ mcu:LPC18XX mcu:LPC40XX mcu:LPC43XX mcu:MAX3421 -mcu:MIMXRT1XXX mcu:MIMXRT10XX mcu:MIMXRT11XX +mcu:MIMXRT1XXX mcu:MSP432E4 +mcu:RAXXX mcu:RP2040 mcu:RX65X -mcu:RAXXX mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32G0 mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 -family:espressif -family:samd21 -family:samd5x_e5x +mcu:STM32U3 +mcu:STM32U5 diff --git a/examples/host/hid_controller/only.txt b/examples/host/hid_controller/only.txt index b859b4cc0..35b7c2361 100644 --- a/examples/host/hid_controller/only.txt +++ b/examples/host/hid_controller/only.txt @@ -1,3 +1,5 @@ +family:samd21 +family:samd5x_e5x mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X @@ -5,19 +7,20 @@ mcu:LPC177X_8X mcu:LPC18XX mcu:LPC40XX mcu:LPC43XX -mcu:MIMXRT1XXX +mcu:MAX3421 mcu:MIMXRT10XX mcu:MIMXRT11XX -mcu:RP2040 +mcu:MIMXRT1XXX mcu:MSP432E4 -mcu:RX65X mcu:RAXXX -mcu:MAX3421 +mcu:RP2040 +mcu:RX65X mcu:STM32F4 mcu:STM32F7 +mcu:STM32G0 mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 -family:samd21 -family:samd5x_e5x +mcu:STM32U3 +mcu:STM32U5 diff --git a/examples/host/midi_rx/only.txt b/examples/host/midi_rx/only.txt index 09d725860..a3976f08d 100644 --- a/examples/host/midi_rx/only.txt +++ b/examples/host/midi_rx/only.txt @@ -1,7 +1,9 @@ +family:samd21 +family:samd5x_e5x mcu:CH32V20X +mcu:ESP32P4 mcu:ESP32S2 mcu:ESP32S3 -mcu:ESP32P4 mcu:KINETIS_KL mcu:LPC175X_6X mcu:LPC177X_8X @@ -9,19 +11,20 @@ mcu:LPC18XX mcu:LPC40XX mcu:LPC43XX mcu:MAX3421 -mcu:MIMXRT1XXX mcu:MIMXRT10XX mcu:MIMXRT11XX +mcu:MIMXRT1XXX mcu:MSP432E4 +mcu:RAXXX mcu:RP2040 mcu:RX65X -mcu:RAXXX mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32G0 mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 -family:samd21 -family:samd5x_e5x +mcu:STM32U3 +mcu:STM32U5 diff --git a/examples/host/msc_file_explorer/only.txt b/examples/host/msc_file_explorer/only.txt index 4cd457879..52e51242c 100644 --- a/examples/host/msc_file_explorer/only.txt +++ b/examples/host/msc_file_explorer/only.txt @@ -1,3 +1,5 @@ +family:samd21 +family:samd5x_e5x mcu:CH32V20X mcu:KINETIS_KL mcu:LPC175X_6X @@ -5,20 +7,21 @@ mcu:LPC177X_8X mcu:LPC18XX mcu:LPC40XX mcu:LPC43XX -mcu:MIMXRT1XXX +mcu:MAX3421 mcu:MIMXRT10XX mcu:MIMXRT11XX -mcu:RP2040 +mcu:MIMXRT1XXX mcu:MSP432E4 -mcu:RX65X mcu:RAXXX -mcu:MAX3421 +mcu:RP2040 +mcu:RX65X mcu:STM32C0 mcu:STM32F4 mcu:STM32F7 +mcu:STM32G0 mcu:STM32H5 mcu:STM32H7 mcu:STM32H7RS mcu:STM32N6 -family:samd21 -family:samd5x_e5x +mcu:STM32U3 +mcu:STM32U5 diff --git a/hw/bsp/stm32u5/family.mk b/hw/bsp/stm32u5/family.mk index 79f181a68..47aed10a9 100644 --- a/hw/bsp/stm32u5/family.mk +++ b/hw/bsp/stm32u5/family.mk @@ -37,11 +37,7 @@ SRC_C += \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_rcc_ex.c \ $(ST_HAL_DRIVER)/Src/stm32$(ST_FAMILY)xx_hal_uart.c -ifeq ($(MCU_VARIANT),stm32u545xx) -SRC_C += \ - src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ - src/portable/st/stm32_fsdev/fsdev_common.c -else ifeq ($(MCU_VARIANT),stm32u535xx) +ifneq ($(filter stm32u545xx stm32u535xx,$(MCU_VARIANT)),) SRC_C += \ src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c \ src/portable/st/stm32_fsdev/fsdev_common.c diff --git a/src/device/usbd.c b/src/device/usbd.c index 5365ae2c2..1a9eb630c 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -574,6 +574,8 @@ bool tud_deinit(uint8_t rhport) { TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport); + const uint8_t cfg_num = _usbd_dev.cfg_num; + // Deinit device controller driver dcd_int_disable(rhport); dcd_disconnect(rhport); @@ -604,7 +606,9 @@ bool tud_deinit(uint8_t rhport) { _usbd_rhport = RHPORT_INVALID; - tud_umount_cb(); + if (cfg_num > 0) { + tud_umount_cb(); + } return true; } diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c index 60ef339a6..5d60ad9a2 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.c +++ b/src/portable/st/stm32_fsdev/fsdev_common.c @@ -78,7 +78,9 @@ void fsdev_deinit(void) { // - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT // - Uses unaligned for RAM (since M0 cannot access unaligned address) bool fsdev_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_t nbytes) { - if (nbytes == 0) return true; + if (nbytes == 0) { + return true; + } uint32_t n_write = nbytes / FSDEV_BUS_SIZE; fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(dst); @@ -107,7 +109,9 @@ bool fsdev_write_packet_memory(uint16_t dst, const void *__restrict src, uint16_ // - Packet memory must be either strictly 16-bit or 32-bit depending on FSDEV_BUS_32BIT // - Uses unaligned for RAM (since M0 cannot access unaligned address) bool fsdev_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbytes) { - if (nbytes == 0) return true; + if (nbytes == 0) { + return true; + } uint32_t n_read = nbytes / FSDEV_BUS_SIZE; fsdev_pma_buf_t* pma_buf = PMA_BUF_AT(src); @@ -134,7 +138,9 @@ bool fsdev_read_packet_memory(void *__restrict dst, uint16_t src, uint16_t nbyte // Write to PMA from FIFO bool fsdev_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) { - if (wNBytes == 0) return true; + if (wNBytes == 0) { + return true; + } // Since we copy from a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies tu_fifo_buffer_info_t info; @@ -183,7 +189,9 @@ bool fsdev_write_packet_memory_ff(tu_fifo_t *ff, uint16_t dst, uint16_t wNBytes) // Read from PMA to FIFO bool fsdev_read_packet_memory_ff(tu_fifo_t *ff, uint16_t src, uint16_t wNBytes) { - if (wNBytes == 0) return true; + if (wNBytes == 0) { + return true; + } // Since we copy into a ring buffer FIFO, a wrap might occur making it necessary to conduct two copies // Check for first linear part diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c index 212f620ac..da9c6961c 100644 --- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c @@ -28,11 +28,11 @@ * This driver provides USB Host controller support for STM32 MCUs with "USB A"/"PCD"/"HCD" peripheral. * This covers these MCU families: * - * C0 2048 byte buffer; 32-bit bus; host mode - * G0 2048 byte buffer; 32-bit bus; host mode - * U3 2048 byte buffer; 32-bit bus; host mode - * H5 2048 byte buffer; 32-bit bus; host mode - * U535, U545 2048 byte buffer; 32-bit bus; host mode + * C0 2048 byte buffer; 32-bit bus; host mode + * G0 2048 byte buffer; 32-bit bus; host mode + * U3 2048 byte buffer; 32-bit bus; host mode + * H5 2048 byte buffer; 32-bit bus; host mode + * U535, U545 2048 byte buffer; 32-bit bus; host mode * */