Merge pull request #3694 from rhgndf/py32f0

Puya PY32F07x support
This commit is contained in:
Zixun LI
2026-07-19 22:20:09 +02:00
committed by GitHub
23 changed files with 968 additions and 13 deletions

1
.gitignore vendored
View File

@ -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/

View File

@ -259,6 +259,8 @@ Supported CPUs
| +---------+-------------------+--------+------+-----------+------------------------+--------------------+
| | RW61x | ✅ | ✅ | ✅ | ci_hs, ehci | |
+--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+
| Puya | PY32F071, PY32F072 | ✅ | ❌ | ❌ | musb | 1-dir ep |
+--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+
| Raspberry Pi | RP2040, RP2350 | ✅ | ✅ | ❌ | rp2040, pio_usb | |
+--------------+-----+-----------------------+--------+------+-----------+------------------------+--------------------+
| Renesas | RX | 63N, 65N, 72N | ✅ | ✅ | ❌ | rusb2 | |

View File

@ -33,3 +33,14 @@ Reference: `CH32V30X Reference Manual`_ USBFS/USBHS controller chapter
Data corruption may occur on isochronous endpoints. Due to the lacking of FIFO for interrupt status registers, later completed transfer will overwrite `INT_ST` and `RX_LEN` register if previous transfer processing is not completed.
Other types of transfers are not affected.
Puya PY32F071/072
---------------------------------
**Severity: Very Low**
Reference: `PY32F07x Reference Manual` USBD chapter
The USB device controller (MUSB-like) has 5 application endpoints EP1-EP5 with fixed FIFO sizes
shared between IN and OUT of the same endpoint number: EP1 = 512 B, EP2-4 = 128 B, EP5 = 64 B.
This is much lower than the max ISO ep size of 1024 for high EP numbers.
Place large isochronous endpoints on EP1 and size descriptors accordingly.

View File

@ -109,8 +109,10 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_N_FORMATS 2
// Audio format type I specifications
#if defined(__RX__)
#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 48000 // 16bit/48kHz is the best quality for Renesas RX
#if defined(__RX__) || (CFG_TUSB_MCU == OPT_MCU_PY32F0)
// RX : 16bit/48kHz is the best quality for Renesas RX
// PY32F0 : 48kHz/16bit keeps ISO packets <= 98 B so both directions fit the fixed EP FIFOs (EP1 512 B, EP2 128 B)
#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 48000
#else
#define CFG_TUD_AUDIO_FUNC_1_MAX_SAMPLE_RATE 96000 // 24bit/96kHz is the best quality for full-speed, high-speed is needed beyond this
#endif
@ -123,7 +125,7 @@ extern "C" {
#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_N_BYTES_PER_SAMPLE_RX 2
#define CFG_TUD_AUDIO_FUNC_1_FORMAT_1_RESOLUTION_RX 16
#if defined(__RX__)
#if defined(__RX__) || (CFG_TUSB_MCU == OPT_MCU_PY32F0)
// 8bit in 8bit slots
#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_N_BYTES_PER_SAMPLE_TX 1
#define CFG_TUD_AUDIO_FUNC_1_FORMAT_2_RESOLUTION_TX 8

View File

@ -10,6 +10,7 @@ mcu:SAMD11
mcu:STM32L0
mcu:STM32F0
mcu:KINETIS_KL
mcu:PY32F0
mcu:STM32H7RS
mcu:STM32N6
family:broadcom_64bit

View File

@ -98,6 +98,11 @@ uint8_t const * tud_descriptor_device_cb(void)
#define EPNUM_AUDIO_OUT 0x0A
#define EPNUM_AUDIO_IN 0x0B
#define EPNUM_AUDIO_INT 0x01
#elif TU_CHECK_MCU(OPT_MCU_PY32F0)
// Speaker OUT (196 B) only fits EP1 (512 B FIFO); mic IN (98 B) fits EP2 (128 B)
#define EPNUM_AUDIO_OUT 0x01
#define EPNUM_AUDIO_IN 0x02
#define EPNUM_AUDIO_INT 0x03
#else
#define EPNUM_AUDIO_IN 0x01
#define EPNUM_AUDIO_OUT 0x02

View File

@ -0,0 +1,108 @@
/*
* 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 FREERTOS_CONFIG_H_
#define FREERTOS_CONFIG_H_
#ifndef __IASMARM__
#include "py32f0xx.h"
#endif
#define configENABLE_MPU 0
#define configENABLE_FPU 0
#define configENABLE_TRUSTZONE 0
#define configMINIMAL_SECURE_STACK_SIZE 1024
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#define configCPU_CLOCK_HZ SystemCoreClock
#define configTICK_RATE_HZ 1000
#define configMAX_PRIORITIES 5
#define configMINIMAL_STACK_SIZE 128
#define configTOTAL_HEAP_SIZE ( configSUPPORT_DYNAMIC_ALLOCATION * 4 * 1024 )
#define configMAX_TASK_NAME_LEN 16
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_MUTEXES 1
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_COUNTING_SEMAPHORES 1
#define configQUEUE_REGISTRY_SIZE 4
#define configUSE_QUEUE_SETS 0
#define configUSE_TIME_SLICING 0
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 1
#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0
#define configSUPPORT_STATIC_ALLOCATION 1
#define configSUPPORT_DYNAMIC_ALLOCATION 0
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configUSE_MALLOC_FAILED_HOOK 0
#define configCHECK_FOR_STACK_OVERFLOW 2
#define configCHECK_HANDLER_INSTALLATION 0
#define configGENERATE_RUN_TIME_STATS 0
#define configRECORD_STACK_HIGH_ADDRESS 1
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 0
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES 2
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 2 )
#define configTIMER_QUEUE_LENGTH 32
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
#define INCLUDE_vTaskPrioritySet 0
#define INCLUDE_uxTaskPriorityGet 0
#define INCLUDE_vTaskDelete 0
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_xResumeFromISR 0
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_xTaskGetSchedulerState 0
#define INCLUDE_xTaskGetCurrentTaskHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 0
#define INCLUDE_xTaskGetIdleTaskHandle 0
#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
#define INCLUDE_pcTaskGetTaskName 0
#define INCLUDE_eTaskGetState 0
#define INCLUDE_xEventGroupSetBitFromISR 0
#define INCLUDE_xTimerPendFunctionCall 0
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
#define vPortSVCHandler SVC_Handler
#define configPRIO_BITS __NVIC_PRIO_BITS
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY ( ( 1 << configPRIO_BITS ) - 1 )
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << ( 8 - configPRIO_BITS ) )
#endif

View File

@ -0,0 +1,12 @@
set(PYOCD_TARGET py32f071xb)
set(PY32_SERIES PY32F071)
set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/py32f071xb.ld)
function(update_board TARGET)
target_compile_definitions(${TARGET} PUBLIC
PY32F071xB
CFG_EXAMPLE_MSC_READONLY
CFG_EXAMPLE_MSC_DUAL_READONLY
CFG_EXAMPLE_VIDEO_READONLY
)
endfunction()

View File

@ -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

View File

@ -0,0 +1,12 @@
PY32_SERIES = PY32F071
CFLAGS += \
-DPY32F071xB \
-DCFG_EXAMPLE_MSC_READONLY \
-DCFG_EXAMPLE_MSC_DUAL_READONLY \
-DCFG_EXAMPLE_VIDEO_READONLY
LD_FILE = $(BOARD_PATH)/py32f071xb.ld
PYOCD_TARGET = py32f071xb
flash: flash-pyocd

View File

@ -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

View File

@ -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) }
}

133
hw/bsp/py32f0/family.c Normal file
View File

@ -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) {
}

View File

@ -0,0 +1,89 @@
include_guard()
include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake)
if (NOT DEFINED MCU_VARIANT)
set(MCU_VARIANT PY32F071)
endif ()
string(TOLOWER ${MCU_VARIANT} PY32_SERIES_LOWER)
set(PY32_SDK_NAME ${MCU_VARIANT}_Firmware)
set(PY32_TEMPLATE ${MCU_VARIANT}xx_Templates)
set(PY32_STARTUP startup_${PY32_SERIES_LOWER}xx.s)
set(PY32_SYSTEM_SOURCE system_${PY32_SERIES_LOWER}.c)
set(PY32_HAL_PREFIX ${PY32_SERIES_LOWER})
set(PY32_SDK ${TOP}/hw/mcu/puya/${PY32_SDK_NAME})
set(PY32_HAL ${PY32_SDK}/Drivers/${MCU_VARIANT}_HAL_Driver)
set(PY32_CMSIS ${PY32_SDK}/Drivers/CMSIS/Device/${MCU_VARIANT})
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()

58
hw/bsp/py32f0/family.mk Normal file
View File

@ -0,0 +1,58 @@
UF2_FAMILY_ID = 0x0
include $(TOP)/$(BOARD_PATH)/board.mk
MCU_VARIANT ?= PY32F071
PY32_SERIES_LOWER = $(subst PY32F,py32f,$(MCU_VARIANT))
PY32_SDK_NAME = $(MCU_VARIANT)_Firmware
PY32_TEMPLATE = $(MCU_VARIANT)xx_Templates
PY32_STARTUP = startup_$(PY32_SERIES_LOWER)xx.s
PY32_SYSTEM_SOURCE = system_$(PY32_SERIES_LOWER).c
PY32_HAL_PREFIX = $(PY32_SERIES_LOWER)
SDK_DIR = hw/mcu/puya/$(PY32_SDK_NAME)
HAL_DIR = $(SDK_DIR)/Drivers/$(MCU_VARIANT)_HAL_Driver
CMSIS_DIR = $(SDK_DIR)/Drivers/CMSIS
CMSIS_DEVICE_DIR = $(CMSIS_DIR)/Device/$(MCU_VARIANT)
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

View File

@ -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

View File

@ -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,12 @@ 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) is_rx; (void) double_packet;
// Puya FIFO sizes: EP0 = 64 B, EP1 = 512 B, EP2..4 = 128 B, EP5 = 64 B, shared between IN and OUT.
static const uint16_t py32_fifo_size[] = { 64, 512, 128, 128, 128, 64 };
return epnum < TU_ARRAY_SIZE(py32_fifo_size) && mps <= py32_fifo_size[epnum];
#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 +282,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 +336,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 +648,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 +661,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 +682,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
@ -712,6 +738,18 @@ void dcd_remote_wakeup(uint8_t rhport) {
musb_regs->power &= ~MUSB_POWER_RESUME;
}
#if defined(TUP_USBIP_MUSB_PY32)
void dcd_connect(uint8_t rhport)
{
(void) rhport;
}
void dcd_disconnect(uint8_t rhport)
{
(void) rhport;
}
#else
// Connect by enabling internal pull-up resistor on D+/D-
void dcd_connect(uint8_t rhport)
{
@ -727,6 +765,8 @@ void dcd_disconnect(uint8_t rhport)
musb_regs->power &= ~MUSB_POWER_SOFTCONN;
}
#endif
void dcd_sof_enable(uint8_t rhport, bool en)
{
(void) rhport;
@ -750,6 +790,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 +798,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 +809,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,8 +820,11 @@ 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);
TU_ASSERT(hwfifo_config(musb, epn, is_rx, largest_packet_size, true));
return true;
}
bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc ) {
@ -796,6 +840,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 +848,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 +863,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 +884,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;
}
}

View File

@ -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 };

View File

@ -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

View File

@ -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 };

View File

@ -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
//--------------------------------------------------------------------+

View File

@ -204,6 +204,9 @@
// HPMicro
#define OPT_MCU_HPM 2600 ///< HPMicro
// Puya
#define OPT_MCU_PY32F0 2700 ///< Puya PY32F0
// Check if configured MCU is one of listed
// Apply TU_MCU_IS_EQUAL with || as separator to list of input
#define TU_MCU_IS_EQUAL(_m) (CFG_TUSB_MCU == (_m))
@ -400,7 +403,9 @@
#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
#if !defined(TUP_USBIP_MUSB_PY32)
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_16BIT_ACCESS // allow odd 16bit access
#endif
#define CFG_TUSB_FIFO_HWFIFO_DATA_ODD_8BIT_ACCESS // allow odd 8bit access
#define CFG_TUSB_FIFO_HWFIFO_ADDR_STRIDE 0 // fixed hwfifo
#endif

View File

@ -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'],