From e158a3dd38fccd99169a3e5b8cecf7a1ac45915e Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 3 Jan 2026 12:49:01 +0700 Subject: hwfifo support custom write/read rusb use custom write enable all hil test for ra4m1 --- test/hil/tinyusb.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 6afcb2186..047d0879c 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -103,8 +103,9 @@ "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": { -- cgit v1.3.1 From e5c53f02c5f1e7a5ffae7d66c702e54e88bf8f71 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 6 Jan 2026 11:09:22 +0700 Subject: minor update --- .idea/cmake.xml | 3 +++ .idea/debugServers/ST_LINK.xml | 4 ++-- test/hil/tinyusb.json | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/.idea/cmake.xml b/.idea/cmake.xml index 0754253ad..cc73ca8fc 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -103,6 +103,8 @@ + + @@ -126,6 +128,7 @@ + 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 @@ - + - + diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 047d0879c..7cb561b2d 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -107,7 +107,6 @@ "host": false, "dual": false }, - "comment": "MSC is slow to enumerated #2602", "flasher": { "name": "jlink", "uid": "000831174392", -- cgit v1.3.1 From e4950e9b693171f7bb47d8c1f800ece8827242ec Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 3 Mar 2026 18:25:18 +0700 Subject: add esptool --force for esp32p4 v0.1 --- test/hil/hil_test.py | 2 +- test/hil/tinyusb.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index b84740867..757456806 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -302,7 +302,7 @@ def flash_esptool(board, firmware): idf_target = json.load(f)['IDF_TARGET'] with open(f'{fw_dir}/flash_args') as f: flash_args = f.read().strip().replace('\n', ' ') - command = (f'esptool.py --chip {idf_target} -p {port} {flasher["args"]} ' + command = (f'esptool --chip {idf_target} -p {port} {flasher["args"]} ' f'--before=default_reset --after=hard_reset write_flash {flash_args}') ret = run_cmd(command, cwd=fw_dir) return ret diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 7cb561b2d..4d7276c8f 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -13,7 +13,8 @@ "flasher": { "name": "esptool", "uid": "4ea4f48f6bc3ee11bbb9d00f9e1b1c54", - "args": "-b 1500000" + "args": "-b 1500000 --force", + "comment": "use --force for ESP32-P4 v0.1" }, "comment": "Use TS3USB30 mux to test both device and host" }, -- cgit v1.3.1 From 07620c125ba2090b7f1983ba39a9655cde194c6d Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 4 Mar 2026 17:59:19 +0700 Subject: esp32p4 min rev 0.1 --- hw/bsp/espressif/boards/espressif_p4_function_ev/board.cmake | 1 + hw/bsp/espressif/boards/espressif_p4_function_ev/sdkconfig.defaults | 2 ++ test/hil/tinyusb.json | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 hw/bsp/espressif/boards/espressif_p4_function_ev/sdkconfig.defaults (limited to 'test/hil/tinyusb.json') diff --git a/hw/bsp/espressif/boards/espressif_p4_function_ev/board.cmake b/hw/bsp/espressif/boards/espressif_p4_function_ev/board.cmake index fe4db4fc1..455ca90a1 100644 --- a/hw/bsp/espressif/boards/espressif_p4_function_ev/board.cmake +++ b/hw/bsp/espressif/boards/espressif_p4_function_ev/board.cmake @@ -1,2 +1,3 @@ # Apply board specific content here set(IDF_TARGET "esp32p4") +list(APPEND SDKCONFIG_DEFAULTS "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults") diff --git a/hw/bsp/espressif/boards/espressif_p4_function_ev/sdkconfig.defaults b/hw/bsp/espressif/boards/espressif_p4_function_ev/sdkconfig.defaults new file mode 100644 index 000000000..6b0a548f6 --- /dev/null +++ b/hw/bsp/espressif/boards/espressif_p4_function_ev/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_1=y diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 4d7276c8f..029e5ffcd 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -13,7 +13,7 @@ "flasher": { "name": "esptool", "uid": "4ea4f48f6bc3ee11bbb9d00f9e1b1c54", - "args": "-b 1500000 --force", + "args": "-b 1500000", "comment": "use --force for ESP32-P4 v0.1" }, "comment": "Use TS3USB30 mux to test both device and host" -- cgit v1.3.1 From c6e13e8c15fc6372589b685f5aa4ee60f0cd28f7 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 12 Mar 2026 23:06:39 +0700 Subject: update hil host --- test/hil/tinyusb.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 029e5ffcd..e1ba5da57 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -67,7 +67,8 @@ }, "tests": { "device": true, "host": false, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002130"}] + "dev_attached": [{"vid_pid": "067b_2303", "serial": "0"}], + "comment": "pl23x" }, "flasher": { "name": "jlink", @@ -80,7 +81,8 @@ "uid": "BAE96FB95AFA6DBB8F00005002001200", "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023299"}] + "dev_attached": [{"vid_pid": "10c4_ea60", "serial": "0001"}], + "comment": "cp2102" }, "flasher": { "name": "jlink", @@ -122,7 +124,8 @@ }, "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002470"}] + "dev_attached": [{"vid_pid": "1a86_7523", "serial": "0"}], + "comment": "ch34x" }, "flasher": { "name": "openocd", -- cgit v1.3.1 From aa1535a226ef5de12f01e4334e0e6c08ecb3b869 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 13 Mar 2026 12:18:27 +0700 Subject: add support for CH32F20X MCU and update board configuration --- .../device/audio_4_channel_mic_freertos/skip.txt | 1 + examples/device/audio_test_freertos/skip.txt | 1 + examples/device/cdc_msc_freertos/skip.txt | 1 + examples/device/hid_composite_freertos/skip.txt | 1 + examples/device/midi_test_freertos/skip.txt | 1 + examples/host/cdc_msc_hid_freertos/skip.txt | 1 + hw/bsp/ch32f20x/boards/ch32f205r-r0/board.cmake | 7 ++ hw/bsp/ch32f20x/family.cmake | 97 ++++++++++++++++++++++ test/hil/tinyusb.json | 24 +++--- 9 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 hw/bsp/ch32f20x/boards/ch32f205r-r0/board.cmake create mode 100644 hw/bsp/ch32f20x/family.cmake (limited to 'test/hil/tinyusb.json') diff --git a/examples/device/audio_4_channel_mic_freertos/skip.txt b/examples/device/audio_4_channel_mic_freertos/skip.txt index db01347ed..ded5ee4bc 100644 --- a/examples/device/audio_4_channel_mic_freertos/skip.txt +++ b/examples/device/audio_4_channel_mic_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/audio_test_freertos/skip.txt b/examples/device/audio_test_freertos/skip.txt index 7463aa86a..be1912a31 100644 --- a/examples/device/audio_test_freertos/skip.txt +++ b/examples/device/audio_test_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/cdc_msc_freertos/skip.txt b/examples/device/cdc_msc_freertos/skip.txt index d3a096eb0..199cd8ac6 100644 --- a/examples/device/cdc_msc_freertos/skip.txt +++ b/examples/device/cdc_msc_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/hid_composite_freertos/skip.txt b/examples/device/hid_composite_freertos/skip.txt index 06920db67..62f4a3795 100644 --- a/examples/device/hid_composite_freertos/skip.txt +++ b/examples/device/hid_composite_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/midi_test_freertos/skip.txt b/examples/device/midi_test_freertos/skip.txt index 06920db67..62f4a3795 100644 --- a/examples/device/midi_test_freertos/skip.txt +++ b/examples/device/midi_test_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32F20X mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/host/cdc_msc_hid_freertos/skip.txt b/examples/host/cdc_msc_hid_freertos/skip.txt index 54e7be1ba..74ee436cb 100644 --- a/examples/host/cdc_msc_hid_freertos/skip.txt +++ b/examples/host/cdc_msc_hid_freertos/skip.txt @@ -1,2 +1,3 @@ +mcu:CH32F20X mcu:RP2040 board:lpcxpresso54114 diff --git a/hw/bsp/ch32f20x/boards/ch32f205r-r0/board.cmake b/hw/bsp/ch32f20x/boards/ch32f205r-r0/board.cmake new file mode 100644 index 000000000..d2877102d --- /dev/null +++ b/hw/bsp/ch32f20x/boards/ch32f205r-r0/board.cmake @@ -0,0 +1,7 @@ +set(MCU_VARIANT D8C) + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + CH32F20x_D8C + ) +endfunction() diff --git a/hw/bsp/ch32f20x/family.cmake b/hw/bsp/ch32f20x/family.cmake new file mode 100644 index 000000000..2027f7bb1 --- /dev/null +++ b/hw/bsp/ch32f20x/family.cmake @@ -0,0 +1,97 @@ +include_guard() + +set(CH32_FAMILY ch32f20x) +set(SDK_DIR ${TOP}/hw/mcu/wch/${CH32_FAMILY}) +set(SDK_SRC_DIR ${SDK_DIR}/EVT/EXAM/SRC) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# toolchain set up +set(CMAKE_SYSTEM_CPU cortex-m3 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake) + +set(FAMILY_MCUS CH32F20X CACHE INTERNAL "") + +#------------------------------------ +# Startup & Linker script +#------------------------------------ +if (NOT DEFINED LD_FILE_GNU) + set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/ch32f205.ld) +endif () +set(LD_FILE_Clang ${LD_FILE_GNU}) + +if (NOT DEFINED STARTUP_FILE_GNU) + set(STARTUP_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/startup_gcc_ch32f20x_d8c.s) +endif () +set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + +#------------------------------------ +# Board Target +#------------------------------------ +function(family_add_board BOARD_TARGET) + add_library(${BOARD_TARGET} STATIC + ${SDK_SRC_DIR}/StdPeriphDriver/src/${CH32_FAMILY}_gpio.c + ${SDK_SRC_DIR}/StdPeriphDriver/src/${CH32_FAMILY}_misc.c + ${SDK_SRC_DIR}/StdPeriphDriver/src/${CH32_FAMILY}_rcc.c + ${SDK_SRC_DIR}/StdPeriphDriver/src/${CH32_FAMILY}_usart.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_${CH32_FAMILY}.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/debug_uart.c + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${SDK_SRC_DIR}/StdPeriphDriver/inc + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + target_compile_definitions(${BOARD_TARGET} PUBLIC + BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + ) + + update_board(${BOARD_TARGET}) +endfunction() + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + family_add_tinyusb(${TARGET} OPT_MCU_CH32F20X) + + target_sources(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ${TOP}/src/portable/wch/dcd_ch32_usbhs.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}" + --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 () + + 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") + 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_stlink(${TARGET}) +endfunction() diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index e1ba5da57..8de8c7f32 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -76,6 +76,18 @@ "args": "-device ATSAMD51J19" } }, + { + "name": "mimxrt1015_evk", + "uid": "DC28F865D2111D228D00B0543A70463C", + "tests": { + "device": true, "host": false, "dual": false + }, + "flasher": { + "name": "jlink", + "uid": "000726284213", + "args": "-device MIMXRT1015DAF5A" + } + }, { "name": "mimxrt1064_evk", "uid": "BAE96FB95AFA6DBB8F00005002001200", @@ -233,18 +245,6 @@ "args": "-device stm32f769ni" } }, - { - "name": "mimxrt1015_evk", - "uid": "DC28F865D2111D228D00B0543A70463C", - "tests": { - "device": true, "host": false, "dual": false - }, - "flasher": { - "name": "jlink", - "uid": "000726284213", - "args": "-device MIMXRT1015DAF5A" - } - }, { "name": "nanoch32v203", "uid": "CDAB277B0FBC03E339E339E3", -- cgit v1.3.1 From 741132948b10d2410692b46b227da194fefb7238 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 16 Mar 2026 22:33:25 +0700 Subject: Unify USB FSDEV driver implementation for various microcontrollers. Replace `FSDEV_BUS_32BIT` with `CFG_TUSB_FSDEV_32BIT`, adjust data/address stride macros, and refactor register/PMU access for consistency across platforms. --- src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c | 4 +- src/portable/st/stm32_fsdev/fsdev_common.c | 2 +- src/portable/st/stm32_fsdev/fsdev_common.h | 180 +++++++++++--------------- src/portable/st/stm32_fsdev/fsdev_stm32.h | 16 +-- src/tusb_option.h | 4 + test/hil/tinyusb.json | 6 +- 6 files changed, 91 insertions(+), 121 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c index 965ebbbe5..c06911177 100644 --- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c +++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c @@ -177,7 +177,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { FSDEV_REG->CNTR = 0; // Enable USB - #if !defined(FSDEV_BUS_32BIT) + #if !defined( CFG_TUSB_FSDEV_32BIT) // BTABLE register does not exist any more on 32-bit bus devices FSDEV_REG->BTABLE = FSDEV_BTABLE_BASE; #endif @@ -407,7 +407,7 @@ void dcd_int_handler(uint8_t rhport) { const uint32_t ep_reg = ep_read(ep_id); if (ep_reg & U_EP_CTR_RX) { - #ifdef FSDEV_BUS_32BIT + #ifdef CFG_TUSB_FSDEV_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 diff --git a/src/portable/st/stm32_fsdev/fsdev_common.c b/src/portable/st/stm32_fsdev/fsdev_common.c index f63b6755a..003bcd069 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.c +++ b/src/portable/st/stm32_fsdev/fsdev_common.c @@ -104,7 +104,7 @@ void btable_set_rx_bufsize(uint32_t ep_id, uint8_t buf_id, uint16_t wCount) { bl_nb = 1 << 15; } -#ifdef FSDEV_BUS_32BIT +#ifdef CFG_TUSB_FSDEV_32BIT uint32_t count_addr = FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr; count_addr = (bl_nb << 16) | (count_addr & 0x0000FFFFu); FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr = count_addr; diff --git a/src/portable/st/stm32_fsdev/fsdev_common.h b/src/portable/st/stm32_fsdev/fsdev_common.h index 36df4809d..140ff1d61 100644 --- a/src/portable/st/stm32_fsdev/fsdev_common.h +++ b/src/portable/st/stm32_fsdev/fsdev_common.h @@ -29,6 +29,10 @@ #ifndef TUSB_FSDEV_COMMON_H #define TUSB_FSDEV_COMMON_H +#ifdef __cplusplus +extern "C" { +#endif + #include "common/tusb_common.h" #if CFG_TUD_ENABLED @@ -88,7 +92,7 @@ #define U_EPREG_MASK_32 (U_EP_ERRRX | U_EP_ERRTX | U_EP_LSEP | U_EP_NAK | U_EP_DEVADDR | U_EPREG_MASK_16) // EP register mask selection based on bus width -#ifdef FSDEV_BUS_32BIT +#ifdef CFG_TUSB_FSDEV_32BIT #define U_EPREG_MASK U_EPREG_MASK_32 #else #define U_EPREG_MASK U_EPREG_MASK_16 @@ -203,89 +207,74 @@ #define U_CH_RX_VALID 0x3000u //--------------------------------------------------------------------+ -// Vendor-specific includes (after U_ definitions so they can use them) +// Registers Typedef //--------------------------------------------------------------------+ -#if defined(TUP_USBIP_FSDEV_STM32) - #include "fsdev_stm32.h" -#elif defined(TUP_USBIP_FSDEV_CH32) - #include "fsdev_ch32.h" -#elif defined(TUP_USBIP_FSDEV_AT32) - #include "fsdev_at32.h" -#else - #error "Unknown USB IP" -#endif +// hardware limit endpoint +#define FSDEV_EP_COUNT 8 -// LPM support - detect from vendor header (L1REQ bit position varies) -#if defined(USB_ISTR_L1REQ) - #define U_ISTR_L1REQ USB_ISTR_L1REQ +// The fsdev_bus_t type can be used for both register and PMA access necessities +#ifdef CFG_TUSB_FSDEV_32BIT +typedef uint32_t fsdev_bus_t; #else - #define U_ISTR_L1REQ 0x0000u +typedef uint16_t fsdev_bus_t; #endif -#define U_ISTR_ALL_EVENTS (U_ISTR_PMAOVR | U_ISTR_ERR | U_ISTR_WKUP | U_ISTR_SUSP | \ - U_ISTR_RESET | U_ISTR_SOF | U_ISTR_ESOF | U_ISTR_L1REQ) +// volatile 32-bit aligned +#define _va32 volatile TU_ATTR_ALIGNED(4) -#ifdef __cplusplus -extern "C" { -#endif +typedef struct { + struct { + _va32 fsdev_bus_t reg; + } 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 + _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status (not on F1, F3, AT32, CH32) + _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector (not on F1, F3, AT32, CH32) +} 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) + +//--------------------------------------------------------------------+ +// BTable and PMA Access +//--------------------------------------------------------------------+ // 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 #endif +TU_VERIFY_STATIC((FSDEV_BTABLE_BASE & 0x7) == 0, "BTABLE base must be aligned to 8 bytes"); -TU_VERIFY_STATIC(FSDEV_BTABLE_BASE % 8 == 0, "BTABLE base must be aligned to 8 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) or 32-bit address -// - 2048-byte devices, access with 32-bit address -#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 +#define FSDEV_ADDR_DATA_RATIO (CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE/CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE) -// 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; +// Need alignment when access address is 32 bit but data is only 16-bit +#if FSDEV_ADDR_DATA_RATIO == 2 + #define fsdev_addr_data_align TU_ATTR_ALIGNED(4) #else -typedef uint16_t fsdev_bus_t; + #define fsdev_addr_data_align #endif -enum { - FSDEV_BUS_SIZE = sizeof(fsdev_bus_t), -}; - -//--------------------------------------------------------------------+ -// BTable Typedef -//--------------------------------------------------------------------+ enum { BTABLE_BUF_TX = 0, BTABLE_BUF_RX = 1 }; -// hardware limit endpoint -#define FSDEV_EP_COUNT 8 - // Buffer Table is located in Packet Memory Area (PMA) and therefore its address access is forced to either -// 16-bit or 32-bit depending on FSDEV_BUS_32BIT. +// 16-bit or 32-bit depending on CFG_TUSB_FSDEV_32BIT. // 0: TX (IN), 1: RX (OUT) typedef union { // data is strictly 16-bit access (address could be 32-bit aligned) struct { - volatile pma_access_scheme uint16_t addr; - volatile pma_access_scheme uint16_t count; + volatile fsdev_addr_data_align uint16_t addr; + volatile fsdev_addr_data_align uint16_t count; } ep16[FSDEV_EP_COUNT][2]; // strictly 32-bit access @@ -294,45 +283,35 @@ 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(sizeof(fsdev_btable_t) == FSDEV_EP_COUNT * 8 * FSDEV_ADDR_DATA_RATIO, "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_ADDR_DATA_RATIO * FSDEV_BTABLE_BASE)) typedef struct { - volatile pma_access_scheme fsdev_bus_t value; + volatile fsdev_addr_data_align 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_ADDR_DATA_RATIO * (_addr))) //--------------------------------------------------------------------+ -// Registers Typedef +// Vendor-specific includes //--------------------------------------------------------------------+ +#if defined(TUP_USBIP_FSDEV_STM32) + #include "fsdev_stm32.h" +#elif defined(TUP_USBIP_FSDEV_CH32) + #include "fsdev_ch32.h" +#elif defined(TUP_USBIP_FSDEV_AT32) + #include "fsdev_at32.h" +#else + #error "Unknown USB IP" +#endif -// volatile 32-bit aligned -#define _va32 volatile TU_ATTR_ALIGNED(4) - -typedef struct { - struct { - _va32 fsdev_bus_t reg; - } 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 - _va32 fsdev_bus_t LPMCSR; // 54: LPM Control and Status (not on F1, F3, AT32, CH32) - _va32 fsdev_bus_t BCDR; // 58: Battery Charging Detector (not on F1, F3, AT32, CH32) -} 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) - - +//--------------------------------------------------------------------+ +// Endpoint Helper +// - CTR is write 0 to clear +// - DTOG and STAT are write 1 to toggle +//--------------------------------------------------------------------+ typedef enum { EP_STAT_DISABLED = 0, EP_STAT_STALL = 1, @@ -346,12 +325,6 @@ typedef enum { #define CH_STAT_MASK(_dir) (3u << (U_EPTX_STAT_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) #define CH_DTOG_MASK(_dir) (1u << (U_EP_DTOG_TX_Pos + ((_dir) == TUSB_DIR_IN ? 8 : 0))) -//--------------------------------------------------------------------+ -// Endpoint Helper -// - CTR is write 0 to clear -// - DTOG and STAT are write 1 to toggle -//--------------------------------------------------------------------+ - TU_ATTR_ALWAYS_INLINE static inline uint32_t ep_read(uint32_t ep_id) { return FSDEV_REG->ep[ep_id].reg; } @@ -422,7 +395,7 @@ TU_ATTR_ALWAYS_INLINE static inline void ch_change_dtog(uint32_t *reg, tusb_dir_ //--------------------------------------------------------------------+ TU_ATTR_ALWAYS_INLINE static inline uint32_t btable_get_addr(uint32_t ep_id, uint8_t buf_id) { -#ifdef FSDEV_BUS_32BIT +#ifdef CFG_TUSB_FSDEV_32BIT return FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr & 0x0000FFFFu; #else return FSDEV_BTABLE->ep16[ep_id][buf_id].addr; @@ -430,9 +403,10 @@ 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); +#ifdef CFG_TUSB_FSDEV_32BIT + 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; @@ -441,7 +415,7 @@ TU_ATTR_ALWAYS_INLINE static inline void btable_set_addr(uint32_t ep_id, uint8_t TU_ATTR_ALWAYS_INLINE static inline uint16_t btable_get_count(uint32_t ep_id, uint8_t buf_id) { uint16_t count; -#ifdef FSDEV_BUS_32BIT +#ifdef CFG_TUSB_FSDEV_32BIT count = (FSDEV_BTABLE->ep32[ep_id][buf_id].count_addr >> 16); #else count = FSDEV_BTABLE->ep16[ep_id][buf_id].count; @@ -450,13 +424,15 @@ 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); +#ifdef CFG_TUSB_FSDEV_32BIT + 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 } diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h index a1c5c9488..3bb137734 100644 --- a/src/portable/st/stm32_fsdev/fsdev_stm32.h +++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h @@ -101,12 +101,10 @@ #elif CFG_TUSB_MCU == OPT_MCU_STM32U0 #include "stm32u0xx.h" - #define FSDEV_BUS_32BIT #define FSDEV_HAS_SBUF_ISO 1 #elif CFG_TUSB_MCU == OPT_MCU_STM32U3 #include "stm32u3xx.h" - #define FSDEV_BUS_32BIT #define FSDEV_HAS_SBUF_ISO 1 // This is assumed to work but has not been tested... #elif CFG_TUSB_MCU == OPT_MCU_STM32U5 @@ -123,16 +121,6 @@ #error You are using an untested or unimplemented STM32 variant. Please update the driver. #endif -//--------------------------------------------------------------------+ -// USB DRD compatibility aliases -// These MCUs use a newer USB_DRD peripheral that needs the USB macro -// mapped to USB_DRD_FS for connect/disconnect register access. -//--------------------------------------------------------------------+ -#if TU_CHECK_MCU(OPT_MCU_STM32C0, OPT_MCU_STM32G0, OPT_MCU_STM32H5, \ - OPT_MCU_STM32U0, OPT_MCU_STM32U3, OPT_MCU_STM32U5) - #define USB USB_DRD_FS -#endif - //--------------------------------------------------------------------+ // Register and PMA Base Address //--------------------------------------------------------------------+ @@ -292,12 +280,12 @@ TU_ATTR_ALWAYS_INLINE static inline void fsdev_int_disable(uint8_t rhport) { TU_ATTR_ALWAYS_INLINE static inline void fsdev_disconnect(uint8_t rhport) { (void)rhport; - USB->BCDR &= ~U_BCDR_DPPU; + FSDEV_REG->BCDR &= ~U_BCDR_DPPU; } TU_ATTR_ALWAYS_INLINE static inline void fsdev_connect(uint8_t rhport) { (void)rhport; - USB->BCDR |= U_BCDR_DPPU; + FSDEV_REG->BCDR |= U_BCDR_DPPU; } #elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151 diff --git a/src/tusb_option.h b/src/tusb_option.h index 3814a4d71..9eb8ee533 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -340,12 +340,16 @@ #define CFG_TUD_EDPT_DEDICATED_HWFIFO 1 #if CFG_TUSB_FSDEV_PMA_SIZE == 2048 || TU_CHECK_MCU(OPT_MCU_STM32U0) + // 32-bit access scheme #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32-bit data #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase + #define CFG_TUSB_FSDEV_32BIT #elif CFG_TUSB_FSDEV_PMA_SIZE == 1024 + // 2 x 16-bit access scheme #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 + // 1 x 16-bit access scheme #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 2 // 16-bit data #define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 4 // 32-bit address increase #endif diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 8de8c7f32..e8449ba74 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -182,7 +182,8 @@ "name": "jlink", "uid": "779541626", "args": "-device stm32f072rb" - } + }, + "comment": "2x16 access scheme with 1KB USB SRAM" }, { "name": "stm32f723disco", @@ -226,7 +227,8 @@ "name": "openocd", "uid": "066FFF495087534867063844", "args": "-f interface/stlink.cfg -f target/stm32g0x.cfg" - } + }, + "comment": "32-bit scheme, 2KB USB SRAM" } ], "boards-skip": [ -- cgit v1.3.1 From a3b2b4217630eea3f514ee042ee399e9ee397b8a Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2026 14:58:45 +0700 Subject: add hil host cdc test --- AGENTS.md | 1 - hw/bsp/stm32h7/boards/stm32h743eval/board.h | 20 ++++++-- hw/bsp/stm32h7/family.c | 20 +++++++- test/hil/hil_test.py | 75 +++++++++++++++++++++++++++++ test/hil/tinyusb.json | 16 +++--- 5 files changed, 117 insertions(+), 15 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/AGENTS.md b/AGENTS.md index 4e510b01e..d491f94f1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -27,7 +27,6 @@ information that does not match the info here. ## Build Examples Choose ONE of these approaches: - **Option 1: Individual Example with CMake and Ninja (RECOMMENDED)** ```bash diff --git a/hw/bsp/stm32h7/boards/stm32h743eval/board.h b/hw/bsp/stm32h7/boards/stm32h743eval/board.h index d2f61a5ce..3914d7aac 100644 --- a/hw/bsp/stm32h7/boards/stm32h743eval/board.h +++ b/hw/bsp/stm32h7/boards/stm32h743eval/board.h @@ -205,13 +205,25 @@ static int32_t board_i2c_deinit(void) { } static int32_t i2c_readreg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { - TU_ASSERT (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)); - return 0; + for (int retry = 0; retry < 3; retry++) { + if (HAL_OK == HAL_I2C_Mem_Read(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)) { + return 0; + } + HAL_Delay(10); + } + TU_ASSERT(0); + return -1; } static int32_t i2c_writereg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length) { - TU_ASSERT(HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)); - return 0; + for (int retry = 0; retry < 3; retry++) { + if (HAL_OK == HAL_I2C_Mem_Write(&i2c_handle, DevAddr, Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 10000)) { + return 0; + } + HAL_Delay(10); + } + TU_ASSERT(0); + return -1; } static int32_t i2c_get_tick(void) { diff --git a/hw/bsp/stm32h7/family.c b/hw/bsp/stm32h7/family.c index c94c2e755..a95674217 100644 --- a/hw/bsp/stm32h7/family.c +++ b/hw/bsp/stm32h7/family.c @@ -275,9 +275,25 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { } int board_uart_read(uint8_t *buf, int len) { - (void) buf; - (void) len; +#ifdef UART_DEV + int count = 0; + // clear overrun error if any + if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_ORE)) { + __HAL_UART_CLEAR_FLAG(&UartHandle, UART_CLEAR_OREF); + } + for (int i = 0; i < len; i++) { + if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_RXNE)) { + buf[i] = (uint8_t) UartHandle.Instance->RDR; + count++; + } else { + break; + } + } + return count; +#else + (void) buf; (void) len; return 0; +#endif } int board_uart_write(void const *buf, int len) { diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 7cffd2da8..65585d929 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -416,6 +416,80 @@ def test_host_device_info(board): return 0 +def test_host_cdc_msc_hid(board): + flasher = board['flasher'] + cdc_devs = [d for d in board['tests'].get('dev_attached', []) if d.get('is_cdc')] + if not cdc_devs: + return + + port = get_serial_dev(flasher["uid"], None, None, 0) + ser = open_serial_dev(port) + ser.timeout = 0.1 + + # reset device to catch mount messages + ret = globals()[f'reset_{flasher["name"].lower()}'](board) + assert ret.returncode == 0, 'Failed to reset device' + + # Wait for CDC mounted message + data = b'' + timeout = ENUM_TIMEOUT + while timeout > 0: + new_data = ser.read(ser.in_waiting or 1) + if new_data: + data += new_data + if b'CDC Interface is mounted' in data: + break + time.sleep(0.1) + timeout -= 0.1 + assert b'CDC Interface is mounted' in data, 'CDC device not mounted on host' + + # Lookup serial chip name from vid_pid + vid_pid_name = { + '0403_6001': 'FTDI', '0403_6010': 'FTDI', '0403_6011': 'FTDI', '0403_6014': 'FTDI', + '10c4_ea60': 'CP210x', '10c4_ea70': 'CP210x', + '067b_2303': 'PL2303', '067b_23a3': 'PL2303', + '1a86_7523': 'CH340', '1a86_7522': 'CH340', + '1a86_55d3': 'CH9102', '1a86_55d4': 'CH9102', + } + dev = cdc_devs[0] + chip_name = vid_pid_name.get(dev['vid_pid'], dev['vid_pid']) + for l in data.decode('utf-8', errors='ignore').splitlines(): + if 'CDC Interface is mounted' in l: + print(f'\r\n {chip_name}: {l} ', end='') + + # CDC echo test via flasher serial + time.sleep(2) + ser.reset_input_buffer() + + def rand_ascii(length): + return "".join(random.choices(string.ascii_letters + string.digits, k=length)).encode("ascii") + + sizes = [8, 32, 64, 128] + for size in sizes: + test_data = rand_ascii(size) + ser.reset_input_buffer() + + # Write byte-by-byte with delay to avoid UART overrun + for b in test_data: + ser.write(bytes([b])) + ser.flush() + time.sleep(0.001) + + # Read echo back with timeout + echo = b'' + t = 5.0 + while t > 0 and len(echo) < size: + rd = ser.read(max(1, ser.in_waiting)) + if rd: + echo += rd + time.sleep(0.05) + t -= 0.05 + assert echo == test_data, (f'CDC echo wrong data ({size} bytes):\n' + f' expected: {test_data}\n received: {echo}') + + ser.close() + + # ------------------------------------------------------------- # Tests: device # ------------------------------------------------------------- @@ -763,6 +837,7 @@ dual_tests = [ ] host_test = [ + 'host/cdc_msc_hid', 'host/device_info', ] diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index e8449ba74..eaf60c6ce 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -8,7 +8,7 @@ }, "tests": { "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427", "is_cdc": true}] }, "flasher": { "name": "esptool", @@ -26,7 +26,7 @@ }, "tests": { "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402", "is_cdc": true}] }, "flasher": { "name": "esptool", @@ -67,7 +67,7 @@ }, "tests": { "device": true, "host": false, "dual": true, - "dev_attached": [{"vid_pid": "067b_2303", "serial": "0"}], + "dev_attached": [{"vid_pid": "067b_2303", "serial": "0", "is_cdc": true}], "comment": "pl23x" }, "flasher": { @@ -93,7 +93,7 @@ "uid": "BAE96FB95AFA6DBB8F00005002001200", "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "10c4_ea60", "serial": "0001"}], + "dev_attached": [{"vid_pid": "10c4_ea60", "serial": "0001", "is_cdc": true}], "comment": "cp2102" }, "flasher": { @@ -136,7 +136,7 @@ }, "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_7523", "serial": "0"}], + "dev_attached": [{"vid_pid": "1a86_7523", "serial": "0", "is_cdc": true}], "comment": "ch34x" }, "flasher": { @@ -150,7 +150,7 @@ "uid": "E6614C311B764A37", "tests": { "device": false, "host": true, "dual": false, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934", "is_cdc": true}] }, "flasher": { "name": "openocd", @@ -167,7 +167,7 @@ }, "tests": { "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242", "is_cdc": true}] }, "flasher": { "name": "openocd", @@ -193,7 +193,7 @@ }, "tests": { "device": true, "host": true, "dual": false, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2003414"}] + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2003414", "is_cdc": true}] }, "flasher": { "name": "jlink", -- cgit v1.3.1 From 45e80a1042ea802b74ebe97db350f9da17cb2fe4 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2026 21:38:46 +0700 Subject: add hil test for host msc and cdc --- AGENTS.md | 7 + LICENSE | 2 +- examples/host/msc_file_explorer/src/msc_app.c | 11 +- .../adafruit_feather_rp2040_usb_host/board.cmake | 1 + .../rp2040/boards/adafruit_fruit_jam/board.cmake | 2 + .../boards/adafruit_metro_rp2350/board.cmake | 2 + hw/bsp/rp2040/family.cmake | 6 + test/hil/hil_test.py | 169 ++++++++++++++++++--- test/hil/tinyusb.json | 19 +++ 9 files changed, 195 insertions(+), 24 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/AGENTS.md b/AGENTS.md index d491f94f1..eb6b737c3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -151,6 +151,13 @@ openocd -f interface/stlink.cfg -f target/stm32h7x.cfg openocd -f interface/jlink.cfg -f target/stm32h7x.cfg ``` +For **rp2040/rp2350** with a CMSIS-DAP probe (e.g. Picoprobe, debugprobe): +```bash +openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000" +# or for rp2350: +openocd -f interface/cmsis-dap.cfg -f target/rp2350.cfg -c "adapter speed 5000" +``` + For boards that define `OPENOCD_OPTION` in `board.cmake`, use those options directly: ```bash openocd $(cat hw/bsp/FAMILY/boards/BOARD/board.cmake | grep OPENOCD_OPTION | ...) diff --git a/LICENSE b/LICENSE index ddd4ab410..0680c2f05 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2018, hathach (tinyusb.org) +Copyright (c) 2012-2026, hathach (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 diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 6ac63e937..238af5431 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -130,11 +130,16 @@ static bool inquiry_complete_cb(uint8_t dev_addr, const tuh_msc_complete_data_t drive_path[0] += drive_num; if (f_mount(&fatfs[drive_num], drive_path, 1) != FR_OK) { - puts("mount failed"); + printf("mount failed\r\n"); + return true; } // change to newly mounted drive - f_chdir(drive_path); + f_chdrive(drive_path); + FRESULT rc = f_chdir("/"); + if (rc != FR_OK) { + printf("chdir failed: %d\r\n", rc); + } // print the drive label // char label[34]; @@ -148,7 +153,7 @@ static bool inquiry_complete_cb(uint8_t dev_addr, const tuh_msc_complete_data_t //------------- IMPLEMENTATION -------------// void tuh_msc_mount_cb(uint8_t dev_addr) { - printf("A MassStorage device is mounted\r\n"); + printf("A MassStorage device (addr = %u) is mounted\r\n", dev_addr); const uint8_t lun = 0; tuh_msc_inquiry(dev_addr, lun, &scsi_resp.inquiry, inquiry_complete_cb, 0); diff --git a/hw/bsp/rp2040/boards/adafruit_feather_rp2040_usb_host/board.cmake b/hw/bsp/rp2040/boards/adafruit_feather_rp2040_usb_host/board.cmake index 41897f644..66758d7d0 100644 --- a/hw/bsp/rp2040/boards/adafruit_feather_rp2040_usb_host/board.cmake +++ b/hw/bsp/rp2040/boards/adafruit_feather_rp2040_usb_host/board.cmake @@ -1,2 +1,3 @@ set(PICO_PLATFORM rp2040) set(PICO_BOARD adafruit_feather_rp2040_usb_host) +set(CFG_TUH_RPI_PIO_USB 1) diff --git a/hw/bsp/rp2040/boards/adafruit_fruit_jam/board.cmake b/hw/bsp/rp2040/boards/adafruit_fruit_jam/board.cmake index 4ab8a5477..d3535fa36 100644 --- a/hw/bsp/rp2040/boards/adafruit_fruit_jam/board.cmake +++ b/hw/bsp/rp2040/boards/adafruit_fruit_jam/board.cmake @@ -2,3 +2,5 @@ set(PICO_PLATFORM rp2350-arm-s) set(PICO_BOARD adafruit_fruit_jam) set(PICO_BOARD_HEADER_DIRS ${CMAKE_CURRENT_LIST_DIR}) #set(OPENOCD_SERIAL E6614103E78E8324) + +set(CFG_TUH_RPI_PIO_USB 1) diff --git a/hw/bsp/rp2040/boards/adafruit_metro_rp2350/board.cmake b/hw/bsp/rp2040/boards/adafruit_metro_rp2350/board.cmake index 9a58821a5..f1f54d217 100644 --- a/hw/bsp/rp2040/boards/adafruit_metro_rp2350/board.cmake +++ b/hw/bsp/rp2040/boards/adafruit_metro_rp2350/board.cmake @@ -2,3 +2,5 @@ set(PICO_PLATFORM rp2350-arm-s) set(PICO_BOARD adafruit_metro_rp2350) set(PICO_BOARD_HEADER_DIRS ${CMAKE_CURRENT_LIST_DIR}) #set(OPENOCD_SERIAL E6614103E78E8324) + +set(CFG_TUH_RPI_PIO_USB 1) diff --git a/hw/bsp/rp2040/family.cmake b/hw/bsp/rp2040/family.cmake index e31abe50b..2e2cd436a 100644 --- a/hw/bsp/rp2040/family.cmake +++ b/hw/bsp/rp2040/family.cmake @@ -72,6 +72,12 @@ target_compile_definitions(tinyusb_common_base INTERFACE CFG_TUSB_DEBUG=${TINYUSB_DEBUG_LEVEL} ) +if (CFG_TUH_RPI_PIO_USB) + target_compile_definitions(tinyusb_common_base INTERFACE + CFG_TUH_RPI_PIO_USB=1 + ) +endif() + target_link_libraries(tinyusb_common_base INTERFACE hardware_structs hardware_irq diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 65585d929..a2c054e61 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -80,6 +80,11 @@ flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 echo "Ready for Remote Connections" """ +MSC_README_TXT = \ +b"This is tinyusb's MassStorage Class demo.\r\n\r\n\ +If you find any bugs or get any questions, feel free to file an\r\n\ +issue at github.com/hathach/tinyusb" + # ------------------------------------------------------------- # Path # ------------------------------------------------------------- @@ -360,10 +365,27 @@ def test_dual_host_info_to_device_cdc(board): declared_devs = [f'{d["vid_pid"]}_{d["serial"]}' for d in board['tests']['dev_attached']] port = get_serial_dev(uid, 'TinyUSB', "TinyUSB_Device", 0) ser = open_serial_dev(port) + ser.timeout = 0.1 - # read from cdc, first line should contain vid/pid and serial - data = ser.read(10000) + # read until all expected devices are enumerated + data = b'' + timeout = ENUM_TIMEOUT + while timeout > 0: + new_data = ser.read(ser.in_waiting or 1) + if new_data: + data += new_data + # check if all devices found + enum_dev_sn = [] + for l in data.decode('utf-8', errors='ignore').splitlines(): + vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l) + if vid_pid_sn: + enum_dev_sn.append(f'{vid_pid_sn.group(1)}_{vid_pid_sn.group(2)}_{vid_pid_sn.group(3)}') + if set(declared_devs).issubset(set(enum_dev_sn)): + break + time.sleep(0.1) + timeout -= 0.1 ser.close() + if len(data) == 0: assert False, 'No data from device' lines = data.decode('utf-8', errors='ignore').splitlines() @@ -391,13 +413,31 @@ def test_host_device_info(board): port = get_serial_dev(flasher["uid"], None, None, 0) ser = open_serial_dev(port) + ser.timeout = 0.1 # reset device since we can miss the first line ret = globals()[f'reset_{flasher["name"].lower()}'](board) - assert ret.returncode == 0, 'Failed to reset device' + assert ret.returncode == 0, 'Failed to reset device' - data = ser.read(10000) + # read until all expected devices are enumerated + data = b'' + timeout = ENUM_TIMEOUT + while timeout > 0: + new_data = ser.read(ser.in_waiting or 1) + if new_data: + data += new_data + # check if all devices found + enum_dev_sn = [] + for l in data.decode('utf-8', errors='ignore').splitlines(): + vid_pid_sn = re.search(r'ID ([0-9a-fA-F]+):([0-9a-fA-F]+) SN (\w+)', l) + if vid_pid_sn: + enum_dev_sn.append(f'{vid_pid_sn.group(1)}_{vid_pid_sn.group(2)}_{vid_pid_sn.group(3)}') + if set(declared_devs).issubset(set(enum_dev_sn)): + break + time.sleep(0.1) + timeout -= 0.1 ser.close() + if len(data) == 0: assert False, 'No data from device' lines = data.decode('utf-8', errors='ignore').splitlines() @@ -416,10 +456,25 @@ def test_host_device_info(board): return 0 +def print_msc_info(lines): + """Print MSC inquiry and disk size on a single line""" + inquiry = '' + disk_size = '' + for l in lines: + if re.match(r'^[A-Za-z].*\s+rev\s+', l): + inquiry = l.strip() + if 'Disk Size' in l: + disk_size = l.strip() + if inquiry or disk_size: + print(f'\r\n {inquiry} {disk_size} ', end='') + + def test_host_cdc_msc_hid(board): flasher = board['flasher'] - cdc_devs = [d for d in board['tests'].get('dev_attached', []) if d.get('is_cdc')] - if not cdc_devs: + dev_attached = board['tests'].get('dev_attached', []) + cdc_devs = [d for d in dev_attached if d.get('is_cdc')] + msc_devs = [d for d in dev_attached if d.get('is_msc')] + if not cdc_devs and not msc_devs: return port = get_serial_dev(flasher["uid"], None, None, 0) @@ -430,18 +485,21 @@ def test_host_cdc_msc_hid(board): ret = globals()[f'reset_{flasher["name"].lower()}'](board) assert ret.returncode == 0, 'Failed to reset device' - # Wait for CDC mounted message + # Wait for all expected mount messages data = b'' timeout = ENUM_TIMEOUT + wait_cdc = len(cdc_devs) > 0 + wait_msc = len(msc_devs) > 0 while timeout > 0: new_data = ser.read(ser.in_waiting or 1) if new_data: data += new_data - if b'CDC Interface is mounted' in data: + cdc_ok = (not wait_cdc) or (b'CDC Interface is mounted' in data) + msc_ok = (not wait_msc) or (b'Disk Size' in data) + if cdc_ok and msc_ok: break time.sleep(0.1) timeout -= 0.1 - assert b'CDC Interface is mounted' in data, 'CDC device not mounted on host' # Lookup serial chip name from vid_pid vid_pid_name = { @@ -451,13 +509,29 @@ def test_host_cdc_msc_hid(board): '1a86_7523': 'CH340', '1a86_7522': 'CH340', '1a86_55d3': 'CH9102', '1a86_55d4': 'CH9102', } - dev = cdc_devs[0] - chip_name = vid_pid_name.get(dev['vid_pid'], dev['vid_pid']) - for l in data.decode('utf-8', errors='ignore').splitlines(): - if 'CDC Interface is mounted' in l: - print(f'\r\n {chip_name}: {l} ', end='') + + lines = data.decode('utf-8', errors='ignore').splitlines() + + # Verify and print CDC mount + if cdc_devs: + assert b'CDC Interface is mounted' in data, 'CDC device not mounted on host' + dev = cdc_devs[0] + chip_name = vid_pid_name.get(dev['vid_pid'], dev['vid_pid']) + for l in lines: + if 'CDC Interface is mounted' in l: + print(f'\r\n {chip_name}: {l} ', end='') + + # Verify and print MSC mount (inquiry + disk size) + if msc_devs: + assert b'MassStorage device is mounted' in data, 'MSC device not mounted on host' + assert b'Disk Size' in data, 'MSC Disk Size not reported' + print_msc_info(lines) # CDC echo test via flasher serial + if not cdc_devs: + ser.close() + return + time.sleep(2) ser.reset_input_buffer() @@ -490,6 +564,65 @@ def test_host_cdc_msc_hid(board): ser.close() +def test_host_msc_file_explorer(board): + flasher = board['flasher'] + msc_devs = [d for d in board['tests'].get('dev_attached', []) if d.get('is_msc')] + if not msc_devs: + return + + port = get_serial_dev(flasher["uid"], None, None, 0) + ser = open_serial_dev(port) + ser.timeout = 0.1 + + # reset device to catch mount messages + ret = globals()[f'reset_{flasher["name"].lower()}'](board) + assert ret.returncode == 0, 'Failed to reset device' + + # Wait for MSC mount (Disk Size message) + data = b'' + timeout = ENUM_TIMEOUT + while timeout > 0: + new_data = ser.read(ser.in_waiting or 1) + if new_data: + data += new_data + if b'Disk Size' in data: + break + time.sleep(0.1) + timeout -= 0.1 + assert b'Disk Size' in data, 'MSC device not mounted' + lines = data.decode('utf-8', errors='ignore').splitlines() + print_msc_info(lines) + + # Send "cat README.TXT" and read response + time.sleep(1) + ser.reset_input_buffer() + for ch in 'cat README.TXT\r': + ser.write(ch.encode()) + ser.flush() + time.sleep(0.002) + + # Read response + resp = b'' + t = 10.0 + while t > 0: + rd = ser.read(max(1, ser.in_waiting)) + if rd: + resp += rd + # wait for prompt after command output + if b'>' in resp and resp.rstrip().endswith(b'>'): + break + time.sleep(0.05) + t -= 0.05 + + # Verify response contains README content + resp_text = resp.decode('utf-8', errors='ignore') + assert MSC_README_TXT.decode() in resp_text, (f'MSC README.TXT not found in response:\n' + f' received: {resp_text}') + print('README.TXT matched ', end='') + + ser.close() + + # ------------------------------------------------------------- # Tests: device # ------------------------------------------------------------- @@ -565,12 +698,7 @@ def test_device_cdc_msc(board): # MSC Block test data = read_disk_file(uid, 0, 'README.TXT') - readme = \ - b"This is tinyusb's MassStorage Class demo.\r\n\r\n\ -If you find any bugs or get any questions, feel free to file an\r\n\ -issue at github.com/hathach/tinyusb" - - assert data == readme, f'MSC wrong data in README.TXT\n expected: {readme.decode()}\n received: {data.decode()}' + assert data == MSC_README_TXT, f'MSC wrong data in README.TXT\n expected: {MSC_README_TXT.decode()}\n received: {data.decode()}' def test_device_cdc_msc_freertos(board): @@ -838,6 +966,7 @@ dual_tests = [ host_test = [ 'host/cdc_msc_hid', + 'host/msc_file_explorer', 'host/device_info', ] diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index eaf60c6ce..e84e9672b 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -175,6 +175,25 @@ "args": "-f interface/cmsis-dap.cfg -f target/rp2350.cfg -c \"adapter speed 5000\"" } }, + { + "name": "adafruit_fruit_jam", + "uid": "2B0DC7A45781189E", + "tests": { + "device": false, + "host": true, + "dual": true, + "dev_attached": [ + {"vid_pid": "0403_6001", "serial": "0", "is_cdc": true}, + {"vid_pid": "058f_6387", "serial": "A8BEE062633D", "is_msc": true, + "msc_disk_size": 3730, "msc_inquiry": "Generic Flash Disk rev 8.07"} + ] + }, + "flasher": { + "name": "openocd", + "uid": "E6614103E78E8324", + "args": "-f interface/cmsis-dap.cfg -f target/rp2350.cfg -c \"adapter speed 5000\"" + } + }, { "name": "stm32f072disco", "uid": "3A001A001357364230353532", -- cgit v1.3.1 From 55994bc1d5ac80ced3f7a8383e7537967a572ed2 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 17 Mar 2026 22:25:23 +0700 Subject: add hil tests for device msc_dual_lun and midi functionality --- test/hil/hil_test.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ test/hil/tinyusb.json | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index a2c054e61..2100fb7fc 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -944,6 +944,76 @@ def test_device_mtp(board): mtp.disconnect() +def test_device_msc_dual_lun(board): + uid = board['uid'] + + # Read README from LUN 0 + data0 = read_disk_file(uid, 0, 'README0.TXT') + readme0 = b"LUN0: " + MSC_README_TXT + assert data0 == readme0, f'MSC LUN0 wrong data in README0.TXT\n expected: {readme0}\n received: {data0}' + + # Read README from LUN 1 + data1 = read_disk_file(uid, 1, 'README1.TXT') + readme1 = b"LUN1: " + MSC_README_TXT + assert data1 == readme1, f'MSC LUN1 wrong data in README1.TXT\n expected: {readme1}\n received: {data1}' + + +def test_device_midi_test(board): + uid = board['uid'] + + # Find MIDI device via /dev/snd/by-id using board UID + timeout = ENUM_TIMEOUT + midi_port = None + while timeout > 0: + pattern = f'/dev/snd/by-id/usb-*_{uid}-*' + devs = glob.glob(pattern) + if devs: + # by-id entry points to controlCX, derive card number for midiCXD0 + link = os.path.basename(os.readlink(devs[0])) # e.g. "controlC2" + card_num = link.replace('controlC', '') + midi_path = f'/dev/snd/midiC{card_num}D0' + if os.path.exists(midi_path): + midi_port = midi_path + break + time.sleep(1) + timeout -= 1 + assert midi_port is not None, f'MIDI device not found for {uid}' + + # Read MIDI messages and verify note on/off + import select + with open(midi_port, 'rb') as f: + notes = [] + # Read for up to 3 seconds to capture a few notes (286ms interval) + end_time = time.time() + 3 + while time.time() < end_time: + ready, _, _ = select.select([f], [], [], 0.5) + if ready: + data = f.read(64) + if data: + # Parse MIDI bytes: note_on = 0x90, note_off = 0x80 + i = 0 + while i + 2 < len(data): + status = data[i] + if (status & 0xF0) == 0x90: # Note On + notes.append(data[i + 1]) + i += 3 + elif (status & 0xF0) == 0x80: # Note Off + i += 3 + else: + i += 1 + + assert len(notes) >= 2, f'Expected at least 2 MIDI notes, got {len(notes)}' + # Verify notes are from the expected sequence + note_sequence = [ + 74, 78, 81, 86, 90, 93, 98, 102, 57, 61, 66, 69, 73, 78, 81, 85, + 88, 92, 97, 100, 97, 92, 88, 85, 81, 78, 74, 69, 66, 62, 57, 62, + 66, 69, 74, 78, 81, 86, 90, 93, 97, 102, 97, 93, 90, 85, 81, 78, + 73, 68, 64, 61, 56, 61, 64, 68, 74, 78, 81, 86, 90, 93, 98, 102 + ] + for n in notes: + assert n in note_sequence, f'Unexpected MIDI note {n}' + + # ------------------------------------------------------------- # Main # ------------------------------------------------------------- @@ -956,7 +1026,9 @@ device_tests = [ 'device/dfu_runtime', 'device/cdc_msc_freertos', 'device/hid_boot_interface', + 'device/msc_dual_lun', 'device/printer_to_cdc', + 'device/midi_test', 'device/mtp' ] diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index e84e9672b..5a42d852e 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -179,7 +179,7 @@ "name": "adafruit_fruit_jam", "uid": "2B0DC7A45781189E", "tests": { - "device": false, + "device": true, "host": true, "dual": true, "dev_attached": [ -- cgit v1.3.1 From 0521e6698eb0719c27ef7c2473c9152be30ae172 Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Wed, 18 Mar 2026 14:56:25 +0700 Subject: hil pico2 test with native host --- test/hil/tinyusb.json | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 5a42d852e..b4c6aaefe 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -162,12 +162,9 @@ { "name": "raspberry_pi_pico2", "uid": "560AE75E1C7152C9", - "build" : { - "flags_on": ["CFG_TUH_RPI_PIO_USB"] - }, "tests": { - "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "533D004242", "is_cdc": true}] + "device": false, "host": true, "dual": false, + "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002694", "is_cdc": true}] }, "flasher": { "name": "openocd", -- cgit v1.3.1 From 3c2627e7390dc9145329732900f0c0de6e886cc0 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 23 Mar 2026 15:43:47 +0700 Subject: update host msc hil test --- examples/host/cdc_msc_hid/src/msc_app.c | 4 ++-- examples/host/cdc_msc_hid_freertos/src/msc_app.c | 6 ++--- examples/host/msc_file_explorer/src/msc_app.c | 6 ++--- test/hil/hil_test.py | 30 +++++++++++++++++------- test/hil/tinyusb.json | 2 +- 5 files changed, 31 insertions(+), 17 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c index dd4e22d7f..4a85e46d7 100644 --- a/examples/host/cdc_msc_hid/src/msc_app.c +++ b/examples/host/cdc_msc_hid/src/msc_app.c @@ -47,8 +47,8 @@ static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun); uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun); - printf("Disk Size: %" PRIu32 " MB\r\n", block_count / ((1024*1024)/block_size)); - printf("Block Count = %" PRIu32 ", Block Size: %" PRIu32 "\r\n", block_count, block_size); + printf("Disk Size: %" PRIu32 " %" PRIu32 "-byte blocks: %" PRIu32 " MB\r\n", + block_count, block_size, block_count / ((1024 * 1024) / block_size)); return true; } diff --git a/examples/host/cdc_msc_hid_freertos/src/msc_app.c b/examples/host/cdc_msc_hid_freertos/src/msc_app.c index fa864c364..17df11951 100644 --- a/examples/host/cdc_msc_hid_freertos/src/msc_app.c +++ b/examples/host/cdc_msc_hid_freertos/src/msc_app.c @@ -47,14 +47,14 @@ static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const } // Print out Vendor ID, Product ID and Rev - printf("%.8s %.16s rev %.4s\r\n", scsi_resp.inquiry.vendor_id, scsi_resp.inquiry.product_id, scsi_resp.inquiry.product_rev); + printf("%.8s %.16s %.4s\r\n", scsi_resp.inquiry.vendor_id, scsi_resp.inquiry.product_id, scsi_resp.inquiry.product_rev); // Get capacity of device uint32_t const block_count = tuh_msc_get_block_count(dev_addr, cbw->lun); uint32_t const block_size = tuh_msc_get_block_size(dev_addr, cbw->lun); - printf("Disk Size: %" PRIu32 " MB\r\n", block_count / ((1024 * 1024) / block_size)); - printf("Block Count = %" PRIu32 ", Block Size: %" PRIu32 "\r\n", block_count, block_size); + printf("Disk Size: %" PRIu32 " %" PRIu32 "-byte blocks: %" PRIu32 " MB\r\n", + block_count, block_size, block_count / ((1024 * 1024) / block_size)); return true; } diff --git a/examples/host/msc_file_explorer/src/msc_app.c b/examples/host/msc_file_explorer/src/msc_app.c index 21ff42726..c7cc366b5 100644 --- a/examples/host/msc_file_explorer/src/msc_app.c +++ b/examples/host/msc_file_explorer/src/msc_app.c @@ -118,15 +118,15 @@ static bool inquiry_complete_cb(uint8_t dev_addr, const tuh_msc_complete_data_t } // Print out Vendor ID, Product ID and Rev - printf("%.8s %.16s rev %.4s\r\n", scsi_resp.inquiry.vendor_id, scsi_resp.inquiry.product_id, + printf("%.8s %.16s %.4s\r\n", scsi_resp.inquiry.vendor_id, scsi_resp.inquiry.product_id, scsi_resp.inquiry.product_rev); // Get capacity of device const uint32_t block_count = tuh_msc_get_block_count(dev_addr, cbw->lun); const uint32_t block_size = tuh_msc_get_block_size(dev_addr, cbw->lun); - printf("Disk Size: %" PRIu32 " MB\r\n", block_count / ((1024 * 1024) / block_size)); - // printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); + printf("Disk Size: %" PRIu32 " %" PRIu32 "-byte blocks: %" PRIu32 " MB\r\n", + block_count, block_size, block_count / ((1024 * 1024) / block_size)); // For simplicity: we only mount 1 LUN per device const uint8_t drive_num = dev_addr - 1; diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index f8b43430d..4b17bed54 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -456,17 +456,30 @@ def test_host_device_info(board): return 0 -def print_msc_info(lines): - """Print MSC inquiry and disk size on a single line""" +def check_msc_info(lines, msc_devs): + """Print MSC info and verify block_count/block_size against config""" inquiry = '' disk_size = '' for l in lines: - if re.match(r'^[A-Za-z].*\s+rev\s+', l): + if re.match(r'^[A-Za-z].*\s+(rev\s+|[0-9])', l) and 'Disk Size' not in l: inquiry = l.strip() if 'Disk Size' in l: disk_size = l.strip() if inquiry or disk_size: print(f'\r\n {inquiry} {disk_size} ', end='') + # Verify block_count and block_size from "Disk Size: COUNT SIZE-byte blocks: N MB" + if disk_size and msc_devs: + m = re.match(r'Disk Size:\s+(\d+)\s+(\d+)-byte blocks', disk_size) + if m: + actual_count = int(m.group(1)) + actual_size = int(m.group(2)) + for dev in msc_devs: + exp_count = dev.get('block_count') + exp_size = dev.get('block_size') + if exp_count and actual_count == exp_count: + assert actual_size == exp_size, ( + f'MSC block_size mismatch: expected {exp_size}, got {actual_size}') + break def test_host_cdc_msc_hid(board): @@ -525,7 +538,7 @@ def test_host_cdc_msc_hid(board): if msc_devs: assert b'MassStorage device is mounted' in data, 'MSC device not mounted on host' assert b'Disk Size' in data, 'MSC Disk Size not reported' - print_msc_info(lines) + check_msc_info(lines, msc_devs) # CDC echo test via flasher serial if not cdc_devs: @@ -533,6 +546,7 @@ def test_host_cdc_msc_hid(board): return time.sleep(2) + ser.read(ser.in_waiting) ser.reset_input_buffer() def rand_ascii(length): @@ -540,7 +554,7 @@ def test_host_cdc_msc_hid(board): packet_size = 64 - # Echo test: 1KB random data, write random 1-packet_size chunks, only write next once echo matched + # Echo test: write random 1-packet_size chunks, wait for echo before sending next echo_len = 1024 echo_data = rand_ascii(echo_len) ser.reset_input_buffer() @@ -551,8 +565,8 @@ def test_host_cdc_msc_hid(board): ser.flush() # wait until this chunk is echoed back echo = b'' - t = 5.0 - while t > 0 and len(echo) < chunk_size: + t_end = time.monotonic() + 5.0 + while time.monotonic() < t_end and len(echo) < chunk_size: rd = ser.read(chunk_size - len(echo)) if rd: echo += rd @@ -591,7 +605,7 @@ def test_host_msc_file_explorer(board): timeout -= 0.1 assert b'Disk Size' in data, 'MSC device not mounted' lines = data.decode('utf-8', errors='ignore').splitlines() - print_msc_info(lines) + check_msc_info(lines, msc_devs) # Send "cat README.TXT" and read response time.sleep(1) diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index b4c6aaefe..37e98a52f 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -182,7 +182,7 @@ "dev_attached": [ {"vid_pid": "0403_6001", "serial": "0", "is_cdc": true}, {"vid_pid": "058f_6387", "serial": "A8BEE062633D", "is_msc": true, - "msc_disk_size": 3730, "msc_inquiry": "Generic Flash Disk rev 8.07"} + "block_size": 512, "block_count": 7639040, "msc_inquiry": "Generic Flash Disk 8.07"} ] }, "flasher": { -- cgit v1.3.1 From d2050487b7a248636792743dac36c238d1e3f2af Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 1 Apr 2026 22:25:27 +0700 Subject: fix hil uid typo --- test/hil/tinyusb.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 37e98a52f..1ac953939 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -147,7 +147,7 @@ }, { "name": "raspberry_pi_pico_w", - "uid": "E6614C311B764A37", + "uid": "E6614864D35DAE36", "tests": { "device": false, "host": true, "dual": false, "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934", "is_cdc": true}] -- cgit v1.3.1 From b6f04f8643e5ca1efe2b8f9754427f5e5a0303e7 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 2 Apr 2026 10:42:00 +0700 Subject: add msc device to hil rp2040 host pool --- test/hil/tinyusb.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 1ac953939..86ac902ce 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -150,7 +150,21 @@ "uid": "E6614864D35DAE36", "tests": { "device": false, "host": true, "dual": false, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2023934", "is_cdc": true}] + "dev_attached": [ + { + "vid_pid": "1a86_55d4", + "serial": "52D2023934", + "is_cdc": true + }, + { + "vid_pid": "2008_2018", + "serial": "O20070925A002746", + "is_msc": true, + "block_size": 512, + "block_count": 4124152, + "msc_inquiry": "USB2.0 Flash Disk 2.10" + } + ] }, "flasher": { "name": "openocd", -- cgit v1.3.1 From 3c6c87479be6a9fdd04240b8bb1267ef80b1a0e8 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 4 Apr 2026 13:20:58 +0700 Subject: implement board_uart_read()/write() as non-blocking for all families --- hw/bsp/at32f402_405/family.c | 24 ++++++-------- hw/bsp/at32f403a_407/family.c | 21 ++++++------ hw/bsp/at32f413/family.c | 21 ++++++------ hw/bsp/at32f415/family.c | 21 ++++++------ hw/bsp/at32f423/family.c | 21 ++++++------ hw/bsp/at32f425/family.c | 21 ++++++------ hw/bsp/at32f435_437/family.c | 21 ++++++------ hw/bsp/at32f45x/family.c | 21 ++++++------ hw/bsp/broadcom_32bit/family.c | 16 ++++----- hw/bsp/broadcom_64bit/family.c | 16 ++++----- hw/bsp/ch32f20x/family.c | 8 ++--- hw/bsp/ch32v10x/family.c | 16 +++++---- hw/bsp/ch32v20x/family.c | 17 ++++++---- hw/bsp/ch32v30x/family.c | 8 ++--- hw/bsp/f1c100s/family.c | 18 +++++++--- hw/bsp/fomu/family.c | 12 ++++--- hw/bsp/ft9xx/family.c | 21 +++++++----- hw/bsp/gd32vf103/family.c | 15 ++++++--- hw/bsp/kinetis_k/family.c | 18 +++++++--- hw/bsp/kinetis_k32l/family.c | 38 ++++++++++++---------- hw/bsp/kinetis_kl/family.c | 25 +++++++++++--- hw/bsp/lpc15/family.c | 12 ++++++- hw/bsp/lpc18/family.c | 14 +++++--- hw/bsp/lpc43/family.c | 14 +++++--- hw/bsp/lpc54/family.c | 17 +++++++++- hw/bsp/lpc55/family.c | 19 +++++++++-- hw/bsp/maxim/family.c | 16 +++++---- hw/bsp/mcx/family.c | 13 ++++++-- hw/bsp/mm32/family.c | 17 ++++++---- hw/bsp/msp430/family.c | 18 +++++----- hw/bsp/msp432e4/family.c | 13 +++++--- hw/bsp/rw61x/family.c | 13 ++++++-- .../samd5x_e5x/boards/metro_m4_express/board.cmake | 2 ++ hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk | 2 ++ hw/bsp/samg/family.c | 13 +++++--- hw/bsp/stm32l0/family.c | 13 ++++++-- hw/bsp/tm4c/family.c | 15 +++++---- hw/bsp/xmc4000/family.c | 22 ++++++++++--- test/hil/tinyusb.json | 7 ++-- 39 files changed, 397 insertions(+), 242 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/hw/bsp/at32f402_405/family.c b/hw/bsp/at32f402_405/family.c index b7dbcbd98..56d4a7bea 100644 --- a/hw/bsp/at32f402_405/family.c +++ b/hw/bsp/at32f402_405/family.c @@ -205,22 +205,18 @@ int board_uart_read(uint8_t *buf, int len) { int board_uart_write(void const *buf, int len) { #if CFG_TUSB_OS == OPT_OS_NONE - int txsize = len; - u16 timeout = 0xffff; - while (txsize--) - { - while(usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) - { - timeout--; - if(timeout == 0) - { - return 0; - } + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) != RESET) { + PRINT_UART->dt = (*p & 0x01FF); + p++; + count++; + } else { + break; } - PRINT_UART->dt = (*((uint8_t const *)buf) & 0x01FF); - buf++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/at32f403a_407/family.c b/hw/bsp/at32f403a_407/family.c index d4a7e446d..942e15872 100644 --- a/hw/bsp/at32f403a_407/family.c +++ b/hw/bsp/at32f403a_407/family.c @@ -223,19 +223,18 @@ int board_uart_read(uint8_t *buf, int len) { int board_uart_write(void const *buf, int len) { #if CFG_TUSB_OS == OPT_OS_NONE - int txsize = len; - u16 timeout = 0xffff; - while (txsize--) { - while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) { - timeout--; - if (timeout == 0) { - return 0; - } + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) != RESET) { + PRINT_UART->dt = (*p & 0x01FF); + p++; + count++; + } else { + break; } - PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF); - buf++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/at32f413/family.c b/hw/bsp/at32f413/family.c index adf29e097..d9af0ae4d 100644 --- a/hw/bsp/at32f413/family.c +++ b/hw/bsp/at32f413/family.c @@ -223,19 +223,18 @@ int board_uart_read(uint8_t *buf, int len) { int board_uart_write(void const *buf, int len) { #if CFG_TUSB_OS == OPT_OS_NONE - int txsize = len; - u16 timeout = 0xffff; - while (txsize--) { - while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) { - timeout--; - if (timeout == 0) { - return 0; - } + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) != RESET) { + PRINT_UART->dt = (*p & 0x01FF); + p++; + count++; + } else { + break; } - PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF); - buf++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/at32f415/family.c b/hw/bsp/at32f415/family.c index b592bf6c5..ca205d480 100644 --- a/hw/bsp/at32f415/family.c +++ b/hw/bsp/at32f415/family.c @@ -197,19 +197,18 @@ int board_uart_read(uint8_t *buf, int len) { // Send characters to UART. Return number of sent bytes int board_uart_write(void const *buf, int len) { #if CFG_TUSB_OS == OPT_OS_NONE - int txsize = len; - u16 timeout = 0xffff; - while (txsize--) { - while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) { - timeout--; - if (timeout == 0) { - return 0; - } + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) != RESET) { + PRINT_UART->dt = (*p & 0x01FF); + p++; + count++; + } else { + break; } - PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF); - buf++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/at32f423/family.c b/hw/bsp/at32f423/family.c index 71cb559dc..9f13dba07 100644 --- a/hw/bsp/at32f423/family.c +++ b/hw/bsp/at32f423/family.c @@ -224,19 +224,18 @@ int board_uart_read(uint8_t *buf, int len) { int board_uart_write(void const *buf, int len) { #if CFG_TUSB_OS == OPT_OS_NONE - int txsize = len; - u16 timeout = 0xffff; - while (txsize--) { - while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) { - timeout--; - if (timeout == 0) { - return 0; - } + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) != RESET) { + PRINT_UART->dt = (*p & 0x01FF); + p++; + count++; + } else { + break; } - PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF); - buf++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/at32f425/family.c b/hw/bsp/at32f425/family.c index 7f443509e..1629ad7c0 100644 --- a/hw/bsp/at32f425/family.c +++ b/hw/bsp/at32f425/family.c @@ -205,19 +205,18 @@ int board_uart_read(uint8_t *buf, int len) { // Send characters to UART. Return number of sent bytes int board_uart_write(void const *buf, int len) { #if CFG_TUSB_OS == OPT_OS_NONE - int txsize = len; - u16 timeout = 0xffff; - while (txsize--) { - while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) { - timeout--; - if (timeout == 0) { - return 0; - } + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) != RESET) { + PRINT_UART->dt = (*p & 0x01FF); + p++; + count++; + } else { + break; } - PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF); - buf++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/at32f435_437/family.c b/hw/bsp/at32f435_437/family.c index 6c6bc4d72..59a4fe120 100644 --- a/hw/bsp/at32f435_437/family.c +++ b/hw/bsp/at32f435_437/family.c @@ -250,19 +250,18 @@ int board_uart_read(uint8_t *buf, int len) { // Send characters to UART. Return number of sent bytes int board_uart_write(void const *buf, int len) { #if CFG_TUSB_OS == OPT_OS_NONE - int txsize = len; - u16 timeout = 0xffff; - while (txsize--) { - while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET) { - timeout--; - if (timeout == 0) { - return 0; - } + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) != RESET) { + PRINT_UART->dt = (*p & 0x01FF); + p++; + count++; + } else { + break; } - PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF); - buf++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/at32f45x/family.c b/hw/bsp/at32f45x/family.c index fa0c1139f..27eae861f 100644 --- a/hw/bsp/at32f45x/family.c +++ b/hw/bsp/at32f45x/family.c @@ -201,19 +201,18 @@ int board_uart_read(uint8_t *buf, int len) { 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; - } + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) != RESET) { + PRINT_UART->dt = (*p & 0x01FF); + p++; + count++; + } else { + break; } - PRINT_UART->dt = (*((uint8_t const *) buf) & 0x01FF); - buf++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/broadcom_32bit/family.c b/hw/bsp/broadcom_32bit/family.c index 399397bb4..1c7f6c7a5 100644 --- a/hw/bsp/broadcom_32bit/family.c +++ b/hw/bsp/broadcom_32bit/family.c @@ -125,16 +125,16 @@ int board_uart_read(uint8_t* buf, int len) { } int board_uart_write(void const* buf, int len) { - for (int i = 0; i < len; i++) { - const char* cbuf = buf; - while (!UART1->STAT_b.TX_READY) {} - if (cbuf[i] == '\n') { - UART1->IO = '\r'; - while (!UART1->STAT_b.TX_READY) {} + const uint8_t* p = (const uint8_t*) buf; + int count = 0; + while (count < len) { + if (!UART1->STAT_b.TX_READY) { + break; } - UART1->IO = cbuf[i]; + UART1->IO = p[count]; + count++; } - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/broadcom_64bit/family.c b/hw/bsp/broadcom_64bit/family.c index 399397bb4..1c7f6c7a5 100644 --- a/hw/bsp/broadcom_64bit/family.c +++ b/hw/bsp/broadcom_64bit/family.c @@ -125,16 +125,16 @@ int board_uart_read(uint8_t* buf, int len) { } int board_uart_write(void const* buf, int len) { - for (int i = 0; i < len; i++) { - const char* cbuf = buf; - while (!UART1->STAT_b.TX_READY) {} - if (cbuf[i] == '\n') { - UART1->IO = '\r'; - while (!UART1->STAT_b.TX_READY) {} + const uint8_t* p = (const uint8_t*) buf; + int count = 0; + while (count < len) { + if (!UART1->STAT_b.TX_READY) { + break; } - UART1->IO = cbuf[i]; + UART1->IO = p[count]; + count++; } - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/ch32f20x/family.c b/hw/bsp/ch32f20x/family.c index dd84b7c77..ab6a6007a 100644 --- a/hw/bsp/ch32f20x/family.c +++ b/hw/bsp/ch32f20x/family.c @@ -136,11 +136,9 @@ int board_uart_read(uint8_t *buf, int len) int board_uart_write(void const *buf, int len) { - int txsize = len; - while ( txsize-- ) - { - uart_write(*(uint8_t const*) buf); - buf++; + uint8_t const *p = (uint8_t const *) buf; + for (int i = 0; i < len; i++) { + uart_write(p[i]); } return len; } diff --git a/hw/bsp/ch32v10x/family.c b/hw/bsp/ch32v10x/family.c index 344dcaf0b..72dae7086 100644 --- a/hw/bsp/ch32v10x/family.c +++ b/hw/bsp/ch32v10x/family.c @@ -143,11 +143,15 @@ int board_uart_read(uint8_t *buf, int len) { } int board_uart_write(void const *buf, int len) { - const char *bufc = (const char *) buf; - for (int i = 0; i < len; i++) { - while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); - USART_SendData(USART1, *bufc++); + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (USART_GetFlagStatus(USART1, USART_FLAG_TC) != RESET) { + USART_SendData(USART1, p[count]); + count++; + } else { + break; + } } - - return len; + return count; } diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c index 4c22450f9..221f62107 100644 --- a/hw/bsp/ch32v20x/family.c +++ b/hw/bsp/ch32v20x/family.c @@ -207,14 +207,19 @@ int board_uart_read(uint8_t *buf, int len) { int board_uart_write(void const *buf, int len) { #ifdef UART_DEV - const char *bufc = (const char *) buf; - for (int i = 0; i < len; i++) { - while (USART_GetFlagStatus(UART_DEV, USART_FLAG_TC) == RESET); - USART_SendData(UART_DEV, *bufc++); + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (USART_GetFlagStatus(UART_DEV, USART_FLAG_TC) != RESET) { + USART_SendData(UART_DEV, p[count]); + count++; + } else { + break; + } } + return count; #else (void) buf; (void) len; + return 0; #endif - - return len; } diff --git a/hw/bsp/ch32v30x/family.c b/hw/bsp/ch32v30x/family.c index 6295f7723..aee4e7d4f 100644 --- a/hw/bsp/ch32v30x/family.c +++ b/hw/bsp/ch32v30x/family.c @@ -173,12 +173,10 @@ int board_uart_read(uint8_t* buf, int len) { } int board_uart_write(void const* buf, int len) { - int txsize = len; - const char* bufc = (const char*) buf; - while (txsize--) { - uart_write(*bufc++); + uint8_t const *p = (uint8_t const *) buf; + for (int i = 0; i < len; i++) { + uart_write(p[i]); } - uart_sync(); return len; } diff --git a/hw/bsp/f1c100s/family.c b/hw/bsp/f1c100s/family.c index 1e71333d4..e221217ef 100644 --- a/hw/bsp/f1c100s/family.c +++ b/hw/bsp/f1c100s/family.c @@ -68,12 +68,20 @@ int board_uart_read(uint8_t* buf, int len) { } int board_uart_write(void const* buf, int len) { - int txsize = len; - while (txsize--) { - sys_uart_putc(*(uint8_t const*) buf); - buf++; + // UART0 base = 0x01c25000, USR register at +0x7c, bit 1 = TFNF (TX FIFO not full) + volatile uint32_t *uart_usr = (volatile uint32_t *) (0x01c25000 + 0x7c); + volatile uint32_t *uart_thr = (volatile uint32_t *) (0x01c25000 + 0x00); + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (*uart_usr & (1 << 1)) { + *uart_thr = p[count]; + count++; + } else { + break; + } } - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/fomu/family.c b/hw/bsp/fomu/family.c index cf04a1f6f..d3ad7a738 100644 --- a/hw/bsp/fomu/family.c +++ b/hw/bsp/fomu/family.c @@ -104,16 +104,18 @@ int board_uart_read(uint8_t* buf, int len) int board_uart_write(void const * buf, int len) { - int32_t offset = 0; uint8_t const* buf8 = (uint8_t const*) buf; - for (offset = 0; offset < len; offset++) + int count = 0; + while (count < len) { - if (!(messible_status_read() & CSR_MESSIBLE_STATUS_FULL_OFFSET)) + if (messible_status_read() & CSR_MESSIBLE_STATUS_FULL_OFFSET) { - messible_in_write(buf8[offset]); + break; } + messible_in_write(buf8[count]); + count++; } - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/ft9xx/family.c b/hw/bsp/ft9xx/family.c index ff24cfe89..5ee134eb0 100644 --- a/hw/bsp/ft9xx/family.c +++ b/hw/bsp/ft9xx/family.c @@ -221,16 +221,21 @@ int board_uart_read(uint8_t *buf, int len) // Send characters to UART int board_uart_write(void const *buf, int len) { - int r = 0; - + int count = 0; #ifdef BOARD_UART -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" // uart_writen does not have const for buffer parameter. - r = uart_writen(BOARD_UART, (uint8_t *)((const void *)buf), len); -#pragma GCC diagnostic pop + uint8_t const *p = (uint8_t const *) buf; + while (count < len) { + if (BOARD_UART->LSR_ICR_XON2 & MASK_UART_LSR_THRE) { + BOARD_UART->RHR_THR_DLL = p[count]; + count++; + } else { + break; + } + } +#else + (void) buf; (void) len; #endif - - return r; + return count; } // Get current milliseconds diff --git a/hw/bsp/gd32vf103/family.c b/hw/bsp/gd32vf103/family.c index 4c1099317..c1dc82bda 100644 --- a/hw/bsp/gd32vf103/family.c +++ b/hw/bsp/gd32vf103/family.c @@ -160,12 +160,17 @@ int board_uart_read(uint8_t* buf, int len) { int board_uart_write(void const* buf, int len) { #if defined(UART_DEV) - int txsize = len; - while (txsize--) { - usart_write(UART_DEV, *(uint8_t const*)buf); - buf++; + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (usart_flag_get(UART_DEV, USART_FLAG_TBE) != RESET) { + usart_data_transmit(UART_DEV, p[count]); + count++; + } else { + break; + } } - return len; + return count; #else (void)buf; (void)len; diff --git a/hw/bsp/kinetis_k/family.c b/hw/bsp/kinetis_k/family.c index 1505defe0..8efab2762 100644 --- a/hw/bsp/kinetis_k/family.c +++ b/hw/bsp/kinetis_k/family.c @@ -125,13 +125,21 @@ int board_uart_read(uint8_t *buf, int len) { } int board_uart_write(void const *buf, int len) { - (void) buf; - (void) len; - #ifdef UART_DEV - UART_WriteBlocking(UART_DEV, (uint8_t const*) buf, len); - return len; + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (UART_DEV->S1 & UART_S1_TDRE_MASK) { + UART_DEV->D = p[count]; + count++; + } else { + break; + } + } + return count; #else + (void) buf; + (void) len; return 0; #endif } diff --git a/hw/bsp/kinetis_k32l/family.c b/hw/bsp/kinetis_k32l/family.c index ec8dc6ecf..a3bd92cec 100644 --- a/hw/bsp/kinetis_k32l/family.c +++ b/hw/bsp/kinetis_k32l/family.c @@ -117,28 +117,30 @@ uint32_t board_button_read(void) { } int board_uart_read(uint8_t* buf, int len) { -#if 0 /* - Use this version if want the LED to blink during BOARD=board_test, - without having to hit a key. - */ - if( 0U != (kLPUART_RxDataRegFullFlag & LPUART_GetStatusFlags( UART_PORT )) ) - { - LPUART_ReadBlocking(UART_PORT, buf, len); - return len; + int count = 0; + while (count < len) { + if (UART_PORT->STAT & LPUART_STAT_RDRF_MASK) { + buf[count] = (uint8_t) UART_PORT->DATA; + count++; + } else { + break; } - - return( 0 ); -#else /* Wait for 'len' characters to come in */ - - LPUART_ReadBlocking(UART_PORT, buf, len); - return len; - -#endif + } + return count; } int board_uart_write(void const* buf, int len) { - LPUART_WriteBlocking(UART_PORT, (uint8_t const*) buf, len); - return len; + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (UART_PORT->STAT & LPUART_STAT_TDRE_MASK) { + UART_PORT->DATA = p[count]; + count++; + } else { + break; + } + } + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/kinetis_kl/family.c b/hw/bsp/kinetis_kl/family.c index f89434d06..b378b6821 100644 --- a/hw/bsp/kinetis_kl/family.c +++ b/hw/bsp/kinetis_kl/family.c @@ -125,14 +125,31 @@ uint32_t board_button_read(void) int board_uart_read(uint8_t* buf, int len) { - LPSCI_ReadBlocking(UART_PORT, buf, len); - return len; + int count = 0; + while (count < len) { + if (UART_PORT->S1 & UART0_S1_RDRF_MASK) { + buf[count] = UART_PORT->D; + count++; + } else { + break; + } + } + return count; } int board_uart_write(void const * buf, int len) { - LPSCI_WriteBlocking(UART_PORT, (uint8_t const*) buf, len); - return len; + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (UART_PORT->S1 & UART0_S1_TDRE_MASK) { + UART_PORT->D = p[count]; + count++; + } else { + break; + } + } + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc15/family.c b/hw/bsp/lpc15/family.c index 0d092d3a9..bbfee1b51 100644 --- a/hw/bsp/lpc15/family.c +++ b/hw/bsp/lpc15/family.c @@ -130,7 +130,17 @@ int board_uart_read(uint8_t* buf, int len) int board_uart_write(void const * buf, int len) { - return Chip_UART_SendBlocking(UART_PORT, buf, len); + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (Chip_UART_GetStatus(UART_PORT) & UART_STAT_TXRDY) { + Chip_UART_SendByte(UART_PORT, p[count]); + count++; + } else { + break; + } + } + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc18/family.c b/hw/bsp/lpc18/family.c index 2043cef99..8a612d9d8 100644 --- a/hw/bsp/lpc18/family.c +++ b/hw/bsp/lpc18/family.c @@ -128,12 +128,16 @@ int board_uart_read(uint8_t *buf, int len) { int board_uart_write(void const *buf, int len) { uint8_t const *buf8 = (uint8_t const *) buf; - for (int i = 0; i < len; i++) { - while ((Chip_UART_ReadLineStatus(UART_DEV) & UART_LSR_THRE) == 0) {} - Chip_UART_SendByte(UART_DEV, buf8[i]); + int count = 0; + while (count < len) { + if (Chip_UART_ReadLineStatus(UART_DEV) & UART_LSR_THRE) { + Chip_UART_SendByte(UART_DEV, buf8[count]); + count++; + } else { + break; + } } - - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc43/family.c b/hw/bsp/lpc43/family.c index 56834a1b0..5aff49704 100644 --- a/hw/bsp/lpc43/family.c +++ b/hw/bsp/lpc43/family.c @@ -244,12 +244,16 @@ int board_uart_read(uint8_t *buf, int len) { int board_uart_write(void const *buf, int len) { uint8_t const *buf8 = (uint8_t const *) buf; - for ( int i = 0; i < len; i++ ) { - while ( (Chip_UART_ReadLineStatus(UART_DEV) & UART_LSR_THRE) == 0 ) {} - Chip_UART_SendByte(UART_DEV, buf8[i]); + int count = 0; + while (count < len) { + if (Chip_UART_ReadLineStatus(UART_DEV) & UART_LSR_THRE) { + Chip_UART_SendByte(UART_DEV, buf8[count]); + count++; + } else { + break; + } } - - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc54/family.c b/hw/bsp/lpc54/family.c index 806bd53dc..129f9f0ec 100644 --- a/hw/bsp/lpc54/family.c +++ b/hw/bsp/lpc54/family.c @@ -228,8 +228,23 @@ int board_uart_read(uint8_t* buf, int len) { } int board_uart_write(void const* buf, int len) { - USART_WriteBlocking(UART_DEV, (uint8_t const*) buf, len); +#ifdef UART_DEV + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (UART_DEV->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) { + UART_DEV->FIFOWR = p[count]; + count++; + } else { + break; + } + } + return count; +#else + (void) buf; + (void) len; return 0; +#endif } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc55/family.c b/hw/bsp/lpc55/family.c index b5d097234..b9d856f86 100644 --- a/hw/bsp/lpc55/family.c +++ b/hw/bsp/lpc55/family.c @@ -177,8 +177,23 @@ int board_uart_read(uint8_t* buf, int len) { } int board_uart_write(void const* buf, int len) { - USART_WriteBlocking(UART_DEV, (uint8_t const*) buf, len); - return len; +#ifdef UART_DEV + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (UART_DEV->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) { + UART_DEV->FIFOWR = p[count]; + count++; + } else { + break; + } + } + return count; +#else + (void) buf; + (void) len; + return 0; +#endif } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/maxim/family.c b/hw/bsp/maxim/family.c index 6ef4c12c1..7f2a0eee6 100644 --- a/hw/bsp/maxim/family.c +++ b/hw/bsp/maxim/family.c @@ -186,13 +186,17 @@ int board_uart_read(uint8_t *buf, int len) { } int board_uart_write(void const *buf, int len) { - int act_len = 0; - const uint8_t *ch_ptr = (const uint8_t *) buf; - while (act_len < len) { - MXC_UART_WriteCharacter(ConsoleUart, *ch_ptr++); - act_len++; + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (MXC_UART_GetTXFIFOAvailable(ConsoleUart) > 0) { + MXC_UART_WriteCharacterRaw(ConsoleUart, p[count]); + count++; + } else { + break; + } } - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/mcx/family.c b/hw/bsp/mcx/family.c index a3969c217..f50a65120 100644 --- a/hw/bsp/mcx/family.c +++ b/hw/bsp/mcx/family.c @@ -204,8 +204,17 @@ int board_uart_read(uint8_t* buf, int len) { int board_uart_write(void const* buf, int len) { #ifdef UART_DEV - LPUART_WriteBlocking(UART_DEV, (uint8_t const*) buf, len); - return len; + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (UART_DEV->STAT & LPUART_STAT_TDRE_MASK) { + UART_DEV->DATA = p[count]; + count++; + } else { + break; + } + } + return count; #else (void) buf; (void) len; return 0; diff --git a/hw/bsp/mm32/family.c b/hw/bsp/mm32/family.c index 330b01f6d..651c9496e 100644 --- a/hw/bsp/mm32/family.c +++ b/hw/bsp/mm32/family.c @@ -153,14 +153,17 @@ int board_uart_read(uint8_t* buf, int len) { int board_uart_write(void const* buf, int len) { #ifdef UART_DEV - const char* buff = buf; - while (len) { - while ((UART1->CSR & UART_IT_TXIEN) == 0); //The loop is sent until it is finished - UART1->TDR = (*buff & 0xFF); - buff++; - len--; + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { + if (UART1->CSR & UART_IT_TXIEN) { + UART1->TDR = (p[count] & 0xFF); + count++; + } else { + break; + } } - return len; + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/msp430/family.c b/hw/bsp/msp430/family.c index 413ad7db6..0438f0abc 100644 --- a/hw/bsp/msp430/family.c +++ b/hw/bsp/msp430/family.c @@ -186,16 +186,18 @@ int board_uart_read(uint8_t * buf, int len) int board_uart_write(void const * buf, int len) { - const char * char_buf = (const char *) buf; - - for(int i = 0; i < len; i++) + uint8_t const *p = (uint8_t const *) buf; + int count = 0; + while (count < len) { - // Wait until TX buffer is empty (cleared by writing buffer). - while(!(UCA1IFG & UCTXIFG)); - UCA1TXBUF = char_buf[i]; + if (UCA1IFG & UCTXIFG) { + UCA1TXBUF = p[count]; + count++; + } else { + break; + } } - - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/msp432e4/family.c b/hw/bsp/msp432e4/family.c index 90eb945f4..be93976a5 100644 --- a/hw/bsp/msp432e4/family.c +++ b/hw/bsp/msp432e4/family.c @@ -188,11 +188,16 @@ int board_uart_read(uint8_t * buf, int len) int board_uart_write(void const * buf, int len) { uint8_t const *p = (uint8_t const *)buf; - for (int i = 0; i < len; ++i) { - while (UART0->FR & UART_FR_TXFF) ; - UART0->DR = *p++; + int count = 0; + while (count < len) { + if (!(UART0->FR & UART_FR_TXFF)) { + UART0->DR = p[count]; + count++; + } else { + break; + } } - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/rw61x/family.c b/hw/bsp/rw61x/family.c index fcc7fb262..951c266ea 100644 --- a/hw/bsp/rw61x/family.c +++ b/hw/bsp/rw61x/family.c @@ -113,8 +113,17 @@ int board_uart_read(uint8_t* buf, int len) { int board_uart_write(void const* buf, int len) { #ifdef UART_DEV - USART_WriteBlocking(UART_DEV, (uint8_t const*) buf, len); - return len; + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (UART_DEV->FIFOSTAT & USART_FIFOSTAT_TXNOTFULL_MASK) { + UART_DEV->FIFOWR = p[count]; + count++; + } else { + break; + } + } + return count; #else (void) buf; (void) len; return 0; diff --git a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake index 86d12ca24..50fbe64b0 100644 --- a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake +++ b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake @@ -3,6 +3,8 @@ set(SAM_FAMILY samd51) set(JLINK_DEVICE ATSAMD51J19) set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/${BOARD}.ld) +set(MAX3421_HOST 1) + function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC __SAMD51J19A__ diff --git a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk index eba7070c1..f0f097c2a 100644 --- a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk +++ b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk @@ -2,6 +2,8 @@ SAM_FAMILY = samd51 CFLAGS += -D__SAMD51J19A__ +MAX3421_HOST = 1 + # All source paths should be relative to the top level. LD_FILE = $(BOARD_PATH)/$(BOARD).ld diff --git a/hw/bsp/samg/family.c b/hw/bsp/samg/family.c index b27134305..519068986 100644 --- a/hw/bsp/samg/family.c +++ b/hw/bsp/samg/family.c @@ -134,11 +134,16 @@ int board_uart_read(uint8_t* buf, int len) { int board_uart_write(void const* buf, int len) { uint8_t const* buf8 = (uint8_t const*) buf; - for (int i = 0; i < len; i++) { - while (!_usart_sync_is_ready_to_send(&edbg_com)) {} - _usart_sync_write_byte(&edbg_com, buf8[i]); + int count = 0; + while (count < len) { + if (_usart_sync_is_ready_to_send(&edbg_com)) { + _usart_sync_write_byte(&edbg_com, buf8[count]); + count++; + } else { + break; + } } - return len; + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/stm32l0/family.c b/hw/bsp/stm32l0/family.c index 2a32ba9f5..930fa2d66 100644 --- a/hw/bsp/stm32l0/family.c +++ b/hw/bsp/stm32l0/family.c @@ -162,8 +162,17 @@ int board_uart_read(uint8_t* buf, int len) { int board_uart_write(void const* buf, int len) { #ifdef UART_ID - HAL_UART_Transmit(&UartHandle, (uint8_t*)(uintptr_t) buf, len, 0xffff); - return len; + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (UartHandle.Instance->ISR & USART_ISR_TXE) { + UartHandle.Instance->TDR = p[count]; + count++; + } else { + break; + } + } + return count; #else (void) buf; (void) len; diff --git a/hw/bsp/tm4c/family.c b/hw/bsp/tm4c/family.c index 503d0a8c9..6988a264e 100644 --- a/hw/bsp/tm4c/family.c +++ b/hw/bsp/tm4c/family.c @@ -189,13 +189,16 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { int board_uart_write(void const* buf, int len) { uint8_t const* data = buf; - - for (int i = 0; i < len; i++) { - while ((UART0->FR & (1 << 5)) != 0) {} // Poll until previous data was shofted out - UART0->DR = data[i]; // Write UART0 DATA REGISTER + int count = 0; + while (count < len) { + if ((UART0->FR & (1 << 5)) == 0) { // TX FIFO not full + UART0->DR = data[count]; + count++; + } else { + break; + } } - - return len; + return count; } int board_uart_read(uint8_t* buf, int len) { diff --git a/hw/bsp/xmc4000/family.c b/hw/bsp/xmc4000/family.c index d0acd04cb..1325b784b 100644 --- a/hw/bsp/xmc4000/family.c +++ b/hw/bsp/xmc4000/family.c @@ -128,11 +128,25 @@ int board_uart_read(uint8_t* buf, int len) { int board_uart_write(void const* buf, int len) { #ifdef UART_DEV - char const* bufch = (char const*) buf; - for(int i=0;iTBCTR & USIC_CH_TBCTR_SIZE_Msk) != 0UL; + while (count < len) { + if (fifo_enabled) { + if (XMC_USIC_CH_TXFIFO_IsFull(UART_DEV)) { + break; + } + UART_DEV->IN[0U] = p[count]; + } else { + if (XMC_USIC_CH_GetTransmitBufferStatus(UART_DEV) == XMC_USIC_CH_TBUF_STATUS_BUSY) { + break; + } + XMC_UART_CH_ClearStatusFlag(UART_DEV, (uint32_t)XMC_UART_CH_STATUS_FLAG_TRANSMIT_BUFFER_INDICATION); + UART_DEV->TBUF[0U] = p[count]; + } + count++; } - return len; + return count; #else (void) buf; (void) len; diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 86ac902ce..b9c768d14 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -62,11 +62,10 @@ { "name": "metro_m4_express", "uid": "9995AD485337433231202020FF100A34", - "build" : { - "args": ["MAX3421_HOST=1"] - }, "tests": { - "device": true, "host": false, "dual": true, + "device": true, + "host": false, + "dual": true, "dev_attached": [{"vid_pid": "067b_2303", "serial": "0", "is_cdc": true}], "comment": "pl23x" }, -- cgit v1.3.1 From 9838a231ad9bff623a3ec819d05aad4a4087193b Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 4 Apr 2026 21:32:39 +0700 Subject: make board_uart_read()/write() return -1 when unimplemented for consistency across all families --- .claude/commands/hil.md | 18 +++++---------- hw/bsp/board.c | 19 ++++++++++------ hw/bsp/da1469x/family.c | 4 ++-- hw/bsp/efm32/family.c | 4 ++-- hw/bsp/lpc11/family.c | 4 ++-- hw/bsp/lpc13/family.c | 4 ++-- hw/bsp/lpc17/family.c | 57 ++++++++++++++++++++++------------------------ hw/bsp/lpc40/family.c | 4 ++-- hw/bsp/lpc51/family.c | 4 ++-- hw/bsp/lpc54/family.c | 4 ++-- hw/bsp/lpc55/family.c | 4 ++-- hw/bsp/mcx/family.c | 4 ++-- hw/bsp/nrf/family.c | 2 +- hw/bsp/nuc100_120/family.c | 4 ++-- hw/bsp/nuc121_125/family.c | 4 ++-- hw/bsp/nuc126/family.c | 4 ++-- hw/bsp/nuc505/family.c | 4 ++-- hw/bsp/pic32mz/family.c | 2 +- hw/bsp/ra/family.c | 4 ++-- hw/bsp/rw61x/family.c | 4 ++-- hw/bsp/samd11/family.c | 4 ++-- hw/bsp/samd2x_l2x/family.c | 6 ++--- hw/bsp/samd5x_e5x/family.c | 4 ++-- hw/bsp/same7x/family.c | 2 +- test/hil/tinyusb.json | 16 ++++++++++++- 25 files changed, 100 insertions(+), 90 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/.claude/commands/hil.md b/.claude/commands/hil.md index 266321bb9..07e1a865b 100644 --- a/.claude/commands/hil.md +++ b/.claude/commands/hil.md @@ -7,27 +7,21 @@ Run Hardware-in-the-Loop (HIL) tests on physical boards. ## Instructions -1. Determine the HIL config file: - ```bash - HIL_CONFIG=$( (systemctl list-units --type=service --state=running 2>/dev/null; systemctl --user list-units --type=service --state=running 2>/dev/null) | grep -q 'actions\.runner' && echo tinyusb.json || echo local.json ) - ``` - Default is `local.json` for local development. - -2. Parse $ARGUMENTS: +1. Parse $ARGUMENTS: - If $ARGUMENTS contains `-b BOARD_NAME`, run for that specific board only. - If $ARGUMENTS is empty or has no `-b`, run for all boards in the config. - Pass through any other flags (e.g. `-v` for verbose, `-r N` for retry count) directly to the command. -3. Determine whether to run **locally** or **remotely via SSH**: +2. Determine whether to run **locally** or **remotely via SSH**: - **Local**: boards are attached to this machine (default when `local.json` is used) - **Remote (`ssh ci.lan`)**: boards are attached to the CI machine (when `tinyusb.json` is used) -4. **Local execution** (boards attached to this machine): +3. **Local execution** (boards attached to this machine): ```bash python test/hil/hil_test.py -b BOARD_NAME -B examples $HIL_CONFIG $EXTRA_ARGS ``` -5. **Remote execution** (boards attached to `ci.lan`): +4. **Remote execution** (boards attached to `ci.lan`): Only copy the minimal files needed (firmware binaries + test script + config), then run remotely. ```bash @@ -56,9 +50,9 @@ Run Hardware-in-the-Loop (HIL) tests on physical boards. - Flasher tools: `JLinkExe`, `openocd`, etc. as needed by the board - USB access to the boards (udev rules configured) -6. Use a timeout of at least 20 minutes (600000ms). HIL tests take 2-5 minutes. NEVER cancel early. +5. Use a timeout of at least 20 minutes (600000ms). HIL tests take 2-5 minutes. NEVER cancel early. -7. After the test completes: +6. After the test completes: - Show the test output to the user. - Summarize pass/fail results per board. - If there are failures, suggest re-running with `-v` flag for verbose output to help debug. diff --git a/hw/bsp/board.c b/hw/bsp/board.c index 1c159189c..ae58bb5fc 100644 --- a/hw/bsp/board.c +++ b/hw/bsp/board.c @@ -97,17 +97,22 @@ int sys_read (int fhdl, char *buf, size_t count) { #else // Default logging with on-board UART -// Retry to ensure printf/log output is not lost when board_uart_write is non-blocking +// board_uart_write() is non-blocking, retry until all bytes sent. +// Returns negative if UART is not available (stub), break immediately. int sys_write (int fhdl, const char *buf, size_t count) { (void) fhdl; - int written = 0; - while ((size_t)written < count) { - int wr = board_uart_write(buf + written, (int)(count - (size_t)written)); - if (wr > 0) { - written += wr; + size_t written = 0; + while (written < count) { + int wr = board_uart_write(buf + written, (int)(count - written)); + if (wr < 0) { + break; // UART not available } + if (wr == 0) { + continue; // TX busy, keep trying + } + written += (size_t) wr; } - return written; + return (int) written; } int sys_read (int fhdl, char *buf, size_t count) { diff --git a/hw/bsp/da1469x/family.c b/hw/bsp/da1469x/family.c index a4f7f2e8d..5f7e2d42f 100644 --- a/hw/bsp/da1469x/family.c +++ b/hw/bsp/da1469x/family.c @@ -123,14 +123,14 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/efm32/family.c b/hw/bsp/efm32/family.c index d318e20d6..7a5ea6a74 100644 --- a/hw/bsp/efm32/family.c +++ b/hw/bsp/efm32/family.c @@ -673,13 +673,13 @@ uint32_t board_button_read(void) int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const * buf, int len) { (void) buf; (void) len; - return 0; + return -1; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc11/family.c b/hw/bsp/lpc11/family.c index 76c2bd17c..06b74bcd7 100644 --- a/hw/bsp/lpc11/family.c +++ b/hw/bsp/lpc11/family.c @@ -114,13 +114,13 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc13/family.c b/hw/bsp/lpc13/family.c index 8513f4df4..e25449689 100644 --- a/hw/bsp/lpc13/family.c +++ b/hw/bsp/lpc13/family.c @@ -101,11 +101,11 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } diff --git a/hw/bsp/lpc17/family.c b/hw/bsp/lpc17/family.c index f398f7e3c..6b94c1163 100644 --- a/hw/bsp/lpc17/family.c +++ b/hw/bsp/lpc17/family.c @@ -64,29 +64,13 @@ void board_init(void) { Chip_GPIO_SetPinDIROutput(LPC_GPIO, LED_PORT, LED_PIN); Chip_GPIO_SetPinDIRInput(LPC_GPIO, BUTTON_PORT, BUTTON_PIN); -#if 0 //------------- UART -------------// - PINSEL_CFG_Type PinCfg = - { - .Portnum = 0, - .Pinnum = 0, // TXD is P0.0 - .Funcnum = 2, - .OpenDrain = 0, - .Pinmode = 0 - }; - PINSEL_ConfigPin(&PinCfg); - - PinCfg.Portnum = 0; - PinCfg.Pinnum = 1; // RXD is P0.1 - PINSEL_ConfigPin(&PinCfg); - - UART_CFG_Type UARTConfigStruct; - UART_ConfigStructInit(&UARTConfigStruct); - UARTConfigStruct.Baud_rate = CFG_BOARD_UART_BAUDRATE; - - UART_Init(BOARD_UART_PORT, &UARTConfigStruct); - UART_TxCmd(BOARD_UART_PORT, ENABLE); // Enable UART Transmit -#endif + // Pin muxing for UART3 (TXD3=P0.0, RXD3=P0.1) is configured in board.h pinmuxing[] + Chip_UART_Init(BOARD_UART_PORT); + Chip_UART_SetBaud(BOARD_UART_PORT, CFG_BOARD_UART_BAUDRATE); + Chip_UART_ConfigData(BOARD_UART_PORT, (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_DIS)); + Chip_UART_SetupFIFOS(BOARD_UART_PORT, (UART_FCR_FIFO_EN | UART_FCR_TRG_LEV0)); + Chip_UART_TXEnable(BOARD_UART_PORT); //------------- USB -------------// Chip_IOCON_SetPinMuxing(LPC_IOCON, pin_usb_mux, sizeof(pin_usb_mux) / sizeof(PINMUX_GRP_T)); @@ -125,17 +109,30 @@ uint32_t board_button_read(void) { } int board_uart_read(uint8_t* buf, int len) { -// return UART_ReceiveByte(BOARD_UART_PORT); - (void) buf; - (void) len; - return 0; + int count = 0; + while (count < len) { + if (BOARD_UART_PORT->LSR & UART_LSR_RDR) { + buf[count] = (uint8_t) BOARD_UART_PORT->RBR; + count++; + } else { + break; + } + } + return count; } int board_uart_write(void const* buf, int len) { -// UART_Send(BOARD_UART_PORT, &c, 1, BLOCKING); - (void) buf; - (void) len; - return 0; + const uint8_t *p = (const uint8_t *) buf; + int count = 0; + while (count < len) { + if (BOARD_UART_PORT->LSR & UART_LSR_THRE) { + BOARD_UART_PORT->THR = p[count]; + count++; + } else { + break; + } + } + return count; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc40/family.c b/hw/bsp/lpc40/family.c index 237cd996b..d8a63576b 100644 --- a/hw/bsp/lpc40/family.c +++ b/hw/bsp/lpc40/family.c @@ -139,14 +139,14 @@ int board_uart_read(uint8_t *buf, int len) { //return UART_ReceiveByte(BOARD_UART_PORT); (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const *buf, int len) { //UART_Send(BOARD_UART_PORT, &c, 1, BLOCKING); (void) buf; (void) len; - return 0; + return -1; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc51/family.c b/hw/bsp/lpc51/family.c index 847972350..57c3e26dd 100644 --- a/hw/bsp/lpc51/family.c +++ b/hw/bsp/lpc51/family.c @@ -106,13 +106,13 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/lpc54/family.c b/hw/bsp/lpc54/family.c index 129f9f0ec..5a5087e56 100644 --- a/hw/bsp/lpc54/family.c +++ b/hw/bsp/lpc54/family.c @@ -224,7 +224,7 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { @@ -243,7 +243,7 @@ int board_uart_write(void const* buf, int len) { #else (void) buf; (void) len; - return 0; + return -1; #endif } diff --git a/hw/bsp/lpc55/family.c b/hw/bsp/lpc55/family.c index b9d856f86..e021caf35 100644 --- a/hw/bsp/lpc55/family.c +++ b/hw/bsp/lpc55/family.c @@ -173,7 +173,7 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { @@ -192,7 +192,7 @@ int board_uart_write(void const* buf, int len) { #else (void) buf; (void) len; - return 0; + return -1; #endif } diff --git a/hw/bsp/mcx/family.c b/hw/bsp/mcx/family.c index f50a65120..2facfb1e0 100644 --- a/hw/bsp/mcx/family.c +++ b/hw/bsp/mcx/family.c @@ -199,7 +199,7 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { @@ -217,7 +217,7 @@ int board_uart_write(void const* buf, int len) { return count; #else (void) buf; (void) len; - return 0; + return -1; #endif } diff --git a/hw/bsp/nrf/family.c b/hw/bsp/nrf/family.c index 04bfbf320..f1e8b829c 100644 --- a/hw/bsp/nrf/family.c +++ b/hw/bsp/nrf/family.c @@ -274,7 +274,7 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; // nrfx_err_t err = nrfx_uarte_rx(&_uart_id, buf, (size_t) len); // return NRFX_SUCCESS == err ? len : 0; } diff --git a/hw/bsp/nuc100_120/family.c b/hw/bsp/nuc100_120/family.c index cfe60121c..4ff24aae7 100644 --- a/hw/bsp/nuc100_120/family.c +++ b/hw/bsp/nuc100_120/family.c @@ -120,11 +120,11 @@ uint32_t board_button_read(void) int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const * buf, int len) { (void) buf; (void) len; - return 0; + return -1; } diff --git a/hw/bsp/nuc121_125/family.c b/hw/bsp/nuc121_125/family.c index dce5b4d62..9dd3c71fc 100644 --- a/hw/bsp/nuc121_125/family.c +++ b/hw/bsp/nuc121_125/family.c @@ -109,11 +109,11 @@ uint32_t board_button_read(void) int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const * buf, int len) { (void) buf; (void) len; - return 0; + return -1; } diff --git a/hw/bsp/nuc126/family.c b/hw/bsp/nuc126/family.c index 3343064e5..663bffbe7 100644 --- a/hw/bsp/nuc126/family.c +++ b/hw/bsp/nuc126/family.c @@ -134,11 +134,11 @@ uint32_t board_button_read(void) int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const * buf, int len) { (void) buf; (void) len; - return 0; + return -1; } diff --git a/hw/bsp/nuc505/family.c b/hw/bsp/nuc505/family.c index f1a77e4a5..41f6017c2 100644 --- a/hw/bsp/nuc505/family.c +++ b/hw/bsp/nuc505/family.c @@ -117,11 +117,11 @@ uint32_t board_button_read(void) int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const * buf, int len) { (void) buf; (void) len; - return 0; + return -1; } diff --git a/hw/bsp/pic32mz/family.c b/hw/bsp/pic32mz/family.c index 2bfc876e1..5805e653f 100644 --- a/hw/bsp/pic32mz/family.c +++ b/hw/bsp/pic32mz/family.c @@ -96,7 +96,7 @@ TU_ATTR_WEAK int board_uart_read(uint8_t * buf, int len) (void) buf; (void) len; - return 0; + return -1; } TU_ATTR_WEAK int board_uart_write(void const * buf, int len) diff --git a/hw/bsp/ra/family.c b/hw/bsp/ra/family.c index f371e694b..c8a4d33d9 100644 --- a/hw/bsp/ra/family.c +++ b/hw/bsp/ra/family.c @@ -153,13 +153,13 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { int board_uart_read(uint8_t *buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const *buf, int len) { (void) buf; (void) len; - return 0; + return -1; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/rw61x/family.c b/hw/bsp/rw61x/family.c index 951c266ea..5d7bd4754 100644 --- a/hw/bsp/rw61x/family.c +++ b/hw/bsp/rw61x/family.c @@ -108,7 +108,7 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { @@ -126,7 +126,7 @@ int board_uart_write(void const* buf, int len) { return count; #else (void) buf; (void) len; - return 0; + return -1; #endif } diff --git a/hw/bsp/samd11/family.c b/hw/bsp/samd11/family.c index bccbac8ea..0c987b85a 100644 --- a/hw/bsp/samd11/family.c +++ b/hw/bsp/samd11/family.c @@ -137,13 +137,13 @@ uint32_t board_button_read(void) int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const * buf, int len) { (void) buf; (void) len; - return 0; + return -1; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/samd2x_l2x/family.c b/hw/bsp/samd2x_l2x/family.c index 737219b6c..11b6343cd 100644 --- a/hw/bsp/samd2x_l2x/family.c +++ b/hw/bsp/samd2x_l2x/family.c @@ -322,7 +322,7 @@ static inline void uart_send_str(const char* text) int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const * buf, int len) @@ -343,13 +343,13 @@ static void uart_init(void) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } #endif diff --git a/hw/bsp/samd5x_e5x/family.c b/hw/bsp/samd5x_e5x/family.c index c008b9719..71ef2d6ce 100644 --- a/hw/bsp/samd5x_e5x/family.c +++ b/hw/bsp/samd5x_e5x/family.c @@ -194,13 +194,13 @@ size_t board_get_unique_id(uint8_t id[], size_t max_len) { int board_uart_read(uint8_t* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const* buf, int len) { (void) buf; (void) len; - return 0; + return -1; } #if CFG_TUSB_OS == OPT_OS_NONE diff --git a/hw/bsp/same7x/family.c b/hw/bsp/same7x/family.c index 61c1792d1..d02e6c5f1 100644 --- a/hw/bsp/same7x/family.c +++ b/hw/bsp/same7x/family.c @@ -133,7 +133,7 @@ uint32_t board_button_read(void) { int board_uart_read(uint8_t *buf, int len) { (void) buf; (void) len; - return 0; + return -1; } int board_uart_write(void const *buf, int len) { diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index b9c768d14..3c03b3721 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -177,7 +177,21 @@ "uid": "560AE75E1C7152C9", "tests": { "device": false, "host": true, "dual": false, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002694", "is_cdc": true}] + "dev_attached": [ + { + "vid_pid": "1a86_55d4", + "serial": "52D2002694", + "is_cdc": true + }, + { + "vid_pid": "0951_1603", + "serial": "820000000000000045B46338", + "is_msc": true, + "block_size": 512, + "block_count": 3987456, + "msc_inquiry": "Kingston DataTraveler 2.0 1.0" + } + ] }, "flasher": { "name": "openocd", -- cgit v1.3.1 From 3747355841f35cf5f1b2998c1806d8d19b167722 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 4 Apr 2026 21:35:42 +0700 Subject: move MAX3421_HOST build flag to test config for metro_m4_express --- hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake | 2 -- hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk | 2 -- test/hil/tinyusb.json | 5 +++++ 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake index 50fbe64b0..86d12ca24 100644 --- a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake +++ b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.cmake @@ -3,8 +3,6 @@ set(SAM_FAMILY samd51) set(JLINK_DEVICE ATSAMD51J19) set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/${BOARD}.ld) -set(MAX3421_HOST 1) - function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC __SAMD51J19A__ diff --git a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk index f0f097c2a..eba7070c1 100644 --- a/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk +++ b/hw/bsp/samd5x_e5x/boards/metro_m4_express/board.mk @@ -2,8 +2,6 @@ SAM_FAMILY = samd51 CFLAGS += -D__SAMD51J19A__ -MAX3421_HOST = 1 - # All source paths should be relative to the top level. LD_FILE = $(BOARD_PATH)/$(BOARD).ld diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 3c03b3721..92b7b21b0 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -62,6 +62,11 @@ { "name": "metro_m4_express", "uid": "9995AD485337433231202020FF100A34", + "build": { + "args": [ + "MAX3421_HOST=1" + ] + }, "tests": { "device": true, "host": false, -- cgit v1.3.1 From ce81b01eda0f9e833bbb717e6f2cebad0030afa1 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 20 Apr 2026 16:44:25 +0700 Subject: improving transfer tracking and adding support for un-armed Rx data handling --- src/portable/mentor/musb/dcd_musb.c | 88 ++++++++++++++++++++++++------------- test/hil/tinyusb.json | 3 ++ 2 files changed, 61 insertions(+), 30 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c index 64f9ebacf..ad3838a09 100644 --- a/src/portable/mentor/musb/dcd_musb.c +++ b/src/portable/mentor/musb/dcd_musb.c @@ -58,15 +58,18 @@ typedef union { volatile uint32_t u32; } hw_fifo_t; -typedef struct TU_ATTR_PACKED -{ - void *buf; /* the start address of a transfer data buffer */ +typedef struct { + union { + uint8_t *buf; /* the start address of a transfer data buffer */ + tu_fifo_t *fifo; + }; uint16_t length; /* the number of bytes in the buffer */ uint16_t remaining; /* the number of bytes remaining in the buffer */ + bool armed; /* true while a transfer is posted */ + bool use_fifo; /* true: buf is tu_fifo_t*; false: buf is plain byte pointer. */ } pipe_state_t; -typedef struct -{ +typedef struct { union { tusb_control_request_t setup_packet; uint32_t setup_buffer[2]; @@ -75,7 +78,6 @@ typedef struct int8_t status_out; pipe_state_t pipe0; pipe_state_t pipe[2][TUP_DCD_ENDPOINT_MAX-1]; /* pipe[direction][endpoint number - 1] */ - uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */ } dcd_data_t; static dcd_data_t _dcd; @@ -197,6 +199,7 @@ static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr) { if (rem == 0 && pipe->length > 0) { pipe->buf = NULL; + pipe->armed = false; return true; } @@ -204,15 +207,13 @@ static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr) { musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); const unsigned mps = ep_csr->tx_maxp; const unsigned len = TU_MIN(mps, rem); - void *buf = pipe->buf; volatile void *fifo_ptr = &musb_regs->fifo[epnum]; - // 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)) { - tu_hwfifo_write_from_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL); + if (pipe->use_fifo) { + tu_hwfifo_write_from_fifo(fifo_ptr, pipe->fifo, len, NULL); } else { - tu_hwfifo_write(fifo_ptr, buf, len, NULL); - pipe->buf = (uint8_t*)buf + len; + tu_hwfifo_write(fifo_ptr, pipe->buf, len, NULL); + pipe->buf += len; } pipe->remaining = rem - len; } @@ -231,11 +232,17 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr) // TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, ep_csr->rx_csrl); //Fail gracefully. Spurious interrupt. - if (!(ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY)) return false; + if (!(ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY)) { + return false; + } - void *buf = pipe->buf; - if (buf == NULL) { - ep_csr->rx_csrl = MUSB_RXCSRL1_FLUSH; + if (!pipe->armed) { + // Packet is already ACK'd by hardware and sitting in the Rx FIFO, but no transfer is + // posted. Do NOT flush (per MUSB spec §3.3.11 FlushFIFO) - that would silently drop + // acknowledged data. Mask this endpoint's Rx interrupt so the ISR stops re-firing; + // the FIFO stays occupied so hardware NAKs further OUT tokens (natural backpressure). + // The next dcd_edpt_xfer() on this endpoint will drain the staged packet. + musb_regs->intr_rxen &= (uint16_t) ~TU_BIT(epnum); return false; } @@ -245,11 +252,11 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr) const unsigned len = TU_MIN(TU_MIN(rem, mps), vld); volatile void *fifo_ptr = &musb_regs->fifo[epnum]; if (len) { - if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) { - tu_hwfifo_read_to_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL); + if (pipe->use_fifo) { + tu_hwfifo_read_to_fifo(fifo_ptr, pipe->fifo, len, NULL); } else { - tu_hwfifo_read(fifo_ptr, buf, len, NULL); - pipe->buf = (uint8_t*)buf + len; + tu_hwfifo_read(fifo_ptr, pipe->buf, len, NULL); + pipe->buf += len; } pipe->remaining = rem - len; } @@ -257,28 +264,46 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr) ep_csr->rx_csrl = 0; /* Always Clear RXRDY bit */ if ((len < mps) || (rem == len)) { pipe->buf = NULL; - return NULL != buf; + pipe->armed = false; + return true; } return false; } -static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) +static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, void *buffer, uint16_t total_bytes, bool use_fifo) { unsigned epnum = tu_edpt_number(ep_addr); unsigned epnum_minus1 = epnum - 1; unsigned dir_in = tu_edpt_dir(ep_addr); pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1]; - pipe->buf = buffer; + if (use_fifo) { + pipe->fifo = (tu_fifo_t *) buffer; + } else { + pipe->buf = (uint8_t *) buffer; + } pipe->length = total_bytes; pipe->remaining = total_bytes; + pipe->use_fifo = use_fifo; + pipe->armed = true; if (dir_in) { handle_xfer_in(rhport, ep_addr); } else { musb_regs_t* musb_regs = MUSB_REGS(rhport); musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum); - if (ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY) ep_csr->rx_csrl = 0; + + // Re-enable Rx interrupt (may have been masked by the no-buffer path in handle_xfer_out) + musb_regs->intr_rxen |= (uint16_t) TU_BIT(epnum); + + // Drain any packet staged in the Rx FIFO from a prior no-buffer interrupt + if (ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY) { + if (handle_xfer_out(rhport, ep_addr)) { + dcd_event_xfer_complete(rhport, ep_addr, + pipe->length - pipe->remaining, + XFER_RESULT_SUCCESS, false); + } + } } return true; } @@ -411,7 +436,7 @@ static void process_ep0(uint8_t rhport) return; } - /* When CSRL0 is zero, it means that completion of sending a any length packet + /* When CSRL0 is zero, it means that completion of sending any length packet * or receiving a zero length packet. */ if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) { /* STATUS IN */ @@ -611,6 +636,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) { pipe->buf = NULL; pipe->length = 0; pipe->remaining = 0; + pipe->armed = false; musb_regs_t* musb = MUSB_REGS(rhport); musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); @@ -656,6 +682,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc ) pipe->buf = NULL; pipe->length = 0; pipe->remaining = 0; + pipe->armed = false; musb_regs_t* musb = MUSB_REGS(rhport); musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn); @@ -722,13 +749,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t musb_dcd_int_disable(rhport); if (epnum) { - _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1); - ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes); + ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes, false); } else { ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes); } - if (ie) musb_dcd_int_enable(rhport); + if (ie) { + musb_dcd_int_enable(rhport); + } return ret; } @@ -744,8 +772,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_ TU_ASSERT(epnum); unsigned const ie = musb_dcd_get_int_enable(rhport); musb_dcd_int_disable(rhport); - _dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1); - ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes); + ret = edpt_n_xfer(rhport, ep_addr, ff, total_bytes, true); if (ie) musb_dcd_int_enable(rhport); return ret; } @@ -768,6 +795,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) { } else { const uint8_t is_rx = 1 - tu_edpt_dir(ep_addr); ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_SEND_STALL(is_rx); + _dcd.pipe[tu_edpt_dir(ep_addr)][epn - 1].armed = false; } if (ie) musb_dcd_int_enable(rhport); diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 92b7b21b0..5466cd534 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -226,6 +226,9 @@ { "name": "stm32f072disco", "uid": "3A001A001357364230353532", + "tests": { + "device": true, "host": false, "dual": false + }, "flasher": { "name": "jlink", "uid": "779541626", -- cgit v1.3.1 From 3792a9a3871cad32d7f38bc831417f60aeb17aff Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 26 Apr 2026 23:15:49 +0700 Subject: fix warning, change hil jlink for feather nrf52840 --- examples/device/cdc_msc_throughput/src/main.c | 6 +++--- test/hil/hil_test.py | 3 ++- test/hil/tinyusb.json | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/examples/device/cdc_msc_throughput/src/main.c b/examples/device/cdc_msc_throughput/src/main.c index b6a0705a3..116cbe13f 100644 --- a/examples/device/cdc_msc_throughput/src/main.c +++ b/examples/device/cdc_msc_throughput/src/main.c @@ -99,9 +99,9 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 const char vid[] = "TinyUSB"; const char pid[] = "Mass Storage"; const char rev[] = "1.0"; - memcpy(vendor_id, vid, strlen(vid)); - memcpy(product_id, pid, strlen(pid)); - memcpy(product_rev, rev, strlen(rev)); + (void) strncpy((char*) vendor_id, vid, 8); + (void) strncpy((char*) product_id, pid, 16); + (void) strncpy((char*) product_rev, rev, 4); } bool tud_msc_test_unit_ready_cb(uint8_t lun) { diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 7d716e339..9b4a36c1c 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -782,7 +782,8 @@ def test_device_cdc_msc_throughput(board): pass # Put tty in raw mode so dd sees pure binary throughput. - run_cmd(f'stty -F {tty} raw -echo') + rs = run_cmd(f'timeout 30 stty -F {tty} raw -echo') + assert rs.returncode == 0, f'stty failed: {rs.stdout.decode()}' # Payload aim: ~5 s per direction at FS (~830 kB/s), much less at HS. msc_count = 2 if is_fs else 16 # bs=1M diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 5466cd534..e7cd435fa 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -43,7 +43,7 @@ }, "flasher": { "name": "jlink", - "uid": "000682804350", + "uid": "681295394", "args": "-device nrf52840_xxaa" } }, -- cgit v1.3.1 From f2654a675b67b0b83337dd4df13afd498c3a0809 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 28 Apr 2026 16:50:44 +0700 Subject: only re-run tests that failed per board hil remove hub from pico2 since it is not stable --- test/hil/hil_test.py | 30 ++++++++++++++++++++++++------ test/hil/tinyusb.json | 5 ----- 2 files changed, 24 insertions(+), 11 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 9b4a36c1c..e98bd5da7 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -58,6 +58,7 @@ STATUS_SKIPPED = "\033[33mSkipped\033[0m" verbose = False test_only = [] +board_test = {} build_dir = 'cmake-build' skip_flash = False @@ -1346,7 +1347,9 @@ def test_board(board): # default to all tests test_list = [] - if len(test_only) > 0: + if name in board_test: + test_list = board_test[name] + elif len(test_only) > 0: test_list = test_only else: if 'tests' in board: @@ -1366,19 +1369,23 @@ def test_board(board): print(f'{name:25} {skip:30} ... Skip') err_count = 0 + failed_tests = [] flags_on_list = [""] if 'build' in board and 'flags_on' in board['build']: flags_on_list = board['build']['flags_on'] for f1 in flags_on_list: for test in test_list: - err_count += test_example(board, f1, test) + ec = test_example(board, f1, test) + err_count += ec + if ec > 0: + failed_tests.append(test) # flash board_test last to disable board's usb (skipped when --skip-flash is set) if not skip_flash: test_example(board, flags_on_list[0], 'device/board_test') - return name, err_count + return name, err_count, sorted(set(failed_tests)) def main(): @@ -1387,6 +1394,7 @@ def main(): """ global verbose global test_only + global board_test global build_dir global max_retry global skip_flash @@ -1399,6 +1407,8 @@ def main(): parser.add_argument('-s', '--skip-board', action='append', default=[], help='Skip boards from test') parser.add_argument('-sf', '--skip-flash', action='store_true', help='Run tests without flashing firmware (use whatever is already on the board)') parser.add_argument('-t', '--test-only', action='append', default=[], help='Tests to run, all if not specified') + parser.add_argument('-bt', '--board-test', action='append', default=[], + help='Per-board test list as BOARD:test1,test2 (overrides -t for that board); repeat for multiple boards') parser.add_argument('-B', '--build-dir', default='cmake-build', help='Build folder name (default: cmake-build)') parser.add_argument('--build', action='store_true', help='Build firmware for selected boards with cmake before running tests') parser.add_argument('-r', '--retry', type=int, default=3, help='Retry count for failed tests (default: 3)') @@ -1410,6 +1420,11 @@ def main(): skip_boards = args.skip_board verbose = args.verbose test_only = args.test_only + for entry in args.board_test: + bname, _, tnames = entry.partition(':') + if not bname or not tnames: + parser.error(f'invalid --board-test value: {entry!r} (expected BOARD:test1,test2)') + board_test[bname] = [t for t in tnames.split(',') if t] build_dir = args.build_dir max_retry = args.retry skip_flash = args.skip_flash @@ -1443,12 +1458,15 @@ def main(): with Pool(processes=os.cpu_count()) as pool: mret = pool.map(test_board, config_boards) err_count = build_err + sum(e[1] for e in mret) - # generate skip list for next re-run if failed + # generate skip list for next re-run if failed: skip boards that fully passed, + # and emit -bt BOARD:t1,t2 so each failed board only re-runs its own failed tests. skip_fname = f'{config_file}.skip' if err_count > 0: - skip_boards += [name for name, err in mret if err == 0] + skip_boards += [name for name, err, _ in mret if err == 0] + parts = [f'--skip-board {i}' for i in skip_boards] + parts += [f'-bt {name}:{",".join(fts)}' for name, err, fts in mret if err > 0 and fts] with open(skip_fname, 'w') as f: - f.write(' '.join(f'--skip-board {i}' for i in skip_boards)) + f.write(' '.join(parts)) elif os.path.exists(skip_fname): os.remove(skip_fname) diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index e7cd435fa..a3f7ff8bf 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -183,11 +183,6 @@ "tests": { "device": false, "host": true, "dual": false, "dev_attached": [ - { - "vid_pid": "1a86_55d4", - "serial": "52D2002694", - "is_cdc": true - }, { "vid_pid": "0951_1603", "serial": "820000000000000045B46338", -- cgit v1.3.1 From fc0747c2a7c04b25b640bfb5acce711fa39f8443 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 4 May 2026 19:39:46 +0700 Subject: hil remove hub from pico native host test for now --- test/hil/tinyusb.json | 5 ----- 1 file changed, 5 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index a3f7ff8bf..aed711f80 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -155,11 +155,6 @@ "tests": { "device": false, "host": true, "dual": false, "dev_attached": [ - { - "vid_pid": "1a86_55d4", - "serial": "52D2023934", - "is_cdc": true - }, { "vid_pid": "2008_2018", "serial": "O20070925A002746", -- cgit v1.3.1 From 460ce56f40d962ebf8a2d7be9f436a9756efb9fe Mon Sep 17 00:00:00 2001 From: HiFiPhile Date: Tue, 12 May 2026 22:18:05 +0200 Subject: hil: add audio test, optimize log print Signed-off-by: HiFiPhile --- test/hil/hil_test.py | 202 ++++++++++++++++++++++++++++++++++++++++++-------- test/hil/tinyusb.json | 4 +- 2 files changed, 174 insertions(+), 32 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 5d9aa8431..ed9ebbf1a 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -27,6 +27,7 @@ # ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb", ENV{ID_FS_USAGE}=="filesystem", MODE="0666", PROGRAM="/bin/sh -c 'echo $$ID_SERIAL_SHORT | rev | cut -c -8 | rev'", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode /media/blkUSB_%c.%s{bInterfaceNumber}" import argparse +import io import os import random import re @@ -35,6 +36,7 @@ import sys import time import warnings import signal +from contextlib import redirect_stdout from pathlib import Path from typing import Any, TypedDict, NotRequired, cast @@ -47,7 +49,8 @@ import serial import subprocess import json import glob -from multiprocessing import Pool +import shutil +from multiprocessing import Pool, Lock from multiprocessing import TimeoutError as MpTimeoutError import fs import hashlib @@ -66,6 +69,28 @@ test_only = [] board_test = {} build_dir = 'cmake-build' skip_flash = False +print_lock = None + + +def init_worker(lock): + global print_lock + print_lock = lock + + +def log_line(msg: str) -> None: + out = sys.__stdout__ if sys.__stdout__ is not None else sys.stdout + if print_lock is not None: + with print_lock: + print(msg, file=out, flush=True) + else: + print(msg, file=out, flush=True) + + +def compact_output(raw: str) -> str: + if not raw: + return '' + lines = [ln.strip() for ln in raw.replace('\r', '\n').split('\n') if ln.strip()] + return ' | '.join(lines) class FlasherCfg(TypedDict): name: str @@ -174,6 +199,19 @@ def get_hid_dev(id, vendor_str, product_str, event): return f'/dev/input/by-id/usb-{vendor_str}_{product_str}_{id}-{event}' +def get_alsa_capture_dev(id): + pattern = f'/dev/snd/by-id/usb-*_{id}-*' + for dev in glob.glob(pattern): + try: + link = os.path.basename(os.path.realpath(dev)) + except OSError: + continue + m = re.match(r'controlC(\d+)', link) + if m: + return f'hw:{m.group(1)},0' + return None + + def open_serial_dev(port: str): timeout = ENUM_TIMEOUT ser = None @@ -1289,6 +1327,79 @@ def test_device_midi_test(board): assert n in note_sequence, f'Unexpected MIDI note {n}' +def test_device_audio_test_freertos(board): + uid = board['uid'] + + if os.name == 'nt': + return 'skipped' + + arecord = shutil.which('arecord') + if arecord is None: + return 'skipped' + + pcm = None + timeout = ENUM_TIMEOUT + while timeout > 0: + pcm = get_alsa_capture_dev(uid) + if pcm: + break + time.sleep(1) + timeout -= 1 + + assert pcm is not None, f'ALSA capture device not found for {uid}' + + raw_path = f'/tmp/tinyusb_audio_{uid}.raw' + cmd = [ + arecord, + '-D', pcm, + '-q', + '-f', 'S16_LE', + '-c', '1', + '-r', '48000', + '-d', '2', + '-t', 'raw', + raw_path, + ] + + ret = subprocess.run(cmd, capture_output=True, text=True, timeout=20) + assert ret.returncode == 0, f'arecord failed: {ret.stderr.strip() or ret.stdout.strip()}' + + try: + with open(raw_path, 'rb') as f: + raw = f.read() + finally: + try: + os.remove(raw_path) + except OSError: + pass + + assert len(raw) >= 48000, f'Captured too little audio: {len(raw)} bytes' + assert (len(raw) % 2) == 0, f'Invalid 16-bit audio length: {len(raw)}' + + sample_count = len(raw) // 2 + samples = [int.from_bytes(raw[i:i + 2], 'little', signed=False) for i in range(0, len(raw), 2)] + assert sample_count > 1024, f'Not enough samples captured: {sample_count}' + + # The firmware sends a continuous uint16 ramp. Using ALSA hw: capture bypasses + # PulseAudio processing, so most adjacent samples should differ by exactly 1. + total_diffs = sample_count - 1 + one_step = 0 + near_step = 0 + for i in range(total_diffs): + d = (samples[i + 1] - samples[i]) & 0xFFFF + if d == 1: + one_step += 1 + if d in (0, 1, 2, 47, 48, 49): + near_step += 1 + + one_ratio = one_step / total_diffs + near_ratio = near_step / total_diffs + assert one_ratio >= 0.85, f'Unexpected audio pattern (strict ratio={one_ratio:.3f})' + assert near_ratio >= 0.98, f'Unexpected audio pattern (relaxed ratio={near_ratio:.3f})' + + print(f' ALSA {pcm} strict={one_ratio:.3f} relaxed={near_ratio:.3f}', end='') + + def test_device_hid_generic_inout(board): uid = board['uid'] import hid @@ -1335,6 +1446,7 @@ device_tests = [ 'device/dfu', 'device/cdc_msc', 'device/cdc_msc_throughput', + 'device/audio_test_freertos', 'device/dfu_runtime', 'device/cdc_msc_freertos', 'device/hid_boot_interface', @@ -1374,47 +1486,76 @@ def test_example(board: Board, f1: str, example: str) -> int: fw_dir = TINYUSB_ROOT / build_dir / f'cmake-build-{name}{f1_str}' / example fw_name = fw_dir / Path(example).name - print(f'{name+f1_str:40} {example:30} ...', end='') + test_name = f'{name+f1_str:40} {example:30} ...' if not fw_dir.exists() or not ((fw_name.with_suffix('.elf')).exists() or (fw_name.with_suffix('.bin')).exists()): - print('Skip (no binary)') + log_line(f'{test_name} Skip (no binary)') return 0 if verbose: - print(f'Flashing {fw_name}.elf') + log_line(f'Flashing {fw_name}.elf') # flash firmware (unless --skip-flash), then run the test. Both may fail randomly, # retry a few times. start_s = time.time() flash_ok = True + last_err = '' + last_detail = '' for i in range(max_retry): - if not skip_flash: - ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, str(fw_name)) - flash_ok = (ret.returncode == 0) - if flash_ok: - try: - tret = globals()[f'test_{example.replace("/", "_")}'](board) - if tret == 'skipped': - print(f' {STATUS_SKIPPED}', end='') - else: - print(' OK', end='') - break - except Exception as e: - if i == max_retry - 1: - err_count += 1 - print(f'{STATUS_FAILED}: {e}') - else: - print(f'\n Test failed: {e}, retry {i+2}/{max_retry}', end='') - time.sleep(0.5) - else: - print(f'\n Flash failed, retry {i+2}/{max_retry}', end='') - time.sleep(0.5) + attempt_out = io.StringIO() + with redirect_stdout(attempt_out): + if not skip_flash: + ret = globals()[f'flash_{board["flasher"]["name"].lower()}'](board, str(fw_name)) + flash_ok = (ret.returncode == 0) + if flash_ok: + try: + tret = globals()[f'test_{example.replace("/", "_")}'](board) + last_detail = compact_output(attempt_out.getvalue()) + if tret == 'skipped': + status = STATUS_SKIPPED + else: + status = STATUS_OK + msg = f'{test_name} {status}' + if last_detail: + msg += f' {last_detail}' + msg += f' in {time.time() - start_s:.1f}s' + log_line(msg) + break + except Exception as e: + last_err = str(e) + last_detail = compact_output(attempt_out.getvalue()) + if i == max_retry - 1: + err_count += 1 + msg = f'{test_name} {STATUS_FAILED}: {e}' + if last_detail: + msg += f' {last_detail}' + msg += f' in {time.time() - start_s:.1f}s' + log_line(msg) + else: + msg = f'{test_name} retry {i+2}/{max_retry}: test failed: {e}' + if last_detail: + msg += f' {last_detail}' + log_line(msg) + time.sleep(0.5) + else: + last_err = 'Flash failed' + last_detail = compact_output(attempt_out.getvalue()) + if i < max_retry - 1: + msg = f'{test_name} retry {i+2}/{max_retry}: flash failed' + if last_detail: + msg += f' {last_detail}' + log_line(msg) + time.sleep(0.5) if not flash_ok: err_count += 1 - print(f' Flash {STATUS_FAILED}', end='') - - print(f' in {time.time() - start_s:.1f}s') + msg = f'{test_name} Flash {STATUS_FAILED}' + if last_err: + msg += f': {last_err}' + if last_detail: + msg += f' {last_detail}' + msg += f' in {time.time() - start_s:.1f}s' + log_line(msg) return err_count @@ -1471,7 +1612,7 @@ def test_board(board: Board) -> tuple[str, int, list[str]]: for skip in board_tests['skip']: if skip in test_list: test_list.remove(skip) - print(f'{name:25} {skip:30} ... Skip') + log_line(f'{name:25} {skip:30} ... Skip') err_count = 0 failed_tests = [] @@ -1560,7 +1701,7 @@ def main() -> None: print(f'Build phase done: {build_err} failed') print('-' * 30) - with Pool(processes=os.cpu_count() or 1) as pool: + with Pool(processes=os.cpu_count() or 1, initializer=init_worker, initargs=(Lock(),)) as pool: async_ret = pool.map_async(test_board, config_boards) try: mret = async_ret.get(timeout=POOL_TIMEOUT) @@ -1568,6 +1709,7 @@ def main() -> None: pool.terminate() pool.join() raise RuntimeError(f'HIL worker pool timed out after {POOL_TIMEOUT}s') + err_count = build_err + sum(e[1] for e in mret) # generate skip list for next re-run if failed: skip boards that fully passed, # and emit -bt BOARD:t1,t2 so each failed board only re-runs its own failed tests. diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index aed711f80..cba7677cf 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -7,7 +7,7 @@ "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"] }, "tests": { - "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], + "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "device/audio_test_freertos", "host/device_info"], "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427", "is_cdc": true}] }, "flasher": { @@ -25,7 +25,7 @@ "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"] }, "tests": { - "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "host/device_info"], + "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "device/audio_test_freertos", "host/device_info"], "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402", "is_cdc": true}] }, "flasher": { -- cgit v1.3.1 From f4d0d09c8ee06a3531c39032cbe102976aeca349 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 21 May 2026 18:18:25 +0700 Subject: hil added hub + msc + cdc for host capable board --- test/hil/hil_ci.sh | 10 +- test/hil/hil_test.py | 5 + test/hil/requirements.txt | 1 + test/hil/tinyusb.json | 236 +++++++++++++++++++++++++++++++++++++--------- 4 files changed, 208 insertions(+), 44 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/hil_ci.sh b/test/hil/hil_ci.sh index 96872e2e1..35e71f1ba 100644 --- a/test/hil/hil_ci.sh +++ b/test/hil/hil_ci.sh @@ -54,11 +54,14 @@ scp -q "$ROOT_DIR/test/hil/hil_test.py" \ "$CONFIG" \ "$REMOTE:$REMOTE_DIR/test/hil/" -# Copy only firmware binaries (elf/bin/hex), preserving directory structure +# Copy only firmware binaries (elf/bin/hex) plus esptool metadata +# (config.env + flash_args needed by the esptool flasher), preserving structure copy_board_binaries() { local src="$1" rsync -a --prune-empty-dirs \ - --include='*/' --include='*.elf' --include='*.bin' --include='*.hex' --exclude='*' \ + --include='*/' --include='*.elf' --include='*.bin' --include='*.hex' \ + --include='config.env' --include='flash_args' \ + --exclude='*' \ "$src" "$REMOTE:$REMOTE_DIR/examples/" } @@ -85,5 +88,8 @@ echo "==> Running HIL test on $REMOTE" ssh "$REMOTE" bash -s -- "$REMOTE_DIR" "${ARGS[@]}" "test/hil/$CONFIG_BASENAME" <<'REMOTE' cd -- "$1" shift +# esptool/idf tools live in ~/.local/bin on ci.lan; the non-interactive shell +# subprocess used for flashing doesn't pick that up otherwise. +export PATH="$HOME/.local/bin:$PATH" exec python3 -u test/hil/hil_test.py -B examples "$@" REMOTE diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index ed9ebbf1a..d921a910a 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -796,6 +796,10 @@ def test_host_msc_file_explorer(board): ser.close() +def test_host_msc_file_explorer_freertos(board): + return test_host_msc_file_explorer(board) + + # ------------------------------------------------------------- # Tests: device # ------------------------------------------------------------- @@ -1465,6 +1469,7 @@ dual_tests = [ host_test = [ 'host/cdc_msc_hid', 'host/msc_file_explorer', + 'host/msc_file_explorer_freertos', 'host/device_info', ] diff --git a/test/hil/requirements.txt b/test/hil/requirements.txt index ef2fecebe..127f6a8ec 100644 --- a/test/hil/requirements.txt +++ b/test/hil/requirements.txt @@ -2,3 +2,4 @@ fs hid pyfatfs pyserial +esptool diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index cba7677cf..dc28df7b9 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -3,12 +3,35 @@ { "name": "espressif_p4_function_ev", "uid": "6055F9F98715", - "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"] + "build": { + "flags_on": [ + "", + "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE" + ] }, "tests": { - "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "device/audio_test_freertos", "host/device_info"], - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2002427", "is_cdc": true}] + "only": [ + "device/cdc_msc_freertos", + "device/hid_composite_freertos", + "device/audio_test_freertos", + "host/device_info", + "host/msc_file_explorer_freertos" + ], + "dev_attached": [ + { + "vid_pid": "1a86_55d4", + "serial": "52D2002427", + "is_cdc": true + }, + { + "vid_pid": "21c4_0cc7", + "serial": "900058944CB80A53", + "is_msc": true, + "block_size": 512, + "block_count": 60620800, + "msc_inquiry": "Lexar USB Flash Drive PMAP" + } + ] }, "flasher": { "name": "esptool", @@ -21,12 +44,36 @@ { "name": "espressif_s3_devkitm", "uid": "84F703C084E4", - "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE"] + "build": { + "flags_on": [ + "", + "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE" + ] }, "tests": { - "only": ["device/cdc_msc_freertos", "device/hid_composite_freertos", "device/audio_test_freertos", "host/device_info"], - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2005402", "is_cdc": true}] + "only": [ + "device/cdc_msc_freertos", + "device/hid_composite_freertos", + "device/audio_test_freertos", + "host/device_info", + "host/msc_file_explorer_freertos" + ], + "dev_attached": [ + { + "vid_pid": "1a86_55d4", + "serial": "52D2005402", + "is_cdc": true + }, + { + "vid_pid": "048d_04d2", + "serial": "\u0409", + "is_msc": true, + "block_size": 512, + "block_count": 30720000, + "msc_inquiry": "General UDisk 5.00", + "comment": "General UDisk reports iSerialNumber=U+0409" + } + ] }, "flasher": { "name": "esptool", @@ -39,7 +86,9 @@ "name": "feather_nrf52840_express", "uid": "1F0479CD0F764471", "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "jlink", @@ -51,7 +100,9 @@ "name": "max32666fthr", "uid": "0C81464124010B20FF0A08CC2C", "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "openocd_adi", @@ -71,7 +122,13 @@ "device": true, "host": false, "dual": true, - "dev_attached": [{"vid_pid": "067b_2303", "serial": "0", "is_cdc": true}], + "dev_attached": [ + { + "vid_pid": "067b_2303", + "serial": "0", + "is_cdc": true + } + ], "comment": "pl23x" }, "flasher": { @@ -84,7 +141,9 @@ "name": "mimxrt1015_evk", "uid": "DC28F865D2111D228D00B0543A70463C", "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "jlink", @@ -96,9 +155,25 @@ "name": "mimxrt1064_evk", "uid": "BAE96FB95AFA6DBB8F00005002001200", "tests": { - "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "10c4_ea60", "serial": "0001", "is_cdc": true}], - "comment": "cp2102" + "device": true, + "host": true, + "dual": true, + "dev_attached": [ + { + "vid_pid": "10c4_ea60", + "serial": "0001", + "is_cdc": true, + "comment": "cp2102" + }, + { + "vid_pid": "21c4_0cc7", + "serial": "900058874D871F66", + "is_msc": true, + "block_size": 512, + "block_count": 60620800, + "msc_inquiry": "Lexar USB Flash Drive PMAP" + } + ] }, "flasher": { "name": "jlink", @@ -110,7 +185,9 @@ "name": "lpcxpresso11u37", "uid": "17121919", "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "jlink", @@ -135,13 +212,32 @@ { "name": "raspberry_pi_pico", "uid": "E6614C311B764A37", - "build" : { - "flags_on": ["CFG_TUH_RPI_PIO_USB"] + "build": { + "flags_on": [ + "CFG_TUH_RPI_PIO_USB" + ] }, "tests": { - "device": true, "host": true, "dual": true, - "dev_attached": [{"vid_pid": "1a86_7523", "serial": "0", "is_cdc": true}], - "comment": "ch34x" + "device": true, + "host": true, + "dual": true, + "dev_attached": [ + { + "vid_pid": "1a86_7523", + "serial": "0", + "is_cdc": true, + "comment": "ch34x" + }, + { + "vid_pid": "048d_04d2", + "serial": "\u0409", + "is_msc": true, + "block_size": 512, + "block_count": 30720000, + "msc_inquiry": "General UDisk 5.00", + "comment": "General UDisk reports iSerialNumber=U+0409" + } + ] }, "flasher": { "name": "openocd", @@ -153,8 +249,15 @@ "name": "raspberry_pi_pico_w", "uid": "E6614864D35DAE36", "tests": { - "device": false, "host": true, "dual": false, + "device": false, + "host": true, + "dual": false, "dev_attached": [ + { + "vid_pid": "1a86_55d4", + "serial": "52D2002694", + "is_cdc": true + }, { "vid_pid": "2008_2018", "serial": "O20070925A002746", @@ -176,7 +279,9 @@ "name": "raspberry_pi_pico2", "uid": "560AE75E1C7152C9", "tests": { - "device": false, "host": true, "dual": false, + "device": false, + "host": true, + "dual": false, "dev_attached": [ { "vid_pid": "0951_1603", @@ -184,7 +289,7 @@ "is_msc": true, "block_size": 512, "block_count": 3987456, - "msc_inquiry": "Kingston DataTraveler 2.0 1.0" + "msc_inquiry": "Kingston DataTraveler 2.0 1.00" } ] }, @@ -202,14 +307,24 @@ "host": true, "dual": true, "dev_attached": [ - {"vid_pid": "0403_6001", "serial": "0", "is_cdc": true}, - {"vid_pid": "058f_6387", "serial": "A8BEE062633D", "is_msc": true, - "block_size": 512, "block_count": 7639040, "msc_inquiry": "Generic Flash Disk 8.07"} + { + "vid_pid": "0403_6001", + "serial": "0", + "is_cdc": true + }, + { + "vid_pid": "058f_6387", + "serial": "A8BEE062633D", + "is_msc": true, + "block_size": 512, + "block_count": 7639040, + "msc_inquiry": "Generic Flash Disk 8.07" + } ] }, "flasher": { "name": "openocd", - "uid": "E6614103E78E8324", + "uid": "E663AC91D3359B38", "args": "-f interface/cmsis-dap.cfg -f target/rp2350.cfg -c \"adapter speed 5000\"" } }, @@ -217,7 +332,9 @@ "name": "stm32f072disco", "uid": "3A001A001357364230353532", "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "jlink", @@ -229,12 +346,31 @@ { "name": "stm32f723disco", "uid": "460029001951373031313335", - "build" : { - "flags_on": ["", "CFG_TUH_DWC2_DMA_ENABLE"] + "build": { + "flags_on": [ + "", + "CFG_TUH_DWC2_DMA_ENABLE" + ] }, "tests": { - "device": true, "host": true, "dual": false, - "dev_attached": [{"vid_pid": "1a86_55d4", "serial": "52D2003414", "is_cdc": true}] + "device": true, + "host": true, + "dual": false, + "dev_attached": [ + { + "vid_pid": "1a86_55d4", + "serial": "52D2003414", + "is_cdc": true + }, + { + "vid_pid": "21c4_0cc7", + "serial": "90005893730A1A63", + "is_msc": true, + "block_size": 512, + "block_count": 60620800, + "msc_inquiry": "Lexar USB Flash Drive PMAP" + } + ] }, "flasher": { "name": "jlink", @@ -246,11 +382,16 @@ { "name": "stm32h743nucleo", "uid": "110018000951383432343236", - "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"] + "build": { + "flags_on": [ + "", + "CFG_TUD_DWC2_DMA_ENABLE" + ] }, "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "openocd", @@ -262,7 +403,9 @@ "name": "stm32g0b1nucleo", "uid": "4D0038000450434E37343120", "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "openocd", @@ -276,11 +419,16 @@ { "name": "stm32f769disco", "uid": "21002F000F51363531383437", - "build" : { - "flags_on": ["", "CFG_TUD_DWC2_DMA_ENABLE"] + "build": { + "flags_on": [ + "", + "CFG_TUD_DWC2_DMA_ENABLE" + ] }, "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "jlink", @@ -292,7 +440,9 @@ "name": "nanoch32v203", "uid": "CDAB277B0FBC03E339E339E3", "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "openocd_wch", @@ -304,7 +454,9 @@ "name": "stm32f407disco", "uid": "30001A000647313332353735", "tests": { - "device": true, "host": false, "dual": false + "device": true, + "host": false, + "dual": false }, "flasher": { "name": "jlink", -- cgit v1.3.1 From e45d5ad528e82d6d4323c5c23c6f489fe0e02dc6 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 3 Jun 2026 23:13:17 +0700 Subject: Add STM32F407 and STM32L476 disco board configurations to tinyusb.json --- test/hil/tinyusb.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index dc28df7b9..c0a35ddc2 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -343,6 +343,20 @@ }, "comment": "2x16 access scheme with 1KB USB SRAM" }, + { + "name": "stm32f407disco", + "uid": "30001A000647313332353735", + "tests": { + "device": true, + "host": false, + "dual": false + }, + "flasher": { + "name": "jlink", + "uid": "000773661813", + "args": "-device stm32f407vg" + } + }, { "name": "stm32f723disco", "uid": "460029001951373031313335", @@ -413,6 +427,20 @@ "args": "-f interface/stlink.cfg -f target/stm32g0x.cfg" }, "comment": "32-bit scheme, 2KB USB SRAM" + }, + { + "name": "stm32l476disco", + "uid": "3C0050001150334258343920", + "tests": { + "device": true, + "host": false, + "dual": false + }, + "flasher": { + "name": "jlink", + "uid": "777632258", + "args": "-device STM32L476VG" + } } ], "boards-skip": [ -- cgit v1.3.1 From 1f6236ae0788e37bb833e4b018faf10fb691bbdd Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 3 Jun 2026 23:41:19 +0700 Subject: dwc2: address Copilot review (comment grammar/typo, tinyusb.json f407 dedup) Co-Authored-By: Claude Opus 4.8 (1M context) --- src/portable/synopsys/dwc2/dcd_dwc2.c | 6 +++--- test/hil/tinyusb.json | 14 -------------- 2 files changed, 3 insertions(+), 17 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c index ac35eb951..bab7118dd 100644 --- a/src/portable/synopsys/dwc2/dcd_dwc2.c +++ b/src/portable/synopsys/dwc2/dcd_dwc2.c @@ -918,7 +918,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { } case GRXSTS_PKTSTS_SETUP_DONE: { - // Pop this word cause Setup interrupt + // Pop this word causes the Setup interrupt epout->doeptsiz |= (3 << DOEPTSIZ_STUPCNT_Pos); epout->doepint = DOEPINT_SETUP | DOEPINT_STPKTRX; // Clear SETUP interrupt, required for core to re-write this control word if (edpt_is_enabled(&dwc2->epin[0])) { @@ -955,7 +955,7 @@ static void handle_rxflvl_irq(uint8_t rhport) { } case GRXSTS_PKTSTS_RX_COMPLETE: { - // Pop this word cause xfer complete interrupt + // Pop this word causes the xfer complete interrupt const uint32_t doepint = epout->doepint; epout->doepint = DOEPINT_XFRC; @@ -1108,7 +1108,7 @@ static void handle_ep_irq(uint8_t rhport, uint8_t dir) { if (dir == TUSB_DIR_IN) { handle_epin_slave(rhport, epnum, intr.diepint_bm); } else { - // epout is handled in rxflv + // epout is handled in handle_rxflvl_irq } #endif } diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index c0a35ddc2..467b7378a 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -477,20 +477,6 @@ "uid": "EBCA8F0670AF", "args": "" } - }, - { - "name": "stm32f407disco", - "uid": "30001A000647313332353735", - "tests": { - "device": true, - "host": false, - "dual": false - }, - "flasher": { - "name": "jlink", - "uid": "000773661813", - "args": "-device stm32f407vg" - } } ] } -- cgit v1.3.1 From 1009b14b02232adc70a0a5a5ed4a3a06118fef0d Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Fri, 5 Jun 2026 21:23:40 +0700 Subject: add tm4c123x evk to hill pool (#3676) * add ek_tm4c123gxl to the hil pool, flashing with lm4flash --- hw/bsp/family_support.cmake | 20 ++++++++++++++++++++ hw/bsp/tm4c/family.cmake | 4 ++-- test/hil/hil_test.py | 13 +++++++++++++ test/hil/tinyusb.json | 14 ++++++++++++++ 4 files changed, 49 insertions(+), 2 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index 07d693d77..af2716b28 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -900,6 +900,26 @@ function(family_flash_uniflash TARGET) #set_property(TARGET ${TARGET}-uniflash PROPERTY FOLDER ${TARGET}-group) endfunction() +# Add flash lm4flash target (lightweight flasher for TI Tiva-C/Stellaris ICDI boards) +function(family_flash_lm4flash TARGET) + if (NOT DEFINED LM4FLASH) + set(LM4FLASH lm4flash) + endif () + + if (NOT DEFINED LM4FLASH_OPTION) + set(LM4FLASH_OPTION "") + endif () + separate_arguments(OPTION_LIST UNIX_COMMAND ${LM4FLASH_OPTION}) + + add_custom_target(${TARGET}-lm4flash + DEPENDS ${TARGET} + COMMAND ${LM4FLASH} ${OPTION_LIST} $/${TARGET}.bin + VERBATIM + ) + + #set_property(TARGET ${TARGET}-lm4flash PROPERTY FOLDER ${TARGET}-group) +endfunction() + # Add flash ft9xx target need to remove kernal's ftdi_sio and bind D2XX drivers # sudo rmmod ftdi_sio && for i in 0 1 2 3; do sudo sh -c "echo 3-3.4:1.$i > /sys/bus/usb/drivers/ftdi_sio/unbind" 2>/dev/null; done function(family_flash_ft9xx TARGET) diff --git a/hw/bsp/tm4c/family.cmake b/hw/bsp/tm4c/family.cmake index 41b8a597a..ce7c62409 100644 --- a/hw/bsp/tm4c/family.cmake +++ b/hw/bsp/tm4c/family.cmake @@ -79,6 +79,6 @@ function(family_configure_example TARGET RTOS) # Flashing family_add_bin_hex(${TARGET}) family_flash_jlink(${TARGET}) - family_flash_openocd(${TARGET}) - family_flash_uniflash(${TARGET}) + family_flash_lm4flash(${TARGET}) + # family_flash_uniflash(${TARGET}) endfunction() diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index b0b3fc17e..609199d1b 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -496,6 +496,19 @@ def reset_uniflash(board): return subprocess.CompletedProcess(args=['dummy'], returncode=0) +def flash_lm4flash(board, firmware): + # TI Tiva-C / Stellaris ICDI: lightweight lm4flash, resets and runs after write + flasher = board['flasher'] + ret = run_cmd(f'lm4flash -s {flasher["uid"]} {flasher["args"]} {firmware}.bin') + return ret + + +def reset_lm4flash(board): + # lm4flash has no reset-only mode; it resets+runs on flash, so reset is a no-op + flasher = board['flasher'] + return subprocess.CompletedProcess(args=['dummy'], returncode=0) + + # ------------------------------------------------------------- # Tests: dual # ------------------------------------------------------------- diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 467b7378a..79b2645c7 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -1,5 +1,19 @@ { "boards": [ + { + "name": "ek_tm4c123gxl", + "uid": "010105186C60A110", + "tests": { + "device": true, + "host": false, + "dual": false + }, + "flasher": { + "name": "lm4flash", + "uid": "0E205D19", + "args": "-v" + } + }, { "name": "espressif_p4_function_ev", "uid": "6055F9F98715", -- cgit v1.3.1 From d2e7bbb0855a3ff3d6393c7d7edd755cfd3362df Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 8 Jun 2026 14:35:07 +0700 Subject: test/hil: add stm32u083nucleo to pool and expose ~/bin on remote PATH Add stm32u083nucleo to the active boards in tinyusb.json, flashed via the stlink flasher (onboard ST-Link + STM32CubeProgrammer); ci's openocd build has no STM32U0 flash driver. STM32_Programmer_CLI lives in ~/bin on ci, which the remote `bash -s` shell in hil_ci.sh did not have on PATH, so add $HOME/bin to its PATH export (matching the GHA runner .path). Verified remote: 13/13 device tests pass on ci.lan. Co-Authored-By: Claude Opus 4.8 (1M context) --- test/hil/hil_ci.sh | 7 ++++--- test/hil/tinyusb.json | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/hil_ci.sh b/test/hil/hil_ci.sh index 4c7ba2936..4bb459af3 100644 --- a/test/hil/hil_ci.sh +++ b/test/hil/hil_ci.sh @@ -91,8 +91,9 @@ echo "==> Running HIL test on $REMOTE" ssh "$REMOTE" bash -s -- "$REMOTE_DIR" "${ARGS[@]}" "test/hil/$CONFIG_BASENAME" <<'REMOTE' cd -- "$1" shift -# esptool/idf tools live in ~/.local/bin on ci.lan; the non-interactive shell -# subprocess used for flashing doesn't pick that up otherwise. -export PATH="$HOME/.local/bin:$PATH" +# Flasher CLIs live in the user bin dirs on ci.lan (esptool/idf in ~/.local/bin, +# STM32CubeProgrammer's STM32_Programmer_CLI in ~/bin); the non-interactive shell +# subprocess used for flashing doesn't source profile/rc, so add them explicitly. +export PATH="$HOME/.local/bin:$HOME/bin:$PATH" exec python3 -u test/hil/hil_test.py -B examples "$@" REMOTE diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 79b2645c7..319ee9a79 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -455,6 +455,19 @@ "uid": "777632258", "args": "-device STM32L476VG" } + }, + { + "name": "stm32u083nucleo", + "uid": "300044000D5036394E373620", + "tests": { + "device": true, + "host": false, + "dual": false + }, + "flasher": { + "name": "stlink", + "uid": "0668FF575457657187061314" + } } ], "boards-skip": [ -- cgit v1.3.1 From 6f35e76667f4015ef429ace5730e20cc0037e042 Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Thu, 11 Jun 2026 08:16:43 +0700 Subject: HIL: replace build.flags_on with named build variants (#3687) * test/hil: replace build.flags_on with named variant schema Boards declare build variants as `variant: [{name, flags}]` instead of `build.flags_on`. The variant `name` is the build dir (cmake-build-) and the HIL report row; `flags` is the raw CFLAGS string (-D...=1) injected via CFLAGS_CLI. No `variant` => a single build named after the board. - build.py: --build-name (dir) + --cflag= (raw CFLAGS, repeatable, =form survives the matrix's shell word-splitting); drop -f1/CFLAGS wrapping. - hil_ci_set_matrix.py: emit one build arg per variant. - hil_test.py: iterate variants; report row + build dir = variant name. - hil_ci.sh: copy all cmake-build-* dirs for -b runs. - get_deps.py: accept (ignore) --build-name/--cflag from matrix args. - tinyusb.json: migrate all 6 flags_on boards to variant. * board_test: park CI build with busy spin instead of wfe --- .github/workflows/build.yml | 10 ++++- examples/device/board_test/src/main.c | 50 ++++++++++--------------- test/hil/hfp.json | 4 ++ test/hil/hil_ci.sh | 39 +++++++++++++++++--- test/hil/hil_ci_set_matrix.py | 26 ++++++------- test/hil/hil_test.py | 69 ++++++++++++++++++----------------- test/hil/tinyusb.json | 58 ++++++++++++----------------- tools/build.py | 30 +++++++++------ tools/get_deps.py | 2 + 9 files changed, 157 insertions(+), 131 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e22ba909c..a7c7cf99a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -397,7 +397,15 @@ jobs: run: python3 tools/get_deps.py $BUILD_ARGS - name: Build - run: python3 tools/build.py --toolchain iar $BUILD_ARGS + run: | + # Each variant carries its own --build-name/--cflag, which are global to a + # single build.py invocation — so build one matrix entry at a time rather + # than joining them (joining would leak a variant's flags onto every board). + readarray -t ENTRIES < <(python test/hil/hil_ci_set_matrix.py test/hil/hfp.json | jq -r '.["arm-gcc"][]') + for entry in "${ENTRIES[@]}"; do + echo "+ tools/build.py --toolchain iar $entry" + python3 tools/build.py --toolchain iar $entry + done - name: Test on actual hardware (hardware in the loop) run: | diff --git a/examples/device/board_test/src/main.c b/examples/device/board_test/src/main.c index 3d8cf9979..96dc1bd30 100644 --- a/examples/device/board_test/src/main.c +++ b/examples/device/board_test/src/main.c @@ -57,8 +57,16 @@ void tusb_time_delay_ms_api(uint32_t ms) { // CI_BUILD (defined for all CI builds, see hw/bsp/family_support.cmake) skips the // blink/echo loop below: after HIL tests, this firmware is flashed to park the // board in a quiet, low-power idle state (no USB, LED, or UART activity). -#ifndef CI_BUILD +#ifdef CI_BUILD +int main(void) { + while (1) { + #if defined(ESP_PLATFORM) + vTaskDelay(portMAX_DELAY); + #endif + } +} +#else // Task parameter type: ULONG for ThreadX, void* for FreeRTOS and noos #if CFG_TUSB_OS == OPT_OS_THREADX #define RTOS_PARAM ULONG @@ -112,46 +120,21 @@ static void board_test_loop(RTOS_PARAM param) { } } -#endif // CI_BUILD - int main(void) { -#ifdef CI_BUILD - // Park the board in a quiet, low-power idle loop. board_init() is intentionally - // skipped: no clocks, peripherals, USB, LED, or UART are brought up, so the MCU - // just idles after CI flashes this over a board's previous test firmware. - while (1) { - #if defined(ESP_PLATFORM) - vTaskDelay(portMAX_DELAY); // ESP runs FreeRTOS: yield this task indefinitely - #elif defined(__ARM_ARCH) || defined(__arm__) - __asm volatile("wfe"); // Cortex-M: sleep until an event - #else - // other architectures (e.g. RISC-V): spin - #endif - } - // no return: the loop never exits (an unreachable return trips IAR's Pe111) -#else board_init(); board_led_write(true); - #if CFG_TUSB_OS == OPT_OS_FREERTOS +#if CFG_TUSB_OS == OPT_OS_FREERTOS freertos_init(); - #elif CFG_TUSB_OS == OPT_OS_THREADX +#elif CFG_TUSB_OS == OPT_OS_THREADX tx_kernel_enter(); - #else +#else board_test_loop(NULL); - #endif - - return 0; #endif -} -#ifdef ESP_PLATFORM -void app_main(void) { - main(); + return 0; } -#endif -#ifndef CI_BUILD //--------------------------------------------------------------------+ // FreeRTOS //--------------------------------------------------------------------+ @@ -197,5 +180,10 @@ void tx_application_define(void *first_unused_memory) { 1, 1, TX_NO_TIME_SLICE, TX_AUTO_START); } #endif - #endif // CI_BUILD + +#ifdef ESP_PLATFORM +void app_main(void) { + main(); +} +#endif diff --git a/test/hil/hfp.json b/test/hil/hfp.json index 8ba7a8f44..bb146d2fc 100644 --- a/test/hil/hfp.json +++ b/test/hil/hfp.json @@ -15,6 +15,10 @@ { "name": "stm32f746disco", "uid": "210041000C51343237303334", + "variant": [ + { "name": "stm32f746disco", "flags": "" }, + { "name": "stm32f746disco-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" } + ], "tests": { "device": true, "host": false, "dual": false }, diff --git a/test/hil/hil_ci.sh b/test/hil/hil_ci.sh index 4f68ed067..3ec907979 100644 --- a/test/hil/hil_ci.sh +++ b/test/hil/hil_ci.sh @@ -66,14 +66,41 @@ copy_board_binaries() { } if [ -n "$BOARD" ]; then - BUILD_DIR="$ROOT_DIR/examples/cmake-build-$BOARD" - if [ ! -d "$BUILD_DIR" ]; then - echo "Error: build directory not found: $BUILD_DIR" - echo "Build first with: cd examples && cmake -DBOARD=$BOARD -G Ninja -B cmake-build-$BOARD . && cmake --build cmake-build-$BOARD" + # Copy the board's build dir plus its variant dirs. Variant names come from + # $CONFIG (they are not required to be prefixed with the board name); the + # cmake-build--* glob is kept as a fallback for ad-hoc local builds. + # Collect only dirs that actually exist, deduplicated. + declare -A SEEN_DIRS=() + BUILD_DIRS=() + add_build_dir() { + [[ -d "$1" && -z "${SEEN_DIRS[$1]:-}" ]] || return 0 + SEEN_DIRS[$1]=1 + BUILD_DIRS+=("$1") + } + shopt -s nullglob + for d in "$ROOT_DIR"/examples/cmake-build-"$BOARD" "$ROOT_DIR"/examples/cmake-build-"$BOARD"-*; do + add_build_dir "$d" + done + shopt -u nullglob + while IFS= read -r v; do + add_build_dir "$ROOT_DIR/examples/cmake-build-$v" + done < <(python3 -c ' +import json, sys +cfg = json.load(open(sys.argv[1])) +for b in cfg.get("boards", []): + if b["name"] == sys.argv[2]: + for v in b.get("variant") or []: + print(v["name"]) +' "$CONFIG" "$BOARD") + if [ ${#BUILD_DIRS[@]} -eq 0 ]; then + echo "Error: no build directory found for $BOARD under $ROOT_DIR/examples/" + echo "Build first with: cd examples && cmake --preset $BOARD && cmake --build --preset $BOARD" exit 1 fi - echo "==> Copying binaries for $BOARD" - copy_board_binaries "$BUILD_DIR" + echo "==> Copying binaries for $BOARD (${#BUILD_DIRS[@]} build dir(s))" + for d in "${BUILD_DIRS[@]}"; do + copy_board_binaries "$d" + done else echo "==> Copying all built binaries" # Use `%/` parameter expansion to strip the trailing slash from the glob — diff --git a/test/hil/hil_ci_set_matrix.py b/test/hil/hil_ci_set_matrix.py index 2cce35ae2..baa24afb1 100644 --- a/test/hil/hil_ci_set_matrix.py +++ b/test/hil/hil_ci_set_matrix.py @@ -44,19 +44,19 @@ def main(): toolchain = 'arm-gcc' build_board = f'-b {name}' - if 'build' in board: - if 'args' in board['build']: - build_board += ' ' + ' '.join(f'-D{a}' for a in board['build']['args']) - if 'flags_on' in board['build']: - for f in board['build']['flags_on']: - if f == '': - append_build_arg(toolchain, build_board) - else: - append_build_arg(toolchain, f'{build_board} -f1 {f.replace(" ", " -f1 ")}') - else: - append_build_arg(toolchain, build_board) - else: - append_build_arg(toolchain, build_board) + if 'build' in board and 'args' in board['build']: + build_board += ' ' + ' '.join(f'-D{a}' for a in board['build']['args']) + + # Each variant builds into cmake-build- with its raw CFLAGS. + # No 'variant' -> a single build named after the board. + variants = board.get('variant') or [{'name': name, 'flags': ''}] + for v in variants: + arg = build_board + if v['name'] != name: + arg += f' --build-name {v["name"]}' + for tok in v.get('flags', '').split(): + arg += f' --cflag={tok}' + append_build_arg(toolchain, arg) print(json.dumps(matrix)) diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 45bad7a45..da13fcbaf 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -122,16 +122,21 @@ class TestsCfg(TypedDict, total=False): class BuildCfg(TypedDict, total=False): - flags_on: list[str] args: list[str] +class VariantCfg(TypedDict, total=False): + name: str # build dir (cmake-build-) and HIL report row + flags: str # raw CFLAGS, e.g. "-DCFG_TUD_DWC2_DMA_ENABLE=1" + + class Board(TypedDict): name: str uid: str tests: TestsCfg flasher: FlasherCfg build: NotRequired[BuildCfg] + variant: NotRequired[list[VariantCfg]] class HilConfig(TypedDict): @@ -223,7 +228,9 @@ def open_serial_dev(port: str): while timeout > 0: if os.path.exists(port): try: - ser = serial.Serial(port, baudrate=115200, timeout=5) + # write_timeout: a wedged device otherwise blocks ser.write() forever, + # hanging the worker until the pool/job timeout kills the whole run + ser = serial.Serial(port, baudrate=115200, timeout=5, write_timeout=5) break except serial.SerialException: print(f'serial {port} not reaady {timeout} sec') @@ -976,9 +983,9 @@ def test_device_cdc_msc_throughput(board): pass print(f' CDC read {cdc_r} write {cdc_w}, MSC read {msc_r} write {msc_w} ', end='') - # compact read/write speed for the report cell, e.g. "C 652k/422k M 1.1M/783k" + # compact read/write speed for the report cell, e.g. "✅ CDC 652k/422k MSC 1.1M/783k" short = lambda s: (s.split()[0].rstrip('0').rstrip('.') + s.split()[-1][0]) if ' ' in s else s - return f'C {short(cdc_r)}/{short(cdc_w)} M {short(msc_r)}/{short(msc_w)}' + return f'{REPORT_CELL["pass"]} CDC {short(cdc_r)}/{short(cdc_w)} MSC {short(msc_r)}/{short(msc_w)}' def test_device_dfu(board): @@ -1502,17 +1509,12 @@ host_test = [ ] -def f1_suffix(f1: str) -> str: - """Build dir / row-label suffix for a flags-on variant ('' for the default).""" - return '-f1_' + f1.replace(' ', '_') if f1 else '' - - -def find_firmware(name: str, f1: str, example: str): +def find_firmware(variant: str, example: str): """Locate a built example's firmware base path (no extension) under - cmake-build-[-f1_...]//. Accepts the single-config layout - (firmware directly in the example dir) or Ninja Multi-Config (a per-config - subdir like RelWithDebInfo/). Returns the base Path, or None if not built.""" - fw_dir = TINYUSB_ROOT / build_dir / f'cmake-build-{name}{f1_suffix(f1)}' / example + cmake-build-//. Accepts the single-config layout (firmware + directly in the example dir) or Ninja Multi-Config (a per-config subdir like + RelWithDebInfo/). Returns the base Path, or None if not built.""" + fw_dir = TINYUSB_ROOT / build_dir / f'cmake-build-{variant}' / example base = Path(example).name if fw_dir.is_dir(): for cand in [fw_dir / base, fw_dir / 'RelWithDebInfo' / base, @@ -1522,25 +1524,24 @@ def find_firmware(name: str, f1: str, example: str): return None -def test_example(board: Board, f1: str, example: str) -> tuple[int, str]: +def test_example(board: Board, variant: str, example: str) -> tuple[int, str]: """ Test example firmware :param board: board dict - :param f1: flags on + :param variant: build variant name = build dir (cmake-build-) and report row :param example: example name :return: (err_count, status, metric) where err_count is 0 on success/skip or 1 on failure, status is one of 'pass'/'fail'/'skip' (a missing binary counts as 'skip'), and metric is an optional string a test returns to show in its report cell instead of the pass symbol (e.g. speed) """ - name = board['name'] err_count = 0 result_status = 'fail' metric = None - test_name = f'{name + f1_suffix(f1):40} {example:30} ...' + test_name = f'{variant:40} {example:30} ...' - fw_name = find_firmware(name, f1, example) + fw_name = find_firmware(variant, example) if fw_name is None: log_line(f'{test_name} Skip (no binary)') return 0, 'skip', None @@ -1619,21 +1620,22 @@ def test_example(board: Board, f1: str, example: str) -> tuple[int, str]: def build_board(board: Board) -> tuple[str, int]: """Build firmware for this board via tools/build.py. - Honors board config's build.flags_on variants and build.args defines. - Output goes to cmake-build/cmake-build-BOARD[-f1_...]/ (tools/build.py layout).""" + Honors board config's variant list and build.args defines. + Output goes to cmake-build/cmake-build-/ (tools/build.py layout).""" name = board['name'] bcfg = cast(BuildCfg, board.get('build', {})) - flags_on_list = bcfg.get('flags_on', ['']) extra_defs = bcfg.get('args', []) + variants = board.get('variant') or [{'name': name, 'flags': ''}] failed = 0 - for f1 in flags_on_list: + for v in variants: cmd = [sys.executable, str(TINYUSB_ROOT / 'tools' / 'build.py'), '-b', name] for d in extra_defs: cmd += ['-D', d] - if f1: - for flag in f1.split(): - cmd += ['-f1', flag] + if v['name'] != name: + cmd += ['--build-name', v['name']] + for tok in v.get('flags', '').split(): + cmd += [f'--cflag={tok}'] if verbose: cmd.append('-v') print(f' + {" ".join(cmd)}') @@ -1684,25 +1686,24 @@ def test_board(board: Board) -> tuple[str, int, list[str], list]: err_count = 0 failed_tests = [] - rows = [] # list of (row_label, {example: status}) — one row per board[-f1] variant - flags_on_list = [""] - if 'build' in board and 'flags_on' in board['build']: - flags_on_list = board['build']['flags_on'] + rows = [] # list of (row_label, {example: status}) — one row per build variant + variants = board.get('variant') or [{'name': name, 'flags': ''}] - for f1 in flags_on_list: + for v in variants: + vname = v['name'] cells = {} for test in test_list: - ec, status, metric = test_example(board, f1, test) + ec, status, metric = test_example(board, vname, test) err_count += ec cells[test] = metric if metric else status if ec > 0: failed_tests.append(test) - rows.append((name + f1_suffix(f1), cells)) + rows.append((vname, cells)) # flash board_test last to disable board's usb (skipped when --skip-flash is set); # this is teardown/park, not a test — not recorded in the report if not skip_flash: - test_example(board, flags_on_list[0], 'device/board_test') + test_example(board, variants[0]['name'], 'device/board_test') return name, err_count, sorted(set(failed_tests)), rows diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 319ee9a79..afe3c4d03 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -17,12 +17,10 @@ { "name": "espressif_p4_function_ev", "uid": "6055F9F98715", - "build": { - "flags_on": [ - "", - "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE" - ] - }, + "variant": [ + { "name": "espressif_p4_function_ev", "flags": "" }, + { "name": "espressif_p4_function_ev-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" } + ], "tests": { "only": [ "device/cdc_msc_freertos", @@ -58,12 +56,10 @@ { "name": "espressif_s3_devkitm", "uid": "84F703C084E4", - "build": { - "flags_on": [ - "", - "CFG_TUD_DWC2_DMA_ENABLE CFG_TUH_DWC2_DMA_ENABLE" - ] - }, + "variant": [ + { "name": "espressif_s3_devkitm", "flags": "" }, + { "name": "espressif_s3_devkitm-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" } + ], "tests": { "only": [ "device/cdc_msc_freertos", @@ -226,11 +222,9 @@ { "name": "raspberry_pi_pico", "uid": "E6614C311B764A37", - "build": { - "flags_on": [ - "CFG_TUH_RPI_PIO_USB" - ] - }, + "variant": [ + { "name": "raspberry_pi_pico", "flags": "-DCFG_TUH_RPI_PIO_USB=1" } + ], "tests": { "device": true, "host": true, @@ -374,12 +368,10 @@ { "name": "stm32f723disco", "uid": "460029001951373031313335", - "build": { - "flags_on": [ - "", - "CFG_TUH_DWC2_DMA_ENABLE" - ] - }, + "variant": [ + { "name": "stm32f723disco", "flags": "" }, + { "name": "stm32f723disco-DMA", "flags": "-DCFG_TUH_DWC2_DMA_ENABLE=1" } + ], "tests": { "device": true, "host": true, @@ -410,12 +402,10 @@ { "name": "stm32h743nucleo", "uid": "110018000951383432343236", - "build": { - "flags_on": [ - "", - "CFG_TUD_DWC2_DMA_ENABLE" - ] - }, + "variant": [ + { "name": "stm32h743nucleo", "flags": "" }, + { "name": "stm32h743nucleo-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" } + ], "tests": { "device": true, "host": false, @@ -474,12 +464,10 @@ { "name": "stm32f769disco", "uid": "21002F000F51363531383437", - "build": { - "flags_on": [ - "", - "CFG_TUD_DWC2_DMA_ENABLE" - ] - }, + "variant": [ + { "name": "stm32f769disco", "flags": "" }, + { "name": "stm32f769disco-DMA", "flags": "-DCFG_TUD_DWC2_DMA_ENABLE=1 -DCFG_TUH_DWC2_DMA_ENABLE=1" } + ], "tests": { "device": true, "host": false, diff --git a/tools/build.py b/tools/build.py index 3c5c3c077..86bc30d28 100755 --- a/tools/build.py +++ b/tools/build.py @@ -105,16 +105,14 @@ def print_build_result(board, build_target, status, duration): # ----------------------------- # CMake # ----------------------------- -def cmake_board(board, build_args, build_flags_on, build_targets): +def cmake_board(board, build_args, build_name, build_cflags, build_targets): ret = [0, 0, 0] start_time = time.monotonic() - build_dir = f'cmake-build/cmake-build-{board}' + build_dir = f'cmake-build/cmake-build-{build_name or board}' build_flags = [] - if len(build_flags_on) > 0: - cli_flags = ' '.join(f'-D{flag}=1' for flag in build_flags_on) - build_flags.append(f'-DCFLAGS_CLI={cli_flags}') - build_dir += '-f1_' + '_'.join(build_flags_on) + if build_cflags: + build_flags.append('-DCFLAGS_CLI=' + ' '.join(build_cflags)) family = find_family(board) if family == 'espressif': @@ -194,13 +192,13 @@ def make_board(board, build_args, build_targets): # ----------------------------- # Build Family # ----------------------------- -def build_boards_list(boards, build_defines, build_system, build_flags_on, build_targets): +def build_boards_list(boards, build_defines, build_system, build_name, build_cflags, build_targets): ret = [0, 0, 0] for b in boards: r = [0, 0, 0] if build_system == 'cmake': build_args = [f'-D{d}' for d in build_defines] - r = cmake_board(b, build_args, build_flags_on, build_targets) + r = cmake_board(b, build_args, build_name, build_cflags, build_targets) elif build_system == 'make': build_args = ' '.join(f'{d}' for d in build_defines) r = make_board(b, build_args, build_targets) @@ -261,7 +259,10 @@ def main(): parser.add_argument('-t', '--toolchain', default='gcc', help='Toolchain to use, default is gcc') parser.add_argument('-s', '--build-system', default='cmake', help='Build system to use, default is cmake') parser.add_argument('-D', '--define-symbol', action='append', default=[], help='Define to pass to build system') - parser.add_argument('-f1', '--build-flags-on', action='append', default=[], help='Build flag to pass to build system') + parser.add_argument('--build-name', default=None, + help='Override build dir name (cmake-build-); default is the board name. Used for HIL variants.') + parser.add_argument('--cflag', action='append', default=[], + help='Raw compiler flag appended to CFLAGS_CLI, e.g. --cflag=-DCFG_TUD_DWC2_DMA_ENABLE=1 (repeatable)') parser.add_argument('--one-random', action='store_true', default=False, help='Build only one random board of each specified family') parser.add_argument('--one-first', action='store_true', default=False, @@ -277,7 +278,8 @@ def main(): toolchain = args.toolchain build_system = args.build_system build_defines = args.define_symbol - build_flags_on = args.build_flags_on + build_name = args.build_name + build_cflags = args.cflag one_random = args.one_random one_first = args.one_first build_targets = args.target if args.target else ['all'] @@ -290,6 +292,12 @@ def main(): print("Please specify families or board to build") return 1 + # --build-name renames the single shared build dir, so building more than one + # board with it would clobber/mix artifacts + if build_name and (len(families) > 0 or len(boards) != 1): + print("--build-name requires exactly one board (-b) and no families") + return 1 + print(build_separator) print(build_format.format('Board', 'Target', '\033[39mResult\033[0m', 'Time')) total_time = time.monotonic() @@ -310,7 +318,7 @@ def main(): all_boards.extend(get_family_boards(f, one_random, one_first)) # build all boards - result = build_boards_list(all_boards, build_defines, build_system, build_flags_on, build_targets) + result = build_boards_list(all_boards, build_defines, build_system, build_name, build_cflags, build_targets) total_time = time.monotonic() - total_time print(build_separator) diff --git a/tools/get_deps.py b/tools/get_deps.py index eb87abf6e..abe5750f1 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -366,6 +366,8 @@ def main(): parser.add_argument('-b', '--board', action='append', default=[], help='Boards to fetch') parser.add_argument('-D', '--define', action='append', default=[], help='Have no effect') parser.add_argument('-f1', '--build-flags-on', action='append', default=[], help='Have no effect') + parser.add_argument('--build-name', default=None, help='Have no effect') + parser.add_argument('--cflag', action='append', default=[], help='Have no effect') args = parser.parse_args() families = args.families -- cgit v1.3.1 From d9f736dcf9c6b71aac470d281cd2fc05a3f7e793 Mon Sep 17 00:00:00 2001 From: Ha Thach Date: Tue, 16 Jun 2026 17:42:31 +0700 Subject: hil: enable nanoch32v203 in CI with fsdev + usbfs variants (#3707) * hil: enable nanoch32v203 in CI with fsdev + usbfs variants nanoch32v203 was parked in boards-skip; move it into the active pool now that the board is wired to the ci.lan rig. Cover both USB device IPs as build variants: - nanoch32v203-fsdev: RHPORT_DEVICE=0 (USBD / stm32 FSDev IP) - nanoch32v203-usbfs: RHPORT_DEVICE=1 (WCH USBFS IP) --- .github/workflows/build.yml | 1 + test/hil/hil_ci_set_matrix.py | 16 +++++++++++++--- test/hil/hil_test.py | 8 ++++++-- test/hil/tinyusb.json | 33 +++++++++++++++++++-------------- 4 files changed, 39 insertions(+), 19 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a7c7cf99a..3f6458285 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -278,6 +278,7 @@ jobs: matrix: toolchain: - 'arm-gcc' + - 'riscv-gcc' - 'esp-idf' with: build-system: 'cmake' diff --git a/test/hil/hil_ci_set_matrix.py b/test/hil/hil_ci_set_matrix.py index baa24afb1..13f7f1882 100644 --- a/test/hil/hil_ci_set_matrix.py +++ b/test/hil/hil_ci_set_matrix.py @@ -19,8 +19,12 @@ def main(): parser.add_argument('config_files', nargs='+', help='Configuration JSON file(s)') args = parser.parse_args() + # Toolchain buckets must match the toolchains instantiated by the hil-build + # job in .github/workflows/build.yml. Keep all keys present (even if empty) + # so `fromJSON(hil_json)[toolchain]` always resolves to a list. matrix = { 'arm-gcc': [], + 'riscv-gcc': [], 'esp-idf': [] } @@ -38,22 +42,28 @@ def main(): for board in config['boards']: name = board['name'] flasher = board['flasher'] + # esptool boards must build under esp-idf; others default to arm-gcc + # but may opt into another bucket via an explicit "toolchain" field + # (e.g. RISC-V boards like ch32v20x need "riscv-gcc"). if flasher['name'] == 'esptool': toolchain = 'esp-idf' else: - toolchain = 'arm-gcc' + toolchain = board.get('toolchain', 'arm-gcc') build_board = f'-b {name}' if 'build' in board and 'args' in board['build']: build_board += ' ' + ' '.join(f'-D{a}' for a in board['build']['args']) - # Each variant builds into cmake-build- with its raw CFLAGS. - # No 'variant' -> a single build named after the board. + # Each variant builds into cmake-build- with its own cmake + # -D defines and raw CFLAGS. No 'variant' -> a single build named after + # the board. variants = board.get('variant') or [{'name': name, 'flags': ''}] for v in variants: arg = build_board if v['name'] != name: arg += f' --build-name {v["name"]}' + for d in v.get('defines', []): + arg += f' -D{d}' for tok in v.get('flags', '').split(): arg += f' --cflag={tok}' append_build_arg(toolchain, arg) diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index da13fcbaf..fb9a8205c 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -126,8 +126,9 @@ class BuildCfg(TypedDict, total=False): class VariantCfg(TypedDict, total=False): - name: str # build dir (cmake-build-) and HIL report row - flags: str # raw CFLAGS, e.g. "-DCFG_TUD_DWC2_DMA_ENABLE=1" + name: str # build dir (cmake-build-) and HIL report row + flags: str # raw CFLAGS, e.g. "-DCFG_TUD_DWC2_DMA_ENABLE=1" + defines: list[str] # cmake -D defines, e.g. ["RHPORT_DEVICE=1"] (vs flags which are compiler-only) class Board(TypedDict): @@ -137,6 +138,7 @@ class Board(TypedDict): flasher: FlasherCfg build: NotRequired[BuildCfg] variant: NotRequired[list[VariantCfg]] + toolchain: NotRequired[str] # CI build bucket override, e.g. "riscv-gcc" (consumed by hil_ci_set_matrix.py) class HilConfig(TypedDict): @@ -1634,6 +1636,8 @@ def build_board(board: Board) -> tuple[str, int]: cmd += ['-D', d] if v['name'] != name: cmd += ['--build-name', v['name']] + for d in v.get('defines', []): + cmd += ['-D', d] for tok in v.get('flags', '').split(): cmd += [f'--cflag={tok}'] if verbose: diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index afe3c4d03..ea9342c03 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -458,6 +458,25 @@ "name": "stlink", "uid": "0668FF575457657187061314" } + }, + { + "name": "nanoch32v203", + "uid": "CDAB277B0FBC03E339E339E3", + "toolchain": "riscv-gcc", + "variant": [ + {"name": "nanoch32v203-fsdev", "defines": ["RHPORT_DEVICE=0"]}, + {"name": "nanoch32v203-usbfs", "defines": ["RHPORT_DEVICE=1"]} + ], + "tests": { + "device": true, + "host": false, + "dual": false + }, + "flasher": { + "name": "openocd_wch", + "uid": "EBCA8F0670AF", + "args": "" + } } ], "boards-skip": [ @@ -478,20 +497,6 @@ "uid": "000778170924", "args": "-device stm32f769ni" } - }, - { - "name": "nanoch32v203", - "uid": "CDAB277B0FBC03E339E339E3", - "tests": { - "device": true, - "host": false, - "dual": false - }, - "flasher": { - "name": "openocd_wch", - "uid": "EBCA8F0670AF", - "args": "" - } } ] } -- cgit v1.3.1 From 133de459505860f6961621b5619f4a4cb6c357c4 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 18 Jun 2026 11:04:02 +0700 Subject: test/hil: add ch32v103r_r1_1v0 to CI HIL pool Now that CH32V103 USB device works, add the board to the active HIL pool. It is a WCH RISC-V USBFS part, so it builds under the riscv-gcc bucket; single config (USBFS only, no fsdev variant). cdc_msc_throughput is skipped for this board: its device->host CDC bulk-IN read hard-fails here (a known, pre-existing dcd_ch32_usbfs throughput limitation, not specific to CH32V103). All other device tests pass on ci.lan (verified green, 0 failures). Co-Authored-By: Claude Opus 4.8 (1M context) --- test/hil/tinyusb.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index ea9342c03..41d94bc00 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -477,6 +477,22 @@ "uid": "EBCA8F0670AF", "args": "" } + }, + { + "name": "ch32v103r_r1_1v0", + "uid": "CDAB3E8749BC54EF0F410025", + "toolchain": "riscv-gcc", + "tests": { + "device": true, + "host": false, + "dual": false, + "skip": ["device/cdc_msc_throughput"] + }, + "flasher": { + "name": "openocd_wch", + "uid": "BC4954081051", + "args": "" + } } ], "boards-skip": [ -- cgit v1.3.1 From d9dc891ee2aaedb733da4c0f2fee5a68be001ee7 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 18 Jun 2026 18:08:25 +0700 Subject: test/hil: fix esp32 audio_test_freertos (FreeRTOS tick), skip metro_m4 Enabling the audio test fleet-wide surfaced failures on esp32-p4/s3 and metro_m4_express: the UAC mic enumerates but arecord fails the iso IN read with EIO, while 18 other boards pass strict=1.000. esp32: root cause is the FreeRTOS tick rate. ESP-IDF defaults CONFIG_FREERTOS_HZ to 100, so the audio task wakes only every 10 ms and can't service the 1 ms UAC iso frames -> underrun -> arecord EIO. (The same dwc2 driver passes on STM32, whose FreeRTOSConfig is 1000 Hz.) Set CONFIG_FREERTOS_HZ=1000 in the example sdkconfig.defaults; the example defaults are honored in the generated sdkconfig alongside the BSP's, so this takes effect. metro_m4_express (samd51): not tick-rate -- its FreeRTOSConfig is already 1000 Hz like the passing boards -- so it's a separate iso-IN issue, skipped for now. Co-Authored-By: Claude Opus 4.8 (1M context) --- examples/device/audio_test_freertos/sdkconfig.defaults | 3 +++ test/hil/tinyusb.json | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'test/hil/tinyusb.json') diff --git a/examples/device/audio_test_freertos/sdkconfig.defaults b/examples/device/audio_test_freertos/sdkconfig.defaults index 83871619e..6e7a1cf52 100644 --- a/examples/device/audio_test_freertos/sdkconfig.defaults +++ b/examples/device/audio_test_freertos/sdkconfig.defaults @@ -1,3 +1,6 @@ CONFIG_IDF_CMAKE=y +# 1000 Hz tick: the UAC iso IN endpoint must be serviced every 1 ms frame; +# ESP-IDF's default 100 Hz starves the audio task -> host capture fails (arecord EIO). +CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 41d94bc00..a534f2601 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -132,6 +132,7 @@ "device": true, "host": false, "dual": true, + "skip": ["device/audio_test_freertos"], "dev_attached": [ { "vid_pid": "067b_2303", @@ -139,7 +140,7 @@ "is_cdc": true } ], - "comment": "pl23x" + "comment": "pl23x; audio_test_freertos skipped: samd51 iso-IN capture fails (arecord EIO)" }, "flasher": { "name": "jlink", -- cgit v1.3.1 From 952ec68753960093066308eb313bd8650d78b7c9 Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 19 Jun 2026 21:37:34 +0700 Subject: test/hil: add ch582m_evt to CI HIL pool Add the device-only CH582M-EVT (WCH USBFS via the shared dcd_ch32_usbfs.c), riscv-gcc, flashed by openocd_wch probe 7FD88F0604B5, to tinyusb.json. Also reorder device_tests to keep examples sharing a VID:PID non-adjacent: cdc_msc and cdc_msc_throughput both use cafe:4003, and on boards whose CPU-reset does not drop D+ (e.g. WCH CH58x via openocd) back-to-back same-PID firmware leaves the host on the previous example's cached descriptors, so the new example's CDC never enumerates and the test fails. Moving dfu (cafe:4000) between them changes the PID and forces the host to re-enumerate. Remote HIL on ci.lan: all device examples pass, including cdc_msc_throughput (no skip needed). Co-Authored-By: Claude Opus 4.8 (1M context) --- test/hil/hil_test.py | 6 +++++- test/hil/tinyusb.json | 15 +++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'test/hil/tinyusb.json') diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py index 8ae9ee0dc..ec6c7c448 100755 --- a/test/hil/hil_test.py +++ b/test/hil/hil_test.py @@ -1490,9 +1490,13 @@ def test_device_hid_generic_inout(board): # device tests # note don't test 2 examples with cdc or 2 msc next to each other device_tests = [ + # Order matters: cdc_msc and cdc_msc_throughput share the same VID:PID (cafe:4003), so keep a + # differently-PID'd example (dfu, cafe:4000) between them. Boards whose CPU-reset does not drop + # D+ (e.g. WCH CH58x via openocd) only re-enumerate when the PID changes; back-to-back same-PID + # firmware would otherwise leave the host on the previous example's cached descriptors. 'device/cdc_dual_ports', - 'device/dfu', 'device/cdc_msc', + 'device/dfu', 'device/cdc_msc_throughput', 'device/audio_test_freertos', 'device/dfu_runtime', diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index 41d94bc00..ccf81c582 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -493,6 +493,21 @@ "uid": "BC4954081051", "args": "" } + }, + { + "name": "ch582m_evt", + "uid": "0123456789ABCDEF", + "toolchain": "riscv-gcc", + "tests": { + "device": true, + "host": false, + "dual": false + }, + "flasher": { + "name": "openocd_wch", + "uid": "7FD88F0604B5", + "args": "" + } } ], "boards-skip": [ -- cgit v1.3.1 From ea5c6fa165649cfa36d704b1852babf19d5e6bb5 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 20 Jun 2026 23:06:07 +0700 Subject: hw/bsp/ch58x: address review feedback and read the real chip unique id Fold in the CH58x BSP review fixes: - family.mk: drop stray trailing backslashes on the last LDFLAGS/SRC_C entries (harmless -- GNU Make ends the list at the blank line -- but misleading). - debug_uart.c: uart_write() spun on a full ring buffer with nothing to drain it (only uart_sync() advances tx_consume), so a burst larger than the buffer deadlocked. Drain the FIFO while waiting, like uart_sync() does. - wch-riscv.cfg: move the OpenOCD work area from 0x80000000 (unmapped) to the 0x20000000 SRAM, sized to 32 KB, matching ch32v20x/wch-riscv.cfg. - family.c: implement board_get_unique_id() from the factory MAC. CH58x is a BLE part, so a unique 6-byte MAC lives in FlashROM at ROM_CFG_MAC_ADDR; GetMACAddress() reads it via FLASH_EEPROM_CMD (in libISP583.a), so no extra source file is needed. The read buffer is TU_ATTR_ALIGNED(4) and 8 bytes, per the SDK's documented 4-byte-aligned, word-granular buffer contract (CH58x_flash.c). - test/hil/tinyusb.json: key ch582m_evt off this board's actual MAC (D443627B5450) instead of the fixed placeholder, like every other board. Verified on ci.lan HIL: ch582m_evt enumerates with serial D443627B5450 and all device examples pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- hw/bsp/ch58x/debug_uart.c | 10 ++++++++-- hw/bsp/ch58x/family.c | 16 +++++++++++++--- hw/bsp/ch58x/family.mk | 4 ++-- hw/bsp/ch58x/wch-riscv.cfg | 2 +- test/hil/tinyusb.json | 2 +- 5 files changed, 25 insertions(+), 9 deletions(-) (limited to 'test/hil/tinyusb.json') diff --git a/hw/bsp/ch58x/debug_uart.c b/hw/bsp/ch58x/debug_uart.c index 7dd133cb2..850e40718 100644 --- a/hw/bsp/ch58x/debug_uart.c +++ b/hw/bsp/ch58x/debug_uart.c @@ -41,8 +41,14 @@ static volatile uint32_t tx_consume; void uart_write(char c) { uint32_t tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX; - // If ring buffer is full, wait - while (tx_produce_next == tx_consume) {} + // If the ring buffer is full, drain it here as the FIFO frees up: nothing else advances + // tx_consume between uart_write() calls, so a plain spin would deadlock on a >buffer-size burst. + while (tx_produce_next == tx_consume) { + if (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP) { + R8_UART1_THR = tx_buf[tx_consume]; + tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX; + } + } // If UART TX FIFO is empty and no pending data, send directly if ((tx_consume == tx_produce) && (R8_UART1_LSR & RB_LSR_TX_FIFO_EMP)) { diff --git a/hw/bsp/ch58x/family.c b/hw/bsp/ch58x/family.c index 8e5f2826b..64ae4a903 100644 --- a/hw/bsp/ch58x/family.c +++ b/hw/bsp/ch58x/family.c @@ -163,9 +163,19 @@ uint32_t board_button_read(void) { #endif } -// Note: CH58x exposes no memory-mapped unique-ID register (unlike ch32v10x/v20x at -// 0x1FFFF7E8), and the SDK's GET_UNIQUE_ID() is a BootROM stub not present in -// libISP583.a. So board_get_unique_id() falls back to the fixed default in board.c. +// CH58x has no memory-mapped unique-ID register (unlike ch32v10x/v20x at 0x1FFFF7E8), but the +// factory programs a unique 6-byte MAC address into FlashROM (it is a BLE part). GetMACAddress() +// reads it via the ISP ROM command FLASH_EEPROM_CMD, which is provided by libISP583.a. +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + // FLASH_EEPROM_CMD writes word-granular and requires a 4-byte-aligned buffer (CH58x_flash.c); + // size 8 matches the SDK's GET_UNIQUE_ID buffer (6 MAC bytes + 2 it pads), so the read can't + // run past the end whether it returns 6 or a full 8. + TU_ATTR_ALIGNED(4) uint8_t mac[8]; + GetMACAddress(mac); + size_t len = TU_MIN(max_len, (size_t) 6); // the 6-byte MAC is the unique part + memcpy(id, mac, len); + return len; +} int board_uart_read(uint8_t* buf, int len) { (void) buf; diff --git a/hw/bsp/ch58x/family.mk b/hw/bsp/ch58x/family.mk index ccdaa7268..ac0443659 100644 --- a/hw/bsp/ch58x/family.mk +++ b/hw/bsp/ch58x/family.mk @@ -28,7 +28,7 @@ CFLAGS += \ LDFLAGS += \ -nostartfiles \ - --specs=nosys.specs --specs=nano.specs \ + --specs=nosys.specs --specs=nano.specs LIBS += $(TOP)/$(SDK_SRC_DIR)/StdPeriphDriver/libISP583.a @@ -40,7 +40,7 @@ SRC_C += \ $(SDK_SRC_DIR)/StdPeriphDriver/CH58x_sys.c \ $(FAMILY_PATH)/debug_uart.c \ $(FAMILY_PATH)/ch58x_it.c \ - $(FAMILY_PATH)/system_ch58x.c \ + $(FAMILY_PATH)/system_ch58x.c SRC_S += \ $(SDK_SRC_DIR)/Startup/startup_CH583.S diff --git a/hw/bsp/ch58x/wch-riscv.cfg b/hw/bsp/ch58x/wch-riscv.cfg index 5913a2465..64d595d8e 100644 --- a/hw/bsp/ch58x/wch-riscv.cfg +++ b/hw/bsp/ch58x/wch-riscv.cfg @@ -9,7 +9,7 @@ sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001 set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME -$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 +$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 0x8000 -work-area-backup 1 set _FLASHNAME $_CHIPNAME.flash flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 diff --git a/test/hil/tinyusb.json b/test/hil/tinyusb.json index ccf81c582..71d92aae1 100644 --- a/test/hil/tinyusb.json +++ b/test/hil/tinyusb.json @@ -496,7 +496,7 @@ }, { "name": "ch582m_evt", - "uid": "0123456789ABCDEF", + "uid": "D443627B5450", "toolchain": "riscv-gcc", "tests": { "device": true, -- cgit v1.3.1