diff --git a/examples/device/audio_4_channel_mic_freertos/skip.txt b/examples/device/audio_4_channel_mic_freertos/skip.txt index 61a7b06058..804afd4fda 100644 --- a/examples/device/audio_4_channel_mic_freertos/skip.txt +++ b/examples/device/audio_4_channel_mic_freertos/skip.txt @@ -1,4 +1,5 @@ mcu:CH32F20X +mcu:CH32H417 mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/audio_test_freertos/skip.txt b/examples/device/audio_test_freertos/skip.txt index 386a0cdfb7..46e9802499 100644 --- a/examples/device/audio_test_freertos/skip.txt +++ b/examples/device/audio_test_freertos/skip.txt @@ -1,4 +1,5 @@ mcu:CH32F20X +mcu:CH32H417 mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/cdc_msc_freertos/skip.txt b/examples/device/cdc_msc_freertos/skip.txt index 429c62d938..0e6b517d47 100644 --- a/examples/device/cdc_msc_freertos/skip.txt +++ b/examples/device/cdc_msc_freertos/skip.txt @@ -1,4 +1,5 @@ mcu:CH32F20X +mcu:CH32H417 mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/hid_composite_freertos/skip.txt b/examples/device/hid_composite_freertos/skip.txt index d2ee8d636d..55f4dd8766 100644 --- a/examples/device/hid_composite_freertos/skip.txt +++ b/examples/device/hid_composite_freertos/skip.txt @@ -1,4 +1,5 @@ mcu:CH32F20X +mcu:CH32H417 mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/midi_test_freertos/skip.txt b/examples/device/midi_test_freertos/skip.txt index d2ee8d636d..55f4dd8766 100644 --- a/examples/device/midi_test_freertos/skip.txt +++ b/examples/device/midi_test_freertos/skip.txt @@ -1,4 +1,5 @@ mcu:CH32F20X +mcu:CH32H417 mcu:CH32V103 mcu:CH32V20X mcu:CH32V307 diff --git a/examples/device/net_lwip_webserver/skip.txt b/examples/device/net_lwip_webserver/skip.txt index 5e5562087f..d73c51634d 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:CH32H417 mcu:LPC11UXX mcu:LPC13XX mcu:LPC15XX diff --git a/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.cmake b/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.cmake new file mode 100644 index 0000000000..cbd878fafd --- /dev/null +++ b/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.cmake @@ -0,0 +1,5 @@ +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + CH32H417 + ) +endfunction() diff --git a/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.h b/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.h new file mode 100644 index 0000000000..d6b12d82aa --- /dev/null +++ b/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.h @@ -0,0 +1,41 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2026, TinyUSB contributors + * + * 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. + */ + +/* metadata: + name: CH32H417QEU6-R0-1v1 + url: https://github.com/openwch/ch32h417/tree/main/EVT/PUB/SCHPCB/CH32H417QEU6-R0 +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.mk b/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.mk new file mode 100644 index 0000000000..3b1c0a9f24 --- /dev/null +++ b/hw/bsp/ch32h41x/boards/ch32h417qeu6_r0_1v1/board.mk @@ -0,0 +1 @@ +MCU_VARIANT = CH32H417QEU6 diff --git a/hw/bsp/ch32h41x/ch32h417_conf.h b/hw/bsp/ch32h41x/ch32h417_conf.h new file mode 100644 index 0000000000..4b0b90e9ba --- /dev/null +++ b/hw/bsp/ch32h41x/ch32h417_conf.h @@ -0,0 +1,8 @@ +#ifndef CH32H417_CONF_H_ +#define CH32H417_CONF_H_ + +#include "ch32h417_gpio.h" +#include "ch32h417_rcc.h" +#include "ch32h417_usb.h" + +#endif diff --git a/hw/bsp/ch32h41x/ch32h417_it.h b/hw/bsp/ch32h41x/ch32h417_it.h new file mode 100644 index 0000000000..8976f53ca6 --- /dev/null +++ b/hw/bsp/ch32h41x/ch32h417_it.h @@ -0,0 +1,4 @@ +#ifndef CH32H417_IT_H_ +#define CH32H417_IT_H_ + +#endif diff --git a/hw/bsp/ch32h41x/family.c b/hw/bsp/ch32h41x/family.c new file mode 100644 index 0000000000..bffe45cd11 --- /dev/null +++ b/hw/bsp/ch32h41x/family.c @@ -0,0 +1,128 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2026, TinyUSB contributors + * + * 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: WCH +*/ + +#include "ch32h417.h" +#include "ch32h417_rcc.h" + +#include "bsp/board_api.h" +#include "board.h" + +//--------------------------------------------------------------------+ +// Forward USB interrupt events to TinyUSB IRQ Handler +//--------------------------------------------------------------------+ + +__attribute__((interrupt)) void USBHS_IRQHandler(void); +__attribute__((interrupt)) void SysTick0_Handler(void); + +__attribute__((interrupt)) void USBHS_IRQHandler(void) { + tud_int_handler(0); +} + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM +//--------------------------------------------------------------------+ + +#if CFG_TUSB_OS == OPT_OS_NONE +static uint32_t systick_config(uint32_t ticks) { + NVIC_EnableIRQ(SysTick0_IRQn); + SysTick0->CTLR = 0; + SysTick0->ISR = 0; + SysTick0->CNT = 0; + SysTick0->CMP = ticks - 1; + SysTick0->CTLR = 0x0F; + return 0; +} +#endif + +static void usbhs_clock_init(void) { + if ((RCC->PLLCFGR & RCC_SYSPLL_SEL) != RCC_SYSPLL_USBHS) { + RCC_USBHS_PLLCmd(DISABLE); + RCC_USBHSPLLCLKConfig(RCC_USBHSPLLSource_HSE); + RCC_USBHSPLLReferConfig(RCC_USBHSPLLRefer_25M); + RCC_USBHSPLLClockSourceDivConfig(RCC_USBHSPLL_IN_Div1); + RCC_USBHS_PLLCmd(ENABLE); + while (!(RCC->CTLR & RCC_USBHS_PLLRDY)) { + } + } + + RCC_UTMIcmd(ENABLE); + RCC_HBPeriphClockCmd(RCC_HBPeriph_USBHS, ENABLE); +} + +void board_init(void) { + __disable_irq(); + + SystemInit(); + SystemAndCoreClockUpdate(); + +#if CFG_TUSB_OS == OPT_OS_NONE + systick_config(SystemCoreClock / 1000); +#endif + + usbhs_clock_init(); + + __enable_irq(); +} + +#if CFG_TUSB_OS == OPT_OS_NONE +volatile uint32_t system_ticks = 0; + +__attribute__((interrupt)) void SysTick0_Handler(void) { + SysTick0->ISR = 0; + system_ticks++; +} + +uint32_t tusb_time_millis_api(void) { + return system_ticks; +} +#endif + +//--------------------------------------------------------------------+ +// Board porting API +//--------------------------------------------------------------------+ + +void board_led_write(bool state) { + (void) state; +} + +uint32_t board_button_read(void) { + return 0; +} + +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; + return len; +} diff --git a/hw/bsp/ch32h41x/family.cmake b/hw/bsp/ch32h41x/family.cmake new file mode 100644 index 0000000000..47d3304def --- /dev/null +++ b/hw/bsp/ch32h41x/family.cmake @@ -0,0 +1,107 @@ +include_guard() + +set(CH32_FAMILY ch32h417) +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 + +# In actual fact, it is IMACBF +set(CMAKE_SYSTEM_CPU rv32imac-ilp32 CACHE INTERNAL "System Processor" FORCE) +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TOOLCHAIN}.cmake) + +set(FAMILY_MCUS CH32H417 CACHE INTERNAL "") +set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-dual-core.cfg -c noload") + +#------------------------------------ +# Startup & Linker script +#------------------------------------ +if (NOT DEFINED LD_FILE_GNU) + set(LD_FILE_GNU ${SDK_SRC_DIR}/Ld/V3F/Link_v3f.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}_v3f.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}_flash.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_gpio.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_rcc.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} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + target_compile_definitions(${BOARD_TARGET} PUBLIC + CFG_TUD_WCH_USBIP_USBHS=1 + BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + ) + + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_compile_options(${BOARD_TARGET} PUBLIC + -msmall-data-limit=8 + -mno-save-restore + -fmessage-length=0 + -fsigned-char + ) + endif () +endfunction() + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + family_add_tinyusb(${TARGET} OPT_MCU_CH32H417) + + target_sources(${TARGET} PUBLIC + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ${TOP}/src/portable/wch/dcd_ch32_usbhs.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${TARGET} PUBLIC + ${SDK_SRC_DIR}/Core + ${SDK_SRC_DIR}/Peripheral/inc + ${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 + "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}) +endfunction() diff --git a/hw/bsp/ch32h41x/family.mk b/hw/bsp/ch32h41x/family.mk new file mode 100644 index 0000000000..2536f5a383 --- /dev/null +++ b/hw/bsp/ch32h41x/family.mk @@ -0,0 +1,51 @@ +# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +CROSS_COMPILE ?= riscv-none-elf- + +CH32_FAMILY = ch32h417 +SDK_DIR = hw/mcu/wch/$(CH32_FAMILY) +SDK_SRC_DIR = $(SDK_DIR)/EVT/EXAM/SRC + +include $(TOP)/$(BOARD_PATH)/board.mk + +# In actual fact, it is IMACBF +CPU_CORE ?= rv32imac-ilp32 + +# CH32H417 support is device-only over USBHS. +SPEED ?= high + +CFLAGS += \ + -flto \ + -msmall-data-limit=8 \ + -mno-save-restore \ + -fmessage-length=0 \ + -fsigned-char \ + -DCH32H417 \ + -DCFG_TUSB_MCU=OPT_MCU_CH32H417 \ + -DCFG_TUD_WCH_USBIP_USBHS=1 \ + -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED \ + +LDFLAGS += \ + -nostdlib -nostartfiles \ + --specs=nosys.specs --specs=nano.specs \ + +SRC_C += \ + src/portable/wch/dcd_ch32_usbhs.c \ + $(SDK_SRC_DIR)/Core/core_riscv.c \ + $(SDK_SRC_DIR)/Peripheral/src/$(CH32_FAMILY)_flash.c \ + $(SDK_SRC_DIR)/Peripheral/src/$(CH32_FAMILY)_gpio.c \ + $(SDK_SRC_DIR)/Peripheral/src/$(CH32_FAMILY)_rcc.c \ + $(FAMILY_PATH)/system_$(CH32_FAMILY).c \ + +SRC_S += \ + $(SDK_SRC_DIR)/Startup/startup_$(CH32_FAMILY)_v3f.S \ + +INC += \ + $(TOP)/$(SDK_SRC_DIR)/Core \ + $(TOP)/$(SDK_SRC_DIR)/Peripheral/inc \ + $(TOP)/$(FAMILY_PATH) \ + $(TOP)/$(BOARD_PATH) \ + +LD_FILE ?= $(SDK_SRC_DIR)/Ld/V3F/Link_v3f.ld + +OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-dual-core.cfg -c noload +flash: flash-openocd-wch diff --git a/hw/bsp/ch32h41x/system_ch32h417.c b/hw/bsp/ch32h41x/system_ch32h417.c new file mode 100644 index 0000000000..daf6799504 --- /dev/null +++ b/hw/bsp/ch32h41x/system_ch32h417.c @@ -0,0 +1,787 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : system_ch32h417.c +* Author : WCH +* Version : V1.0.1 +* Date : 2025/10/16 +* Description : CH32H417 Device Peripheral Access Layer System Source File. +* For HSE = 25Mhz +********************************************************************************* +* Copyright (c) 2025 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#include "ch32h417.h" + +/* +* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after +* reset the HSI is used as SYSCLK source). +* If none of the define below is enabled, the HSI is used as System clock source. +*/ +#define SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE 400000000 +// #define SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE 480000000 +// #define SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI 400000000 +// #define SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI 480000000 + +/*Only suitable for commercial applications, with a temperature not exceeding 70 ℃ and good heat dissipation*/ +/* // #define SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE 480000000 +// #define SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI 480000000 */ + +/* Clock Definitions */ +uint32_t HCLKClock; +#ifdef SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE +uint32_t SystemClock = SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE; /* System Clock Frequency */ +uint32_t SystemCoreClock = 100000000; +#elif defined SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE +uint32_t SystemClock = SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE; /* System Clock Frequency */ +uint32_t SystemCoreClock = 120000000; +#elif defined SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI +uint32_t SystemClock = SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI; /* System Clock Frequency */ +uint32_t SystemCoreClock = 100000000; +#elif defined SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI +uint32_t SystemClock = SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI; /* System Clock Frequency */ +uint32_t SystemCoreClock = 120000000; + +#elif defined SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE +uint32_t SystemClock = SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE; /* System Clock Frequency */ +uint32_t SystemCoreClock = 120000000; + +#elif defined SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI +uint32_t SystemClock = SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI; /* System Clock Frequency */ +uint32_t SystemCoreClock = 120000000; + + + +#else + +uint32_t SystemClock = HSI_VALUE; /* System Clock Frequency */ +uint32_t SystemCoreClock = HSI_VALUE; +#endif + +static __I uint8_t PLLMULTB[32] = {4,6,7,8,17,9,19,10,21,11,23,12,25,13,14,15,16,17,18,19,20,22,24,26,28,30,32,34,36,38,40,59}; +static __I uint8_t HBPrescTB[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +static __I uint8_t SERDESPLLMULTB[16] = {25, 28, 30, 32, 35, 38, 40, 45, 50, 56, 60, 64, 70, 76, 80, 90}; +static __I uint8_t FPRETB[4] = {0, 1, 2, 2}; + + + +/* system_private_function_proto_types */ +static void SetSysClock(void); + +#ifdef SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE +static void SetSYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE( void ); +#elif defined SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE +static void SetSYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE( void ); +#elif defined SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI +static void SetSYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI( void ); +#elif defined SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI +static void SetSYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI( void ); + +#elif defined SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE +static void SetSYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE( void ); +#elif defined SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI +static void SetSYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI( void ); + +#endif + +/********************************************************************* + * @fn SystemInit + * + * @brief Setup the microcontroller system Initialize the Embedded Flash Interface, + * the PLL and update the SystemCoreClock variable. + * + * @return none + */ +void SystemInit (void) +{ + RCC->CTLR |= (uint32_t)0x00000001; + RCC->CFGR0 &= (uint32_t)0x305C0000; + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x00) + { + } + RCC->CFGR0 &= (uint32_t)0xFFBFFFFF; + + RCC->PLLCFGR &= (uint32_t)0x7FFFFFFF; + + RCC->CTLR &= (uint32_t)0x6AA6FFFF; + RCC->CTLR &= (uint32_t)0xFFFBFFFF; + + RCC->PLLCFGR &= (uint32_t)0x0FFFC000; + RCC->PLLCFGR |= (uint32_t)0x00000004; + + RCC->INTR = 0x00FF0000; + RCC->CFGR2 &= 0x0C600000; + RCC->PLLCFGR2 &= 0xFFF0E080; + RCC->PLLCFGR2 |= 0x00080020; + + SetSysClock(); +} + +/********************************************************************* + * @fn SetSysClock + * + * @brief Sets System clock frequency. + * Sets V5F Core clock frequency. + * Sets V3F Core clock frequency. + * configure HCLK prescalers. + * + * @return none + */ +static void SetSysClock(void) +{ + GPIO_IPD_Unused(); +#ifdef SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE + SetSYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE(); +#elif defined SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE + SetSYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE(); +#elif defined SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI + SetSYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI(); +#elif defined SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI + SetSYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI(); + +#elif defined SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE + SetSYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE(); +#elif defined SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI + SetSYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI(); + +#endif + + /* If none of the define above is enabled, the HSI is used as System clock + * source (default after reset) + */ +} + +/********************************************************************* + * @fn SystemAndCoreClockUpdate + * + * @brief Update SystemClock and CoreClock variable according to Clock Register Values. + * + * @return none + */ +void SystemAndCoreClockUpdate (void) +{ + uint32_t tmp = 0,tmp1 = 0, tmp2 = 0, tmp3 = 0, pllmull = 0, pllsource = 0, presc = 0, presc1 = 0; + + tmp = RCC->CFGR0 & RCC_SWS; + tmp2 = RCC->PLLCFGR & RCC_SYSPLL_SEL; + + switch(tmp) + { + case 0x00: + SystemClock = HSI_VALUE; + break; + + case 0x04: + SystemClock = HSE_VALUE; + break; + + case 0x08: + switch(tmp2) + { + case RCC_SYSPLL_PLL: + pllmull = RCC->PLLCFGR & RCC_PLLMUL; + pllsource = RCC->PLLCFGR & RCC_PLLSRC; + presc = (((RCC->PLLCFGR & RCC_PLL_SRC_DIV) >> 8) + 1); + + if(pllsource == 0xA0) + { + tmp1 = 500000000 / presc; + } + else if(pllsource == 0xE0) + { + tmp1 = HSE_VALUE*SERDESPLLMULTB[RCC->PLLCFGR2>>16]/2/presc; + } + + else if(pllsource == 0x80) + { + tmp1 = 480000000 / presc; + } + else if(pllsource == 0xC0) + { + tmp1 = 125000000 / presc; + } + else if(pllsource == 0x20) + { + tmp1 = HSE_VALUE / presc; + } + else + { + tmp1 = HSI_VALUE / presc; + } + + if((pllmull == 4) || (pllmull == 6) || (pllmull == 8) || (pllmull == 10) || (pllmull == 12)) + { + SystemClock = (tmp1 * PLLMULTB[pllmull]) >> 1; + } + else + { + SystemClock = tmp1 * PLLMULTB[pllmull]; + } + + break; + + case RCC_SYSPLL_USBHS: + SystemClock = 480000000; + break; + + case RCC_SYSPLL_ETH: + SystemClock = 500000000; + break; + + case RCC_SYSPLL_SERDES: + SystemClock = HSE_VALUE*SERDESPLLMULTB[RCC->PLLCFGR2>>16]/2; + break; + + case RCC_SYSPLL_USBSS: + SystemClock = 125000000; + break; + + default: + SystemClock = HSI_VALUE; + break; + } + break; + + default: + SystemClock = HSI_VALUE; + break; + } + + tmp = (RCC->CFGR0 & RCC_HPRE) >> 4; + presc1 = HBPrescTB[tmp]; + + tmp3 = SystemClock >> presc1; + + tmp = (RCC->CFGR0 & RCC_FPRE) >> 16; + presc1 = FPRETB[tmp]; + HCLKClock = tmp3 >> presc1; + + if(NVIC_GetCurrentCoreID() == 0)//V3F + { + SystemCoreClock = HCLKClock; + } + else + { + SystemCoreClock = tmp3; + } +} + +#ifdef SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE + +/********************************************************************* + * @fn SetSYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE + * + * @brief Sets System clock frequency to 400MHz. + * Sets V5F Core clock frequency to 400MHz. + * Sets V3F Core clock frequency to 100MHz. + * configure HCLK prescalers. + * + * @return none + */ +static void SetSYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0, FLASH_Temp = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* configure PLL Clock */ + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_PLLMUL)); + RCC->PLLCFGR |= (uint32_t)RCC_PLLMUL16; + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_PLL_SRC_DIV)); + RCC->PLLCFGR |= (uint32_t)RCC_PLL_SRC_DIV1; + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_PLLSRC)); + RCC->PLLCFGR |= (uint32_t)RCC_PLLSRC_HSE; + + /* Wait till HSE clock is used as PLL clock source */ + while ((RCC->PLLCFGR & (uint32_t)RCC_PLLSRC) != (uint32_t)RCC_PLLSRC_HSE) + { + } + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) != (uint32_t)RCC_PLLRDY) + { + } + + /* Select PLL Clock as SYSPLL clock source */ + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_GATE)); + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_SEL)); + + /* Wait till PLL is used as system clock source */ + while ((RCC->PLLCFGR & (uint32_t)RCC_SYSPLL_SEL) != (uint32_t)0x00) + { + } + + /* V5F core clock = SYSCLK */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_HPRE)); + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + + /* V3F core clock = HCLK = SYSCLK/4 */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_FPRE)); + RCC->CFGR0 |= (uint32_t)RCC_FPRE_DIV4; + + /* Select FLASH clock frequency*/ + FLASH_Temp = FLASH->ACTLR; + FLASH_Temp &= ~((uint32_t)0x3); + FLASH_Temp |= FLASH_ACTLR_LATENCY_HCLK_DIV2; + FLASH->ACTLR = FLASH_Temp; + + /* Select PLL as system clock source */ + RCC->PLLCFGR |= (uint32_t)RCC_SYSPLL_GATE; + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + + } + else + { + /* If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE + +/********************************************************************* + * @fn SetSYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE + * + * @brief Sets System clock frequency to 480MHz. + * Sets V5F Core clock frequency to 240MHz. + * Sets V3F Core clock frequency to 120MHz. + * configure HCLK prescalers. + * + * @return none + */ +static void SetSYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0, FLASH_Temp = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* Select 25MHz as USBHS PLL clock reference */ + RCC->PLLCFGR2 &= (uint32_t)((uint32_t)~(RCC_USBHSPLL_REFSEL)); + + /* Select HSE as USBHS PLL clock source */ + RCC->PLLCFGR2 &= (uint32_t)((uint32_t)~(RCC_USBHSPLLSRC)); + + /* Wait till HSE is used as USBHS PLL clock source */ + while ((RCC->PLLCFGR2 & (uint32_t)RCC_USBHSPLLSRC) != (uint32_t)0x00) + { + } + + /* Enable USBHS PLL */ + RCC->CTLR |= (uint32_t)RCC_USBHS_PLLON; + + /* Wait till USBHS PLL is ready */ + while ((RCC->CTLR & (uint32_t)RCC_USBHS_PLLRDY) != (uint32_t)RCC_USBHS_PLLRDY) + { + } + + /* Select USBHS_PLL Clock as SYSPLL clock source */ + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_GATE)); + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_SEL)); + RCC->PLLCFGR |= (uint32_t)((uint32_t)(RCC_SYSPLL_USBHS)); + + /* Wait till USBHS is used as system clock source */ + while ((RCC->PLLCFGR & (uint32_t)RCC_SYSPLL_USBHS) != (uint32_t)RCC_SYSPLL_USBHS) + { + } + + /* V5F core clock = SYSCLK */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_HPRE)); + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2; + + /* V3F core clock = HCLK = SYSCLK/4 */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_FPRE)); + RCC->CFGR0 |= (uint32_t)RCC_FPRE_DIV2; + + /* Select FLASH clock frequency*/ + FLASH_Temp = FLASH->ACTLR; + FLASH_Temp &= ~((uint32_t)0x3); + FLASH_Temp |= FLASH_ACTLR_LATENCY_HCLK_DIV2; + FLASH->ACTLR = FLASH_Temp; + + /* Select PLL as system clock source */ + RCC->PLLCFGR |= (uint32_t)RCC_SYSPLL_GATE; + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + + } + else + { + /* If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI + +/********************************************************************* + * @fn SetSYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI + * + * @brief Sets System clock frequency to 400MHz. + * Sets V5F Core clock frequency to 400MHz. + * Sets V3F Core clock frequency to 100MHz. + * configure HCLK prescalers. + * + * @return none + */ +static void SetSYSCLK_400M_CoreCLK_V5F_400M_V3F_100M_HSI(void) +{ + __IO uint32_t FLASH_Temp = 0; + /* configure PLL Clock */ + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_PLLMUL)); + RCC->PLLCFGR |= (uint32_t)RCC_PLLMUL16; + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_PLL_SRC_DIV)); + RCC->PLLCFGR |= (uint32_t)RCC_PLL_SRC_DIV1; + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_PLLSRC)); + RCC->PLLCFGR |= (uint32_t)RCC_PLLSRC_HSI; + + /* Wait till HSI clock is used as PLL clock source */ + while ((RCC->PLLCFGR & (uint32_t)RCC_PLLSRC) != (uint32_t)RCC_PLLSRC_HSI) + { + } + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) != (uint32_t)RCC_PLLRDY) + { + } + + /* Select PLL Clock as SYSPLL clock source */ + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_GATE)); + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_SEL)); + + /* Wait till PLL is used as system clock source */ + while ((RCC->PLLCFGR & (uint32_t)RCC_SYSPLL_SEL) != (uint32_t)0x00) + { + } + + /* V5F core clock = SYSCLK */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_HPRE)); + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + + /* V3F core clock = HCLK = SYSCLK/4 */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_FPRE)); + RCC->CFGR0 |= (uint32_t)RCC_FPRE_DIV4; + + /* Select FLASH clock frequency*/ + FLASH_Temp = FLASH->ACTLR; + FLASH_Temp &= ~((uint32_t)0x3); + FLASH_Temp |= FLASH_ACTLR_LATENCY_HCLK_DIV2; + FLASH->ACTLR = FLASH_Temp; + + /* Select PLL as system clock source */ + RCC->PLLCFGR |= (uint32_t)RCC_SYSPLL_GATE; + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} + +#elif defined SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI + +/********************************************************************* + * @fn SYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI + * + * @brief Sets System clock frequency to 480MHz. + * Sets V5F Core clock frequency to 240MHz. + * Sets V3F Core clock frequency to 120MHz. + * configure HCLK prescalers. + * + * @return none + */ +static void SetSYSCLK_480M_CoreCLK_V5F_240M_V3F_120M_HSI(void) +{ + __IO uint32_t FLASH_Temp = 0; + /* Select 25MHz as USBHS PLL clock reference */ + RCC->PLLCFGR2 &= (uint32_t)((uint32_t)~(RCC_USBHSPLL_REFSEL)); + + /* Select HSI as USBHS PLL clock source */ + RCC->PLLCFGR2 &= (uint32_t)((uint32_t)~(RCC_USBHSPLLSRC)); + RCC->PLLCFGR2 |= (uint32_t)RCC_USBHSPLLSRC_HSI; + + /* Wait till HSI is used as USBHS PLL clock source */ + while ((RCC->PLLCFGR2 & (uint32_t)RCC_USBHSPLLSRC) != (uint32_t)0x01) + { + } + + /* Enable USBHS PLL */ + RCC->CTLR |= (uint32_t)RCC_USBHS_PLLON; + + /* Wait till USBHS PLL is ready */ + while ((RCC->CTLR & (uint32_t)RCC_USBHS_PLLRDY) != (uint32_t)RCC_USBHS_PLLRDY) + { + } + + /* Select USBSS_PLL Clock as SYSPLL clock source */ + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_GATE)); + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_SEL)); + RCC->PLLCFGR |= (uint32_t)((uint32_t)(RCC_SYSPLL_USBHS)); + + /* Wait till USBHS is used as system clock source */ + while ((RCC->PLLCFGR & (uint32_t)RCC_SYSPLL_USBHS) != (uint32_t)RCC_SYSPLL_USBHS) + { + } + + /* V5F core clock = SYSCLK */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_HPRE)); + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2; + + /* V3F core clock = HCLK = SYSCLK/4 */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_FPRE)); + RCC->CFGR0 |= (uint32_t)RCC_FPRE_DIV2; + + /* Select FLASH clock frequency*/ + FLASH_Temp = FLASH->ACTLR; + FLASH_Temp &= ~((uint32_t)0x3); + FLASH_Temp |= FLASH_ACTLR_LATENCY_HCLK_DIV2; + FLASH->ACTLR = FLASH_Temp; + + /* Select PLL as system clock source */ + RCC->PLLCFGR |= (uint32_t)RCC_SYSPLL_GATE; + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} + +#elif defined SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE + +/********************************************************************* + * @fn SetSYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE + * + * @brief Sets System clock frequency to 480MHz. + * Sets V5F Core clock frequency to 480MHz. + * Sets V3F Core clock frequency to 120MHz. + * configure HCLK prescalers. + * + * @return none + */ +static void SetSYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0, FLASH_Temp = 0; + + /* Select VDDK to 1.25V */ + vu32 tmp = 0; + tmp = *(vu32*)SYS_CFGR0_BASE; + tmp &= ~(0x7 << 4); + tmp |= (0x5 << 4); + *(vu32*)SYS_CFGR0_BASE = tmp; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* Select 25MHz as USBHS PLL clock reference */ + RCC->PLLCFGR2 &= (uint32_t)((uint32_t)~(RCC_USBHSPLL_REFSEL)); + + /* Select HSE as USBHS PLL clock source */ + RCC->PLLCFGR2 &= (uint32_t)((uint32_t)~(RCC_USBHSPLLSRC)); + + /* Wait till HSE is used as USBHS PLL clock source */ + while ((RCC->PLLCFGR2 & (uint32_t)RCC_USBHSPLLSRC) != (uint32_t)0x00) + { + } + + /* Enable USBHS PLL */ + RCC->CTLR |= (uint32_t)RCC_USBHS_PLLON; + + /* Wait till USBHS PLL is ready */ + while ((RCC->CTLR & (uint32_t)RCC_USBHS_PLLRDY) != (uint32_t)RCC_USBHS_PLLRDY) + { + } + + /* Select USBHS_PLL Clock as SYSPLL clock source */ + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_GATE)); + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_SEL)); + RCC->PLLCFGR |= (uint32_t)((uint32_t)(RCC_SYSPLL_USBHS)); + + /* Wait till USBHS is used as system clock source */ + while ((RCC->PLLCFGR & (uint32_t)RCC_SYSPLL_USBHS) != (uint32_t)RCC_SYSPLL_USBHS) + { + } + + /* V5F core clock = SYSCLK */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_HPRE)); + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + + /* V3F core clock = HCLK = SYSCLK/4 */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_FPRE)); + RCC->CFGR0 |= (uint32_t)RCC_FPRE_DIV4; + + /* Select FLASH clock frequency*/ + FLASH_Temp = FLASH->ACTLR; + FLASH_Temp &= ~((uint32_t)0x3); + FLASH_Temp |= FLASH_ACTLR_LATENCY_HCLK_DIV2; + FLASH->ACTLR = FLASH_Temp; + + /* Select PLL as system clock source */ + RCC->PLLCFGR |= (uint32_t)RCC_SYSPLL_GATE; + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + + } + else + { + /* If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI + +/********************************************************************* + * @fn SetSYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI + * + * @brief Sets System clock frequency to 480MHz. + * Sets V5F Core clock frequency to 480MHz. + * Sets V3F Core clock frequency to 120MHz. + * configure HCLK prescalers. + * + * @return none + */ +static void SetSYSCLK_480M_CoreCLK_V5F_480M_V3F_120M_HSI(void) +{ + __IO uint32_t FLASH_Temp = 0; + /* Select VDDK to 1.25V */ + vu32 tmp = 0; + tmp = *(vu32*)SYS_CFGR0_BASE; + tmp &= ~(0x7 << 4); + tmp |= (0x5 << 4); + *(vu32*)SYS_CFGR0_BASE = tmp; + + /* Select 25MHz as USBHS PLL clock reference */ + RCC->PLLCFGR2 &= (uint32_t)((uint32_t)~(RCC_USBHSPLL_REFSEL)); + + /* Select HSI as USBHS PLL clock source */ + RCC->PLLCFGR2 &= (uint32_t)((uint32_t)~(RCC_USBHSPLLSRC)); + RCC->PLLCFGR2 |= (uint32_t)RCC_USBHSPLLSRC_HSI; + + /* Wait till HSI is used as USBHS PLL clock source */ + while ((RCC->PLLCFGR2 & (uint32_t)RCC_USBHSPLLSRC) != (uint32_t)0x01) + { + } + + /* Enable USBHS PLL */ + RCC->CTLR |= (uint32_t)RCC_USBHS_PLLON; + + /* Wait till USBHS PLL is ready */ + while ((RCC->CTLR & (uint32_t)RCC_USBHS_PLLRDY) != (uint32_t)RCC_USBHS_PLLRDY) + { + } + + /* Select USBSS_PLL Clock as SYSPLL clock source */ + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_GATE)); + RCC->PLLCFGR &= (uint32_t)((uint32_t)~(RCC_SYSPLL_SEL)); + RCC->PLLCFGR |= (uint32_t)((uint32_t)(RCC_SYSPLL_USBHS)); + + /* Wait till USBHS is used as system clock source */ + while ((RCC->PLLCFGR & (uint32_t)RCC_SYSPLL_USBHS) != (uint32_t)RCC_SYSPLL_USBHS) + { + } + + /* V5F core clock = SYSCLK */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_HPRE)); + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + + /* V3F core clock = HCLK = SYSCLK/4 */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_FPRE)); + RCC->CFGR0 |= (uint32_t)RCC_FPRE_DIV4; + + /* Select FLASH clock frequency*/ + FLASH_Temp = FLASH->ACTLR; + FLASH_Temp &= ~((uint32_t)0x3); + FLASH_Temp |= FLASH_ACTLR_LATENCY_HCLK_DIV2; + FLASH->ACTLR = FLASH_Temp; + + /* Select PLL as system clock source */ + RCC->PLLCFGR |= (uint32_t)RCC_SYSPLL_GATE; + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} + +#endif diff --git a/hw/bsp/ch32h41x/system_ch32h417.h b/hw/bsp/ch32h41x/system_ch32h417.h new file mode 100644 index 0000000000..ae94f081a6 --- /dev/null +++ b/hw/bsp/ch32h41x/system_ch32h417.h @@ -0,0 +1,31 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : system_ch32h417.h +* Author : WCH +* Version : V1.0.0 +* Date : 2025/03/01 +* Description : CH32H417 Device Peripheral Access Layer System Header File. +********************************************************************************* +* Copyright (c) 2025 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __SYSTEM_CH32H417_H +#define __SYSTEM_CH32H417_H + +#ifdef __cplusplus + extern "C" { +#endif + +extern uint32_t HCLKClock; +extern uint32_t SystemClock; /* System Clock Frequency */ +extern uint32_t SystemCoreClock; /* System Core Frequency */ + +/* System_Exported_Functions */ +extern void SystemInit(void); +extern void SystemAndCoreClockUpdate(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 413ac48508..1d0b1ba09d 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -653,6 +653,17 @@ #define TUP_DCD_EDPT_CLOSE_API #endif +#elif TU_CHECK_MCU(OPT_MCU_CH32H417) + #define TUP_USBIP_WCH_USBHS + + #if !defined(CFG_TUD_WCH_USBIP_USBHS) + #define CFG_TUD_WCH_USBIP_USBHS 1 + #endif + + #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 8 + #define TUP_DCD_EDPT_CLOSE_API + //--------------------------------------------------------------------+ // Analog Devices //--------------------------------------------------------------------+ diff --git a/src/portable/wch/ch32_usbhs_reg.h b/src/portable/wch/ch32_usbhs_reg.h index 87300b4970..68106f60f8 100644 --- a/src/portable/wch/ch32_usbhs_reg.h +++ b/src/portable/wch/ch32_usbhs_reg.h @@ -39,12 +39,16 @@ #include #elif CFG_TUSB_MCU == OPT_MCU_CH32F20X #include +#elif CFG_TUSB_MCU == OPT_MCU_CH32H417 + #include + #include #endif #ifdef __GNUC__ #pragma GCC diagnostic pop #endif +#if CFG_TUSB_MCU != OPT_MCU_CH32H417 /******************* GLOBAL ******************/ @@ -391,5 +395,6 @@ #define USBHS_UH_T_TOG_AUTO (1 << 5) #define USBHS_UH_T_DATA_NO (1 << 6) +#endif #endif diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index ea3b052ad1..fcaca0e58e 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -32,8 +32,14 @@ #include "device/dcd.h" + #if CFG_TUSB_MCU == OPT_MCU_CH32H417 + #include "usbhs_h41x.h" + #else + #include "usbhs_f20x_v30x.h" + #endif + // Max number of bi-directional endpoints including EP0 - #define EP_MAX 16 + #define EP_MAX TUP_DCD_ENDPOINT_MAX typedef struct { uint8_t *buffer; @@ -47,14 +53,6 @@ typedef struct { #define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir] static xfer_ctl_t xfer_status[EP_MAX][2]; - #define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2) - #define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4) - #define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4) - #define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2) - - #define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1)) - #define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1)) - /* Endpoint Buffer */ TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE]; static bool ep0_tog; @@ -87,6 +85,7 @@ static void queue_in_packet(uint8_t ep_num, xfer_ctl_t* xfer) { EP_TX_CTRL(0) = USBHS_EP_T_RES_ACK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); ep0_tog = !ep0_tog; } else if (xfer->is_iso) { + wch_usbhs_edpt_enable_iso_in(ep_num); EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NYET; } else { set_ep_toggle(ep_num, TUSB_DIR_IN, ep_data_tog[ep_num][TUSB_DIR_IN]); @@ -130,6 +129,9 @@ static void update_in(uint8_t rhport, uint8_t ep_num, bool force) { if (ep_num == 0) { EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | (ep0_tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0); } else { + if (xfer->is_iso) { + wch_usbhs_edpt_disable_iso_in(ep_num); + } EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK; } dcd_event_xfer_complete(rhport, ep_num | TUSB_DIR_IN_MASK, xfer->queued_len, XFER_RESULT_SUCCESS, true); @@ -181,24 +183,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { memset(ep_data_tog, 0, sizeof(ep_data_tog)); ep0_tog = true; - USBHSD->HOST_CTRL = 0x00; - USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM; - - USBHSD->CONTROL = 0; - - #if TUD_OPT_HIGH_SPEED - USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED; - #else - #error OPT_MODE_FULL_SPEED not currently supported on CH32 - USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED; - #endif - - USBHSD->INT_EN = 0; - USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN; - - USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; - USBHSD->ENDP_TYPE = 0x00; - USBHSD->BUF_MODE = 0x00; + wch_usbhs_dcd_hw_init(); for (int ep = 0; ep < EP_MAX; ep++) { EP_TX_LEN(ep) = 0; @@ -214,7 +199,7 @@ bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init) { xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE; USBHSD->DEV_AD = 0; - USBHSD->CONTROL |= USBHS_DEV_PU_EN; + wch_usbhs_dcd_connect(); return true; } @@ -242,7 +227,7 @@ void dcd_edpt_close_all(uint8_t rhport) { EP_RX_MAX_LEN(ep) = 0; } - USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; + wch_usbhs_edpt_close_all(); } void dcd_set_address(uint8_t rhport, uint8_t dev_addr) { @@ -258,11 +243,7 @@ void dcd_remote_wakeup(uint8_t rhport) { void dcd_sof_enable(uint8_t rhport, bool en) { (void)rhport; - if (en) { - USBHSD->INT_EN |= USBHS_SOF_ACT_EN; - } else { - USBHSD->INT_EN &= ~(USBHS_SOF_ACT_EN); - } + wch_usbhs_dcd_sof_enable(en); } void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t *request) { @@ -291,17 +272,11 @@ bool dcd_edpt_open(uint8_t rhport, const tusb_desc_endpoint_t *desc_edpt) { xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS); if (dir == TUSB_DIR_OUT) { - USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num); + wch_usbhs_edpt_enable(ep_num, dir, xfer->is_iso); EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; - if (xfer->is_iso == true) { - USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num); - } EP_RX_MAX_LEN(ep_num) = xfer->max_size; } else { - if (xfer->is_iso == true) { - USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num); - } - USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); + wch_usbhs_edpt_enable(ep_num, dir, xfer->is_iso); EP_TX_LEN(ep_num) = 0; EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; } @@ -319,15 +294,12 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0; EP_RX_MAX_LEN(ep_num) = 0; ep_data_tog[ep_num][TUSB_DIR_OUT] = false; - USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num); - USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num); } else { // TUSB_DIR_IN EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; EP_TX_LEN(ep_num) = 0; ep_data_tog[ep_num][TUSB_DIR_IN] = false; - USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num); - USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); } + wch_usbhs_edpt_disable(ep_num, dir); } #if 0 @@ -409,6 +381,59 @@ void dcd_int_handler(uint8_t rhport) { uint8_t int_flag = USBHSD->INT_FG; uint8_t int_status = USBHSD->INT_ST; + #if CFG_TUSB_MCU == OPT_MCU_CH32H417 + if (int_flag & USBHS_UDIF_TRANSFER) { + uint8_t const ep_num = int_status & USBHS_UDIS_EP_ID_MASK; + tusb_dir_t const ep_dir = (int_status & USBHS_UDIS_EP_DIR) ? TUSB_DIR_IN : TUSB_DIR_OUT; + + if (ep_dir == TUSB_DIR_OUT) { + if (wch_usbhs_edpt_setup_received(ep_num)) { + tusb_control_request_t const* setup = + (tusb_control_request_t const*) ep0_buffer; + wch_usbhs_edpt_rx_done_clear(0); + ep0_tog = true; + EP_RX_CTRL(0) = (setup->wLength == 0) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK; + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK; + dcd_event_setup_received(rhport, ep0_buffer, true); + + USBHSD->INT_FG = USBHS_UDIF_TRANSFER; + return; + } + + uint16_t rx_len = wch_usbhs_edpt_rx_len(ep_num); + wch_usbhs_edpt_rx_done_clear(ep_num); + update_out(rhport, ep_num, rx_len); + } else { + wch_usbhs_edpt_tx_done_clear(ep_num); + update_in(rhport, ep_num, false); + } + + USBHSD->INT_FG = USBHS_UDIF_TRANSFER; + } else if (int_flag & USBHS_UDIF_RX_SOF) { + uint32_t frame_count = USBHSD->FRAME_NO & USBHS_UD_FRAME_NO; + dcd_event_sof(rhport, frame_count, true); + USBHSD->INT_FG = USBHS_UDIF_RX_SOF; + } else if (int_flag & USBHS_UDIF_BUS_RST) { + dcd_event_bus_reset(rhport, TUSB_SPEED_HIGH, true); + + USBHSD->DEV_AD = 0; + memset(ep_data_tog, 0, sizeof(ep_data_tog)); + ep0_tog = true; + EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0; + EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0; + + USBHSD->INT_FG = USBHS_UDIF_BUS_RST; + } else if (int_flag & (USBHS_UDIF_SUSPEND | USBHS_UDIF_BUS_SLEEP)) { + dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND}; + dcd_event_handler(&event, true); + + USBHSD->INT_FG = int_flag & (USBHS_UDIF_SUSPEND | USBHS_UDIF_BUS_SLEEP); + } else if (int_flag & USBHS_UDIF_LINK_RDY) { + USBHSD->INT_FG = USBHS_UDIF_LINK_RDY; + } else { + USBHSD->INT_FG = int_flag; + } + #else if (int_flag & USBHS_TRANSFER_FLAG) { const uint8_t token = int_status & MASK_UIS_TOKEN; const uint8_t ep_num = int_status & MASK_UIS_ENDP; @@ -471,5 +496,6 @@ void dcd_int_handler(uint8_t rhport) { // Unhandled interrupt USBHSD->INT_FG = int_flag; /* Clear all flags */ } + #endif } #endif diff --git a/src/portable/wch/usbhs_f20x_v30x.h b/src/portable/wch/usbhs_f20x_v30x.h new file mode 100644 index 0000000000..ff398eafb3 --- /dev/null +++ b/src/portable/wch/usbhs_f20x_v30x.h @@ -0,0 +1,107 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2026, TinyUSB contributors + * + * 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 DCD_CH32_USBHS_F20X_V30X_H_ +#define DCD_CH32_USBHS_F20X_V30X_H_ + +#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2) +#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4) +#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4) +#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2) + +#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1)) +#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1)) + +static inline void wch_usbhs_dcd_hw_init(void) { + USBHSD->HOST_CTRL = 0x00; + USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM; + + USBHSD->CONTROL = 0; + +#if TUD_OPT_HIGH_SPEED + USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED; +#else + #error OPT_MODE_FULL_SPEED not currently supported on CH32 + USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED; +#endif + + USBHSD->INT_EN = 0; + USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN; + + USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; + USBHSD->ENDP_TYPE = 0x00; + USBHSD->BUF_MODE = 0x00; +} + +static inline void wch_usbhs_dcd_connect(void) { + USBHSD->CONTROL |= USBHS_DEV_PU_EN; +} + +static inline void wch_usbhs_dcd_sof_enable(bool en) { + if (en) { + USBHSD->INT_EN |= USBHS_SOF_ACT_EN; + } else { + USBHSD->INT_EN &= ~(USBHS_SOF_ACT_EN); + } +} + +static inline void wch_usbhs_edpt_enable(uint8_t ep_num, tusb_dir_t dir, bool is_iso) { + if (dir == TUSB_DIR_OUT) { + USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num); + if (is_iso) { + USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num); + } + } else { + if (is_iso) { + USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num); + } + USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num); + } +} + +static inline void wch_usbhs_edpt_enable_iso_in(uint8_t ep_num) { + (void)ep_num; +} + +static inline void wch_usbhs_edpt_disable(uint8_t ep_num, tusb_dir_t dir) { + if (dir == TUSB_DIR_OUT) { + USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num); + USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num); + } else { + USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num); + USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num); + } +} + +static inline void wch_usbhs_edpt_disable_iso_in(uint8_t ep_num) { + (void)ep_num; +} + +static inline void wch_usbhs_edpt_close_all(void) { + USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN; +} + +#endif diff --git a/src/portable/wch/usbhs_h41x.h b/src/portable/wch/usbhs_h41x.h new file mode 100644 index 0000000000..da094fc40e --- /dev/null +++ b/src/portable/wch/usbhs_h41x.h @@ -0,0 +1,148 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2026, TinyUSB contributors + * + * 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 DCD_CH32_USBHS_H41X_H_ +#define DCD_CH32_USBHS_H41X_H_ + +// These alias new USBHS_UEP_* names to older WCH USBHS_EP_* names, so that +// the common DCD can use the same code path +#define USBHS_EP_T_RES_MASK USBHS_UEP_T_RES_MASK +#define USBHS_EP_T_RES_ACK USBHS_UEP_T_RES_ACK +#define USBHS_EP_T_RES_NAK USBHS_UEP_T_RES_NAK +#define USBHS_EP_T_RES_STALL USBHS_UEP_T_RES_STALL +#define USBHS_EP_T_TOG_MASK USBHS_UEP_T_TOG_MASK +#define USBHS_EP_T_TOG_0 USBHS_UEP_T_TOG_DATA0 +#define USBHS_EP_T_TOG_1 USBHS_UEP_T_TOG_DATA1 + +#define USBHS_EP_R_RES_MASK USBHS_UEP_R_RES_MASK +#define USBHS_EP_R_RES_ACK USBHS_UEP_R_RES_ACK +#define USBHS_EP_R_RES_NAK USBHS_UEP_R_RES_NAK +#define USBHS_EP_R_RES_STALL USBHS_UEP_R_RES_STALL +#define USBHS_EP_R_TOG_MASK USBHS_UEP_R_TOG_MASK +#define USBHS_EP_R_TOG_0 USBHS_UEP_R_TOG_DATA0 +#define USBHS_EP_R_TOG_1 USBHS_UEP_R_TOG_DATA1 + +// TODO: are these correct? +#define USBHS_EP_T_RES_NYET USBHS_UEP_T_RES_NAK +#define USBHS_EP_R_RES_NYET USBHS_UEP_R_RES_NAK + +#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2) +#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4) +#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4) +#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2) +#define EP_RX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_RX_LEN) + (ep) * 2) + +#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1)) +#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1)) + +static inline void wch_usbhs_dcd_hw_init(void) { + USBHSD->CONTROL = USBHS_UD_RST_LINK | USBHS_UD_PHY_SUSPENDM; + USBHSD->INT_EN = 0; + USBHSD->INT_EN = USBHS_UDIE_BUS_RST | USBHS_UDIE_SUSPEND | USBHS_UDIE_BUS_SLEEP | + USBHS_UDIE_TRANSFER | USBHS_UDIE_LINK_RDY; + + USBHSD->UEP_TX_EN = USBHS_UEP0_T_EN; + USBHSD->UEP_RX_EN = USBHS_UEP0_R_EN; + USBHSD->UEP_TX_ISO = 0; + USBHSD->UEP_RX_ISO = 0; + USBHSD->UEP_TX_TOG_AUTO = 0xFE; + USBHSD->UEP_RX_TOG_AUTO = 0xFE; + USBHSD->UEP_TX_BURST = 0; + USBHSD->UEP_TX_BURST_MODE = 0; + USBHSD->UEP_RX_BURST = 0; + USBHSD->UEP_RX_RES_MODE = 0; + USBHSD->UEP_AF_MODE = 0; +} + +static inline void wch_usbhs_dcd_connect(void) { + USBHSD->BASE_MODE = USBHS_UD_SPEED_HIGH; + USBHSD->CONTROL = USBHS_UD_DEV_EN | USBHS_UD_DMA_EN | USBHS_UD_LPM_EN | USBHS_UD_PHY_SUSPENDM; +} + +static inline void wch_usbhs_dcd_sof_enable(bool en) { + if (en) { + USBHSD->INT_EN |= USBHS_UDIE_SOF_ACT; + } else { + USBHSD->INT_EN &= (uint8_t) ~USBHS_UDIE_SOF_ACT; + } +} + +static inline void wch_usbhs_edpt_enable(uint8_t ep_num, tusb_dir_t dir, bool is_iso) { + if (dir == TUSB_DIR_OUT) { + USBHSD->UEP_RX_EN |= (uint16_t)(1u << ep_num); + if (is_iso) { + USBHSD->UEP_RX_ISO |= (uint16_t)(1u << ep_num); + } + } else { + USBHSD->UEP_TX_EN |= (uint16_t)(1u << ep_num); + if (is_iso) { + USBHSD->UEP_TX_ISO |= (uint16_t)(1u << ep_num); + } + } +} + +static inline void wch_usbhs_edpt_enable_iso_in(uint8_t ep_num) { + USBHSD->UEP_TX_EN |= (uint16_t)(1u << ep_num); +} + +static inline void wch_usbhs_edpt_disable(uint8_t ep_num, tusb_dir_t dir) { + if (dir == TUSB_DIR_OUT) { + USBHSD->UEP_RX_ISO &= (uint16_t) ~(1u << ep_num); + USBHSD->UEP_RX_EN &= (uint16_t) ~(1u << ep_num); + } else { + USBHSD->UEP_TX_ISO &= (uint16_t) ~(1u << ep_num); + USBHSD->UEP_TX_EN &= (uint16_t) ~(1u << ep_num); + } +} + +static inline void wch_usbhs_edpt_disable_iso_in(uint8_t ep_num) { + USBHSD->UEP_TX_EN &= (uint16_t) ~(1u << ep_num); +} + +static inline void wch_usbhs_edpt_close_all(void) { + USBHSD->UEP_TX_EN = USBHS_UEP0_T_EN; + USBHSD->UEP_RX_EN = USBHS_UEP0_R_EN; + USBHSD->UEP_TX_ISO = 0; + USBHSD->UEP_RX_ISO = 0; +} + +static inline uint16_t wch_usbhs_edpt_rx_len(uint8_t ep_num) { + return EP_RX_LEN(ep_num); +} + +static inline void wch_usbhs_edpt_rx_done_clear(uint8_t ep_num) { + EP_RX_CTRL(ep_num) &= (uint8_t) ~USBHS_UEP_R_DONE; +} + +static inline void wch_usbhs_edpt_tx_done_clear(uint8_t ep_num) { + EP_TX_CTRL(ep_num) &= (uint8_t) ~USBHS_UEP_T_DONE; +} + +static inline bool wch_usbhs_edpt_setup_received(uint8_t ep_num) { + return ep_num == 0 && (EP_RX_CTRL(0) & USBHS_UEP_R_SETUP_IS); +} + +#endif diff --git a/src/tusb_option.h b/src/tusb_option.h index 74eb8cc06d..36dbbe5595 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -194,6 +194,7 @@ #define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x #define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X #define OPT_MCU_CH32V103 2230 ///< WCH CH32V103 +#define OPT_MCU_CH32H417 2240 ///< WCH CH32H417 // 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 eb87abf6e1..dccb2186b1 100755 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -247,6 +247,9 @@ 'hw/mcu/wch/ch32f20x': ['https://github.com/openwch/ch32f20x.git', '77c4095087e5ed2c548ec9058e655d0b8757663b', 'ch32f20x'], + 'hw/mcu/wch/ch32h417': ['https://github.com/openwch/ch32h417.git', + 'a0a56fa830b860297a64a72315a731b71c841329', + 'ch32h417'], 'hw/mcu/artery/at32f403a_407': ['https://github.com/ArteryTek/AT32F403A_407_Firmware_Library.git', 'f2cb360c3d28fada76b374308b8c4c61d37a090b', 'at32f403a_407'],