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 bb8c6d65d..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 }}
@@ -319,3 +318,46 @@ jobs:
- 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/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/ccache-action@v1.2
+ 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 cc73ca8fc..5f9e1acd2 100644
--- a/.idea/cmake.xml
+++ b/.idea/cmake.xml
@@ -131,6 +131,7 @@
+
diff --git a/README.rst b/README.rst
index e439a3137..0eb1e84b9 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
--------
@@ -293,6 +293,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/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} $
VERBATIM)
+ set_property(TARGET ${TARGET}-bloaty PROPERTY FOLDER ${TARGET})
# post build
# add_custom_command(TARGET ${TARGET} POST_BUILD
# COMMAND ${BLOATY_EXE} --csv ${OPTION_LIST} $ > ${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} $.map
@@ -508,6 +511,8 @@ exit"
COMMAND ${JLINKEXE} -device ${JLINK_DEVICE} ${OPTION_LIST} -if ${JLINK_IF} -JTAGConf -1,-1 -speed auto -CommandFile $/${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 $ --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}.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 $" -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 $
)
+
+ 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} $
)
+
+ 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}.uf2
)
+ set_property(TARGET ${TARGET}-uf2 PROPERTY FOLDER ${TARGET})
endfunction()
@@ -657,6 +673,8 @@ function(family_flash_teensy TARGET)
COMMAND ${CMAKE_OBJCOPY} -Oihex $ $/${TARGET}.hex
COMMAND ${TEENSY_CLI} --mcu=${TEENSY_MCU} -w -s $/${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 $
)
+
+ 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}.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}.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}.hex
VERBATIM
)
+
+ set_property(TARGET ${TARGET}-uniflash PROPERTY FOLDER ${TARGET})
endfunction()
#----------------------------------
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 a725b7c8b..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; }
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index 22a9e4af8..a6abc6244 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -833,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);
}
diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h
index c53e345b0..b749a92ff 100644
--- a/src/portable/st/stm32_fsdev/fsdev_common.h
+++ b/src/portable/st/stm32_fsdev/fsdev_common.h
@@ -63,23 +63,21 @@ TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 b
// 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 CFG_TUSB_FSDEV_PMA_SIZE == 512
- // 1x16 bit / word access scheme
- #define FSDEV_PMA_STRIDE 2
- #define pma_access_scheme TU_ATTR_ALIGNED(4)
-#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 == 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 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
diff --git a/src/tusb.c b/src/tusb.c
index bf82cdbe9..6075e9db4 100644
--- a/src/tusb.c
+++ b/src/tusb.c
@@ -392,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);
}
diff --git a/src/tusb_option.h b/src/tusb_option.h
index abf5e0608..8e270e5f2 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -340,14 +340,14 @@
#if defined(TUP_USBIP_FSDEV)
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
- #if CFG_TUSB_FSDEV_PMA_SIZE == 512
- #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data
+ #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 == 2048
- #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32-bit data
+ #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
#endif
@@ -560,6 +560,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
@@ -679,6 +684,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