summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksei Musin <[email protected]>2026-02-09 12:22:20 +0400
committerGitHub <[email protected]>2026-02-09 12:22:20 +0400
commit6e675da608b063e2ea7db1d700d788d6a247f9ec (patch)
tree5bcf5bb529e6ca2ebefc889920b28f1fab851e3f
parentebc9edfb7a512c8dd6816a40698c62c364bd78da (diff)
parentf5424c569ddc673a9c23b78febceed8f7f098509 (diff)
Merge branch 'hathach:master' into threadx_osal
-rw-r--r--.github/membrowse-targets.json494
-rw-r--r--.github/pull_request_template.md5
-rw-r--r--.github/workflows/build.yml60
-rw-r--r--.github/workflows/build_util.yml14
-rwxr-xr-x.github/workflows/ci_set_matrix.py6
-rw-r--r--.github/workflows/membrowse-comment.yml38
-rw-r--r--.github/workflows/membrowse-onboard.yml62
-rw-r--r--.github/workflows/membrowse-report.yml101
-rw-r--r--.idea/cmake.xml4
-rw-r--r--.idea/debugServers/ST_LINK.xml4
-rw-r--r--.idea/debugServers/mcxa153.xml13
-rw-r--r--.idea/debugServers/ra6m1.xml13
-rw-r--r--.idea/debugServers/ra6m5.xml13
-rw-r--r--.idea/debugServers/rt1011.xml13
-rw-r--r--.idea/debugServers/rt1170.xml13
-rw-r--r--.idea/debugServers/stm32f072.xml13
-rw-r--r--.idea/debugServers/stm32f303.xml13
-rw-r--r--.idea/debugServers/stm32l053.xml13
-rw-r--r--README.rst26
-rw-r--r--docs/reference/boards.rst5
-rw-r--r--docs/reference/dependencies.rst1
-rw-r--r--examples/device/dfu/skip.txt2
-rw-r--r--examples/device/mtp/src/mtp_fs_example.c2
-rw-r--r--examples/dual/host_info_to_device_cdc/src/main.c7
-rw-r--r--examples/host/device_info/src/main.c9
-rw-r--r--hw/bsp/BoardPresets.json44
-rw-r--r--hw/bsp/at32f45x/FreeRTOSConfig/FreeRTOSConfig.h176
-rw-r--r--hw/bsp/at32f45x/at32f45x_clock.c114
-rw-r--r--hw/bsp/at32f45x/at32f45x_clock.h44
-rw-r--r--hw/bsp/at32f45x/at32f45x_conf.h174
-rw-r--r--hw/bsp/at32f45x/at32f45x_int.c100
-rw-r--r--hw/bsp/at32f45x/at32f45x_int.h59
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f455/board.cmake8
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f455/board.h96
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f455/board.mk7
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f456/board.cmake8
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f456/board.h96
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f456/board.mk7
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f457/board.cmake8
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f457/board.h96
-rw-r--r--hw/bsp/at32f45x/boards/at_start_f457/board.mk7
-rw-r--r--hw/bsp/at32f45x/family.c258
-rw-r--r--hw/bsp/at32f45x/family.cmake97
-rw-r--r--hw/bsp/at32f45x/family.mk40
-rw-r--r--hw/bsp/family_support.cmake26
-rw-r--r--hw/bsp/rp2040/family.cmake5
-rw-r--r--hw/bsp/stm32h7/boards/stm32h747disco/board.cmake23
-rw-r--r--hw/bsp/stm32h7/boards/stm32h747disco/board.h169
-rw-r--r--hw/bsp/stm32h7/boards/stm32h747disco/board.mk15
-rw-r--r--hw/bsp/stm32h7/linker/stm32h747xx_flash_CM7.ld184
-rw-r--r--hw/bsp/tm4c/FreeRTOSConfig/FreeRTOSConfig.h8
-rw-r--r--hw/bsp/tm4c/boards/ek_tm4c123gxl/board.h6
-rw-r--r--hw/bsp/tm4c/boards/ek_tm4c123gxl/tm4c123.ld2
-rw-r--r--hw/bsp/tm4c/boards/ek_tm4c1294xl/TM4C1294NC.icf28
-rw-r--r--hw/bsp/tm4c/boards/ek_tm4c1294xl/board.cmake13
-rw-r--r--hw/bsp/tm4c/boards/ek_tm4c1294xl/board.h75
-rw-r--r--hw/bsp/tm4c/boards/ek_tm4c1294xl/board.mk16
-rw-r--r--hw/bsp/tm4c/boards/ek_tm4c1294xl/tm4c1294nc.ld66
-rw-r--r--hw/bsp/tm4c/family.c76
-rw-r--r--hw/bsp/tm4c/family.cmake17
-rw-r--r--hw/bsp/tm4c/family.mk6
-rw-r--r--src/class/audio/audio_device.c12
-rw-r--r--src/class/cdc/cdc_host.c2
-rw-r--r--src/class/mtp/mtp_device.c105
-rw-r--r--src/class/vendor/vendor_device.c262
-rw-r--r--src/class/vendor/vendor_device.h44
-rw-r--r--src/common/tusb_common.h4
-rw-r--r--src/common/tusb_fifo.c439
-rw-r--r--src/common/tusb_fifo.h114
-rw-r--r--src/common/tusb_mcu.h173
-rw-r--r--src/common/tusb_private.h8
-rw-r--r--src/common/tusb_types.h2
-rw-r--r--src/common/tusb_verify.h10
-rw-r--r--src/device/usbd.c10
-rw-r--r--src/device/usbd.h4
-rw-r--r--src/host/usbh.c24
-rw-r--r--src/osal/osal_none.h18
-rw-r--r--src/osal/osal_pico.h54
-rw-r--r--src/portable/mentor/musb/dcd_musb.c100
-rw-r--r--src/portable/mentor/musb/musb_ti.h5
-rw-r--r--src/portable/mentor/musb/musb_type.h2
-rw-r--r--src/portable/microchip/samg/dcd_samg.c4
-rw-r--r--src/portable/nuvoton/nuc505/dcd_nuc505.c4
-rw-r--r--src/portable/raspberrypi/rp2040/dcd_rp2040.c269
-rw-r--r--src/portable/raspberrypi/rp2040/hcd_rp2040.c220
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.c260
-rw-r--r--src/portable/raspberrypi/rp2040/rp2040_usb.h179
-rw-r--r--src/portable/renesas/rusb2/dcd_rusb2.c259
-rw-r--r--src/portable/renesas/rusb2/hcd_rusb2.c135
-rw-r--r--src/portable/renesas/rusb2/rusb2_common.c80
-rw-r--r--src/portable/renesas/rusb2/rusb2_common.h58
-rw-r--r--src/portable/renesas/rusb2/rusb2_type.h20
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c302
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_at32.h1
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_ch32.h1
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.c173
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.h140
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h188
-rw-r--r--src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c18
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c97
-rw-r--r--src/portable/synopsys/dwc2/dwc2_at32.h5
-rw-r--r--src/portable/synopsys/dwc2/dwc2_common.c54
-rw-r--r--src/portable/synopsys/dwc2/hcd_dwc2.c4
-rw-r--r--src/tusb.c103
-rw-r--r--src/tusb_option.h132
-rwxr-xr-xtest/hil/hil_test.py12
-rw-r--r--test/hil/tinyusb.json6
-rw-r--r--test/unit-test/CMakeLists.txt1
-rw-r--r--test/unit-test/project.yml4
-rw-r--r--test/unit-test/test/test_fifo.c130
-rwxr-xr-xtools/build.py4
-rwxr-xr-xtools/get_deps.py5
112 files changed, 5189 insertions, 2189 deletions
diff --git a/.github/membrowse-targets.json b/.github/membrowse-targets.json
new file mode 100644
index 000000000..05c90c74e
--- /dev/null
+++ b/.github/membrowse-targets.json
@@ -0,0 +1,494 @@
+{
+ "templates": {
+ "build_cmd": "python3 tools/build.py -s cmake -b ${board}",
+ "elf": "cmake-build/cmake-build-${board}/device/${example}/${example}.elf",
+ "setup_cmd": "${toolchain.setup_cmd} && python3 tools/get_deps.py ${get_deps}",
+ "get_deps": "${port}"
+ },
+ "toolchains": {
+ "arm-none-eabi-gcc-14": {
+ "setup_cmd": "NINJA_URL=https://github.com/ninja-build/ninja/releases/download/v1.13.1/ninja-linux.zip && wget -q $NINJA_URL -O ninja-linux.zip && unzip -q ninja-linux.zip -d $HOME/bin && echo \"$HOME/bin\" >> $GITHUB_PATH && TOOLCHAIN_URL=https://github.com/xpack-dev-tools/arm-none-eabi-gcc-xpack/releases/download/v14.2.1-1.1/xpack-arm-none-eabi-gcc-14.2.1-1.1-linux-x64.tar.gz && mkdir -p $HOME/toolchain && wget -q $TOOLCHAIN_URL -O toolchain.tar.gz && tar -C $HOME/toolchain -xf toolchain.tar.gz && echo \"$HOME/toolchain/xpack-arm-none-eabi-gcc-14.2.1-1.1/bin\" >> $GITHUB_PATH"
+ },
+ "aarch64-none-elf-gcc-10": {
+ "setup_cmd": "NINJA_URL=https://github.com/ninja-build/ninja/releases/download/v1.13.1/ninja-linux.zip && wget -q $NINJA_URL -O ninja-linux.zip && unzip -q ninja-linux.zip -d $HOME/bin && echo \"$HOME/bin\" >> $GITHUB_PATH && TOOLCHAIN_URL=https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz && mkdir -p $HOME/toolchain && wget -q $TOOLCHAIN_URL -O toolchain.tar.xz && tar -C $HOME/toolchain -xf toolchain.tar.xz && echo \"$HOME/toolchain/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin\" >> $GITHUB_PATH"
+ },
+ "riscv-none-elf-gcc-13": {
+ "setup_cmd": "NINJA_URL=https://github.com/ninja-build/ninja/releases/download/v1.13.1/ninja-linux.zip && wget -q $NINJA_URL -O ninja-linux.zip && unzip -q ninja-linux.zip -d $HOME/bin && echo \"$HOME/bin\" >> $GITHUB_PATH && TOOLCHAIN_URL=https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz && mkdir -p $HOME/toolchain && wget -q $TOOLCHAIN_URL -O toolchain.tar.gz && tar -C $HOME/toolchain -xf toolchain.tar.gz && echo \"$HOME/toolchain/xpack-riscv-none-elf-gcc-13.2.0-2/bin\" >> $GITHUB_PATH"
+ },
+ "msp430-gcc-9": {
+ "setup_cmd": "NINJA_URL=https://github.com/ninja-build/ninja/releases/download/v1.13.1/ninja-linux.zip && wget -q $NINJA_URL -O ninja-linux.zip && unzip -q ninja-linux.zip -d $HOME/bin && echo \"$HOME/bin\" >> $GITHUB_PATH && TOOLCHAIN_URL=http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2 && mkdir -p $HOME/toolchain && wget -q $TOOLCHAIN_URL -O toolchain.tar.bz2 && tar -C $HOME/toolchain -xf toolchain.tar.bz2 && echo \"$HOME/toolchain/msp430-gcc-9.2.0.50_linux64/bin\" >> $GITHUB_PATH"
+ }
+ },
+ "targets": [
+ {
+ "port": "at32f402_405",
+ "board": "at_start_f402",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/artery/at32f402_405/libraries/cmsis/cm4/device_support/startup/gcc/linker/AT32F402xC_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "at32f403a_407",
+ "board": "at32f403a_weact_blackpill",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/artery/at32f403a_407/libraries/cmsis/cm4/device_support/startup/gcc/linker/AT32F403AxC_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "at32f413",
+ "board": "at_start_f413",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/artery/at32f413/libraries/cmsis/cm4/device_support/startup/gcc/linker/AT32F413xC_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "at32f415",
+ "board": "at_start_f415",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/artery/at32f415/libraries/cmsis/cm4/device_support/startup/gcc/linker/AT32F415xC_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "at32f423",
+ "board": "at_start_f423",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/artery/at32f423/libraries/cmsis/cm4/device_support/startup/gcc/linker/AT32F423xC_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "at32f425",
+ "board": "at_start_f425",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/artery/at32f425/libraries/cmsis/cm4/device_support/startup/gcc/linker/AT32F425x8_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "at32f435_437",
+ "board": "at_start_f435",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/artery/at32f435_437/libraries/cmsis/cm4/device_support/startup/gcc/linker/AT32F435xM_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "broadcom_32bit",
+ "board": "raspberrypi_zero",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/broadcom/broadcom/link.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "broadcom_64bit",
+ "board": "raspberrypi_cm4",
+ "toolchain": "aarch64-none-elf-gcc-10",
+ "ld": "hw/mcu/broadcom/broadcom/link8.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "ch32v10x",
+ "board": "ch32v103r_r1_1v0",
+ "toolchain": "riscv-none-elf-gcc-13",
+ "ld": "hw/bsp/ch32v10x/linker/ch32v10x.ld",
+ "linker_vars": "__FLASH_SIZE=64K __RAM_SIZE=20K",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "ch32v20x",
+ "board": "ch32v203c_r0_1v0",
+ "toolchain": "riscv-none-elf-gcc-13",
+ "ld": "hw/bsp/ch32v20x/linker/ch32v20x.ld",
+ "linker_vars": "__flash_size=64K __ram_size=20K",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "ch32v30x",
+ "board": "ch32v307v_r1_1v0",
+ "toolchain": "riscv-none-elf-gcc-13",
+ "ld": "hw/bsp/ch32v30x/linker/ch32v30x.ld",
+ "linker_vars": "__flash_size=128K __ram_size=32K",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "da1469x",
+ "board": "da14695_dk_usb",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/da1469x/linker/da1469x.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "fomu",
+ "board": "fomu",
+ "toolchain": "riscv-none-elf-gcc-13",
+ "ld": "hw/bsp/fomu/fomu.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "gd32vf103",
+ "board": "sipeed_longan_nano",
+ "toolchain": "riscv-none-elf-gcc-13",
+ "ld": "hw/mcu/gd/nuclei-sdk/SoC/gd32vf103/Board/gd32vf103c_longan_nano/Source/GCC/gcc_gd32vf103xb_flashxip.ld",
+ "linker_vars": "__ROM_BASE=0x08000000 __ROM_SIZE=0x00020000 __RAM_BASE=0x20000000 __RAM_SIZE=0x00008000",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "hpmicro",
+ "board": "hpm6750evk2",
+ "toolchain": "riscv-none-elf-gcc-13",
+ "ld": "hw/mcu/hpmicro/hpm_sdk/soc/HPM6700/HPM6750/toolchains/gcc/flash_xip.ld",
+ "linker_vars": "_flash_size=16M _stack_size=16K _heap_size=16K",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "imxrt",
+ "board": "metro_m7_1011",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/nxp/mcux-sdk/devices/MIMXRT1011/gcc/MIMXRT1011xxxxx_flexspi_nor.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "kinetis_k",
+ "board": "frdm_k64f",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/nxp/mcux-sdk/devices/MK64F12/gcc/MK64FN1M0xxx12_flash.ld",
+ "get_deps": "kinetis_k kinetis_kl",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "kinetis_k32l2",
+ "board": "frdm_k32l2a4s",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/nxp/mcux-sdk/devices/K32L2A41A/gcc/K32L2A41xxxxA_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "kinetis_kl",
+ "board": "frdm_kl25z",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/kinetis_kl/gcc/MKL25Z128xxx4_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc11",
+ "board": "lpcxpresso11u37",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/lpc11/boards/lpcxpresso11u37/lpc11u37.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc13",
+ "board": "lpcxpresso1347",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/lpc13/boards/lpcxpresso1347/lpc1347.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc15",
+ "board": "lpcxpresso1549",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/lpc15/boards/lpcxpresso1549/lpc1549.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc17",
+ "board": "lpcxpresso1769",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/lpc17/boards/lpcxpresso1769/lpc1769.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc18",
+ "board": "lpcxpresso18s37",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/lpc18/boards/lpcxpresso18s37/lpc1837.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc40",
+ "board": "ea4088_quickstart",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/lpc40/boards/ea4088_quickstart/lpc4088.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc43",
+ "board": "ea4357",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/lpc43/boards/ea4357/lpc4357.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc51",
+ "board": "lpcxpresso51u68",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/nxp/mcux-sdk/devices/LPC51U68/gcc/LPC51U68_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc54",
+ "board": "lpcxpresso54114",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/nxp/mcux-sdk/devices/LPC54114/gcc/LPC54114J256_cm4_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "lpc55",
+ "board": "double_m33_express",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/lpc55/boards/double_m33_express/LPC55S69_cm33_core0_uf2.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "maxim",
+ "board": "apard32690",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/maxim/linker/max32690.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "mcx",
+ "board": "frdm_mcxa153",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/nxp/mcux-sdk/devices/MCXA153/gcc/MCXA153_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "mm32",
+ "board": "mm32f327x_mb39",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/mm32/boards/mm32f327x_mb39/flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "msp430",
+ "board": "msp_exp430f5529lp",
+ "toolchain": "msp430-gcc-9",
+ "ld": "hw/mcu/ti/msp430/msp430-gcc-support-files/include/msp430f5529.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "msp432e4",
+ "board": "msp_exp432e401y",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/ti/msp432e4/Source/msp432e411y.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "nrf",
+ "board": "adafruit_clue",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/nrf/linker/nrf52840_xxaa.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "nuc100_120",
+ "board": "nutiny_sdk_nuc120",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/nuc100_120/boards/nutiny_sdk_nuc120/nuc120_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "nuc121_125",
+ "board": "nutiny_sdk_nuc121",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/nuc121_125/boards/nutiny_sdk_nuc121/nuc121_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "nuc126",
+ "board": "nutiny_nuc126v",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/nuc126/boards/nutiny_nuc126v/nuc126_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "nuc505",
+ "board": "nutiny_sdk_nuc505",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/nuc505/boards/nutiny_sdk_nuc505/nuc505_flashtoram.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "ra",
+ "board": "portenta_c33",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/ra/boards/portenta_c33/script/memory_regions.ld hw/bsp/ra/boards/portenta_c33/script/fsp.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "rw61x",
+ "board": "frdm_rw612",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/nxp/mcux-sdk/devices/RW612/gcc/RW612_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "samd11",
+ "board": "cynthion_d11",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/samd11/boards/cynthion_d11/cynthion_d11.ld",
+ "linker_vars": "BOOTLOADER_SIZE=0x800",
+ "example": "cdc_dual_ports"
+ },
+ {
+ "port": "samd5x_e5x",
+ "board": "metro_m4_express",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/samd5x_e5x/boards/metro_m4_express/metro_m4_express.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "samg",
+ "board": "samg55_xplained",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/samg/boards/samg55_xplained/samg55j19_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32c0",
+ "board": "stm32c071nucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32c0/boards/stm32c071nucleo/STM32C071RBTx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32f0",
+ "board": "stm32f070rbnucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32f0/boards/stm32f070rbnucleo/stm32F070rbtx_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32f1",
+ "board": "stm32f103_bluepill",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32f1/boards/stm32f103_bluepill/STM32F103X8_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32f2",
+ "board": "stm32f207nucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32f2/boards/stm32f207nucleo/STM32F207ZGTx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32f3",
+ "board": "stm32f303disco",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32f3/boards/stm32f303disco/STM32F303VCTx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32f4",
+ "board": "feather_stm32f405",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32f4/boards/feather_stm32f405/STM32F405RGTx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32f7",
+ "board": "stlinkv3mini",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32f7/boards/stlinkv3mini/STM32F723xE_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32g0",
+ "board": "stm32g0b1nucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32g0/boards/stm32g0b1nucleo/STM32G0B1RETx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32g4",
+ "board": "b_g474e_dpow1",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32g4/boards/b_g474e_dpow1/STM32G474RETx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32h5",
+ "board": "stm32h503nucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32h5/linker/STM32H533xx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32h7",
+ "board": "stm32h743eval",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32h7/linker/stm32h743xx_flash.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32h7rs",
+ "board": "stm32h7s3nucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32h7rs/linker/stm32h7s3xx_flash.ld",
+ "linker_vars": "__FLASH_BEGIN=0x08000000 __FLASH_SIZE=0x00010000 __RAM_BEGIN=0x24000000 __RAM_SIZE=0x4FC00 __RAM_NONCACHEABLEBUFFER_SIZE=0x400",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32l0",
+ "board": "stm32l052dap52",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32l0/boards/stm32l052dap52/STM32L052K8Ux_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32l4",
+ "board": "stm32l412nucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32l4/boards/stm32l412nucleo/STM32L412KBUx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32n6",
+ "board": "stm32n6570dk",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32n6/boards/stm32n6570dk/STM32N657XX_AXISRAM2_fsbl.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32u0",
+ "board": "stm32u083cdk",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32u0/boards/stm32u083cdk/STM32U083MCTx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32u5",
+ "board": "b_u585i_iot2a",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32u5/linker/STM32U5A9xx_FLASH.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32wb",
+ "board": "stm32wb55nucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32wb/boards/stm32wb55nucleo/stm32wb55xx_flash_cm4.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "stm32wba",
+ "board": "stm32wba_nucleo",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/stm32wba/linker/STM32WBA65xx_FLASH_ns.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "tm4c",
+ "board": "ek_tm4c123gxl",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/bsp/tm4c/boards/ek_tm4c123gxl/tm4c123.ld",
+ "example": "cdc_msc"
+ },
+ {
+ "port": "xmc4000",
+ "board": "xmc4500_relax",
+ "toolchain": "arm-none-eabi-gcc-14",
+ "ld": "hw/mcu/infineon/mtb-xmclib-cat3/CMSIS/Infineon/COMPONENT_XMC4500/Source/TOOLCHAIN_GCC_ARM/XMC4500x1024.ld",
+ "example": "cdc_msc"
+ }
+ ]
+}
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
deleted file mode 100644
index aa148eb79..000000000
--- a/.github/pull_request_template.md
+++ /dev/null
@@ -1,5 +0,0 @@
-**Describe the PR**
-A clear and concise description of what this PR solve.
-
-**Additional context**
-If applicable, add any other context about the PR and/or screenshots here.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 781d3b002..ded4e816c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -3,6 +3,7 @@ name: Build
on:
workflow_dispatch:
push:
+ branches: [master]
paths:
- 'src/**'
- 'examples/**'
@@ -29,6 +30,7 @@ on:
- '.github/workflows/ci_set_matrix.py'
release:
types: [ published ]
+
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
@@ -82,6 +84,7 @@ jobs:
build-args: ${{ toJSON(fromJSON(needs.set-matrix.outputs.json)[matrix.toolchain]) }}
build-options: '--one-first'
upload-metrics: true
+ upload-artifacts: true
code-metrics:
needs: cmake
@@ -181,7 +184,6 @@ jobs:
# Build Make/CMake on Windows/MacOS
# ---------------------------------------
build-os:
- if: github.event_name == 'pull_request'
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
@@ -198,7 +200,8 @@ jobs:
# Zephyr
# ---------------------------------------
zephyr:
- if: github.event_name == 'push'
+ # skip zephyr build due to failed build, fix later
+ if: false
runs-on: ubuntu-latest
steps:
- name: Checkout TinyUSB
@@ -220,10 +223,8 @@ jobs:
# Run on PR only (hil-tinyusb), hil-hfp only run on non-forked PR
# ---------------------------------------
hil-build:
- if: |
- github.repository_owner == 'hathach' &&
- (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch')
needs: set-matrix
+ if: github.repository_owner == 'hathach'
uses: ./.github/workflows/build_util.yml
strategy:
fail-fast: false
@@ -242,7 +243,6 @@ jobs:
# self-hosted on local VM, for attached hardware checkout HIL_JSON
# ---------------------------------------
hil-tinyusb:
- if: github.repository_owner == 'hathach' && github.event_name != 'push'
needs: hil-build
runs-on: [ self-hosted, X64, hathach, hardware-in-the-loop ]
steps:
@@ -285,8 +285,7 @@ jobs:
hil-hfp:
if: |
github.repository_owner == 'hathach' &&
- github.event.pull_request.head.repo.fork == false &&
- github.event_name != 'push'
+ !(github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == true)
runs-on: [ self-hosted, Linux, X64, hifiphile ]
env:
IAR_LMS_BEARER_TOKEN: ${{ secrets.IAR_LMS_BEARER_TOKEN }}
@@ -315,7 +314,50 @@ jobs:
run: python3 tools/get_deps.py $BUILD_ARGS
- name: Build
- run: python3 tools/build.py -j 4 --toolchain iar $BUILD_ARGS
+ run: python3 tools/build.py --toolchain iar $BUILD_ARGS
- name: Test on actual hardware (hardware in the loop)
run: python3 test/hil/hil_test.py hfp.json
+
+ # ---------------------------------------
+ # Membrowse Memory Analysis
+ # Push: always runs (uses identical for doc-only to maintain commit chain)
+ # PR: only runs if code changed (doc-only PRs skip entirely)
+ # ---------------------------------------
+ membrowse:
+ needs: cmake
+ permissions:
+ contents: read
+ actions: read
+ uses: ./.github/workflows/membrowse-report.yml
+ with:
+ code_changed: true
+ secrets: inherit
+
+ membrowse-comment:
+ needs: membrowse
+ # skip membrowse comment since it is too verbal
+ if: false && github.event_name == 'pull_request'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ actions: read
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+
+ - name: Download report artifacts
+ id: download
+ uses: actions/download-artifact@v5
+ with:
+ pattern: membrowse-report-*
+ path: reports
+ merge-multiple: true
+ continue-on-error: true
+
+ - name: Upload Membrowse Comment Artifact
+ if: steps.download.outcome == 'success'
+ uses: actions/upload-artifact@v5
+ with:
+ name: membrowse-comment
+ path: reports/
diff --git a/.github/workflows/build_util.yml b/.github/workflows/build_util.yml
index 540ee8b47..e62c10ca1 100644
--- a/.github/workflows/build_util.yml
+++ b/.github/workflows/build_util.yml
@@ -73,6 +73,19 @@ jobs:
name: metrics-${{ matrix.arg }}
path: cmake-build/cmake-build-*/metrics.json
+ - name: Copy linker scripts for artifacts
+ if: ${{ inputs.upload-artifacts }}
+ run: |
+ for dir in cmake-build/cmake-build-*; do
+ board=$(basename "$dir" | sed 's/cmake-build-//')
+ ld_path=$(jq -r --arg b "$board" '.targets[] | select(.board == $b) | .ld // empty' .github/membrowse-targets.json)
+ if [ -n "$ld_path" ] && [ -f "$ld_path" ]; then
+ mkdir -p "cmake-build/$(dirname "$ld_path")"
+ cp "$ld_path" "cmake-build/$ld_path"
+ fi
+ done
+ shell: bash
+
- name: Upload Artifacts for Hardware Testing
if: ${{ inputs.upload-artifacts }}
uses: actions/upload-artifact@v5
@@ -86,3 +99,4 @@ jobs:
cmake-build/cmake-build-*/*/*/partition_table/partition-table.bin
cmake-build/cmake-build-*/*/*/config.env
cmake-build/cmake-build-*/*/*/flash_args
+ cmake-build/hw/mcu/**/*.ld
diff --git a/.github/workflows/ci_set_matrix.py b/.github/workflows/ci_set_matrix.py
index c276d5253..9ab08601d 100755
--- a/.github/workflows/ci_set_matrix.py
+++ b/.github/workflows/ci_set_matrix.py
@@ -15,7 +15,8 @@ toolchain_list = [
# family: [supported toolchain]
family_list = {
- "at32f402_405 at32f403a_407 at32f413 at32f415 at32f423 at32f425 at32f435_437 broadcom_32bit da1469x": ["arm-gcc"],
+ "at32f45x at32f402_405 at32f403a_407 at32f413 at32f415 at32f423 at32f425 at32f435_437 broadcom_32bit da1469x": [
+ "arm-gcc"],
"broadcom_64bit": ["aarch64-gcc"],
"ch32v10x ch32v20x ch32v30x fomu gd32vf103 hpmicro": ["riscv-gcc"],
"imxrt": ["arm-gcc", "arm-clang"],
@@ -37,7 +38,8 @@ family_list = {
"stm32h7": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32h7rs stm32l0 stm32l4": ["arm-gcc", "arm-clang", "arm-iar"],
"stm32n6": ["arm-gcc"],
- "stm32u0 stm32u5 stm32wb stm32wba": ["arm-gcc", "arm-clang", "arm-iar"],
+ "stm32u0 stm32wb stm32wba": ["arm-gcc", "arm-clang", "arm-iar"],
+ "stm32u5": ["arm-gcc", "arm-clang", "arm-iar"],
"-bespressif_s2_devkitc": ["esp-idf"],
# S3, P4 will be built by hil test
# "-bespressif_s3_devkitm": ["esp-idf"],
diff --git a/.github/workflows/membrowse-comment.yml b/.github/workflows/membrowse-comment.yml
new file mode 100644
index 000000000..a99c9db51
--- /dev/null
+++ b/.github/workflows/membrowse-comment.yml
@@ -0,0 +1,38 @@
+name: Membrowse Comment
+
+on:
+ workflow_run:
+ workflows: ["Build"]
+ types:
+ - completed
+
+jobs:
+ post-comment:
+ runs-on: ubuntu-latest
+ if: >
+ github.event.workflow_run.event == 'pull_request' &&
+ github.event.workflow_run.conclusion != 'cancelled'
+ permissions:
+ actions: read
+ pull-requests: write
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+
+ - name: Download Artifacts
+ id: download
+ uses: actions/download-artifact@v5
+ with:
+ run-id: ${{ github.event.workflow_run.id }}
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ name: membrowse-comment
+ path: reports
+ continue-on-error: true
+
+ - name: Post Membrowse PR comment
+ if: steps.download.outcome == 'success'
+ uses: membrowse/membrowse-action/comment-action@v1
+ with:
+ json_files: 'reports/*.json'
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/membrowse-onboard.yml b/.github/workflows/membrowse-onboard.yml
new file mode 100644
index 000000000..aa7204ffa
--- /dev/null
+++ b/.github/workflows/membrowse-onboard.yml
@@ -0,0 +1,62 @@
+name: Onboard to Membrowse
+
+on:
+ workflow_dispatch:
+ inputs:
+ num_commits:
+ description: 'Number of commits to process'
+ required: true
+ default: '10'
+ type: string
+
+jobs:
+ load-targets:
+ runs-on: ubuntu-22.04
+ outputs:
+ targets: ${{ steps.load.outputs.targets }}
+ toolchains: ${{ steps.load.outputs.toolchains }}
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+
+ - name: Load target matrix
+ id: load
+ run: |
+ echo "targets=$(jq -c '.targets' .github/membrowse-targets.json)" >> $GITHUB_OUTPUT
+ echo "toolchains=$(jq -c '.toolchains' .github/membrowse-targets.json)" >> $GITHUB_OUTPUT
+
+ onboard:
+ needs: load-targets
+ runs-on: ubuntu-22.04
+ strategy:
+ fail-fast: false
+ matrix:
+ include: ${{ fromJson(needs.load-targets.outputs.targets) }}
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v5
+ with:
+ fetch-depth: 0
+ submodules: recursive
+
+ - name: Install packages
+ run: |
+ ${{ fromJson(needs.load-targets.outputs.toolchains)[matrix.toolchain].setup_cmd }} && python3 tools/get_deps.py ${{ matrix.get_deps || matrix.port }}
+
+ - name: Setup ccache
+ uses: hendrikmuhs/[email protected]
+ with:
+ key: ${{ matrix.port }}-${{ matrix.board }}
+
+ - name: Run Membrowse Onboard Action
+ uses: membrowse/membrowse-action/onboard-action@v1
+ with:
+ target_name: ${{ matrix.port }}-${{ matrix.board }}-${{ matrix.example }}
+ num_commits: ${{ github.event.inputs.num_commits }}
+ build_script: python3 tools/build.py -s cmake -b ${{ matrix.board }}
+ elf: cmake-build/cmake-build-${{ matrix.board }}/device/${{ matrix.example }}/${{ matrix.example }}.elf
+ ld: ${{ matrix.ld }}
+ linker_vars: ${{ matrix.linker_vars || '' }}
+ api_key: ${{ secrets.MEMBROWSE_API_KEY }}
+ api_url: ${{ vars.MEMBROWSE_API_URL }}
diff --git a/.github/workflows/membrowse-report.yml b/.github/workflows/membrowse-report.yml
new file mode 100644
index 000000000..0667418e6
--- /dev/null
+++ b/.github/workflows/membrowse-report.yml
@@ -0,0 +1,101 @@
+name: Membrowse Memory Report
+
+on:
+ workflow_call:
+ inputs:
+ code_changed:
+ description: 'Whether code paths changed (true) or doc-only (false)'
+ type: boolean
+ required: true
+
+permissions:
+ contents: read
+ actions: read
+
+jobs:
+ load-targets:
+ runs-on: ubuntu-latest
+ outputs:
+ targets: ${{ steps.load.outputs.targets }}
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+
+ - name: Load target matrix
+ id: load
+ run: echo "targets=$(jq -c '.targets' .github/membrowse-targets.json)" >> $GITHUB_OUTPUT
+
+ analyze:
+ needs: [load-targets]
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ include: ${{ fromJson(needs.load-targets.outputs.targets) }}
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+ submodules: recursive
+
+ # Download artifacts when code changed (build artifacts available)
+ - name: Download build artifacts
+ if: inputs.code_changed
+ id: download
+ uses: actions/download-artifact@v5
+ with:
+ pattern: binaries-*
+ path: cmake-build
+ merge-multiple: true
+ continue-on-error: true
+
+ - name: Restore linker scripts
+ if: inputs.code_changed
+ run: cp -r cmake-build/hw . 2>/dev/null || true
+
+ - name: Check if ELF exists
+ id: check-elf
+ run: |
+ if [ -f "cmake-build/cmake-build-${{ matrix.board }}/device/${{ matrix.example }}/${{ matrix.example }}.elf" ]; then
+ echo "exists=true" >> $GITHUB_OUTPUT
+ else
+ echo "exists=false" >> $GITHUB_OUTPUT
+ fi
+
+ # Run with actual ELF analysis when build artifacts available
+ - name: Run Membrowse Analysis
+ if: steps.check-elf.outputs.exists == 'true'
+ id: membrowse
+ continue-on-error: true
+ uses: membrowse/membrowse-action@v1
+ with:
+ target_name: ${{ matrix.port }}-${{ matrix.board }}-${{ matrix.example }}
+ elf: cmake-build/cmake-build-${{ matrix.board }}/device/${{ matrix.example }}/${{ matrix.example }}.elf
+ ld: ${{ matrix.ld }}
+ linker_vars: ${{ matrix.linker_vars || '' }}
+ api_key: ${{ secrets.MEMBROWSE_API_KEY }}
+ api_url: ${{ vars.MEMBROWSE_API_URL }}
+ verbose: INFO
+
+ # Run with identical=true when no ELF (doc-only push)
+ # Preserves the chain of commits in membrowse tracking
+ - name: Run Membrowse Identical Report
+ if: steps.check-elf.outputs.exists == 'false'
+ id: membrowse-identical
+ continue-on-error: true
+ uses: membrowse/membrowse-action@v1
+ with:
+ target_name: ${{ matrix.port }}-${{ matrix.board }}-${{ matrix.example }}
+ identical: true
+ api_key: ${{ secrets.MEMBROWSE_API_KEY }}
+ api_url: ${{ vars.MEMBROWSE_API_URL }}
+ verbose: INFO
+
+ - name: Upload report artifact
+ if: steps.membrowse.outcome == 'success' || steps.membrowse-identical.outcome == 'success'
+ uses: actions/upload-artifact@v5
+ with:
+ name: membrowse-report-${{ matrix.port }}-${{ matrix.board }}-${{ matrix.example }}
+ path: ${{ steps.membrowse.outputs.report_path || steps.membrowse-identical.outputs.report_path }}
diff --git a/.idea/cmake.xml b/.idea/cmake.xml
index 0754253ad..5f9e1acd2 100644
--- a/.idea/cmake.xml
+++ b/.idea/cmake.xml
@@ -103,6 +103,8 @@
<configuration PROFILE_NAME="metro m7 1011 sd" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011_sd -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="metro_m7_1011" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=metro_m7_1011 -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="rt1010 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1010_evk -DLOG=1 -DLOGGER=RTT" />
+ <configuration PROFILE_NAME="rt1024 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1024_evk -DLOG=1 -DLOGGER=RTT" />
+ <configuration PROFILE_NAME="rt1050 evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1050_evkb -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="mimxrt1060_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1060_evk -DLOG=1" />
<configuration PROFILE_NAME="mimxrt1064_evk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1064_evk" />
<configuration PROFILE_NAME="rt1170 evkb" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=mimxrt1170_evkb -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
@@ -126,8 +128,10 @@
<configuration PROFILE_NAME="stm32h743eval_host1" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h743eval -DRHPORT_HOST=1 -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1" />
<configuration PROFILE_NAME="stm32h743eval IAR" ENABLED="false" CONFIG_NAME="Debug" TOOLCHAIN_NAME="iccarm" GENERATION_OPTIONS="-DBOARD=stm32h743eval -DLOG=1 -DLOGGER=RTT -DTRACE_ETM=1 -DIAR_CSTAT=1" />
<configuration PROFILE_NAME="stm32h743nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h743nucleo -DLOG=1" />
+ <configuration PROFILE_NAME="stm32h7s3nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32h7s3nucleo -DLOG=1" />
<configuration PROFILE_NAME="stm32l0538disco" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32l0538disco -DLOG=0 -DLOGGER=RTT" />
<configuration PROFILE_NAME="stm32l476disco" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32l476disco -DLOG=1 -DLOGGER=RTT" />
+ <configuration PROFILE_NAME="stm32u083cdk" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32u083cdk -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="stm32u575nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32u575nucleo -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="stm32u5a5nucleo" ENABLED="false" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DBOARD=stm32u5a5nucleo -DLOG=1 -DLOGGER=RTT" />
<configuration PROFILE_NAME="stm32wb55nucleo" ENABLED="false" GENERATION_OPTIONS="-DBOARD=stm32wb55nucleo" />
diff --git a/.idea/debugServers/ST_LINK.xml b/.idea/debugServers/ST_LINK.xml
index 7c21d3879..c4dadd5bb 100644
--- a/.idea/debugServers/ST_LINK.xml
+++ b/.idea/debugServers/ST_LINK.xml
@@ -1,10 +1,10 @@
<component name="DebugServers">
- <stlink-debug-target name="ST-LINK" uniqueID="300d1a6f-85c0-4eb3-9753-f033d01e2eff">
+ <stlink-debug-target name="ST-LINK" uniqueID="cf98f5f4-9c5b-4340-ab06-16ddd7f07062">
<debugger version="1">
<debugger kind="GDB" isBundled="true" />
<env />
</debugger>
- <gdbserver exe="$USER_HOME$/st/stm32cubeide_1.16.1/plugins/com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.linux64_2.1.400.202404281720/tools/bin/ST-LINK_gdbserver" programmer="$USER_HOME$/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin" />
+ <gdbserver exe="/opt/st/stm32cubeclt_1.20.0/STLink-gdb-server/bin/ST-LINK_gdbserver" programmer="/opt/st/stm32cubeclt_1.20.0/STM32CubeProgrammer/bin" />
<st-link />
<device interface="SWD" />
<connection port="61234" warmup-ms="500" />
diff --git a/.idea/debugServers/mcxa153.xml b/.idea/debugServers/mcxa153.xml
new file mode 100644
index 000000000..0e493cbd5
--- /dev/null
+++ b/.idea/debugServers/mcxa153.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="mcxa153" uniqueID="6a023429-69e6-4f8c-a592-4995cdf255db">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="MCXA153" reset-before="false" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/ra6m1.xml b/.idea/debugServers/ra6m1.xml
new file mode 100644
index 000000000..17c902ec4
--- /dev/null
+++ b/.idea/debugServers/ra6m1.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="ra6m1" uniqueID="c8cdc79a-939b-4342-92b1-d24da72d12fe">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="R7FA6M1AD" reset-before="false" frequency="16000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/ra6m5.xml b/.idea/debugServers/ra6m5.xml
new file mode 100644
index 000000000..d8dfbdeeb
--- /dev/null
+++ b/.idea/debugServers/ra6m5.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="ra6m5" uniqueID="19100d9f-7329-47da-b566-f9faf297f47c">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="R7FA6M5BH" reset-before="false" frequency="16000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/rt1011.xml b/.idea/debugServers/rt1011.xml
new file mode 100644
index 000000000..b4be501bd
--- /dev/null
+++ b/.idea/debugServers/rt1011.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="rt1011" uniqueID="e10c53c4-acf5-4a6f-a05d-32b7b042d70a">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="MIMXRT1011xxx5A" reset-before="false" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/rt1170.xml b/.idea/debugServers/rt1170.xml
new file mode 100644
index 000000000..9a564ed57
--- /dev/null
+++ b/.idea/debugServers/rt1170.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="rt1170" uniqueID="cfc772e4-782e-49a3-99fb-b6f726e14f9d">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="MIMXRT1176xxxA_M7" reset-before="false" frequency="16000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/stm32f072.xml b/.idea/debugServers/stm32f072.xml
new file mode 100644
index 000000000..c56f5a8fb
--- /dev/null
+++ b/.idea/debugServers/stm32f072.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="stm32f072" uniqueID="f5c65701-0f8d-4923-a7ea-3ee2547147ae">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="STM32F072RB" reset-before="false" frequency="12000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/stm32f303.xml b/.idea/debugServers/stm32f303.xml
new file mode 100644
index 000000000..84aafc1e3
--- /dev/null
+++ b/.idea/debugServers/stm32f303.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="stm32f303" uniqueID="1cdd63e5-1736-42be-bff3-4c48e1f169fa">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="STM32F303VC" reset-before="false" frequency="12000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/.idea/debugServers/stm32l053.xml b/.idea/debugServers/stm32l053.xml
new file mode 100644
index 000000000..5365189cc
--- /dev/null
+++ b/.idea/debugServers/stm32l053.xml
@@ -0,0 +1,13 @@
+<component name="DebugServers">
+ <jlink-debug-target name="stm32l053" uniqueID="51d156d7-86a6-4006-814a-ed14981d7b49">
+ <debugger version="1">
+ <debugger kind="GDB" isBundled="true" />
+ <env />
+ </debugger>
+ <gdbserver exe="/usr/bin/JLinkGDBServerCLExe" />
+ <console port="19021" />
+ <target device="STM32L053R8" reset-before="false" frequency="12000" />
+ <connection extended-remote="false" port="4444" warmup-ms="500" />
+ <swo />
+ </jlink-debug-target>
+</component> \ No newline at end of file
diff --git a/README.rst b/README.rst
index 178a084ce..a3863c375 100644
--- a/README.rst
+++ b/README.rst
@@ -1,7 +1,7 @@
TinyUSB
=======
-|Build Status| |CircleCI Status| |Documentation Status| |Static Analysis| |Fuzzing Status| |License|
+|Build Status| |CircleCI Status| |Documentation Status| |Static Analysis| |Fuzzing Status| |Membrowse| |License|
Sponsors
--------
@@ -101,10 +101,11 @@ If you have a special requirement, ``usbd_app_driver_get_cb()`` can be used to w
Host Stack
----------
-- Human Interface Device (HID): Keyboard, Mouse, Generic
-- Mass Storage Class (MSC)
- Communication Device Class: CDC-ACM
- Vendor serial over USB: FTDI, CP210x, CH34x, PL2303
+- Human Interface Device (HID): Keyboard, Mouse, Generic
+- Mass Storage Class (MSC)
+- Musical Instrument Digital Interface (MIDI)
- Hub with multiple-level support
Similar to the Device Stack, if you have a special requirement, ``usbh_app_driver_get_cb()`` can be used to write your own class driver without modifying the stack.
@@ -139,9 +140,10 @@ Supported CPUs
| | MAX32 650, 666, 690, | ✔ | | ✔ | musb | 1-dir ep |
| | MAX78002 | | | | | |
+--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+
-| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | Packet SRAM 512 |
+| Artery AT32 | F403a_407, F413 | ✔ | | | fsdev | 512 USB RAM |
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
-| | F415, F435_437, F423, F425 | ✔ | ✔ | | dwc2 | |
+| | F415, F435_437, F423, | ✔ | ✔ | | dwc2 | |
+| | F425, F45x | | | | | |
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
| | F402_F405 | ✔ | ✔ | ✔ | dwc2 | F405 is HS |
+--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+
@@ -225,25 +227,25 @@ Supported CPUs
+--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+
| ST STM32 | F0, F3, L0, L1, L5, WBx5 | ✔ | ✖ | ✖ | stm32_fsdev | |
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
-| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 512 |
+| | F1 | 102, 103 | ✔ | ✖ | ✖ | stm32_fsdev | 512 USB RAM |
| | +------------------------+--------+------+-----------+------------------------+--------------------+
| | | 105, 107 | ✔ | ✔ | ✖ | dwc2 | |
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
| | F2, F4, F7, H7, H7RS | ✔ | ✔ | ✔ | dwc2 | |
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
-| | C0, G0, H5, U3 | ✔ | ✔ | ✖ | stm32_fsdev | Packet SRAM 2KB |
+| | C0, G0, H5, U3 | ✔ | ✔ | ✖ | stm32_fsdev | 2KB USB RAM |
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
-| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB |
+| | G4 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM |
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
-| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB |
+| | L4 | 4x2, 4x3 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM |
| | +------------------------+--------+------+-----------+------------------------+--------------------+
| | | 4x5, 4x6, 4+ | ✔ | ✔ | ✖ | dwc2 | |
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
| | N6 | ✔ | ✔ | ✔ | dwc2 | |
| +-----------------------------+--------+------+-----------+------------------------+--------------------+
-| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | Packet SRAM 1KB |
+| | U0 | ✔ | ✖ | ✖ | stm32_fsdev | 1KB USB RAM |
| +----+------------------------+--------+------+-----------+------------------------+--------------------+
-| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | Packet SRAM 2KB |
+| | U5 | 535, 545 | ✔ | ✔ | ✖ | stm32_fsdev | 2KB USB RAM |
| | +------------------------+--------+------+-----------+------------------------+--------------------+
| | | 575, 585 | ✔ | ✔ | ✖ | dwc2 | |
| | +------------------------+--------+------+-----------+------------------------+--------------------+
@@ -292,6 +294,8 @@ The following tools are provided freely to support the development of the TinyUS
:target: https://github.com/hathach/tinyusb/actions/workflows/static_analysis.yml
.. |Fuzzing Status| image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/tinyusb.svg
:target: https://oss-fuzz-build-logs.storage.googleapis.com/index.html#tinyusb
+.. |Membrowse| image:: https://membrowse.com/badge.svg
+ :target: https://membrowse.com/public/hathach/tinyusb
.. |License| image:: https://img.shields.io/badge/license-MIT-brightgreen.svg
:target: https://opensource.org/licenses/MIT
diff --git a/docs/reference/boards.rst b/docs/reference/boards.rst
index 12da5c90b..f6dd3cd91 100644
--- a/docs/reference/boards.rst
+++ b/docs/reference/boards.rst
@@ -44,6 +44,9 @@ at_start_f423 AT-START-F423 at32f423 https:/
at_start_f425 AT-START-F425 at32f425 https://www.arterychip.com/en/product/AT32F425.jsp
at_start_f435 AT-START-F435 at32f435_437 https://www.arterychip.com/en/product/AT32F435.jsp
at_start_f437 AT-START-F437 at32f435_437 https://www.arterychip.com/en/product/AT32F437.jsp
+at_start_f455 AT-START-F455 at32f45x https://www.arterychip.com/en/product/AT32F455.jsp
+at_start_f456 AT-START-F456 at32f45x https://www.arterychip.com/en/product/AT32F456.jsp
+at_start_f457 AT-START-F457 at32f45x https://www.arterychip.com/en/product/AT32F457.jsp
========================= ============================= ============= ==================================================== ======
Bridgetek
@@ -289,6 +292,7 @@ stm32h723nucleo STM32 H723 Nucleo stm32h7 https://www.s
stm32h743eval STM32 H743 Eval stm32h7 https://www.st.com/en/evaluation-tools/stm32h743i-eval.html
stm32h743nucleo STM32 H743 Nucleo stm32h7 https://www.st.com/en/evaluation-tools/nucleo-h743zi.html
stm32h745disco STM32 H745 Discovery stm32h7 https://www.st.com/en/evaluation-tools/stm32h745i-disco.html
+stm32h747disco STM32 H747 Discovery stm32h7 https://www.st.com/en/evaluation-tools/stm32h747i-disco.html
stm32h750_weact STM32 H750 WeAct stm32h7 https://www.adafruit.com/product/5032
stm32h750bdk STM32 H750b Discovery Kit stm32h7 https://www.st.com/en/evaluation-tools/stm32h750b-dk.html
waveshare_openh743i Waveshare Open H743i stm32h7 https://www.waveshare.com/openh743i-c-standard.htm
@@ -330,6 +334,7 @@ Board Name Family URL
msp_exp430f5529lp MSP430F5529 LaunchPad msp430 https://www.ti.com/tool/MSP-EXP430F5529LP
msp_exp432e401y MSP432E401Y LaunchPad msp432e4 https://www.ti.com/tool/MSP-EXP432E401Y
ek_tm4c123gxl TM4C123G LaunchPad tm4c https://www.ti.com/tool/EK-TM4C123GXL
+ek_tm4c1294xl TM4C1294 LaunchPad tm4c https://www.ti.com/tool/EK-TM4C1294XL
================= ===================== ======== ========================================= ======
Tomu
diff --git a/docs/reference/dependencies.rst b/docs/reference/dependencies.rst
index de1603383..ce5f265d5 100644
--- a/docs/reference/dependencies.rst
+++ b/docs/reference/dependencies.rst
@@ -16,6 +16,7 @@ hw/mcu/artery/at32f415 https://github.com/ArteryTek/AT32F415_
hw/mcu/artery/at32f423 https://github.com/ArteryTek/AT32F423_Firmware_Library.git 2afa7f12852e57a9e8aab3a892c641e1a8635a18 at32f423
hw/mcu/artery/at32f425 https://github.com/ArteryTek/AT32F425_Firmware_Library.git 620233e1357d5c1b7e2bde6b9dd5196822b91817 at32f425
hw/mcu/artery/at32f435_437 https://github.com/ArteryTek/AT32F435_437_Firmware_Library.git 25439cc6650a8ae0345934e8707a5f38c7ae41f8 at32f435_437
+hw/mcu/artery/at32f45x https://github.com/ArteryTek/AT32F45x_Firmware_Library.git 3d4a1b38be8ebac292e2350ca53bc4bfa4430233 at32f45x
hw/mcu/bridgetek/ft9xx/ft90x-sdk https://github.com/BRTSG-FOSS/ft90x-sdk.git 91060164afe239fcb394122e8bf9eb24d3194eb1 brtmm90x
hw/mcu/broadcom https://github.com/adafruit/broadcom-peripherals.git 08370086080759ed54ac1136d62d2ad24c6fa267 broadcom_32bit broadcom_64bit
hw/mcu/gd/nuclei-sdk https://github.com/Nuclei-Software/nuclei-sdk.git 7eb7bfa9ea4fbeacfafe1d5f77d5a0e6ed3922e7 gd32vf103
diff --git a/examples/device/dfu/skip.txt b/examples/device/dfu/skip.txt
index 9dde06c30..79d3da9d2 100644
--- a/examples/device/dfu/skip.txt
+++ b/examples/device/dfu/skip.txt
@@ -1,3 +1,3 @@
-mcu:TM4C123
+mcu:TM4C
mcu:BCM2835
family:espressif
diff --git a/examples/device/mtp/src/mtp_fs_example.c b/examples/device/mtp/src/mtp_fs_example.c
index 7fd7db61b..60fc9f79e 100644
--- a/examples/device/mtp/src/mtp_fs_example.c
+++ b/examples/device/mtp/src/mtp_fs_example.c
@@ -557,7 +557,7 @@ static int32_t fs_send_object_info(tud_mtp_cb_data_t* cb_data) {
return MTP_RESP_INVALID_STORAGE_ID;
}
- if (obj_info->parent_object != 0) { // not root
+ if (obj_info->parent_object != 0 && obj_info->parent_object != 0xFFFFFFFFu) { // not root
fs_file_t* parent = fs_get_file(obj_info->parent_object);
if (parent == NULL || 0u == parent->association_type) {
return MTP_RESP_INVALID_PARENT_OBJECT;
diff --git a/examples/dual/host_info_to_device_cdc/src/main.c b/examples/dual/host_info_to_device_cdc/src/main.c
index 00d059b66..fffb54d58 100644
--- a/examples/dual/host_info_to_device_cdc/src/main.c
+++ b/examples/dual/host_info_to_device_cdc/src/main.c
@@ -246,10 +246,9 @@ static void print_device_info(uint8_t daddr, const tusb_desc_device_t* desc_devi
cdc_printf("Device %u: ID %04x:%04x SN ", daddr, desc_device->idVendor, desc_device->idProduct);
uint8_t xfer_result = tuh_descriptor_get_serial_string_sync(daddr, LANGUAGE_ID, serial, sizeof(serial));
if (XFER_RESULT_SUCCESS != xfer_result) {
- serial[0] = 'n';
- serial[1] = '/';
- serial[2] = 'a';
- serial[3] = 0;
+ serial[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * 1 + 2));
+ serial[1] = '0';
+ serial[2] = 0;
}
print_utf16(serial, TU_ARRAY_SIZE(serial));
cdc_printf("\r\n");
diff --git a/examples/host/device_info/src/main.c b/examples/host/device_info/src/main.c
index 5b914a2ee..ab617e989 100644
--- a/examples/host/device_info/src/main.c
+++ b/examples/host/device_info/src/main.c
@@ -130,11 +130,10 @@ void tuh_mount_cb(uint8_t daddr) {
}
if (XFER_RESULT_SUCCESS != xfer_result) {
uint16_t* serial = (uint16_t*)(uintptr_t) desc.serial;
- serial[0] = (uint16_t) ((TUSB_DESC_STRING << 8) | (2 * 3 + 2));
- serial[1] = 'n';
- serial[2] = '/';
- serial[3] = 'a';
- serial[4] = 0;
+
+ serial[0] = (uint16_t)((TUSB_DESC_STRING << 8) | (2 * 1 + 2));
+ serial[1] = '0'; // simply 0
+ serial[2] = 0;
}
print_utf16((uint16_t*)(uintptr_t) desc.serial, sizeof(desc.serial)/2);
printf("\r\n");
diff --git a/hw/bsp/BoardPresets.json b/hw/bsp/BoardPresets.json
index 440ef8733..fabbeed93 100644
--- a/hw/bsp/BoardPresets.json
+++ b/hw/bsp/BoardPresets.json
@@ -175,6 +175,10 @@
"inherits": "default"
},
{
+ "name": "ek_tm4c1294xl",
+ "inherits": "default"
+ },
+ {
"name": "f1c100s",
"inherits": "default"
},
@@ -719,6 +723,10 @@
"inherits": "default"
},
{
+ "name": "stm32h747disco",
+ "inherits": "default"
+ },
+ {
"name": "stm32h750_weact",
"inherits": "default"
},
@@ -1109,6 +1117,11 @@
"configurePreset": "ek_tm4c123gxl"
},
{
+ "name": "ek_tm4c1294xl",
+ "description": "Build preset for the ek_tm4c1294xl board",
+ "configurePreset": "ek_tm4c1294xl"
+ },
+ {
"name": "espressif_addax_1",
"description": "Build preset for the espressif_addax_1 board",
"configurePreset": "espressif_addax_1"
@@ -1834,6 +1847,11 @@
"configurePreset": "stm32h745disco"
},
{
+ "name": "stm32h747disco",
+ "description": "Build preset for the stm32h747disco board",
+ "configurePreset": "stm32h747disco"
+ },
+ {
"name": "stm32h750_weact",
"description": "Build preset for the stm32h750_weact board",
"configurePreset": "stm32h750_weact"
@@ -2543,6 +2561,19 @@
]
},
{
+ "name": "ek_tm4c1294xl",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "ek_tm4c1294xl"
+ },
+ {
+ "type": "build",
+ "name": "ek_tm4c1294xl"
+ }
+ ]
+ },
+ {
"name": "espressif_addax_1",
"steps": [
{
@@ -4428,6 +4459,19 @@
]
},
{
+ "name": "stm32h747disco",
+ "steps": [
+ {
+ "type": "configure",
+ "name": "stm32h747disco"
+ },
+ {
+ "type": "build",
+ "name": "stm32h747disco"
+ }
+ ]
+ },
+ {
"name": "stm32h750_weact",
"steps": [
{
diff --git a/hw/bsp/at32f45x/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/at32f45x/FreeRTOSConfig/FreeRTOSConfig.h
new file mode 100644
index 000000000..c5b89452e
--- /dev/null
+++ b/hw/bsp/at32f45x/FreeRTOSConfig/FreeRTOSConfig.h
@@ -0,0 +1,176 @@
+/*
+ * FreeRTOS Kernel V10.0.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * 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. If you wish to use our Amazon
+ * FreeRTOS name, please do so in a fair use way that does not cause confusion.
+ *
+ * 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.
+ *
+ * http://www.FreeRTOS.org
+ * http://aws.amazon.com/freertos
+ *
+ * 1 tab == 4 spaces!
+ */
+
+
+#ifndef FREERTOS_CONFIG_H
+#define FREERTOS_CONFIG_H
+
+/*-----------------------------------------------------------
+ * Application specific definitions.
+ *
+ * These definitions should be adjusted for your particular hardware and
+ * application requirements.
+ *
+ * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
+ * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE.
+ *
+ * See http://www.freertos.org/a00110.html.
+ *----------------------------------------------------------*/
+
+// skip if included from IAR assembler
+#ifndef __IASMARM__
+// Include MCU header
+ #include "at32f45x.h"
+#endif
+
+/* Cortex-M4 port configuration. */
+#define configENABLE_MPU 0
+#define configENABLE_FPU 1
+#define configENABLE_TRUSTZONE 0
+#define configMINIMAL_SECURE_STACK_SIZE ( 1024 )
+
+#define configUSE_PREEMPTION 1
+#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
+#define configCPU_CLOCK_HZ system_core_clock
+#define configTICK_RATE_HZ ( 1000 )
+#define configMAX_PRIORITIES ( 5 )
+#define configMINIMAL_STACK_SIZE ( 128 )
+#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION*4*1024 )
+#define configMAX_TASK_NAME_LEN 16
+#define configUSE_16_BIT_TICKS 0
+#define configIDLE_SHOULD_YIELD 1
+#define configUSE_MUTEXES 1
+#define configUSE_RECURSIVE_MUTEXES 1
+#define configUSE_COUNTING_SEMAPHORES 1
+#define configQUEUE_REGISTRY_SIZE 4
+#define configUSE_QUEUE_SETS 0
+#define configUSE_TIME_SLICING 0
+#define configUSE_NEWLIB_REENTRANT 0
+#define configENABLE_BACKWARD_COMPATIBILITY 1
+#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
+
+#define configSUPPORT_STATIC_ALLOCATION 1
+#define configSUPPORT_DYNAMIC_ALLOCATION 0
+
+/* Hook function related definitions. */
+#define configUSE_IDLE_HOOK 0
+#define configUSE_TICK_HOOK 0
+#define configUSE_MALLOC_FAILED_HOOK 0 // cause nested extern warning
+#define configCHECK_FOR_STACK_OVERFLOW 2
+#define configCHECK_HANDLER_INSTALLATION 0
+
+/* Run time and task stats gathering related definitions. */
+#define configGENERATE_RUN_TIME_STATS 0
+#define configUSE_TRACE_FACILITY 1 // legacy trace
+#define configUSE_STATS_FORMATTING_FUNCTIONS 0
+
+/* Co-routine definitions. */
+#define configUSE_CO_ROUTINES 0
+#define configMAX_CO_ROUTINE_PRIORITIES 2
+
+/* Software timer related definitions. */
+#define configUSE_TIMERS 1
+#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-2)
+#define configTIMER_QUEUE_LENGTH 32
+#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
+
+/* Optional functions - most linkers will remove unused functions anyway. */
+#define INCLUDE_vTaskPrioritySet 0
+#define INCLUDE_uxTaskPriorityGet 0
+#define INCLUDE_vTaskDelete 0
+#define INCLUDE_vTaskSuspend 1 // required for queue, semaphore, mutex to be blocked indefinitely with portMAX_DELAY
+#define INCLUDE_xResumeFromISR 0
+#define INCLUDE_vTaskDelayUntil 1
+#define INCLUDE_vTaskDelay 1
+#define INCLUDE_xTaskGetSchedulerState 0
+#define INCLUDE_xTaskGetCurrentTaskHandle 1
+#define INCLUDE_uxTaskGetStackHighWaterMark 0
+#define INCLUDE_xTaskGetIdleTaskHandle 0
+#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
+#define INCLUDE_pcTaskGetTaskName 0
+#define INCLUDE_eTaskGetState 0
+#define INCLUDE_xEventGroupSetBitFromISR 0
+#define INCLUDE_xTimerPendFunctionCall 0
+
+#ifdef __RX__
+/* Renesas RX series */
+#define vSoftwareInterruptISR INT_Excep_ICU_SWINT
+#define vTickISR INT_Excep_CMT0_CMI0
+#define configPERIPHERAL_CLOCK_HZ (configCPU_CLOCK_HZ/2)
+#define configKERNEL_INTERRUPT_PRIORITY 1
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY 4
+
+#else
+
+/* FreeRTOS hooks to NVIC vectors */
+#define xPortPendSVHandler PendSV_Handler
+#define xPortSysTickHandler SysTick_Handler
+#define vPortSVCHandler SVC_Handler
+
+//--------------------------------------------------------------------+
+// Interrupt nesting behavior configuration.
+//--------------------------------------------------------------------+
+#if defined(__NVIC_PRIO_BITS)
+ // For Cortex-M specific: __NVIC_PRIO_BITS is defined in core_cmx.h
+ #define configPRIO_BITS __NVIC_PRIO_BITS
+
+#elif defined(__ECLIC_INTCTLBITS)
+ // RISC-V Bumblebee core from nuclei
+ #define configPRIO_BITS __ECLIC_INTCTLBITS
+
+#elif defined(__IASMARM__)
+ // FIXME: IAR Assembler cannot include mcu header directly to get __NVIC_PRIO_BITS.
+ // Therefore we will hard coded it to minimum value of 2 to get pass ci build.
+ // IAR user must update this to correct value of the target MCU
+ #message "configPRIO_BITS is hard coded to 2 to pass IAR build only. User should update it per MCU"
+ #define configPRIO_BITS 2
+
+#else
+ #error "FreeRTOS configPRIO_BITS to be defined"
+#endif
+
+/* The lowest interrupt priority that can be used in a call to a "set priority" function. */
+#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ((1<<configPRIO_BITS) - 1)
+
+/* The highest interrupt priority that can be used by any interrupt service
+routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL
+INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
+PRIORITY THAN THIS! (higher priorities are lower numeric values. */
+#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
+
+/* Interrupt priorities used by the kernel port layer itself. These are generic
+to all Cortex-M ports, and do not rely on any particular library functions. */
+#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
+/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
+See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
+#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
+
+#endif
+
+#endif /* __FREERTOS_CONFIG__H */
diff --git a/hw/bsp/at32f45x/at32f45x_clock.c b/hw/bsp/at32f45x/at32f45x_clock.c
new file mode 100644
index 000000000..a66a8b1aa
--- /dev/null
+++ b/hw/bsp/at32f45x/at32f45x_clock.c
@@ -0,0 +1,114 @@
+/**
+ **************************************************************************
+ * @file at32f45x_clock.c
+ * @brief system clock config program
+ **************************************************************************
+ *
+ * Copyright (c) 2025, Artery Technology, All rights reserved.
+ *
+ * The software Board Support Package (BSP) that is made available to
+ * download from Artery official website is the copyrighted work of Artery.
+ * Artery authorizes customers to use, copy, and distribute the BSP
+ * software and its related documentation for the purpose of design and
+ * development in conjunction with Artery microcontrollers. Use of the
+ * software is governed by this copyright notice and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
+ * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
+ * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
+ * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
+ * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ *
+ **************************************************************************
+ */
+
+/* includes ------------------------------------------------------------------*/
+#include "at32f45x_clock.h"
+
+/**
+ * @brief system clock config program
+ * @note the system clock is configured as follow:
+ * - system clock = (hext * pll_ns)/(pll_ms * pll_fp)
+ * - system clock source = pll (hext)
+ * - hext = 8000000
+ * - sclk = 192000000
+ * - ahbdiv = 1
+ * - ahbclk = 192000000
+ * - apb2div = 1
+ * - apb2clk = 192000000
+ * - apb1div = 1
+ * - apb1clk = 192000000
+ * - pll_ns = 96
+ * - pll_ms = 1
+ * - pll_fp = 4
+ * @param none
+ * @retval none
+ */
+void system_clock_config(void)
+{
+ /* reset crm */
+ crm_reset();
+
+ /* set the flash clock divider */
+ flash_psr_set(FLASH_WAIT_CYCLE_5);
+
+ /* enable pwc periph clock */
+ crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
+
+ /* config ldo voltage */
+ pwc_ldo_output_voltage_set(PWC_LDO_OUTPUT_1V3);
+
+ crm_clock_source_enable(CRM_CLOCK_SOURCE_HEXT, TRUE);
+
+ /* wait till hext is ready */
+ while(crm_hext_stable_wait() == ERROR)
+ {
+ }
+
+ /* config pll clock resource */
+ crm_pll_config(CRM_PLL_SOURCE_HEXT, 96, 1, CRM_PLL_FP_4);
+
+ /* config pllu divider */
+ crm_pllu_div_set(CRM_PLL_FU_16);
+
+ /* pllu enable */
+ crm_pllu_output_set(TRUE);
+
+ /* enable pll */
+ crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);
+
+ /* wait till pll is ready */
+ while(crm_flag_get(CRM_PLL_STABLE_FLAG) != SET)
+ {
+ }
+
+ /* config ahbclk */
+ crm_ahb_div_set(CRM_AHB_DIV_1);
+
+ /* config apb3clk, the maximum frequency of APB3 clock is 90 MHz */
+ crm_apb3_div_set(CRM_APB3_DIV_4);
+
+ /* config apb2clk, the maximum frequency of APB2 clock is 192 MHz */
+ crm_apb2_div_set(CRM_APB2_DIV_1);
+
+ /* config apb1clk, the maximum frequency of APB1 clock is 192 MHz */
+ crm_apb1_div_set(CRM_APB1_DIV_1);
+
+ /* enable auto step mode */
+ crm_auto_step_mode_enable(TRUE);
+
+ /* select pll as system clock source */
+ crm_sysclk_switch(CRM_SCLK_PLL);
+
+ /* wait till pll is used as system clock source */
+ while(crm_sysclk_switch_status_get() != CRM_SCLK_PLL)
+ {
+ }
+
+ /* disable auto step mode */
+ crm_auto_step_mode_enable(FALSE);
+
+ /* update system_core_clock global variable */
+ system_core_clock_update();
+}
diff --git a/hw/bsp/at32f45x/at32f45x_clock.h b/hw/bsp/at32f45x/at32f45x_clock.h
new file mode 100644
index 000000000..a372a605b
--- /dev/null
+++ b/hw/bsp/at32f45x/at32f45x_clock.h
@@ -0,0 +1,44 @@
+/**
+ **************************************************************************
+ * @file at32f45x_clock.h
+ * @brief header file of clock program
+ **************************************************************************
+ *
+ * Copyright (c) 2025, Artery Technology, All rights reserved.
+ *
+ * The software Board Support Package (BSP) that is made available to
+ * download from Artery official website is the copyrighted work of Artery.
+ * Artery authorizes customers to use, copy, and distribute the BSP
+ * software and its related documentation for the purpose of design and
+ * development in conjunction with Artery microcontrollers. Use of the
+ * software is governed by this copyright notice and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
+ * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
+ * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
+ * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
+ * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ *
+ **************************************************************************
+ */
+
+/* define to prevent recursive inclusion -------------------------------------*/
+#ifndef __AT32F45x_CLOCK_H
+#define __AT32F45x_CLOCK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* includes ------------------------------------------------------------------*/
+#include "at32f45x.h"
+
+/* exported functions ------------------------------------------------------- */
+void system_clock_config(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/bsp/at32f45x/at32f45x_conf.h b/hw/bsp/at32f45x/at32f45x_conf.h
new file mode 100644
index 000000000..90182437f
--- /dev/null
+++ b/hw/bsp/at32f45x/at32f45x_conf.h
@@ -0,0 +1,174 @@
+/**
+ **************************************************************************
+ * @file at32f45x_conf.h
+ * @brief at32f45x config header file
+ **************************************************************************
+ *
+ * Copyright (c) 2025, Artery Technology, All rights reserved.
+ *
+ * The software Board Support Package (BSP) that is made available to
+ * download from Artery official website is the copyrighted work of Artery.
+ * Artery authorizes customers to use, copy, and distribute the BSP
+ * software and its related documentation for the purpose of design and
+ * development in conjunction with Artery microcontrollers. Use of the
+ * software is governed by this copyright notice and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
+ * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
+ * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
+ * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
+ * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ *
+ **************************************************************************
+ */
+
+/* define to prevent recursive inclusion -------------------------------------*/
+#ifndef __AT32F45x_CONF_H
+#define __AT32F45x_CONF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief in the following line adjust the value of high speed external crystal (hext)
+ * used in your application
+ *
+ * tip: to avoid modifying this file each time you need to use different hext, you
+ * can define the hext value in your toolchain compiler preprocessor.
+ *
+ */
+#if !defined HEXT_VALUE
+#define HEXT_VALUE ((uint32_t)8000000) /*!< value of the high speed external crystal in hz */
+#endif
+
+/**
+ * @brief in the following line adjust the high speed external crystal (hext) startup
+ * timeout value
+ */
+#define HEXT_STARTUP_TIMEOUT ((uint16_t)0x3000) /*!< time out for hext start up */
+#define HICK_VALUE ((uint32_t)8000000) /*!< value of the high speed internal clock in hz */
+#define LEXT_VALUE ((uint32_t)32768) /*!< value of the low speed external clock in hz */
+
+/* module define -------------------------------------------------------------*/
+#define ACC_MODULE_ENABLED
+#define ADC_MODULE_ENABLED
+#define AES_MODULE_ENABLED
+#define CAN_MODULE_ENABLED
+#define CRC_MODULE_ENABLED
+#define CRM_MODULE_ENABLED
+#define DAC_MODULE_ENABLED
+#define DEBUG_MODULE_ENABLED
+#define DMA_MODULE_ENABLED
+#define EMAC_MODULE_ENABLED
+#define ERTC_MODULE_ENABLED
+#define EXINT_MODULE_ENABLED
+#define FLASH_MODULE_ENABLED
+#define GPIO_MODULE_ENABLED
+#define I2C_MODULE_ENABLED
+#define MISC_MODULE_ENABLED
+#define PWC_MODULE_ENABLED
+#define QSPI_MODULE_ENABLED
+#define SCFG_MODULE_ENABLED
+#define SDIO_MODULE_ENABLED
+#define SPI_MODULE_ENABLED
+#define TMR_MODULE_ENABLED
+#define TRNG_MODULE_ENABLED
+#define USART_MODULE_ENABLED
+#define USB_MODULE_ENABLED
+#define WWDT_MODULE_ENABLED
+#define WDT_MODULE_ENABLED
+#define XMC_MODULE_ENABLED
+
+/* includes ------------------------------------------------------------------*/
+#ifdef ACC_MODULE_ENABLED
+#include "at32f45x_acc.h"
+#endif
+#ifdef ADC_MODULE_ENABLED
+#include "at32f45x_adc.h"
+#endif
+#ifdef AES_MODULE_ENABLED
+#include "at32f45x_aes.h"
+#endif
+#ifdef CAN_MODULE_ENABLED
+#include "at32f45x_can.h"
+#endif
+#ifdef CRC_MODULE_ENABLED
+#include "at32f45x_crc.h"
+#endif
+#ifdef CRM_MODULE_ENABLED
+#include "at32f45x_crm.h"
+#endif
+#ifdef DAC_MODULE_ENABLED
+#include "at32f45x_dac.h"
+#endif
+#ifdef DEBUG_MODULE_ENABLED
+#include "at32f45x_debug.h"
+#endif
+#ifdef DMA_MODULE_ENABLED
+#include "at32f45x_dma.h"
+#endif
+#ifdef EMAC_MODULE_ENABLED
+#include "at32f45x_emac.h"
+#endif
+#ifdef ERTC_MODULE_ENABLED
+#include "at32f45x_ertc.h"
+#endif
+#ifdef EXINT_MODULE_ENABLED
+#include "at32f45x_exint.h"
+#endif
+#ifdef FLASH_MODULE_ENABLED
+#include "at32f45x_flash.h"
+#endif
+#ifdef GPIO_MODULE_ENABLED
+#include "at32f45x_gpio.h"
+#endif
+#ifdef I2C_MODULE_ENABLED
+#include "at32f45x_i2c.h"
+#endif
+#ifdef MISC_MODULE_ENABLED
+#include "at32f45x_misc.h"
+#endif
+#ifdef PWC_MODULE_ENABLED
+#include "at32f45x_pwc.h"
+#endif
+#ifdef QSPI_MODULE_ENABLED
+#include "at32f45x_qspi.h"
+#endif
+#ifdef SCFG_MODULE_ENABLED
+#include "at32f45x_scfg.h"
+#endif
+#ifdef SDIO_MODULE_ENABLED
+#include "at32f45x_sdio.h"
+#endif
+#ifdef SPI_MODULE_ENABLED
+#include "at32f45x_spi.h"
+#endif
+#ifdef TMR_MODULE_ENABLED
+#include "at32f45x_tmr.h"
+#endif
+#ifdef TRNG_MODULE_ENABLED
+#include "at32f45x_trng.h"
+#endif
+#ifdef USART_MODULE_ENABLED
+#include "at32f45x_usart.h"
+#endif
+#ifdef USB_MODULE_ENABLED
+#include "at32f45x_usb.h"
+#endif
+#ifdef WDT_MODULE_ENABLED
+#include "at32f45x_wdt.h"
+#endif
+#ifdef WWDT_MODULE_ENABLED
+#include "at32f45x_wwdt.h"
+#endif
+#ifdef XMC_MODULE_ENABLED
+#include "at32f45x_xmc.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/bsp/at32f45x/at32f45x_int.c b/hw/bsp/at32f45x/at32f45x_int.c
new file mode 100644
index 000000000..b3ba6ad9c
--- /dev/null
+++ b/hw/bsp/at32f45x/at32f45x_int.c
@@ -0,0 +1,100 @@
+/**
+ **************************************************************************
+ * @file at32f45x_int.c
+ * @brief main interrupt service routines.
+ **************************************************************************
+ *
+ * Copyright (c) 2025, Artery Technology, All rights reserved.
+ *
+ * The software Board Support Package (BSP) that is made available to
+ * download from Artery official website is the copyrighted work of Artery.
+ * Artery authorizes customers to use, copy, and distribute the BSP
+ * software and its related documentation for the purpose of design and
+ * development in conjunction with Artery microcontrollers. Use of the
+ * software is governed by this copyright notice and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
+ * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
+ * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
+ * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
+ * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ *
+ **************************************************************************
+ */
+
+/* includes ------------------------------------------------------------------*/
+#include "at32f45x_int.h"
+
+/** @addtogroup AT32F45X_BSP
+ * @{
+ */
+
+/** @addtogroup AT32F45X_USB_Device_Keyboard
+ * @{
+ */
+
+/**
+ * @brief this function handles nmi exception.
+ * @param none
+ * @retval none
+ */
+void NMI_Handler(void)
+{
+}
+
+/**
+ * @brief this function handles memory manage exception.
+ * @param none
+ * @retval none
+ */
+void MemManage_Handler(void)
+{
+ /* go to infinite loop when memory manage exception occurs */
+ while(1)
+ {
+ }
+}
+
+/**
+ * @brief this function handles bus fault exception.
+ * @param none
+ * @retval none
+ */
+void BusFault_Handler(void)
+{
+ /* go to infinite loop when bus fault exception occurs */
+ while(1)
+ {
+ }
+}
+
+/**
+ * @brief this function handles usage fault exception.
+ * @param none
+ * @retval none
+ */
+void UsageFault_Handler(void)
+{
+ /* go to infinite loop when usage fault exception occurs */
+ while(1)
+ {
+ }
+}
+
+/**
+ * @brief this function handles debug monitor exception.
+ * @param none
+ * @retval none
+ */
+void DebugMon_Handler(void)
+{
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/hw/bsp/at32f45x/at32f45x_int.h b/hw/bsp/at32f45x/at32f45x_int.h
new file mode 100644
index 000000000..3a2667e9d
--- /dev/null
+++ b/hw/bsp/at32f45x/at32f45x_int.h
@@ -0,0 +1,59 @@
+/**
+ **************************************************************************
+ * @file at32f45x_int.h
+ * @brief header file of main interrupt service routines.
+ **************************************************************************
+ *
+ * Copyright (c) 2025, Artery Technology, All rights reserved.
+ *
+ * The software Board Support Package (BSP) that is made available to
+ * download from Artery official website is the copyrighted work of Artery.
+ * Artery authorizes customers to use, copy, and distribute the BSP
+ * software and its related documentation for the purpose of design and
+ * development in conjunction with Artery microcontrollers. Use of the
+ * software is governed by this copyright notice and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
+ * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
+ * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
+ * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
+ * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
+ *
+ **************************************************************************
+ */
+
+/* define to prevent recursive inclusion -------------------------------------*/
+#ifndef __AT32F45x_INT_H
+#define __AT32F45x_INT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* includes ------------------------------------------------------------------*/
+#include "at32f45x.h"
+
+/* exported types ------------------------------------------------------------*/
+/* exported constants --------------------------------------------------------*/
+/* exported macro ------------------------------------------------------------*/
+/* exported functions ------------------------------------------------------- */
+
+void NMI_Handler(void);
+void HardFault_Handler(void);
+void MemManage_Handler(void);
+void BusFault_Handler(void);
+void UsageFault_Handler(void);
+void SVC_Handler(void);
+void DebugMon_Handler(void);
+void PendSV_Handler(void);
+void SysTick_Handler(void);
+
+void OTGFS1_IRQHandler(void);
+void OTGFS1_WKUP_IRQHandler(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/bsp/at32f45x/boards/at_start_f455/board.cmake b/hw/bsp/at32f45x/boards/at_start_f455/board.cmake
new file mode 100644
index 000000000..f06f9599e
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f455/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT AT32F455ZET7)
+set(MCU_LINKER_NAME AT32F455xE)
+
+set(JLINK_DEVICE ${MCU_VARIANT})
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT})
+endfunction()
diff --git a/hw/bsp/at32f45x/boards/at_start_f455/board.h b/hw/bsp/at32f45x/boards/at_start_f455/board.h
new file mode 100644
index 000000000..64e27c016
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f455/board.h
@@ -0,0 +1,96 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * 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.
+ */
+
+/* metadata:
+ name: AT-START-F455
+ url: https://www.arterychip.com/en/product/AT32F455.jsp
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define USB_VBUS_IGNORE
+
+// LED
+#define LED_PORT GPIOD
+#define LED_PIN GPIO_PINS_13
+#define LED_STATE_ON 0 // Active Low
+#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE)
+
+// Button
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PINS_0
+#define BUTTON_STATE_ACTIVE 1
+#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
+
+// UART
+#define PRINT_UART USART1
+#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN GPIO_PINS_9
+#define PRINT_UART_TX_GPIO GPIOA
+#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9
+#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7
+
+//USB
+#define USB_ID 0
+#define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK
+#define OTG_IRQ OTGFS1_IRQn
+#define OTG_IRQ_HANDLER OTGFS1_IRQHandler
+#define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn
+#define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler
+#define OTG_WKUP_EXINT_LINE EXINT_LINE_18
+#define OTG_PIN_GPIO GPIOA
+#define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
+#define OTG_PIN_DP GPIO_PINS_12
+#define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE12
+#define OTG_PIN_DM GPIO_PINS_11
+#define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE11
+#define OTG_PIN_VBUS GPIO_PINS_9
+#define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9
+#define OTG_PIN_ID GPIO_PINS_10
+#define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10
+#define OTG_PIN_SOF_GPIO GPIOA
+#define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
+#define OTG_PIN_SOF GPIO_PINS_8
+#define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8
+#define OTG_PIN_MUX GPIO_MUX_10
+
+//Vbus
+static inline void board_vbus_sense_init(void)
+{
+ *(int*)(0x50000038) |= (1<<21);
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/at32f45x/boards/at_start_f455/board.mk b/hw/bsp/at32f45x/boards/at_start_f455/board.mk
new file mode 100644
index 000000000..7c24ad288
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f455/board.mk
@@ -0,0 +1,7 @@
+MCU_VARIANT = AT32F455ZET7
+MCU_LINKER_NAME = AT32F455xE
+
+JLINK_DEVICE = ${MCU_VARIANT}
+
+CFLAGS += \
+ -D${MCU_VARIANT}
diff --git a/hw/bsp/at32f45x/boards/at_start_f456/board.cmake b/hw/bsp/at32f45x/boards/at_start_f456/board.cmake
new file mode 100644
index 000000000..a5048d3b1
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f456/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT AT32F456ZET7)
+set(MCU_LINKER_NAME AT32F456xE)
+
+set(JLINK_DEVICE ${MCU_VARIANT})
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT})
+endfunction()
diff --git a/hw/bsp/at32f45x/boards/at_start_f456/board.h b/hw/bsp/at32f45x/boards/at_start_f456/board.h
new file mode 100644
index 000000000..d3d734a9b
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f456/board.h
@@ -0,0 +1,96 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * 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.
+ */
+
+/* metadata:
+ name: AT-START-F456
+ url: https://www.arterychip.com/en/product/AT32F456.jsp
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define USB_VBUS_IGNORE
+
+// LED
+#define LED_PORT GPIOD
+#define LED_PIN GPIO_PINS_13
+#define LED_STATE_ON 0 // Active Low
+#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE)
+
+// Button
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PINS_0
+#define BUTTON_STATE_ACTIVE 1
+#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
+
+// UART
+#define PRINT_UART USART1
+#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN GPIO_PINS_9
+#define PRINT_UART_TX_GPIO GPIOA
+#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9
+#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7
+
+//USB
+#define USB_ID 0
+#define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK
+#define OTG_IRQ OTGFS1_IRQn
+#define OTG_IRQ_HANDLER OTGFS1_IRQHandler
+#define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn
+#define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler
+#define OTG_WKUP_EXINT_LINE EXINT_LINE_18
+#define OTG_PIN_GPIO GPIOA
+#define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
+#define OTG_PIN_DP GPIO_PINS_12
+#define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE12
+#define OTG_PIN_DM GPIO_PINS_11
+#define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE11
+#define OTG_PIN_VBUS GPIO_PINS_9
+#define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9
+#define OTG_PIN_ID GPIO_PINS_10
+#define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10
+#define OTG_PIN_SOF_GPIO GPIOA
+#define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
+#define OTG_PIN_SOF GPIO_PINS_8
+#define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8
+#define OTG_PIN_MUX GPIO_MUX_10
+
+//Vbus
+static inline void board_vbus_sense_init(void)
+{
+ *(int*)(0x50000038) |= (1<<21);
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/at32f45x/boards/at_start_f456/board.mk b/hw/bsp/at32f45x/boards/at_start_f456/board.mk
new file mode 100644
index 000000000..596d99d61
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f456/board.mk
@@ -0,0 +1,7 @@
+MCU_VARIANT = AT32F456ZET7
+MCU_LINKER_NAME = AT32F456xE
+
+JLINK_DEVICE = ${MCU_VARIANT}
+
+CFLAGS += \
+ -D${MCU_VARIANT}
diff --git a/hw/bsp/at32f45x/boards/at_start_f457/board.cmake b/hw/bsp/at32f45x/boards/at_start_f457/board.cmake
new file mode 100644
index 000000000..c8cd886be
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f457/board.cmake
@@ -0,0 +1,8 @@
+set(MCU_VARIANT AT32F457ZET7)
+set(MCU_LINKER_NAME AT32F457xE)
+
+set(JLINK_DEVICE ${MCU_VARIANT})
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC ${MCU_VARIANT})
+endfunction()
diff --git a/hw/bsp/at32f45x/boards/at_start_f457/board.h b/hw/bsp/at32f45x/boards/at_start_f457/board.h
new file mode 100644
index 000000000..2216b1ed3
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f457/board.h
@@ -0,0 +1,96 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020, Ha Thach (tinyusb.org)
+ *
+ * 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.
+ */
+
+/* metadata:
+ name: AT-START-F457
+ url: https://www.arterychip.com/en/product/AT32F457.jsp
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define USB_VBUS_IGNORE
+
+// LED
+#define LED_PORT GPIOD
+#define LED_PIN GPIO_PINS_13
+#define LED_STATE_ON 0 // Active Low
+#define LED_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE)
+
+// Button
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PINS_0
+#define BUTTON_STATE_ACTIVE 1
+#define BUTTON_GPIO_CLK_EN() crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE)
+
+// UART
+#define PRINT_UART USART1
+#define PRINT_UART_CRM_CLK CRM_USART1_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN GPIO_PINS_9
+#define PRINT_UART_TX_GPIO GPIOA
+#define PRINT_UART_TX_GPIO_CRM_CLK CRM_GPIOA_PERIPH_CLOCK
+#define PRINT_UART_TX_PIN_SOURCE GPIO_PINS_SOURCE9
+#define PRINT_UART_TX_PIN_MUX_NUM GPIO_MUX_7
+
+//USB
+#define USB_ID 0
+#define OTG_CLOCK CRM_OTGFS1_PERIPH_CLOCK
+#define OTG_IRQ OTGFS1_IRQn
+#define OTG_IRQ_HANDLER OTGFS1_IRQHandler
+#define OTG_WKUP_IRQ OTGFS1_WKUP_IRQn
+#define OTG_WKUP_HANDLER OTGFS1_WKUP_IRQHandler
+#define OTG_WKUP_EXINT_LINE EXINT_LINE_18
+#define OTG_PIN_GPIO GPIOA
+#define OTG_PIN_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
+#define OTG_PIN_DP GPIO_PINS_12
+#define OTG_PIN_DP_SOURCE GPIO_PINS_SOURCE12
+#define OTG_PIN_DM GPIO_PINS_11
+#define OTG_PIN_DM_SOURCE GPIO_PINS_SOURCE11
+#define OTG_PIN_VBUS GPIO_PINS_9
+#define OTG_PIN_VBUS_SOURCE GPIO_PINS_SOURCE9
+#define OTG_PIN_ID GPIO_PINS_10
+#define OTG_PIN_ID_SOURCE GPIO_PINS_SOURCE10
+#define OTG_PIN_SOF_GPIO GPIOA
+#define OTG_PIN_SOF_GPIO_CLOCK CRM_GPIOA_PERIPH_CLOCK
+#define OTG_PIN_SOF GPIO_PINS_8
+#define OTG_PIN_SOF_SOURCE GPIO_PINS_SOURCE8
+#define OTG_PIN_MUX GPIO_MUX_10
+
+//Vbus
+static inline void board_vbus_sense_init(void)
+{
+ *(int*)(0x50000038) |= (1<<21);
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* BOARD_H_ */
diff --git a/hw/bsp/at32f45x/boards/at_start_f457/board.mk b/hw/bsp/at32f45x/boards/at_start_f457/board.mk
new file mode 100644
index 000000000..4cb4adad5
--- /dev/null
+++ b/hw/bsp/at32f45x/boards/at_start_f457/board.mk
@@ -0,0 +1,7 @@
+MCU_VARIANT = AT32F457ZET7
+MCU_LINKER_NAME = AT32F457xE
+
+JLINK_DEVICE = ${MCU_VARIANT}
+
+CFLAGS += \
+ -D${MCU_VARIANT}
diff --git a/hw/bsp/at32f45x/family.c b/hw/bsp/at32f45x/family.c
new file mode 100644
index 000000000..0593e5115
--- /dev/null
+++ b/hw/bsp/at32f45x/family.c
@@ -0,0 +1,258 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * 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.
+ */
+
+/* metadata:
+ manufacturer: Artery
+*/
+
+#include "at32f45x_clock.h"
+#include "at32f45x_int.h"
+#include "board.h"
+#include "bsp/board_api.h"
+
+void usb_clock48m_select(usb_clk48_s clk_s);
+void led_and_button_init(void);
+void uart_print_init(uint32_t baudrate);
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+void OTGFS1_IRQHandler(void) {
+ tusb_int_handler(0, true);
+}
+void OTGFS1_WKUP_IRQHandler(void) {
+ tusb_int_handler(0, true);
+}
+
+void board_init(void) {
+ /* config nvic priority group */
+ nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
+
+ /* config system clock */
+ system_clock_config();
+
+ /* enable usb clock */
+ crm_periph_clock_enable(OTG_CLOCK, TRUE);
+
+ /* select usb 48m clcok source */
+ usb_clock48m_select(USB_CLK_HEXT);
+
+ /* vbus ignore */
+ board_vbus_sense_init();
+
+ /* configure systick */
+ systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV);
+ SysTick_Config(system_core_clock / 1000);
+#if CFG_TUSB_OS == OPT_OS_FREERTOS
+ // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher )
+ NVIC_SetPriority(OTG_IRQ, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+#endif
+
+/* otgfs use vbus pin */
+#ifndef USB_VBUS_IGNORE
+ gpio_init_type gpio_init_struct;
+ crm_periph_clock_enable(OTG_PIN_GPIO_CLOCK, TRUE);
+ gpio_default_para_init(&gpio_init_struct);
+ gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+ gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+ gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
+ gpio_init_struct.gpio_pins = OTG_PIN_VBUS;
+ gpio_init_struct.gpio_pull = GPIO_PULL_DOWN;
+ gpio_pin_mux_config(OTG_PIN_GPIO, OTG_PIN_VBUS_SOURCE, OTG_PIN_MUX);
+ gpio_init(OTG_PIN_GPIO, &gpio_init_struct);
+#endif
+
+ /* config led and key */
+ led_and_button_init();
+
+ /* config usart printf */
+ uart_print_init(115200);
+ printf("usart printf config success!\r\n");
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+/**
+ * @brief usb 48M clock select
+ * @param clk_s:USB_CLK_HICK, USB_CLK_HEXT
+ * @retval none
+ */
+void usb_clock48m_select(usb_clk48_s clk_s)
+{
+ if(clk_s == USB_CLK_HICK)
+ {
+ crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_HICK);
+
+ /* enable the acc calibration ready interrupt */
+ crm_periph_clock_enable(CRM_ACC_PERIPH_CLOCK, TRUE);
+
+ /* update the c1\c2\c3 value */
+ acc_write_c1(7980);
+ acc_write_c2(8000);
+ acc_write_c3(8020);
+
+ /* open acc calibration */
+ acc_calibration_mode_enable(ACC_CAL_HICKTRIM, TRUE);
+ }
+ else
+ {
+ crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_PLLU);
+ }
+}
+
+void uart_print_init(uint32_t baudrate) {
+ gpio_init_type gpio_init_struct;
+ /* enable the uart and gpio clock */
+ crm_periph_clock_enable(PRINT_UART_CRM_CLK, TRUE);
+ crm_periph_clock_enable(PRINT_UART_TX_GPIO_CRM_CLK, TRUE);
+ gpio_default_para_init(&gpio_init_struct);
+ /* configure the uart tx pin */
+ gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+ gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+ gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
+ gpio_init_struct.gpio_pins = PRINT_UART_TX_PIN;
+ gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
+ gpio_init(PRINT_UART_TX_GPIO, &gpio_init_struct);
+ gpio_pin_mux_config(PRINT_UART_TX_GPIO, PRINT_UART_TX_PIN_SOURCE, PRINT_UART_TX_PIN_MUX_NUM);
+ /* configure uart param */
+ usart_init(PRINT_UART, baudrate, USART_DATA_8BITS, USART_STOP_1_BIT);
+ usart_transmitter_enable(PRINT_UART, TRUE);
+ usart_enable(PRINT_UART, TRUE);
+}
+
+void led_and_button_init(void) {
+ /* LED */
+ gpio_init_type gpio_led_init_struct;
+ /* enable the led clock */
+ LED_GPIO_CLK_EN();
+ /* set default parameter */
+ gpio_default_para_init(&gpio_led_init_struct);
+ /* configure the led gpio */
+ gpio_led_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+ gpio_led_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+ gpio_led_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
+ gpio_led_init_struct.gpio_pins = LED_PIN;
+ gpio_led_init_struct.gpio_pull = GPIO_PULL_NONE;
+ gpio_init(LED_PORT, &gpio_led_init_struct);
+ /* Button */
+ gpio_init_type gpio_button_init_struct;
+ /* enable the button clock */
+ BUTTON_GPIO_CLK_EN();
+ /* set default parameter */
+ gpio_default_para_init(&gpio_button_init_struct);
+ /* configure the button gpio */
+ gpio_button_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+ gpio_button_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+ gpio_button_init_struct.gpio_mode = GPIO_MODE_INPUT;
+ gpio_button_init_struct.gpio_pins = BUTTON_PIN;
+ gpio_button_init_struct.gpio_pull = GPIO_PULL_DOWN;
+ gpio_init(BUTTON_PORT, &gpio_button_init_struct);
+}
+
+void board_led_write(bool state) {
+ gpio_bits_write(LED_PORT, LED_PIN, state ^ (!LED_STATE_ON));
+}
+
+uint32_t board_button_read(void) {
+ return gpio_input_data_bit_read(BUTTON_PORT, BUTTON_PIN);
+}
+
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ (void) max_len;
+ volatile uint32_t *at32_uuid = ((volatile uint32_t *) 0x1FFFF7E8);
+ uint32_t *id32 = (uint32_t *) (uintptr_t) id;
+ uint8_t const len = 12;
+
+ id32[0] = at32_uuid[0];
+ id32[1] = at32_uuid[1];
+ id32[2] = at32_uuid[2];
+
+ return len;
+}
+
+int board_uart_read(uint8_t *buf, int len) {
+ (void) buf;
+ (void) len;
+ return 0;
+}
+
+int board_uart_write(void const *buf, int len) {
+#if CFG_TUSB_OS == OPT_OS_NONE
+ int txsize = len;
+ uint16_t timeout = 0xffff;
+ while (txsize--) {
+ while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) {
+ timeout--;
+ if (timeout == 0) {
+ return 0;
+ }
+ }
+ PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF);
+ buf++;
+ }
+ return len;
+#else
+ (void) buf;
+ (void) len;
+ return 0;
+#endif
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+void SysTick_Handler(void) {
+ system_ticks++;
+}
+
+uint32_t board_millis(void) {
+ return system_ticks;
+}
+
+void SVC_Handler(void) {
+}
+
+void PendSV_Handler(void) {
+}
+#endif
+
+void HardFault_Handler(void) {
+ __asm("BKPT #0\n");
+}
+
+// Required by __libc_init_array in startup code if we are compiling using
+// -nostdlib/-nostartfiles.
+void _init(void);
+void _init(void) {
+}
+
+#ifdef USE_FULL_ASSERT
+void assert_failed(const char *file, uint32_t line) {
+ /* USER CODE BEGIN 6 */
+ /* User can add his own implementation to report the file name and line number,
+ e.g.: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
+ /* USER CODE END 6 */
+}
+#endif /* USE_FULL_ASSERT */
diff --git a/hw/bsp/at32f45x/family.cmake b/hw/bsp/at32f45x/family.cmake
new file mode 100644
index 000000000..fe13347af
--- /dev/null
+++ b/hw/bsp/at32f45x/family.cmake
@@ -0,0 +1,97 @@
+include_guard()
+
+set(AT32_FAMILY at32f45x)
+set(AT32_SDK_LIB ${TOP}/hw/mcu/artery/${AT32_FAMILY}/libraries)
+
+string(TOUPPER ${AT32_FAMILY} AT32_FAMILY_UPPER)
+
+# include board specific
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+# toolchain set up
+set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS ${AT32_FAMILY_UPPER} CACHE INTERNAL "")
+
+#------------------------------------
+# Startup & Linker script
+#------------------------------------
+set(STARTUP_FILE_GNU ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/gcc/startup_${AT32_FAMILY}.s)
+set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+set(STARTUP_FILE_IAR ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/iar/startup_${AT32_FAMILY}.s)
+if (NOT DEFINED LD_FILE_GNU)
+set(LD_FILE_GNU ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/gcc/linker/${MCU_LINKER_NAME}_FLASH.ld)
+endif ()
+set(LD_FILE_Clang ${LD_FILE_GNU})
+set(LD_FILE_IAR ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/iar/linker/${MCU_LINKER_NAME}.icf)
+
+#------------------------------------
+# BOARD_TARGET
+#------------------------------------
+function(family_add_board BOARD_TARGET)
+ add_library(${BOARD_TARGET} STATIC
+ ${AT32_SDK_LIB}/cmsis/cm4/device_support/system_${AT32_FAMILY}.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
+ ${AT32_SDK_LIB}/drivers/src/${AT32_FAMILY}_acc.c
+ ${AT32_SDK_LIB}/drivers/src/${AT32_FAMILY}_crm.c
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${AT32_SDK_LIB}/cmsis/cm4/core_support
+ ${AT32_SDK_LIB}/cmsis/cm4/device_support
+ ${AT32_SDK_LIB}/drivers/inc
+ )
+
+ update_board(${BOARD_TARGET})
+endfunction()
+
+#------------------------------------
+# Functions
+#------------------------------------
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+ family_add_tinyusb(${TARGET} OPT_MCU_${AT32_FAMILY_UPPER})
+
+ target_sources(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${AT32_FAMILY}_clock.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${AT32_FAMILY}_int.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
+ ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
+ )
+ target_include_directories(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_options(${TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_GNU}"
+ -nostartfiles
+ --specs=nosys.specs --specs=nano.specs
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ target_link_options(${TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_Clang}"
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+ target_link_options(${TARGET} PUBLIC
+ "LINKER:--config=${LD_FILE_IAR}"
+ )
+ endif ()
+
+ set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES
+ SKIP_LINTING ON
+ COMPILE_OPTIONS -w)
+
+ # Flashing
+ family_add_bin_hex(${TARGET})
+ family_flash_jlink(${TARGET})
+endfunction()
diff --git a/hw/bsp/at32f45x/family.mk b/hw/bsp/at32f45x/family.mk
new file mode 100644
index 000000000..e42f27557
--- /dev/null
+++ b/hw/bsp/at32f45x/family.mk
@@ -0,0 +1,40 @@
+AT32_FAMILY = at32f45x
+AT32_SDK_LIB = hw/mcu/artery/${AT32_FAMILY}/libraries
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+CPU_CORE ?= cortex-m4
+
+CFLAGS_GCC += \
+ -flto
+
+CFLAGS += \
+ -DCFG_TUSB_MCU=OPT_MCU_AT32F45X \
+
+LDFLAGS_GCC += \
+ -flto --specs=nosys.specs -nostdlib -nostartfiles
+
+SRC_C += \
+ src/portable/synopsys/dwc2/dcd_dwc2.c \
+ src/portable/synopsys/dwc2/hcd_dwc2.c \
+ src/portable/synopsys/dwc2/dwc2_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 \
+ $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_crm.c \
+ $(AT32_SDK_LIB)/drivers/src/${AT32_FAMILY}_acc.c \
+ $(AT32_SDK_LIB)/cmsis/cm4/device_support/system_${AT32_FAMILY}.c
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/$(AT32_SDK_LIB)/drivers/inc \
+ $(TOP)/$(AT32_SDK_LIB)/cmsis/cm4/core_support \
+ $(TOP)/$(AT32_SDK_LIB)/cmsis/cm4/device_support
+
+SRC_S_GCC += ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/gcc/startup_${AT32_FAMILY}.s
+SRC_S_IAR += ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/iar/startup_${AT32_FAMILY}.s
+
+LD_FILE_GCC ?= ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/gcc/linker/${MCU_LINKER_NAME}_FLASH.ld
+LD_FILE_IAR ?= ${AT32_SDK_LIB}/cmsis/cm4/device_support/startup/iar/linker/${MCU_LINKER_NAME}.icf
+
+flash: flash-atlink
diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake
index baa8422fe..ad9a4f94d 100644
--- a/hw/bsp/family_support.cmake
+++ b/hw/bsp/family_support.cmake
@@ -238,6 +238,7 @@ function(family_add_bloaty TARGET)
COMMAND ${BLOATY_EXE} ${OPTION_LIST} $<TARGET_FILE:${TARGET}>
VERBATIM)
+ set_property(TARGET ${TARGET}-bloaty PROPERTY FOLDER ${TARGET})
# post build
# add_custom_command(TARGET ${TARGET} POST_BUILD
# COMMAND ${BLOATY_EXE} --csv ${OPTION_LIST} $<TARGET_FILE:${TARGET}> > ${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_bloaty.csv
@@ -258,6 +259,8 @@ function(family_add_linkermap TARGET)
VERBATIM
)
+ set_property(TARGET ${TARGET}-linkermap PROPERTY FOLDER ${TARGET})
+
# post build
add_custom_command(TARGET ${TARGET} POST_BUILD
COMMAND python ${LINKERMAP_PY} ${OPTION_LIST} $<TARGET_FILE:${TARGET}>.map
@@ -508,6 +511,8 @@ exit"
COMMAND ${JLINKEXE} -device ${JLINK_DEVICE} ${OPTION_LIST} -if ${JLINK_IF} -JTAGConf -1,-1 -speed auto -CommandFile $<TARGET_FILE_DIR:${BINARY_TARGET}>/${BINARY_TARGET}.jlink
VERBATIM
)
+
+ set_property(TARGET ${NAME_TARGET}-jlink PROPERTY FOLDER ${TARGET})
endfunction()
@@ -521,6 +526,8 @@ function(family_flash_stlink TARGET)
DEPENDS ${TARGET}
COMMAND ${STM32_PROGRAMMER_CLI} --connect port=swd --write $<TARGET_FILE:${TARGET}> --go
)
+
+ set_property(TARGET ${TARGET}-stlink PROPERTY FOLDER ${TARGET})
endfunction()
@@ -534,6 +541,8 @@ function(family_flash_stflash TARGET)
DEPENDS ${TARGET}
COMMAND ${ST_FLASH} write $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.bin 0x8000000
)
+
+ set_property(TARGET ${TARGET}-stflash PROPERTY FOLDER ${TARGET})
endfunction()
@@ -560,6 +569,8 @@ function(family_flash_openocd TARGET)
COMMAND ${OPENOCD} -c "tcl_port disabled; gdb_port disabled" ${OPTION_LIST} -c "init; halt; program $<TARGET_FILE:${TARGET}>" -c reset ${OPTION_LIST2} -c exit
VERBATIM
)
+
+ set_property(TARGET ${TARGET}-openocd PROPERTY FOLDER ${TARGET})
endfunction()
@@ -621,6 +632,8 @@ function(family_flash_wlink_rs TARGET)
DEPENDS ${TARGET}
COMMAND ${WLINK_RS} flash $<TARGET_FILE:${TARGET}>
)
+
+ set_property(TARGET ${TARGET}-wlink-rs PROPERTY FOLDER ${TARGET})
endfunction()
@@ -634,6 +647,8 @@ function(family_flash_pyocd TARGET)
DEPENDS ${TARGET}
COMMAND ${PYOCD} flash -t ${PYOCD_TARGET} $<TARGET_FILE:${TARGET}>
)
+
+ set_property(TARGET ${TARGET}-pyocd PROPERTY FOLDER ${TARGET})
endfunction()
@@ -643,6 +658,7 @@ function(family_flash_uf2 TARGET FAMILY_ID)
DEPENDS ${TARGET}
COMMAND python ${UF2CONV_PY} -f ${FAMILY_ID} --deploy $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.uf2
)
+ set_property(TARGET ${TARGET}-uf2 PROPERTY FOLDER ${TARGET})
endfunction()
@@ -657,6 +673,8 @@ function(family_flash_teensy TARGET)
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${TARGET}> $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.hex
COMMAND ${TEENSY_CLI} --mcu=${TEENSY_MCU} -w -s $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.hex
)
+
+ set_property(TARGET ${TARGET}-teensy PROPERTY FOLDER ${TARGET})
endfunction()
@@ -675,6 +693,8 @@ function(family_flash_nxplink TARGET)
DEPENDS ${TARGET}
COMMAND ${LINKSERVER_PATH} flash ${NXPLINK_DEVICE} load $<TARGET_FILE:${TARGET}>
)
+
+ set_property(TARGET ${TARGET}-nxplink PROPERTY FOLDER ${TARGET})
endfunction()
@@ -688,6 +708,8 @@ function(family_flash_dfu_util TARGET OPTION)
COMMAND ${DFU_UTIL} -R -d ${DFU_UTIL_VID_PID} -a 0 -D $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.bin
VERBATIM
)
+
+ set_property(TARGET ${TARGET}-dfu-util PROPERTY FOLDER ${TARGET})
endfunction()
function(family_flash_msp430flasher TARGET)
@@ -703,6 +725,8 @@ function(family_flash_msp430flasher TARGET)
COMMAND ${CMAKE_COMMAND} -E env LD_LIBRARY_PATH=${MSP430FLASHER_PARENT_DIR}
${MSP430FLASHER} -w $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.hex -z [VCC]
)
+
+ set_property(TARGET ${TARGET}-msp430flasher PROPERTY FOLDER ${TARGET})
endfunction()
function(family_flash_uniflash TARGET)
@@ -717,6 +741,8 @@ function(family_flash_uniflash TARGET)
COMMAND ${DSLITE} ${UNIFLASH_OPTION} -f $<TARGET_FILE_DIR:${TARGET}>/${TARGET}.hex
VERBATIM
)
+
+ set_property(TARGET ${TARGET}-uniflash PROPERTY FOLDER ${TARGET})
endfunction()
#----------------------------------
diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake
index 1602e35eb..e617ab3ca 100644
--- a/hw/bsp/rp2040/family.cmake
+++ b/hw/bsp/rp2040/family.cmake
@@ -157,10 +157,12 @@ target_link_libraries(tinyusb_bsp INTERFACE
# tinyusb_additions will hold our extra settings for examples
add_library(tinyusb_additions INTERFACE)
+if (PICO_PLATFORM STREQUAL rp2040)
target_compile_definitions(tinyusb_additions INTERFACE
PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1
PICO_RP2040_USB_DEVICE_UFRAME_FIX=1
-)
+ )
+endif ()
if(LOGGER STREQUAL "RTT" OR LOGGER STREQUAL "rtt")
target_compile_definitions(tinyusb_additions INTERFACE
@@ -249,6 +251,7 @@ function(family_configure_target TARGET RTOS)
family_flash_jlink(${TARGET})
# Generate linkermap target and post build. LINKERMAP_OPTION can be set with -D to change default options
+ family_add_bloaty(${TARGET})
family_add_linkermap(${TARGET})
endfunction()
diff --git a/hw/bsp/stm32h7/boards/stm32h747disco/board.cmake b/hw/bsp/stm32h7/boards/stm32h747disco/board.cmake
new file mode 100644
index 000000000..8bce542a5
--- /dev/null
+++ b/hw/bsp/stm32h7/boards/stm32h747disco/board.cmake
@@ -0,0 +1,23 @@
+set(MCU_VARIANT stm32h747xx)
+set(JLINK_DEVICE stm32h747xi_m7)
+
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/../../linker/${MCU_VARIANT}_flash_CM7.ld)
+set(LD_FILE_IAR ${ST_CMSIS}/Source/Templates/iar/linker/${MCU_VARIANT}_flash_CM7.icf)
+
+set(RHPORT_SPEED OPT_MODE_FULL_SPEED OPT_MODE_HIGH_SPEED)
+
+# device default to PORT 1 High Speed
+if (NOT DEFINED RHPORT_DEVICE)
+ set(RHPORT_DEVICE 1)
+endif()
+if (NOT DEFINED RHPORT_HOST)
+ set(RHPORT_HOST 1)
+endif()
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ STM32H747xx
+ HSE_VALUE=25000000
+ CORE_CM7
+ )
+endfunction()
diff --git a/hw/bsp/stm32h7/boards/stm32h747disco/board.h b/hw/bsp/stm32h7/boards/stm32h747disco/board.h
new file mode 100644
index 000000000..71e8b1427
--- /dev/null
+++ b/hw/bsp/stm32h7/boards/stm32h747disco/board.h
@@ -0,0 +1,169 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * 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.
+ */
+
+/* metadata:
+ name: STM32 H745 Discovery
+ url: https://www.st.com/en/evaluation-tools/stm32h745i-disco.html
+*/
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+// UART
+#define UART_DEV USART3
+#define UART_CLK_EN __HAL_RCC_USART3_CLK_ENABLE
+
+// VBUS Sense detection
+#define OTG_FS_VBUS_SENSE 1
+#define OTG_HS_VBUS_SENSE 0
+
+// USB HS External PHY Pin: CLK, STP, DIR, NXT, D0-D7
+#define ULPI_PINS \
+ {GPIOA, GPIO_PIN_3 }, {GPIOA, GPIO_PIN_5 }, {GPIOB, GPIO_PIN_0 }, {GPIOB, GPIO_PIN_1 }, \
+ {GPIOB, GPIO_PIN_5 }, {GPIOB, GPIO_PIN_10}, {GPIOB, GPIO_PIN_11}, {GPIOB, GPIO_PIN_12}, \
+ {GPIOB, GPIO_PIN_13}, {GPIOC, GPIO_PIN_0 }, {GPIOH, GPIO_PIN_4 }, {GPIOI, GPIO_PIN_11}
+
+#define PINID_LED 0
+#define PINID_BUTTON 1
+#define PINID_UART_TX 2
+#define PINID_UART_RX 3
+
+static board_pindef_t board_pindef[] = {
+ { // LED
+ .port = GPIOI,
+ .pin_init = { .Pin = GPIO_PIN_12, .Mode = GPIO_MODE_OUTPUT_PP, .Pull = GPIO_PULLDOWN, .Speed = GPIO_SPEED_HIGH, .Alternate = 0 },
+ .active_state = 0
+ },
+ { // Button
+ .port = GPIOC,
+ .pin_init = { .Pin = GPIO_PIN_13, .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_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_HIGH, .Alternate = GPIO_AF7_USART3 },
+ .active_state = 0
+ },
+ { // UART RX
+ .port = GPIOA,
+ .pin_init = { .Pin = GPIO_PIN_10, .Mode = GPIO_MODE_AF_PP, .Pull = GPIO_PULLUP, .Speed = GPIO_SPEED_HIGH, .Alternate = GPIO_AF7_USART3 },
+ .active_state = 0
+ }
+};
+
+//--------------------------------------------------------------------+
+// RCC Clock
+//--------------------------------------------------------------------+
+static inline void SystemClock_Config(void)
+{
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
+ RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
+ RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = { 0 };
+
+ /*!< Supply configuration update enable */
+ /* For STM32H750XB, use "HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);" */
+ HAL_PWREx_ConfigSupply(PWR_DIRECT_SMPS_SUPPLY);
+
+ /* The voltage scaling allows optimizing the power consumption when the
+ device is clocked below the maximum system frequency, to update the
+ voltage scaling value regarding system frequency refer to product
+ datasheet. */
+ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+
+ while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {}
+
+ /* Enable HSE Oscillator and activate PLL with HSE as source */
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+ RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
+ RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
+ RCC_OscInitStruct.CSIState = RCC_CSI_OFF;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+
+ /* PLL1 for System Clock */
+ RCC_OscInitStruct.PLL.PLLM = 5;
+ RCC_OscInitStruct.PLL.PLLN = 160;
+ RCC_OscInitStruct.PLL.PLLFRACN = 0;
+ RCC_OscInitStruct.PLL.PLLP = 2;
+ RCC_OscInitStruct.PLL.PLLR = 2;
+ RCC_OscInitStruct.PLL.PLLQ = 4;
+
+ RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOMEDIUM;
+ RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
+ HAL_RCC_OscConfig(&RCC_OscInitStruct);
+
+ /* PLL3 for USB Clock */
+ PeriphClkInitStruct.PLL3.PLL3M = 25;
+ PeriphClkInitStruct.PLL3.PLL3N = 336;
+ PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
+ PeriphClkInitStruct.PLL3.PLL3P = 2;
+ PeriphClkInitStruct.PLL3.PLL3R = 2;
+ PeriphClkInitStruct.PLL3.PLL3Q = 7;
+
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
+ PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3;
+ HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
+
+ /* Select PLL as system clock source and configure bus clocks dividers */
+ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \
+ RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1);
+
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
+ RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
+ RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1;
+ HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
+
+ /*activate CSI clock mondatory for I/O Compensation Cell*/
+ __HAL_RCC_CSI_ENABLE() ;
+
+ /* Enable SYSCFG clock mondatory for I/O Compensation Cell */
+ __HAL_RCC_SYSCFG_CLK_ENABLE() ;
+
+ /* Enables the I/O Compensation Cell */
+ HAL_EnableCompensationCell();
+}
+
+static inline void board_init2(void) {
+ // For this board does nothing
+}
+
+void board_vbus_set(uint8_t rhport, bool state) {
+ (void) rhport;
+ (void) state;
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/stm32h7/boards/stm32h747disco/board.mk b/hw/bsp/stm32h7/boards/stm32h747disco/board.mk
new file mode 100644
index 000000000..4b17246e2
--- /dev/null
+++ b/hw/bsp/stm32h7/boards/stm32h747disco/board.mk
@@ -0,0 +1,15 @@
+# STM32H747I-DISCO uses OTG_FS
+# FIXME: Reset enumerates, un/replug USB plug does not enumerate
+MCU_VARIANT = stm32h747xx
+CFLAGS += -DSTM32H747xx -DCORE_CM7 -DHSE_VALUE=25000000
+
+# Default is FulSpeed port
+PORT ?= 0
+
+LD_FILE_GCC = $(FAMILY_PATH)/linker/${MCU_VARIANT}_flash_CM7.ld
+LD_FILE_IAR = $(ST_CMSIS)/Source/Templates/iar/linker/stm32h747xx_flash_CM7.icf
+
+# For flash-jlink target
+JLINK_DEVICE = stm32h747xi_m7
+# flash target using on-board stlink
+flash: flash-stlink
diff --git a/hw/bsp/stm32h7/linker/stm32h747xx_flash_CM7.ld b/hw/bsp/stm32h7/linker/stm32h747xx_flash_CM7.ld
new file mode 100644
index 000000000..5b7fe4528
--- /dev/null
+++ b/hw/bsp/stm32h7/linker/stm32h747xx_flash_CM7.ld
@@ -0,0 +1,184 @@
+/*
+******************************************************************************
+**
+
+** File : LinkerScript.ld
+**
+**
+** Abstract : Linker script for STM32H7 series
+** 1024Kbytes FLASH and 192Kbytes RAM
+**
+** Set heap size, stack size and stack location according
+** to application requirements.
+**
+** Set memory bank area and size if external memory is used.
+**
+** Target : STMicroelectronics STM32
+**
+** Distribution: The file is distributed as is without any warranty
+** of any kind.
+**
+*****************************************************************************
+** @attention
+**
+** Copyright (c) 2019 STMicroelectronics.
+** All rights reserved.
+**
+** This software is licensed under terms that can be found in the LICENSE file
+** in the root directory of this software component.
+** If no LICENSE file comes with this software, it is provided AS-IS.
+**
+******************************************************************************
+*/
+
+/* Entry Point */
+ENTRY(Reset_Handler)
+
+/* Highest address of the user mode stack */
+_estack = 0x20020000; /* end of RAM */
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0x200; /* required amount of heap */
+_Min_Stack_Size = 0x400; /* required amount of stack */
+
+/* Specify the memory areas */
+MEMORY
+{
+FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
+RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
+ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
+}
+
+/* Define output sections */
+SECTIONS
+{
+ /* The startup code goes first into FLASH */
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* The program code and other data goes into FLASH */
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text) /* .text sections (code) */
+ *(.text*) /* .text* sections (code) */
+ *(.glue_7) /* glue arm to thumb code */
+ *(.glue_7t) /* glue thumb to arm code */
+ *(.eh_frame)
+
+ KEEP (*(.init))
+ KEEP (*(.fini))
+
+ . = ALIGN(4);
+ _etext = .; /* define a global symbols at end of code */
+ } >FLASH
+
+ /* Constant data goes into FLASH */
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata) /* .rodata sections (constants, strings, etc.) */
+ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab :
+ {
+ . = ALIGN(4);
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ } >FLASH
+ .ARM :
+ {
+ . = ALIGN(4);
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ . = ALIGN(4);
+ } >FLASH
+
+ .preinit_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array*))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+ .init_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array*))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+ .fini_array :
+ {
+ . = ALIGN(4);
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(SORT(.fini_array.*)))
+ KEEP (*(.fini_array*))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ . = ALIGN(4);
+ } >FLASH
+
+ /* used by the startup to initialize data */
+ _sidata = LOADADDR(.data);
+
+ /* Initialized data sections goes into RAM, load LMA copy after code */
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .; /* create a global symbol at data start */
+ *(.data) /* .data sections */
+ *(.data*) /* .data* sections */
+
+ . = ALIGN(4);
+ _edata = .; /* define a global symbol at data end */
+ } >RAM AT> FLASH
+
+
+ /* Uninitialized data section */
+ . = ALIGN(4);
+ .bss :
+ {
+ /* This is used by the startup in order to initialize the .bss section */
+ _sbss = .; /* define a global symbol at bss start */
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+
+ . = ALIGN(4);
+ _ebss = .; /* define a global symbol at bss end */
+ __bss_end__ = _ebss;
+ } >RAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+
+
+ /* Remove information from the standard libraries */
+ /DISCARD/ :
+ {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/tm4c/FreeRTOSConfig/FreeRTOSConfig.h b/hw/bsp/tm4c/FreeRTOSConfig/FreeRTOSConfig.h
index 454b085e9..b4423e269 100644
--- a/hw/bsp/tm4c/FreeRTOSConfig/FreeRTOSConfig.h
+++ b/hw/bsp/tm4c/FreeRTOSConfig/FreeRTOSConfig.h
@@ -44,7 +44,13 @@
// skip if included from IAR assembler
#ifndef __IASMARM__
- #include "TM4C123.h"
+ #ifdef TM4C123GH6PM
+ #include "TM4C123.h"
+ #elif TM4C1294NCPDT
+ #include "TM4C129.h"
+ #else
+ #error "Unknown TM4C device"
+ #endif
#endif
/* Cortex M23/M33 port configuration. */
diff --git a/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.h b/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.h
index c0ceb4cd8..fc0ab4c60 100644
--- a/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.h
+++ b/hw/bsp/tm4c/boards/ek_tm4c123gxl/board.h
@@ -36,20 +36,26 @@
extern "C" {
#endif
+#include "TM4C123.h"
+
#define BOARD_UART UART0
#define BOARD_UART_PORT GPIOA
+#define BTN_PORT_CLK 5
#define BOARD_BTN_PORT GPIOF
#define BOARD_BTN 4
#define BOARD_BTN_Msk (1u<<4)
#define BUTTON_STATE_ACTIVE 0
+#define LED_PORT_CLK 5
#define LED_PORT GPIOF
#define LED_PIN_RED 1
#define LED_PIN_BLUE 2
#define LED_PIN_GREEN 3
#define LED_STATE_ON 1
+#define BOARD_LED_PIN LED_PIN_BLUE
+
#ifdef __cplusplus
}
#endif
diff --git a/hw/bsp/tm4c/boards/ek_tm4c123gxl/tm4c123.ld b/hw/bsp/tm4c/boards/ek_tm4c123gxl/tm4c123.ld
index 11e9608cc..3f06d8f03 100644
--- a/hw/bsp/tm4c/boards/ek_tm4c123gxl/tm4c123.ld
+++ b/hw/bsp/tm4c/boards/ek_tm4c123gxl/tm4c123.ld
@@ -17,7 +17,7 @@ SECTIONS
.text :
{
. = ALIGN(4) ;
- *(.vectors)
+ KEEP(*(.vectors))
*(.text)
*(.text.*)
*(.init)
diff --git a/hw/bsp/tm4c/boards/ek_tm4c1294xl/TM4C1294NC.icf b/hw/bsp/tm4c/boards/ek_tm4c1294xl/TM4C1294NC.icf
new file mode 100644
index 000000000..2dba41866
--- /dev/null
+++ b/hw/bsp/tm4c/boards/ek_tm4c1294xl/TM4C1294NC.icf
@@ -0,0 +1,28 @@
+/*###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__ = 0x00000000;
+/*-Memory Regions-*/
+define symbol __ICFEDIT_region_ROM_start__ = 0x00000000;
+define symbol __ICFEDIT_region_ROM_end__ = 0x000FFFFF;
+define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
+define symbol __ICFEDIT_region_RAM_end__ = 0x2003FFFF;
+/*-Sizes-*/
+define symbol __ICFEDIT_size_cstack__ = 0x8000;
+define symbol __ICFEDIT_size_heap__ = 0x10000;
+/**** 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 };
+
+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/tm4c/boards/ek_tm4c1294xl/board.cmake b/hw/bsp/tm4c/boards/ek_tm4c1294xl/board.cmake
new file mode 100644
index 000000000..3e03b3f72
--- /dev/null
+++ b/hw/bsp/tm4c/boards/ek_tm4c1294xl/board.cmake
@@ -0,0 +1,13 @@
+set(MCU_SUB_VARIANT 129)
+
+set(JLINK_DEVICE TM4C1294NCPDT)
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/tm4c1294nc.ld)
+set(LD_FILE_IAR ${CMAKE_CURRENT_LIST_DIR}/TM4C1294NC.icf)
+
+set(OPENOCD_OPTION "-f board/ti_ek-tm4c1294xl.cfg")
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ TM4C1294NCPDT
+ )
+endfunction()
diff --git a/hw/bsp/tm4c/boards/ek_tm4c1294xl/board.h b/hw/bsp/tm4c/boards/ek_tm4c1294xl/board.h
new file mode 100644
index 000000000..4530e9430
--- /dev/null
+++ b/hw/bsp/tm4c/boards/ek_tm4c1294xl/board.h
@@ -0,0 +1,75 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021, Ha Thach (tinyusb.org)
+ *
+ * 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.
+ */
+
+/* metadata:
+ name: TM4C1294 LaunchPad
+ url: https://www.ti.com/tool/EK-TM4C1294XL
+*/
+
+#ifndef _BOARD_H_
+#define _BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "TM4C129.h"
+
+#define BOARD_UART UART0
+#define BOARD_UART_PORT GPIOA
+
+#define BTN_PORT_CLK 8
+#define BOARD_BTN_PORT GPIOJ
+#define BOARD_BTN 0
+#define BOARD_BTN_Msk (1u<<0)
+#define BUTTON_STATE_ACTIVE 0
+
+#define LED_PORT_CLK 12
+#define LED_PORT GPION
+#define LED_PIN_1 1
+#define LED_PIN_2 0
+#define LED_STATE_ON 1
+
+#define BOARD_LED_PIN LED_PIN_2
+
+#define GPIOA GPIOA_AHB
+#define GPIOB GPIOB_AHB
+#define GPIOC GPIOC_AHB
+#define GPIOD GPIOD_AHB
+#define GPIOE GPIOE_AHB
+#define GPIOF GPIOF_AHB
+#define GPIOG GPIOG_AHB
+#define GPIOH GPIOH_AHB
+#define GPIOI GPIOI_AHB
+#define GPIOJ GPIOJ_AHB
+
+#define GPIOA_Type GPIOA_AHB_Type
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/tm4c/boards/ek_tm4c1294xl/board.mk b/hw/bsp/tm4c/boards/ek_tm4c1294xl/board.mk
new file mode 100644
index 000000000..b01977674
--- /dev/null
+++ b/hw/bsp/tm4c/boards/ek_tm4c1294xl/board.mk
@@ -0,0 +1,16 @@
+MCU_SUB_VARIANT = 129
+
+CFLAGS += -DTM4C1294NCPDT
+
+LD_FILE_GCC = $(BOARD_PATH)/tm4c1294nc.ld
+LD_FILE_IAR = $(BOARD_PATH)/TM4C1294NC.icf
+
+# For flash-jlink target
+JLINK_DEVICE = TM4C1294NCPDT
+
+# flash using openocd
+OPENOCD_OPTION = -f board/ti_ek-tm4c1294xl.cfg
+
+UNIFLASH_OPTION = -c ${TOP}/${BOARD_PATH}/${BOARD}.ccxml -r 1
+
+flash: flash-openocd
diff --git a/hw/bsp/tm4c/boards/ek_tm4c1294xl/tm4c1294nc.ld b/hw/bsp/tm4c/boards/ek_tm4c1294xl/tm4c1294nc.ld
new file mode 100644
index 000000000..fa4ea4dc5
--- /dev/null
+++ b/hw/bsp/tm4c/boards/ek_tm4c1294xl/tm4c1294nc.ld
@@ -0,0 +1,66 @@
+ENTRY(Reset_Handler)
+
+_estack = 0x20008000; /* end of RAM */
+/* Generate a link error if heap and stack don't fit into RAM */
+_Min_Heap_Size = 0; /* required amount of heap */
+_Min_Stack_Size = 0x1000; /* required amount of stack */
+
+
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00100000
+ SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00040000
+}
+
+SECTIONS
+{
+ .text :
+ {
+ . = ALIGN(4) ;
+ _text = . ;
+ KEEP(*(.isr_vector))
+ *(.text)
+ *(.text.*)
+ *(.init)
+ *(.fini)
+ *(.rodata)
+ *(.rodata.*)
+ *(.ARM.exidx*)
+ _etext = . ;
+ . = ALIGN(4) ;
+ } >FLASH
+
+ .data : AT(ADDR(.text) + SIZEOF(.text))
+ {
+ _data = .;
+ . = ALIGN(4);
+ _ldata = LOADADDR (.data);
+ *(.data)
+ *(.data.*)
+ _edata = .;
+ . = ALIGN(4);
+
+ } >SRAM
+
+ .bss :
+ {
+ . = ALIGN(4) ;
+ _bss = .;
+ *(.bss)
+ *(.bss.*)
+ *(.COMMON)
+ _ebss = .;
+ . = ALIGN(4);
+ }>SRAM
+
+ /* User_heap_stack section, used to check that there is enough RAM left */
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE ( end = . );
+ PROVIDE ( _end = . );
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >SRAM
+}
diff --git a/hw/bsp/tm4c/family.c b/hw/bsp/tm4c/family.c
index ee1fa2a3c..ae7f22f00 100644
--- a/hw/bsp/tm4c/family.c
+++ b/hw/bsp/tm4c/family.c
@@ -2,7 +2,6 @@
manufacturer: Texas Instruments
*/
-#include "TM4C123.h"
#include "bsp/board_api.h"
#include "board.h"
@@ -27,6 +26,9 @@ static void board_uart_init(void) {
SYSCTL->RCGCUART |= (1 << 0); // Enable the clock to UART0
SYSCTL->RCGCGPIO |= (1 << 0); // Enable the clock to GPIOA
+ while (!(SYSCTL->PRGPIO & (1 << 0))) {} // Wait for the GPIOA clock to stabilize
+ while (!(SYSCTL->PRUART & (1 << 0))) {} // Wait for the UART0 clock to stabilize
+
GPIOA->AFSEL |= (1 << 1) | (1 << 0); // Enable the alternate function on pin PA0 & PA1
GPIOA->PCTL |= (1 << 0) | (1 << 4); // Configure the GPIOPCTL register to select UART0 in PA0 and PA1
GPIOA->DEN |= (1 << 0) | (1 << 1); // Enable the digital functionality in PA0 and PA1
@@ -44,12 +46,26 @@ static void board_uart_init(void) {
UART0->CTL = (1 << 0) | (1 << 8) | (1 << 9); // UART0 Enable, Transmit Enable, Receive Enable
}
-static void initialize_board_led(GPIOA_Type* port, uint8_t PinMsk, uint8_t dirmsk) {
- /* Enable PortF Clock */
- SYSCTL->RCGCGPIO |= (1 << 5);
+static void board_button_init(GPIOA_Type* port, uint8_t PinMsk) {
+ /* Enable Port Clock */
+ SYSCTL->RCGCGPIO |= (1 << BTN_PORT_CLK);
+
+ /* Let the clock stabilize */
+ while (!((SYSCTL->PRGPIO) & (1 << BTN_PORT_CLK))) {}
+
+ /* Port Digital Enable */
+ port->DEN |= PinMsk;
+
+ /* Set direction */
+ port->DIR &= ~PinMsk;
+}
+
+static void board_led_init(GPIOA_Type* port, uint8_t PinMsk, uint8_t dirmsk) {
+ /* Enable Port Clock */
+ SYSCTL->RCGCGPIO |= (1 << LED_PORT_CLK);
/* Let the clock stabilize */
- while (!((SYSCTL->PRGPIO) & (1 << 5))) {}
+ while (!((SYSCTL->PRGPIO) & (1 << LED_PORT_CLK))) {}
/* Port Digital Enable */
port->DEN |= PinMsk;
@@ -71,7 +87,9 @@ static uint32_t ReadGPIOPin(GPIOA_Type* port, uint8_t pinMsk) {
}
void board_init(void) {
+#ifdef TM4C123_H
SystemCoreClockUpdate();
+#endif
#if CFG_TUSB_OS == OPT_OS_NONE
// 1ms tick timer
@@ -83,6 +101,7 @@ void board_init(void) {
NVIC_SetPriority(USB0_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
#endif
+#ifdef TM4C123_H
/* Reset USB */
SYSCTL->SRCR2 |= (1u << 16);
@@ -99,7 +118,7 @@ void board_init(void) {
/* USB IO Initialization */
SYSCTL->RCGCGPIO |= (1u << 3);
- /* Let the clock stabilize */
+ /* Let the clock stabilize */
while (!(SYSCTL->PRGPIO & (1u << 3))) {}
/* USB IOs to Analog Mode */
@@ -107,16 +126,43 @@ void board_init(void) {
GPIOD->DEN &= ~((1u << 4) | (1u << 5));
GPIOD->AMSEL |= ((1u << 4) | (1u << 5));
- uint8_t leds = (1 << LED_PIN_RED) | (1 << LED_PIN_BLUE) | (1 << LED_PIN_GREEN);
- uint8_t dirmsk = (1 << LED_PIN_RED) | (1 << LED_PIN_BLUE) | (1 << LED_PIN_GREEN);
+#else // TM4C129
+ /* Reset USB */
+ SYSCTL->SRUSB = 1;
- /* Configure GPIO for board LED */
- initialize_board_led(LED_PORT, leds, dirmsk);
+ for (volatile uint8_t i = 0; i < 20; i++) {}
+
+ SYSCTL->SRUSB = 0;
- /* Configure GPIO for board switch */
- GPIOF->DIR &= ~(1 << BOARD_BTN);
- GPIOF->PUR |= (1 << BOARD_BTN);
- GPIOF->DEN |= (1 << BOARD_BTN);
+ /* Open the USB clock gate */
+ SYSCTL->RCGCUSB = 1;
+
+ /* Let the clock stabilize */
+ while(!(SYSCTL->PRUSB & 1)) {}
+
+ /* USB IO Initialization */
+ SYSCTL->RCGCGPIO |= (1u << 10);
+
+ /* Let the clock stabilize */
+ while (!(SYSCTL->PRGPIO & (1u << 10))) {}
+
+ /* USB IOs to Analog Mode */
+ GPIOL->AFSEL &= ~((1u << 6) | (1u << 7));
+ GPIOL->DEN &= ~((1u << 6) | (1u << 7));
+ GPIOL->AMSEL |= ((1u << 6) | (1u << 7));
+
+ /* USB Clock Configuration */
+ USB0->CC = 0x207;
+#endif
+
+ uint8_t leds = 1 << BOARD_LED_PIN;
+ uint8_t dirmsk = 1 << BOARD_LED_PIN;
+
+ /* Configure GPIO for board button */
+ board_button_init(BOARD_BTN_PORT, BOARD_BTN_Msk);
+
+ /* Configure GPIO for board LED */
+ board_led_init(LED_PORT, leds, dirmsk);
/* Initialize board UART */
board_uart_init();
@@ -125,7 +171,7 @@ void board_init(void) {
}
void board_led_write(bool state) {
- WriteGPIOPin(LED_PORT, (1 << LED_PIN_BLUE), state);
+ WriteGPIOPin(LED_PORT, (1 << BOARD_LED_PIN), state);
}
uint32_t board_button_read(void) {
diff --git a/hw/bsp/tm4c/family.cmake b/hw/bsp/tm4c/family.cmake
index 12f0448a3..41b8a597a 100644
--- a/hw/bsp/tm4c/family.cmake
+++ b/hw/bsp/tm4c/family.cmake
@@ -5,14 +5,14 @@ include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
set(MCU_VARIANT tm4c${MCU_SUB_VARIANT})
set(MCU_VARIANT_UPPER TM4C${MCU_SUB_VARIANT})
-set(SDK_DIR ${TOP}/hw/mcu/ti/${MCU_VARIANT}xx)
+set(SDK_DIR ${TOP}/hw/mcu/ti/tm4c)
set(CMSIS_DIR ${TOP}/lib/CMSIS_5)
# toolchain set up
set(CMAKE_SYSTEM_CPU cortex-m4 CACHE INTERNAL "System Processor")
set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
-set(FAMILY_MCUS TM4C123 CACHE INTERNAL "")
+set(FAMILY_MCUS TM4C CACHE INTERNAL "")
#------------------------------------
# Startup & Linker script
@@ -20,7 +20,7 @@ set(FAMILY_MCUS TM4C123 CACHE INTERNAL "")
set(LD_FILE_Clang ${LD_FILE_GNU})
set(STARTUP_FILE_GNU ${SDK_DIR}/Source/GCC/${MCU_VARIANT}_startup.c)
set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
-
+set(STARTUP_FILE_IAR ${SDK_DIR}/Source/IAR/${MCU_VARIANT}_startup.c)
#------------------------------------
# Board Target
#------------------------------------
@@ -29,7 +29,7 @@ function(family_add_board BOARD_TARGET)
${SDK_DIR}/Source/system_${MCU_VARIANT_UPPER}.c
)
target_include_directories(${BOARD_TARGET} PUBLIC
- ${SDK_DIR}/Include/${MCU_VARIANT_UPPER}
+ ${SDK_DIR}/Include
${CMSIS_DIR}/CMSIS/Core/Include
)
@@ -41,7 +41,7 @@ endfunction()
#------------------------------------
function(family_configure_example TARGET RTOS)
family_configure_common(${TARGET} ${RTOS})
- family_add_tinyusb(${TARGET} OPT_MCU_TM4C123)
+ family_add_tinyusb(${TARGET} OPT_MCU_TM4C${MCU_SUB_VARIANT})
target_sources(${TARGET} PUBLIC
${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
@@ -71,13 +71,14 @@ function(family_configure_example TARGET RTOS)
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
set_source_files_properties(${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c PROPERTIES COMPILE_FLAGS "-Wno-missing-prototypes")
+ set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES
+ SKIP_LINTING ON
+ COMPILE_OPTIONS -w)
endif ()
- set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES
- SKIP_LINTING ON
- COMPILE_OPTIONS -w)
# Flashing
family_add_bin_hex(${TARGET})
+ family_flash_jlink(${TARGET})
family_flash_openocd(${TARGET})
family_flash_uniflash(${TARGET})
endfunction()
diff --git a/hw/bsp/tm4c/family.mk b/hw/bsp/tm4c/family.mk
index 76ae785b2..bc966d98e 100644
--- a/hw/bsp/tm4c/family.mk
+++ b/hw/bsp/tm4c/family.mk
@@ -4,11 +4,11 @@ CPU_CORE ?= cortex-m4
MCU_VARIANT = tm4c${MCU_SUB_VARIANT}
MCU_VARIANT_UPPER = TM4C${MCU_SUB_VARIANT}
-SDK_DIR = hw/mcu/ti/${MCU_VARIANT}xx
+SDK_DIR = hw/mcu/ti/tm4c
CFLAGS += \
-flto \
- -DCFG_TUSB_MCU=OPT_MCU_TM4C123 \
+ -DCFG_TUSB_MCU=OPT_MCU_TM4C${MCU_SUB_VARIANT} \
-uvectors \
# mcu driver cause following warnings
@@ -18,7 +18,7 @@ LDFLAGS_GCC += --specs=nosys.specs --specs=nano.specs
INC += \
$(TOP)/lib/CMSIS_5/CMSIS/Core/Include \
- $(TOP)/$(SDK_DIR)/Include/${MCU_VARIANT_UPPER} \
+ $(TOP)/$(SDK_DIR)/Include \
$(TOP)/$(BOARD_PATH)
SRC_C += \
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index 55eba81dd..be0224811 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -674,17 +674,17 @@ void audiod_init(void) {
switch (i) {
#if CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ > 0
case 0:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ > 0
case 1:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_IN_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ > 0
case 2:
- tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_in_ff, ep_in_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_IN_SW_BUF_SZ, true);
break;
#endif
}
@@ -716,17 +716,17 @@ void audiod_init(void) {
switch (i) {
#if CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ > 0
case 0:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_1, CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 1 && CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ > 0
case 1:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_2, CFG_TUD_AUDIO_FUNC_2_EP_OUT_SW_BUF_SZ, true);
break;
#endif
#if CFG_TUD_AUDIO > 2 && CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ > 0
case 2:
- tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, 1, true);
+ tu_fifo_config(&audio->ep_out_ff, ep_out_sw_buf.buf_3, CFG_TUD_AUDIO_FUNC_3_EP_OUT_SW_BUF_SZ, true);
break;
#endif
}
diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c
index 32f6827b0..f19c4a327 100644
--- a/src/class/cdc/cdc_host.c
+++ b/src/class/cdc/cdc_host.c
@@ -828,7 +828,9 @@ static bool set_line_state_on_enum(cdch_interface_t *p_cdc, tuh_xfer_t *xfer) {
ENUM_SET_LINE_CONTROL,
ENUM_SET_LINE_COMPLETE,
};
+ #ifdef CFG_TUH_CDC_LINE_CODING_ON_ENUM
const uint8_t idx = get_idx_by_ptr(p_cdc);
+ #endif
const uintptr_t state = xfer->user_data;
switch (state) {
diff --git a/src/class/mtp/mtp_device.c b/src/class/mtp/mtp_device.c
index 4942a105a..59096e476 100644
--- a/src/class/mtp/mtp_device.c
+++ b/src/class/mtp/mtp_device.c
@@ -92,8 +92,9 @@ typedef struct {
uint8_t itf_num;
uint8_t ep_in;
uint8_t ep_out;
- uint8_t ep_event;
+ uint8_t ep_event;
+ uint8_t ep_sz_fs;
// Bulk Only Transfer (BOT) Protocol
uint8_t phase;
@@ -194,42 +195,47 @@ static bool prepare_new_command(mtpd_interface_t* p_mtp) {
return usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_out, _mtpd_epbuf.buf, CFG_TUD_MTP_EP_BUFSIZE, false);
}
-static bool mtpd_data_xfer(mtp_container_info_t* p_container, uint8_t ep_addr) {
- mtpd_interface_t* p_mtp = &_mtpd_itf;
+bool tud_mtp_data_send(mtp_container_info_t *p_container) {
+ mtpd_interface_t *p_mtp = &_mtpd_itf;
if (p_mtp->phase == MTP_PHASE_COMMAND) {
// 1st data block: header + payload
p_mtp->phase = MTP_PHASE_DATA;
p_mtp->xferred_len = 0;
+ p_mtp->total_len = p_container->header->len;
- if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
- p_mtp->total_len = p_container->header->len;
- p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
- p_container->header->transaction_id = p_mtp->command.header.transaction_id;
- p_mtp->io_header = *p_container->header; // save header for subsequent data
- } else {
- // OUT transfer: total length is at least max packet size
- p_mtp->total_len = tu_max32(p_container->header->len, CFG_TUD_MTP_EP_BUFSIZE);
- }
- } else {
- // subsequent data block: payload only
- TU_ASSERT(p_mtp->phase == MTP_PHASE_DATA);
+ p_container->header->type = MTP_CONTAINER_TYPE_DATA_BLOCK;
+ p_container->header->transaction_id = p_mtp->command.header.transaction_id;
+ p_mtp->io_header = *p_container->header; // save header for subsequent data
}
- const uint16_t xact_len = (uint16_t) tu_min32(p_mtp->total_len - p_mtp->xferred_len, CFG_TUD_MTP_EP_BUFSIZE);
+ const uint16_t xact_len = (uint16_t)tu_min32(p_mtp->total_len - p_mtp->xferred_len, CFG_TUD_MTP_EP_BUFSIZE);
+
+ TU_LOG_DRV(" MTP Data IN: xferred_len/total_len=%lu/%lu, xact_len=%u\r\n", p_mtp->xferred_len, p_mtp->total_len,
+ xact_len);
if (xact_len) {
- // already transferred all bytes in header's length. Application make an unnecessary extra call
- TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr));
- TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, _mtpd_epbuf.buf, xact_len, false));
+ TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_in));
+ TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_in, _mtpd_epbuf.buf, xact_len, false));
}
return true;
}
-bool tud_mtp_data_send(mtp_container_info_t* p_container) {
- return mtpd_data_xfer(p_container, _mtpd_itf.ep_in);
-}
+bool tud_mtp_data_receive(mtp_container_info_t *p_container) {
+ mtpd_interface_t *p_mtp = &_mtpd_itf;
+ if (p_mtp->phase == MTP_PHASE_COMMAND) {
+ // 1st data block: header + payload
+ p_mtp->phase = MTP_PHASE_DATA;
+ p_mtp->xferred_len = 0;
+ p_mtp->total_len = p_container->header->len;
+ }
-bool tud_mtp_data_receive(mtp_container_info_t* p_container) {
- return mtpd_data_xfer(p_container, _mtpd_itf.ep_out);
+ // up to buffer size since 1st packet (with header) may also contain payload
+ const uint16_t xact_len = CFG_TUD_MTP_EP_BUFSIZE;
+
+ TU_LOG_DRV(" MTP Data OUT: xferred_len/total_len=%lu/%lu, xact_len=%u\r\n", p_mtp->xferred_len, p_mtp->total_len,
+ xact_len);
+ TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, p_mtp->ep_out));
+ TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, p_mtp->ep_out, _mtpd_epbuf.buf, xact_len, false));
+ return true;
}
bool tud_mtp_response_send(mtp_container_info_t* p_container) {
@@ -287,15 +293,20 @@ uint16_t mtpd_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc, uint16
p_mtp->itf_num = itf_desc->bInterfaceNumber;
// Open interrupt IN endpoint
- const tusb_desc_endpoint_t* ep_desc = (const tusb_desc_endpoint_t*) tu_desc_next(itf_desc);
- TU_ASSERT(ep_desc->bDescriptorType == TUSB_DESC_ENDPOINT && ep_desc->bmAttributes.xfer == TUSB_XFER_INTERRUPT, 0);
- TU_ASSERT(usbd_edpt_open(rhport, ep_desc), 0);
- p_mtp->ep_event = ep_desc->bEndpointAddress;
+ const tusb_desc_endpoint_t* ep_desc_int = (const tusb_desc_endpoint_t*) tu_desc_next(itf_desc);
+ TU_ASSERT(ep_desc_int->bDescriptorType == TUSB_DESC_ENDPOINT && ep_desc_int->bmAttributes.xfer == TUSB_XFER_INTERRUPT, 0);
+ TU_ASSERT(usbd_edpt_open(rhport, ep_desc_int), 0);
+ p_mtp->ep_event = ep_desc_int->bEndpointAddress;
// Open endpoint pair
- TU_ASSERT(usbd_open_edpt_pair(rhport, tu_desc_next(ep_desc), 2, TUSB_XFER_BULK, &p_mtp->ep_out, &p_mtp->ep_in), 0);
+ const tusb_desc_endpoint_t* ep_desc_bulk = (const tusb_desc_endpoint_t*) tu_desc_next(ep_desc_int);
+ TU_ASSERT(usbd_open_edpt_pair(rhport, (const uint8_t*)ep_desc_bulk, 2, TUSB_XFER_BULK, &p_mtp->ep_out, &p_mtp->ep_in), 0);
TU_ASSERT(prepare_new_command(p_mtp), 0);
+ if (tud_speed_get() == TUSB_SPEED_FULL) {
+ p_mtp->ep_sz_fs = (uint8_t)tu_edpt_packet_size(ep_desc_bulk);
+ }
+
return mtpd_itf_size;
}
@@ -377,8 +388,8 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
mtp_generic_container_t* p_container = (mtp_generic_container_t*) _mtpd_epbuf.buf;
#if CFG_TUSB_DEBUG >= CFG_TUD_MTP_LOG_LEVEL
- tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code);
- TU_LOG_DRV(" MTP %s: %s phase\r\n", (const char *) tu_lookup_find(&_mtp_op_table, p_mtp->command.header.code),
+ const uint16_t code = (p_mtp->phase == MTP_PHASE_COMMAND) ? p_container->header.code : p_mtp->command.header.code;
+ TU_LOG_DRV(" MTP %s: %s phase\r\n", (const char *) tu_lookup_find(&_mtp_op_table, code),
_mtp_phase_str[p_mtp->phase]);
#endif
@@ -417,19 +428,35 @@ bool mtpd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
}
case MTP_PHASE_DATA: {
- const uint16_t bulk_mps = (tud_speed_get() == TUSB_SPEED_HIGH) ? 512 : 64;
p_mtp->xferred_len += xferred_bytes;
cb_data.total_xferred_bytes = p_mtp->xferred_len;
- bool is_complete = false;
- // complete if ZLP or short packet or total length reached
- if (xferred_bytes == 0 || // ZLP
- (xferred_bytes & (bulk_mps - 1)) || // short packet
- p_mtp->xferred_len >= p_mtp->total_len) { // total length reached
- is_complete = true;
+ const bool is_data_in = (ep_addr == p_mtp->ep_in);
+ // For IN endpoint, threshold is bulk max packet size
+ // For OUT endpoint, threshold is endpoint buffer size, since we always queue fixed size
+ uint16_t threshold;
+ if (is_data_in) {
+ threshold = (p_mtp->ep_sz_fs > 0) ? p_mtp->ep_sz_fs : 512; // full speed bulk if set
+ } else {
+ threshold = CFG_TUD_MTP_EP_BUFSIZE;
+ }
+
+ // Check completion: ZLP, short packet, or total length reached
+ const bool is_complete =
+ (xferred_bytes == 0 || xferred_bytes < threshold || p_mtp->xferred_len >= p_mtp->total_len);
+
+ TU_LOG_DRV(" MTP Data %s CB: xferred_bytes=%lu, xferred_len/total_len=%lu/%lu, is_complete=%d\r\n",
+ is_data_in ? "IN" : "OUT", xferred_bytes, p_mtp->xferred_len, p_mtp->total_len, is_complete ? 1 : 0);
+
+ // Send/queue ZLP if packet is full-sized but transfer is complete
+ if (is_complete && xferred_bytes > 0 && !(xferred_bytes & (threshold - 1))) {
+ TU_LOG_DRV(" queue ZLP\r\n");
+ TU_VERIFY(usbd_edpt_claim(p_mtp->rhport, ep_addr));
+ TU_ASSERT(usbd_edpt_xfer(p_mtp->rhport, ep_addr, NULL, 0, false));
+ return true;
}
- if (ep_addr == p_mtp->ep_in) {
+ if (is_data_in) {
// Data In
if (is_complete) {
cb_data.io_container.header->len = sizeof(mtp_container_header_t);
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
index b8e6fec6f..b917c8dc7 100644
--- a/src/class/vendor/vendor_device.c
+++ b/src/class/vendor/vendor_device.c
@@ -40,36 +40,33 @@ typedef struct {
uint8_t rhport;
uint8_t itf_num;
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
/*------------- From this point, data is not cleared by bus reset -------------*/
- struct {
- tu_edpt_stream_t tx;
- tu_edpt_stream_t rx;
-
- #if CFG_TUD_VENDOR_TX_BUFSIZE > 0
- uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
- #endif
-
- #if CFG_TUD_VENDOR_RX_BUFSIZE > 0
- uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
+ tu_edpt_stream_t tx_stream;
+ tu_edpt_stream_t rx_stream;
+ uint8_t tx_ff_buf[CFG_TUD_VENDOR_TX_BUFSIZE];
+ uint8_t rx_ff_buf[CFG_TUD_VENDOR_RX_BUFSIZE];
+ #else
+ uint8_t ep_in;
+ uint8_t ep_out;
+ uint16_t ep_in_mps;
+ uint16_t ep_out_mps;
#endif
- } stream;
} vendord_interface_t;
-#define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + sizeof(((vendord_interface_t *)0)->itf_num))
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ #define ITF_MEM_RESET_SIZE (offsetof(vendord_interface_t, itf_num) + TU_FIELD_SIZE(vendord_interface_t, itf_num))
+ #else
+ #define ITF_MEM_RESET_SIZE sizeof(vendord_interface_t)
+ #endif
static vendord_interface_t _vendord_itf[CFG_TUD_VENDOR];
-#if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0
+ // Skip local EP buffer if dedicated hw FIFO is supported or no fifo mode
+ #if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || !CFG_TUD_VENDOR_TXRX_BUFFERED
typedef struct {
- // Skip local EP buffer if dedicated hw FIFO is supported
- #if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0
TUD_EPBUF_DEF(epout, CFG_TUD_VENDOR_EPSIZE);
- #endif
-
- // Skip local EP buffer if dedicated hw FIFO is supported
- #if CFG_TUD_EDPT_DEDICATED_HWFIFO == 0
TUD_EPBUF_DEF(epin, CFG_TUD_VENDOR_EPSIZE);
- #endif
} vendord_epbuf_t;
CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
@@ -78,7 +75,6 @@ CFG_TUD_MEM_SECTION static vendord_epbuf_t _vendord_epbuf[CFG_TUD_VENDOR];
//--------------------------------------------------------------------+
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
-
TU_ATTR_WEAK void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize) {
(void)idx;
(void)buffer;
@@ -93,40 +89,44 @@ TU_ATTR_WEAK void tud_vendor_tx_cb(uint8_t idx, uint32_t sent_bytes) {
//--------------------------------------------------------------------
// Application API
//--------------------------------------------------------------------
-
bool tud_vendor_n_mounted(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- return p_itf->stream.rx.ep_addr || p_itf->stream.tx.ep_addr;
+
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ return (p_itf->rx_stream.ep_addr != 0) || (p_itf->tx_stream.ep_addr != 0);
+ #else
+ return (p_itf->ep_out != 0) || (p_itf->ep_in != 0);
+ #endif
}
//--------------------------------------------------------------------+
// Read API
//--------------------------------------------------------------------+
-#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
uint32_t tud_vendor_n_available(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- return tu_edpt_stream_read_available(&p_itf->stream.rx);
+ return tu_edpt_stream_read_available(&p_itf->rx_stream);
}
bool tud_vendor_n_peek(uint8_t idx, uint8_t *u8) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- return tu_edpt_stream_peek(&p_itf->stream.rx, u8);
+ return tu_edpt_stream_peek(&p_itf->rx_stream, u8);
}
uint32_t tud_vendor_n_read(uint8_t idx, void *buffer, uint32_t bufsize) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- return tu_edpt_stream_read(&p_itf->stream.rx, buffer, bufsize);
+ return tu_edpt_stream_read(&p_itf->rx_stream, buffer, bufsize);
}
void tud_vendor_n_read_flush(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, );
vendord_interface_t *p_itf = &_vendord_itf[idx];
- tu_edpt_stream_clear(&p_itf->stream.rx);
- tu_edpt_stream_read_xfer(&p_itf->stream.rx);
+ tu_edpt_stream_clear(&p_itf->rx_stream);
+ tu_edpt_stream_read_xfer(&p_itf->rx_stream);
}
#endif
@@ -134,9 +134,17 @@ void tud_vendor_n_read_flush(uint8_t idx) {
bool tud_vendor_n_read_xfer(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- return tu_edpt_stream_read_xfer(&p_itf->stream.rx);
+
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ return tu_edpt_stream_read_xfer(&p_itf->rx_stream);
+
+ #else
+ // Non-FIFO mode
+ TU_VERIFY(usbd_edpt_claim(p_itf->rhport, p_itf->ep_out));
+ return usbd_edpt_xfer(p_itf->rhport, p_itf->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false);
+ #endif
}
-#endif
+ #endif
//--------------------------------------------------------------------+
@@ -145,26 +153,45 @@ bool tud_vendor_n_read_xfer(uint8_t idx) {
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- return tu_edpt_stream_write(&p_itf->stream.tx, buffer, (uint16_t)bufsize);
+
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ return tu_edpt_stream_write(&p_itf->tx_stream, buffer, (uint16_t)bufsize);
+
+ #else
+ // non-fifo mode: direct transfer
+ TU_VERIFY(usbd_edpt_claim(p_itf->rhport, p_itf->ep_in), 0);
+ const uint32_t xact_len = tu_min32(bufsize, CFG_TUD_VENDOR_EPSIZE);
+ memcpy(_vendord_epbuf[idx].epin, buffer, xact_len);
+ TU_ASSERT(usbd_edpt_xfer(p_itf->rhport, p_itf->ep_in, _vendord_epbuf[idx].epin, (uint16_t)xact_len, false), 0);
+ return xact_len;
+ #endif
}
-#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
-uint32_t tud_vendor_n_write_flush(uint8_t idx) {
+uint32_t tud_vendor_n_write_available(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- return tu_edpt_stream_write_xfer(&p_itf->stream.tx);
+
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ return tu_edpt_stream_write_available(&p_itf->tx_stream);
+
+ #else
+ // Non-FIFO mode
+ TU_VERIFY(p_itf->ep_in > 0, 0); // must be opened
+ return usbd_edpt_busy(p_itf->rhport, p_itf->ep_in) ? 0 : CFG_TUD_VENDOR_EPSIZE;
+ #endif
}
-uint32_t tud_vendor_n_write_available(uint8_t idx) {
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+uint32_t tud_vendor_n_write_flush(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- return tu_edpt_stream_write_available(&p_itf->stream.tx);
+ return tu_edpt_stream_write_xfer(&p_itf->tx_stream);
}
bool tud_vendor_n_write_clear(uint8_t idx) {
TU_VERIFY(idx < CFG_TUD_VENDOR, 0);
vendord_interface_t *p_itf = &_vendord_itf[idx];
- tu_edpt_stream_clear(&p_itf->stream.tx);
+ tu_edpt_stream_clear(&p_itf->tx_stream);
return true;
}
#endif
@@ -175,48 +202,37 @@ bool tud_vendor_n_write_clear(uint8_t idx) {
void vendord_init(void) {
tu_memclr(_vendord_itf, sizeof(_vendord_itf));
- for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
- vendord_interface_t* p_itf = &_vendord_itf[i];
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ for (uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
+ vendord_interface_t *p_itf = &_vendord_itf[i];
- #if CFG_TUD_EDPT_DEDICATED_HWFIFO
- #if CFG_TUD_VENDOR_RX_BUFSIZE == 0 // non-fifo rx still need ep buffer
- uint8_t *epout_buf = _vendord_epbuf[i].epout;
- #else
+ #if CFG_TUD_EDPT_DEDICATED_HWFIFO
uint8_t *epout_buf = NULL;
- #endif
-
- uint8_t *epin_buf = NULL;
- #else
+ uint8_t *epin_buf = NULL;
+ #else
uint8_t *epout_buf = _vendord_epbuf[i].epout;
uint8_t *epin_buf = _vendord_epbuf[i].epin;
- #endif
-
- #if CFG_TUD_VENDOR_RX_BUFSIZE > 0
- uint8_t *rx_ff_buf = p_itf->stream.rx_ff_buf;
- #else
- uint8_t *rx_ff_buf = NULL;
- #endif
+ #endif
- tu_edpt_stream_init(&p_itf->stream.rx, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
+ uint8_t *rx_ff_buf = p_itf->rx_ff_buf;
+ tu_edpt_stream_init(&p_itf->rx_stream, false, false, false, rx_ff_buf, CFG_TUD_VENDOR_RX_BUFSIZE, epout_buf,
CFG_TUD_VENDOR_EPSIZE);
- #if CFG_TUD_VENDOR_TX_BUFSIZE > 0
- uint8_t *tx_ff_buf = p_itf->stream.tx_ff_buf;
- #else
- uint8_t *tx_ff_buf = NULL;
- #endif
-
- tu_edpt_stream_init(&p_itf->stream.tx, false, true, false, tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, epin_buf,
+ uint8_t *tx_ff_buf = p_itf->tx_ff_buf;
+ tu_edpt_stream_init(&p_itf->tx_stream, false, true, false, tx_ff_buf, CFG_TUD_VENDOR_TX_BUFSIZE, epin_buf,
CFG_TUD_VENDOR_EPSIZE);
}
+ #endif
}
bool vendord_deinit(void) {
- for(uint8_t i=0; i<CFG_TUD_VENDOR; i++) {
- vendord_interface_t* p_itf = &_vendord_itf[i];
- tu_edpt_stream_deinit(&p_itf->stream.rx);
- tu_edpt_stream_deinit(&p_itf->stream.tx);
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ for (uint8_t i = 0; i < CFG_TUD_VENDOR; i++) {
+ vendord_interface_t *p_itf = &_vendord_itf[i];
+ tu_edpt_stream_deinit(&p_itf->rx_stream);
+ tu_edpt_stream_deinit(&p_itf->tx_stream);
}
+ #endif
return true;
}
@@ -227,11 +243,12 @@ void vendord_reset(uint8_t rhport) {
vendord_interface_t* p_itf = &_vendord_itf[i];
tu_memclr(p_itf, ITF_MEM_RESET_SIZE);
- tu_edpt_stream_clear(&p_itf->stream.rx);
- tu_edpt_stream_close(&p_itf->stream.rx);
-
- tu_edpt_stream_clear(&p_itf->stream.tx);
- tu_edpt_stream_close(&p_itf->stream.tx);
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ tu_edpt_stream_clear(&p_itf->rx_stream);
+ tu_edpt_stream_close(&p_itf->rx_stream);
+ tu_edpt_stream_clear(&p_itf->tx_stream);
+ tu_edpt_stream_close(&p_itf->tx_stream);
+ #endif
}
}
@@ -241,13 +258,25 @@ static uint8_t find_vendor_itf(uint8_t ep_addr) {
const vendord_interface_t *p_vendor = &_vendord_itf[idx];
if (ep_addr == 0) {
// find unused: require both ep == 0
- if (p_vendor->stream.rx.ep_addr == 0 && p_vendor->stream.tx.ep_addr == 0) {
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ if (p_vendor->rx_stream.ep_addr == 0 && p_vendor->tx_stream.ep_addr == 0) {
return idx;
}
- } else if (ep_addr == p_vendor->stream.rx.ep_addr || ep_addr == p_vendor->stream.tx.ep_addr) {
- return idx;
+ #else
+ if (p_vendor->ep_out == 0 && p_vendor->ep_in == 0) {
+ return idx;
+ }
+ #endif
} else {
- // nothing to do
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ if (ep_addr == p_vendor->rx_stream.ep_addr || ep_addr == p_vendor->tx_stream.ep_addr) {
+ return idx;
+ }
+ #else
+ if (ep_addr == p_vendor->ep_out || ep_addr == p_vendor->ep_in) {
+ return idx;
+ }
+ #endif
}
}
return 0xff;
@@ -273,28 +302,39 @@ uint16_t vendord_open(uint8_t rhport, const tusb_desc_interface_t *desc_itf, uin
const tusb_desc_endpoint_t* desc_ep = (const tusb_desc_endpoint_t*) p_desc;
TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
- // open endpoint stream, skip if already opened (multiple IN/OUT endpoints)
+ #if CFG_TUD_VENDOR_TXRX_BUFFERED
+ // open endpoint stream
if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
- tu_edpt_stream_t *stream_tx = &p_vendor->stream.tx;
- if (stream_tx->ep_addr == 0) {
- tu_edpt_stream_open(stream_tx, rhport, desc_ep);
- tu_edpt_stream_write_xfer(stream_tx); // flush pending data
- }
+ tu_edpt_stream_t *tx_stream = &p_vendor->tx_stream;
+ tu_edpt_stream_open(tx_stream, rhport, desc_ep);
+ tu_edpt_stream_write_xfer(tx_stream); // flush pending data
} else {
- tu_edpt_stream_t *stream_rx = &p_vendor->stream.rx;
- if (stream_rx->ep_addr == 0) {
- tu_edpt_stream_open(stream_rx, rhport, desc_ep);
- #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
- TU_ASSERT(tu_edpt_stream_read_xfer(stream_rx) > 0, 0); // prepare for incoming data
- #endif
- }
+ tu_edpt_stream_t *rx_stream = &p_vendor->rx_stream;
+ tu_edpt_stream_open(rx_stream, rhport, desc_ep);
+ #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
+ TU_ASSERT(tu_edpt_stream_read_xfer(rx_stream) > 0, 0); // prepare for incoming data
+ #endif
+ }
+ #else
+ // Non-FIFO mode: store endpoint info
+ if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
+ p_vendor->ep_in = desc_ep->bEndpointAddress;
+ p_vendor->ep_in_mps = tu_edpt_packet_size(desc_ep);
+ } else {
+ p_vendor->ep_out = desc_ep->bEndpointAddress;
+ p_vendor->ep_out_mps = tu_edpt_packet_size(desc_ep);
+ #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
+ // Prepare for incoming data
+ TU_ASSERT(usbd_edpt_xfer(rhport, p_vendor->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false), 0);
+ #endif
}
+ #endif
}
p_desc = tu_desc_next(p_desc);
}
- return (uint16_t) ((uintptr_t) p_desc - (uintptr_t) desc_itf);
+ return (uint16_t)((uintptr_t)p_desc - (uintptr_t)desc_itf);
}
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
@@ -304,34 +344,36 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
TU_VERIFY(idx < CFG_TUD_VENDOR);
vendord_interface_t *p_vendor = &_vendord_itf[idx];
- if (ep_addr == p_vendor->stream.rx.ep_addr) {
- #if CFG_TUD_VENDOR_RX_BUFSIZE
- // Received new data: put into stream's fifo
- tu_edpt_stream_read_xfer_complete(&p_vendor->stream.rx, xferred_bytes);
- #endif
-
- // invoke callback
- #if CFG_TUD_VENDOR_RX_BUFSIZE == 0
- tud_vendor_rx_cb(idx, p_vendor->stream.rx.ep_buf, xferred_bytes);
- #else
+#if CFG_TUD_VENDOR_TXRX_BUFFERED
+ if (ep_addr == p_vendor->rx_stream.ep_addr) {
+ // Put received data to FIFO
+ tu_edpt_stream_read_xfer_complete(&p_vendor->rx_stream, xferred_bytes);
tud_vendor_rx_cb(idx, NULL, 0);
- #endif
-
- #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
- tu_edpt_stream_read_xfer(&p_vendor->stream.rx); // prepare next data
- #endif
- } else if (ep_addr == p_vendor->stream.tx.ep_addr) {
+ #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
+ tu_edpt_stream_read_xfer(&p_vendor->rx_stream); // prepare next data
+ #endif
+ } else if (ep_addr == p_vendor->tx_stream.ep_addr) {
// Send complete
tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
- #if CFG_TUD_VENDOR_TX_BUFSIZE > 0
// try to send more if possible
- if (0 == tu_edpt_stream_write_xfer(&p_vendor->stream.tx)) {
+ if (0 == tu_edpt_stream_write_xfer(&p_vendor->tx_stream)) {
// If there is no data left, a ZLP should be sent if xferred_bytes is multiple of EP Packet size and not zero
- tu_edpt_stream_write_zlp_if_needed(&p_vendor->stream.tx, xferred_bytes);
+ tu_edpt_stream_write_zlp_if_needed(&p_vendor->tx_stream, xferred_bytes);
}
- #endif
}
+ #else
+ if (ep_addr == p_vendor->ep_out) {
+ // Non-FIFO mode: invoke callback with buffer
+ tud_vendor_rx_cb(idx, _vendord_epbuf[idx].epout, xferred_bytes);
+ #if CFG_TUD_VENDOR_RX_MANUAL_XFER == 0
+ usbd_edpt_xfer(rhport, p_vendor->ep_out, _vendord_epbuf[idx].epout, CFG_TUD_VENDOR_EPSIZE, false);
+ #endif
+ } else if (ep_addr == p_vendor->ep_in) {
+ // Send complete
+ tud_vendor_tx_cb(idx, (uint16_t)xferred_bytes);
+ }
+ #endif
return true;
}
diff --git a/src/class/vendor/vendor_device.h b/src/class/vendor/vendor_device.h
index c3de4c49d..101765bb1 100644
--- a/src/class/vendor/vendor_device.h
+++ b/src/class/vendor/vendor_device.h
@@ -50,8 +50,14 @@ extern "C" {
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
#endif
+// Vendor is buffered (FIFO mode) if both TX and RX buffers are configured
+// If either is 0, vendor operates in non-buffered (direct transfer) mode
+#ifndef CFG_TUD_VENDOR_TXRX_BUFFERED
+ #define CFG_TUD_VENDOR_TXRX_BUFFERED ((CFG_TUD_VENDOR_RX_BUFSIZE > 0) && (CFG_TUD_VENDOR_TX_BUFSIZE > 0))
+#endif
+
// Application will manually schedule RX transfer. This can be useful when using with non-fifo (buffered) mode
-// i.e. CFG_TUD_VENDOR_RX_BUFSIZE = 0
+// i.e. CFG_TUD_VENDOR_TXRX_BUFFERED = 0
#ifndef CFG_TUD_VENDOR_RX_MANUAL_XFER
#define CFG_TUD_VENDOR_RX_MANUAL_XFER 0
#endif
@@ -63,7 +69,8 @@ extern "C" {
// Return whether the vendor interface is mounted
bool tud_vendor_n_mounted(uint8_t idx);
-#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
+//------------- RX -------------//
+#if CFG_TUD_VENDOR_TXRX_BUFFERED
// Return number of available bytes for reading
uint32_t tud_vendor_n_available(uint8_t idx);
@@ -82,16 +89,17 @@ void tud_vendor_n_read_flush(uint8_t idx);
bool tud_vendor_n_read_xfer(uint8_t idx);
#endif
+//------------- TX -------------//
// Write to TX FIFO. This can be buffered and not sent immediately unless buffered bytes >= USB endpoint size
uint32_t tud_vendor_n_write(uint8_t idx, const void *buffer, uint32_t bufsize);
-#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
+// Return number of bytes available for writing in TX FIFO (or endpoint if non-buffered)
+uint32_t tud_vendor_n_write_available(uint8_t idx);
+
+#if CFG_TUD_VENDOR_TXRX_BUFFERED
// Force sending buffered data, return number of bytes sent
uint32_t tud_vendor_n_write_flush(uint8_t idx);
-// Return number of bytes available for writing in TX FIFO
-uint32_t tud_vendor_n_write_available(uint8_t idx);
-
// Clear the transmit FIFO
bool tud_vendor_n_write_clear(uint8_t idx);
#endif
@@ -111,7 +119,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_mounted(void) {
return tud_vendor_n_mounted(0);
}
-#if CFG_TUD_VENDOR_RX_BUFSIZE > 0
+#if CFG_TUD_VENDOR_TXRX_BUFFERED
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_available(void) {
return tud_vendor_n_available(0);
}
@@ -127,6 +135,14 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_read(void *buffer, uint3
TU_ATTR_ALWAYS_INLINE static inline void tud_vendor_read_flush(void) {
tud_vendor_n_read_flush(0);
}
+
+TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
+ return tud_vendor_n_write_flush(0);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
+ return tud_vendor_n_write_clear(0);
+}
#endif
#if CFG_TUD_VENDOR_RX_MANUAL_XFER
@@ -143,20 +159,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_str(const char *st
return tud_vendor_n_write_str(0, str);
}
-#if CFG_TUD_VENDOR_TX_BUFSIZE > 0
-TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_flush(void) {
- return tud_vendor_n_write_flush(0);
-}
-
TU_ATTR_ALWAYS_INLINE static inline uint32_t tud_vendor_write_available(void) {
return tud_vendor_n_write_available(0);
}
-TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
- return tud_vendor_n_write_clear(0);
-}
-#endif
-
// backward compatible
#define tud_vendor_flush() tud_vendor_write_flush()
@@ -165,8 +171,8 @@ TU_ATTR_ALWAYS_INLINE static inline bool tud_vendor_write_clear(void) {
//--------------------------------------------------------------------+
// Invoked when received new data.
-// - CFG_TUD_VENDOR_RX_BUFSIZE > 0; buffer and bufsize must not be used (both NULL,0) since data is in RX FIFO
-// - CFG_TUD_VENDOR_RX_BUFSIZE = 0: Buffer and bufsize are valid
+// - CFG_TUD_VENDOR_TXRX_BUFFERED = 1: buffer and bufsize must not be used (both NULL,0) since data is in RX FIFO
+// - CFG_TUD_VENDOR_TXRX_BUFFERED = 0: Buffer and bufsize are valid
void tud_vendor_rx_cb(uint8_t idx, const uint8_t *buffer, uint32_t bufsize);
// Invoked when tx transfer is finished
diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h
index d74760608..6ac1405f3 100644
--- a/src/common/tusb_common.h
+++ b/src/common/tusb_common.h
@@ -329,7 +329,7 @@ TU_ATTR_ALWAYS_INLINE static inline void tu_unaligned_write16(void *mem, uint16_
#endif
-// scatter read 4 bytes from two buffers. Parameter are not checked
+// scatter read 4 bytes from two buffers (LE). Parameter are not checked
TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *buf1, uint8_t len1, const uint8_t *buf2,
uint8_t len2) {
uint32_t result = 0;
@@ -348,7 +348,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t tu_scatter_read32(const uint8_t *bu
return result;
}
-// scatter write 4 bytes to two buffers. Parameter are not checked
+// scatter write 4 bytes (LE) to two buffers. Parameter are not checked
TU_ATTR_ALWAYS_INLINE static inline void tu_scatter_write32(uint32_t value, uint8_t *buf1, uint8_t len1,
uint8_t *buf2, uint8_t len2) {
for (uint8_t i = 0; i < len1; ++i) {
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index e97b6ccce..9f188f296 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -33,7 +33,7 @@
// Suppress IAR warning
// Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement
#if defined(__ICCARM__)
-#pragma diag_suppress = Pa082
+ #pragma diag_suppress = Pa082
#endif
#if OSAL_MUTEX_REQUIRED
@@ -59,7 +59,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ff_unlock(osal_mutex_t mutex) {
//--------------------------------------------------------------------+
// Setup API
//--------------------------------------------------------------------+
-bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable) {
+bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, bool overwritable) {
// Limit index space to 2*depth - this allows for a fast "modulo" calculation
// but limits the maximum depth to 2^16/2 = 2^15 and buffer overflows are detectable
// only if overflow happens once (important for unsupervised DMA applications)
@@ -72,7 +72,6 @@ bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_si
f->buffer = (uint8_t *)buffer;
f->depth = depth;
- f->item_size = (uint16_t)(item_size & 0x7FFFu);
f->overwritable = overwritable;
f->rd_idx = 0u;
f->wr_idx = 0u;
@@ -111,175 +110,306 @@ void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable) {
}
//--------------------------------------------------------------------+
-// Pull & Push
-// copy data to/from fifo without updating read/write pointers
+// Hardware FIFO API
+// Support different data access width and address increment scheme
+// Can support multiple i.e both 16 and 32-bit data access if needed
//--------------------------------------------------------------------+
-#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
-// Copy to fifo from fixed address buffer (usually a rx register) with TU_FIFO_FIXED_ADDR_RW32 mode
-static void ff_push_fixed_addr_rw32(uint8_t *ff_buf, const volatile uint32_t *reg_rx, uint16_t len) {
- // Reading full available 32 bit words from const app address
- uint16_t full_words = len >> 2;
- while (full_words--) {
- const uint32_t tmp32 = *reg_rx;
- tu_unaligned_write32(ff_buf, tmp32);
- ff_buf += 4;
+#if CFG_TUSB_FIFO_HWFIFO_API
+ #if CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
+ #define HWFIFO_ADDR_NEXT_N(_hwfifo, _const, _n) _hwfifo = (_const volatile void *)((uintptr_t)(_hwfifo) + _n)
+ #else
+ #define HWFIFO_ADDR_NEXT_N(_hwfifo, _const, _n)
+ #endif
+
+ #define HWFIFO_ADDR_NEXT(_hwfifo, _const) HWFIFO_ADDR_NEXT_N(_hwfifo, _const, CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE)
+
+//------------- Write -------------//
+ #ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE
+TU_ATTR_ALWAYS_INLINE static inline void stride_write(volatile void *hwfifo, const void *src, uint8_t data_stride) {
+ (void)data_stride; // possible unused
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4
+ if (data_stride == 4)
+ #endif
+ {
+ *((volatile uint32_t *)hwfifo) = tu_unaligned_read32(src);
}
+ #endif
- // Read the remaining 1-3 bytes from const app address
- const uint8_t bytes_rem = len & 0x03;
- if (bytes_rem) {
- const uint32_t tmp32 = *reg_rx;
- memcpy(ff_buf, &tmp32, bytes_rem);
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 2
+ if (data_stride == 2)
+ #endif
+ {
+ *((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
}
+ #endif
+
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
+ *((volatile uint8_t *)hwfifo) = *(const uint8_t *)src;
+ #endif
}
// Copy from fifo to fixed address buffer (usually a tx register) with TU_FIFO_FIXED_ADDR_RW32 mode
-static void ff_pull_fixed_addr_rw32(volatile uint32_t *reg_tx, const uint8_t *ff_buf, uint16_t len) {
- // Write full available 32 bit words to const address
- uint16_t full_words = len >> 2u;
- while (full_words--) {
- *reg_tx = tu_unaligned_read32(ff_buf);
- ff_buf += 4u;
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ // Write full available 16/32 bit words to dest
+ const uint8_t data_stride = (access_mode != NULL) ? access_mode->data_stride : CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE;
+ while (len >= data_stride) {
+ stride_write(hwfifo, src, data_stride);
+ src += data_stride;
+ len -= data_stride;
+ HWFIFO_ADDR_NEXT(hwfifo, );
}
- // Write the remaining 1-3 bytes
- const uint8_t bytes_rem = len & 0x03;
- if (bytes_rem) {
- uint32_t tmp32 = 0u;
- memcpy(&tmp32, ff_buf, bytes_rem);
- *reg_tx = tmp32;
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE > 1
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
+ // 16-bit access is allowed for odd bytes
+ if (len >= 2) {
+ *((volatile uint16_t *)hwfifo) = tu_unaligned_read16(src);
+ src += 2;
+ len -= 2;
+ HWFIFO_ADDR_NEXT_N(hwfifo, , 2);
}
-}
-#endif
-
-// send n items to fifo WITHOUT updating write pointer
-static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr,
- tu_fifo_access_mode_t copy_mode) {
- const uint16_t lin_count = f->depth - wr_ptr;
- const uint16_t wrap_count = n - lin_count;
+ #endif
- uint16_t lin_bytes = lin_count * f->item_size;
- uint16_t wrap_bytes = wrap_count * f->item_size;
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
+ // 8-bit access is allowed for odd bytes
+ while (len > 0) {
+ *((volatile uint8_t *)hwfifo) = *src++;
+ len--;
+ HWFIFO_ADDR_NEXT_N(hwfifo, , 1);
+ }
+ #else
- // current buffer of fifo
- uint8_t *ff_buf = f->buffer + (wr_ptr * f->item_size);
+ // Write odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit
+ if (len > 0) {
+ uint32_t tmp = 0u;
+ memcpy(&tmp, src, len);
+ stride_write(hwfifo, &tmp, data_stride);
+ HWFIFO_ADDR_NEXT(hwfifo, );
+ }
+ #endif
+ #endif
+}
+ #endif
- switch (copy_mode) {
- case TU_FIFO_INC_ADDR_RW8:
- if (n <= lin_count) {
- // Linear only
- memcpy(ff_buf, app_buf, n * f->item_size);
- } else {
- // Wrap around
- memcpy(ff_buf, app_buf, lin_bytes); // linear part
- memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part
- }
- break;
+//------------- Read -------------//
+ #ifndef CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ
+TU_ATTR_ALWAYS_INLINE static inline void stride_read(const volatile void *hwfifo, void *dest, uint8_t data_stride) {
+ (void)data_stride; // possible unused
-#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
- case TU_FIFO_FIXED_ADDR_RW32: {
- const volatile uint32_t *reg_rx = (volatile const uint32_t *)app_buf;
- if (n <= lin_count) {
- // Linear only
- ff_push_fixed_addr_rw32(ff_buf, reg_rx, n * f->item_size);
- } else {
- // Wrap around
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 4
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 4
+ if (data_stride == 4)
+ #endif
+ {
+ tu_unaligned_write32(dest, *((const volatile uint32_t *)hwfifo));
+ }
+ #endif
- // Write full words to linear part of buffer
- uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
- ff_push_fixed_addr_rw32(ff_buf, reg_rx, lin_4n_bytes);
- ff_buf += lin_4n_bytes;
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE & 2
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE != 2
+ if (data_stride == 2)
+ #endif
+ {
+ tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
+ }
+ #endif
- // There could be odd 1-3 bytes before the wrap-around boundary
- const uint8_t rem = lin_bytes & 0x03;
- if (rem > 0) {
- const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem);
- const uint32_t tmp32 = *reg_rx;
- tu_scatter_write32(tmp32, ff_buf, rem, f->buffer, remrem);
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
+ *(uint8_t *)dest = *((const volatile uint8_t *)hwfifo);
+ #endif
+}
- wrap_bytes -= remrem;
- ff_buf = f->buffer + remrem; // wrap around
- } else {
- ff_buf = f->buffer; // wrap around to beginning
- }
+void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ // Reading full available 16/32-bit hwfifo and write to fifo
+ const uint8_t data_stride = (access_mode != NULL) ? access_mode->data_stride : CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE;
+ while (len >= data_stride) {
+ stride_read(hwfifo, dest, data_stride);
+ dest += data_stride;
+ len -= data_stride;
+ HWFIFO_ADDR_NEXT(hwfifo, const);
+ }
- // Write data wrapped part
- if (wrap_bytes > 0) {
- ff_push_fixed_addr_rw32(ff_buf, reg_rx, wrap_bytes);
- }
- }
- break;
- }
-#endif
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE > 1
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS
+ // 16-bit access is allowed for odd bytes
+ if (len >= 2) {
+ tu_unaligned_write16(dest, *((const volatile uint16_t *)hwfifo));
+ dest += 2;
+ len -= 2;
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, 2);
+ }
+ #endif
- default:
- break; // unknown mode
+ #ifdef CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS
+ // 8-bit access is allowed for odd bytes
+ while (len > 0) {
+ *dest++ = *((const volatile uint8_t *)hwfifo);
+ len--;
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, 1);
+ }
+ #else
+ // Read odd bytes i.e 1 byte for 16 bit or 1-3 bytes for 32 bit
+ if (len > 0) {
+ uint32_t tmp;
+ stride_read(hwfifo, &tmp, data_stride);
+ memcpy(dest, &tmp, len);
+ HWFIFO_ADDR_NEXT(hwfifo, const);
}
+ #endif
+ #endif
}
+ #endif
-// get n items from fifo WITHOUT updating read pointer
-static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr, tu_fifo_access_mode_t copy_mode) {
- const uint16_t lin_count = f->depth - rd_ptr;
- const uint16_t wrap_count = n - lin_count; // only used if wrapped
+// push to sw fifo from hwfifo
+static void hwff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr,
+ const tu_hwfifo_access_t *access_mode) {
+ uint16_t lin_bytes = f->depth - wr_ptr;
+ uint16_t wrap_bytes = n - lin_bytes;
+ uint8_t *ff_buf = f->buffer + wr_ptr;
- uint16_t lin_bytes = lin_count * f->item_size;
- uint16_t wrap_bytes = wrap_count * f->item_size;
+ const volatile void *hwfifo = (const volatile void *)app_buf;
+ if (n <= lin_bytes) {
+ // Linear only case
+ tu_hwfifo_read(hwfifo, ff_buf, n, access_mode);
+ } else {
+ // Wrap around case
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
+ tu_hwfifo_read(hwfifo, ff_buf, lin_bytes, access_mode); // linear part
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, lin_bytes);
+ tu_hwfifo_read(hwfifo, f->buffer, wrap_bytes, access_mode); // wrapped part
+ #else
+ // Write full words to linear part of buffer
+ const uint8_t data_stride = access_mode->data_stride;
+ const uint32_t odd_mask = data_stride - 1;
+ uint16_t lin_even = lin_bytes & ~odd_mask;
+ tu_hwfifo_read(hwfifo, ff_buf, lin_even, access_mode);
+ HWFIFO_ADDR_NEXT_N(hwfifo, const, lin_even);
+ ff_buf += lin_even;
- // current buffer of fifo
- const uint8_t *ff_buf = f->buffer + (rd_ptr * f->item_size);
+ // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
+ // combine it with the wrapped part to form a full word for data stride
+ const uint8_t lin_odd = lin_bytes & odd_mask;
+ if (lin_odd > 0) {
+ const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
+ uint8_t buf_temp[4];
+ tu_hwfifo_read(hwfifo, buf_temp, lin_odd + wrap_odd, access_mode);
+ HWFIFO_ADDR_NEXT(hwfifo, const);
- switch (copy_mode) {
- case TU_FIFO_INC_ADDR_RW8:
- if (n <= lin_count) {
- // Linear only
- memcpy(app_buf, ff_buf, n * f->item_size);
- } else {
- // Wrap around
- memcpy(app_buf, ff_buf, lin_bytes); // linear part
- memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part
+ for (uint8_t i = 0; i < lin_odd; ++i) {
+ ff_buf[i] = buf_temp[i];
+ }
+ for (uint8_t i = 0; i < wrap_odd; ++i) {
+ f->buffer[i] = buf_temp[lin_odd + i];
}
- break;
-#ifdef CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
- case TU_FIFO_FIXED_ADDR_RW32: {
- volatile uint32_t *reg_tx = (volatile uint32_t *)app_buf;
+ wrap_bytes -= wrap_odd;
+ ff_buf = f->buffer + wrap_odd; // wrap around
+ } else {
+ ff_buf = f->buffer; // wrap around to beginning
+ }
- if (n <= lin_count) {
- // Linear only
- ff_pull_fixed_addr_rw32(reg_tx, ff_buf, n * f->item_size);
- } else {
- // Wrap around case
+ // Write data wrapped part
+ if (wrap_bytes > 0) {
+ tu_hwfifo_read(hwfifo, ff_buf, wrap_bytes, access_mode);
+ }
+ #endif
+ }
+}
- // Read full words from linear part
- uint16_t lin_4n_bytes = lin_bytes & 0xFFFC;
- ff_pull_fixed_addr_rw32(reg_tx, ff_buf, lin_4n_bytes);
- ff_buf += lin_4n_bytes;
+// pull from sw fifo to hwfifo
+static void hwff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr,
+ const tu_hwfifo_access_t *access_mode) {
+ uint16_t lin_bytes = f->depth - rd_ptr;
+ uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped
+ const uint8_t *ff_buf = f->buffer + rd_ptr;
- // There could be odd 1-3 bytes before the wrap-around boundary
- const uint8_t rem = lin_bytes & 0x03;
- if (rem > 0) {
- const uint8_t remrem = (uint8_t)tu_min16(wrap_bytes, 4 - rem);
- const uint32_t scatter32 = tu_scatter_read32(ff_buf, rem, f->buffer, remrem);
+ volatile void *hwfifo = (volatile void *)app_buf;
- *reg_tx = scatter32;
+ if (n <= lin_bytes) {
+ // Linear only case
+ tu_hwfifo_write(hwfifo, ff_buf, n, access_mode);
+ } else {
+ // Wrap around case
+ #if CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE == 1
+ tu_hwfifo_write(hwfifo, ff_buf, lin_bytes, access_mode); // linear part
+ HWFIFO_ADDR_NEXT_N(hwfifo, , lin_bytes);
+ tu_hwfifo_write(hwfifo, f->buffer, wrap_bytes, access_mode); // wrapped part
+ #else
+ // Read full words from linear part
+ const uint8_t data_stride = access_mode->data_stride;
+ const uint32_t odd_mask = data_stride - 1;
+ uint16_t lin_even = lin_bytes & ~odd_mask;
+ tu_hwfifo_write(hwfifo, ff_buf, lin_even, access_mode);
+ HWFIFO_ADDR_NEXT_N(hwfifo, , lin_even);
+ ff_buf += lin_even;
- wrap_bytes -= remrem;
- ff_buf = f->buffer + remrem; // wrap around
- } else {
- ff_buf = f->buffer; // wrap around to beginning
- }
+ // There could be odd 1 byte (16bit) or 1-3 bytes (32bit) before the wrap-around boundary
+ const uint8_t lin_odd = lin_bytes & odd_mask;
+ if (lin_odd > 0) {
+ const uint8_t wrap_odd = (uint8_t)tu_min16(wrap_bytes, data_stride - lin_odd);
- // Read data wrapped part
- if (wrap_bytes > 0) {
- ff_pull_fixed_addr_rw32(reg_tx, ff_buf, wrap_bytes);
- }
+ uint8_t buf_temp[4];
+ for (uint8_t i = 0; i < lin_odd; ++i) {
+ buf_temp[i] = ff_buf[i];
}
- break;
+ for (uint8_t i = 0; i < wrap_odd; ++i) {
+ buf_temp[lin_odd + i] = f->buffer[i];
+ }
+
+ tu_hwfifo_write(hwfifo, buf_temp, lin_odd + wrap_odd, access_mode);
+ HWFIFO_ADDR_NEXT(hwfifo, );
+
+ wrap_bytes -= wrap_odd;
+ ff_buf = f->buffer + wrap_odd; // wrap around
+ } else {
+ ff_buf = f->buffer; // wrap around to beginning
}
+
+ // Read data wrapped part
+ if (wrap_bytes > 0) {
+ tu_hwfifo_write(hwfifo, ff_buf, wrap_bytes, access_mode);
+ }
+ #endif
+ }
+}
#endif
- default:
- break; // unknown mode
+//--------------------------------------------------------------------+
+// Pull & Push
+// copy data to/from fifo without updating read/write pointers
+//--------------------------------------------------------------------+
+// send n items to fifo WITHOUT updating write pointer
+static void ff_push_n(const tu_fifo_t *f, const void *app_buf, uint16_t n, uint16_t wr_ptr) {
+ uint16_t lin_bytes = f->depth - wr_ptr;
+ uint16_t wrap_bytes = n - lin_bytes;
+ uint8_t *ff_buf = f->buffer + wr_ptr;
+
+ if (n <= lin_bytes) {
+ // Linear only case
+ memcpy(ff_buf, app_buf, n);
+ } else {
+ // Wrap around case
+ memcpy(ff_buf, app_buf, lin_bytes); // linear part
+ memcpy(f->buffer, ((const uint8_t *)app_buf) + lin_bytes, wrap_bytes); // wrapped part
+ }
+}
+
+// get n items from fifo WITHOUT updating read pointer
+static void ff_pull_n(const tu_fifo_t *f, void *app_buf, uint16_t n, uint16_t rd_ptr) {
+ uint16_t lin_bytes = f->depth - rd_ptr;
+ uint16_t wrap_bytes = n - lin_bytes; // only used if wrapped
+ const uint8_t *ff_buf = f->buffer + rd_ptr;
+
+ // single byte access
+ if (n <= lin_bytes) {
+ // Linear only
+ memcpy(app_buf, ff_buf, n);
+ } else {
+ // Wrap around
+ memcpy(app_buf, ff_buf, lin_bytes); // linear part
+ memcpy((uint8_t *)app_buf + lin_bytes, f->buffer, wrap_bytes); // wrapped part
}
}
@@ -332,7 +462,7 @@ static uint16_t correct_read_index(tu_fifo_t *f, uint16_t wr_idx) {
// Works on local copies of w and r
// Must be protected by read mutex since in case of an overflow read pointer gets modified
uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx,
- tu_fifo_access_mode_t access_mode) {
+ const tu_hwfifo_access_t *access_mode) {
uint16_t count = tu_ff_overflow_count(f->depth, wr_idx, rd_idx);
if (count == 0) {
return 0; // nothing to peek
@@ -349,7 +479,16 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui
}
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
- ff_pull_n(f, p_buffer, n, rd_ptr, access_mode);
+
+#if CFG_TUSB_FIFO_HWFIFO_API
+ if (access_mode != NULL) {
+ hwff_pull_n(f, p_buffer, n, rd_ptr, access_mode);
+ } else
+#endif
+ {
+ (void)access_mode;
+ ff_pull_n(f, p_buffer, n, rd_ptr);
+ }
return n;
}
@@ -357,13 +496,13 @@ uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, ui
// Read n items without removing it from the FIFO, correct read pointer if overflowed
uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n) {
ff_lock(f->mutex_rd);
- const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, TU_FIFO_INC_ADDR_RW8);
+ const uint16_t ret = tu_fifo_peek_n_access_mode(f, p_buffer, n, f->wr_idx, f->rd_idx, NULL);
ff_unlock(f->mutex_rd);
return ret;
}
// Read n items from fifo with access mode
-uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode) {
+uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, const tu_hwfifo_access_t *access_mode) {
ff_lock(f->mutex_rd);
// Peek the data: f->rd_idx might get modified in case of an overflow so we can not use a local variable
@@ -375,7 +514,8 @@ uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_f
}
// Write n items to fifo with access mode
-uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode) {
+uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
+ const tu_hwfifo_access_t *access_mode) {
if (n == 0) {
return 0;
}
@@ -401,8 +541,8 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
// function! Since it would end up in a race condition with read functions!
if (n >= f->depth) {
// Only copy last part
- if (access_mode == TU_FIFO_INC_ADDR_RW8) {
- buf8 += (n - f->depth) * f->item_size;
+ if (access_mode == NULL) {
+ buf8 += (n - f->depth);
} else {
// TODO should read from hw fifo to discard data, however reading an odd number could
// accidentally discard data.
@@ -437,7 +577,14 @@ uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n,
const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
TU_LOG(TU_FIFO_DBG, "actual_n = %u, wr_ptr = %u", n, wr_ptr);
- ff_push_n(f, buf8, n, wr_ptr, access_mode);
+#if CFG_TUSB_FIFO_HWFIFO_API
+ if (access_mode != NULL) {
+ hwff_push_n(f, buf8, n, wr_ptr, access_mode);
+ } else
+#endif
+ {
+ ff_push_n(f, buf8, n, wr_ptr);
+ }
f->wr_idx = advance_index(f->depth, wr_idx, n);
TU_LOG(TU_FIFO_DBG, "\tnew_wr = %u\r\n", f->wr_idx);
@@ -477,7 +624,7 @@ static bool ff_peek_local(tu_fifo_t *f, void *buf, uint16_t wr_idx, uint16_t rd_
}
const uint16_t rd_ptr = idx2ptr(f->depth, rd_idx);
- memcpy(buf, f->buffer + (rd_ptr * f->item_size), f->item_size);
+ memcpy(buf, f->buffer + rd_ptr, 1);
return true;
}
@@ -512,7 +659,7 @@ bool tu_fifo_write(tu_fifo_t *f, const void *data) {
ret = false;
} else {
const uint16_t wr_ptr = idx2ptr(f->depth, wr_idx);
- memcpy(f->buffer + (wr_ptr * f->item_size), data, f->item_size);
+ memcpy(f->buffer + wr_ptr, data, 1);
f->wr_idx = advance_index(f->depth, wr_idx, 1);
ret = true;
}
@@ -678,6 +825,6 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info) {
} else {
info->linear.len = f->depth - wr_ptr;
info->wrapped.len = remain - info->linear.len; // Remaining length - n already was limited to remain or FIFO depth
- info->wrapped.ptr = f->buffer; // Always start of buffer
+ info->wrapped.ptr = f->buffer; // Always start of buffer
}
}
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
index 2e2a0db6f..86ba59059 100644
--- a/src/common/tusb_fifo.h
+++ b/src/common/tusb_fifo.h
@@ -32,6 +32,25 @@
extern "C" {
#endif
+#include "common/tusb_common.h"
+#include "osal/osal.h"
+
+//--------------------------------------------------------------------+
+// Configuration
+//--------------------------------------------------------------------+
+// mutex is only needed for RTOS. For OS None, we don't get preempted
+#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED
+
+#define CFG_TUSB_FIFO_HWFIFO_API (CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO)
+
+#ifndef CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 0
+#endif
+
+#ifndef CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0
+#endif
+
// Due to the use of unmasked pointers, this FIFO does not suffer from losing
// one item slice. Furthermore, write and read operations are completely
// decoupled as write and read functions do not modify a common state. Henceforth,
@@ -41,17 +60,6 @@ extern "C" {
// read pointers can be updated from within a DMA ISR. Overflows are detectable
// within a certain number (see tu_fifo_overflow()).
-#include "common/tusb_common.h"
-#include "osal/osal.h"
-
-// mutex is only needed for RTOS
-// for OS None, we don't get preempted
-#define CFG_FIFO_MUTEX OSAL_MUTEX_REQUIRED
-
-#if CFG_TUD_EDPT_DEDICATED_HWFIFO || CFG_TUH_EDPT_DEDICATED_HWFIFO
- #define CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
-#endif
-
/* Write/Read "pointer" is in the range of: 0 .. depth - 1, and is used to get the fifo data.
* Write/Read "index" is always in the range of: 0 .. 2*depth-1
*
@@ -111,20 +119,16 @@ extern "C" {
typedef struct {
uint8_t *buffer; // buffer pointer
uint16_t depth; // max items
+ bool overwritable; // overwritable when full
+ // 1 byte padding here
- struct TU_ATTR_PACKED {
- uint16_t item_size : 15; // size of each item
- bool overwritable : 1; // ovwerwritable when full
- };
-
- volatile uint16_t wr_idx; // write index
+ volatile uint16_t wr_idx; // write index TODO maybe can drop volatile
volatile uint16_t rd_idx; // read index
#if OSAL_MUTEX_REQUIRED
osal_mutex_t mutex_wr;
osal_mutex_t mutex_rd;
#endif
-
} tu_fifo_t;
typedef struct {
@@ -134,29 +138,32 @@ typedef struct {
} linear, wrapped;
} tu_fifo_buffer_info_t;
-#define TU_FIFO_INIT(_buffer, _depth, _type, _overwritable) \
- { \
- .buffer = _buffer, \
- .depth = _depth, \
- .item_size = sizeof(_type), \
- .overwritable = _overwritable, \
+// Access mode for hardware fifo read/write
+typedef struct {
+ uint8_t data_stride;
+ uintptr_t param;
+} tu_hwfifo_access_t;
+
+#define TU_FIFO_INIT(_buffer, _depth, _overwritable) \
+ { \
+ .buffer = _buffer, \
+ .depth = _depth, \
+ .overwritable = _overwritable, \
}
-#define TU_FIFO_DEF(_name, _depth, _type, _overwritable) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _type, _overwritable)
+#define TU_FIFO_DEF(_name, _depth, _overwritable) \
+ uint8_t _name##_buf[_depth]; \
+ tu_fifo_t _name = TU_FIFO_INIT(_name##_buf, _depth, _overwritable)
-// Write modes intended to allow special read and write functions to be able to
-// copy data to and from USB hardware FIFOs as needed for e.g. STM32s and others
-typedef enum {
- TU_FIFO_INC_ADDR_RW8, // increased address read/write by bytes - normal (default) mode
- TU_FIFO_FIXED_ADDR_RW32, // fixed address read/write by 4 bytes (word). Used for STM32 access into USB hardware FIFO
-} tu_fifo_access_mode_t;
+// Moving data from tusb_fifo <-> USB hardware FIFOs e.g. STM32s need to use a special stride mode which reads/writes
+// data in 2/4 byte chunks from/to a fixed address (USB FIFO register) instead of incrementing the address. For this use
+// read/write access_mode with stride_mode = true. The STRIDE DATA and ADDR stride must be configured with
+// CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE and CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE
//--------------------------------------------------------------------+
// Setup API
//--------------------------------------------------------------------+
-bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, uint16_t item_size, bool overwritable);
+bool tu_fifo_config(tu_fifo_t *f, void *buffer, uint16_t depth, bool overwritable);
void tu_fifo_set_overwritable(tu_fifo_t *f, bool overwritable);
void tu_fifo_clear(tu_fifo_t *f);
@@ -191,7 +198,7 @@ void tu_fifo_get_write_info(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
// peek() will correct/re-index read pointer in case of an overflowed fifo to form a full fifo
//--------------------------------------------------------------------+
uint16_t tu_fifo_peek_n_access_mode(tu_fifo_t *f, void *p_buffer, uint16_t n, uint16_t wr_idx, uint16_t rd_idx,
- tu_fifo_access_mode_t access_mode);
+ const tu_hwfifo_access_t *access_mode);
bool tu_fifo_peek(tu_fifo_t *f, void *p_buffer);
uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n);
@@ -199,10 +206,10 @@ uint16_t tu_fifo_peek_n(tu_fifo_t *f, void *p_buffer, uint16_t n);
// Read API
// peek() + advance read index
//--------------------------------------------------------------------+
-uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, tu_fifo_access_mode_t access_mode);
+uint16_t tu_fifo_read_n_access_mode(tu_fifo_t *f, void *buffer, uint16_t n, const tu_hwfifo_access_t *access_mode);
bool tu_fifo_read(tu_fifo_t *f, void *buffer);
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_read_n(tu_fifo_t *f, void *buffer, uint16_t n) {
- return tu_fifo_read_n_access_mode(f, buffer, n, TU_FIFO_INC_ADDR_RW8);
+ return tu_fifo_read_n_access_mode(f, buffer, n, NULL);
}
// discard first n items from fifo i.e advance read pointer by n with mutex
@@ -212,12 +219,41 @@ uint16_t tu_fifo_discard_n(tu_fifo_t *f, uint16_t n);
//--------------------------------------------------------------------+
// Write API
//--------------------------------------------------------------------+
-uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, tu_fifo_access_mode_t access_mode);
+uint16_t tu_fifo_write_n_access_mode(tu_fifo_t *f, const void *data, uint16_t n, const tu_hwfifo_access_t *access_mode);
bool tu_fifo_write(tu_fifo_t *f, const void *data);
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_fifo_write_n(tu_fifo_t *f, const void *data, uint16_t n) {
- return tu_fifo_write_n_access_mode(f, data, n, TU_FIFO_INC_ADDR_RW8);
+ return tu_fifo_write_n_access_mode(f, data, n, NULL);
+}
+
+//--------------------------------------------------------------------+
+// Hardware FIFO API
+// Special hardware FIFO/Buffer to hold USB data, usually requires certain access method these can be configured with
+// CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (data width) and CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE (address increment)
+// Note: these usually has opposite direction (read/write) to/from our software FIFO (tu_fifo_t)
+//--------------------------------------------------------------------+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_write_from_fifo(volatile void *hwfifo, tu_fifo_t *f, uint16_t n,
+ const tu_hwfifo_access_t *access_mode) {
+ const tu_hwfifo_access_t default_access = {.data_stride = CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE, .param = 0};
+ return tu_fifo_read_n_access_mode(f, (void *)(uintptr_t)hwfifo, n,
+ (access_mode != NULL) ? access_mode : &default_access);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_hwfifo_read_to_fifo(const volatile void *hwfifo, tu_fifo_t *f,
+ uint16_t n, const tu_hwfifo_access_t *access_mode) {
+ const tu_hwfifo_access_t default_access = {.data_stride = CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE, .param = 0};
+ return tu_fifo_write_n_access_mode(f, (const void *)(uintptr_t)hwfifo, n,
+ (access_mode != NULL) ? access_mode : &default_access);
}
+#if CFG_TUSB_FIFO_HWFIFO_API
+// read from hwfifo to buffer
+void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode);
+
+// write to hwfifo from buffer with access mode
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode);
+
+#endif
+
//--------------------------------------------------------------------+
// Internal Helper Local
// work on local copies of read/write indices in order to only access them once for re-entrancy
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 55f7e0b7c..5b9497b9a 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -184,10 +184,15 @@
//--------------------------------------------------------------------+
// ST
//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
+
#elif TU_CHECK_MCU(OPT_MCU_STM32F0)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
#elif TU_CHECK_MCU(OPT_MCU_STM32F1)
// - F102, F103 use fsdev
@@ -203,7 +208,7 @@
defined(STM32F103xE) || defined(STM32F103xG)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#else
#error "Unsupported STM32F1 mcu"
#endif
@@ -218,7 +223,16 @@
#elif TU_CHECK_MCU(OPT_MCU_STM32F3)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+
+ #if defined(STM32F302xB) || defined(STM32F302xC) || defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
+ #elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \
+ defined(STM32F303xD) || defined(STM32F303xE)
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
+ #else
+ #error "Unsupported STM32F3 mcu"
+ #endif
#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
#define TUP_USBIP_DWC2
@@ -244,49 +258,63 @@
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
+#elif TU_CHECK_MCU(OPT_MCU_STM32G0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
+ // Device controller
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
+
+ // TypeC controller
+ #define TUP_USBIP_TYPEC_STM32
+ #define TUP_TYPEC_RHPORTS_NUM 1
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
+
#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
- #include "stm32h7xx.h"
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
#define TUP_DCD_ENDPOINT_MAX 9
- #if __CORTEX_M == 7
+ #ifndef CORE_CM4
// Enable dcache if DMA is enabled
#define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
#define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
#endif
-#elif TU_CHECK_MCU(OPT_MCU_STM32H5)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6)
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
-#elif TU_CHECK_MCU(OPT_MCU_STM32G4)
- // Device controller
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
+ // FS has 6, HS has 9
+ #define TUP_DCD_ENDPOINT_MAX 9
- // TypeC controller
- #define TUP_USBIP_TYPEC_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
- #define TUP_TYPEC_RHPORTS_NUM 1
+ // MCU with on-chip HS Phy
+ #define TUP_RHPORT_HIGHSPEED 1
-#elif TU_CHECK_MCU(OPT_MCU_STM32G0)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ // Enable dcache if DMA is enabled
+ #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
+ #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
+ #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
-#elif TU_CHECK_MCU(OPT_MCU_STM32C0)
+#elif TU_CHECK_MCU(OPT_MCU_STM32L0)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
-#elif TU_CHECK_MCU(OPT_MCU_STM32L0, OPT_MCU_STM32L1)
+#elif TU_CHECK_MCU(OPT_MCU_STM32L1)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#elif TU_CHECK_MCU(OPT_MCU_STM32L4)
// - L4x2, L4x3 use fsdev
@@ -303,28 +331,32 @@
defined(STM32L442xx) || defined(STM32L443xx) || defined(STM32L452xx) || defined(STM32L462xx)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
#else
#error "Unsupported STM32L4 mcu"
#endif
-#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
+#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE (1024u)
-#elif TU_CHECK_MCU(OPT_MCU_STM32WBA)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_STM32
- #define TUP_DCD_ENDPOINT_MAX 9
- #define TUP_RHPORT_HIGHSPEED 1
+#elif TU_CHECK_MCU(OPT_MCU_STM32U0)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
+
+#elif TU_CHECK_MCU(OPT_MCU_STM32U3)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
+ // U535/545 use fsdev
#if defined(STM32U535xx) || defined(STM32U545xx)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
-
+ #define CFG_TUSB_FSDEV_PMA_SIZE 2048u
#else
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
@@ -339,35 +371,16 @@
#endif
#endif
-#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32U0)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_STM32U3)
+#elif TU_CHECK_MCU(OPT_MCU_STM32WB)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_STM32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 1024u
-#elif TU_CHECK_MCU(OPT_MCU_STM32H7RS, OPT_MCU_STM32N6)
+#elif TU_CHECK_MCU(OPT_MCU_STM32WBA)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
-
- // FS has 6, HS has 9
- #define TUP_DCD_ENDPOINT_MAX 9
-
- // MCU with on-chip HS Phy
- #define TUP_RHPORT_HIGHSPEED 1
-
- // Enable dcache if DMA is enabled
- #define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
- #define CFG_TUSB_MEM_DCACHE_LINE_SIZE_DEFAULT 32
+ #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_RHPORT_HIGHSPEED 1
//--------------------------------------------------------------------+
// Sony
@@ -423,10 +436,6 @@
#define TUP_MCU_MULTIPLE_CORE 1
#endif
- // Disable slave if DMA is enabled
- #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
-
#elif TU_CHECK_MCU(OPT_MCU_ESP32P4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_ESP32
@@ -439,10 +448,6 @@
#define TUP_MCU_MULTIPLE_CORE 1
- // Disable slave if DMA is enabled
- #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE
-
// Enable dcache if DMA is enabled
#define CFG_TUD_MEM_DCACHE_ENABLE_DEFAULT CFG_TUD_DWC2_DMA_ENABLE
#define CFG_TUH_MEM_DCACHE_ENABLE_DEFAULT CFG_TUH_DWC2_DMA_ENABLE
@@ -574,6 +579,7 @@
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_CH32
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
// default to FSDEV for device
#if !defined(CFG_TUD_WCH_USBIP_USBFS)
@@ -619,32 +625,17 @@
//--------------------------------------------------------------------+
// ArteryTek
//--------------------------------------------------------------------+
-#elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407)
+#elif TU_CHECK_MCU(OPT_MCU_AT32F403A_407, OPT_MCU_AT32F413)
#define TUP_USBIP_FSDEV
#define TUP_USBIP_FSDEV_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_AT32F413)
- #define TUP_USBIP_FSDEV
- #define TUP_USBIP_FSDEV_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
+ #define CFG_TUSB_FSDEV_PMA_SIZE 512u
#elif TU_CHECK_MCU(OPT_MCU_AT32F415)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_AT32
#define TUP_DCD_ENDPOINT_MAX 4
-#elif TU_CHECK_MCU(OPT_MCU_AT32F435_437)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_AT32F423)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
-
-#elif TU_CHECK_MCU(OPT_MCU_AT32F402_405)
+#elif TU_CHECK_MCU(OPT_MCU_AT32F402_405, OPT_MCU_AT32F423, OPT_MCU_AT32F425, OPT_MCU_AT32F435_437, OPT_MCU_AT32F45X)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_AT32
#define TUP_DCD_ENDPOINT_MAX 8
@@ -656,11 +647,6 @@
#define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
#endif
-#elif TU_CHECK_MCU(OPT_MCU_AT32F425)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_AT32
- #define TUP_DCD_ENDPOINT_MAX 8
-
//--------------------------------------------------------------------+
// HPMicro
//--------------------------------------------------------------------+
@@ -675,10 +661,7 @@
#endif
-//--------------------------------------------------------------------+
// External USB controller
-//--------------------------------------------------------------------+
-
#if defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421
#ifndef CFG_TUH_MAX3421_ENDPOINT_TOTAL
#define CFG_TUH_MAX3421_ENDPOINT_TOTAL (8 + 4 * (CFG_TUH_DEVICE_MAX - 1))
@@ -690,6 +673,10 @@
// Default Values
//--------------------------------------------------------------------+
+#if defined(TUP_USBIP_FSDEV)
+ #define TUP_DCD_ENDPOINT_MAX 8
+#endif
+
#ifndef TUP_MCU_MULTIPLE_CORE
#define TUP_MCU_MULTIPLE_CORE 0
#endif
diff --git a/src/common/tusb_private.h b/src/common/tusb_private.h
index 10e12c2af..43ce7a1df 100644
--- a/src/common/tusb_private.h
+++ b/src/common/tusb_private.h
@@ -37,14 +37,6 @@
// Configuration
//--------------------------------------------------------------------+
-#if CFG_TUD_ENABLED && CFG_TUD_VENDOR && (CFG_TUD_VENDOR_TX_BUFSIZE == 0 || CFG_TUD_VENDOR_RX_BUFSIZE == 0)
- #define CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED 1
-#endif
-
-#ifndef CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
- #define CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED 0
-#endif
-
#define TUP_USBIP_CONTROLLER_NUM 2
extern tusb_role_t _tusb_rhport_role[TUP_USBIP_CONTROLLER_NUM];
diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h
index d473e53e6..7d26ac74e 100644
--- a/src/common/tusb_types.h
+++ b/src/common/tusb_types.h
@@ -554,7 +554,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_number(uint8_t addr) {
}
TU_ATTR_ALWAYS_INLINE static inline uint8_t tu_edpt_addr(uint8_t num, uint8_t dir) {
- return (uint8_t) (num | (dir == TUSB_DIR_IN ? TUSB_DIR_IN_MASK : 0u));
+ return (uint8_t) (num | (dir == (uint8_t)TUSB_DIR_IN ? (uint8_t)TUSB_DIR_IN_MASK : 0u));
}
TU_ATTR_ALWAYS_INLINE static inline uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const* desc_ep) {
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 587554e7f..c9e06361c 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -96,10 +96,12 @@
* - TU_VERIFY_1ARGS : return false if failed
* - TU_VERIFY_2ARGS : return provided value if failed
*------------------------------------------------------------------*/
-#define TU_VERIFY_DEFINE(_cond, _ret) \
- do { \
- if (!(_cond)) { return _ret; } \
- } while(0)
+#define TU_VERIFY_DEFINE(_cond, _ret) \
+ do { \
+ if (!(_cond)) { \
+ return _ret; \
+ } \
+ } while (0)
#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false)
#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret)
diff --git a/src/device/usbd.c b/src/device/usbd.c
index 1e21c667a..cca4169d7 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -666,8 +666,14 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
return;
}
- // Loop until there is no more events in the queue
- while (1) {
+ // Loop until there are no more events in the queue or CFG_TUD_TASK_EVENTS_PER_RUN is reached
+ for (unsigned epr = 0;; epr++) {
+#if CFG_TUD_TASK_EVENTS_PER_RUN > 0
+ if (epr >= CFG_TUD_TASK_EVENTS_PER_RUN) {
+ TU_LOG_USBD("USBD event limit (" TU_XSTRING(CFG_TUD_TASK_EVENTS_PER_RUN) ") reached\r\n");
+ break;
+ }
+#endif
dcd_event_t event;
if (!osal_queue_receive(_usbd_q, &event, timeout_ms)) {
return;
diff --git a/src/device/usbd.h b/src/device/usbd.h
index bd5a3c395..4016a45a4 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -819,7 +819,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
/* Interface */ \
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUD_DFU_APP_CLASS, TUD_DFU_APP_SUBCLASS, DFU_PROTOCOL_RT, _stridx, \
/* Function */ \
- 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
+ 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0110)
//--------------------------------------------------------------------+
// DFU Descriptor Templates
@@ -833,7 +833,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
#define TUD_DFU_DESCRIPTOR(_itfnum, _alt_count, _stridx, _attr, _timeout, _xfer_size) \
TU_XSTRCAT(TUD_DFU_ALT_,_alt_count)(_itfnum, 0, _stridx), \
/* Function */ \
- 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0101)
+ 9, DFU_DESC_FUNCTIONAL, _attr, U16_TO_U8S_LE(_timeout), U16_TO_U8S_LE(_xfer_size), U16_TO_U8S_LE(0x0110)
#define TUD_DFU_ALT(_itfnum, _alt, _stridx) \
/* Interface */ \
diff --git a/src/host/usbh.c b/src/host/usbh.c
index e99d9e977..41f41dcfb 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -599,8 +599,14 @@ void tuh_task_ext(uint32_t timeout_ms, bool in_isr) {
return;
}
- // Loop until there is no more events in the queue
- while (1) {
+ // Loop until there are no more events in the queue or CFG_TUH_TASK_EVENTS_PER_RUN is reached
+ for (unsigned epr = 0;; epr++) {
+#if CFG_TUH_TASK_EVENTS_PER_RUN > 0
+ if (epr >= CFG_TUH_TASK_EVENTS_PER_RUN) {
+ TU_LOG_USBH("USBH event limit (" TU_XSTRING(CFG_TUH_TASK_EVENTS_PER_RUN) ") reached\r\n");
+ break;
+ }
+#endif
hcd_event_t event;
if (!osal_queue_receive(_usbh_q, &event, timeout_ms)) { return; }
@@ -1405,12 +1411,13 @@ static void remove_device_tree(uint8_t rhport, uint8_t hub_addr, uint8_t hub_por
// NOTE: due to the shared control buffer, we must complete enumerating
// one device before enumerating another one.
//--------------------------------------------------------------------+
-enum { // USB 2.0 specs 7.1.7 for timing
- ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
- ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
- ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
- ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
- ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
+enum { // USB 2.0 specs 7.1.7 for timing
+ ENUM_DEBOUNCING_DELAY_MS = 150, // T(ATTDB) minimum 100 ms for stable connection
+ ENUM_RESET_ROOT_DELAY_MS = 50, // T(DRSTr) minimum 50 ms for reset from root port
+ ENUM_RESET_ROOT_POST_DELAY_MS = 2, // 2 ms delay after root port reset before getting speed/status
+ ENUM_RESET_HUB_DELAY_MS = 20, // T(DRST) 10-20 ms for hub reset
+ ENUM_RESET_RECOVERY_DELAY_MS = 10, // T(RSTRCY) minimum 10 ms for reset recovery
+ ENUM_SET_ADDRESS_RECOVERY_DELAY_MS = 2, // USB 2.0 Spec 9.2.6.3 min is 2 ms
};
enum {
@@ -1469,6 +1476,7 @@ static bool enum_new_device(hcd_event_t* event) {
hcd_port_reset(dev0_bus->rhport);
tusb_time_delay_ms_api(ENUM_RESET_ROOT_DELAY_MS);
hcd_port_reset_end(dev0_bus->rhport);
+ tusb_time_delay_ms_api(ENUM_RESET_ROOT_POST_DELAY_MS);
if (!hcd_port_connect_status(dev0_bus->rhport)) {
// device unplugged while delaying
diff --git a/src/osal/osal_none.h b/src/osal/osal_none.h
index 174136e38..6ab18ace8 100644
--- a/src/osal/osal_none.h
+++ b/src/osal/osal_none.h
@@ -157,21 +157,21 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
typedef struct {
void (* interrupt_set)(bool enabled);
+ uint16_t item_size;
tu_fifo_t ff;
} osal_queue_def_t;
typedef osal_queue_def_t* osal_queue_t;
// _int_set is used as mutex in OS NONE (disable/enable USB ISR)
-#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- osal_queue_def_t _name = { \
- .interrupt_set = _int_set, \
- .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
- }
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+ uint8_t _name##_buf[_depth * sizeof(_type)]; \
+ osal_queue_def_t _name = {.interrupt_set = _int_set, \
+ .item_size = sizeof(_type), \
+ .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)}
TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
- (void) tu_fifo_clear(&qdef->ff);
+ tu_fifo_clear(&qdef->ff);
return (osal_queue_t) qdef;
}
@@ -184,7 +184,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, v
(void) msec; // not used, always behave as msec = 0
qhdl->interrupt_set(false);
- const bool success = tu_fifo_read(&qhdl->ff, data);
+ const bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size);
qhdl->interrupt_set(true);
return success;
@@ -195,7 +195,7 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void
qhdl->interrupt_set(false);
}
- const bool success = tu_fifo_write(&qhdl->ff, data);
+ const bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size);
if (!in_isr) {
qhdl->interrupt_set(true);
diff --git a/src/osal/osal_pico.h b/src/osal/osal_pico.h
index f5385071a..79b728e9a 100644
--- a/src/osal/osal_pico.h
+++ b/src/osal/osal_pico.h
@@ -47,40 +47,39 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_task_delay(uint32_t msec) {
// Spinlock API
//--------------------------------------------------------------------+
typedef critical_section_t osal_spinlock_t; // pico implement critical section with spinlock
-#define OSAL_SPINLOCK_DEF(_name, _int_set) \
- osal_spinlock_t _name
+#define OSAL_SPINLOCK_DEF(_name, _int_set) osal_spinlock_t _name
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_init(osal_spinlock_t *ctx) {
critical_section_init(ctx);
}
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_lock(osal_spinlock_t *ctx, bool in_isr) {
- (void) in_isr;
+ (void)in_isr;
critical_section_enter_blocking(ctx);
}
TU_ATTR_ALWAYS_INLINE static inline void osal_spin_unlock(osal_spinlock_t *ctx, bool in_isr) {
- (void) in_isr;
+ (void)in_isr;
critical_section_exit(ctx);
}
//--------------------------------------------------------------------+
// Binary Semaphore API
//--------------------------------------------------------------------+
-typedef struct semaphore osal_semaphore_def_t, * osal_semaphore_t;
+typedef struct semaphore osal_semaphore_def_t, *osal_semaphore_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semdef) {
+TU_ATTR_ALWAYS_INLINE static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t *semdef) {
sem_init(semdef, 0, 255);
return semdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_delete(osal_semaphore_t semd_hdl) {
- (void) semd_hdl;
+ (void)semd_hdl;
return true; // nothing to do
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr) {
- (void) in_isr;
+ (void)in_isr;
return sem_release(sem_hdl);
}
@@ -96,15 +95,15 @@ TU_ATTR_ALWAYS_INLINE static inline void osal_semaphore_reset(osal_semaphore_t s
// MUTEX API
// Within tinyusb, mutex is never used in ISR context
//--------------------------------------------------------------------+
-typedef struct mutex osal_mutex_def_t, * osal_mutex_t;
+typedef struct mutex osal_mutex_def_t, *osal_mutex_t;
-TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t* mdef) {
+TU_ATTR_ALWAYS_INLINE static inline osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef) {
mutex_init(mdef);
return mdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_delete(osal_mutex_t mutex_hdl) {
- (void) mutex_hdl;
+ (void)mutex_hdl;
return true; // nothing to do
}
@@ -123,46 +122,45 @@ TU_ATTR_ALWAYS_INLINE static inline bool osal_mutex_unlock(osal_mutex_t mutex_hd
#include "common/tusb_fifo.h"
typedef struct {
- tu_fifo_t ff;
+ uint16_t item_size;
+ tu_fifo_t ff;
struct critical_section critsec; // osal_queue may be used in IRQs, so need critical section
} osal_queue_def_t;
-typedef osal_queue_def_t* osal_queue_t;
+typedef osal_queue_def_t *osal_queue_t;
// role device/host is used by OS NONE for mutex (disable usb isr) only
-#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
- uint8_t _name##_buf[_depth*sizeof(_type)]; \
- osal_queue_def_t _name = { \
- .ff = TU_FIFO_INIT(_name##_buf, _depth, _type, false) \
- }
+#define OSAL_QUEUE_DEF(_int_set, _name, _depth, _type) \
+ uint8_t _name##_buf[_depth * sizeof(_type)]; \
+ osal_queue_def_t _name = {.item_size = sizeof(_type), .ff = TU_FIFO_INIT(_name##_buf, _depth * sizeof(_type), false)}
-TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t* qdef) {
+TU_ATTR_ALWAYS_INLINE static inline osal_queue_t osal_queue_create(osal_queue_def_t *qdef) {
critical_section_init(&qdef->critsec);
- (void) tu_fifo_clear(&qdef->ff);
- return (osal_queue_t) qdef;
+ tu_fifo_clear(&qdef->ff);
+ return (osal_queue_t)qdef;
}
TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_delete(osal_queue_t qhdl) {
- osal_queue_def_t* qdef = (osal_queue_def_t*) qhdl;
+ osal_queue_def_t *qdef = (osal_queue_def_t *)qhdl;
critical_section_deinit(&qdef->critsec);
return true;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void* data, uint32_t msec) {
- (void) msec; // not used, always behave as msec = 0
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec) {
+ (void)msec; // not used, always behave as msec = 0
critical_section_enter_blocking(&qhdl->critsec);
- bool success = tu_fifo_read(&qhdl->ff, data);
+ bool success = tu_fifo_read_n(&qhdl->ff, data, qhdl->item_size);
critical_section_exit(&qhdl->critsec);
return success;
}
-TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, void const* data, bool in_isr) {
- (void) in_isr;
+TU_ATTR_ALWAYS_INLINE static inline bool osal_queue_send(osal_queue_t qhdl, const void *data, bool in_isr) {
+ (void)in_isr;
critical_section_enter_blocking(&qhdl->critsec);
- bool success = tu_fifo_write(&qhdl->ff, data);
+ bool success = tu_fifo_write_n(&qhdl->ff, data, qhdl->item_size);
critical_section_exit(&qhdl->critsec);
return success;
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index ad20d64bd..d329285e9 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -32,12 +32,6 @@
#define MUSB_DEBUG 2
#define MUSB_REGS(rhport) ((musb_regs_t*) MUSB_BASES[rhport])
-#if __GNUC__ > 8 && defined(__ARM_FEATURE_UNALIGNED)
-/* GCC warns that an address may be unaligned, even though
- * the target CPU has the capability for unaligned memory access. */
-_Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");
-#endif
-
#include "musb_type.h"
#include "device/dcd.h"
@@ -73,7 +67,10 @@ typedef struct TU_ATTR_PACKED
typedef struct
{
- tusb_control_request_t setup_packet;
+ union {
+ tusb_control_request_t setup_packet;
+ uint32_t setup_buffer[2];
+ };
uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
int8_t status_out;
pipe_state_t pipe0;
@@ -170,76 +167,12 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigne
}
}
-static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
-{
- volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
- uintptr_t addr = (uintptr_t)buf;
- while (len >= 4) {
- reg->u32 = *(uint32_t const *)addr;
- addr += 4;
- len -= 4;
- }
- if (len >= 2) {
- reg->u16 = *(uint16_t const *)addr;
- addr += 2;
- len -= 2;
- }
- if (len) {
- reg->u8 = *(uint8_t const *)addr;
- }
-}
-
-static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
-{
- volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
- uintptr_t addr = (uintptr_t)buf;
- while (len >= 4) {
- *(uint32_t *)addr = reg->u32;
- addr += 4;
- len -= 4;
- }
- if (len >= 2) {
- *(uint16_t *)addr = reg->u16;
- addr += 2;
- len -= 2;
- }
- if (len) {
- *(uint8_t *)addr = reg->u8;
- }
-}
-
-static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigned len, unsigned dir)
-{
- static const struct {
- void (*tu_fifo_get_info)(tu_fifo_t *f, tu_fifo_buffer_info_t *info);
- void (*tu_fifo_advance)(tu_fifo_t *f, uint16_t n);
- void (*pipe_read_write)(void *buf, volatile void *fifo, unsigned len);
- } ops[] = {
- /* OUT */ {tu_fifo_get_write_info,tu_fifo_advance_write_pointer,pipe_read_packet},
- /* IN */ {tu_fifo_get_read_info, tu_fifo_advance_read_pointer, pipe_write_packet},
- };
- tu_fifo_buffer_info_t info;
- ops[dir].tu_fifo_get_info(f, &info);
- unsigned total_len = len;
- len = TU_MIN(total_len, info.linear.len);
- ops[dir].pipe_read_write(info.linear.ptr, fifo, len);
- unsigned rem = total_len - len;
- if (rem) {
- len = TU_MIN(rem, info.wrapped.len);
- ops[dir].pipe_read_write(info.wrapped.ptr, fifo, len);
- rem -= len;
- }
- ops[dir].tu_fifo_advance(f, total_len - rem);
-}
-
static void process_setup_packet(uint8_t rhport) {
musb_regs_t* musb_regs = MUSB_REGS(rhport);
// Read setup packet
- uint32_t *p = (void*)&_dcd.setup_packet;
- volatile uint32_t *fifo_ptr = &musb_regs->fifo[0];
- p[0] = *fifo_ptr;
- p[1] = *fifo_ptr;
+ _dcd.setup_buffer[0] = musb_regs->fifo[0];
+ _dcd.setup_buffer[1] = musb_regs->fifo[0];
_dcd.pipe0.buf = NULL;
_dcd.pipe0.length = 0;
@@ -256,14 +189,13 @@ static void process_setup_packet(uint8_t rhport) {
}
}
-static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr)
-{
+static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr) {
unsigned epnum = tu_edpt_number(ep_addr);
unsigned epnum_minus1 = epnum - 1;
pipe_state_t *pipe = &_dcd.pipe[tu_edpt_dir(ep_addr)][epnum_minus1];
const unsigned rem = pipe->remaining;
- if (!rem) {
+ if (rem == 0 && pipe->length > 0) {
pipe->buf = NULL;
return true;
}
@@ -277,10 +209,10 @@ static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr)
// TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem);
if (len) {
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_IN);
+ tu_hwfifo_write_from_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL);
} else {
- pipe_write_packet(buf, fifo_ptr, len);
- pipe->buf = buf + len;
+ tu_hwfifo_write(fifo_ptr, buf, len, NULL);
+ pipe->buf = (uint8_t*)buf + len;
}
pipe->remaining = rem - len;
}
@@ -308,10 +240,10 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
volatile void *fifo_ptr = &musb_regs->fifo[epnum];
if (len) {
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff(buf, fifo_ptr, len, TUSB_DIR_OUT);
+ tu_hwfifo_read_to_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL);
} else {
- pipe_read_packet(buf, fifo_ptr, len);
- pipe->buf = buf + len;
+ tu_hwfifo_read(fifo_ptr, buf, len, NULL);
+ pipe->buf = (uint8_t*)buf + len;
}
pipe->remaining = rem - len;
}
@@ -378,7 +310,7 @@ static bool edpt0_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_
const unsigned len = TU_MIN(TU_MIN(rem, 64), total_bytes);
volatile void *fifo_ptr = &musb_regs->fifo[0];
if (dir_in) {
- pipe_write_packet(buffer, fifo_ptr, len);
+ tu_hwfifo_write(fifo_ptr, buffer, len, NULL);
_dcd.pipe0.buf = buffer + len;
_dcd.pipe0.length = len;
@@ -458,7 +390,7 @@ static void process_ep0(uint8_t rhport)
const unsigned rem = _dcd.pipe0.remaining;
const unsigned len = TU_MIN(TU_MIN(rem, 64), vld);
volatile void *fifo_ptr = &musb_regs->fifo[0];
- pipe_read_packet(_dcd.pipe0.buf, fifo_ptr, len);
+ tu_hwfifo_read(fifo_ptr, _dcd.pipe0.buf, len, NULL);
_dcd.pipe0.remaining = rem - len;
_dcd.remaining_ctrl -= len;
diff --git a/src/portable/mentor/musb/musb_ti.h b/src/portable/mentor/musb/musb_ti.h
index d17e836ee..68e89d77d 100644
--- a/src/portable/mentor/musb/musb_ti.h
+++ b/src/portable/mentor/musb/musb_ti.h
@@ -35,7 +35,10 @@
#include "TM4C123.h"
#define FIFO0_WORD FIFO0
#define FIFO1_WORD FIFO1
-//#elif CFG_TUSB_MCU == OPT_MCU_TM4C129
+#elif CFG_TUSB_MCU == OPT_MCU_TM4C129
+ #include "TM4C129.h"
+ #define FIFO0_WORD FIFOA
+ #define FIFO1_WORD FIFOB
#elif CFG_TUSB_MCU == OPT_MCU_MSP432E4
#include "msp.h"
#else
diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h
index 4e448c0ed..b2f6492fa 100644
--- a/src/portable/mentor/musb/musb_type.h
+++ b/src/portable/mentor/musb/musb_type.h
@@ -147,7 +147,7 @@ typedef struct TU_ATTR_PACKED {
TU_VERIFY_STATIC(sizeof(musb_ep_csr_t) == 16, "size is not correct");
-typedef struct TU_ATTR_PACKED {
+typedef struct {
//------------- Common -------------//
__IO uint8_t faddr; // 0x00: FADDR
union {
diff --git a/src/portable/microchip/samg/dcd_samg.c b/src/portable/microchip/samg/dcd_samg.c
index 1faac2aa8..4115eecc5 100644
--- a/src/portable/microchip/samg/dcd_samg.c
+++ b/src/portable/microchip/samg/dcd_samg.c
@@ -437,7 +437,7 @@ void dcd_int_handler(uint8_t rhport)
// write to EP fifo
#if 0 // TODO support dcd_edpt_xfer_fifo
if (xfer->ff) {
- tu_fifo_read_n_access_mode(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len, TU_FIFO_FIXED_ADDR_RW32);
+ tu_fifo_read_n_access_mode(xfer->ff, (void *) &UDP->UDP_FDR[epnum], xact_len, true);
}
else
#endif
@@ -471,7 +471,7 @@ void dcd_int_handler(uint8_t rhport)
// Read from EP fifo
#if 0 // TODO support dcd_edpt_xfer_fifo API
if (xfer->ff) {
- tu_fifo_write_n_access_mode(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len, TU_FIFO_FIXED_ADDR_RW32);
+ tu_fifo_write_n_access_mode(xfer->ff, (const void *) &UDP->UDP_FDR[epnum], xact_len, true);
}
else
#endif
diff --git a/src/portable/nuvoton/nuc505/dcd_nuc505.c b/src/portable/nuvoton/nuc505/dcd_nuc505.c
index 91b876718..ca17d6251 100644
--- a/src/portable/nuvoton/nuc505/dcd_nuc505.c
+++ b/src/portable/nuvoton/nuc505/dcd_nuc505.c
@@ -194,7 +194,7 @@ static void dcd_userEP_in_xfer(struct xfer_ctl_t *xfer, USBD_EP_T *ep)
/* provided buffers are thankfully 32-bit aligned, allowing most data to be transferred as 32-bit */
#if 0 // TODO support dcd_edpt_xfer_fifo API
if (xfer->ff) {
- tu_fifo_read_n_access_mode(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now, TU_FIFO_FIXED_ADDR_RW32);
+ tu_fifo_read_n_access_mode(xfer->ff, (void *) (&ep->EPDAT_BYTE), bytes_now, true);
}
else
#endif
@@ -696,7 +696,7 @@ void dcd_int_handler(uint8_t rhport)
/* copy the data from the PC to the previously provided buffer */
#if 0 // TODO support dcd_edpt_xfer_fifo API
if (xfer->ff) {
- tu_fifo_write_n_access_mode(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far), TU_FIFO_FIXED_ADDR_RW32);
+ tu_fifo_write_n_access_mode(xfer->ff, (const void *) &ep->EPDAT_BYTE, tu_min16(available_bytes, xfer->total_bytes - xfer->out_bytes_so_far), true);
}
else
#endif
diff --git a/src/portable/raspberrypi/rp2040/dcd_rp2040.c b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
index 15852f29f..240e6c727 100644
--- a/src/portable/raspberrypi/rp2040/dcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/dcd_rp2040.c
@@ -39,122 +39,103 @@
#include "device/dcd.h"
// Current implementation force vbus detection as always present, causing device think it is always plugged into host.
-// Therefore it cannot detect disconnect event, mistaken it as suspend.
+// Therefore, it cannot detect disconnect event, mistaken it as suspend.
// Note: won't work if change to 0 (for now)
-#define FORCE_VBUS_DETECT 1
+ #define FORCE_VBUS_DETECT 1
+
+ #define USB_INTS_ERROR_BITS \
+ (USB_INTS_ERROR_DATA_SEQ_BITS | USB_INTS_ERROR_BIT_STUFF_BITS | USB_INTS_ERROR_CRC_BITS | \
+ USB_INTS_ERROR_RX_OVERFLOW_BITS | USB_INTS_ERROR_RX_TIMEOUT_BITS)
/*------------------------------------------------------------------*/
/* Low level controller
*------------------------------------------------------------------*/
-// Init these in dcd_init
-static uint8_t* next_buffer_ptr;
+// HW buffer pointer from USB buffer space (max 3840 bytes)
+static uint8_t *hw_buffer_ptr;
// USB_MAX_ENDPOINTS Endpoints, direction TUSB_DIR_OUT for out and TUSB_DIR_IN for in.
static struct hw_endpoint hw_endpoints[USB_MAX_ENDPOINTS][2];
-// SOF may be used by remote wakeup as RESUME, this indicate whether SOF is actually used by usbd
+// SOF may be used by remote wakeup as RESUME, this indicates whether SOF is actually used by usbd
static bool _sof_enable = false;
-TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_num(uint8_t num, tusb_dir_t dir) {
- return &hw_endpoints[num][dir];
-}
-
-TU_ATTR_ALWAYS_INLINE static inline struct hw_endpoint* hw_endpoint_get_by_addr(uint8_t ep_addr) {
- uint8_t num = tu_edpt_number(ep_addr);
- tusb_dir_t dir = tu_edpt_dir(ep_addr);
- return hw_endpoint_get_by_num(num, dir);
-}
-
-// Allocate from the USB buffer space (max 3840 bytes)
-static void hw_endpoint_alloc(struct hw_endpoint* ep, size_t size) {
- // round up size to multiple of 64
- size = tu_round_up(ep->wMaxPacketSize, 64);
-
- // double buffered Bulk endpoint
- if (ep->transfer_type == TUSB_XFER_BULK) {
- size *= 2u;
- }
-
- // assign buffer
- ep->hw_data_buf = next_buffer_ptr;
- next_buffer_ptr += size;
-
- hard_assert(next_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data));
- pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf);
+TU_ATTR_ALWAYS_INLINE static inline hw_endpoint_t *hw_endpoint_get(uint8_t epnum, tusb_dir_t dir) {
+ return &hw_endpoints[epnum][dir];
}
-// Enable endpoint
-TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_enable(struct hw_endpoint* ep) {
- uint32_t const reg = EP_CTRL_ENABLE_BITS | ((uint) ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf);
- *ep->endpoint_control = reg;
+TU_ATTR_ALWAYS_INLINE static inline hw_endpoint_t *hw_endpoint_get_by_addr(uint8_t ep_addr) {
+ const uint8_t num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ return hw_endpoint_get(num, dir);
}
// main processing for dcd_edpt_iso_activate
-static void hw_endpoint_init(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
- struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
-
- const uint8_t num = tu_edpt_number(ep_addr);
- const tusb_dir_t dir = tu_edpt_dir(ep_addr);
-
- ep->ep_addr = ep_addr;
-
- // For device, IN is a tx transfer and OUT is an rx transfer
- ep->rx = (dir == TUSB_DIR_OUT);
-
- ep->next_pid = 0u;
+static void hw_endpoint_init(hw_endpoint_t *ep, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
+ ep->ep_addr = ep_addr;
+ ep->next_pid = 0u;
ep->wMaxPacketSize = wMaxPacketSize;
- ep->transfer_type = transfer_type;
-
- // Every endpoint has a buffer control register in dpram
- if (dir == TUSB_DIR_IN) {
- ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].in;
- } else {
- ep->buffer_control = &usb_dpram->ep_buf_ctrl[num].out;
- }
// Clear existing buffer control state
- *ep->buffer_control = 0;
-
- if (num == 0) {
- // EP0 has no endpoint control register because the buffer offsets are fixed
- ep->endpoint_control = NULL;
+ io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ *buf_ctrl_reg = 0;
+ // allocated hw buffer
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ if (epnum == 0) {
// Buffer offset is fixed (also double buffered)
ep->hw_data_buf = (uint8_t*) &usb_dpram->ep0_buf_a[0];
} else {
- // Set the endpoint control register (starts at EP1, hence num-1)
- if (dir == TUSB_DIR_IN) {
- ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].in;
- } else {
- ep->endpoint_control = &usb_dpram->ep_ctrl[num - 1].out;
+ // round up size to multiple of 64
+ uint16_t size = (uint16_t)tu_round_up(wMaxPacketSize, 64);
+
+ // double buffered Bulk endpoint
+ if (transfer_type == TUSB_XFER_BULK) {
+ size *= 2u;
+
+ #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
+ ep->e15_bulk_in = true;
+ }
+ #endif
}
+
+ // assign buffer
+ ep->hw_data_buf = hw_buffer_ptr;
+ hw_buffer_ptr += size;
+
+ hard_assert(hw_buffer_ptr < usb_dpram->epx_data + sizeof(usb_dpram->epx_data));
+ pico_info(" Allocated %d bytes (0x%p)\r\n", size, ep->hw_data_buf);
}
}
-// Init, allocate buffer and enable endpoint
-static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
- struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
- hw_endpoint_init(ep_addr, wMaxPacketSize, transfer_type);
- const uint8_t num = tu_edpt_number(ep_addr);
- if (num != 0) {
- // EP0 is already enabled
- hw_endpoint_alloc(ep, ep->wMaxPacketSize);
- hw_endpoint_enable(ep);
+static void hw_endpoint_enable(hw_endpoint_t *ep, uint8_t transfer_type) {
+ io_rw_32 *ctrl_reg = hwep_ctrl_reg_device(ep);
+ // Set endpoint control register to enable (EP0 has no endpoint control register)
+ if (ctrl_reg != NULL) {
+ const uint32_t ctrl_value =
+ EP_CTRL_ENABLE_BITS | ((uint32_t)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | hw_data_offset(ep->hw_data_buf);
+ *ctrl_reg = ctrl_value;
}
}
-static void hw_endpoint_xfer(uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
- struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
- hw_endpoint_xfer_start(ep, buffer, total_bytes);
+// Init and enable endpoint
+static void hw_endpoint_open(uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type) {
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ hw_endpoint_t *ep = hw_endpoint_get(epnum, dir);
+
+ hw_endpoint_init(ep, ep_addr, wMaxPacketSize, transfer_type);
+ hw_endpoint_enable(ep, transfer_type);
}
static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
// Abort any pending transfer
+ const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr);
+ const uint8_t epnum = tu_edpt_number(ep->ep_addr);
+ const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1));
+
// Due to Errata RP2040-E2: ABORT flag is only applicable for B2 and later (unusable for B0, B1).
// Which means we are not guaranteed to safely abort pending transfer on B0 and B1.
- const uint8_t dir = tu_edpt_dir(ep->ep_addr);
- const uint8_t epnum = tu_edpt_number(ep->ep_addr);
- const uint32_t abort_mask = TU_BIT((epnum << 1) | (dir ? 0 : 1));
if (rp2040_chip_version() >= 2) {
usb_hw_set->abort = abort_mask;
while ((usb_hw->abort_done & abort_mask) != abort_mask) {}
@@ -165,7 +146,8 @@ static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
buf_ctrl |= USB_BUF_CTRL_DATA1_PID;
}
- _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
+ io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl);
hw_endpoint_reset_transfer(ep);
if (rp2040_chip_version() >= 2) {
@@ -174,7 +156,7 @@ static void hw_endpoint_abort_xfer(struct hw_endpoint* ep) {
}
}
-static void __tusb_irq_path_func(hw_handle_buff_status)(void) {
+static void __tusb_irq_path_func(handle_hw_buff_status)(void) {
uint32_t remaining_buffers = usb_hw->buf_status;
pico_trace("buf_status = 0x%08lx\r\n", remaining_buffers);
uint bit = 1u;
@@ -184,12 +166,13 @@ static void __tusb_irq_path_func(hw_handle_buff_status)(void) {
usb_hw_clear->buf_status = bit;
// IN transfer for even i, OUT transfer for odd i
- struct hw_endpoint* ep = hw_endpoint_get_by_num(i >> 1u, (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN);
+ const uint8_t epnum = i >> 1u;
+ const tusb_dir_t dir = (i & 1u) ? TUSB_DIR_OUT : TUSB_DIR_IN;
+ hw_endpoint_t *ep = hw_endpoint_get(epnum, dir);
- // Continue xfer
- bool done = hw_endpoint_xfer_continue(ep);
+ const bool done = hw_endpoint_xfer_continue(ep);
if (done) {
- // Notify
+ // Notify usbd
const uint16_t xferred_len = ep->xferred_len;
hw_endpoint_reset_transfer(ep);
dcd_event_xfer_complete(0, ep->ep_addr, xferred_len, XFER_RESULT_SUCCESS, true);
@@ -204,7 +187,7 @@ TU_ATTR_ALWAYS_INLINE static inline void reset_ep0(void) {
// If we have finished this transfer on EP0 set pid back to 1 for next
// setup transfer. Also clear a stall in case
for (uint8_t dir = 0; dir < 2; dir++) {
- struct hw_endpoint* ep = hw_endpoint_get_by_num(0, dir);
+ struct hw_endpoint *ep = hw_endpoint_get(0, dir);
ep->next_pid = 1u;
if (ep->active) {
hw_endpoint_abort_xfer(ep); // Abort any pending transfer per USB specs
@@ -223,11 +206,11 @@ static void __tusb_irq_path_func(reset_non_control_endpoints)(void) {
tu_memclr(hw_endpoints[1], sizeof(hw_endpoints) - 2 * sizeof(hw_endpoint_t));
// reclaim buffer space
- next_buffer_ptr = &usb_dpram->epx_data[0];
+ hw_buffer_ptr = &usb_dpram->epx_data[0];
}
static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
- uint32_t const status = usb_hw->ints;
+ const uint32_t status = usb_hw->ints;
uint32_t handled = 0;
if (status & USB_INTF_DEV_SOF_BITS) {
@@ -240,27 +223,26 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
e15_last_sof = time_us_32();
for (uint8_t i = 0; i < USB_MAX_ENDPOINTS; i++) {
- struct hw_endpoint* ep = hw_endpoint_get_by_num(i, TUSB_DIR_IN);
+ struct hw_endpoint *ep = hw_endpoint_get(i, TUSB_DIR_IN);
// Active Bulk IN endpoint requires SOF
- if ((ep->transfer_type == TUSB_XFER_BULK) && ep->active) {
+ if (ep->e15_bulk_in && ep->active) {
keep_sof_alive = true;
hw_endpoint_lock_update(ep, 1);
-
- // Deferred enable?
if (ep->pending) {
ep->pending = 0;
hw_endpoint_start_next_buffer(ep);
}
-
hw_endpoint_lock_update(ep, -1);
}
}
#endif
// disable SOF interrupt if it is used for RESUME in remote wakeup
- if (!keep_sof_alive && !_sof_enable) usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+ if (!keep_sof_alive && !_sof_enable) {
+ usb_hw_clear->inte = USB_INTS_DEV_SOF_BITS;
+ }
dcd_event_sof(0, usb_hw->sof_rd & USB_SOF_RD_BITS, true);
}
@@ -269,7 +251,7 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
// before closing the EP, the events will be delivered in same order.
if (status & USB_INTS_BUFF_STATUS_BITS) {
handled |= USB_INTS_BUFF_STATUS_BITS;
- hw_handle_buff_status();
+ handle_hw_buff_status();
}
if (status & USB_INTS_SETUP_REQ_BITS) {
@@ -287,15 +269,12 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
#if FORCE_VBUS_DETECT == 0
// Since we force VBUS detect On, device will always think it is connected and
// couldn't distinguish between disconnect and suspend
- if (status & USB_INTS_DEV_CONN_DIS_BITS)
- {
+ if (status & USB_INTS_DEV_CONN_DIS_BITS) {
handled |= USB_INTS_DEV_CONN_DIS_BITS;
- if ( usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS )
- {
+ if (usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS) {
// Connected: nothing to do
- }else
- {
+ } else {
// Disconnected
dcd_event_bus_signal(0, DCD_EVENT_UNPLUGGED, true);
}
@@ -315,10 +294,12 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
dcd_event_bus_reset(0, TUSB_SPEED_FULL, true);
usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
-#if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
+ #if TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
// Only run enumeration workaround if pull up is enabled
- if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) rp2040_usb_device_enumeration_fix();
-#endif
+ if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS) {
+ rp2040_usb_device_enumeration_fix();
+ }
+ #endif
}
/* Note from pico datasheet 4.1.2.6.4 (v1.2)
@@ -346,13 +327,6 @@ static void __tusb_irq_path_func(dcd_rp2040_irq)(void) {
}
}
-#define USB_INTS_ERROR_BITS ( \
- USB_INTS_ERROR_DATA_SEQ_BITS | \
- USB_INTS_ERROR_BIT_STUFF_BITS | \
- USB_INTS_ERROR_CRC_BITS | \
- USB_INTS_ERROR_RX_OVERFLOW_BITS | \
- USB_INTS_ERROR_RX_TIMEOUT_BITS)
-
/*------------------------------------------------------------------*/
/* Controller API
*------------------------------------------------------------------*/
@@ -369,9 +343,9 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
TU_LOG(2, "Chip Version B%u\r\n", rp2040_chip_version());
// Reset hardware to default state
- rp2040_usb_init();
+ rp2usb_init();
-#if FORCE_VBUS_DETECT
+ #if FORCE_VBUS_DETECT
// Force VBUS detect so the device thinks it is plugged into a host
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
#endif
@@ -425,12 +399,11 @@ void dcd_int_disable(__unused uint8_t rhport) {
irq_set_enabled(USBCTRL_IRQ, false);
}
-void dcd_set_address(__unused uint8_t rhport, __unused uint8_t dev_addr) {
- assert(rhport == 0);
-
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+ (void)dev_addr;
// Can't set device address in hardware until status xfer has complete
// Send 0len complete response on EP0 IN
- hw_endpoint_xfer(0x80, NULL, 0);
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0, false);
}
void dcd_remote_wakeup(__unused uint8_t rhport) {
@@ -475,7 +448,6 @@ void dcd_sof_enable(uint8_t rhport, bool en) {
/*------------------------------------------------------------------*/
/* DCD Endpoint port
*------------------------------------------------------------------*/
-
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
(void) rhport;
@@ -489,7 +461,6 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* req
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
(void) rhport;
const uint8_t xfer_type = desc_edpt->bmAttributes.xfer;
- TU_VERIFY(xfer_type != TUSB_XFER_ISOCHRONOUS);
hw_endpoint_open(desc_edpt->bEndpointAddress, tu_edpt_packet_size(desc_edpt), xfer_type);
return true;
}
@@ -497,56 +468,65 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
// New API: Allocate packet buffer used by ISO endpoints
// Some MCU need manual packet buffer allocation, we allocate the largest size to avoid clustering
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
- (void) rhport;
- struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
- hw_endpoint_init(ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS);
- hw_endpoint_alloc(ep, largest_packet_size);
+ (void)rhport;
+ struct hw_endpoint *ep = hw_endpoint_get_by_addr(ep_addr);
+ hw_endpoint_init(ep, ep_addr, largest_packet_size, TUSB_XFER_ISOCHRONOUS);
return true;
}
// New API: Configure and enable an ISO endpoint according to descriptor
-bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
- (void) rhport;
- struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_desc->bEndpointAddress);
+bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *ep_desc) {
+ (void)rhport;
+ const uint8_t epnum = tu_edpt_number(ep_desc->bEndpointAddress);
+ const tusb_dir_t dir = tu_edpt_dir(ep_desc->bEndpointAddress);
+ struct hw_endpoint *ep = hw_endpoint_get(epnum, dir);
TU_ASSERT(ep->hw_data_buf != NULL); // must be inited and allocated previously
if (ep->active) {
hw_endpoint_abort_xfer(ep); // abort any pending transfer
}
-
ep->wMaxPacketSize = ep_desc->wMaxPacketSize;
- hw_endpoint_enable(ep);
+
+ hw_endpoint_enable(ep, TUSB_XFER_ISOCHRONOUS);
return true;
}
void dcd_edpt_close_all(uint8_t rhport) {
(void) rhport;
-
// may need to use EP Abort
reset_non_control_endpoints();
}
-bool dcd_edpt_xfer(__unused uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes, bool is_isr) {
- (void) is_isr;
- assert(rhport == 0);
- hw_endpoint_xfer(ep_addr, buffer, total_bytes);
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) {
+ (void)rhport;
+ (void)is_isr;
+ hw_endpoint_t *ep = hw_endpoint_get_by_addr(ep_addr);
+ hw_endpoint_xfer_start(ep, buffer, NULL, total_bytes);
+ return true;
+}
+
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes, bool is_isr) {
+ (void)rhport;
+ (void)is_isr;
+ hw_endpoint_t *ep = hw_endpoint_get_by_addr(ep_addr);
+ hw_endpoint_xfer_start(ep, NULL, ff, total_bytes);
return true;
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
- (void) rhport;
+ (void)rhport;
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ hw_endpoint_t *ep = hw_endpoint_get(epnum, dir);
- if (tu_edpt_number(ep_addr) == 0) {
+ if (epnum == 0) {
// A stall on EP0 has to be armed so it can be cleared on the next setup packet
- usb_hw_set->ep_stall_arm = (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS
- : USB_EP_STALL_ARM_EP0_OUT_BITS;
+ usb_hw_set->ep_stall_arm = (dir == TUSB_DIR_IN) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
}
- struct hw_endpoint* ep = hw_endpoint_get_by_addr(ep_addr);
-
- // stall and clear current pending buffer
- // may need to use EP_ABORT
- _hw_endpoint_buffer_control_set_value32(ep, USB_BUF_CTRL_STALL);
+ // stall and clear current pending buffer, may need to use EP_ABORT
+ io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ hwbuf_ctrl_set(buf_ctrl_reg, USB_BUF_CTRL_STALL);
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
@@ -557,7 +537,8 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
// clear stall also reset toggle to DATA0, ready for next transfer
ep->next_pid = 0;
- _hw_endpoint_buffer_control_clear_mask32(ep, USB_BUF_CTRL_STALL);
+ io_rw_32 *buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ hwbuf_ctrl_clear_mask(buf_ctrl_reg, USB_BUF_CTRL_STALL);
}
}
diff --git a/src/portable/raspberrypi/rp2040/hcd_rp2040.c b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
index cd8c905d5..06c0ce340 100644
--- a/src/portable/raspberrypi/rp2040/hcd_rp2040.c
+++ b/src/portable/raspberrypi/rp2040/hcd_rp2040.c
@@ -62,34 +62,33 @@ enum {
USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
};
-static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr)
-{
+static struct hw_endpoint *get_dev_ep(uint8_t dev_addr, uint8_t ep_addr) {
uint8_t num = tu_edpt_number(ep_addr);
- if ( num == 0 ) return &epx;
+ if (num == 0) {
+ return &epx;
+ }
- for ( uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++ )
- {
+ for (uint32_t i = 1; i < TU_ARRAY_SIZE(ep_pool); i++) {
struct hw_endpoint *ep = &ep_pool[i];
- if ( ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr) ) return ep;
+ if (ep->configured && (ep->dev_addr == dev_addr) && (ep->ep_addr == ep_addr)) {
+ return ep;
+ }
}
return NULL;
}
-TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void)
-{
+TU_ATTR_ALWAYS_INLINE static inline uint8_t dev_speed(void) {
return (usb_hw->sie_status & USB_SIE_STATUS_SPEED_BITS) >> USB_SIE_STATUS_SPEED_LSB;
}
-TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr)
-{
+TU_ATTR_ALWAYS_INLINE static inline bool need_pre(uint8_t dev_addr) {
// If this device is different to the speed of the root device
// (i.e. is a low speed device on a full speed hub) then need pre
return hcd_port_speed_get(0) != tuh_speed_get(dev_addr);
}
-static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result)
-{
+static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_result_t xfer_result) {
// Mark transfer as done before we tell the tinyusb stack
uint8_t dev_addr = ep->dev_addr;
uint8_t ep_addr = ep->ep_addr;
@@ -98,47 +97,28 @@ static void __tusb_irq_path_func(hw_xfer_complete)(struct hw_endpoint *ep, xfer_
hcd_event_xfer_complete(dev_addr, ep_addr, xferred_len, xfer_result, true);
}
-static void __tusb_irq_path_func(_handle_buff_status_bit)(uint bit, struct hw_endpoint *ep)
-{
+static void __tusb_irq_path_func(handle_hwbuf_status_bit)(uint bit, struct hw_endpoint *ep) {
usb_hw_clear->buf_status = bit;
- // EP may have been stalled?
- assert(ep->active);
- bool done = hw_endpoint_xfer_continue(ep);
- if ( done )
- {
+ const bool done = hw_endpoint_xfer_continue(ep);
+ if (done) {
hw_xfer_complete(ep, XFER_RESULT_SUCCESS);
}
}
-static void __tusb_irq_path_func(hw_handle_buff_status)(void)
-{
- uint32_t remaining_buffers = usb_hw->buf_status;
- pico_trace("buf_status 0x%08lx\n", remaining_buffers);
+static void __tusb_irq_path_func(handle_hwbuf_status)(void) {
+ uint32_t buf_status = usb_hw->buf_status;
+ pico_trace("buf_status 0x%08lx\n", buf_status);
// Check EPX first
- uint bit = 0b1;
- if ( remaining_buffers & bit )
- {
- remaining_buffers &= ~bit;
+ uint32_t bit = 1u;
+ if (buf_status & bit) {
+ buf_status &= ~bit;
struct hw_endpoint * ep = &epx;
-
- uint32_t ep_ctrl = *ep->endpoint_control;
- if ( ep_ctrl & EP_CTRL_DOUBLE_BUFFERED_BITS )
- {
- TU_LOG(3, "Double Buffered: ");
- }
- else
- {
- TU_LOG(3, "Single Buffered: ");
- }
- TU_LOG_HEX(3, ep_ctrl);
-
- _handle_buff_status_bit(bit, ep);
+ handle_hwbuf_status_bit(bit, ep);
}
// Check "interrupt" (asynchronous) endpoints for both IN and OUT
- for ( uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && remaining_buffers; i++ )
- {
+ for (uint i = 1; i <= USB_HOST_INTERRUPT_ENDPOINTS && buf_status; i++) {
// EPX is bit 0 & 1
// IEP1 IN is bit 2
// IEP1 OUT is bit 3
@@ -147,20 +127,17 @@ static void __tusb_irq_path_func(hw_handle_buff_status)(void)
// IEP3 IN is bit 6
// IEP3 OUT is bit 7
// etc
- for ( uint j = 0; j < 2; j++ )
- {
+ for (uint j = 0; j < 2; j++) {
bit = 1 << (i * 2 + j);
- if ( remaining_buffers & bit )
- {
- remaining_buffers &= ~bit;
- _handle_buff_status_bit(bit, &ep_pool[i]);
+ if (buf_status & bit) {
+ buf_status &= ~bit;
+ handle_hwbuf_status_bit(bit, &ep_pool[i]);
}
}
}
- if ( remaining_buffers )
- {
- panic("Unhandled buffer %d\n", remaining_buffers);
+ if (buf_status) {
+ panic("Unhandled buffer %d\n", buf_status);
}
}
@@ -220,7 +197,7 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
{
handled |= USB_INTS_BUFF_STATUS_BITS;
TU_LOG(2, "Buffer complete\r\n");
- hw_handle_buff_status();
+ handle_hwbuf_status();
}
if ( status & USB_INTS_TRANS_COMPLETE_BITS )
@@ -240,9 +217,8 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
if ( status & USB_INTS_ERROR_DATA_SEQ_BITS )
{
usb_hw_clear->sie_status = USB_SIE_STATUS_DATA_SEQ_ERROR_BITS;
- TU_LOG(3, " Seq Error: [0] = 0x%04u [1] = 0x%04x\r\n",
- tu_u32_low16(*epx.buffer_control),
- tu_u32_high16(*epx.buffer_control));
+ TU_LOG(3, " Seq Error: [0] = 0x%04u [1] = 0x%04x\r\n", tu_u32_low16(*hwbuf_ctrl_reg_host(&epx)),
+ tu_u32_high16(*hwbuf_ctrl_reg_host(&epx)));
panic("Data Seq Error \n");
}
@@ -266,7 +242,7 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
ep = &ep_pool[i];
if ( !ep->configured )
{
- // Will be configured by _hw_endpoint_init / _hw_endpoint_allocate
+ // Will be configured by hw_endpoint_init / hw_endpoint_allocate
ep->interrupt_num = (uint8_t) (i - 1);
return ep;
}
@@ -274,41 +250,31 @@ static struct hw_endpoint *_next_free_interrupt_ep(void)
return ep;
}
-static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
-{
- struct hw_endpoint * ep = NULL;
+static hw_endpoint_t *hw_endpoint_allocate(uint8_t transfer_type) {
+ hw_endpoint_t *ep = NULL;
- if ( transfer_type != TUSB_XFER_CONTROL )
- {
+ if (transfer_type == TUSB_XFER_CONTROL) {
+ ep = &epx;
+ ep->hw_data_buf = &usbh_dpram->epx_data[0];
+ } else {
// Note: even though datasheet name these "Interrupt" endpoints. These are actually
// "Asynchronous" endpoints and can be used for other type such as: Bulk (ISO need confirmation)
ep = _next_free_interrupt_ep();
pico_info("Allocate %s ep %d\n", tu_edpt_type_str(transfer_type), ep->interrupt_num);
assert(ep);
- ep->buffer_control = &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
- ep->endpoint_control = &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
// 0 for epx (double buffered): TODO increase to 1024 for ISO
// 2x64 for intep0
// 3x64 for intep1
// etc
ep->hw_data_buf = &usbh_dpram->epx_data[64 * (ep->interrupt_num + 2)];
}
- else
- {
- ep = &epx;
- ep->buffer_control = &usbh_dpram->epx_buf_ctrl;
- ep->endpoint_control = &usbh_dpram->epx_ctrl;
- ep->hw_data_buf = &usbh_dpram->epx_data[0];
- }
return ep;
}
-static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize, uint8_t transfer_type, uint8_t bmInterval)
-{
+static void hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t ep_addr, uint16_t wMaxPacketSize,
+ uint8_t transfer_type, uint8_t bmInterval) {
// Already has data buffer, endpoint control, and buffer control allocated at this point
- assert(ep->endpoint_control);
- assert(ep->buffer_control);
assert(ep->hw_data_buf);
uint8_t const num = tu_edpt_number(ep_addr);
@@ -317,49 +283,41 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
ep->ep_addr = ep_addr;
ep->dev_addr = dev_addr;
- // For host, IN to host == RX, anything else rx == false
- ep->rx = (dir == TUSB_DIR_IN);
-
// Response to a setup packet on EP0 starts with pid of 1
ep->next_pid = (num == 0 ? 1u : 0u);
ep->wMaxPacketSize = wMaxPacketSize;
- ep->transfer_type = transfer_type;
- pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, ep->transfer_type);
+ pico_trace("hw_endpoint_init dev %d ep %02X xfer %d\n", ep->dev_addr, ep->ep_addr, transfer_type);
pico_trace("dev %d ep %02X setup buffer @ 0x%p\n", ep->dev_addr, ep->ep_addr, ep->hw_data_buf);
uint dpram_offset = hw_data_offset(ep->hw_data_buf);
// Bits 0-5 should be 0
assert(!(dpram_offset & 0b111111));
// Fill in endpoint control register with buffer offset
- uint32_t ep_reg = EP_CTRL_ENABLE_BITS
- | EP_CTRL_INTERRUPT_PER_BUFFER
- | (ep->transfer_type << EP_CTRL_BUFFER_TYPE_LSB)
- | dpram_offset;
- if ( bmInterval )
- {
- ep_reg |= (uint32_t) ((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
+ uint32_t ctrl_value = EP_CTRL_ENABLE_BITS | EP_CTRL_INTERRUPT_PER_BUFFER |
+ ((uint32_t)transfer_type << EP_CTRL_BUFFER_TYPE_LSB) | dpram_offset;
+ if (bmInterval) {
+ ctrl_value |= (uint32_t)((bmInterval - 1) << EP_CTRL_HOST_INTERRUPT_INTERVAL_LSB);
}
- *ep->endpoint_control = ep_reg;
- pico_trace("endpoint control (0x%p) <- 0x%lx\n", ep->endpoint_control, ep_reg);
+
+ io_rw_32 *ctrl_reg = hwep_ctrl_reg_host(ep);
+ *ctrl_reg = ctrl_value;
+ pico_trace("endpoint control (0x%p) <- 0x%lx\n", ctrl_reg, ctrl_value);
ep->configured = true;
- if ( ep != &epx )
- {
+ if (ep != &epx) {
// Endpoint has its own addr_endp and interrupt bits to be setup!
// This is an interrupt/async endpoint. so need to set up ADDR_ENDP register with:
// - device address
// - endpoint number / direction
// - preamble
- uint32_t reg = (uint32_t) (dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB));
+ uint32_t reg = (uint32_t)(dev_addr | (num << USB_ADDR_ENDP1_ENDPOINT_LSB));
- if ( dir == TUSB_DIR_OUT )
- {
+ if (dir == TUSB_DIR_OUT) {
reg |= USB_ADDR_ENDP1_INTEP_DIR_BITS;
}
- if ( need_pre(dev_addr) )
- {
+ if (need_pre(dev_addr)) {
reg |= USB_ADDR_ENDP1_INTEP_PREAMBLE_BITS;
}
usb_hw->int_ep_addr_ctrl[ep->interrupt_num] = reg;
@@ -367,8 +325,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
// Finally, enable interrupt that endpoint
usb_hw_set->int_ep_ctrl = 1 << (ep->interrupt_num + 1);
- // If it's an interrupt endpoint we need to set up the buffer control
- // register
+ // If it's an interrupt endpoint we need to set up the buffer control register
}
}
@@ -382,7 +339,7 @@ bool hcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
assert(rhport == 0);
// Reset any previous state
- rp2040_usb_init();
+ rp2usb_init();
// Force VBUS detect to always present, for now we assume vbus is always provided (without using VBUS En)
usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
@@ -466,8 +423,8 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// reset epx if it is currently active with unplugged device
if (epx.configured && epx.active && epx.dev_addr == dev_addr) {
epx.configured = false;
- *epx.endpoint_control = 0;
- *epx.buffer_control = 0;
+ *hwep_ctrl_reg_host(&epx) = 0;
+ *hwbuf_ctrl_reg_host(&epx) = 0;
hw_endpoint_reset_transfer(&epx);
}
@@ -482,54 +439,41 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr) {
// unconfigure the endpoint
ep->configured = false;
- *ep->endpoint_control = 0;
- *ep->buffer_control = 0;
+ *hwep_ctrl_reg_host(ep) = 0;
+ *hwbuf_ctrl_reg_host(ep) = 0;
hw_endpoint_reset_transfer(ep);
}
}
}
}
-uint32_t hcd_frame_number(uint8_t rhport)
-{
- (void) rhport;
+uint32_t hcd_frame_number(uint8_t rhport) {
+ (void)rhport;
return usb_hw->sof_rd;
}
-void hcd_int_enable(uint8_t rhport)
-{
- (void) rhport;
- assert(rhport == 0);
+void hcd_int_enable(uint8_t rhport) {
+ (void)rhport;
irq_set_enabled(USBCTRL_IRQ, true);
}
-void hcd_int_disable(uint8_t rhport)
-{
- (void) rhport;
+void hcd_int_disable(uint8_t rhport) {
+ (void)rhport;
// todo we should check this is disabling from the correct core; note currently this is never called
- assert(rhport == 0);
irq_set_enabled(USBCTRL_IRQ, false);
}
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
-bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc)
-{
- (void) rhport;
-
+bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_endpoint_t *ep_desc) {
+ (void)rhport;
pico_trace("hcd_edpt_open dev_addr %d, ep_addr %d\n", dev_addr, ep_desc->bEndpointAddress);
-
- // Allocated differently based on if it's an interrupt endpoint or not
- struct hw_endpoint *ep = _hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
+ hw_endpoint_t *ep = hw_endpoint_allocate(ep_desc->bmAttributes.xfer);
TU_ASSERT(ep);
- _hw_endpoint_init(ep,
- dev_addr,
- ep_desc->bEndpointAddress,
- tu_edpt_packet_size(ep_desc),
- ep_desc->bmAttributes.xfer,
- ep_desc->bInterval);
+ hw_endpoint_init(ep, dev_addr, ep_desc->bEndpointAddress, tu_edpt_packet_size(ep_desc), ep_desc->bmAttributes.xfer,
+ ep_desc->bInterval);
return true;
}
@@ -539,13 +483,12 @@ bool hcd_edpt_close(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
return false; // TODO not implemented yet
}
-bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen)
-{
+bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen) {
(void) rhport;
pico_trace("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n", dev_addr, ep_addr, buflen);
- uint8_t const ep_num = tu_edpt_number(ep_addr);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
tusb_dir_t const ep_dir = tu_edpt_dir(ep_addr);
// Get appropriate ep. Either EPX or interrupt endpoint
@@ -557,20 +500,18 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
assert(!ep->active);
// Control endpoint can change direction 0x00 <-> 0x80
- if ( ep_addr != ep->ep_addr )
- {
+ if (ep_addr != ep->ep_addr) {
assert(ep_num == 0);
// Direction has flipped on endpoint control so re init it but with same properties
- _hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, ep->transfer_type, 0);
+ hw_endpoint_init(ep, dev_addr, ep_addr, ep->wMaxPacketSize, TUSB_XFER_CONTROL, 0);
}
// If a normal transfer (non-interrupt) then initiate using
// sie ctrl registers. Otherwise, interrupt ep registers should
// already be configured
- if ( ep == &epx )
- {
- hw_endpoint_xfer_start(ep, buffer, buflen);
+ if (ep == &epx) {
+ hw_endpoint_xfer_start(ep, buffer, NULL, buflen);
// That has set up buffer control, endpoint control etc
// for host we have to initiate the transfer
@@ -585,9 +526,8 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
usb_hw->sie_ctrl = flags & ~USB_SIE_CTRL_START_TRANS_BITS;
busy_wait_at_least_cycles(12);
usb_hw->sie_ctrl = flags;
- }else
- {
- hw_endpoint_xfer_start(ep, buffer, buflen);
+ } else {
+ hw_endpoint_xfer_start(ep, buffer, NULL, buflen);
}
return true;
@@ -611,14 +551,14 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
}
// Configure EP0 struct with setup info for the trans complete
- struct hw_endpoint * ep = _hw_endpoint_allocate( (uint8_t) TUSB_XFER_CONTROL);
+ hw_endpoint_t *ep = hw_endpoint_allocate((uint8_t)TUSB_XFER_CONTROL);
TU_ASSERT(ep);
// EPX should be inactive
assert(!ep->active);
// EP0 out
- _hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
+ hw_endpoint_init(ep, dev_addr, 0x00, ep->wMaxPacketSize, 0, 0);
assert(ep->configured);
ep->remaining_len = 8;
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.c b/src/portable/raspberrypi/rp2040/rp2040_usb.c
index 9d0bd762d..3b65f57a4 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.c
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.c
@@ -35,34 +35,35 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTOTYPE
//--------------------------------------------------------------------+
-static void _hw_endpoint_xfer_sync(struct hw_endpoint* ep);
+static void sync_xfer(hw_endpoint_t *ep);
-#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
- static bool e15_is_bulkin_ep(struct hw_endpoint* ep);
- static bool e15_is_critical_frame_period(struct hw_endpoint* ep);
-#else
- #define e15_is_bulkin_ep(x) (false)
- #define e15_is_critical_frame_period(x) (false)
-#endif
-
-// if usb hardware is in host mode
-TU_ATTR_ALWAYS_INLINE static inline bool is_host_mode(void) {
- return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false;
-}
+ #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+static bool e15_is_critical_frame_period(struct hw_endpoint *ep);
+ #else
+ #define e15_is_critical_frame_period(x) (false)
+ #endif
//--------------------------------------------------------------------+
// Implementation
//--------------------------------------------------------------------+
// Provide own byte by byte memcpy as not all copies are aligned
-static void unaligned_memcpy(void *dst, const void *src, size_t n) {
- uint8_t *dst_byte = (uint8_t*)dst;
- const uint8_t *src_byte = (const uint8_t*)src;
+static void unaligned_memcpy(uint8_t *dst, const uint8_t *src, size_t n) {
while (n--) {
- *dst_byte++ = *src_byte++;
+ *dst++ = *src++;
}
}
-void rp2040_usb_init(void) {
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ (void)access_mode;
+ unaligned_memcpy((uint8_t *)(uintptr_t)hwfifo, src, len);
+}
+
+void tu_hwfifo_read(const volatile void *hwfifo, uint8_t *dest, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ (void)access_mode;
+ unaligned_memcpy(dest, (const uint8_t *)(uintptr_t)hwfifo, len);
+}
+
+void rp2usb_init(void) {
// Reset usb controller
reset_block(RESETS_RESET_USBCTRL_BITS);
unreset_block_wait(RESETS_RESET_USBCTRL_BITS);
@@ -93,35 +94,38 @@ void __tusb_irq_path_func(hw_endpoint_reset_transfer)(struct hw_endpoint* ep) {
ep->user_buf = 0;
}
-void __tusb_irq_path_func(_hw_endpoint_buffer_control_update32)(struct hw_endpoint* ep, uint32_t and_mask,
- uint32_t or_mask) {
- uint32_t value = 0;
+void __tusb_irq_path_func(hwbuf_ctrl_update)(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask) {
+ const bool is_host = rp2usb_is_host_mode();
+ uint32_t value = 0;
+ uint32_t buf_ctrl = *buf_ctrl_reg;
if (and_mask) {
- value = *ep->buffer_control & and_mask;
+ value = buf_ctrl & and_mask;
}
if (or_mask) {
value |= or_mask;
if (or_mask & USB_BUF_CTRL_AVAIL) {
- if (*ep->buffer_control & USB_BUF_CTRL_AVAIL) {
- panic("ep %02X was already available", ep->ep_addr);
+ if (buf_ctrl & USB_BUF_CTRL_AVAIL) {
+ panic("buf_ctrl @ 0x%lX already available", (uintptr_t)buf_ctrl_reg);
}
- *ep->buffer_control = value & ~USB_BUF_CTRL_AVAIL;
- // 4.1.2.5.1 Con-current access: 12 cycles (should be good for 48*12Mhz = 576Mhz) after write to buffer control
+ *buf_ctrl_reg = value & ~USB_BUF_CTRL_AVAIL;
+
+ // Section 4.1.2.7.1 (rp2040) / 12.7.3.7.1 (rp2350) Concurrent access: after write to buffer control, we need to
+ // wait at least 1/48 mhz (usb clock), 12 cycles should be good for 48*12Mhz = 576Mhz.
// Don't need delay in host mode as host is in charge
- if (!is_host_mode()) {
+ if (!is_host) {
busy_wait_at_least_cycles(12);
}
}
}
- *ep->buffer_control = value;
+ *buf_ctrl_reg = value;
}
-// prepare buffer, return buffer control
-static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep, uint8_t buf_id) {
- uint16_t const buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
+// prepare buffer, move data if tx, return buffer control
+static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint *ep, uint8_t buf_id, bool is_rx) {
+ const uint16_t buflen = tu_min16(ep->remaining_len, ep->wMaxPacketSize);
ep->remaining_len = (uint16_t) (ep->remaining_len - buflen);
uint32_t buf_ctrl = buflen | USB_BUF_CTRL_AVAIL;
@@ -130,10 +134,18 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep,
buf_ctrl |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
ep->next_pid ^= 1u;
- if (!ep->rx) {
- // Copy data from user buffer to hw buffer
- unaligned_memcpy(ep->hw_data_buf + buf_id * 64, ep->user_buf, buflen);
- ep->user_buf += buflen;
+ if (!is_rx) {
+ if (buflen) {
+ // Copy data from user buffer/fifo to hw buffer
+ uint8_t *hw_buf = ep->hw_data_buf + buf_id * 64;
+ if (ep->is_xfer_fifo) {
+ // not in sram, may mess up timing with E15 workaround
+ tu_hwfifo_write_from_fifo(hw_buf, ep->user_fifo, buflen, NULL);
+ } else {
+ unaligned_memcpy(hw_buf, ep->user_buf, buflen);
+ ep->user_buf += buflen;
+ }
+ }
// Mark as full
buf_ctrl |= USB_BUF_CTRL_FULL;
@@ -146,52 +158,75 @@ static uint32_t __tusb_irq_path_func(prepare_ep_buffer)(struct hw_endpoint* ep,
buf_ctrl |= USB_BUF_CTRL_LAST;
}
- if (buf_id) buf_ctrl = buf_ctrl << 16;
+ if (buf_id) {
+ buf_ctrl = buf_ctrl << 16;
+ }
return buf_ctrl;
}
// Prepare buffer control register value
void __tusb_irq_path_func(hw_endpoint_start_next_buffer)(struct hw_endpoint* ep) {
- uint32_t ep_ctrl = *ep->endpoint_control;
+ const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
+ bool is_rx;
+ bool is_host = false;
+ io_rw_32 *ep_ctrl_reg;
+ io_rw_32 *buf_ctrl_reg;
+
+ #if CFG_TUH_ENABLED
+ is_host = rp2usb_is_host_mode();
+ if (is_host) {
+ buf_ctrl_reg = hwbuf_ctrl_reg_host(ep);
+ ep_ctrl_reg = hwep_ctrl_reg_host(ep);
+ is_rx = (dir == TUSB_DIR_IN);
+ } else
+ #endif
+ {
+ buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ ep_ctrl_reg = hwep_ctrl_reg_device(ep);
+ is_rx = (dir == TUSB_DIR_OUT);
+ }
// always compute and start with buffer 0
- uint32_t buf_ctrl = prepare_ep_buffer(ep, 0) | USB_BUF_CTRL_SEL;
+ uint32_t buf_ctrl = prepare_ep_buffer(ep, 0, is_rx) | USB_BUF_CTRL_SEL;
- // For now: skip double buffered for OUT endpoint in Device mode, since
- // host could send < 64 bytes and cause short packet on buffer0
- // NOTE: this could happen to Host mode IN endpoint
- // Also, Host mode "interrupt" endpoint hardware is only single buffered,
- // NOTE2: Currently Host bulk is implemented using "interrupt" endpoint
- bool const is_host = is_host_mode();
- bool const force_single = (!is_host && !tu_edpt_dir(ep->ep_addr)) ||
- (is_host && tu_edpt_number(ep->ep_addr) != 0);
+ // EP0 has no endpoint control register, also usbd only schedule 1 packet at a time (single buffer)
+ if (ep_ctrl_reg != NULL) {
+ uint32_t ep_ctrl = *ep_ctrl_reg;
- if (ep->remaining_len && !force_single) {
- // Use buffer 1 (double buffered) if there is still data
- // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
+ // For now: skip double buffered for RX e.g OUT endpoint in Device mode, since host could send < 64 bytes and cause
+ // short packet on buffer0
+ // NOTE: this could happen to Host mode IN endpoint Also, Host mode "interrupt" endpoint hardware is only single
+ // buffered,
+ // NOTE2: Currently Host bulk is implemented using "interrupt" endpoint
+ const bool force_single = (!is_host && is_rx) || (is_host && tu_edpt_number(ep->ep_addr) != 0);
- buf_ctrl |= prepare_ep_buffer(ep, 1);
+ if (ep->remaining_len && !force_single) {
+ // Use buffer 1 (double buffered) if there is still data
+ // TODO: Isochronous for buffer1 bit-field is different than CBI (control bulk, interrupt)
- // Set endpoint control double buffered bit if needed
- ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
- ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER;
- } else {
- // Single buffered since 1 is enough
- ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
- ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
- }
+ buf_ctrl |= prepare_ep_buffer(ep, 1, is_rx);
- *ep->endpoint_control = ep_ctrl;
+ // Set endpoint control double buffered bit if needed
+ ep_ctrl &= ~EP_CTRL_INTERRUPT_PER_BUFFER;
+ ep_ctrl |= EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER;
+ } else {
+ // Single buffered since 1 is enough
+ ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
+ ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
+ }
+
+ *ep_ctrl_reg = ep_ctrl;
+ }
TU_LOG(3, " Prepare BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
// Finally, write to buffer_control which will trigger the transfer
// the next time the controller polls this dpram address
- _hw_endpoint_buffer_control_set_value32(ep, buf_ctrl);
+ hwbuf_ctrl_set(buf_ctrl_reg, buf_ctrl);
}
-void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t total_len) {
+void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, tu_fifo_t *ff, uint16_t total_len) {
hw_endpoint_lock_update(ep, 1);
if (ep->active) {
@@ -204,15 +239,25 @@ void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t to
ep->remaining_len = total_len;
ep->xferred_len = 0;
ep->active = true;
- ep->user_buf = buffer;
- if (e15_is_bulkin_ep(ep)) {
+ if (ff != NULL) {
+ ep->user_fifo = ff;
+ ep->is_xfer_fifo = true;
+ } else {
+ ep->user_buf = buffer;
+ ep->is_xfer_fifo = false;
+ }
+
+ #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ if (ep->e15_bulk_in) {
usb_hw_set->inte = USB_INTS_DEV_SOF_BITS;
}
if (e15_is_critical_frame_period(ep)) {
- ep->pending = 1;
- } else {
+ ep->pending = 1; // skip transfer if we are in critical frame period
+ } else
+ #endif
+ {
hw_endpoint_start_next_buffer(ep);
}
@@ -220,31 +265,37 @@ void hw_endpoint_xfer_start(struct hw_endpoint* ep, uint8_t* buffer, uint16_t to
}
// sync endpoint buffer and return transferred bytes
-static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uint8_t buf_id) {
- uint32_t buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
- if (buf_id) buf_ctrl = buf_ctrl >> 16;
+static uint16_t __tusb_irq_path_func(sync_ep_buffer)(hw_endpoint_t *ep, io_rw_32 *buf_ctrl_reg, uint8_t buf_id,
+ bool is_rx) {
+ uint32_t buf_ctrl = *buf_ctrl_reg;
+ if (buf_id) {
+ buf_ctrl = buf_ctrl >> 16;
+ }
- uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
+ const uint16_t xferred_bytes = buf_ctrl & USB_BUF_CTRL_LEN_MASK;
- if (!ep->rx) {
+ if (!is_rx) {
// We are continuing a transfer here. If we are TX, we have successfully
// sent some data can increase the length we have sent
assert(!(buf_ctrl & USB_BUF_CTRL_FULL));
-
- ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
} else {
// If we have received some data, so can increase the length
// we have received AFTER we have copied it to the user buffer at the appropriate offset
assert(buf_ctrl & USB_BUF_CTRL_FULL);
- unaligned_memcpy(ep->user_buf, ep->hw_data_buf + buf_id * 64, xferred_bytes);
- ep->xferred_len = (uint16_t) (ep->xferred_len + xferred_bytes);
- ep->user_buf += xferred_bytes;
+ uint8_t *hw_buf = ep->hw_data_buf + buf_id * 64;
+ if (ep->is_xfer_fifo) {
+ // not in sram, may mess up timing with E15 workaround
+ tu_hwfifo_read_to_fifo(hw_buf, ep->user_fifo, xferred_bytes, NULL);
+ } else {
+ unaligned_memcpy(ep->user_buf, hw_buf, xferred_bytes);
+ ep->user_buf += xferred_bytes;
+ }
}
+ ep->xferred_len += xferred_bytes;
// Short packet
if (xferred_bytes < ep->wMaxPacketSize) {
- pico_trace(" Short packet on buffer %d with %u bytes\r\n", buf_id, xferred_bytes);
// Reduce total length as this is last packet
ep->remaining_len = 0;
}
@@ -252,21 +303,38 @@ static uint16_t __tusb_irq_path_func(sync_ep_buffer)(struct hw_endpoint* ep, uin
return xferred_bytes;
}
-static void __tusb_irq_path_func(_hw_endpoint_xfer_sync)(struct hw_endpoint* ep) {
- // Update hw endpoint struct with info from hardware
- // after a buff status interrupt
+// Update hw endpoint struct with info from hardware after a buff status interrupt
+static void __tusb_irq_path_func(sync_xfer)(hw_endpoint_t *ep) {
+ // const uint8_t ep_num = tu_edpt_number(ep->ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep->ep_addr);
- uint32_t __unused buf_ctrl = _hw_endpoint_buffer_control_get_value32(ep);
- TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(buf_ctrl), tu_u32_high16(buf_ctrl));
+ io_rw_32 *buf_ctrl_reg;
+ io_rw_32 *ep_ctrl_reg;
+ bool is_rx;
- // always sync buffer 0
- uint16_t buf0_bytes = sync_ep_buffer(ep, 0);
+ #if CFG_TUH_ENABLED
+ const bool is_host = rp2usb_is_host_mode();
+ if (is_host) {
+ buf_ctrl_reg = hwbuf_ctrl_reg_host(ep);
+ ep_ctrl_reg = hwep_ctrl_reg_host(ep);
+ is_rx = (dir == TUSB_DIR_IN);
+ } else
+ #endif
+ {
+ buf_ctrl_reg = hwbuf_ctrl_reg_device(ep);
+ ep_ctrl_reg = hwep_ctrl_reg_device(ep);
+ is_rx = (dir == TUSB_DIR_OUT);
+ }
+
+ TU_LOG(3, " Sync BufCtrl: [0] = 0x%04x [1] = 0x%04x\r\n", tu_u32_low16(*buf_ctrl_reg),
+ tu_u32_high16(*buf_ctrl_reg));
+ uint16_t buf0_bytes = sync_ep_buffer(ep, buf_ctrl_reg, 0, is_rx); // always sync buffer 0
// sync buffer 1 if double buffered
- if ((*ep->endpoint_control) & EP_CTRL_DOUBLE_BUFFERED_BITS) {
+ if (ep_ctrl_reg != NULL && (*ep_ctrl_reg) & EP_CTRL_DOUBLE_BUFFERED_BITS) {
if (buf0_bytes == ep->wMaxPacketSize) {
// sync buffer 1 if not short packet
- sync_ep_buffer(ep, 1);
+ sync_ep_buffer(ep, buf_ctrl_reg, 1, is_rx);
} else {
// short packet on buffer 0
// TODO couldn't figure out how to handle this case which happen with net_lwip_webserver example
@@ -287,7 +355,8 @@ static void __tusb_irq_path_func(_hw_endpoint_xfer_sync)(struct hw_endpoint* ep)
ep_ctrl &= ~(EP_CTRL_DOUBLE_BUFFERED_BITS | EP_CTRL_INTERRUPT_PER_DOUBLE_BUFFER);
ep_ctrl |= EP_CTRL_INTERRUPT_PER_BUFFER;
- _hw_endpoint_buffer_control_set_value32(ep, 0);
+ io_rw_32 *buf_ctrl_reg = is_host ? hwbuf_ctrl_reg_host(ep) : hwbuf_ctrl_reg_device(ep);
+ hwbuf_ctrl_set(buf_ctrl_reg, 0);
usb_hw->abort &= ~TU_BIT(ep_id);
@@ -307,8 +376,7 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
panic("Can't continue xfer on inactive ep %02X", ep->ep_addr);
}
- // Update EP struct from hardware state
- _hw_endpoint_xfer_sync(ep);
+ sync_xfer(ep); // Update EP struct from hardware state
// Now we have synced our state with the hardware. Is there more data to transfer?
// If we are done then notify tinyusb
@@ -318,9 +386,12 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
hw_endpoint_lock_update(ep, -1);
return true;
} else {
+ #if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
if (e15_is_critical_frame_period(ep)) {
ep->pending = 1;
- } else {
+ } else
+ #endif
+ {
hw_endpoint_start_next_buffer(ep);
}
}
@@ -335,6 +406,7 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
//--------------------------------------------------------------------+
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+// E15 is fixed with RP2350
/* Don't mark IN buffers as available during the last 200us of a full-speed
frame. This avoids a situation seen with the USB2.0 hub on a Raspberry
@@ -354,16 +426,12 @@ bool __tusb_irq_path_func(hw_endpoint_xfer_continue)(struct hw_endpoint* ep) {
volatile uint32_t e15_last_sof = 0;
-// check if Errata 15 is needed for this endpoint i.e device bulk-in
-static bool __tusb_irq_path_func(e15_is_bulkin_ep)(struct hw_endpoint* ep) {
- return (!is_host_mode() && tu_edpt_dir(ep->ep_addr) == TUSB_DIR_IN &&
- ep->transfer_type == TUSB_XFER_BULK);
-}
-
// check if we need to apply Errata 15 workaround : i.e
// Endpoint is BULK IN and is currently in critical frame period i.e 20% of last usb frame
static bool __tusb_irq_path_func(e15_is_critical_frame_period)(struct hw_endpoint* ep) {
- TU_VERIFY(e15_is_bulkin_ep(ep));
+ if (!ep->e15_bulk_in) {
+ return false;
+ }
/* Avoid the last 200us (uframe 6.5-7) of a frame, up to the EOF2 point.
* The device state machine cannot recover from receiving an incorrect PID
diff --git a/src/portable/raspberrypi/rp2040/rp2040_usb.h b/src/portable/raspberrypi/rp2040/rp2040_usb.h
index d4d29a816..c03dc34b2 100644
--- a/src/portable/raspberrypi/rp2040/rp2040_usb.h
+++ b/src/portable/raspberrypi/rp2040/rp2040_usb.h
@@ -1,29 +1,44 @@
#ifndef RP2040_COMMON_H_
#define RP2040_COMMON_H_
-#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
-#error TinyUSB device and host mode not supported at the same time
-#endif
-
-#include "common/tusb_common.h"
-
#include "pico.h"
#include "hardware/structs/usb.h"
#include "hardware/irq.h"
#include "hardware/resets.h"
#include "hardware/timer.h"
-#if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX)
-#define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
+#include "common/tusb_common.h"
+#include "osal/osal.h"
+#include "common/tusb_fifo.h"
+
+#if defined(RP2040_USB_HOST_MODE) && defined(RP2040_USB_DEVICE_MODE)
+ #error TinyUSB device and host mode not supported at the same time
+#endif
+
+// E5 and E15 only apply to RP2040
+#if defined(PICO_RP2040) && PICO_RP2040 == 1
+ // RP2040 E5: USB device fails to exit RESET state on busy USB bus.
+ #if defined(PICO_RP2040_USB_DEVICE_ENUMERATION_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX)
+ #define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX PICO_RP2040_USB_DEVICE_ENUMERATION_FIX
+ #endif
+
+ // RP2040 E15: USB Device controller will hang if certain bus errors occur during an IN transfer.
+ #if defined(PICO_RP2040_USB_DEVICE_UFRAME_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX)
+ #define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX PICO_RP2040_USB_DEVICE_UFRAME_FIX
+ #endif
+#endif
+
+#ifndef TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
+ #define TUD_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX 0
#endif
-#if defined(PICO_RP2040_USB_DEVICE_UFRAME_FIX) && !defined(TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX)
-#define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX PICO_RP2040_USB_DEVICE_UFRAME_FIX
+#ifndef TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ #define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX 0
#endif
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
-#undef PICO_RP2040_USB_FAST_IRQ
-#define PICO_RP2040_USB_FAST_IRQ 1
+ #undef PICO_RP2040_USB_FAST_IRQ
+ #define PICO_RP2040_USB_FAST_IRQ 1
#endif
#ifndef PICO_RP2040_USB_FAST_IRQ
@@ -36,6 +51,9 @@
#define __tusb_irq_path_func(x) x
#endif
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
#define usb_hw_set ((usb_hw_t *) hw_set_alias_untyped(usb_hw))
#define usb_hw_clear ((usb_hw_t *) hw_clear_alias_untyped(usb_hw))
@@ -43,63 +61,48 @@
#define pico_trace(...) TU_LOG(3, __VA_ARGS__)
// Hardware information per endpoint
-typedef struct hw_endpoint
-{
- // Is this a valid struct
- bool configured;
-
- // Transfer direction (i.e. IN is rx for host but tx for device)
- // allows us to common up transfer functions
- bool rx;
-
- uint8_t ep_addr;
- uint8_t next_pid;
-
- // Endpoint control register
- io_rw_32 *endpoint_control;
-
- // Buffer control register
- io_rw_32 *buffer_control;
-
- // Buffer pointer in usb dpram
- uint8_t *hw_data_buf;
-
- // User buffer in main memory
- uint8_t *user_buf;
-
- // Current transfer information
- uint16_t remaining_len;
- uint16_t xferred_len;
+typedef struct hw_endpoint {
+ uint8_t ep_addr;
+ uint8_t next_pid;
+ bool active; // transferring data
+ bool is_xfer_fifo; // transfer using fifo
- // Data needed from EP descriptor
- uint16_t wMaxPacketSize;
-
- // Endpoint is in use
- bool active;
-
- // Interrupt, bulk, etc
- uint8_t transfer_type;
-
- // Transfer scheduled but not active
- uint8_t pending;
+#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
+ bool e15_bulk_in; // Errata15 device bulk in
+ uint8_t pending; // Transfer scheduled but not active
+#endif
#if CFG_TUH_ENABLED
- // Only needed for host
- uint8_t dev_addr;
-
- // If interrupt endpoint
- uint8_t interrupt_num;
+ bool configured; // Is this a valid struct
+ uint8_t dev_addr;
+ uint8_t interrupt_num; // for host interrupt endpoints
#endif
+ uint16_t wMaxPacketSize;
+ uint8_t *hw_data_buf; // Buffer pointer in usb dpram
+
+ // transfer info
+ union {
+ uint8_t *user_buf; // User buffer in main memory
+ tu_fifo_t *user_fifo;
+ };
+ uint16_t remaining_len;
+ uint16_t xferred_len;
+
} hw_endpoint_t;
#if TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
extern volatile uint32_t e15_last_sof;
#endif
-void rp2040_usb_init(void);
+void rp2usb_init(void);
+
+// if usb hardware is in host mode
+TU_ATTR_ALWAYS_INLINE static inline bool rp2usb_is_host_mode(void) {
+ return (usb_hw->main_ctrl & USB_MAIN_CTRL_HOST_NDEVICE_BITS) ? true : false;
+}
-void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, uint16_t total_len);
+void hw_endpoint_xfer_start(struct hw_endpoint *ep, uint8_t *buffer, tu_fifo_t *ff, uint16_t total_len);
bool hw_endpoint_xfer_continue(struct hw_endpoint *ep);
void hw_endpoint_reset_transfer(struct hw_endpoint *ep);
void hw_endpoint_start_next_buffer(struct hw_endpoint *ep);
@@ -110,34 +113,60 @@ TU_ATTR_ALWAYS_INLINE static inline void hw_endpoint_lock_update(__unused struct
// sense to have worker and IRQ on same core, however I think using critsec is about equivalent.
}
-void _hw_endpoint_buffer_control_update32(struct hw_endpoint *ep, uint32_t and_mask, uint32_t or_mask);
+// #if CFG_TUD_ENABLED
+TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_ctrl_reg_device(struct hw_endpoint *ep) {
+ uint8_t const epnum = tu_edpt_number(ep->ep_addr);
+ const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr);
+ if (epnum == 0) {
+ // EP0 has no endpoint control register because the buffer offsets are fixed and always enabled
+ return NULL;
+ }
+ return (dir == TUSB_DIR_IN) ? &usb_dpram->ep_ctrl[epnum - 1].in : &usb_dpram->ep_ctrl[epnum - 1].out;
+}
-TU_ATTR_ALWAYS_INLINE static inline uint32_t _hw_endpoint_buffer_control_get_value32 (struct hw_endpoint *ep)
-{
- return *ep->buffer_control;
+TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwbuf_ctrl_reg_device(struct hw_endpoint *ep) {
+ const uint8_t epnum = tu_edpt_number(ep->ep_addr);
+ const uint8_t dir = (uint8_t)tu_edpt_dir(ep->ep_addr);
+ return (dir == TUSB_DIR_IN) ? &usb_dpram->ep_buf_ctrl[epnum].in : &usb_dpram->ep_buf_ctrl[epnum].out;
}
+// #endif
-TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_value32 (struct hw_endpoint *ep, uint32_t value)
-{
- _hw_endpoint_buffer_control_update32(ep, 0, value);
+#if CFG_TUH_ENABLED
+TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwep_ctrl_reg_host(struct hw_endpoint *ep) {
+ if (tu_edpt_number(ep->ep_addr) == 0) {
+ return &usbh_dpram->epx_ctrl;
+ }
+ return &usbh_dpram->int_ep_ctrl[ep->interrupt_num].ctrl;
}
-TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_set_mask32 (struct hw_endpoint *ep, uint32_t value)
-{
- _hw_endpoint_buffer_control_update32(ep, ~value, value);
+TU_ATTR_ALWAYS_INLINE static inline io_rw_32 *hwbuf_ctrl_reg_host(struct hw_endpoint *ep) {
+ if (tu_edpt_number(ep->ep_addr) == 0) {
+ return &usbh_dpram->epx_buf_ctrl;
+ }
+ return &usbh_dpram->int_ep_buffer_ctrl[ep->interrupt_num].ctrl;
}
+#endif
-TU_ATTR_ALWAYS_INLINE static inline void _hw_endpoint_buffer_control_clear_mask32 (struct hw_endpoint *ep, uint32_t value)
-{
- _hw_endpoint_buffer_control_update32(ep, ~value, 0);
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+void hwbuf_ctrl_update(io_rw_32 *buf_ctrl_reg, uint32_t and_mask, uint32_t or_mask);
+
+TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set(io_rw_32 *buf_ctrl_reg, uint32_t value) {
+ hwbuf_ctrl_update(buf_ctrl_reg, 0, value);
}
-static inline uintptr_t hw_data_offset (uint8_t *buf)
-{
- // Remove usb base from buffer pointer
- return (uintptr_t) buf ^ (uintptr_t) usb_dpram;
+TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_set_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) {
+ hwbuf_ctrl_update(buf_ctrl_reg, ~value, value);
}
-extern const char *ep_dir_string[];
+TU_ATTR_ALWAYS_INLINE static inline void hwbuf_ctrl_clear_mask(io_rw_32 *buf_ctrl_reg, uint32_t value) {
+ hwbuf_ctrl_update(buf_ctrl_reg, ~value, 0);
+}
+
+static inline uintptr_t hw_data_offset(uint8_t *buf) {
+ // Remove usb base from buffer pointer
+ return (uintptr_t)buf ^ (uintptr_t)usb_dpram;
+}
#endif
diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c
index 779c7bc3d..e2a51a5ca 100644
--- a/src/portable/renesas/rusb2/dcd_rusb2.c
+++ b/src/portable/renesas/rusb2/dcd_rusb2.c
@@ -30,25 +30,7 @@
#if CFG_TUD_ENABLED && defined(TUP_USBIP_RUSB2)
#include "device/dcd.h"
-#include "rusb2_type.h"
-
-#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
- #include "rusb2_rx.h"
-#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
- #include "rusb2_ra.h"
- #if defined(RENESAS_CORTEX_M23)
- #define D0FIFO CFIFO
- #define D0FIFOSEL CFIFOSEL
- #define D0FIFOSEL_b CFIFOSEL_b
- #define D1FIFOSEL CFIFOSEL
- #define D1FIFOSEL_b CFIFOSEL_b
- #define D0FIFOCTR CFIFOCTR
- #define D0FIFOCTR_b CFIFOCTR_b
- #endif
-
-#else
- #error "Unsupported MCU"
-#endif
+#include "rusb2_common.h"
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM
@@ -161,106 +143,11 @@ static inline void pipe_wait_for_ready(rusb2_reg_t * rusb, unsigned num) {
}
//--------------------------------------------------------------------+
-// Pipe FIFO
-//--------------------------------------------------------------------+
-
-// Write data buffer --> hw fifo
-static void pipe_write_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len)
-{
- (void) rusb;
-
- volatile uint16_t *ff16;
- volatile uint8_t *ff8;
-
- // Highspeed FIFO is 32-bit
- if ( rusb2_is_highspeed_reg(rusb) ) {
- // TODO 32-bit access for better performance
- ff16 = (volatile uint16_t*) ((uintptr_t) fifo+2);
- ff8 = (volatile uint8_t *) ((uintptr_t) fifo+3);
- }else {
- ff16 = (volatile uint16_t*) fifo;
- ff8 = ((volatile uint8_t*) fifo);
- }
-
- uint8_t const* buf8 = (uint8_t const*) buf;
-
- while (len >= 2) {
- *ff16 = tu_unaligned_read16(buf8);
- buf8 += 2;
- len -= 2;
- }
-
- if (len > 0) {
- *ff8 = *buf8;
- ++buf8;
- }
-}
-
-// Read data buffer <-- hw fifo
-static void pipe_read_packet(rusb2_reg_t * rusb, void *buf, volatile void *fifo, unsigned len)
-{
- (void) rusb;
-
- // TODO 16/32-bit access for better performance
-
- uint8_t *p = (uint8_t*)buf;
- volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
- while (len--) *p++ = *reg;
-}
-
-// Write data sw fifo --> hw fifo
-static void pipe_write_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) {
- tu_fifo_buffer_info_t info;
- tu_fifo_get_read_info(f, &info);
-
- uint16_t cnt_lin = tu_min16(total_len, info.linear.len);
- uint16_t cnt_wrap = tu_min16(total_len - cnt_lin, info.wrapped.len);
- uint16_t const cnt_written = cnt_lin + cnt_wrap;
-
- // Ensure only the last write is odd if total_len is odd
- if (cnt_wrap == 0) {
- pipe_write_packet(rusb, info.linear.ptr, fifo, cnt_lin);
- } else {
- pipe_write_packet(rusb, info.linear.ptr, fifo, cnt_lin & ~1);
-
- if (cnt_lin & 1) {
- uint8_t glue[2] = {info.linear.ptr[cnt_lin & ~1], info.wrapped.ptr[0]};
- pipe_write_packet(rusb, glue, fifo, 2);
- cnt_wrap--;
- info.wrapped.ptr++;
- }
-
- pipe_write_packet(rusb, info.wrapped.ptr, fifo, cnt_wrap);
- }
- tu_fifo_advance_read_pointer(f, cnt_written);
-}
-
-// Read data sw fifo <-- hw fifo
-static void pipe_read_packet_ff(rusb2_reg_t * rusb, tu_fifo_t *f, volatile void *fifo, uint16_t total_len) {
- tu_fifo_buffer_info_t info;
- tu_fifo_get_write_info(f, &info);
-
- uint16_t count = tu_min16(total_len, info.linear.len);
- pipe_read_packet(rusb, info.linear.ptr, fifo, count);
-
- uint16_t rem = total_len - count;
- if (rem) {
- rem = tu_min16(rem, info.wrapped.len);
- pipe_read_packet(rusb, info.wrapped.ptr, fifo, rem);
- count += rem;
- }
-
- tu_fifo_advance_write_pointer(f, count);
-}
-
-//--------------------------------------------------------------------+
// Pipe Transfer
//--------------------------------------------------------------------+
-
-static bool pipe0_xfer_in(rusb2_reg_t* rusb)
-{
- pipe_state_t *pipe = &_dcd.pipe[0];
- const unsigned rem = pipe->remaining;
+static bool pipe0_xfer_in(rusb2_reg_t *rusb) {
+ pipe_state_t *pipe = &_dcd.pipe[0];
+ const unsigned rem = pipe->remaining;
if (!rem) {
pipe->buf = NULL;
@@ -272,11 +159,25 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
void *buf = pipe->buf;
if (len) {
+ // uint16_t fifo_sel = RUSB2_CFIFOSEL_ISEL_WRITE | FIFOSEL_BIGEND;
+ tu_hwfifo_access_t access_mode;
+ access_mode.param = (uintptr_t)rusb;
+ //
+ if (rusb2_is_highspeed_reg(rusb)) {
+ // fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
+ access_mode.data_stride = 4u;
+ } else {
+ // fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
+ access_mode.data_stride = 2u;
+ }
+ // rusb->CFIFOSEL = fifo_sel;
+ // while (0 == (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) {}
+
if (pipe->ff) {
- pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_write_from_fifo(&rusb->CFIFO, (tu_fifo_t *)buf, len, &access_mode);
} else {
- pipe_write_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len);
- pipe->buf = (uint8_t*)buf + len;
+ tu_hwfifo_write(&rusb->CFIFO, buf, len, &access_mode);
+ pipe->buf = (uint8_t *)buf + len;
}
}
@@ -288,10 +189,9 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
return false;
}
-static bool pipe0_xfer_out(rusb2_reg_t* rusb)
-{
- pipe_state_t *pipe = &_dcd.pipe[0];
- const unsigned rem = pipe->remaining;
+static bool pipe0_xfer_out(rusb2_reg_t *rusb) {
+ pipe_state_t *pipe = &_dcd.pipe[0];
+ const unsigned rem = pipe->remaining;
const uint16_t mps = edpt0_max_packet_size(rusb);
const uint16_t vld = rusb->CFIFOCTR_b.DTLN;
@@ -299,11 +199,14 @@ static bool pipe0_xfer_out(rusb2_reg_t* rusb)
void *buf = pipe->buf;
if (len) {
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+
if (pipe->ff) {
- pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_read_to_fifo(&rusb->CFIFO, (tu_fifo_t *)buf, len, &access_mode);
} else {
- pipe_read_packet(rusb, buf, (volatile void*)&rusb->CFIFO, len);
- pipe->buf = (uint8_t*)buf + len;
+ tu_hwfifo_read(&rusb->CFIFO, buf, len, &access_mode);
+ pipe->buf = (uint8_t *)buf + len;
}
}
@@ -330,18 +233,27 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
return true;
}
- rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
- const uint16_t mps = edpt_max_packet_size(rusb, num);
+ const uint16_t fifo_sel = num | FIFOSEL_BIGEND;
+ const bool is_highspeed = rusb2_is_highspeed_reg(rusb);
+ if (is_highspeed) {
+ rusb->D0FIFOSEL = fifo_sel | RUSB2_FIFOSEL_MBW_32BIT;
+ } else {
+ rusb->D0FIFOSEL = fifo_sel | RUSB2_FIFOSEL_MBW_16BIT;
+ }
+
+ const uint16_t mps = edpt_max_packet_size(rusb, num);
pipe_wait_for_ready(rusb, num);
- const uint16_t len = tu_min16(rem, mps);
- void *buf = pipe->buf;
+ uint16_t len = tu_min16(rem, mps);
+ void *buf = pipe->buf;
if (len) {
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
if (pipe->ff) {
- pipe_write_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len);
+ tu_hwfifo_write_from_fifo(&rusb->D0FIFO, (tu_fifo_t *)buf, len, &access_mode);
} else {
- pipe_write_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len);
- pipe->buf = (uint8_t*)buf + len;
+ tu_hwfifo_write(&rusb->D0FIFO, buf, len, &access_mode);
+ pipe->buf = (uint8_t *)buf + len;
}
}
@@ -362,7 +274,14 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
pipe_state_t *pipe = &_dcd.pipe[num];
const uint16_t rem = pipe->remaining;
- rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
+ uint16_t fifo_sel = num | FIFOSEL_BIGEND;
+ if (rusb2_is_highspeed_reg(rusb)) {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
+ } else {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
+ }
+ rusb->D0FIFOSEL = fifo_sel;
+
const uint16_t mps = edpt_max_packet_size(rusb, num);
pipe_wait_for_ready(rusb, num);
@@ -371,11 +290,13 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
void *buf = pipe->buf;
if (len) {
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
if (pipe->ff) {
- pipe_read_packet_ff(rusb, (tu_fifo_t*)buf, (volatile void*)&rusb->D0FIFO, len);
+ tu_hwfifo_read_to_fifo(&rusb->D0FIFO, (tu_fifo_t *)buf, len, &access_mode);
} else {
- pipe_read_packet(rusb, buf, (volatile void*)&rusb->D0FIFO, len);
- pipe->buf = (uint8_t*)buf + len;
+ tu_hwfifo_read(&rusb->D0FIFO, buf, len, &access_mode);
+ pipe->buf = (uint8_t *)buf + len;
}
}
@@ -428,28 +349,29 @@ static void process_status_completion(uint8_t rhport)
dcd_event_xfer_complete(rhport, ep_addr, 0, XFER_RESULT_SUCCESS, true);
}
-static bool process_pipe0_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_addr, void* buffer, uint16_t total_bytes)
-{
+static bool process_pipe0_xfer(rusb2_reg_t *rusb, int buffer_type, uint8_t ep_addr, void *buffer,
+ uint16_t total_bytes) {
+ uint16_t fifo_sel =
+ (rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND;
+
/* configure fifo direction and access unit settings */
- if ( ep_addr ) {
- /* IN, 2 bytes */
- rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
- (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
- while ( !(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ) {}
- } else {
- /* OUT, a byte */
- rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
- while ( rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE ) {}
+ if (ep_addr != 0) {
+ // Control IN
+ fifo_sel |= RUSB2_CFIFOSEL_ISEL_WRITE;
+ }
+ rusb->CFIFOSEL = fifo_sel;
+ while ((rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) != (fifo_sel & RUSB2_CFIFOSEL_ISEL_WRITE)) {
+ // wait until ISEL_WRITE take effect
}
pipe_state_t *pipe = &_dcd.pipe[0];
- pipe->ff = buffer_type;
- pipe->length = total_bytes;
- pipe->remaining = total_bytes;
+ pipe->ff = buffer_type;
+ pipe->length = total_bytes;
+ pipe->remaining = total_bytes;
- if ( total_bytes ) {
+ if (total_bytes) {
pipe->buf = buffer;
- if ( ep_addr ) {
+ if (ep_addr) {
/* IN */
TU_ASSERT(rusb->DCPCTR_b.BSTS && (rusb->USBREQ & 0x80));
pipe0_xfer_in(rusb);
@@ -525,7 +447,7 @@ static bool process_edpt_xfer(rusb2_reg_t* rusb, int buffer_type, uint8_t ep_add
static void process_pipe0_bemp(uint8_t rhport)
{
rusb2_reg_t* rusb = RUSB2_REG(rhport);
- bool completed = pipe0_xfer_in(rusb);
+ bool completed = pipe0_xfer_in(rusb);
if (completed) {
pipe_state_t *pipe = &_dcd.pipe[0];
dcd_event_xfer_complete(rhport, tu_edpt_addr(0, TUSB_DIR_IN),
@@ -621,18 +543,20 @@ static void process_set_address(uint8_t rhport)
{
rusb2_reg_t* rusb = RUSB2_REG(rhport);
const uint16_t addr = rusb->USBADDR_b.USBADDR;
- if (!addr) return;
+ if (!addr) {
+ return;
+ }
const tusb_control_request_t setup_packet = {
#if defined(__CCRX__)
.bmRequestType = { 0 }, /* Note: CCRX needs the braces over this struct member */
-#else
- .bmRequestType = 0,
-#endif
- .bRequest = TUSB_REQ_SET_ADDRESS,
- .wValue = addr,
- .wIndex = 0,
- .wLength = 0,
+ #else
+ .bmRequestType = 0,
+ #endif
+ .bRequest = TUSB_REQ_SET_ADDRESS,
+ .wValue = addr,
+ .wIndex = 0,
+ .wLength = 0,
};
dcd_event_setup_received(rhport, (const uint8_t *) &setup_packet, true);
@@ -899,7 +823,6 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
{
(void) is_isr;
// USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
- TU_ASSERT(ff->item_size == 1);
rusb2_reg_t* rusb = RUSB2_REG(rhport);
dcd_int_disable(rhport);
@@ -912,7 +835,9 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
{
volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
- if (!ctr) return;
+ if (!ctr) {
+ return;
+ }
dcd_int_disable(rhport);
const uint32_t pid = *ctr & 0x3;
*ctr = pid | RUSB2_PIPE_CTR_PID_STALL;
@@ -924,7 +849,9 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
{
rusb2_reg_t * rusb = RUSB2_REG(rhport);
volatile uint16_t *ctr = ep_addr_to_pipectr(rhport, ep_addr);
- if (!ctr) return;
+ if (!ctr) {
+ return;
+ }
dcd_int_disable(rhport);
*ctr = RUSB2_PIPE_CTR_SQCLR_Msk;
diff --git a/src/portable/renesas/rusb2/hcd_rusb2.c b/src/portable/renesas/rusb2/hcd_rusb2.c
index 6f6d27d0e..4c3315044 100644
--- a/src/portable/renesas/rusb2/hcd_rusb2.c
+++ b/src/portable/renesas/rusb2/hcd_rusb2.c
@@ -31,17 +31,9 @@
#include "host/hcd.h"
#include "host/usbh.h"
-#include "rusb2_type.h"
+#include "rusb2_common.h"
-#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
- #include "rusb2_rx.h"
-#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
- #include "rusb2_ra.h"
-#else
- #error "Unsupported MCU"
-#endif
-
-#define TU_RUSB2_HCD_DBG 2
+ #define TU_RUSB2_HCD_DBG 2
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
@@ -76,12 +68,10 @@ typedef struct TU_ATTR_PACKED {
TU_ATTR_PACKED_END // End of definition of packed structs (used by the CCRX toolchain)
TU_ATTR_BIT_FIELD_ORDER_END
-typedef struct
-{
- bool need_reset; /* The device has not been reset after connection. */
+typedef struct {
pipe_state_t pipe[PIPE_COUNT];
- uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
- uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
+ uint8_t ep[4][2][15]; /* a lookup table for a pipe index from an endpoint address */
+ uint8_t ctl_mps[5]; /* EP0 max packet size for each device */
} hcd_data_t;
//--------------------------------------------------------------------+
@@ -166,29 +156,6 @@ static inline void pipe_wait_for_ready(rusb2_reg_t* rusb, unsigned num)
while (!rusb->D0FIFOCTR_b.FRDY) {}
}
-static void pipe_write_packet(void *buf, volatile void *fifo, unsigned len)
-{
- // NOTE: unlike DCD, Highspeed 32-bit FIFO does not need to adjust the fifo address
- volatile hw_fifo_t *reg = (volatile hw_fifo_t*)fifo;
- uintptr_t addr = (uintptr_t)buf;
- while (len >= 2) {
- reg->u16 = *(const uint16_t *)addr;
- addr += 2;
- len -= 2;
- }
- if (len) {
- reg->u8 = *(const uint8_t *)addr;
- ++addr;
- }
-}
-
-static void pipe_read_packet(void *buf, volatile void *fifo, unsigned len)
-{
- uint8_t *p = (uint8_t*)buf;
- volatile uint8_t *reg = (volatile uint8_t*)fifo; /* byte access is always at base register address */
- while (len--) *p++ = *reg;
-}
-
static bool pipe0_xfer_in(rusb2_reg_t* rusb)
{
pipe_state_t *pipe = &_hcd.pipe[0];
@@ -199,8 +166,12 @@ static bool pipe0_xfer_in(rusb2_reg_t* rusb)
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
void *buf = pipe->buf;
if (len) {
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+
rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
- pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ // pipe_read_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_read(&rusb->CFIFO, buf, len, &access_mode);
pipe->buf = (uint8_t*)buf + len;
}
if (len < mps) {
@@ -227,7 +198,11 @@ static bool pipe0_xfer_out(rusb2_reg_t* rusb)
const unsigned len = TU_MIN(mps, rem);
void *buf = pipe->buf;
if (len) {
- pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+
+ // pipe_write_packet(buf, (volatile void*)&rusb->CFIFO, len);
+ tu_hwfifo_write(&rusb->CFIFO, buf, len, &access_mode);
pipe->buf = (uint8_t*)buf + len;
}
if (len < mps) {
@@ -242,14 +217,24 @@ static bool pipe_xfer_in(rusb2_reg_t* rusb, unsigned num)
pipe_state_t *pipe = &_hcd.pipe[num];
const unsigned rem = pipe->remaining;
- rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_8BIT;
+ uint16_t fifo_sel = num | FIFOSEL_BIGEND;
+ if (rusb2_is_highspeed_reg(rusb)) {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
+ } else {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
+ }
+ rusb->D0FIFOSEL = fifo_sel;
+
const unsigned mps = edpt_max_packet_size(rusb, num);
pipe_wait_for_ready(rusb, num);
const unsigned vld = rusb->D0FIFOCTR_b.DTLN;
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
void *buf = pipe->buf;
if (len) {
- pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ // pipe_read_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+ tu_hwfifo_read(&rusb->D0FIFO, buf, len, &access_mode);
pipe->buf = (uint8_t*)buf + len;
}
if (len < mps) {
@@ -275,13 +260,23 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
return true;
}
- rusb->D0FIFOSEL = num | RUSB2_FIFOSEL_MBW_16BIT | (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
+ uint16_t fifo_sel = num | FIFOSEL_BIGEND;
+ if (rusb2_is_highspeed_reg(rusb)) {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_32BIT;
+ } else {
+ fifo_sel |= RUSB2_FIFOSEL_MBW_16BIT;
+ }
+ rusb->D0FIFOSEL = fifo_sel;
+
const unsigned mps = edpt_max_packet_size(rusb, num);
pipe_wait_for_ready(rusb, num);
const unsigned len = TU_MIN(rem, mps);
void *buf = pipe->buf;
if (len) {
- pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ // pipe_write_packet(buf, (volatile void*)&rusb->D0FIFO, len);
+ tu_hwfifo_access_t access_mode = {.data_stride = (rusb2_is_highspeed_reg(rusb) ? 4u : 2u),
+ .param = (uintptr_t)rusb};
+ tu_hwfifo_write(&rusb->D0FIFO, buf, len, &access_mode);
pipe->buf = (uint8_t*)buf + len;
}
if (len < mps) {
@@ -296,18 +291,19 @@ static bool pipe_xfer_out(rusb2_reg_t* rusb, unsigned num)
static bool process_pipe0_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, void* buffer, uint16_t buflen)
{
(void)dev_addr;
-
rusb2_reg_t* rusb = RUSB2_REG(rhport);
const unsigned dir_in = tu_edpt_dir(ep_addr);
+ uint16_t fifo_sel =
+ (rusb2_is_highspeed_reg(rusb) ? RUSB2_FIFOSEL_MBW_32BIT : RUSB2_FIFOSEL_MBW_16BIT) | FIFOSEL_BIGEND;
+
/* configure fifo direction and access unit settings */
- if (dir_in) { /* IN, a byte */
- rusb->CFIFOSEL = RUSB2_FIFOSEL_MBW_8BIT;
- while (rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) ;
- } else { /* OUT, 2 bytes */
- rusb->CFIFOSEL = RUSB2_CFIFOSEL_ISEL_WRITE | RUSB2_FIFOSEL_MBW_16BIT |
- (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0);
- while (!(rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE)) ;
+ if (dir_in == TUSB_DIR_OUT) {
+ fifo_sel |= RUSB2_CFIFOSEL_ISEL_WRITE;
+ }
+ rusb->CFIFOSEL = fifo_sel;
+ while ((rusb->CFIFOSEL & RUSB2_CFIFOSEL_ISEL_WRITE) != (fifo_sel & RUSB2_CFIFOSEL_ISEL_WRITE)) {
+ // wait until ISEL_WRITE take effect
}
pipe_state_t *pipe = &_hcd.pipe[0];
@@ -535,13 +531,8 @@ void hcd_int_disable(uint8_t rhport) {
rusb2_int_disable(rhport);
}
-uint32_t hcd_frame_number(uint8_t rhport)
-{
- rusb2_reg_t* rusb = RUSB2_REG(rhport);
-
- /* The device must be reset at least once after connection
- * in order to start the frame counter. */
- if (_hcd.need_reset) hcd_port_reset(rhport);
+uint32_t hcd_frame_number(uint8_t rhport) {
+ rusb2_reg_t *rusb = RUSB2_REG(rhport);
return rusb->FRMNUM_b.FRNM;
}
@@ -550,32 +541,18 @@ uint32_t hcd_frame_number(uint8_t rhport)
*--------------------------------------------------------------------+*/
bool hcd_port_connect_status(uint8_t rhport) {
rusb2_reg_t* rusb = RUSB2_REG(rhport);
- return rusb->INTSTS1_b.ATTCH ? true : false;
+ const uint16_t line_state = rusb->SYSSTS0 & RUSB2_SYSSTS0_LNST_Msk;
+ return line_state == RUSB2_SYSSTS0_LNST_FS_J || line_state == RUSB2_SYSSTS0_LNST_FS_K;
}
void hcd_port_reset(uint8_t rhport) {
rusb2_reg_t* rusb = RUSB2_REG(rhport);
- rusb->DCPCTR = RUSB2_PIPE_CTR_PID_NAK;
- while (rusb->DCPCTR_b.PBUSY) {}
-
- hcd_int_disable(rhport);
- rusb->DVSTCTR0_b.UACT = 0;
- if (rusb->DCPCTR_b.SUREQ) {
- rusb->DCPCTR_b.SUREQCLR = 1;
- }
- hcd_int_enable(rhport);
-
- /* Reset should be asserted 10-20ms. */
rusb->DVSTCTR0_b.USBRST = 1;
- for (volatile int i = 0; i < 2400000; ++i) {}
- rusb->DVSTCTR0_b.USBRST = 0;
-
- rusb->DVSTCTR0_b.UACT = 1;
- _hcd.need_reset = false;
}
void hcd_port_reset_end(uint8_t rhport) {
- (void) rhport;
+ rusb2_reg_t *rusb = RUSB2_REG(rhport);
+ rusb->DVSTCTR0_b.USBRST = 0;
}
tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
@@ -584,7 +561,8 @@ tusb_speed_t hcd_port_speed_get(uint8_t rhport) {
case RUSB2_DVSTCTR0_RHST_HS: return TUSB_SPEED_HIGH;
case RUSB2_DVSTCTR0_RHST_FS: return TUSB_SPEED_FULL;
case RUSB2_DVSTCTR0_RHST_LS: return TUSB_SPEED_LOW;
- default: return TUSB_SPEED_INVALID;
+ default:
+ return TUSB_SPEED_INVALID;
}
}
@@ -802,7 +780,6 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (is1 & RUSB2_INTSTS1_ATTCH_Msk) {
rusb->DVSTCTR0_b.UACT = 1;
- _hcd.need_reset = true;
rusb->INTENB1 = (rusb->INTENB1 & ~RUSB2_INTSTS1_ATTCH_Msk) | RUSB2_INTSTS1_DTCH_Msk;
hcd_event_device_attach(rhport, true);
}
diff --git a/src/portable/renesas/rusb2/rusb2_common.c b/src/portable/renesas/rusb2/rusb2_common.c
index 856f9714f..8addbe4c6 100644
--- a/src/portable/renesas/rusb2/rusb2_common.c
+++ b/src/portable/renesas/rusb2/rusb2_common.c
@@ -27,20 +27,19 @@
#include "tusb_option.h"
#if defined(TUP_USBIP_RUSB2) && (CFG_TUH_ENABLED || CFG_TUD_ENABLED)
+ #include "osal/osal.h"
+ #include "common/tusb_fifo.h"
-#include "rusb2_type.h"
+ #include "rusb2_common.h"
-#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
-#include "rusb2_rx.h"
-
-#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
-#include "rusb2_ra.h"
+ #if TU_CHECK_MCU(OPT_MCU_RAXXX)
+ #include "rusb2_ra.h"
// USBFS_INT_IRQn and USBHS_USB_INT_RESUME_IRQn are generated by FSP
rusb2_controller_t rusb2_controller[] = {
- { .reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn },
+ {.reg_base = R_USB_FS0_BASE, .irqnum = USBFS_INT_IRQn},
#ifdef RUSB2_SUPPORT_HIGHSPEED
- { .reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn },
+ {.reg_base = R_USB_HS0_BASE, .irqnum = USBHS_USB_INT_RESUME_IRQn},
#endif
};
@@ -49,10 +48,69 @@ void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum);
void tusb_rusb2_set_irqnum(uint8_t rhport, int32_t irqnum) {
rusb2_controller[rhport].irqnum = irqnum;
}
+ #endif
-#else
- #error "Unsupported MCU"
-#endif
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+static void hwfifo_set_mbw(rusb2_reg_t *rusb, uintptr_t hwfifo, uint16_t mbw) {
+ volatile uint16_t *fifo_sel;
+ if (hwfifo == (uintptr_t)&rusb->CFIFO) {
+ fifo_sel = &rusb->CFIFOSEL;
+ } else if (hwfifo == (uintptr_t)&rusb->D0FIFO) {
+ fifo_sel = &rusb->D0FIFOSEL;
+ } else if (hwfifo == (uintptr_t)&rusb->D1FIFO) {
+ fifo_sel = &rusb->D1FIFOSEL;
+ } else {
+ return;
+ }
+
+ *fifo_sel = (*fifo_sel & ~RUSB2_CFIFOSEL_MBW_Msk) | mbw;
+}
+
+// write to hwfifo from buffer with access mode
+void tu_hwfifo_write(volatile void *hwfifo, const uint8_t *src, uint16_t len, const tu_hwfifo_access_t *access_mode) {
+ rusb2_reg_t *rusb = (rusb2_reg_t *)access_mode->param;
+ const uint8_t *buf8 = (const uint8_t *)src;
+ volatile uint16_t *ff16;
+ volatile uint8_t *ff8;
+ const bool is_highspeed = rusb2_is_highspeed_reg(rusb);
+ if (is_highspeed) {
+ ff16 = (volatile uint16_t *)((uintptr_t)hwfifo + 2);
+ ff8 = (volatile uint8_t *)((uintptr_t)hwfifo + 3);
+ } else {
+ ff16 = (volatile uint16_t *)hwfifo;
+ ff8 = ((volatile uint8_t *)hwfifo);
+ }
+
+ // 32-bit access for highspeed
+ if (is_highspeed) {
+ volatile uint32_t *ff32 = (volatile uint32_t *)hwfifo;
+ while (len >= 4) {
+ *ff32 = tu_unaligned_read32(buf8);
+ buf8 += 4;
+ len -= 4;
+ }
+
+ if (len >= 2) {
+ // switch to 16-bit access
+ hwfifo_set_mbw(rusb, (uintptr_t)hwfifo, RUSB2_FIFOSEL_MBW_16BIT);
+ }
+ }
+
+ // 16-bit access
+ while (len >= 2) {
+ *ff16 = tu_unaligned_read16(buf8);
+ buf8 += 2;
+ len -= 2;
+ }
+
+ // 8-bit access does not need to change MBW
+ if (len > 0) {
+ *ff8 = *buf8;
+ ++buf8;
+ }
+}
#endif
diff --git a/src/portable/renesas/rusb2/rusb2_common.h b/src/portable/renesas/rusb2/rusb2_common.h
new file mode 100644
index 000000000..6b8c3d7f2
--- /dev/null
+++ b/src/portable/renesas/rusb2/rusb2_common.h
@@ -0,0 +1,58 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Ha Thach (tinyusb.org)
+ *
+ * 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.
+ */
+#pragma once
+
+#include "common/tusb_common.h"
+#include "rusb2_type.h"
+
+#if TU_CHECK_MCU(OPT_MCU_RX63X, OPT_MCU_RX65X, OPT_MCU_RX72N)
+ #include "rusb2_rx.h"
+#elif TU_CHECK_MCU(OPT_MCU_RAXXX)
+ #include "rusb2_ra.h"
+
+ // Hack for D0FIFO definitions on RA Cortex-M23
+ #if defined(RENESAS_CORTEX_M23)
+ #define D0FIFO CFIFO
+ #define D0FIFOSEL CFIFOSEL
+ #define D0FIFOSEL_b CFIFOSEL_b
+ #define D1FIFOSEL CFIFOSEL
+ #define D1FIFOSEL_b CFIFOSEL_b
+ #define D0FIFOCTR CFIFOCTR
+ #define D0FIFOCTR_b CFIFOCTR_b
+ #endif
+
+#else
+ #error "Unsupported MCU"
+#endif
+
+
+//--------------------------------------------------------------------+
+// Common
+//--------------------------------------------------------------------+
+
+enum {
+ FIFOSEL_BIGEND = (TU_BYTE_ORDER == TU_BIG_ENDIAN ? RUSB2_FIFOSEL_BIGEND : 0)
+};
diff --git a/src/portable/renesas/rusb2/rusb2_type.h b/src/portable/renesas/rusb2/rusb2_type.h
index 71837d03c..21f116857 100644
--- a/src/portable/renesas/rusb2/rusb2_type.h
+++ b/src/portable/renesas/rusb2/rusb2_type.h
@@ -41,10 +41,9 @@ extern "C" {
#define _ccrx_evenaccess
#endif
-/*--------------------------------------------------------------------*/
-/* Register Definitions */
-/*--------------------------------------------------------------------*/
-
+//--------------------------------------------------------------------+
+// Register Definitions
+//--------------------------------------------------------------------+
/* Start of definition of packed structs (used by the CCRX toolchain) */
TU_ATTR_PACKED_BEGIN
TU_ATTR_BIT_FIELD_ORDER_BEGIN
@@ -1669,15 +1668,20 @@ TU_ATTR_BIT_FIELD_ORDER_END
/*--------------------------------------------------------------------*/
/* Register Bit Utils */
/*--------------------------------------------------------------------*/
-#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
-#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
-#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
-#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
+#define RUSB2_SYSSTS0_LNST_SE0 (0)
+#define RUSB2_SYSSTS0_LNST_FS_J (1u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed J state */
+#define RUSB2_SYSSTS0_LNST_FS_K (2u << RUSB2_SYSSTS0_LNST_Pos) /* Full-speed K state */
+#define RUSB2_SYSSTS0_LNST_LS_SE1 (3u << RUSB2_SYSSTS0_LNST_Pos) /* Low-speed SE1 state */
#define RUSB2_DVSTCTR0_RHST_LS (1U << RUSB2_DVSTCTR0_RHST_Pos) /* Low-speed connection */
#define RUSB2_DVSTCTR0_RHST_FS (2U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
#define RUSB2_DVSTCTR0_RHST_HS (3U << RUSB2_DVSTCTR0_RHST_Pos) /* Full-speed connection */
+#define RUSB2_PIPE_CTR_PID_NAK (0U << RUSB2_PIPE_CTR_PID_Pos) /* NAK response */
+#define RUSB2_PIPE_CTR_PID_BUF (1U << RUSB2_PIPE_CTR_PID_Pos) /* BUF response (depends buffer state) */
+#define RUSB2_PIPE_CTR_PID_STALL (2U << RUSB2_PIPE_CTR_PID_Pos) /* STALL response */
+#define RUSB2_PIPE_CTR_PID_STALL2 (3U << RUSB2_PIPE_CTR_PID_Pos) /* Also STALL response */
+
#define RUSB2_DEVADD_USBSPD_LS (1U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Low-speed */
#define RUSB2_DEVADD_USBSPD_FS (2U << RUSB2_DEVADD_USBSPD_Pos) /* Target Device Full-speed */
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 087639d4b..a6abc6244 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -108,11 +108,10 @@
#include "tusb_option.h"
-#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && \
- !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0)
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0)
-#include "device/dcd.h"
-#include "fsdev_common.h"
+ #include "device/dcd.h"
+ #include "fsdev_common.h"
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
@@ -120,25 +119,25 @@
// One of these for every EP IN & OUT, uses a bit of RAM....
typedef struct {
- uint8_t *buffer;
+ uint8_t *buffer;
tu_fifo_t *ff;
- uint16_t total_len;
- uint16_t queued_len;
- uint16_t max_packet_size;
- uint8_t ep_idx; // index for USB_EPnR register
- bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask
+ uint16_t total_len;
+ uint16_t queued_len;
+ uint16_t max_packet_size;
+ uint8_t ep_idx; // index for USB_EPnR register
+ bool iso_in_sending; // Workaround for ISO IN EP doesn't have interrupt mask
} xfer_ctl_t;
// EP allocator
typedef struct {
uint8_t ep_num;
uint8_t ep_type;
- bool allocated[2];
+ bool allocated[2];
} ep_alloc_t;
static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2];
static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT];
-static uint8_t remoteWakeCountdown; // When wake is requested
+static uint8_t remoteWakeCountdown; // When wake is requested
//--------------------------------------------------------------------+
// Prototypes
@@ -152,12 +151,12 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir);
// PMA allocation/access
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 uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type);
static void edpt0_open(uint8_t rhport);
TU_ATTR_ALWAYS_INLINE static inline void edpt0_prepare_setup(void) {
- btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8);
+ btable_set_rx_bufsize(0, BTABLE_BUF_RX, 8);
}
//--------------------------------------------------------------------+
@@ -171,21 +170,21 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint8_t epnum, uint
//--------------------------------------------------------------------+
// Controller API
//--------------------------------------------------------------------+
-bool dcd_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
- (void) rh_init;
+bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) {
+ (void)rh_init;
fsdev_core_reset();
FSDEV_REG->CNTR = 0; // Enable USB
-#if !defined(FSDEV_BUS_32BIT)
+ #if !defined(FSDEV_BUS_32BIT)
// BTABLE register does not exist any more on 32-bit bus devices
FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE;
-#endif
+ #endif
// 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;
+ FSDEV_REG->CNTR |=
+ USB_CNTR_RESETM | USB_CNTR_ESOFM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_PMAOVRM;
handle_bus_reset(rhport);
@@ -236,8 +235,8 @@ static void handle_bus_reset(uint8_t rhport) {
for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) {
// Clear EP allocation status
- ep_alloc_status[i].ep_num = 0xFF;
- ep_alloc_status[i].ep_type = 0xFF;
+ ep_alloc_status[i].ep_num = 0xFF;
+ ep_alloc_status[i].ep_type = 0xFF;
ep_alloc_status[i].allocated[0] = false;
ep_alloc_status[i].allocated[1] = false;
}
@@ -245,7 +244,7 @@ static void handle_bus_reset(uint8_t rhport) {
// Reset PMA allocation
ep_buf_ptr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT;
- edpt0_open(rhport); // open control endpoint (both IN & OUT)
+ edpt0_open(rhport); // open control endpoint (both IN & OUT)
FSDEV_REG->DADDR = USB_DADDR_EF; // Enable USB Function
}
@@ -254,8 +253,8 @@ static void handle_bus_reset(uint8_t rhport) {
static void handle_ctr_tx(uint32_t ep_id) {
uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
- uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD;
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN);
+ const uint8_t ep_num = ep_reg & USB_EPADDR_FIELD;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_IN);
if (ep_is_iso(ep_reg)) {
// Ignore spurious interrupts that we don't schedule
@@ -265,11 +264,11 @@ static void handle_ctr_tx(uint32_t ep_id) {
return;
}
xfer->iso_in_sending = false;
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
uint8_t buf_id = (ep_reg & USB_EP_DTOG_TX) ? 0 : 1;
-#else
+ #else
uint8_t buf_id = BTABLE_BUF_TX;
-#endif
+ #endif
btable_set_count(ep_id, buf_id, 0);
}
@@ -282,17 +281,17 @@ static void handle_ctr_tx(uint32_t ep_id) {
static void handle_ctr_setup(uint32_t ep_id) {
uint16_t rx_count = btable_get_count(ep_id, BTABLE_BUF_RX);
- uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX);
- uint8_t setup_packet[8] TU_ATTR_ALIGNED(4);
+ uint16_t rx_addr = btable_get_addr(ep_id, BTABLE_BUF_RX);
+ uint8_t setup_packet[8] TU_ATTR_ALIGNED(4);
- fsdev_read_packet_memory(setup_packet, rx_addr, rx_count);
+ tu_hwfifo_read(PMA_BUF_AT(rx_addr), setup_packet, rx_count, NULL);
// Clear CTR RX if another setup packet arrived before this, it will be discarded
ep_write_clear_ctr(ep_id, TUSB_DIR_OUT);
// Setup packet should always be 8 bytes. If not, we probably missed the packet
if (rx_count == 8) {
- dcd_event_setup_received(0, (uint8_t*) setup_packet, true);
+ dcd_event_setup_received(0, (uint8_t *)setup_packet, true);
// Hardware should reset EP0 RX/TX to NAK and both toggle to 1
} else {
// Missed setup packet !!!
@@ -303,29 +302,30 @@ static void handle_ctr_setup(uint32_t ep_id) {
// Handle CTR interrupt for the RX/OUT direction
static void handle_ctr_rx(uint32_t ep_id) {
- uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
- uint8_t const ep_num = ep_reg & USB_EPADDR_FIELD;
- bool const is_iso = ep_is_iso(ep_reg);
- xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
+ uint32_t ep_reg = ep_read(ep_id) | USB_EP_CTR_TX | USB_EP_CTR_RX;
+ const uint8_t ep_num = ep_reg & USB_EPADDR_FIELD;
+ const bool is_iso = ep_is_iso(ep_reg);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, TUSB_DIR_OUT);
uint8_t buf_id;
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
bool const dbl_buf = is_iso;
-#else
+ #else
bool const dbl_buf = false;
-#endif
+ #endif
if (dbl_buf) {
buf_id = (ep_reg & USB_EP_DTOG_RX) ? 0 : 1;
} else {
buf_id = BTABLE_BUF_RX;
}
- uint16_t const rx_count = btable_get_count(ep_id, buf_id);
- uint16_t pma_addr = (uint16_t) btable_get_addr(ep_id, buf_id);
+ const uint16_t rx_count = btable_get_count(ep_id, buf_id);
+ uint16_t pma_addr = (uint16_t)btable_get_addr(ep_id, buf_id);
+ fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(pma_addr);
if (xfer->ff) {
- fsdev_read_packet_memory_ff(xfer->ff, pma_addr, rx_count);
+ tu_hwfifo_read_to_fifo(pma_buf, xfer->ff, rx_count, NULL);
} else {
- fsdev_read_packet_memory(xfer->buffer + xfer->queued_len, pma_addr, rx_count);
+ tu_hwfifo_read(pma_buf, xfer->buffer + xfer->queued_len, rx_count, NULL);
}
xfer->queued_len += rx_count;
@@ -343,7 +343,7 @@ static void handle_ctr_rx(uint32_t ep_id) {
} else {
// Set endpoint active again for receiving more data. Note that isochronous endpoints stay active always
if (!is_iso) {
- uint16_t const cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
+ const uint16_t cnt = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
btable_set_rx_bufsize(ep_id, BTABLE_BUF_RX, cnt);
}
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(TUSB_DIR_OUT); // will change RX Status, reserved other toggle bits
@@ -403,18 +403,18 @@ void dcd_int_handler(uint8_t rhport) {
// loop to handle all pending CTR interrupts
while (FSDEV_REG->ISTR & USB_ISTR_CTR) {
// skip DIR bit, and use CTR TX/RX instead, since there is chance we have both TX/RX completed in one interrupt
- uint32_t const ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID;
- uint32_t const ep_reg = ep_read(ep_id);
+ const uint32_t ep_id = FSDEV_REG->ISTR & USB_ISTR_EP_ID;
+ const uint32_t ep_reg = ep_read(ep_id);
if (ep_reg & USB_EP_CTR_RX) {
- #ifdef FSDEV_BUS_32BIT
+ #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:
+ * - 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
@@ -425,9 +425,9 @@ void dcd_int_handler(uint8_t rhport) {
*/
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)
+ cycle_count--; // each count take 3 cycles (1 for sub, jump, and compare)
}
- #endif
+ #endif
if (ep_reg & USB_EP_SETUP) {
handle_ctr_setup(ep_id); // CTR will be clear after copied setup packet
@@ -455,14 +455,13 @@ void dcd_int_handler(uint8_t rhport) {
// Invoked when a control transfer's status stage is complete.
// May help DCD to prepare for next control transfer, this API is optional.
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
+void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) {
(void)rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
- request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS) {
- uint8_t const dev_addr = (uint8_t)request->wValue;
- FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr);
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD && request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ const uint8_t dev_addr = (uint8_t)request->wValue;
+ FSDEV_REG->DADDR = (USB_DADDR_EF | dev_addr);
}
edpt0_prepare_setup();
@@ -473,15 +472,14 @@ void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *req
* In case of double buffering, high 16bit is the address of 2nd buffer
* During failure, TU_ASSERT is used. If this happens, rework/reallocate memory manually.
*/
-static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
-{
- uint8_t blsize, num_block;
+static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf) {
+ uint8_t blsize, num_block;
uint16_t aligned_len = pma_align_buffer_size(len, &blsize, &num_block);
- (void) blsize;
- (void) num_block;
+ (void)blsize;
+ (void)num_block;
uint32_t addr = ep_buf_ptr;
- ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer
+ ep_buf_ptr = (uint16_t)(ep_buf_ptr + aligned_len); // increment buffer pointer
if (dbuf) {
addr |= ((uint32_t)ep_buf_ptr) << 16;
@@ -489,7 +487,7 @@ static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
}
// Verify packet buffer is not overflowed
- TU_ASSERT(ep_buf_ptr <= FSDEV_PMA_SIZE, 0xFFFF);
+ TU_ASSERT(ep_buf_ptr <= CFG_TUSB_FSDEV_PMA_SIZE, 0xFFFF);
return addr;
}
@@ -497,35 +495,32 @@ static uint32_t dcd_pma_alloc(uint16_t len, bool dbuf)
/***
* Allocate hardware endpoint
*/
-static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
-{
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type) {
+ const uint8_t epnum = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
// Check if already allocated
- if (ep_alloc_status[i].allocated[dir] &&
- ep_alloc_status[i].ep_type == ep_type &&
+ if (ep_alloc_status[i].allocated[dir] && ep_alloc_status[i].ep_type == ep_type &&
ep_alloc_status[i].ep_num == epnum) {
return i;
}
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
bool const dbl_buf = ep_type == TUSB_XFER_ISOCHRONOUS;
-#else
+ #else
bool const dbl_buf = false;
-#endif
+ #endif
// If EP of current direction is not allocated
// For double-buffered mode both directions needs to be free
- if (!ep_alloc_status[i].allocated[dir] &&
- (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) {
+ if (!ep_alloc_status[i].allocated[dir] && (!dbl_buf || !ep_alloc_status[i].allocated[dir ^ 1])) {
// Check if EP number is the same
if (ep_alloc_status[i].ep_num == 0xFF || ep_alloc_status[i].ep_num == epnum) {
// One EP pair has to be the same type
if (ep_alloc_status[i].ep_type == 0xFF || ep_alloc_status[i].ep_type == ep_type) {
- ep_alloc_status[i].ep_num = epnum;
- ep_alloc_status[i].ep_type = ep_type;
+ ep_alloc_status[i].ep_num = epnum;
+ ep_alloc_status[i].ep_type = ep_type;
ep_alloc_status[i].allocated[dir] = true;
return i;
@@ -539,16 +534,16 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
}
void edpt0_open(uint8_t rhport) {
- (void) rhport;
+ (void)rhport;
dcd_ep_alloc(0x0, TUSB_XFER_CONTROL);
dcd_ep_alloc(0x80, TUSB_XFER_CONTROL);
xfer_status[0][0].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
- xfer_status[0][0].ep_idx = 0;
+ xfer_status[0][0].ep_idx = 0;
xfer_status[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE;
- xfer_status[0][1].ep_idx = 0;
+ xfer_status[0][1].ep_idx = 0;
uint16_t pma_addr0 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false);
uint16_t pma_addr1 = dcd_pma_alloc(CFG_TUD_ENDPOINT0_SIZE, false);
@@ -566,13 +561,13 @@ void edpt0_open(uint8_t rhport) {
ep_write(0, ep_reg, false);
}
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
+bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) {
(void)rhport;
- uint8_t const ep_addr = desc_ep->bEndpointAddress;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- const uint16_t packet_size = tu_edpt_packet_size(desc_ep);
- uint8_t const ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer);
+ const uint8_t ep_addr = desc_ep->bEndpointAddress;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ const uint16_t packet_size = tu_edpt_packet_size(desc_ep);
+ const uint8_t ep_idx = dcd_ep_alloc(ep_addr, desc_ep->bmAttributes.xfer);
TU_ASSERT(ep_idx < FSDEV_EP_COUNT);
uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
@@ -596,9 +591,9 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
uint16_t pma_addr = dcd_pma_alloc(packet_size, false);
btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
xfer->max_packet_size = packet_size;
- xfer->ep_idx = ep_idx;
+ xfer->ep_idx = ep_idx;
ep_change_status(&ep_reg, dir, EP_STAT_NAK);
ep_change_dtog(&ep_reg, dir, 0);
@@ -622,8 +617,8 @@ void dcd_edpt_close_all(uint8_t rhport) {
// Reset endpoint
ep_write(i, 0, false);
// Clear EP allocation status
- ep_alloc_status[i].ep_num = 0xFF;
- ep_alloc_status[i].ep_type = 0xFF;
+ ep_alloc_status[i].ep_num = 0xFF;
+ ep_alloc_status[i].ep_type = 0xFF;
ep_alloc_status[i].allocated[0] = false;
ep_alloc_status[i].allocated[1] = false;
}
@@ -637,46 +632,46 @@ void dcd_edpt_close_all(uint8_t rhport) {
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
(void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
- uint8_t const ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const uint8_t dir = tu_edpt_dir(ep_addr);
+ const uint8_t ep_idx = dcd_ep_alloc(ep_addr, TUSB_XFER_ISOCHRONOUS);
-#if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0
- uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
+ #if CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP != 0
+ uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, true);
uint16_t pma_addr2 = pma_addr >> 16;
-#else
- uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false);
+ #else
+ uint32_t pma_addr = dcd_pma_alloc(largest_packet_size, false);
uint16_t pma_addr2 = pma_addr;
-#endif
+ #endif
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
btable_set_addr(ep_idx, 0, pma_addr);
btable_set_addr(ep_idx, 1, pma_addr2);
-#else
+ #else
btable_set_addr(ep_idx, dir == TUSB_DIR_IN ? BTABLE_BUF_TX : BTABLE_BUF_RX, pma_addr);
- (void) pma_addr2;
-#endif
+ (void)pma_addr2;
+ #endif
- xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
- xfer->ep_idx = ep_idx;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ xfer->ep_idx = ep_idx;
return true;
}
-bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
+bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) {
(void)rhport;
- uint8_t const ep_addr = desc_ep->bEndpointAddress;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t* xfer = xfer_ctl_ptr(ep_num, dir);
+ const uint8_t ep_addr = desc_ep->bEndpointAddress;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- uint8_t const ep_idx = xfer->ep_idx;
+ const uint8_t ep_idx = xfer->ep_idx;
xfer->max_packet_size = tu_edpt_packet_size(desc_ep);
uint32_t ep_reg = ep_read(ep_idx) & ~USB_EPREG_MASK;
ep_reg |= tu_edpt_number(ep_addr) | USB_EP_ISOCHRONOUS | USB_EP_CTR_TX | USB_EP_CTR_RX;
-#if FSDEV_USE_SBUF_ISO != 0
+ #if FSDEV_USE_SBUF_ISO != 0
ep_reg |= USB_EP_KIND;
ep_change_status(&ep_reg, dir, EP_STAT_DISABLED);
@@ -687,12 +682,12 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
} else {
ep_reg &= ~(USB_EPTX_STAT | USB_EP_DTOG_TX);
}
-#else
+ #else
ep_change_status(&ep_reg, TUSB_DIR_IN, EP_STAT_DISABLED);
ep_change_status(&ep_reg, TUSB_DIR_OUT, EP_STAT_DISABLED);
ep_change_dtog(&ep_reg, dir, 0);
ep_change_dtog(&ep_reg, (tusb_dir_t)(1 - dir), 1);
-#endif
+ #endif
ep_write(ep_idx, ep_reg, true);
@@ -701,28 +696,29 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
// Currently, single-buffered, and only 64 bytes at a time (max)
static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
- uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
+ uint16_t len = tu_min16(xfer->total_len - xfer->queued_len, xfer->max_packet_size);
uint32_t ep_reg = ep_read(ep_ix) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR
- bool const is_iso = ep_is_iso(ep_reg);
+ const bool is_iso = ep_is_iso(ep_reg);
uint8_t buf_id;
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
bool const dbl_buf = is_iso;
-#else
+ #else
bool const dbl_buf = false;
-#endif
+ #endif
if (dbl_buf) {
buf_id = (ep_reg & USB_EP_DTOG_TX) ? 1 : 0;
} else {
buf_id = BTABLE_BUF_TX;
}
- uint16_t addr_ptr = (uint16_t) btable_get_addr(ep_ix, buf_id);
+ uint16_t addr_ptr = (uint16_t)btable_get_addr(ep_ix, buf_id);
+ fsdev_pma_buf_t *pma_buf = PMA_BUF_AT(addr_ptr);
if (xfer->ff) {
- fsdev_write_packet_memory_ff(xfer->ff, addr_ptr, len);
+ tu_hwfifo_write_from_fifo(pma_buf, xfer->ff, len, NULL);
} else {
- fsdev_write_packet_memory(addr_ptr, &(xfer->buffer[xfer->queued_len]), len);
+ tu_hwfifo_write(pma_buf, &(xfer->buffer[xfer->queued_len]), len, NULL);
}
xfer->queued_len += len;
@@ -737,10 +733,10 @@ static void dcd_transmit_packet(xfer_ctl_t *xfer, uint16_t ep_ix) {
}
static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
- (void) rhport;
+ (void)rhport;
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- uint8_t const ep_idx = xfer->ep_idx;
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ const uint8_t ep_idx = xfer->ep_idx;
if (dir == TUSB_DIR_IN) {
dcd_transmit_packet(xfer, ep_idx);
@@ -750,11 +746,11 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
uint16_t cnt = tu_min16(xfer->total_len, xfer->max_packet_size);
-#if FSDEV_USE_SBUF_ISO == 0
+ #if FSDEV_USE_SBUF_ISO == 0
bool const dbl_buf = ep_is_iso(ep_reg);
-#else
+ #else
bool const dbl_buf = false;
-#endif
+ #endif
if (dbl_buf) {
btable_set_rx_bufsize(ep_idx, 0, cnt);
btable_set_rx_bufsize(ep_idx, 1, cnt);
@@ -769,29 +765,29 @@ static bool edpt_xfer(uint8_t rhport, uint8_t ep_num, tusb_dir_t dir) {
return true;
}
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes, bool is_isr) {
- (void) is_isr;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) {
+ (void)is_isr;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- xfer->buffer = buffer;
- xfer->ff = NULL;
- xfer->total_len = total_bytes;
+ xfer->buffer = buffer;
+ xfer->ff = NULL;
+ xfer->total_len = total_bytes;
xfer->queued_len = 0;
return edpt_xfer(rhport, ep_num, dir);
}
-bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) {
- (void) is_isr;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes, bool is_isr) {
+ (void)is_isr;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- xfer->buffer = NULL;
- xfer->ff = ff;
- xfer->total_len = total_bytes;
+ xfer->buffer = NULL;
+ xfer->ff = ff;
+ xfer->total_len = total_bytes;
xfer->queued_len = 0;
return edpt_xfer(rhport, ep_num, dir);
@@ -799,10 +795,10 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
(void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- uint8_t const ep_idx = xfer->ep_idx;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ const uint8_t ep_idx = xfer->ep_idx;
uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir);
@@ -814,10 +810,10 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
(void)rhport;
- uint8_t const ep_num = tu_edpt_number(ep_addr);
- tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
- uint8_t const ep_idx = xfer->ep_idx;
+ const uint8_t ep_num = tu_edpt_number(ep_addr);
+ const tusb_dir_t dir = tu_edpt_dir(ep_addr);
+ xfer_ctl_t *xfer = xfer_ctl_ptr(ep_num, dir);
+ const uint8_t ep_idx = xfer->ep_idx;
uint32_t ep_reg = ep_read(ep_idx) | USB_EP_CTR_TX | USB_EP_CTR_RX; // reserve CTR bits
ep_reg &= USB_EPREG_MASK | EP_STAT_MASK(dir) | EP_DTOG_MASK(dir);
@@ -837,7 +833,7 @@ void dcd_int_disable(uint8_t rhport) {
fsdev_int_disable(rhport);
}
-#if defined(USB_BCDR_DPPU) || defined(SYSCFG_PMC_USB_PU)
+ #if defined(USB_BCDR_DPPU) || defined(SYSCFG_PMC_USB_PU) || defined(EXTEN_USBD_PU_EN)
void dcd_connect(uint8_t rhport) {
fsdev_connect(rhport);
}
@@ -845,6 +841,6 @@ void dcd_connect(uint8_t rhport) {
void dcd_disconnect(uint8_t rhport) {
fsdev_disconnect(rhport);
}
-#endif
+ #endif
#endif
diff --git a/src/portable/st/stm32_fsdev/fsdev_at32.h b/src/portable/st/stm32_fsdev/fsdev_at32.h
index 6877dc131..e75430396 100644
--- a/src/portable/st/stm32_fsdev/fsdev_at32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_at32.h
@@ -35,7 +35,6 @@
#endif
-#define FSDEV_PMA_SIZE (512u)
#define FSDEV_USE_SBUF_ISO 0
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h
index ee0057cb4..37ea7808e 100644
--- a/src/portable/st/stm32_fsdev/fsdev_ch32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h
@@ -53,7 +53,6 @@
#pragma GCC diagnostic pop
#endif
-#define FSDEV_PMA_SIZE (512u)
#define FSDEV_USE_SBUF_ISO 0
#define FSDEV_REG_BASE (APB1PERIPH_BASE + 0x00005C00UL)
#define FSDEV_PMA_BASE (APB1PERIPH_BASE + 0x00006000UL)
diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c
index 5d60ad9a2..4f127ae86 100644
--- a/src/portable/st/stm32_fsdev/fsdev_common.c
+++ b/src/portable/st/stm32_fsdev/fsdev_common.c
@@ -69,179 +69,6 @@ void fsdev_deinit(void) {
}
}
-
-//--------------------------------------------------------------------+
-// 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.linear.len);
- uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.wrapped.len);
- 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.linear.ptr;
-
- // 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.wrapped.ptr;
- } 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.wrapped.ptr;
- 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.linear.len);
- uint16_t cnt_wrap = tu_min16(wNBytes - cnt_lin, info.wrapped.len);
- 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.linear.ptr;
-
- // 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.wrapped.ptr;
- } 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.wrapped.ptr;
- 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
//--------------------------------------------------------------------+
diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h
index 0c67ee0c7..b749a92ff 100644
--- a/src/portable/st/stm32_fsdev/fsdev_common.h
+++ b/src/portable/st/stm32_fsdev/fsdev_common.h
@@ -32,11 +32,11 @@
#include "common/tusb_common.h"
#if CFG_TUD_ENABLED
-#include "device/dcd.h"
+ #include "device/dcd.h"
#endif
#if CFG_TUH_ENABLED
-#include "host/hcd.h"
+ #include "host/hcd.h"
#endif
#if defined(TUP_USBIP_FSDEV_STM32)
@@ -56,41 +56,35 @@ extern "C" {
// 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.
#ifndef FSDEV_BTABLE_BASE
-#define FSDEV_BTABLE_BASE 0U
+ #define FSDEV_BTABLE_BASE 0U
#endif
TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 bytes");
-// FSDEV_PMA_SIZE is PMA buffer size in bytes.
+// CFG_TUSB_FSDEV_PMA_SIZE is PMA buffer size in bytes.
// - 512-byte devices, access with a stride of two words (use every other 16-bit address)
-// - 1024-byte devices, access with a stride of one word (use every 16-bit address)
+// - 1024-byte devices, access with a stride of one word (use every 16-bit address) or 32-bit address
// - 2048-byte devices, access with 32-bit address
-
-// For purposes of accessing the packet
-#if FSDEV_PMA_SIZE == 512
- // 1x16 bit / word access scheme
- #define FSDEV_PMA_STRIDE 2
- #define pma_access_scheme TU_ATTR_ALIGNED(4)
-#elif FSDEV_PMA_SIZE == 1024
- // 2x16 bit / word access scheme
- #define FSDEV_PMA_STRIDE 1
- #define pma_access_scheme
-#elif FSDEV_PMA_SIZE == 2048
+#if CFG_TUSB_FSDEV_PMA_SIZE == 2048 || TU_CHECK_MCU(OPT_MCU_STM32U0)
// 32 bit access scheme
#define FSDEV_BUS_32BIT
- #define FSDEV_PMA_STRIDE 1
+ #define FSDEV_PMA_STRIDE 1
+ #define pma_access_scheme
+#elif CFG_TUSB_FSDEV_PMA_SIZE == 1024
+ // 2x16 bit / word access scheme
+ #define FSDEV_PMA_STRIDE 1
#define pma_access_scheme
+#elif CFG_TUSB_FSDEV_PMA_SIZE == 512
+ // 1x16 bit / word access scheme
+ #define FSDEV_PMA_STRIDE 2
+ #define pma_access_scheme TU_ATTR_ALIGNED(4)
#endif
// The fsdev_bus_t type can be used for both register and PMA access necessities
#ifdef FSDEV_BUS_32BIT
- typedef uint32_t fsdev_bus_t;
- #define fsdevbus_unaligned_read(_addr) tu_unaligned_read32(_addr)
- #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write32(_addr, _value)
+typedef uint32_t fsdev_bus_t;
#else
- typedef uint16_t fsdev_bus_t;
- #define fsdevbus_unaligned_read(_addr) tu_unaligned_read16(_addr)
- #define fsdevbus_unaligned_write(_addr, _value) tu_unaligned_write16(_addr, _value)
+typedef uint16_t fsdev_bus_t;
#endif
enum {
@@ -124,77 +118,77 @@ typedef union {
} ep32[FSDEV_EP_COUNT][2];
} fsdev_btable_t;
-TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT*8*FSDEV_PMA_STRIDE, "size is not correct");
-TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT*8 <= FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM");
+TU_VERIFY_STATIC(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT * 8 * FSDEV_PMA_STRIDE, "size is not correct");
+TU_VERIFY_STATIC(FSDEV_BTABLE_BASE + FSDEV_EP_COUNT * 8 <= CFG_TUSB_FSDEV_PMA_SIZE, "BTABLE does not fit in PMA RAM");
-#define FSDEV_BTABLE ((volatile fsdev_btable_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(FSDEV_BTABLE_BASE)))
+#define FSDEV_BTABLE ((volatile fsdev_btable_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (FSDEV_BTABLE_BASE)))
typedef struct {
volatile pma_access_scheme fsdev_bus_t value;
} fsdev_pma_buf_t;
-#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t*) (FSDEV_PMA_BASE + FSDEV_PMA_STRIDE*(_addr)))
+#define PMA_BUF_AT(_addr) ((fsdev_pma_buf_t *)(FSDEV_PMA_BASE + FSDEV_PMA_STRIDE * (_addr)))
//--------------------------------------------------------------------+
// Registers Typedef
//--------------------------------------------------------------------+
// volatile 32-bit aligned
-#define _va32 volatile TU_ATTR_ALIGNED(4)
+#define _va32 volatile TU_ATTR_ALIGNED(4)
typedef struct {
struct {
_va32 fsdev_bus_t reg;
- }ep[FSDEV_EP_COUNT];
+ } ep[FSDEV_EP_COUNT];
- _va32 uint32_t RESERVED7[8]; // Reserved
- _va32 fsdev_bus_t CNTR; // 40: Control register
- _va32 fsdev_bus_t ISTR; // 44: Interrupt status register
- _va32 fsdev_bus_t FNR; // 48: Frame number register
- _va32 fsdev_bus_t DADDR; // 4C: Device address register
- _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only)
- _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only)
- _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only)
+ _va32 uint32_t RESERVED7[8]; // Reserved
+ _va32 fsdev_bus_t CNTR; // 40: Control register
+ _va32 fsdev_bus_t ISTR; // 44: Interrupt status register
+ _va32 fsdev_bus_t FNR; // 48: Frame number register
+ _va32 fsdev_bus_t DADDR; // 4C: Device address register
+ _va32 fsdev_bus_t BTABLE; // 50: Buffer Table address register (16-bit only)
+ _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status Register (32-bit only)
+ _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector Register (32-bit only)
} fsdev_regs_t;
TU_VERIFY_STATIC(offsetof(fsdev_regs_t, CNTR) == 0x40, "Wrong offset");
TU_VERIFY_STATIC(sizeof(fsdev_regs_t) == 0x5C, "Size is not correct");
-#define FSDEV_REG ((fsdev_regs_t*) FSDEV_REG_BASE)
+#define FSDEV_REG ((fsdev_regs_t *)FSDEV_REG_BASE)
#ifndef USB_EPTX_STAT
-#define USB_EPTX_STAT 0x0030U
+ #define USB_EPTX_STAT 0x0030U
#endif
#ifndef USB_EPRX_STAT
-#define USB_EPRX_STAT 0x3000U
+ #define USB_EPRX_STAT 0x3000U
#endif
#ifndef USB_EPTX_STAT_Pos
-#define USB_EPTX_STAT_Pos 4u
+ #define USB_EPTX_STAT_Pos 4u
#endif
#ifndef USB_EP_DTOG_TX_Pos
-#define USB_EP_DTOG_TX_Pos 6u
+ #define USB_EP_DTOG_TX_Pos 6u
#endif
#ifndef USB_EP_CTR_TX_Pos
-#define USB_EP_CTR_TX_Pos 7u
+ #define USB_EP_CTR_TX_Pos 7u
#endif
typedef enum {
EP_STAT_DISABLED = 0,
- EP_STAT_STALL = 1,
- EP_STAT_NAK = 2,
- EP_STAT_VALID = 3
-}ep_stat_t;
+ EP_STAT_STALL = 1,
+ EP_STAT_NAK = 2,
+ EP_STAT_VALID = 3
+} ep_stat_t;
-#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 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)))
+#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)))
//--------------------------------------------------------------------+
// Endpoint Helper
@@ -211,7 +205,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_write(uint32_t ep_id, uint32_t value
fsdev_int_disable(0);
}
- FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t) value;
+ FSDEV_REG->ep[ep_id].reg = (fsdev_bus_t)value;
if (need_exclusive) {
fsdev_int_enable(0);
@@ -226,11 +220,11 @@ TU_ATTR_ALWAYS_INLINE static inline void ep_write_clear_ctr(uint32_t ep_id, tusb
ep_write(ep_id, reg, false);
}
-TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t* reg, tusb_dir_t dir, ep_stat_t state) {
+TU_ATTR_ALWAYS_INLINE static inline void ep_change_status(uint32_t *reg, tusb_dir_t dir, ep_stat_t state) {
*reg ^= (state << (USB_EPTX_STAT_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
}
-TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t* reg, tusb_dir_t dir, uint8_t state) {
+TU_ATTR_ALWAYS_INLINE static inline void ep_change_dtog(uint32_t *reg, tusb_dir_t dir, uint8_t state) {
*reg ^= (state << (USB_EP_DTOG_TX_Pos + (dir == TUSB_DIR_IN ? 0 : 8)));
}
@@ -259,11 +253,11 @@ TU_ATTR_ALWAYS_INLINE static inline void ch_write_clear_ctr(uint32_t ch_id, tusb
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) {
+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) {
+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)));
}
@@ -281,8 +275,8 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uin
TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t buf_id, uint16_t addr) {
#ifdef FSDEV_BUS_32BIT
- uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
- count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (count_addr & 0xFFFF0000u) | (addr & 0x0000FFFCu);
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
#else
FSDEV_BTABLE->ep16[ep_id][buf_id].addr = addr;
@@ -301,12 +295,12 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, ui
TU_ATTR_ALWAYS_INLINE static inline void btable_set_count(uint32_t ep_id, uint8_t buf_id, uint16_t byte_count) {
#ifdef FSDEV_BUS_32BIT
- uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
- count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
+ uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr;
+ count_addr = (count_addr & ~0x03FF0000u) | ((byte_count & 0x3FFu) << 16);
FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr;
#else
- uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
- cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
+ uint16_t cnt = FSDEV_BTABLE->ep16[ep_id][buf_id].count;
+ cnt = (cnt & ~0x3FFU) | (byte_count & 0x3FFU);
FSDEV_BTABLE->ep16[ep_id][buf_id].count = cnt;
#endif
}
@@ -318,31 +312,11 @@ void fsdev_core_reset(void);
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);
+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);
-//--------------------------------------------------------------------+
-// PMA (Packet Memory Area) Access
-//--------------------------------------------------------------------+
-
-// 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);
-
-// 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
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
index 4b7d3d301..02dba05a6 100644
--- a/src/portable/st/stm32_fsdev/fsdev_stm32.h
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -32,10 +32,23 @@
#ifndef TUSB_FSDEV_STM32_H
#define TUSB_FSDEV_STM32_H
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0
+#if CFG_TUSB_MCU == OPT_MCU_STM32C0
+ #include "stm32c0xx.h"
+ #define FSDEV_HAS_SBUF_ISO 1
+ #define USB USB_DRD_FS
+ #define USB_EP_CTR_RX USB_CHEP_VTRX
+ #define USB_EP_CTR_TX USB_CHEP_VTTX
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F0
#include "stm32f0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- #define FSDEV_REG_BASE USB_BASE
+ #define FSDEV_REG_BASE USB_BASE
#define FSDEV_HAS_SBUF_ISO 0
// F0x2 models are crystal-less
// All have internal D+ pull-up
@@ -44,29 +57,24 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
#include "stm32f1xx.h"
- #define FSDEV_PMA_SIZE (512u)
#define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *B, and *C: 2 x 16 bits/word
// F1 names this differently from the rest
- #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
+ #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
-#elif defined(STM32F302xB) || defined(STM32F302xC) || \
- defined(STM32F303xB) || defined(STM32F303xC) || \
- defined(STM32F373xC)
+#elif defined(STM32F302xB) || defined(STM32F302xC) || defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
#include "stm32f3xx.h"
- #define FSDEV_PMA_SIZE (512u)
#define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *B, and *C: 1 x 16 bits/word
// PMA dedicated to USB (no sharing with CAN)
-#elif defined(STM32F302x6) || defined(STM32F302x8) || \
- defined(STM32F302xD) || defined(STM32F302xE) || \
- defined(STM32F303xD) || defined(STM32F303xE)
+#elif defined(STM32F302x6) || defined(STM32F302x8) || defined(STM32F302xD) || defined(STM32F302xE) || \
+ defined(STM32F303xD) || defined(STM32F303xE)
#include "stm32f3xx.h"
- #define FSDEV_PMA_SIZE (1024u)
#define FSDEV_HAS_SBUF_ISO 0
// NO internal Pull-ups
// *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
@@ -74,28 +82,32 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
#include "stm32l0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
#define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
#include "stm32l1xx.h"
- #define FSDEV_PMA_SIZE (512u)
#define FSDEV_HAS_SBUF_ISO 0
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
- #include "stm32g4xx.h"
- #define FSDEV_PMA_SIZE (1024u)
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+ #include "stm32l4xx.h"
+ #define FSDEV_HAS_SBUF_ISO 0
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ #include "stm32l5xx.h"
#define FSDEV_HAS_SBUF_ISO 0
+ #ifndef USB_PMAADDR
+ #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
+ #endif
+
#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
#include "stm32g0xx.h"
- #define FSDEV_PMA_SIZE (2048u)
- #define FSDEV_HAS_SBUF_ISO 1
- #define USB USB_DRD_FS
+ #define FSDEV_HAS_SBUF_ISO 1
+ #define USB USB_DRD_FS
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
#define USB_EPREG_MASK USB_CHEP_REG_MASK
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
@@ -110,78 +122,20 @@
#define USB_ISTR_EP_ID USB_ISTR_IDN
#define USB_EPADDR_FIELD USB_CHEP_ADDR
#define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-#elif CFG_TUSB_MCU == OPT_MCU_STM32C0
- #include "stm32c0xx.h"
- #define FSDEV_PMA_SIZE (2048u)
- #define FSDEV_HAS_SBUF_ISO 1
- #define USB USB_DRD_FS
- #define USB_EP_CTR_RX USB_CHEP_VTRX
- #define USB_EP_CTR_TX USB_CHEP_VTTX
- #define USB_EPREG_MASK USB_CHEP_REG_MASK
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+ #include "stm32g4xx.h"
+ #define FSDEV_HAS_SBUF_ISO 0
#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
#include "stm32h5xx.h"
- #define FSDEV_PMA_SIZE (2048u)
- #define FSDEV_HAS_SBUF_ISO 1
- #define USB USB_DRD_FS
-
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
- #define USB_EPREG_MASK USB_CHEP_REG_MASK
- #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
- #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
- #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
- #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
- #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
- #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
- #define USB_EPRX_STAT USB_CH_RX_VALID
- #define USB_EPKIND_MASK USB_EP_KIND_MASK
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
- #include "stm32wbxx.h"
- #define FSDEV_PMA_SIZE (1024u)
- #define FSDEV_HAS_SBUF_ISO 0
- /* ST provided header has incorrect value of USB_PMAADDR */
- #define FSDEV_PMA_BASE USB1_PMAADDR
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
- #include "stm32l4xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- #define FSDEV_HAS_SBUF_ISO 0
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
- #include "stm32l5xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- #define FSDEV_HAS_SBUF_ISO 0
-
- #ifndef USB_PMAADDR
- #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
- #endif
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
- #include "stm32u5xx.h"
- #define FSDEV_PMA_SIZE (2048u)
#define FSDEV_HAS_SBUF_ISO 1
- #define USB USB_DRD_FS
+ #define USB USB_DRD_FS
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
#define USB_EPREG_MASK USB_CHEP_REG_MASK
#define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
#define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
@@ -200,7 +154,6 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U0
#include "stm32u0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
#define FSDEV_BUS_32BIT
#define FSDEV_HAS_SBUF_ISO 1
#define USB USB_DRD_FS
@@ -226,10 +179,9 @@
#elif CFG_TUSB_MCU == OPT_MCU_STM32U3
#include "stm32u3xx.h"
- #define FSDEV_PMA_SIZE (2048u)
#define FSDEV_BUS_32BIT
#define FSDEV_HAS_SBUF_ISO 1 // This is assumed to work but has not been tested...
- #define USB USB_DRD_FS
+ #define USB USB_DRD_FS
#define USB_EP_CTR_RX USB_EP_VTRX
#define USB_EP_CTR_TX USB_EP_VTTX
@@ -240,15 +192,45 @@
#define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
#define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
#define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
- #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
- #define USB_EPRX_STAT USB_CH_RX_VALID
- #define USB_EPKIND_MASK USB_EP_KIND_MASK
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #include "stm32u5xx.h"
+ #define FSDEV_HAS_SBUF_ISO 1
+ #define USB USB_DRD_FS
+
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
+ #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
+ #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
+ #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
+ #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ #include "stm32wbxx.h"
+ #define FSDEV_HAS_SBUF_ISO 0
+ /* ST provided header has incorrect value of USB_PMAADDR */
+ #define FSDEV_PMA_BASE USB1_PMAADDR
#else
#error You are using an untested or unimplemented STM32 variant. Please update the driver.
@@ -299,7 +281,7 @@
// - Enable double buffering on devices with >1KB Packet Memory Area (PMA)
// to improve isochronous transfer reliability and performance
// - Disable on devices with limited PMA to conserve memory space
- #if FSDEV_PMA_SIZE > 1024u
+ #if CFG_TUSB_FSDEV_PMA_SIZE > 1024u
#define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 1
#else
#define CFG_TUD_FSDEV_DOUBLE_BUFFERED_ISO_EP 0
diff --git a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c
index da9c6961c..acdeccf6d 100644
--- a/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/hcd_stm32_fsdev.c
@@ -303,10 +303,12 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
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;
+ 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];
+ hcd_endpoint_t *edpt = &_hcd_data.edpt[ep_id];
+ hcd_channel_t *channel = &_hcd_data.channel[ch_id];
if (dir == TUSB_DIR_OUT) {
// OUT/TX direction
@@ -314,7 +316,7 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
// More data to send
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[edpt->queued_len]), len);
+ tu_hwfifo_write(PMA_BUF_AT(pma_addr), &(edpt->buffer[edpt->queued_len]), len, NULL);
btable_set_count(ch_id, BTABLE_BUF_TX, len);
edpt->queued_len += len;
channel_write_status(ch_id, ch_reg, TUSB_DIR_OUT, EP_STAT_VALID, false);
@@ -329,8 +331,7 @@ static void ch_handle_ack(uint8_t ch_id, uint32_t ch_reg, tusb_dir_t dir) {
// 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 + edpt->queued_len, pma_addr, rx_count);
+ tu_hwfifo_read(PMA_BUF_AT(pma_addr), edpt->buffer + edpt->queued_len, rx_count, NULL);
edpt->queued_len += rx_count;
if ((rx_count < edpt->max_packet_size) || (edpt->queued_len >= edpt->buflen)) {
@@ -740,7 +741,7 @@ static uint32_t hcd_pma_alloc(uint8_t channel, tusb_dir_t dir, uint16_t len) {
uint16_t addr = FSDEV_BTABLE_BASE + 8 * FSDEV_EP_COUNT;
addr += channel * TUSB_EPSIZE_BULK_FS * 2 + (dir == TUSB_DIR_IN ? TUSB_EPSIZE_BULK_FS : 0);
- TU_ASSERT(addr <= FSDEV_PMA_SIZE, 0xFFFF);
+ TU_ASSERT(addr <= CFG_TUSB_FSDEV_PMA_SIZE, 0xFFFF);
return addr;
}
@@ -841,8 +842,7 @@ 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 - edpt->queued_len, edpt->max_packet_size);
-
- fsdev_write_packet_memory(pma_addr, &(edpt->buffer[edpt->queued_len]), len);
+ tu_hwfifo_write(PMA_BUF_AT(pma_addr), &(edpt->buffer[edpt->queued_len]), len, NULL);
btable_set_count(ch_id, BTABLE_BUF_TX, len);
edpt->queued_len += len;
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index ba40498e6..44f7137f9 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -98,10 +98,14 @@ TU_ATTR_ALWAYS_INLINE static inline bool edpt_is_enabled(dwc2_dep_t* dep) {
return (dep->ctl & EPCTL_EPENA) != 0;
}
-//--------------------------------------------------------------------
-// DMA
-//--------------------------------------------------------------------
-#if CFG_TUD_MEM_DCACHE_ENABLE
+ #if CFG_TUD_DWC2_SLAVE_ENABLE
+static uint16_t epin_write_tx_fifo(dwc2_regs_t *dwc2, uint8_t epnum);
+ #endif
+
+ //--------------------------------------------------------------------
+ // DMA
+ //--------------------------------------------------------------------
+ #if CFG_TUD_MEM_DCACHE_ENABLE
bool dcd_dcache_clean(const void* addr, uint32_t data_size) {
TU_VERIFY(addr && data_size);
return dwc2_dcache_clean(addr, data_size);
@@ -345,40 +349,6 @@ static void edpt_disable(uint8_t rhport, uint8_t ep_addr, bool stall) {
}
}
-static uint16_t epin_write_tx_fifo(uint8_t rhport, uint8_t epnum) {
- dwc2_regs_t* dwc2 = DWC2_REG(rhport);
- dwc2_dep_t* const epin = &dwc2->ep[0][epnum];
- xfer_ctl_t* const xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
-
- dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
- const uint16_t remain_packets = tsiz.packet_count;
-
- uint16_t total_bytes_written = 0;
- // Process every single packet (only whole packets can be written to fifo)
- for (uint16_t i = 0; i < remain_packets; i++) {
- tsiz.value = epin->tsiz;
- const uint16_t remain_bytes = (uint16_t) tsiz.xfer_size;
- const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
-
- // Check if dtxfsts has enough space available
- if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
- break;
- }
-
- // Push packet to Tx-FIFO
- if (xfer->ff) {
- volatile uint32_t* tx_fifo = dwc2->fifo[epnum];
- tu_fifo_read_n_access_mode(xfer->ff, (void *)(uintptr_t)tx_fifo, xact_bytes, TU_FIFO_FIXED_ADDR_RW32);
- total_bytes_written += xact_bytes;
- } else {
- dfifo_write_packet(dwc2, epnum, xfer->buffer, xact_bytes);
- xfer->buffer += xact_bytes;
- total_bytes_written += xact_bytes;
- }
- }
- return total_bytes_written;
-}
-
// Since this function returns void, it is not possible to return a boolean success message
// We must make sure that this function is not called when the EP is disabled
// Must be called from critical section
@@ -423,6 +393,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
}
}
+ #if CFG_TUD_DWC2_DMA_ENABLE
const bool is_dma = dma_device_enabled(dwc2);
if(is_dma) {
if (dir == TUSB_DIR_IN && total_bytes != 0) {
@@ -434,11 +405,14 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
if (epnum == 0) {
xfer->buffer += total_bytes;
}
- } else {
+ } else
+ #endif
+ {
+ #if CFG_TUD_DWC2_SLAVE_ENABLE
dep->diepctl = depctl.value; // enable endpoint
if (dir == TUSB_DIR_IN && total_bytes != 0) {
- const uint16_t xferred_bytes = epin_write_tx_fifo(rhport, epnum);
+ const uint16_t xferred_bytes = epin_write_tx_fifo(dwc2, epnum);
// Enable TXFE interrupt if there are still data to be sent
// EP0 only sends one packet at a time, so no need to check for EP0
@@ -446,6 +420,7 @@ static void edpt_schedule_packets(uint8_t rhport, const uint8_t epnum, const uin
dwc2->diepempmsk |= (1u << epnum);
}
}
+ #endif
}
}
@@ -689,9 +664,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
// into the USB buffer!
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes, bool is_isr) {
(void) is_isr;
- // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1
- TU_ASSERT(ff->item_size == 1);
-
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_ctl_t* xfer = XFER_CTL_BASE(epnum, dir);
@@ -854,6 +826,39 @@ TU_ATTR_ALWAYS_INLINE static inline void print_doepint(uint32_t doepint) {
#endif
#if CFG_TUD_DWC2_SLAVE_ENABLE
+static uint16_t epin_write_tx_fifo(dwc2_regs_t *dwc2, uint8_t epnum) {
+ dwc2_dep_t *const epin = &dwc2->ep[0][epnum];
+ xfer_ctl_t *const xfer = XFER_CTL_BASE(epnum, TUSB_DIR_IN);
+
+ dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
+ const uint16_t remain_packets = tsiz.packet_count;
+
+ uint16_t total_bytes_written = 0;
+ // Process every single packet (only whole packets can be written to fifo)
+ for (uint16_t i = 0; i < remain_packets; i++) {
+ tsiz.value = epin->tsiz;
+ const uint16_t remain_bytes = (uint16_t)tsiz.xfer_size;
+ const uint16_t xact_bytes = tu_min16(remain_bytes, xfer->max_size);
+
+ // Check if dtxfsts has enough space available
+ if (xact_bytes > ((epin->dtxfsts & DTXFSTS_INEPTFSAV_Msk) << 2)) {
+ break;
+ }
+
+ // Push packet to Tx-FIFO
+ volatile uint32_t *tx_fifo = dwc2->fifo[epnum];
+ if (xfer->ff) {
+ tu_hwfifo_write_from_fifo(tx_fifo, xfer->ff, xact_bytes, NULL);
+ total_bytes_written += xact_bytes;
+ } else {
+ tu_hwfifo_write(tx_fifo, xfer->buffer, xact_bytes, NULL);
+ xfer->buffer += xact_bytes;
+ total_bytes_written += xact_bytes;
+ }
+ }
+ return total_bytes_written;
+}
+
// Process shared receive FIFO, this interrupt is only used in Slave mode
static void handle_rxflvl_irq(uint8_t rhport) {
dwc2_regs_t* dwc2 = DWC2_REG(rhport);
@@ -893,9 +898,9 @@ static void handle_rxflvl_irq(uint8_t rhport) {
if (byte_count != 0) {
// Read packet off RxFIFO
if (xfer->ff != NULL) {
- tu_fifo_write_n_access_mode(xfer->ff, (const void *)(uintptr_t)rx_fifo, byte_count, TU_FIFO_FIXED_ADDR_RW32);
+ tu_hwfifo_read_to_fifo(rx_fifo, xfer->ff, byte_count, NULL);
} else {
- dfifo_read_packet(dwc2, xfer->buffer, byte_count);
+ tu_hwfifo_read(rx_fifo, xfer->buffer, byte_count, NULL);
xfer->buffer += byte_count;
}
}
@@ -967,7 +972,7 @@ static void handle_epin_slave(uint8_t rhport, uint8_t epnum, dwc2_diepint_t diep
// - 64 bytes or
// - Half/Empty of TX FIFO size (configured by GAHBCFG.TXFELVL)
if (diepint_bm.txfifo_empty && tu_bit_test(dwc2->diepempmsk, epnum)) {
- epin_write_tx_fifo(rhport, epnum);
+ epin_write_tx_fifo(dwc2, epnum);
// Turn off TXFE if all bytes are written.
dwc2_ep_tsize_t tsiz = {.value = epin->tsiz};
diff --git a/src/portable/synopsys/dwc2/dwc2_at32.h b/src/portable/synopsys/dwc2/dwc2_at32.h
index 513495eb1..10824ae92 100644
--- a/src/portable/synopsys/dwc2/dwc2_at32.h
+++ b/src/portable/synopsys/dwc2/dwc2_at32.h
@@ -61,6 +61,11 @@
#define OTG1_FIFO_SIZE 1280
#define OTG1_IRQn OTGFS1_IRQn
#define DWC2_OTG1_REG_BASE 0x50000000UL
+#elif CFG_TUSB_MCU == OPT_MCU_AT32F45X
+ #include <at32f45x.h>
+ #define OTG1_FIFO_SIZE 1280
+ #define OTG1_IRQn OTGFS1_IRQn
+ #define DWC2_OTG1_REG_BASE 0x50000000UL
#endif
#ifdef __cplusplus
diff --git a/src/portable/synopsys/dwc2/dwc2_common.c b/src/portable/synopsys/dwc2/dwc2_common.c
index 980574e12..a7e6188df 100644
--- a/src/portable/synopsys/dwc2/dwc2_common.c
+++ b/src/portable/synopsys/dwc2/dwc2_common.c
@@ -264,58 +264,4 @@ bool dwc2_core_init(uint8_t rhport, bool is_highspeed, bool is_dma) {
//
// }
-//--------------------------------------------------------------------
-// DFIFO
-//--------------------------------------------------------------------
-// Read a single data packet from receive DFIFO
-void dfifo_read_packet(dwc2_regs_t* dwc2, uint8_t* dst, uint16_t len) {
- const volatile uint32_t* rx_fifo = dwc2->fifo[0];
-
- // Reading full available 32 bit words from fifo
- uint16_t word_count = len >> 2;
- while (word_count--) {
- tu_unaligned_write32(dst, *rx_fifo);
- dst += 4;
- }
-
- // Read the remaining 1-3 bytes from fifo
- const uint8_t bytes_rem = len & 0x03;
- if (bytes_rem != 0) {
- const uint32_t tmp = *rx_fifo;
- dst[0] = tu_u32_byte0(tmp);
- if (bytes_rem > 1) {
- dst[1] = tu_u32_byte1(tmp);
- }
- if (bytes_rem > 2) {
- dst[2] = tu_u32_byte2(tmp);
- }
- }
-}
-
-// Write a single data packet to DFIFO
-void dfifo_write_packet(dwc2_regs_t* dwc2, uint8_t fifo_num, const uint8_t* src, uint16_t len) {
- volatile uint32_t* tx_fifo = dwc2->fifo[fifo_num];
-
- // Pushing full available 32 bit words to fifo
- uint16_t word_count = len >> 2;
- while (word_count--) {
- *tx_fifo = tu_unaligned_read32(src);
- src += 4;
- }
-
- // Write the remaining 1-3 bytes into fifo
- const uint8_t bytes_rem = len & 0x03;
- if (bytes_rem) {
- uint32_t tmp_word = src[0];
- if (bytes_rem > 1) {
- tmp_word |= (src[1] << 8);
- }
- if (bytes_rem > 2) {
- tmp_word |= (src[2] << 16);
- }
-
- *tx_fifo = tmp_word;
- }
-}
-
#endif
diff --git a/src/portable/synopsys/dwc2/hcd_dwc2.c b/src/portable/synopsys/dwc2/hcd_dwc2.c
index fc748c85f..c40703b09 100644
--- a/src/portable/synopsys/dwc2/hcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/hcd_dwc2.c
@@ -856,7 +856,7 @@ static void handle_rxflvl_irq(uint8_t rhport) {
hcd_endpoint_t* edpt = &_hcd_data.edpt[xfer->ep_id];
if (byte_count > 0) {
- dfifo_read_packet(dwc2, edpt->buffer + xfer->xferred_bytes, byte_count);
+ tu_hwfifo_read(dwc2->fifo[0], edpt->buffer + xfer->xferred_bytes, byte_count, NULL);
xfer->xferred_bytes += byte_count;
xfer->fifo_bytes = byte_count;
}
@@ -907,7 +907,7 @@ static bool handle_txfifo_empty(dwc2_regs_t* dwc2, bool is_periodic) {
return true;
}
- dfifo_write_packet(dwc2, ch_id, edpt->buffer + xfer->fifo_bytes, xact_bytes);
+ tu_hwfifo_write(dwc2->fifo[ch_id], edpt->buffer + xfer->fifo_bytes, xact_bytes, NULL);
xfer->fifo_bytes += xact_bytes;
}
}
diff --git a/src/tusb.c b/src/tusb.c
index 8117c3e3e..6075e9db4 100644
--- a/src/tusb.c
+++ b/src/tusb.c
@@ -309,14 +309,12 @@ bool tu_edpt_stream_init(tu_edpt_stream_t *s, bool is_host, bool is_tx, bool ove
uint16_t ff_bufsize, uint8_t *ep_buf, uint16_t ep_bufsize) {
(void) is_tx;
- #if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED == 0 // FIFO is required
if (ff_buf == NULL || ff_bufsize == 0) {
return false;
}
- #endif
s->is_host = is_host;
- tu_fifo_config(&s->ff, ff_buf, ff_bufsize, 1, overwritable);
+ tu_fifo_config(&s->ff, ff_buf, ff_bufsize, overwritable);
#if OSAL_MUTEX_REQUIRED
if (ff_buf != NULL && ff_bufsize > 0) {
@@ -394,7 +392,7 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t *s) {
// Pull data from FIFO -> EP buf
uint16_t count;
if (s->ep_buf == NULL) {
- count = ff_count;
+ count = tu_fifo_count(&s->ff); // re-get count since fifo can be changed
} else {
count = tu_fifo_read_n(&s->ff, s->ep_buf, s->ep_bufsize);
}
@@ -411,90 +409,45 @@ uint32_t tu_edpt_stream_write_xfer(tu_edpt_stream_t *s) {
}
uint32_t tu_edpt_stream_write(tu_edpt_stream_t *s, const void *buffer, uint32_t bufsize) {
- #if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
- if (0 == tu_fifo_depth(&s->ff)) {
- // non-fifo mode: TX need ep buffer
- TU_VERIFY(s->ep_buf != NULL, 0);
- TU_VERIFY(stream_claim(s), 0);
- uint32_t xact_len = tu_min32(bufsize, s->ep_bufsize);
- memcpy(s->ep_buf, buffer, xact_len);
- TU_ASSERT(stream_xfer(s, (uint16_t) xact_len), 0);
- return xact_len;
- } else
- #endif
- {
- TU_VERIFY(bufsize > 0);
- const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize);
+ TU_VERIFY(bufsize > 0);
+ const uint16_t ret = tu_fifo_write_n(&s->ff, buffer, (uint16_t) bufsize);
- // flush if fifo has more than packet size or
- // in rare case: fifo depth is configured too small (which never reach packet size)
- if ((tu_fifo_count(&s->ff) >= s->mps) || (tu_fifo_depth(&s->ff) < s->mps)) {
- tu_edpt_stream_write_xfer(s);
- }
- return ret;
+ // flush if fifo has more than packet size or
+ // in rare case: fifo depth is configured too small (which never reach packet size)
+ if ((tu_fifo_count(&s->ff) >= s->mps) || (tu_fifo_depth(&s->ff) < s->mps)) {
+ tu_edpt_stream_write_xfer(s);
}
+ return ret;
}
uint32_t tu_edpt_stream_write_available(tu_edpt_stream_t *s) {
- #if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
- if (0 == tu_fifo_depth(&s->ff)) {
- // non-fifo mode
- TU_VERIFY(s->ep_addr > 0); // must be opened
- bool is_busy = true;
- if (s->is_host) {
- #if CFG_TUH_ENABLED
- is_busy = usbh_edpt_busy(s->hwid, s->ep_addr);
- #endif
- } else {
- #if CFG_TUD_ENABLED
- is_busy = usbd_edpt_busy(s->hwid, s->ep_addr);
- #endif
- }
- return is_busy ? 0 : s->ep_bufsize;
- } else
- #endif
- {
- return (uint32_t)tu_fifo_remaining(&s->ff);
- }
+ return (uint32_t)tu_fifo_remaining(&s->ff);
}
//--------------------------------------------------------------------+
// Stream Read
//--------------------------------------------------------------------+
uint32_t tu_edpt_stream_read_xfer(tu_edpt_stream_t *s) {
- #if CFG_TUSB_EDPT_STREAM_NO_FIFO_ENABLED
- if (0 == tu_fifo_depth(&s->ff)) {
- // non-fifo mode: RX need ep buffer
- TU_VERIFY(s->ep_buf != NULL, 0);
- TU_VERIFY(stream_claim(s), 0);
- TU_ASSERT(stream_xfer(s, s->ep_bufsize), 0);
- return s->ep_bufsize;
- } else
- #endif
- {
- uint16_t available = tu_fifo_remaining(&s->ff);
+ uint16_t available = tu_fifo_remaining(&s->ff);
- // Prepare for incoming data but only allow what we can store in the ring buffer.
- // TODO Actually we can still carry out the transfer, keeping count of received bytes
- // and slowly move it to the FIFO when read().
- // This pre-check reduces endpoint claiming
- TU_VERIFY(available >= s->mps);
- TU_VERIFY(stream_claim(s), 0);
- available = tu_fifo_remaining(&s->ff); // re-get available since fifo can be changed
+ // Prepare for incoming data but only allow what we can store in the ring buffer.
+ // TODO Actually we can still carry out the transfer, keeping count of received bytes
+ // and slowly move it to the FIFO when read().
+ // This pre-check reduces endpoint claiming
+ TU_VERIFY(available >= s->mps);
+ TU_VERIFY(stream_claim(s), 0);
+ available = tu_fifo_remaining(&s->ff); // re-get available since fifo can be changed
- if (available >= s->mps) {
- // multiple of packet size limit by ep bufsize
- uint16_t count = (uint16_t) (available & ~(s->mps - 1));
- if (s->ep_buf != NULL) {
- count = tu_min16(count, s->ep_bufsize);
- }
- TU_ASSERT(stream_xfer(s, count), 0);
- return count;
- } else {
- // Release endpoint since we don't make any transfer
- stream_release(s);
- return 0;
- }
+ if (available >= s->mps) {
+ // multiple of packet size limit by ep bufsize
+ uint16_t count = (uint16_t) (available & ~(s->mps - 1));
+ count = tu_min16(count, s->ep_bufsize);
+ TU_ASSERT(stream_xfer(s, count), 0);
+ return count;
+ } else {
+ // Release endpoint since we don't make any transfer
+ stream_release(s);
+ return 0;
}
}
diff --git a/src/tusb_option.h b/src/tusb_option.h
index 08bf0ebc5..1e4d8ef4a 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -216,6 +216,7 @@
#define OPT_MCU_AT32F402_405 2504 ///< ArteryTek AT32F402_405
#define OPT_MCU_AT32F425 2505 ///< ArteryTek AT32F425
#define OPT_MCU_AT32F413 2506 ///< ArteryTek AT32F413
+#define OPT_MCU_AT32F45X 2507 ///< ArteryTek AT32F45x
// HPMicro
#define OPT_MCU_HPM 2600 ///< HPMicro
@@ -272,17 +273,27 @@
// USBIP
//--------------------------------------------------------------------+
-//------------- DWC2 -------------//
-// Slave mode for device
-#ifndef CFG_TUD_DWC2_SLAVE_ENABLE
- #ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
- #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT 1
+//------------- ChipIdea -------------//
+// Enable CI_HS VBUS Charge. Set this to 1 if the USB_VBUS pin is not connected to 5V VBUS (note: 3.3V is
+// insufficient).
+#ifndef CFG_TUD_CI_HS_VBUS_CHARGE
+ #ifndef CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
+ #define CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT 0
#endif
+ #define CFG_TUD_CI_HS_VBUS_CHARGE CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
+#endif
- #define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
+// CI_HS support FIFO transfer if endpoint buffer is 4k aligned and size is multiple of 4k, also DCACHE is disabled
+#ifndef CFG_TUD_CI_HS_EPBUF_4K_ALIGNED
+ #define CFG_TUD_CI_HS_EPBUF_4K_ALIGNED 0
+#endif
+
+#if CFG_TUD_CI_HS_EPBUF_4K_ALIGNED && !CFG_TUD_MEM_DCACHE_ENABLE
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
#endif
-// DMA for device
+//------------- DWC2 -------------//
+// DMA mode for device
#ifndef CFG_TUD_DWC2_DMA_ENABLE
#ifndef CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
#define CFG_TUD_DWC2_DMA_ENABLE_DEFAULT 0
@@ -291,16 +302,16 @@
#define CFG_TUD_DWC2_DMA_ENABLE CFG_TUD_DWC2_DMA_ENABLE_DEFAULT
#endif
-// Slave mode for host
-#ifndef CFG_TUH_DWC2_SLAVE_ENABLE
- #ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
- #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT 1
+// Slave mode for device
+#ifndef CFG_TUD_DWC2_SLAVE_ENABLE
+ #ifndef CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
+ #define CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUD_DWC2_DMA_ENABLE // disabled if DMA is enabled
#endif
- #define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
+ #define CFG_TUD_DWC2_SLAVE_ENABLE CFG_TUD_DWC2_SLAVE_ENABLE_DEFAULT
#endif
-// DMA for host
+// DMA mode for host
#ifndef CFG_TUH_DWC2_DMA_ENABLE
#ifndef CFG_TUH_DWC2_DMA_ENABLE_DEFAULT
#define CFG_TUH_DWC2_DMA_ENABLE_DEFAULT 0
@@ -309,36 +320,55 @@
#define CFG_TUH_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE_DEFAULT
#endif
-#if defined(TUP_USBIP_DWC2)
- #if CFG_TUD_DWC2_SLAVE_ENABLE && !CFG_TUD_DWC2_DMA_ENABLE
- #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+// Slave mode for host
+#ifndef CFG_TUH_DWC2_SLAVE_ENABLE
+ #ifndef CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
+ #define CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT !CFG_TUH_DWC2_DMA_ENABLE // disabled if DMA is enabled
#endif
- #if CFG_TUH_DWC2_SLAVE_ENABLE && !CFG_TUH_DWC2_DMA_ENABLE
- #define CFG_TUH_EDPT_DEDICATED_HWFIFO 1
- #endif
+ #define CFG_TUH_DWC2_SLAVE_ENABLE CFG_TUH_DWC2_SLAVE_ENABLE_DEFAULT
#endif
-//------------- ChipIdea -------------//
-// Enable CI_HS VBUS Charge. Set this to 1 if the USB_VBUS pin is not connected to 5V VBUS (note: 3.3V is
-// insufficient).
-#ifndef CFG_TUD_CI_HS_VBUS_CHARGE
- #ifndef CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
- #define CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT 0
+#if defined(TUP_USBIP_DWC2)
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO CFG_TUD_DWC2_SLAVE_ENABLE
+ #define CFG_TUH_EDPT_DEDICATED_HWFIFO CFG_TUH_DWC2_SLAVE_ENABLE
+
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32bit access
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo address
+#endif
+
+//------------ FSDEV --------------//
+#if defined(TUP_USBIP_FSDEV)
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+
+ #if CFG_TUSB_FSDEV_PMA_SIZE == 2048 || TU_CHECK_MCU(OPT_MCU_STM32U0)
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32-bit data
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase
+ #elif CFG_TUSB_FSDEV_PMA_SIZE == 1024
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 2 // 16-bit address increase
+ #elif CFG_TUSB_FSDEV_PMA_SIZE == 512
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase
#endif
- #define CFG_TUD_CI_HS_VBUS_CHARGE CFG_TUD_CI_HS_VBUS_CHARGE_DEFAULT
#endif
-// CI_HS support FIFO transfer if endpoint buffer is 4k aligned and size is multiple of 4k, also DCACHE is disabled
-#ifndef CFG_TUD_CI_HS_EPBUF_4K_ALIGNED
- #define CFG_TUD_CI_HS_EPBUF_4K_ALIGNED 0
+//------------ MAX3421 -------------//
+// Enable MAX3421 USB host controller
+#ifndef CFG_TUH_MAX3421
+ #define CFG_TUH_MAX3421 0
#endif
-#if CFG_TUD_CI_HS_EPBUF_4K_ALIGNED && !CFG_TUD_MEM_DCACHE_ENABLE
- #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+//------------ MUSB --------------//
+#if defined(TUP_USBIP_MUSB)
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32 bit data
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo
#endif
-//------------- pio-usb -------------//
+//------------- Raspberry Pi -------------//
// Enable PIO-USB software host controller
#ifndef CFG_TUH_RPI_PIO_USB
#define CFG_TUH_RPI_PIO_USB 0
@@ -348,25 +378,21 @@
#define CFG_TUD_RPI_PIO_USB 0
#endif
-//------------ MAX3421 -------------//
-// Enable MAX3421 USB host controller
-#ifndef CFG_TUH_MAX3421
- #define CFG_TUH_MAX3421 0
-#endif
-
-//------------ FSDEV --------------//
-#if defined(TUP_USBIP_FSDEV)
- #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
-#endif
-
-//------------ MUSB --------------//
-#if defined(TUP_USBIP_MUSB)
- #define CFG_TUD_EDPT_DEDICATED_HWFIFO 0 // need testing to enable
+#if (CFG_TUSB_MCU == OPT_MCU_RP2040) && !CFG_TUD_RPI_PIO_USB
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 1
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 1
+ #define CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE
+ #define CFG_TUSB_FIFO_HWFIFO_CUSTOM_READ
#endif
//------------ RUSB2 --------------//
#if defined(TUP_USBIP_RUSB2)
- #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE (2 | (TUD_OPT_HIGH_SPEED ? 4 : 0)) // 16 bit and 32 bit if highspeed
+ #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0
+ #define CFG_TUSB_FIFO_HWFIFO_CUSTOM_WRITE // custom write since rusb2 can change access width 32 -> 16 and can write
+ // odd byte with byte access
#endif
//--------------------------------------------------------------------
@@ -535,6 +561,11 @@
#define CFG_TUD_INTERFACE_MAX 16
#endif
+// max events processed in one tud_task_ext() call, 0 for unlimited
+#ifndef CFG_TUD_TASK_EVENTS_PER_RUN
+ #define CFG_TUD_TASK_EVENTS_PER_RUN 16
+#endif
+
// default to max hardware endpoint, but can be smaller to save RAM
#ifndef CFG_TUD_ENDPPOINT_MAX
#define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX
@@ -654,6 +685,11 @@
#define CFG_TUH_MEM_DCACHE_LINE_SIZE CFG_TUSB_MEM_DCACHE_LINE_SIZE
#endif
+// max events processed in one tuh_task_ext() call, 0 for unlimited
+#ifndef CFG_TUH_TASK_EVENTS_PER_RUN
+ #define CFG_TUH_TASK_EVENTS_PER_RUN 16
+#endif
+
//------------- CLASS -------------//
#ifndef CFG_TUH_HUB
@@ -725,7 +761,7 @@
#define CFG_TUH_CDC_PL2303 0
#endif
-#ifndef CFG_TUH_CDC_PL2303_VID_PID_QUIRKS_LIST
+#ifndef CFG_TUH_CDC_PL2303_VID_PID_LIST
// List of product IDs that can use the PL2303 CDC driver
#define CFG_TUH_CDC_PL2303_VID_PID_LIST \
{ 0x067b, 0x2303 }, /* initial 2303 */ \
diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py
index b2e883119..b84740867 100755
--- a/test/hil/hil_test.py
+++ b/test/hil/hil_test.py
@@ -151,7 +151,7 @@ def read_disk_file(uid, lun, fname):
def open_mtp_dev(uid):
mtp = MTP()
# MTP seems to take a while to enumerate
- timeout = 2*ENUM_TIMEOUT
+ timeout = 2 * ENUM_TIMEOUT
while timeout > 0:
# run_cmd(f"gio mount -u mtp://TinyUsb_TinyUsb_Device_{uid}/")
for raw in mtp.detect_devices():
@@ -410,22 +410,22 @@ def test_device_cdc_dual_ports(board):
sizes = [32, 64, 128, 256, 512, random.randint(2000, 5000)]
def write_and_check(writer, payload):
- size = len(payload)
+ payload_len = len(payload)
for s in ser:
s.reset_input_buffer()
rd0 = b''
rd1 = b''
offset = 0
# Write in chunks of random 1-64 bytes (device has 64-byte buffer)
- while offset < size:
- chunk_size = min(random.randint(1, 64), size - offset)
+ while offset < payload_len:
+ chunk_size = min(random.randint(1, 64), payload_len - offset)
ser[writer].write(payload[offset:offset + chunk_size])
ser[writer].flush()
rd0 += ser[0].read(chunk_size)
rd1 += ser[1].read(chunk_size)
offset += chunk_size
- assert rd0 == payload.lower(), f'Port0 wrong data ({size}): expected {payload.lower()[:16]}... was {rd0[:16]}'
- assert rd1 == payload.upper(), f'Port1 wrong data ({size}): expected {payload.upper()[:16]}... was {rd1[:16]}'
+ assert rd0 == payload.lower(), f'Port0 wrong data ({payload_len}): expected {payload.lower()}... was {rd0}'
+ assert rd1 == payload.upper(), f'Port1 wrong data ({payload_len}): expected {payload.upper()}... was {rd1}'
for size in sizes:
payload0 = rand_ascii(size)
diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json
index 6afcb2186..7cb561b2d 100644
--- a/test/hil/tinyusb.json
+++ b/test/hil/tinyusb.json
@@ -103,10 +103,10 @@
"name": "ra4m1_ek",
"uid": "152E163038303131393346E46F26574B",
"tests": {
- "device": true, "host": false, "dual": false,
- "skip": ["device/cdc_msc", "device/cdc_msc_freertos"]
+ "device": true,
+ "host": false,
+ "dual": false
},
- "comment": "MSC is slow to enumerated #2602",
"flasher": {
"name": "jlink",
"uid": "000831174392",
diff --git a/test/unit-test/CMakeLists.txt b/test/unit-test/CMakeLists.txt
index 7172f5575..b44a91d57 100644
--- a/test/unit-test/CMakeLists.txt
+++ b/test/unit-test/CMakeLists.txt
@@ -113,7 +113,6 @@ add_ceedling_test(
${CEEDLING_WORKDIR}/../../src/common/tusb_fifo.c
""
)
-target_compile_definitions(test_fifo PRIVATE CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32=1)
add_ceedling_test(
test_usbd
diff --git a/test/unit-test/project.yml b/test/unit-test/project.yml
index d971d098d..be3fc3de0 100644
--- a/test/unit-test/project.yml
+++ b/test/unit-test/project.yml
@@ -128,7 +128,9 @@
:defines:
:test:
- _UNITY_TEST_
- - CFG_TUSB_FIFO_ACCESS_FIXED_ADDR_RW32
+ - CFG_TUD_EDPT_DEDICATED_HWFIFO=1
+ - CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE=6
+ - CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE=0
:release: []
# Enable to inject name of a test as a unique compilation symbol into its respective executable build.
diff --git a/test/unit-test/test/test_fifo.c b/test/unit-test/test/test_fifo.c
index 35bbeaa62..b9279cb25 100644
--- a/test/unit-test/test/test_fifo.c
+++ b/test/unit-test/test/test_fifo.c
@@ -32,7 +32,7 @@
#define FIFO_SIZE 64
uint8_t tu_ff_buf[FIFO_SIZE * sizeof(uint8_t)];
-tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, uint8_t, false);
+tu_fifo_t tu_ff = TU_FIFO_INIT(tu_ff_buf, FIFO_SIZE, false);
tu_fifo_t *ff = &tu_ff;
tu_fifo_buffer_info_t info;
@@ -40,6 +40,16 @@ tu_fifo_buffer_info_t info;
uint8_t test_data[4096];
uint8_t rd_buf[FIFO_SIZE];
+static const tu_hwfifo_access_t hwfifo_access_32 = {
+ .data_stride = 4,
+ .param = 0,
+};
+
+static const tu_hwfifo_access_t hwfifo_access_16 = {
+ .data_stride = 2,
+ .param = 0,
+};
+
void setUp(void) {
tu_fifo_clear(ff);
memset(&info, 0, sizeof(tu_fifo_buffer_info_t));
@@ -68,34 +78,6 @@ void test_normal(void) {
}
}
-void test_item_size(void) {
- uint8_t ff4_buf[FIFO_SIZE * sizeof(uint32_t)];
- tu_fifo_t ff4 = TU_FIFO_INIT(ff4_buf, FIFO_SIZE, uint32_t, false);
-
- uint32_t data4[2 * FIFO_SIZE];
- for (uint32_t i = 0; i < sizeof(data4) / 4; i++) {
- data4[i] = i;
- }
-
- // fill up fifo
- tu_fifo_write_n(&ff4, data4, FIFO_SIZE);
-
- uint32_t rd_buf4[FIFO_SIZE];
- uint16_t rd_count;
-
- // read 0 -> 4
- rd_count = tu_fifo_read_n(&ff4, rd_buf4, 5);
- TEST_ASSERT_EQUAL(5, rd_count);
- TEST_ASSERT_EQUAL_UINT32_ARRAY(data4, rd_buf4, rd_count); // 0 -> 4
-
- tu_fifo_write_n(&ff4, data4 + FIFO_SIZE, 5);
-
- // read all 5 -> 68
- rd_count = tu_fifo_read_n(&ff4, rd_buf4, FIFO_SIZE);
- TEST_ASSERT_EQUAL(FIFO_SIZE, rd_count);
- TEST_ASSERT_EQUAL_UINT32_ARRAY(data4 + 5, rd_buf4, rd_count); // 5 -> 68
-}
-
void test_read_n(void) {
uint16_t rd_count;
@@ -362,7 +344,7 @@ void test_rd_idx_wrap(void) {
uint8_t buf[10];
uint8_t dst[10];
- tu_fifo_config(&ff10, buf, 10, 1, 1);
+ tu_fifo_config(&ff10, buf, 10, 1);
uint16_t n;
@@ -431,7 +413,7 @@ void test_write_n_fixed_addr_rw32_nowrap(void) {
for (uint8_t n = 1; n <= 8; n++) {
tu_fifo_clear(ff);
- uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)&reg, n, TU_FIFO_FIXED_ADDR_RW32);
+ uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)&reg, n, &hwfifo_access_32);
TEST_ASSERT_EQUAL(n, written);
TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
@@ -453,7 +435,7 @@ void test_write_n_fixed_addr_rw32_wrapped(void) {
ff->wr_idx = FIFO_SIZE - 3;
ff->rd_idx = FIFO_SIZE - 3;
- uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)&reg, n, TU_FIFO_FIXED_ADDR_RW32);
+ uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)&reg, n, &hwfifo_access_32);
TEST_ASSERT_EQUAL(n, written);
TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
@@ -473,7 +455,7 @@ void test_read_n_fixed_addr_rw32_nowrap(void) {
tu_fifo_write_n(ff, pattern, 8);
uint32_t reg = 0;
- uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, &reg, n, TU_FIFO_FIXED_ADDR_RW32);
+ uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, &reg, n, &hwfifo_access_32);
TEST_ASSERT_EQUAL(n, read_cnt);
TEST_ASSERT_EQUAL(8 - n, tu_fifo_count(ff));
@@ -497,7 +479,7 @@ void test_read_n_fixed_addr_rw32_wrapped(void) {
}
uint32_t reg = 0;
- uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, &reg, n, TU_FIFO_FIXED_ADDR_RW32);
+ uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, &reg, n, &hwfifo_access_32);
TEST_ASSERT_EQUAL(n, read_cnt);
TEST_ASSERT_EQUAL(0, tu_fifo_count(ff));
@@ -505,6 +487,86 @@ void test_read_n_fixed_addr_rw32_wrapped(void) {
}
}
+void test_write_n_fixed_addr_rw16_nowrap(void) {
+ tu_fifo_clear(ff);
+
+ volatile uint16_t reg = 0x1122;
+ uint8_t expected[6] = {0x22, 0x11, 0x22, 0x11, 0x22, 0x11};
+
+ for (uint8_t n = 1; n <= 6; n++) {
+ tu_fifo_clear(ff);
+ uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)&reg, n, &hwfifo_access_16);
+ TEST_ASSERT_EQUAL(n, written);
+ TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
+
+ uint8_t out[6] = {0};
+ tu_fifo_read_n(ff, out, n);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n);
+ }
+}
+
+void test_write_n_fixed_addr_rw16_wrapped(void) {
+ tu_fifo_clear(ff);
+
+ volatile uint16_t reg = 0xA1B2;
+ uint8_t expected[6] = {0xB2, 0xA1, 0xB2, 0xA1, 0xB2, 0xA1};
+
+ for (uint8_t n = 1; n <= 6; n++) {
+ tu_fifo_clear(ff);
+ // Position the fifo near the end so writes wrap
+ ff->wr_idx = FIFO_SIZE - 3;
+ ff->rd_idx = FIFO_SIZE - 3;
+
+ uint16_t written = tu_fifo_write_n_access_mode(ff, (const void *)&reg, n, &hwfifo_access_16);
+ TEST_ASSERT_EQUAL(n, written);
+ TEST_ASSERT_EQUAL(n, tu_fifo_count(ff));
+
+ uint8_t out[6] = {0};
+ tu_fifo_read_n(ff, out, n);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, out, n);
+ }
+}
+
+void test_read_n_fixed_addr_rw16_nowrap(void) {
+ uint8_t pattern[6] = {0x10, 0x21, 0x32, 0x43, 0x54, 0x65};
+ uint16_t reg_expected[6] = {0x0010, 0x2110, 0x0032, 0x4332, 0x0054, 0x6554};
+
+ for (uint8_t n = 1; n <= 6; n++) {
+ tu_fifo_clear(ff);
+ tu_fifo_write_n(ff, pattern, 6);
+
+ uint16_t reg = 0;
+ uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, &reg, n, &hwfifo_access_16);
+ TEST_ASSERT_EQUAL(n, read_cnt);
+ TEST_ASSERT_EQUAL(6 - n, tu_fifo_count(ff));
+
+ TEST_ASSERT_EQUAL_HEX16(reg_expected[n - 1], reg);
+ }
+}
+
+void test_read_n_fixed_addr_rw16_wrapped(void) {
+ uint8_t pattern[6] = {0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5};
+ uint16_t reg_expected[6] = {0x00F0, 0xE1F0, 0x00D2, 0xC3D2, 0x00B4, 0xA5B4};
+
+ for (uint8_t n = 1; n <= 6; n++) {
+ tu_fifo_clear(ff);
+ ff->rd_idx = FIFO_SIZE - 1;
+ ff->wr_idx = (uint16_t)(ff->rd_idx + n);
+
+ for (uint8_t i = 0; i < n; i++) {
+ uint8_t idx = (uint8_t)((ff->rd_idx + i) % FIFO_SIZE);
+ ff->buffer[idx] = pattern[i];
+ }
+
+ uint16_t reg = 0;
+ uint16_t read_cnt = tu_fifo_read_n_access_mode(ff, &reg, n, &hwfifo_access_16);
+ TEST_ASSERT_EQUAL(n, read_cnt);
+ TEST_ASSERT_EQUAL(0, tu_fifo_count(ff));
+
+ TEST_ASSERT_EQUAL_HEX16(reg_expected[n - 1], reg);
+ }
+}
+
void test_get_read_info_advanced_cases(void) {
tu_fifo_clear(ff);
diff --git a/tools/build.py b/tools/build.py
index 87064b7a0..d22d06a0b 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -40,7 +40,9 @@ ci_skip_boards = {
}
ci_preferred_boards = {
- 'stm32h7': ['stm32h743eval'],
+ 'samd2x_l2x': ['metro_m0_express'],
+ 'samd5x_e5x': ['metro_m4_express'],
+ 'stm32h7': ['stm32h743eval']
}
diff --git a/tools/get_deps.py b/tools/get_deps.py
index deacbb23b..a75f0c169 100755
--- a/tools/get_deps.py
+++ b/tools/get_deps.py
@@ -209,7 +209,7 @@ deps_optional = {
'9442fbb71f855ff2e64fbf662b7726beba511a24',
'stm32wba'],
'hw/mcu/ti': ['https://github.com/hathach/ti_driver.git',
- '143ed6cc20a7615d042b03b21e070197d473e6e5',
+ '083944907e7d08fcb1f614b47598ce45935b8da1',
'msp430 msp432e4 tm4c'],
'hw/mcu/wch/ch32v103': ['https://github.com/openwch/ch32v103.git',
'7578cae0b21f86dd053a1f781b2fc6ab99d0ec17',
@@ -244,6 +244,9 @@ deps_optional = {
'hw/mcu/artery/at32f413': ['https://github.com/ArteryTek/AT32F413_Firmware_Library.git',
'f6fe62dfec9fd40c5b63d92fc5ef2c2b5e77a450',
'at32f413'],
+ 'hw/mcu/artery/at32f45x': ['https://github.com/ArteryTek/AT32F45x_Firmware_Library.git',
+ '3d4a1b38be8ebac292e2350ca53bc4bfa4430233',
+ 'at32f45x'],
'hw/mcu/hpmicro/hpm_sdk': ['https://github.com/hpmicro/hpm_sdk',
'8d2af741ecc4aaa82d7ee395dc1ce25d7070c3ff',
'hpmicro'],