summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJie Feng <[email protected]>2026-06-10 18:25:08 +0800
committerJie Feng <[email protected]>2026-07-19 19:24:40 +0800
commit127dd2ca26dcba18d14e745bec4c1a69b55a2c01 (patch)
treed53c3fd95ecb6f274fa56efd86f99cbc4fcf408e
parent50f30773522d21bc599f00c18980ae651f780ff8 (diff)
add py32f0 support
-rw-r--r--.gitignore1
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/board.cmake9
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/board.h75
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/board.mk8
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/py32f071_hal_conf.h105
-rw-r--r--hw/bsp/py32f0/boards/py32f071_dev_board/py32f071xb.ld122
-rw-r--r--hw/bsp/py32f0/family.c133
-rw-r--r--hw/bsp/py32f0/family.cmake97
-rw-r--r--hw/bsp/py32f0/family.mk57
-rw-r--r--src/common/tusb_mcu.h11
-rw-r--r--src/portable/mentor/musb/dcd_musb.c51
-rw-r--r--src/portable/mentor/musb/musb_max32.h1
-rw-r--r--src/portable/mentor/musb/musb_py32.h79
-rw-r--r--src/portable/mentor/musb/musb_ti.h1
-rw-r--r--src/portable/mentor/musb/musb_type.h71
-rw-r--r--src/tusb_option.h13
-rwxr-xr-xtools/get_deps.py6
17 files changed, 829 insertions, 11 deletions
diff --git a/.gitignore b/.gitignore
index 145069e72..ca745ee19 100644
--- a/.gitignore
+++ b/.gitignore
@@ -81,6 +81,7 @@ hw/mcu/gd/
hw/mcu/hpmicro/
hw/mcu/infineon/
hw/mcu/microchip/
+hw/mcu/puya/
hw/mcu/mindmotion/
hw/mcu/nordic/nrfx/
hw/mcu/nuvoton/
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/board.cmake b/hw/bsp/py32f0/boards/py32f071_dev_board/board.cmake
new file mode 100644
index 000000000..6c9c58e3d
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/board.cmake
@@ -0,0 +1,9 @@
+set(PYOCD_TARGET py32f071ex8)
+set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/py32f071xb.ld)
+
+function(update_board TARGET)
+ target_compile_definitions(${TARGET} PUBLIC
+ PY32F071xB
+ CFG_EXAMPLE_VIDEO_READONLY
+ )
+endfunction()
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/board.h b/hw/bsp/py32f0/boards/py32f071_dev_board/board.h
new file mode 100644
index 000000000..ddd67bb6a
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/board.h
@@ -0,0 +1,75 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define LED_PORT GPIOB
+#define LED_PIN GPIO_PIN_2
+#define LED_STATE_ON 0
+
+#define BUTTON_PORT GPIOB
+#define BUTTON_PIN GPIO_PIN_0
+#define BUTTON_STATE_ACTIVE 0
+
+static inline void board_py32f0_clock_init(void) {
+ RCC_OscInitTypeDef RCC_OscInitStruct = {0};
+ RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
+
+ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI |
+ RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
+ RCC_OscInitStruct.HSIState = RCC_HSI_ON;
+ RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
+ RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_16MHz;
+ RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+ RCC_OscInitStruct.HSEFreq = RCC_HSE_16_32MHz;
+ RCC_OscInitStruct.LSIState = RCC_LSI_OFF;
+ RCC_OscInitStruct.LSEState = RCC_LSE_OFF;
+ RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+ RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+ RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL2;
+ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
+ while (1) {}
+ }
+
+ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
+ RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+ RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+ RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
+ if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
+ while (1) {}
+ }
+}
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/board.mk b/hw/bsp/py32f0/boards/py32f071_dev_board/board.mk
new file mode 100644
index 000000000..61a2c578c
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/board.mk
@@ -0,0 +1,8 @@
+CFLAGS += \
+ -DPY32F071xB \
+ -DCFG_EXAMPLE_VIDEO_READONLY
+
+LD_FILE = $(BOARD_PATH)/py32f071xb.ld
+PYOCD_TARGET = py32f071ex8
+
+flash: flash-pyocd
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071_hal_conf.h b/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071_hal_conf.h
new file mode 100644
index 000000000..e513bf8cb
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071_hal_conf.h
@@ -0,0 +1,105 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef PY32F071_HAL_CONF_H_
+#define PY32F071_HAL_CONF_H_
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define HAL_MODULE_ENABLED
+#define HAL_RCC_MODULE_ENABLED
+#define HAL_FLASH_MODULE_ENABLED
+#define HAL_GPIO_MODULE_ENABLED
+#define HAL_PWR_MODULE_ENABLED
+#define HAL_CORTEX_MODULE_ENABLED
+
+#if !defined(HSI_VALUE)
+ #define HSI_VALUE ((uint32_t) 8000000)
+#endif
+
+#if !defined(HSE_VALUE)
+ #define HSE_VALUE ((uint32_t) 24000000)
+#endif
+
+#if !defined(HSE_STARTUP_TIMEOUT)
+ #define HSE_STARTUP_TIMEOUT ((uint32_t) 200)
+#endif
+
+#if !defined(LSI_VALUE)
+ #define LSI_VALUE ((uint32_t) 32768)
+#endif
+
+#if !defined(LSE_VALUE)
+ #define LSE_VALUE ((uint32_t) 32768)
+#endif
+
+#if !defined(LSE_STARTUP_TIMEOUT)
+ #define LSE_STARTUP_TIMEOUT ((uint32_t) 5000)
+#endif
+
+#define VDD_VALUE ((uint32_t) 3300)
+#define TICK_INT_PRIORITY ((uint32_t) 3)
+#define USE_RTOS 0
+#define PREFETCH_ENABLE 0
+
+#ifdef HAL_MODULE_ENABLED
+ #include "py32f0xx_hal.h"
+#endif
+
+#ifdef HAL_RCC_MODULE_ENABLED
+ #include "py32f071_hal_rcc.h"
+#endif
+
+#ifdef HAL_FLASH_MODULE_ENABLED
+ #include "py32f071_hal_flash.h"
+#endif
+
+#ifdef HAL_GPIO_MODULE_ENABLED
+ #include "py32f071_hal_gpio.h"
+#endif
+
+#ifdef HAL_PWR_MODULE_ENABLED
+ #include "py32f071_hal_pwr.h"
+#endif
+
+#ifdef HAL_CORTEX_MODULE_ENABLED
+ #include "py32f071_hal_cortex.h"
+#endif
+
+#ifdef USE_FULL_ASSERT
+void assert_failed(uint8_t *file, uint32_t line);
+ #define assert_param(expr) ((expr) ? (void) 0U : assert_failed((uint8_t *) __FILE__, __LINE__))
+#else
+ #define assert_param(expr) ((void) 0U)
+#endif
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff --git a/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071xb.ld b/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071xb.ld
new file mode 100644
index 000000000..bb6b88d2c
--- /dev/null
+++ b/hw/bsp/py32f0/boards/py32f071_dev_board/py32f071xb.ld
@@ -0,0 +1,122 @@
+ENTRY(Reset_Handler)
+
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+_Min_Heap_Size = 0x200;
+_Min_Stack_Size = 0x400;
+
+MEMORY
+{
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K
+ FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+}
+
+SECTIONS
+{
+ .isr_vector :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector))
+ . = ALIGN(4);
+ } >FLASH
+
+ .text :
+ {
+ . = ALIGN(4);
+ *(.text)
+ *(.text*)
+ *(.glue_7)
+ *(.glue_7t)
+ *(.eh_frame)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ . = ALIGN(4);
+ _etext = .;
+ } >FLASH
+
+ .rodata :
+ {
+ . = ALIGN(4);
+ *(.rodata)
+ *(.rodata*)
+ . = ALIGN(4);
+ } >FLASH
+
+ .ARM.extab :
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ } >FLASH
+
+ .ARM :
+ {
+ __exidx_start = .;
+ *(.ARM.exidx*)
+ __exidx_end = .;
+ } >FLASH
+
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN(__preinit_array_start = .);
+ KEEP(*(.preinit_array*))
+ PROVIDE_HIDDEN(__preinit_array_end = .);
+ } >FLASH
+
+ .init_array :
+ {
+ PROVIDE_HIDDEN(__init_array_start = .);
+ KEEP(*(SORT(.init_array.*)))
+ KEEP(*(.init_array*))
+ PROVIDE_HIDDEN(__init_array_end = .);
+ } >FLASH
+
+ .fini_array :
+ {
+ PROVIDE_HIDDEN(__fini_array_start = .);
+ KEEP(*(SORT(.fini_array.*)))
+ KEEP(*(.fini_array*))
+ PROVIDE_HIDDEN(__fini_array_end = .);
+ } >FLASH
+
+ _sidata = LOADADDR(.data);
+
+ .data :
+ {
+ . = ALIGN(4);
+ _sdata = .;
+ *(.data)
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } >RAM AT> FLASH
+
+ . = ALIGN(4);
+ .bss :
+ {
+ _sbss = .;
+ __bss_start__ = _sbss;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ __bss_end__ = _ebss;
+ } >RAM
+
+ ._user_heap_stack :
+ {
+ . = ALIGN(8);
+ PROVIDE(end = .);
+ PROVIDE(_end = .);
+ . = . + _Min_Heap_Size;
+ . = . + _Min_Stack_Size;
+ . = ALIGN(8);
+ } >RAM
+
+ /DISCARD/ :
+ {
+ libc.a(*)
+ libm.a(*)
+ libgcc.a(*)
+ }
+
+ .ARM.attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/hw/bsp/py32f0/family.c b/hw/bsp/py32f0/family.c
new file mode 100644
index 000000000..1428b1fa9
--- /dev/null
+++ b/hw/bsp/py32f0/family.c
@@ -0,0 +1,133 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+/* metadata:
+ manufacturer: Puya
+*/
+
+#include "py32f0xx_hal.h"
+#include "bsp/board_api.h"
+#include "board.h"
+
+void USB_IRQHandler(void) {
+ tud_int_handler(0);
+}
+
+void USBD_IRQHandler(void) {
+ tud_int_handler(0);
+}
+
+void HAL_MspInit(void) {
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+}
+
+void board_init(void) {
+ HAL_Init();
+ board_py32f0_clock_init();
+
+ __HAL_RCC_SYSCFG_CLK_ENABLE();
+ __HAL_RCC_PWR_CLK_ENABLE();
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+ SysTick_Config(SystemCoreClock / 1000);
+#elif CFG_TUSB_OS == OPT_OS_FREERTOS
+ SysTick->CTRL &= ~1U;
+ NVIC_SetPriority(USB_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
+#endif
+
+ GPIO_InitTypeDef GPIO_InitStruct;
+
+ GPIO_InitStruct.Pin = LED_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct);
+ board_led_write(false);
+
+ GPIO_InitStruct.Pin = BUTTON_PIN;
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
+ HAL_GPIO_Init(BUTTON_PORT, &GPIO_InitStruct);
+
+ __HAL_RCC_USB_CLK_ENABLE();
+}
+
+void board_led_write(bool state) {
+ GPIO_PinState pin_state = (GPIO_PinState) (state ? LED_STATE_ON : (1 - LED_STATE_ON));
+ HAL_GPIO_WritePin(LED_PORT, LED_PIN, pin_state);
+}
+
+uint32_t board_button_read(void) {
+ return BUTTON_STATE_ACTIVE == HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN);
+}
+
+size_t board_get_unique_id(uint8_t id[], size_t max_len) {
+ (void) max_len;
+ volatile uint32_t * py32_uuid = (volatile uint32_t *) UID_BASE;
+ uint32_t* id32 = (uint32_t*) (uintptr_t) id;
+ uint8_t const len = 12;
+
+ id32[0] = py32_uuid[0];
+ id32[1] = py32_uuid[1];
+ id32[2] = py32_uuid[2];
+
+ return len;
+}
+
+int board_uart_read(uint8_t *buf, int len) {
+ (void) buf; (void) len;
+ return 0;
+}
+
+int board_uart_write(void const *buf, int len) {
+ (void) buf; (void) len;
+ return -1;
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+
+void SysTick_Handler(void) {
+ HAL_IncTick();
+ system_ticks++;
+}
+
+uint32_t tusb_time_millis_api(void) {
+ return system_ticks;
+}
+#endif
+
+void HardFault_Handler(void) {
+ __asm("BKPT #0\n");
+}
+
+void _init(void);
+void _init(void) {
+}
diff --git a/hw/bsp/py32f0/family.cmake b/hw/bsp/py32f0/family.cmake
new file mode 100644
index 000000000..2416ace88
--- /dev/null
+++ b/hw/bsp/py32f0/family.cmake
@@ -0,0 +1,97 @@
+include_guard()
+
+include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
+
+if (NOT DEFINED PY32_SDK_NAME)
+ set(PY32_SDK_NAME PY32F071_Firmware)
+endif ()
+if (NOT DEFINED PY32_SERIES)
+ set(PY32_SERIES PY32F071)
+endif ()
+if (NOT DEFINED PY32_TEMPLATE)
+ set(PY32_TEMPLATE PY32F071xx_Templates)
+endif ()
+if (NOT DEFINED PY32_STARTUP)
+ set(PY32_STARTUP startup_py32f071xx.s)
+endif ()
+if (NOT DEFINED PY32_SYSTEM_SOURCE)
+ set(PY32_SYSTEM_SOURCE system_py32f071.c)
+endif ()
+if (NOT DEFINED PY32_HAL_PREFIX)
+ set(PY32_HAL_PREFIX py32f071)
+endif ()
+set(PY32_SDK ${TOP}/hw/mcu/puya/${PY32_SDK_NAME})
+set(PY32_HAL ${PY32_SDK}/Drivers/${PY32_SERIES}_HAL_Driver)
+set(PY32_CMSIS ${PY32_SDK}/Drivers/CMSIS/Device/${PY32_SERIES})
+
+set(CMAKE_SYSTEM_CPU cortex-m0plus CACHE INTERNAL "System Processor")
+set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/arm_${TOOLCHAIN}.cmake)
+
+set(FAMILY_MCUS PY32F0 CACHE INTERNAL "")
+
+set(STARTUP_FILE_GNU ${PY32_SDK}/Templates/${PY32_TEMPLATE}/EIDE/${PY32_STARTUP})
+set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU})
+set(LD_FILE_Clang ${LD_FILE_GNU})
+
+function(family_add_board BOARD_TARGET)
+ add_library(${BOARD_TARGET} STATIC
+ ${PY32_SDK}/Templates/${PY32_TEMPLATE}/Src/${PY32_SYSTEM_SOURCE}
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_cortex.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_flash.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_gpio.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_pwr.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_rcc.c
+ ${PY32_HAL}/Src/${PY32_HAL_PREFIX}_hal_rcc_ex.c
+ )
+ target_include_directories(${BOARD_TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${PY32_SDK}/Drivers/CMSIS/Include
+ ${PY32_CMSIS}/Include
+ ${PY32_HAL}/Inc
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+ target_compile_definitions(${BOARD_TARGET} PRIVATE
+ USE_HAL_DRIVER
+ )
+ update_board(${BOARD_TARGET})
+endfunction()
+
+function(family_configure_example TARGET RTOS)
+ family_configure_common(${TARGET} ${RTOS})
+ family_add_tinyusb(${TARGET} OPT_MCU_PY32F0)
+
+ target_sources(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c
+ ${TOP}/src/portable/mentor/musb/dcd_musb.c
+ ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}}
+ )
+ target_include_directories(${TARGET} PUBLIC
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../
+ ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD}
+ )
+
+ if (CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_link_options(${TARGET} PUBLIC
+ "LINKER:--script=${LD_FILE_GNU}"
+ -nostartfiles
+ --specs=nosys.specs --specs=nano.specs
+ )
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ message(FATAL_ERROR "Clang is not supported")
+ elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR")
+ message(FATAL_ERROR "IAR is not supported")
+ 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)
+
+ family_add_bin_hex(${TARGET})
+ family_flash_pyocd(${TARGET})
+endfunction()
diff --git a/hw/bsp/py32f0/family.mk b/hw/bsp/py32f0/family.mk
new file mode 100644
index 000000000..7ddfea5f7
--- /dev/null
+++ b/hw/bsp/py32f0/family.mk
@@ -0,0 +1,57 @@
+UF2_FAMILY_ID = 0x0
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+PY32_SDK_NAME ?= PY32F071_Firmware
+PY32_SERIES ?= PY32F071
+PY32_TEMPLATE ?= PY32F071xx_Templates
+PY32_STARTUP ?= startup_py32f071xx.s
+PY32_SYSTEM_SOURCE ?= system_py32f071.c
+PY32_HAL_PREFIX ?= py32f071
+
+SDK_DIR = hw/mcu/puya/$(PY32_SDK_NAME)
+HAL_DIR = $(SDK_DIR)/Drivers/$(PY32_SERIES)_HAL_Driver
+CMSIS_DIR = $(SDK_DIR)/Drivers/CMSIS
+CMSIS_DEVICE_DIR = $(CMSIS_DIR)/Device/$(PY32_SERIES)
+
+DEPS_SUBMODULES += $(SDK_DIR)
+
+CFLAGS += \
+ -DCFG_TUSB_MCU=OPT_MCU_PY32F0 \
+ -DUSE_HAL_DRIVER
+
+# Puya HAL leaves some CMSIS-compatible callback parameters intentionally unused.
+CFLAGS += -Wno-error=unused-parameter
+
+MCU_DIR = $(SDK_DIR)
+
+SRC_C += \
+ src/portable/mentor/musb/dcd_musb.c \
+ hw/bsp/py32f0/family.c \
+ $(SDK_DIR)/Templates/$(PY32_TEMPLATE)/Src/$(PY32_SYSTEM_SOURCE) \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_cortex.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_flash.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_gpio.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_pwr.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_rcc.c \
+ $(HAL_DIR)/Src/$(PY32_HAL_PREFIX)_hal_rcc_ex.c
+
+SRC_S += $(SDK_DIR)/Templates/$(PY32_TEMPLATE)/EIDE/$(PY32_STARTUP)
+
+INC += \
+ $(TOP)/hw/bsp/py32f0 \
+ $(TOP)/$(CMSIS_DIR)/Include \
+ $(TOP)/$(CMSIS_DEVICE_DIR)/Include \
+ $(TOP)/$(HAL_DIR)/Inc \
+ $(TOP)/hw/bsp/py32f0/boards/$(BOARD)
+
+SKIP_NANOLIB = 1
+
+LDFLAGS += \
+ -nostdlib -nostartfiles \
+ --specs=nosys.specs --specs=nano.specs \
+ -Wl,--gc-sections \
+ -Wl,--print-memory-usage
+
+CPU_CORE ?= cortex-m0plus
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 0959ac3a9..d599f89fb 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -703,6 +703,17 @@
#define TU_ATTR_FAST_FUNC __attribute__((section(".fast")))
+//--------------------------------------------------------------------+
+// Puya
+//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_PY32F0)
+ #define TUP_USBIP_MUSB
+ #define TUP_USBIP_MUSB_PY32
+ #define TUP_DCD_ENDPOINT_MAX 6
+ // PY32 shares the buffer between IN and OUT of the same endpoint number.
+ // Possible to share IN/OUT if only one direction is armed at any one time
+ #define CFG_TUD_ENDPOINT_ONE_DIRECTION_ONLY 1
+
#endif
// External USB controller
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index 17993f23a..45c6fe7df 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -24,6 +24,8 @@
#include "musb_ti.h"
#elif defined(TUP_USBIP_MUSB_ADI)
#include "musb_max32.h"
+#elif defined(TUP_USBIP_MUSB_PY32)
+ #include "musb_py32.h"
#else
#error "Unsupported MCU"
#endif
@@ -45,6 +47,7 @@ typedef struct {
};
uint16_t length; /* the number of bytes in the buffer */
uint16_t remaining; /* the number of bytes remaining in the buffer */
+ uint16_t mps; /* maximum packet size */
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;
@@ -159,6 +162,14 @@ TU_ATTR_ALWAYS_INLINE static inline pipe_state_t* pipe_get(uint8_t epnum, tusb_d
return &_dcd.pipe[idx];
}
+TU_ATTR_ALWAYS_INLINE static inline uint16_t musb_mps_to_maxp(uint16_t mps) {
+#if defined(TUP_USBIP_MUSB_PY32)
+ return (uint8_t) ((mps + 7u) / 8u);
+#else
+ return mps;
+#endif
+}
+
//--------------------------------------------------------------------
// HW FIFO Helper
// Note: Index register is already set by caller
@@ -223,7 +234,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool hwfifo_config(musb_regs_t* musb, unsign
bool double_packet) {
(void) mps;
- #if defined(TUP_USBIP_MUSB_ADI)
+ #if defined(TUP_USBIP_MUSB_PY32)
+ (void) musb; (void) epnum; (void) is_rx; (void) double_packet;
+ #elif defined(TUP_USBIP_MUSB_ADI)
// AnalogDevice FIFO sizes: EP1..7 = 512 B, EP8..9 = 2048 B, EP10..11 = 4096 B.
// DPB requires FIFO >= 2 * MPS. For HS bulk (MPS=512) only EP >= 8 qualifies.
// Force single-buffered on EP < 8 even if the caller requested DPB.
@@ -266,7 +279,7 @@ TU_ATTR_ALWAYS_INLINE static inline void hwfifo_flush(musb_regs_t* musb, unsigne
// write to txfifo using pipe_state_t info
static void pipe_write(musb_regs_t* musb_regs, pipe_state_t* pipe, uint8_t epnum) {
musb_ep_csr_t* ep_csr = &musb_regs->indexed_csr;
- const uint16_t mps = ep_csr->tx_maxp & MUSB_TXMAXP_PACKET_SIZE_M;
+ const uint16_t mps = pipe->mps;
const uint16_t xact_len = tu_min16(mps, pipe->remaining);
volatile void *hwfifo = &musb_regs->fifo[epnum];
if (xact_len) {
@@ -320,7 +333,7 @@ static void process_epin_isr(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epn
// release the FIFO slot by clearing RXRDY. return true if short packet
static bool pipe_read(musb_regs_t* musb_regs, pipe_state_t* pipe, uint8_t epnum) {
musb_ep_csr_t* ep_csr = &musb_regs->indexed_csr; // index already set in process_epout_isr()
- const uint16_t mps = ep_csr->rx_maxp & MUSB_RXMAXP_PACKET_SIZE_M;
+ const uint16_t mps = pipe->mps;
const uint16_t rx_count = ep_csr->rx_count;
const uint16_t xact_len = tu_min16(tu_min16(pipe->remaining, mps), rx_count);
volatile void *hwfifo = &musb_regs->fifo[epnum];
@@ -632,7 +645,11 @@ static void process_bus_reset_isr(uint8_t rhport) {
hwfifo_reset(musb, i, 0);
hwfifo_reset(musb, i, 1);
}
+#if defined(TUP_USBIP_MUSB_PY32)
+ dcd_event_bus_reset(rhport, TUSB_SPEED_FULL, true);
+#else
dcd_event_bus_reset(rhport, (musb->power & MUSB_POWER_HSMODE) ? TUSB_SPEED_HIGH : TUSB_SPEED_FULL, true);
+#endif
}
/*------------------------------------------------------------------
@@ -641,6 +658,11 @@ static void process_bus_reset_isr(uint8_t rhport) {
#if CFG_TUSB_DEBUG >= MUSB_DEBUG
static void print_musb_info(musb_regs_t* musb_regs) {
+#if defined(TUP_USBIP_MUSB_PY32)
+ (void) musb_regs;
+ // musb discovery fields not present
+ TU_LOG1("musb py32 fixed full-speed configuration\r\n");
+#else
// print version, epinfo, raminfo, config_data0, fifo_size
TU_LOG1("musb version = %u.%u\r\n", musb_regs->hwvers_bit.major, musb_regs->hwvers_bit.minor);
TU_LOG1("Number of endpoints: %u TX, %u RX\r\n", musb_regs->epinfo_bit.tx_ep_num, musb_regs->epinfo_bit.rx_ep_num);
@@ -657,6 +679,7 @@ static void print_musb_info(musb_regs_t* musb_regs) {
TU_LOG1("FIFO %u Size: TX %u RX %u\r\n", i, musb_regs->indexed_csr.fifo_size_bit.tx, musb_regs->indexed_csr.fifo_size_bit.rx);
}
#endif
+#endif
}
#endif
@@ -716,15 +739,23 @@ void dcd_remote_wakeup(uint8_t rhport) {
void dcd_connect(uint8_t rhport)
{
musb_regs_t* musb_regs = MUSB_REGS(rhport);
+#if defined(TUP_USBIP_MUSB_PY32)
+ (void) musb_regs;
+#else
musb_regs->power |= TUD_OPT_HIGH_SPEED ? MUSB_POWER_HSENAB : 0;
musb_regs->power |= MUSB_POWER_SOFTCONN;
+#endif
}
// Disconnect by disabling internal pull-up resistor on D+/D-
void dcd_disconnect(uint8_t rhport)
{
musb_regs_t* musb_regs = MUSB_REGS(rhport);
+#if defined(TUP_USBIP_MUSB_PY32)
+ (void) musb_regs;
+#else
musb_regs->power &= ~MUSB_POWER_SOFTCONN;
+#endif
}
void dcd_sof_enable(uint8_t rhport, bool en)
@@ -750,6 +781,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->mps = (uint16_t) mps;
pipe->armed = false;
musb_regs_t* musb = MUSB_REGS(rhport);
@@ -757,7 +789,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
const uint8_t is_rx = (1 - epdir);
musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx];
- maxp_csr->maxp = mps;
+ maxp_csr->maxp = musb_mps_to_maxp((uint16_t) mps);
maxp_csr->csrh = 0;
#if MUSB_CFG_SHARED_FIFO
if (epdir) {
@@ -768,7 +800,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
hwfifo_flush(musb, epn, is_rx, true);
TU_ASSERT(hwfifo_config(musb, epn, is_rx, mps, ep_desc->bmAttributes.xfer == TUSB_XFER_BULK));
- musb->intren_ep[is_rx] |= TU_BIT(epn);
+ musb->intren_ep[is_rx ^ MUSB_INTR_EP_TX_RX_SWAP] |= TU_BIT(epn);
return true;
}
@@ -779,6 +811,8 @@ bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet
musb_regs_t* musb = MUSB_REGS(rhport);
musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn);
const uint8_t is_rx = 1 - dir_in;
+ pipe_state_t *pipe = pipe_get(epn, dir_in);
+ pipe->mps = largest_packet_size;
ep_csr->maxp_csr[is_rx].csrh = 0;
return hwfifo_config(musb, epn, is_rx, largest_packet_size, true);
}
@@ -796,6 +830,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->mps = (uint16_t) mps;
pipe->armed = false;
musb_regs_t* musb = MUSB_REGS(rhport);
@@ -803,7 +838,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc )
const uint8_t is_rx = 1 - dir_in;
musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[is_rx];
- maxp_csr->maxp = mps;
+ maxp_csr->maxp = musb_mps_to_maxp((uint16_t) mps);
maxp_csr->csrh |= MUSB_CSRH_ISO;
#if MUSB_CFG_SHARED_FIFO
if (dir_in) {
@@ -818,7 +853,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc )
musb->fifo_size[is_rx] = hwfifo_byte2size(mps) | MUSB_FIFOSZ_DOUBLE_PACKET;
#endif
- musb->intren_ep[is_rx] |= TU_BIT(epn);
+ musb->intren_ep[is_rx ^ MUSB_INTR_EP_TX_RX_SWAP] |= TU_BIT(epn);
if (ie) musb_dcd_int_enable(rhport);
@@ -839,7 +874,7 @@ void dcd_edpt_close_all(uint8_t rhport)
musb_ep_maxp_csr_t* maxp_csr = &ep_csr->maxp_csr[d];
hwfifo_flush(musb, i, d, true);
hwfifo_reset(musb, i, d);
- maxp_csr->maxp = 0;
+ maxp_csr->maxp = musb_mps_to_maxp(0);
maxp_csr->csrh = 0;
}
}
diff --git a/src/portable/mentor/musb/musb_max32.h b/src/portable/mentor/musb/musb_max32.h
index 628454216..9cf99126e 100644
--- a/src/portable/mentor/musb/musb_max32.h
+++ b/src/portable/mentor/musb/musb_max32.h
@@ -28,6 +28,7 @@ extern "C" {
#define MUSB_CFG_SHARED_FIFO 1 // shared FIFO for TX and RX endpoints
#define MUSB_CFG_DYNAMIC_FIFO 0 // dynamic EP FIFO sizing
+#define MUSB_INTR_EP_TX_RX_SWAP 0
static const uintptr_t MUSB_BASES[] = { MXC_BASE_USBHS };
diff --git a/src/portable/mentor/musb/musb_py32.h b/src/portable/mentor/musb/musb_py32.h
new file mode 100644
index 000000000..68d58ccb8
--- /dev/null
+++ b/src/portable/mentor/musb/musb_py32.h
@@ -0,0 +1,79 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2026, Ha Thach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_MUSB_PY32_H_
+#define TUSB_MUSB_PY32_H_
+
+#include "py32f0xx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// PY32 does not expose generic MUSB shared FIFO allocation registers; this
+// selects the existing TX_MODE path required for IN endpoints.
+#define MUSB_CFG_SHARED_FIFO 1
+#define MUSB_CFG_DYNAMIC_FIFO 0
+#define MUSB_INTR_EP_TX_RX_SWAP 1
+
+static const uintptr_t MUSB_BASES[] = { USBD_BASE };
+static const IRQn_Type musb_irqs[] = { USB_IRQn };
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_phy_init(uint8_t rhport) {
+ musb_regs_t* musb_regs = MUSB_REGS(rhport);
+
+ musb_regs->index = 0;
+ musb_regs->faddr = 0;
+ musb_regs->intr_usben = MUSB_IE_RESET | MUSB_IE_RESUME | MUSB_IE_SUSPND;
+ musb_regs->intr_txen = TU_BIT(0);
+ musb_regs->intr_rxen = 0;
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_enable(uint8_t rhport) {
+ NVIC_EnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_disable(uint8_t rhport) {
+ NVIC_DisableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_clear(uint8_t rhport) {
+ NVIC_ClearPendingIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline unsigned musb_dcd_get_int_enable(uint8_t rhport) {
+ return NVIC_GetEnableIRQ(musb_irqs[rhport]);
+}
+
+TU_ATTR_ALWAYS_INLINE static inline void musb_dcd_int_handler_enter(uint8_t rhport) {
+ (void) rhport;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/portable/mentor/musb/musb_ti.h b/src/portable/mentor/musb/musb_ti.h
index db2e237d2..1cf26b1cb 100644
--- a/src/portable/mentor/musb/musb_ti.h
+++ b/src/portable/mentor/musb/musb_ti.h
@@ -30,6 +30,7 @@
#define MUSB_CFG_SHARED_FIFO 0
#define MUSB_CFG_DYNAMIC_FIFO 1
#define MUSB_CFG_DYNAMIC_FIFO_SIZE 4096
+#define MUSB_INTR_EP_TX_RX_SWAP 0
static const uintptr_t MUSB_BASES[] = { USB0_BASE };
diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h
index 3c079cb25..1e8a761c0 100644
--- a/src/portable/mentor/musb/musb_type.h
+++ b/src/portable/mentor/musb/musb_type.h
@@ -64,6 +64,75 @@
#define __R volatile const
#endif
+#if defined(TUP_USBIP_MUSB_PY32)
+
+typedef struct TU_ATTR_PACKED {
+ __IO uint8_t csrh; // 0x04, 0x08: CSRH
+ __IO uint8_t csrl; // 0x05, 0x09: CSRL
+ __IO uint8_t maxp; // 0x06, 0x0A: MAXP
+ __I uint8_t reserved;
+} musb_ep_maxp_csr_t;
+
+TU_VERIFY_STATIC(sizeof(musb_ep_maxp_csr_t) == 4, "size is not correct");
+
+typedef struct TU_ATTR_PACKED {
+ __IO uint8_t csr0l; // 0x00: CSR0
+ __IO uint8_t count0; // 0x01: COUNT0
+ __I uint8_t reserved_0x02[2];
+
+ union {
+ struct {
+ __IO uint8_t tx_csrh; // 0x04: TX CSRH
+ __IO uint8_t tx_csrl; // 0x05: TX CSRL
+ __IO uint8_t tx_maxp; // 0x06: TX MAXP
+ __I uint8_t reserved_0x07;
+
+ __IO uint8_t rx_csrh; // 0x08: RX CSRH
+ __IO uint8_t rx_csrl; // 0x09: RX CSRL
+ __IO uint8_t rx_maxp; // 0x0A: RX MAXP
+ __I uint8_t reserved_0x0b;
+ };
+
+ musb_ep_maxp_csr_t maxp_csr[2];
+ };
+
+ __IO uint16_t rx_count; // 0x0C: RX COUNT
+ __I uint8_t reserved_0x0e[2];
+} musb_ep_csr_t;
+
+TU_VERIFY_STATIC(sizeof(musb_ep_csr_t) == 16, "size is not correct");
+
+typedef struct TU_ATTR_PACKED {
+ __IO uint8_t faddr; // 0x00: FADDR
+ __IO uint8_t power; // 0x01: POWER
+ __I uint8_t reserved_0x02[2];
+
+ __IO uint8_t intr_usb; // 0x04: INTRUSB
+ __IO uint8_t intr_rx; // 0x05: INTRRX
+ __IO uint8_t intr_tx; // 0x06: INTRTX
+ __I uint8_t reserved_0x07;
+
+ __IO uint8_t intr_usben; // 0x08: INTRUSBEN
+ union {
+ struct {
+ __IO uint8_t intr_rxen; // 0x09: INTRRXEN
+ __IO uint8_t intr_txen; // 0x0A: INTRTXEN
+ };
+
+ __IO uint8_t intren_ep[2]; // 0x09-0x0A: RX, TX
+ };
+ __I uint8_t reserved_0x0b;
+
+ __IO uint16_t frame; // 0x0C: FRAME
+ __IO uint8_t index; // 0x0E: INDEX
+ __I uint8_t reserved_0x0f;
+
+ musb_ep_csr_t indexed_csr; // 0x10-0x1F: Indexed CSR
+ __IO uint32_t fifo[16]; // 0x20-0x5F: FIFO 0-15
+} musb_regs_t;
+
+#else
+
typedef struct TU_ATTR_PACKED {
__IO uint16_t maxp; // 0x00, 0x04: MAXP
__IO uint8_t csrl; // 0x02, 0x06: CSRL
@@ -277,6 +346,8 @@ typedef struct {
TU_VERIFY_STATIC(sizeof(musb_regs_t) == 0x350, "size is not correct");
+#endif
+
//--------------------------------------------------------------------+
// Helper
//--------------------------------------------------------------------+
diff --git a/src/tusb_option.h b/src/tusb_option.h
index e19ee1629..0036fbe3c 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -104,6 +104,9 @@
#define OPT_MCU_NUC120 802
#define OPT_MCU_NUC505 803
+// Puya
+#define OPT_MCU_PY32F0 850 ///< Puya PY32F0
+
// Espressif
#define OPT_MCU_ESP32S2 900 ///< Espressif ESP32-S2
#define OPT_MCU_ESP32S3 901 ///< Espressif ESP32-S3
@@ -349,9 +352,13 @@
//------------ MUSB --------------//
#if defined(TUP_USBIP_MUSB)
#define CFG_TUD_EDPT_DEDICATED_HWFIFO 1
- #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32 bit data
- #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access
- #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access
+ #if defined(TUP_USBIP_MUSB_PY32)
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 1 // 8 bit data
+ #else
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_STRIDE 4 // 32 bit data
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access
+ #define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access
+ #endif
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo
#endif
diff --git a/tools/get_deps.py b/tools/get_deps.py
index 9d745ee26..e26810cac 100755
--- a/tools/get_deps.py
+++ b/tools/get_deps.py
@@ -82,6 +82,12 @@ deps_optional = {
'hw/mcu/nxp/mcux-devices-rt': ['https://github.com/nxp-mcuxpresso/mcux-devices-rt',
'dba2b523c9df61f3330bd186242f8210a8e47c45',
'imxrt'],
+ 'hw/mcu/puya/PY32F071_Firmware': ['https://github.com/OpenPuya/PY32F071_Firmware.git',
+ '73e384cddce63e3019de41d9b6af17dfc96fa536',
+ 'py32f0'],
+ 'hw/mcu/puya/PY32F072_Firmware': ['https://github.com/OpenPuya/PY32F072_Firmware.git',
+ 'bc3a6cdbece335a27abb8b51e6fc4911f5116185',
+ 'py32f0'],
'hw/mcu/raspberry_pi/FreeRTOS-Kernel': ['https://github.com/raspberrypi/FreeRTOS-Kernel.git',
'4f7299d6ea746b27a9dd19e87af568e34bd65b15',
'rp2040'],