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