From 036266e4b18329c3f68748cc21a3a43c9b390160 Mon Sep 17 00:00:00 2001 From: Jie Feng Date: Sun, 14 Jun 2026 19:24:55 +0800 Subject: [PATCH 1/4] CH32X035 port --- README.rst | 2 + docs/reference/boards.rst | 29 +-- docs/reference/dependencies.rst | 1 + .../weact_ch32x035_core_board/board.cmake | 9 + .../boards/weact_ch32x035_core_board/board.h | 23 +++ .../boards/weact_ch32x035_core_board/board.mk | 7 + hw/bsp/ch32x035/ch32x035_conf.h | 23 +++ hw/bsp/ch32x035/ch32x035_it.h | 29 +++ hw/bsp/ch32x035/family.c | 176 ++++++++++++++++++ hw/bsp/ch32x035/family.cmake | 104 +++++++++++ hw/bsp/ch32x035/family.mk | 45 +++++ hw/bsp/ch32x035/linker/ch32x035.ld | 151 +++++++++++++++ hw/bsp/ch32x035/system_ch32x035.c | 76 ++++++++ hw/bsp/ch32x035/system_ch32x035.h | 28 +++ hw/bsp/ch32x035/wch-riscv.cfg | 12 ++ src/common/tusb_mcu.h | 9 + src/portable/wch/ch32_usbfs_reg.h | 7 + src/portable/wch/dcd_ch32_usbfs.c | 26 ++- src/tusb_option.h | 1 + tools/get_deps.py | 3 + 20 files changed, 744 insertions(+), 17 deletions(-) create mode 100644 hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.cmake create mode 100644 hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.h create mode 100644 hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.mk create mode 100644 hw/bsp/ch32x035/ch32x035_conf.h create mode 100644 hw/bsp/ch32x035/ch32x035_it.h create mode 100644 hw/bsp/ch32x035/family.c create mode 100644 hw/bsp/ch32x035/family.cmake create mode 100644 hw/bsp/ch32x035/family.mk create mode 100644 hw/bsp/ch32x035/linker/ch32x035.ld create mode 100644 hw/bsp/ch32x035/system_ch32x035.c create mode 100644 hw/bsp/ch32x035/system_ch32x035.h create mode 100644 hw/bsp/ch32x035/wch-riscv.cfg diff --git a/README.rst b/README.rst index e5806bafc0..18a3550d51 100644 --- a/README.rst +++ b/README.rst @@ -312,6 +312,8 @@ Supported CPUs | | CH32V305, CH32V307 | 🟡 | | ✅ | ch32_usbfs/hs | ISO data loss [2]_ | | +-----------------------------+--------+------+-----------+------------------------+--------------------+ | | CH583/2, CH32V103 | 🟡 | | ❌ | ch32_usbfs | ISO data loss [2]_ | +| +-----------------------------+--------+------+-----------+------------------------+--------------------+ +| | CH32X033, CH32X035 | ✅ | | ❌ | ch32_usbfs | EP4 quirk | +--------------+-----------------------------+--------+------+-----------+------------------------+--------------------+ Table Legend diff --git a/docs/reference/boards.rst b/docs/reference/boards.rst index 1481756715..41b8c6de3e 100644 --- a/docs/reference/boards.rst +++ b/docs/reference/boards.rst @@ -363,17 +363,18 @@ fomu fomu fomu https://tomu.im/fomu.html WCH --- -================== ============================= ======== ===================================================================== ====== -Board Name Family URL Note -================== ============================= ======== ===================================================================== ====== -ch32f205r-r0 CH32F205r-r0 ch32f20x https://github.com/openwch/ch32f20x -ch32v103c_bluepill CH32V103C8T6-Bluepill ch32v10x https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill -ch32v103r_r1_1v0 CH32V103R-R1-1v1 ch32v10x https://github.com/openwch/ch32v103/tree/main/SCHPCB/CH32V103R-R1-1v1 -ch32v203c_r0_1v0 CH32V203C-R0-1v0 ch32v20x https://github.com/openwch/ch32v20x/tree/main/SCHPCB/CH32V203C-R0 -ch32v203g_r0_1v0 CH32V203G-R0-1v0 ch32v20x https://github.com/openwch/ch32v20x/tree/main/SCHPCB/CH32V203C-R0 -nanoch32v203 nanoCH32V203 ch32v20x https://github.com/wuxx/nanoCH32V203 -ch32v307v_r1_1v0 CH32V307V-R1-1v0 ch32v30x https://github.com/openwch/ch32v307/tree/main/SCHPCB/CH32V307V-R1-1v0 -nanoch32v305 nanoCH32V305 ch32v30x https://github.com/wuxx/nanoCH32V305 -ch582m_evt CH582M-EVT evaluation board ch583 https://www.wch-ic.com/products/CH582.html -yd-ch582m yd-ch582m from vcc-gnd studio ch583 http://vcc-gnd.com/ -================== ============================= ======== ===================================================================== ====== +=========================== ============================= ======== ===================================================================== ====== +Board Name Family URL Note +=========================== ============================= ======== ===================================================================== ====== +ch32f205r-r0 CH32F205r-r0 ch32f20x https://github.com/openwch/ch32f20x +ch32v103c_bluepill CH32V103C8T6-Bluepill ch32v10x https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill +ch32v103r_r1_1v0 CH32V103R-R1-1v1 ch32v10x https://github.com/openwch/ch32v103/tree/main/SCHPCB/CH32V103R-R1-1v1 +ch32v203c_r0_1v0 CH32V203C-R0-1v0 ch32v20x https://github.com/openwch/ch32v20x/tree/main/SCHPCB/CH32V203C-R0 +ch32v203g_r0_1v0 CH32V203G-R0-1v0 ch32v20x https://github.com/openwch/ch32v20x/tree/main/SCHPCB/CH32V203C-R0 +nanoch32v203 nanoCH32V203 ch32v20x https://github.com/wuxx/nanoCH32V203 +ch32v307v_r1_1v0 CH32V307V-R1-1v0 ch32v30x https://github.com/openwch/ch32v307/tree/main/SCHPCB/CH32V307V-R1-1v0 +nanoch32v305 nanoCH32V305 ch32v30x https://github.com/wuxx/nanoCH32V305 +ch582m_evt CH582M-EVT evaluation board ch583 https://www.wch-ic.com/products/CH582.html +yd-ch582m yd-ch582m from vcc-gnd studio ch583 http://vcc-gnd.com/ +weact_ch32x035_core_board WeAct CH32X035 Core Board ch32x035 https://github.com/WeActStudio/WeActStudio.CH32X035CoreBoard +=========================== ============================= ======== ===================================================================== ====== diff --git a/docs/reference/dependencies.rst b/docs/reference/dependencies.rst index 146192ef8c..67808d929d 100644 --- a/docs/reference/dependencies.rst +++ b/docs/reference/dependencies.rst @@ -91,6 +91,7 @@ hw/mcu/wch/ch32v103 https://github.com/openwch/ch32v103.gi hw/mcu/wch/ch32v20x https://github.com/openwch/ch32v20x.git c4c38f507e258a4e69b059ccc2dc27dde33cea1b ch32v20x hw/mcu/wch/ch32v307 https://github.com/openwch/ch32v307.git 184f21b852cb95eed58e86e901837bc9fff68775 ch32v30x hw/mcu/wch/ch583 https://github.com/openwch/ch583.git bd508ad7ceed48377619837051412a651952857f ch583 +hw/mcu/wch/ch32x035 https://github.com/openwch/ch32x035.git c6253942b29ff2a3f5e2829182a874afffa45881 ch32x035 lib/CMSIS_5 https://github.com/ARM-software/CMSIS_5.git 2b7495b8535bdcb306dac29b9ded4cfb679d7e5c kinetis_k kinetis_kl lpc54 rw61x mm32 msp432e4 nrf samd2x_l2x lpc11 lpc13 lpc15 lpc17 lpc18 lpc40 lpc43 stm32c0 stm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h5 stm32h7 stm32h7rs stm32l0 stm32l1 stm32l4 stm32l5 stm32u0 stm32u5 stm32wb stm32wba sam3x samd11 samd21 samd2x_l2x samd51 samd5x_e5x same5x same7x samg tm4c lib/CMSIS_6 https://github.com/ARM-software/CMSIS_6.git 6f0a58d01aa9bd2feba212097f9afe7acd991d52 imxrt kinetis_k32l ra stm32n6 lpc51 lpc55 mcx stm32c5 lib/FreeRTOS-Kernel https://github.com/FreeRTOS/FreeRTOS-Kernel.git 9b777ae5c5b8e9e456065a00294d1e5f5f9facf5 all diff --git a/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.cmake b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.cmake new file mode 100644 index 0000000000..36dd500e3e --- /dev/null +++ b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.cmake @@ -0,0 +1,9 @@ +set(LD_FLASH_SIZE 62K) +set(LD_RAM_SIZE 20K) + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + SYSCLK_FREQ_48MHz_HSI=48000000 + CFG_EXAMPLE_MSC_DUAL_READONLY + ) +endfunction() diff --git a/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.h b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.h new file mode 100644 index 0000000000..e42970ed70 --- /dev/null +++ b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.h @@ -0,0 +1,23 @@ +/* metadata: + name: WeAct CH32X035 Core Board + url: https://github.com/WeActStudio/WeActStudio.CH32X035CoreBoard +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define LED_PORT GPIOB +#define LED_PIN GPIO_Pin_12 +#define LED_STATE_ON 1 +#define LED_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE) +#define LED_MODE GPIO_Mode_Out_PP + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.mk b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.mk new file mode 100644 index 0000000000..bbd8106f39 --- /dev/null +++ b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.mk @@ -0,0 +1,7 @@ +CFLAGS += \ + -DSYSCLK_FREQ_48MHz_HSI=48000000 \ + -DCFG_EXAMPLE_MSC_DUAL_READONLY \ + +LDFLAGS += \ + -Wl,--defsym=__FLASH_SIZE=62K \ + -Wl,--defsym=__RAM_SIZE=20K \ diff --git a/hw/bsp/ch32x035/ch32x035_conf.h b/hw/bsp/ch32x035/ch32x035_conf.h new file mode 100644 index 0000000000..9672f983ff --- /dev/null +++ b/hw/bsp/ch32x035/ch32x035_conf.h @@ -0,0 +1,23 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : ch32x035_conf.h + * Author : WCH + * Version : V1.0.0 + * Date : 2023/04/06 + * Description : Library configuration file. + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ +#ifndef __CH32X035_CONF_H +#define __CH32X035_CONF_H + +#include "ch32x035_dbgmcu.h" +#include "ch32x035_flash.h" +#include "ch32x035_gpio.h" +#include "ch32x035_misc.h" +#include "ch32x035_rcc.h" +#include "ch32x035_usb.h" +#include "ch32x035_usart.h" + +#endif diff --git a/hw/bsp/ch32x035/ch32x035_it.h b/hw/bsp/ch32x035/ch32x035_it.h new file mode 100644 index 0000000000..5d6c5d9b2a --- /dev/null +++ b/hw/bsp/ch32x035/ch32x035_it.h @@ -0,0 +1,29 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : ch32x035_it.h + * Author : WCH + * Version : V1.0.0 + * Date : 2023/04/06 + * Description : This file contains the headers of the interrupt handlers. + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ +#ifndef __CH32X035_IT_H +#define __CH32X035_IT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ch32x035.h" + +void USBFS_IRQHandler(void); +void USBFSWakeUp_IRQHandler(void); +void SysTick_Handler(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch32x035/family.c b/hw/bsp/ch32x035/family.c new file mode 100644 index 0000000000..edfaa6fbcf --- /dev/null +++ b/hw/bsp/ch32x035/family.c @@ -0,0 +1,176 @@ +/* metadata: +manufacturer: WCH +*/ + +#include + +// https://github.com/openwch/ch32v307/pull/90 +// https://github.com/openwch/ch32v20x/pull/12 +#ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wstrict-prototypes" +#endif + +#include "ch32x035.h" +#include "ch32x035_it.h" + +#ifdef __GNUC__ + #pragma GCC diagnostic pop +#endif + +#include "bsp/board_api.h" +#include "board.h" + +__attribute__((interrupt)) __attribute__((used)) void USBFS_IRQHandler(void) { +#if CFG_TUD_ENABLED && CFG_TUD_WCH_USBIP_USBFS + tud_int_handler(0); +#endif +} + +__attribute__((interrupt)) __attribute__((used)) void USBFSWakeUp_IRQHandler(void) { +#if CFG_TUD_ENABLED && CFG_TUD_WCH_USBIP_USBFS + tud_int_handler(0); +#endif +} + +//--------------------------------------------------------------------+ +// Board API +//--------------------------------------------------------------------+ +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +__attribute__((interrupt)) void SysTick_Handler(void) { + SysTick->SR = 0; + system_ticks++; +} + +static uint32_t SysTick_Config(uint32_t ticks) { + NVIC_EnableIRQ(SysTicK_IRQn); + SysTick->CTLR = 0; + SysTick->SR = 0; + SysTick->CNT = 0; + SysTick->CMP = ticks - 1; + SysTick->CTLR = 0xF; + return 0; +} + +uint32_t tusb_time_millis_api(void) { + return system_ticks; +} +#endif + +void board_init(void) { + __disable_irq(); + + SystemCoreClockUpdate(); + +#if CFG_TUSB_OS == OPT_OS_NONE + SysTick_Config(SystemCoreClock / 1000); +#endif + + LED_CLOCK_EN(); + + GPIO_InitTypeDef GPIO_InitStructure = { + .GPIO_Pin = LED_PIN, + .GPIO_Mode = LED_MODE, + .GPIO_Speed = GPIO_Speed_50MHz, + }; + GPIO_Init(LED_PORT, &GPIO_InitStructure); + + RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBFS, ENABLE); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_16; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; + GPIO_Init(GPIOC, &GPIO_InitStructure); + + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_17; + GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; + GPIO_Init(GPIOC, &GPIO_InitStructure); + + AFIO->CTLR = (AFIO->CTLR & ~(AFIO_CTLR_UDP_PUE | AFIO_CTLR_UDM_PUE)) | AFIO_CTLR_USB_PHY_V33 | AFIO_CTLR_UDP_PUE | + AFIO_CTLR_USB_IOEN; + +#ifdef UART_DEV + UART_CLOCK_EN(); + GPIO_InitTypeDef usart_init = { + .GPIO_Pin = UART_TX_PIN | UART_RX_PIN, + .GPIO_Speed = GPIO_Speed_50MHz, + .GPIO_Mode = GPIO_Mode_AF_PP, + }; + GPIO_Init(GPIOA, &usart_init); + + USART_InitTypeDef usart = { + .USART_BaudRate = 115200, + .USART_WordLength = USART_WordLength_8b, + .USART_StopBits = USART_StopBits_1, + .USART_Parity = USART_Parity_No, + .USART_Mode = USART_Mode_Tx | USART_Mode_Rx, + .USART_HardwareFlowControl = USART_HardwareFlowControl_None, + }; + USART_Init(UART_DEV, &usart); + USART_Cmd(UART_DEV, ENABLE); +#endif + + __enable_irq(); +} + +void board_reset_to_bootloader(void) { +} + +void board_led_write(bool state) { + GPIO_WriteBit(LED_PORT, LED_PIN, state ? LED_STATE_ON : (1 - LED_STATE_ON)); +} + +uint32_t board_button_read(void) { + return false; +} + +size_t board_get_unique_id(uint8_t id[], size_t max_len) { + (void)max_len; + volatile uint32_t *ch32_uuid = ((volatile uint32_t *)0x1FFFF7E8UL); + uint32_t *serial_32 = (uint32_t *)(uintptr_t)id; + serial_32[0] = ch32_uuid[0]; + serial_32[1] = ch32_uuid[1]; + serial_32[2] = ch32_uuid[2]; + + return 12; +} + +int board_uart_read(uint8_t *buf, int len) { +#ifdef UART_DEV + int count; + for (count = 0; count < len; count++) { + if (USART_GetFlagStatus(UART_DEV, USART_FLAG_RXNE) == RESET) { + break; + } + buf[count] = USART_ReceiveData(UART_DEV); + } + return count; +#else + (void)buf; + (void)len; + return 0; +#endif +} + +int board_uart_write(const void *buf, int len) { +#ifdef UART_DEV + const uint8_t *p = (const uint8_t *)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 +} diff --git a/hw/bsp/ch32x035/family.cmake b/hw/bsp/ch32x035/family.cmake new file mode 100644 index 0000000000..1ec1bb01b0 --- /dev/null +++ b/hw/bsp/ch32x035/family.cmake @@ -0,0 +1,104 @@ +include_guard() + +set(UF2_FAMILY_ID 0x699b62ec) +set(CH32_FAMILY ch32x035) +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 rv32imac-ilp32 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TOOLCHAIN}.cmake) + +set(FAMILY_MCUS CH32X035 CACHE INTERNAL "") +set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") + +set(RHPORT_DEVICE 0) + +#------------------------------------ +# Startup & Linker script +#------------------------------------ +if (NOT DEFINED LD_FILE_GNU) + set(LD_FILE_GNU ${CMAKE_CURRENT_LIST_DIR}/linker/${CH32_FAMILY}.ld) +endif () +set(LD_FILE_Clang ${LD_FILE_GNU}) +if (NOT DEFINED STARTUP_FILE_GNU) + set(STARTUP_FILE_GNU ${SDK_SRC_DIR}/Startup/startup_${CH32_FAMILY}.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}/Core/core_riscv.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_dbgmcu.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_gpio.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_misc.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_rcc.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_usart.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_${CH32_FAMILY}.c + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${SDK_SRC_DIR}/Core + ${SDK_SRC_DIR}/Peripheral/inc + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ) + target_compile_definitions(${BOARD_TARGET} PUBLIC + BOARD_TUD_RHPORT=${RHPORT_DEVICE} + ) + + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang") + target_compile_options(${BOARD_TARGET} PUBLIC -mcmodel=medany) + endif() +endfunction() + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + family_add_tinyusb(${TARGET} OPT_MCU_CH32X035) + + target_sources(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ${TOP}/src/portable/wch/dcd_ch32_usbfs.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 + -nostartfiles + --specs=nosys.specs --specs=nano.specs + -Wl,--defsym=__FLASH_SIZE=${LD_FLASH_SIZE} + -Wl,--defsym=__RAM_SIZE=${LD_RAM_SIZE} + "LINKER:--script=${LD_FILE_GNU}" + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + message(FATAL_ERROR "Clang is not supported") + elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") + target_link_options(${TARGET} PUBLIC + "LINKER:--config=${LD_FILE_IAR}" + ) + endif () + + set_source_files_properties(${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} PROPERTIES + SKIP_LINTING ON + COMPILE_OPTIONS -w) + + # Flashing + family_add_bin_hex(${TARGET}) + family_flash_openocd_wch(${TARGET}) + family_flash_wlink_rs(${TARGET}) +endfunction() diff --git a/hw/bsp/ch32x035/family.mk b/hw/bsp/ch32x035/family.mk new file mode 100644 index 0000000000..5d2ef64158 --- /dev/null +++ b/hw/bsp/ch32x035/family.mk @@ -0,0 +1,45 @@ +# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +CROSS_COMPILE ?= riscv-none-elf- + +CH32_FAMILY = ch32x035 +SDK_DIR = hw/mcu/wch/ch32x035 +SDK_SRC_DIR = $(SDK_DIR)/EVT/EXAM/SRC + +include $(TOP)/$(BOARD_PATH)/board.mk +CPU_CORE ?= rv32imac-ilp32 + +CFLAGS += \ + -mcmodel=medany \ + -ffat-lto-objects \ + -flto \ + -DCFG_TUSB_MCU=OPT_MCU_CH32X035 \ + -DCFG_TUD_WCH_USBIP_USBFS=1 \ + +CFLAGS += -Wno-error=strict-prototypes + +LDFLAGS += \ + -nostdlib -nostartfiles \ + --specs=nosys.specs --specs=nano.specs \ + +LD_FILE = $(FAMILY_PATH)/linker/${CH32_FAMILY}.ld + +SRC_C += \ + src/portable/wch/dcd_ch32_usbfs.c \ + $(SDK_SRC_DIR)/Core/core_riscv.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_dbgmcu.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_gpio.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_misc.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_rcc.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_usart.c \ + +SRC_S += $(SDK_SRC_DIR)/Startup/startup_${CH32_FAMILY}.S + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(SDK_SRC_DIR)/Core \ + $(TOP)/$(SDK_SRC_DIR)/Peripheral/inc \ + +FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V + +OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg +flash: flash-wlink-rs diff --git a/hw/bsp/ch32x035/linker/ch32x035.ld b/hw/bsp/ch32x035/linker/ch32x035.ld new file mode 100644 index 0000000000..c52b058046 --- /dev/null +++ b/hw/bsp/ch32x035/linker/ch32x035.ld @@ -0,0 +1,151 @@ +/* Define default values if not already defined */ +__flash_size = DEFINED(__FLASH_SIZE) ? __FLASH_SIZE : 62K; +__ram_size = DEFINED(__RAM_SIZE) ? __RAM_SIZE : 20K; +__stack_size = DEFINED(__STACK_SIZE) ? __STACK_SIZE : 2048; + +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000, LENGTH = __flash_size + RAM (xrw) : ORIGIN = 0x20000000, LENGTH = __ram_size +} + +ENTRY( _start ) + +PROVIDE( _stack_size = __stack_size ); +_estack = ORIGIN(RAM) + LENGTH(RAM); + +SECTIONS +{ + .init : + { + _sinit = .; + . = ALIGN(4); + KEEP(*(SORT_NONE(.init))) + . = ALIGN(4); + _einit = .; + } >FLASH AT>FLASH + + .vector : + { + *(.vector); + . = ALIGN(64); + } >FLASH AT>FLASH + + .text : + { + . = ALIGN(4); + *(.text) + *(.text.*) + *(.rodata) + *(.rodata*) + *(.gnu.linkonce.t.*) + . = ALIGN(4); + } >FLASH AT>FLASH + + .fini : + { + KEEP(*(SORT_NONE(.fini))) + . = ALIGN(4); + } >FLASH AT>FLASH + + PROVIDE( _etext = . ); + PROVIDE( _eitcm = . ); + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH AT>FLASH + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH AT>FLASH + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH AT>FLASH + + .ctors : + { + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } >FLASH AT>FLASH + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } >FLASH AT>FLASH + + .dalign : + { + . = ALIGN(4); + PROVIDE(_data_vma = .); + } >RAM AT>FLASH + + .dlalign : + { + . = ALIGN(4); + PROVIDE(_data_lma = .); + } >FLASH AT>FLASH + + .data : + { + *(.gnu.linkonce.r.*) + *(.data .data.*) + *(.gnu.linkonce.d.*) + . = ALIGN(8); + PROVIDE( __global_pointer$ = . + 0x800 ); + *(.sdata .sdata.*) + *(.sdata2.*) + *(.gnu.linkonce.s.*) + . = ALIGN(8); + *(.srodata.cst16) + *(.srodata.cst8) + *(.srodata.cst4) + *(.srodata.cst2) + *(.srodata .srodata.*) + . = ALIGN(4); + PROVIDE( _edata = .); + } >RAM AT>FLASH + + .bss : + { + . = ALIGN(4); + PROVIDE( _sbss = .); + *(.sbss*) + *(.gnu.linkonce.sb.*) + *(.bss*) + *(.gnu.linkonce.b.*) + *(COMMON*) + . = ALIGN(4); + PROVIDE( _ebss = .); + } >RAM AT>FLASH + + PROVIDE( _end = _ebss); + PROVIDE( end = . ); + + .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : + { + PROVIDE( _heap_end = . ); + . = ALIGN(4); + PROVIDE(_susrstack = . ); + . = . + __stack_size; + PROVIDE( _eusrstack = .); + } >RAM +} diff --git a/hw/bsp/ch32x035/system_ch32x035.c b/hw/bsp/ch32x035/system_ch32x035.c new file mode 100644 index 0000000000..1a48906042 --- /dev/null +++ b/hw/bsp/ch32x035/system_ch32x035.c @@ -0,0 +1,76 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : system_ch32x035.c + * Author : WCH + * Version : V1.0.0 + * Date : 2023/04/06 + * Description : CH32X035 Device Peripheral Access Layer System Source File. + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ +#include "ch32x035.h" + +#if defined SYSCLK_FREQ_8MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_8MHz_HSI; +#elif defined SYSCLK_FREQ_12MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_12MHz_HSI; +#elif defined SYSCLK_FREQ_16MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_16MHz_HSI; +#elif defined SYSCLK_FREQ_24MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz_HSI; +#else +uint32_t SystemCoreClock = HSI_VALUE; +#endif + +__I uint8_t AHBPrescTable[16] = {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8}; + +static void SetSysClock(void); + +void SystemInit(void) { + RCC->CTLR |= (uint32_t)0x00000001; + RCC->CFGR0 |= (uint32_t)0x00000050; + RCC->CFGR0 &= (uint32_t)0xF8FFFF5F; + SetSysClock(); +} + +void SystemCoreClockUpdate(void) { + uint32_t tmp; + + SystemCoreClock = HSI_VALUE; + tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)]; + + if (((RCC->CFGR0 & RCC_HPRE) >> 4) < 8) { + SystemCoreClock /= tmp; + } else { + SystemCoreClock >>= tmp; + } +} + +static void SetSysClock(void) { + GPIO_IPD_Unused(); + + FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY); + FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_2; + + RCC->CFGR0 &= (uint32_t)0xFFFFFF0F; + +#if defined SYSCLK_FREQ_8MHz_HSI + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV6; + FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY); + FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_0; +#elif defined SYSCLK_FREQ_12MHz_HSI + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV4; + FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY); + FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_0; +#elif defined SYSCLK_FREQ_16MHz_HSI + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV3; + FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY); + FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_1; +#elif defined SYSCLK_FREQ_24MHz_HSI + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2; + FLASH->ACTLR = (uint32_t)FLASH_ACTLR_LATENCY_1; +#else + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; +#endif +} diff --git a/hw/bsp/ch32x035/system_ch32x035.h b/hw/bsp/ch32x035/system_ch32x035.h new file mode 100644 index 0000000000..173b16c1b9 --- /dev/null +++ b/hw/bsp/ch32x035/system_ch32x035.h @@ -0,0 +1,28 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : system_ch32x035.h + * Author : WCH + * Version : V1.0.0 + * Date : 2023/04/06 + * Description : CH32X035 Device Peripheral Access Layer System Header File. + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ +#ifndef __SYSTEM_CH32X035_H +#define __SYSTEM_CH32X035_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t SystemCoreClock; + +extern void SystemInit(void); +extern void SystemCoreClockUpdate(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch32x035/wch-riscv.cfg b/hw/bsp/ch32x035/wch-riscv.cfg new file mode 100644 index 0000000000..7051c5c941 --- /dev/null +++ b/hw/bsp/ch32x035/wch-riscv.cfg @@ -0,0 +1,12 @@ +adapter driver wlinke +adapter speed 6000 +transport select sdi + +set _CHIPNAME wch_riscv +jtag 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 0x20000000 -work-area-size 10000 -work-area-backup 1 +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 1f2afb03a0..554c21a5b1 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -599,6 +599,15 @@ #define TUP_DCD_ENDPOINT_MAX 8 +#elif TU_CHECK_MCU(OPT_MCU_CH32X035) + #define TUP_USBIP_WCH_USBFS + + #if !defined(CFG_TUD_WCH_USBIP_USBFS) + #define CFG_TUD_WCH_USBIP_USBFS 1 + #endif + + #define TUP_DCD_ENDPOINT_MAX 8 + #elif TU_CHECK_MCU(OPT_MCU_CH32V20X) // v20x support both port0 FSDEV (USBD) and port1 USBFS #define TUP_USBIP_WCH_USBFS diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index 8bac103fee..e16761da0f 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -177,6 +177,13 @@ #define NVIC_EnableIRQ(n) PFIC_EnableIRQ(n) #define NVIC_DisableIRQ(n) PFIC_DisableIRQ(n) #endif +#elif CFG_TUSB_MCU == OPT_MCU_CH32X035 + #include + #define USBOTG_FS USBFSD + #define CH32_USBFS_EP_CTRL_COMBINED 1 + #define CH32_USBFS_EP_MANUAL_TOG 1 + #define CH32_USBFS_EP4_SHARES_EP0 1 + #define USBHD_IRQn USBFS_IRQn #endif #ifdef __GNUC__ diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index a6458748a9..bf9565fe44 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -30,6 +30,25 @@ #define EP_DMA(ep) (*((ep) <= 3u ? &USBOTG_FS->EP_DMA_0_3[0].DMA + (ep) * 2u \ : (ep) == 4u ? &USBOTG_FS->EP_DMA_0_3[0].DMA \ : &USBOTG_FS->EP_DMA_5_7[0].DMA + ((ep) - 5u) * 2u)) + #elif CFG_TUSB_MCU == OPT_MCU_CH32X035 + static inline volatile uint32_t* ch32_usbfs_ep_dma_reg(uint8_t ep) { + switch (ep) { + case 0: return &USBOTG_FS->UEP0_DMA; + case 1: return &USBOTG_FS->UEP1_DMA; + case 2: return &USBOTG_FS->UEP2_DMA; + case 3: return &USBOTG_FS->UEP3_DMA; + case 4: return &USBOTG_FS->UEP0_DMA; + case 5: return &USBOTG_FS->UEP5_DMA; + case 6: return &USBOTG_FS->UEP6_DMA; + default: return &USBOTG_FS->UEP7_DMA; + } + } + + // There's a gap between EP4 and EP5 registers. + #define EP_DMA(ep) (*ch32_usbfs_ep_dma_reg(ep)) + #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * (ep) + ((ep) > 4 ? 24 : 0)]) + #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_CTRL_H)[2 * (ep) + ((ep) > 4 ? 24 : 0)]) + #define EP_RX_CTRL(ep) EP_TX_CTRL(ep) #else #define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) @@ -37,9 +56,8 @@ #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) #endif -// Endpoint control register access. The newer USBFS IP (CH32V20x/V307/X035) has separate -// TX_CTRL and RX_CTRL bytes per endpoint; the older IP (CH32V103) has a single combined -// UEPn_CTRL register. These helpers hide the difference so the rest of the driver is shared. +// Endpoint control register access. Some WCH USBFS IPs have separate TX_CTRL/RX_CTRL bytes per +// endpoint; others have a single combined UEPn_CTRL register. These helpers hide the difference. // Values use the newer-IP encoding (USBFS_EP_T_*/USBFS_EP_R_*); the combined path remaps them. #ifdef CH32_USBFS_EP_CTRL_COMBINED #ifndef EP_CTRL // parts with a custom register map (CH58X) define EP_CTRL directly in reg.h @@ -293,6 +311,8 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { // CH58X: a single mode register enables EP5/6/7 RX+TX (different bit layout than CH32). USBOTG_FS->UEP567_MOD = RB_UEP5_RX_EN | RB_UEP5_TX_EN | RB_UEP6_RX_EN | RB_UEP6_TX_EN | RB_UEP7_RX_EN | RB_UEP7_TX_EN; +#elif CFG_TUSB_MCU == OPT_MCU_CH32X035 + USBOTG_FS->UEP567_MOD = 0x3F; #else USBOTG_FS->UEP5_6_MOD = 0xCC; USBOTG_FS->UEP7_MOD = 0x0C; diff --git a/src/tusb_option.h b/src/tusb_option.h index e19ee1629d..5f5200b3be 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -178,6 +178,7 @@ #define OPT_MCU_CH32V103 2230 ///< WCH CH32V103 #define OPT_MCU_CH583 2240 ///< WCH CH583 #define OPT_MCU_CH582 OPT_MCU_CH583 ///< WCH CH582 (alias, same USB IP as CH583) +#define OPT_MCU_CH32X035 2250 ///< WCH CH32X035 // NXP LPC MCX #define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series diff --git a/tools/get_deps.py b/tools/get_deps.py index 9d745ee266..38262aebcd 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -256,6 +256,9 @@ 'hw/mcu/wch/ch583': ['https://github.com/openwch/ch583.git', 'bd508ad7ceed48377619837051412a651952857f', 'ch583'], + 'hw/mcu/wch/ch32x035': ['https://github.com/openwch/ch32x035.git', + 'c6253942b29ff2a3f5e2829182a874afffa45881', + 'ch32x035'], 'hw/mcu/artery/at32f403a_407': ['https://github.com/ArteryTek/AT32F403A_407_Firmware_Library.git', 'f2cb360c3d28fada76b374308b8c4c61d37a090b', 'at32f403a_407'], From 769ee1ae5ce556f87ade60a7c64f904e879fbf32 Mon Sep 17 00:00:00 2001 From: Jie Feng Date: Sun, 14 Jun 2026 20:07:09 +0800 Subject: [PATCH 2/4] Examples now pass --- .../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/device/net_lwip_webserver/skip.txt | 1 + .../boards/weact_ch32x035_core_board/board.cmake | 1 - .../boards/weact_ch32x035_core_board/board.mk | 4 +--- hw/bsp/ch32x035/family.cmake | 2 ++ hw/bsp/ch32x035/family.mk | 2 ++ src/portable/wch/dcd_ch32_usbfs.c | 13 ++----------- 11 files changed, 13 insertions(+), 15 deletions(-) diff --git a/examples/device/audio_4_channel_mic_freertos/skip.txt b/examples/device/audio_4_channel_mic_freertos/skip.txt index 1fd6b4b8a6..695f9b292a 100644 --- a/examples/device/audio_4_channel_mic_freertos/skip.txt +++ b/examples/device/audio_4_channel_mic_freertos/skip.txt @@ -3,6 +3,7 @@ mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 mcu:CH583 +mcu:CH32X035 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/audio_test_freertos/skip.txt b/examples/device/audio_test_freertos/skip.txt index 660bacd259..90d621986f 100644 --- a/examples/device/audio_test_freertos/skip.txt +++ b/examples/device/audio_test_freertos/skip.txt @@ -3,6 +3,7 @@ mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 mcu:CH583 +mcu:CH32X035 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/cdc_msc_freertos/skip.txt b/examples/device/cdc_msc_freertos/skip.txt index 48781de842..72d260079b 100644 --- a/examples/device/cdc_msc_freertos/skip.txt +++ b/examples/device/cdc_msc_freertos/skip.txt @@ -3,6 +3,7 @@ mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 mcu:CH583 +mcu:CH32X035 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/hid_composite_freertos/skip.txt b/examples/device/hid_composite_freertos/skip.txt index 97d8e168b2..2e1cfb8928 100644 --- a/examples/device/hid_composite_freertos/skip.txt +++ b/examples/device/hid_composite_freertos/skip.txt @@ -3,6 +3,7 @@ mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 mcu:CH583 +mcu:CH32X035 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/midi_test_freertos/skip.txt b/examples/device/midi_test_freertos/skip.txt index 97d8e168b2..2e1cfb8928 100644 --- a/examples/device/midi_test_freertos/skip.txt +++ b/examples/device/midi_test_freertos/skip.txt @@ -3,6 +3,7 @@ mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 mcu:CH583 +mcu:CH32X035 mcu:CXD56 mcu:F1C100S mcu:GD32VF103 diff --git a/examples/device/net_lwip_webserver/skip.txt b/examples/device/net_lwip_webserver/skip.txt index 5e5562087f..1cf67e341f 100644 --- a/examples/device/net_lwip_webserver/skip.txt +++ b/examples/device/net_lwip_webserver/skip.txt @@ -1,5 +1,6 @@ mcu:CH32V103 mcu:CH32V20X +mcu:CH32X035 mcu:LPC11UXX mcu:LPC13XX mcu:LPC15XX diff --git a/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.cmake b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.cmake index 36dd500e3e..4687e127fe 100644 --- a/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.cmake +++ b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.cmake @@ -4,6 +4,5 @@ set(LD_RAM_SIZE 20K) function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC SYSCLK_FREQ_48MHz_HSI=48000000 - CFG_EXAMPLE_MSC_DUAL_READONLY ) endfunction() diff --git a/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.mk b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.mk index bbd8106f39..b6698c9721 100644 --- a/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.mk +++ b/hw/bsp/ch32x035/boards/weact_ch32x035_core_board/board.mk @@ -1,6 +1,4 @@ -CFLAGS += \ - -DSYSCLK_FREQ_48MHz_HSI=48000000 \ - -DCFG_EXAMPLE_MSC_DUAL_READONLY \ +CFLAGS += -DSYSCLK_FREQ_48MHz_HSI=48000000 LDFLAGS += \ -Wl,--defsym=__FLASH_SIZE=62K \ diff --git a/hw/bsp/ch32x035/family.cmake b/hw/bsp/ch32x035/family.cmake index 1ec1bb01b0..2eb9f20e77 100644 --- a/hw/bsp/ch32x035/family.cmake +++ b/hw/bsp/ch32x035/family.cmake @@ -49,6 +49,8 @@ function(family_add_board BOARD_TARGET) ) target_compile_definitions(${BOARD_TARGET} PUBLIC BOARD_TUD_RHPORT=${RHPORT_DEVICE} + CFG_EXAMPLE_MSC_DUAL_READONLY + CFG_EXAMPLE_VIDEO_READONLY ) update_board(${BOARD_TARGET}) diff --git a/hw/bsp/ch32x035/family.mk b/hw/bsp/ch32x035/family.mk index 5d2ef64158..715ef810c1 100644 --- a/hw/bsp/ch32x035/family.mk +++ b/hw/bsp/ch32x035/family.mk @@ -14,6 +14,8 @@ CFLAGS += \ -flto \ -DCFG_TUSB_MCU=OPT_MCU_CH32X035 \ -DCFG_TUD_WCH_USBIP_USBFS=1 \ + -DCFG_EXAMPLE_MSC_DUAL_READONLY=1 \ + -DCFG_EXAMPLE_VIDEO_READONLY=1 CFLAGS += -Wno-error=strict-prototypes diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index bf9565fe44..c7c73fcdac 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -47,8 +47,7 @@ // There's a gap between EP4 and EP5 registers. #define EP_DMA(ep) (*ch32_usbfs_ep_dma_reg(ep)) #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * (ep) + ((ep) > 4 ? 24 : 0)]) - #define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_CTRL_H)[2 * (ep) + ((ep) > 4 ? 24 : 0)]) - #define EP_RX_CTRL(ep) EP_TX_CTRL(ep) + #define EP_CTRL(ep) ((&USBOTG_FS->UEP0_CTRL_H)[2 * (ep) + ((ep) > 4 ? 24 : 0)]) #else #define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep]) #define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep]) @@ -60,10 +59,6 @@ // endpoint; others have a single combined UEPn_CTRL register. These helpers hide the difference. // Values use the newer-IP encoding (USBFS_EP_T_*/USBFS_EP_R_*); the combined path remaps them. #ifdef CH32_USBFS_EP_CTRL_COMBINED - #ifndef EP_CTRL // parts with a custom register map (CH58X) define EP_CTRL directly in reg.h - #define EP_CTRL(ep) EP_TX_CTRL(ep) // UEPn_TX_CTRL field aliases the combined UEPn_CTRL register - #endif - static inline uint8_t ep_tx_to_comb(uint8_t v) { uint8_t c = v & USBFS_EP_T_RES_MASK; // IN response: bits [1:0] in both encodings if (v & USBFS_EP_T_TOG) { c |= USBFS_EPC_T_TOG; } @@ -307,11 +302,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { // enable other endpoints but NAK everything USBOTG_FS->UEP4_1_MOD = 0xCC; USBOTG_FS->UEP2_3_MOD = 0xCC; -#if CFG_TUSB_MCU == OPT_MCU_CH583 - // CH58X: a single mode register enables EP5/6/7 RX+TX (different bit layout than CH32). - USBOTG_FS->UEP567_MOD = RB_UEP5_RX_EN | RB_UEP5_TX_EN | RB_UEP6_RX_EN | RB_UEP6_TX_EN | - RB_UEP7_RX_EN | RB_UEP7_TX_EN; -#elif CFG_TUSB_MCU == OPT_MCU_CH32X035 +#if CFG_TUSB_MCU == OPT_MCU_CH583 || CFG_TUSB_MCU == OPT_MCU_CH32X035 USBOTG_FS->UEP567_MOD = 0x3F; #else USBOTG_FS->UEP5_6_MOD = 0xCC; From 930d59457a9697a1b6e766728ab1aab70a52c5fa Mon Sep 17 00:00:00 2001 From: Jie Feng Date: Tue, 23 Jun 2026 12:59:27 +0800 Subject: [PATCH 3/4] EP buffer cleanup and fix UART --- hw/bsp/ch32x035/family.c | 2 +- src/portable/wch/dcd_ch32_usbfs.c | 117 +++++++++++++++++------------- 2 files changed, 66 insertions(+), 53 deletions(-) diff --git a/hw/bsp/ch32x035/family.c b/hw/bsp/ch32x035/family.c index edfaa6fbcf..1e31add8f0 100644 --- a/hw/bsp/ch32x035/family.c +++ b/hw/bsp/ch32x035/family.c @@ -160,7 +160,7 @@ int board_uart_write(const void *buf, int len) { const uint8_t *p = (const uint8_t *)buf; int count = 0; while (count < len) { - if (USART_GetFlagStatus(UART_DEV, USART_FLAG_TC) != RESET) { + if (USART_GetFlagStatus(UART_DEV, USART_FLAG_TXE) != RESET) { USART_SendData(UART_DEV, p[count]); count++; } else { diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index c7c73fcdac..c03e9b3655 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -31,6 +31,7 @@ : (ep) == 4u ? &USBOTG_FS->EP_DMA_0_3[0].DMA \ : &USBOTG_FS->EP_DMA_5_7[0].DMA + ((ep) - 5u) * 2u)) #elif CFG_TUSB_MCU == OPT_MCU_CH32X035 + // EP0-4 and EP5-7 are split, and EP4 has no DMA register static inline volatile uint32_t* ch32_usbfs_ep_dma_reg(uint8_t ep) { switch (ep) { case 0: return &USBOTG_FS->UEP0_DMA; @@ -55,10 +56,14 @@ #define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep]) #endif -// Endpoint control register access. Some WCH USBFS IPs have separate TX_CTRL/RX_CTRL bytes per -// endpoint; others have a single combined UEPn_CTRL register. These helpers hide the difference. -// Values use the newer-IP encoding (USBFS_EP_T_*/USBFS_EP_R_*); the combined path remaps them. +// Map generic TX/RX control values to split or combined endpoint control registers. +// Combined: V103/CH58X/X035 +// Split: V20x/V307 #ifdef CH32_USBFS_EP_CTRL_COMBINED + #ifndef EP_CTRL // parts with a custom register map (CH58X) define EP_CTRL directly in reg.h + #define EP_CTRL(ep) EP_TX_CTRL(ep) // UEPn_TX_CTRL field aliases the combined UEPn_CTRL register + #endif + static inline uint8_t ep_tx_to_comb(uint8_t v) { uint8_t c = v & USBFS_EP_T_RES_MASK; // IN response: bits [1:0] in both encodings if (v & USBFS_EP_T_TOG) { c |= USBFS_EPC_T_TOG; } @@ -127,16 +132,16 @@ static struct { // share one contiguous 192-byte DMA region (EP4 has no DMA register of its own): // EP0 [0:63] (half-duplex OUT+IN) + EP4 OUT [64:127] + EP4 IN [128:191]. Every other endpoint // (incl. EP3, which is bulk-only here — CH58X has no isochronous support) gets a plain 128-byte - // OUT+IN buffer, so no oversized EP3 buffer is needed. - TU_ATTR_ALIGNED(4) uint8_t ep0_ep4_buffer[3 * 64]; - TU_ATTR_ALIGNED(4) uint8_t ep1_buffer[2][64]; - TU_ATTR_ALIGNED(4) uint8_t ep2_buffer[2][64]; - TU_ATTR_ALIGNED(4) uint8_t ep3_buffer[2][64]; - TU_ATTR_ALIGNED(4) uint8_t ep5_buffer[2][64]; - TU_ATTR_ALIGNED(4) uint8_t ep6_buffer[2][64]; - TU_ATTR_ALIGNED(4) uint8_t ep7_buffer[2][64]; + TU_ATTR_ALIGNED(4) union { + uint8_t ep0_ep4_buffer[3 * 64]; + struct { + uint8_t ep0_buffer[64]; + uint8_t ep4_buffer[2][64]; + }; + }; + TU_ATTR_ALIGNED(4) uint8_t buffer[6][2][64]; #else - TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64]; + TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX - 1][2][64]; // EP3 IN gets an enlarged buffer for full-speed isochronous (packets up to 1023 B). TU_ATTR_ALIGNED(4) struct { // OUT transfers >64 bytes will overwrite queued IN data! @@ -153,60 +158,64 @@ static struct { // their own named buffer (see the struct above). #ifdef CH32_USBFS_EP4_SHARES_EP0 // OUT base of the regular CH58X endpoints (EP1/2/3/5/6/7; EP0/EP4 share ep0_ep4_buffer). -static inline uint8_t* ch58x_ep_buffer(uint8_t ep) { +static inline uint8_t* ep_buffer(uint8_t ep, uint8_t dir) { switch (ep) { - case 1: return data.ep1_buffer[0]; - case 2: return data.ep2_buffer[0]; - case 3: return data.ep3_buffer[0]; - case 5: return data.ep5_buffer[0]; - case 6: return data.ep6_buffer[0]; - default: return data.ep7_buffer[0]; // ep == 7 + case 1: return data.buffer[0][dir]; + case 2: return data.buffer[1][dir]; + case 3: return data.buffer[2][dir]; + case 4: return data.ep4_buffer[dir]; + case 5: return data.buffer[3][dir]; + case 6: return data.buffer[4][dir]; + default: return data.buffer[5][dir]; // ep == 7 } } -#endif static inline uint32_t ep_dma_addr(uint8_t ep) { -#ifdef CH32_USBFS_EP4_SHARES_EP0 - if (ep == 0 || ep == 4) { return (uint32_t) &data.ep0_ep4_buffer[0]; } // EP4 shares EP0's DMA - return (uint32_t) ch58x_ep_buffer(ep); + if (ep == 0 || ep == 4) { return (uint32_t) data.ep0_ep4_buffer; } // EP4 shares EP0's DMA + return (uint32_t) ep_buffer(ep, TUSB_DIR_OUT); +} + +static inline uint8_t* ep_out_buf(uint8_t ep) { + if (ep == 0) { return data.ep0_buffer; } + return ep_buffer(ep, TUSB_DIR_OUT); +} + +static inline uint8_t* ep_in_buf(uint8_t ep) { + if (ep == 0) { return data.ep0_buffer; } // EP0 half-duplex: IN reuses OUT chunk + return ep_buffer(ep, TUSB_DIR_IN); +} + +// EP4 on CH58X/X035 has no DMA register (shares EP0's); skip its EP_DMA() write. +static inline bool ep_shares_ep0_dma(uint8_t ep) { + return ep == 4; +} #else +static inline uint8_t* ep_buffer(uint8_t ep, uint8_t dir) { + if (ep > 3) { return data.buffer[ep - 1][dir]; } + return data.buffer[ep][dir]; +} + +static inline uint32_t ep_dma_addr(uint8_t ep) { if (ep == 3) { return (uint32_t) &data.ep3_buffer.out[0]; } - return (uint32_t) &data.buffer[ep][0]; -#endif + return (uint32_t) ep_buffer(ep, TUSB_DIR_OUT); } static inline uint8_t* ep_out_buf(uint8_t ep) { -#ifdef CH32_USBFS_EP4_SHARES_EP0 - if (ep == 0) { return &data.ep0_ep4_buffer[0]; } - if (ep == 4) { return &data.ep0_ep4_buffer[64]; } - return ch58x_ep_buffer(ep); -#else if (ep == 3) { return data.ep3_buffer.out; } - return data.buffer[ep][TUSB_DIR_OUT]; -#endif + return ep_buffer(ep, TUSB_DIR_OUT); } static inline uint8_t* ep_in_buf(uint8_t ep) { -#ifdef CH32_USBFS_EP4_SHARES_EP0 - if (ep == 0) { return &data.ep0_ep4_buffer[0]; } // EP0 half-duplex: IN reuses OUT chunk - if (ep == 4) { return &data.ep0_ep4_buffer[128]; } - return ch58x_ep_buffer(ep) + 64; // IN at +64 within the endpoint's 128-byte buffer -#else - if (ep == 0) { return data.buffer[0][TUSB_DIR_OUT]; } // EP0 half-duplex: IN reuses OUT chunk + if (ep == 0) { return ep_buffer(0, TUSB_DIR_OUT); } // EP0 half-duplex: IN reuses OUT chunk if (ep == 3) { return data.ep3_buffer.in; } - return data.buffer[ep][TUSB_DIR_IN]; -#endif + return ep_buffer(ep, TUSB_DIR_IN); } -// EP4 on CH58X has no DMA register (shares EP0's); skip its EP_DMA() write. static inline bool ep_shares_ep0_dma(uint8_t ep) { -#ifdef CH32_USBFS_EP4_SHARES_EP0 - return ep == 4; -#else (void) ep; return false; -#endif } +#endif /* private helpers */ static void update_in(uint8_t rhport, uint8_t ep, bool force) { @@ -214,7 +223,7 @@ static void update_in(uint8_t rhport, uint8_t ep, bool force) { if (xfer->valid) { if (force || xfer->len) { size_t len = TU_MIN(xfer->max_size, xfer->len); -#if CFG_TUSB_MCU == OPT_MCU_CH583 +#if CFG_TUSB_MCU == OPT_MCU_CH583 || CFG_TUSB_MCU == OPT_MCU_CH32X035 // Every CH58x endpoint buffer is 64 bytes. Isochronous (which would push max_size up to 1023) // is refused in dcd_edpt_iso_alloc(), but some classes (e.g. video) ignore that result, so cap // the copy here to guarantee we never write past the buffer into a neighbouring endpoint's. @@ -250,7 +259,7 @@ static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) { struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT]; if (xfer->valid) { size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len)); -#if CFG_TUSB_MCU == OPT_MCU_CH583 +#if CFG_TUSB_MCU == OPT_MCU_CH583 || CFG_TUSB_MCU == OPT_MCU_CH32X035 len = TU_MIN(len, 64u); // cap to the 64-byte EP buffer (see update_in) #endif memcpy(xfer->buffer, ep_out_buf(ep), len); @@ -303,6 +312,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { USBOTG_FS->UEP4_1_MOD = 0xCC; USBOTG_FS->UEP2_3_MOD = 0xCC; #if CFG_TUSB_MCU == OPT_MCU_CH583 || CFG_TUSB_MCU == OPT_MCU_CH32X035 + // CH58X: a single mode register enables EP5/6/7 RX+TX (different bit layout than CH32). USBOTG_FS->UEP567_MOD = 0x3F; #else USBOTG_FS->UEP5_6_MOD = 0xCC; @@ -475,21 +485,23 @@ void dcd_edpt_close_all(uint8_t rhport) { bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) { (void)rhport; +#if CFG_TUSB_MCU == OPT_MCU_CH583 (void)ep_addr; (void)largest_packet_size; -#if CFG_TUSB_MCU == OPT_MCU_CH583 // No isochronous support on CH58x: its 8-bit T_LEN caps a packet at 255B and the endpoints use // plain 64-byte buffers, so accepting an iso max_size (up to 1023) would let update_in()/ // update_out() run off the end of the buffer into neighbouring ones. Refuse it outright. return false; -#else +#elif CFG_TUSB_MCU == OPT_MCU_CH32X035 + if (largest_packet_size > 64u) { return false; } +#endif + uint8_t ep = tu_edpt_number(ep_addr); uint8_t dir = tu_edpt_dir(ep_addr); data.isochronous[ep] = true; data.xfer[ep][dir].max_size = largest_packet_size; return true; -#endif } bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) { @@ -497,9 +509,10 @@ bool dcd_edpt_iso_activate(uint8_t rhport, const tusb_desc_endpoint_t *desc_ep) (void)desc_ep; #if CFG_TUSB_MCU == OPT_MCU_CH583 return false; // CH58x has no isochronous support (see dcd_edpt_iso_alloc) -#else - return true; +#elif CFG_TUSB_MCU == OPT_MCU_CH32X035 + if (tu_edpt_packet_size(desc_ep) > 64u) { return false; } #endif + return true; } bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes, bool is_isr) { From 20504ac0093c5daf722e4c30392bf301d77f9422 Mon Sep 17 00:00:00 2001 From: Jie Feng Date: Sat, 4 Jul 2026 17:29:12 +0800 Subject: [PATCH 4/4] Sync make and cmake --- hw/bsp/ch32x035/family.cmake | 3 --- hw/bsp/ch32x035/family.mk | 1 - 2 files changed, 4 deletions(-) diff --git a/hw/bsp/ch32x035/family.cmake b/hw/bsp/ch32x035/family.cmake index 2eb9f20e77..35d8c04d6f 100644 --- a/hw/bsp/ch32x035/family.cmake +++ b/hw/bsp/ch32x035/family.cmake @@ -15,8 +15,6 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TO set(FAMILY_MCUS CH32X035 CACHE INTERNAL "") set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") -set(RHPORT_DEVICE 0) - #------------------------------------ # Startup & Linker script #------------------------------------ @@ -48,7 +46,6 @@ function(family_add_board BOARD_TARGET) ${CMAKE_CURRENT_FUNCTION_LIST_DIR} ) target_compile_definitions(${BOARD_TARGET} PUBLIC - BOARD_TUD_RHPORT=${RHPORT_DEVICE} CFG_EXAMPLE_MSC_DUAL_READONLY CFG_EXAMPLE_VIDEO_READONLY ) diff --git a/hw/bsp/ch32x035/family.mk b/hw/bsp/ch32x035/family.mk index 715ef810c1..f389bed723 100644 --- a/hw/bsp/ch32x035/family.mk +++ b/hw/bsp/ch32x035/family.mk @@ -13,7 +13,6 @@ CFLAGS += \ -ffat-lto-objects \ -flto \ -DCFG_TUSB_MCU=OPT_MCU_CH32X035 \ - -DCFG_TUD_WCH_USBIP_USBFS=1 \ -DCFG_EXAMPLE_MSC_DUAL_READONLY=1 \ -DCFG_EXAMPLE_VIDEO_READONLY=1