summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Davill <[email protected]>2022-03-21 10:01:11 +1030
committerGreg Davill <[email protected]>2022-03-22 00:30:46 +1030
commitfccbcfc88977ebdfb1448f6787cb052cfa949788 (patch)
treebf1843b534329c82e94a095543a8c140e200f269
parentae531a79f654d566790a4daae350730cdc0a01e9 (diff)
Add WCH CH32V307 port
Add WCH mcu submodule Add CH32V307V-R1-1v0 bsp
-rw-r--r--.gitmodules3
-rw-r--r--hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk3
-rw-r--r--hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c110
-rw-r--r--hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h31
-rw-r--r--hw/bsp/ch32v307/ch32v30x_conf.h43
-rw-r--r--hw/bsp/ch32v307/ch32v30x_it.c49
-rw-r--r--hw/bsp/ch32v307/ch32v30x_it.h18
-rw-r--r--hw/bsp/ch32v307/core_riscv.h384
-rw-r--r--hw/bsp/ch32v307/family.c160
-rw-r--r--hw/bsp/ch32v307/family.mk62
-rw-r--r--hw/bsp/ch32v307/system_ch32v30x.c776
-rw-r--r--hw/bsp/ch32v307/system_ch32v30x.h30
m---------hw/mcu/wch/ch32v3070
-rw-r--r--src/common/tusb_mcu.h4
-rw-r--r--src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h345
-rw-r--r--src/portable/wch/ch32v307/usb_dc_usbhs.c388
-rw-r--r--src/tusb_option.h3
17 files changed, 2409 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules
index 21bbf08c0..fd2b75cb8 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -146,3 +146,6 @@
[submodule "hw/mcu/allwinner"]
path = hw/mcu/allwinner
url = https://github.com/hathach/allwinner_driver.git
+[submodule "hw/mcu/wch/ch32v307"]
+ path = hw/mcu/wch/ch32v307
+ url = https://github.com/openwch/ch32v307.git
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
new file mode 100644
index 000000000..f71def2c7
--- /dev/null
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/board.mk
@@ -0,0 +1,3 @@
+LINKER_SCRIPTS = $(CH32V307_SDK_SRC)/Ld
+
+LD_FILE = $(LINKER_SCRIPTS)/Link.ld # CH32V307
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
new file mode 100644
index 000000000..416782d0e
--- /dev/null
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.c
@@ -0,0 +1,110 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill
+ *
+ * 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.
+ */
+
+#include "debug_uart.h"
+#include <ch32v30x.h>
+
+
+#define UART_RINGBUFFER_SIZE_TX 64
+#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX-1)
+
+static char tx_buf[UART_RINGBUFFER_SIZE_TX];
+static unsigned int tx_produce;
+static volatile unsigned int tx_consume;
+
+void USART1_IRQHandler(void) __attribute__((naked));
+void USART1_IRQHandler(void) {
+ __asm volatile ("call USART1_IRQHandler_impl; mret");
+}
+
+__attribute__((used)) void USART1_IRQHandler_impl(void)
+{
+ if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)
+ {
+ USART_ClearITPendingBit(USART1, USART_IT_TC);
+
+ if(tx_consume != tx_produce) {
+ USART_SendData(USART1, tx_buf[tx_consume]);
+ tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
+ }
+ }
+
+}
+
+void uart_write(char c)
+{
+ unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;
+
+ NVIC_DisableIRQ(USART1_IRQn);
+ if((tx_consume != tx_produce) || (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)) {
+ tx_buf[tx_produce] = c;
+ tx_produce = tx_produce_next;
+ } else {
+ USART_SendData(USART1, c);
+ }
+ NVIC_EnableIRQ(USART1_IRQn);
+}
+
+
+void uart_sync(void)
+{
+ while(tx_consume != tx_produce);
+}
+
+
+void USART_Printf_Init(uint32_t baudrate)
+{
+ GPIO_InitTypeDef GPIO_InitStructure;
+ USART_InitTypeDef USART_InitStructure;
+
+ tx_produce = 0;
+ tx_consume = 0;
+
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
+
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+ GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+ USART_InitStructure.USART_BaudRate = baudrate;
+ USART_InitStructure.USART_WordLength = USART_WordLength_8b;
+ USART_InitStructure.USART_StopBits = USART_StopBits_1;
+ USART_InitStructure.USART_Parity = USART_Parity_No;
+ USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
+ USART_InitStructure.USART_Mode = USART_Mode_Tx;
+
+ USART_Init(USART1, &USART_InitStructure);
+ USART_ITConfig(USART1, USART_IT_TC, ENABLE);
+ USART_Cmd(USART1, ENABLE);
+
+ NVIC_InitTypeDef NVIC_InitStructure = {0};
+ NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
+ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
+ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
+ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+ NVIC_Init(&NVIC_InitStructure);
+}
diff --git a/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
new file mode 100644
index 000000000..4348438bb
--- /dev/null
+++ b/hw/bsp/ch32v307/boards/CH32V307V-R1-1v0/debug_uart.h
@@ -0,0 +1,31 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill
+ *
+ * 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.
+ */
+
+#include <stdint.h>
+
+void uart_write(char c);
+void uart_sync(void);
+void USART_Printf_Init(uint32_t baudrate);
diff --git a/hw/bsp/ch32v307/ch32v30x_conf.h b/hw/bsp/ch32v307/ch32v30x_conf.h
new file mode 100644
index 000000000..399feaf68
--- /dev/null
+++ b/hw/bsp/ch32v307/ch32v30x_conf.h
@@ -0,0 +1,43 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name : ch32v30x_conf.h
+* Author : WCH
+* Version : V1.0.0
+* Date : 2021/06/06
+* Description : Library configuration file.
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#ifndef __CH32V30x_CONF_H
+#define __CH32V30x_CONF_H
+
+#include "ch32v30x_adc.h"
+#include "ch32v30x_bkp.h"
+#include "ch32v30x_can.h"
+#include "ch32v30x_crc.h"
+#include "ch32v30x_dac.h"
+#include "ch32v30x_dbgmcu.h"
+#include "ch32v30x_dma.h"
+#include "ch32v30x_exti.h"
+#include "ch32v30x_flash.h"
+#include "ch32v30x_fsmc.h"
+#include "ch32v30x_gpio.h"
+#include "ch32v30x_i2c.h"
+#include "ch32v30x_iwdg.h"
+#include "ch32v30x_pwr.h"
+#include "ch32v30x_rcc.h"
+#include "ch32v30x_rtc.h"
+#include "ch32v30x_sdio.h"
+#include "ch32v30x_spi.h"
+#include "ch32v30x_tim.h"
+#include "ch32v30x_usart.h"
+#include "ch32v30x_wwdg.h"
+#include "ch32v30x_it.h"
+#include "ch32v30x_misc.h"
+
+
+#endif /* __CH32V30x_CONF_H */
+
+
+
+
+
diff --git a/hw/bsp/ch32v307/ch32v30x_it.c b/hw/bsp/ch32v307/ch32v30x_it.c
new file mode 100644
index 000000000..d348dd989
--- /dev/null
+++ b/hw/bsp/ch32v307/ch32v30x_it.c
@@ -0,0 +1,49 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name : ch32v30x_it.c
+* Author : WCH
+* Version : V1.0.0
+* Date : 2021/06/06
+* Description : Main Interrupt Service Routines.
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#include "ch32v30x_it.h"
+
+void NMI_Handler(void) __attribute__((naked));
+void HardFault_Handler(void) __attribute__((naked));
+
+/*********************************************************************
+ * @fn NMI_Handler
+ *
+ * @brief This function handles NMI exception.
+ *
+ * @return none
+ */
+void NMI_Handle(void){
+ __asm volatile ("call NMI_Handler_impl; mret");
+}
+
+__attribute__((used)) void NMI_Handler_impl(void)
+{
+
+}
+
+/*********************************************************************
+ * @fn HardFault_Handler
+ *
+ * @brief This function handles Hard Fault exception.
+ *
+ * @return none
+ */
+void HardFault_Handler(void){
+ __asm volatile ("call HardFault_Handler_impl; mret");
+}
+
+__attribute__((used)) void HardFault_Handler_impl(void)
+{
+ while (1)
+ {
+ }
+}
+
+
diff --git a/hw/bsp/ch32v307/ch32v30x_it.h b/hw/bsp/ch32v307/ch32v30x_it.h
new file mode 100644
index 000000000..6475c5f11
--- /dev/null
+++ b/hw/bsp/ch32v307/ch32v30x_it.h
@@ -0,0 +1,18 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name : ch32v30x_it.h
+* Author : WCH
+* Version : V1.0.0
+* Date : 2021/06/06
+* Description : This file contains the headers of the interrupt handlers.
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#ifndef __CH32V30x_IT_H
+#define __CH32V30x_IT_H
+
+#include "debug.h"
+
+
+#endif /* __CH32V30x_IT_H */
+
+
diff --git a/hw/bsp/ch32v307/core_riscv.h b/hw/bsp/ch32v307/core_riscv.h
new file mode 100644
index 000000000..2e94ec683
--- /dev/null
+++ b/hw/bsp/ch32v307/core_riscv.h
@@ -0,0 +1,384 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name : core_riscv.h
+* Author : WCH
+* Version : V1.0.0
+* Date : 2021/06/06
+* Description : RISC-V Core Peripheral Access Layer Header File for CH32V30x
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#ifndef __CORE_RISCV_H__
+#define __CORE_RISCV_H__
+
+/* IO definitions */
+#ifdef __cplusplus
+ #define __I volatile /* defines 'read only' permissions */
+#else
+ #define __I volatile const /* defines 'read only' permissions */
+#endif
+#define __O volatile /* defines 'write only' permissions */
+#define __IO volatile /* defines 'read / write' permissions */
+
+/* Standard Peripheral Library old types (maintained for legacy purpose) */
+typedef __I uint64_t vuc64; /* Read Only */
+typedef __I uint32_t vuc32; /* Read Only */
+typedef __I uint16_t vuc16; /* Read Only */
+typedef __I uint8_t vuc8; /* Read Only */
+
+typedef const uint64_t uc64; /* Read Only */
+typedef const uint32_t uc32; /* Read Only */
+typedef const uint16_t uc16; /* Read Only */
+typedef const uint8_t uc8; /* Read Only */
+
+typedef __I int64_t vsc64; /* Read Only */
+typedef __I int32_t vsc32; /* Read Only */
+typedef __I int16_t vsc16; /* Read Only */
+typedef __I int8_t vsc8; /* Read Only */
+
+typedef const int64_t sc64; /* Read Only */
+typedef const int32_t sc32; /* Read Only */
+typedef const int16_t sc16; /* Read Only */
+typedef const int8_t sc8; /* Read Only */
+
+typedef __IO uint64_t vu64;
+typedef __IO uint32_t vu32;
+typedef __IO uint16_t vu16;
+typedef __IO uint8_t vu8;
+
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+typedef __IO int64_t vs64;
+typedef __IO int32_t vs32;
+typedef __IO int16_t vs16;
+typedef __IO int8_t vs8;
+
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t s8;
+
+typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
+
+typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
+
+typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
+
+#define RV_STATIC_INLINE static inline
+
+/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
+typedef struct{
+ __I uint32_t ISR[8];
+ __I uint32_t IPR[8];
+ __IO uint32_t ITHRESDR;
+ __IO uint32_t RESERVED;
+ __IO uint32_t CFGR;
+ __I uint32_t GISR;
+ uint8_t VTFIDR[4];
+ uint8_t RESERVED0[12];
+ __IO uint32_t VTFADDR[4];
+ uint8_t RESERVED1[0x90];
+ __O uint32_t IENR[8];
+ uint8_t RESERVED2[0x60];
+ __O uint32_t IRER[8];
+ uint8_t RESERVED3[0x60];
+ __O uint32_t IPSR[8];
+ uint8_t RESERVED4[0x60];
+ __O uint32_t IPRR[8];
+ uint8_t RESERVED5[0x60];
+ __IO uint32_t IACTR[8];
+ uint8_t RESERVED6[0xE0];
+ __IO uint8_t IPRIOR[256];
+ uint8_t RESERVED7[0x810];
+ __IO uint32_t SCTLR;
+}PFIC_Type;
+
+/* memory mapped structure for SysTick */
+typedef struct
+{
+ __IO u32 CTLR;
+ __IO u32 SR;
+ __IO u64 CNT;
+ __IO u64 CMP;
+}SysTick_Type;
+
+
+#define PFIC ((PFIC_Type *) 0xE000E000 )
+#define NVIC PFIC
+#define NVIC_KEY1 ((uint32_t)0xFA050000)
+#define NVIC_KEY2 ((uint32_t)0xBCAF0000)
+#define NVIC_KEY3 ((uint32_t)0xBEEF0000)
+
+#define SysTick ((SysTick_Type *) 0xE000F000)
+
+
+/*********************************************************************
+ * @fn __enable_irq
+ *
+ * @brief Enable Global Interrupt
+ *
+ * @return none
+ */
+RV_STATIC_INLINE void __enable_irq(void)
+{
+ __asm volatile ("csrw 0x800, %0" : : "r" (0x6088) );
+}
+
+/*********************************************************************
+ * @fn __disable_irq
+ *
+ * @brief Disable Global Interrupt
+ *
+ * @return none
+ */
+RV_STATIC_INLINE void __disable_irq(void)
+{
+ __asm volatile ("csrw 0x800, %0" : : "r" (0x6000) );
+}
+
+/*********************************************************************
+ * @fn __NOP
+ *
+ * @brief nop
+ *
+ * @return none
+ */
+RV_STATIC_INLINE void __NOP(void)
+{
+ __asm volatile ("nop");
+}
+
+/*********************************************************************
+ * @fn NVIC_EnableIRQ
+ *
+ * @brief Enable Interrupt
+ *
+ * @param IRQn: Interrupt Numbers
+ *
+ * @return none
+ */
+RV_STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
+{
+ NVIC->IENR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn NVIC_DisableIRQ
+ *
+ * @brief Disable Interrupt
+ *
+ * @param IRQn: Interrupt Numbers
+ *
+ * @return none
+ */
+RV_STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
+{
+ NVIC->IRER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn NVIC_GetStatusIRQ
+ *
+ * @brief Get Interrupt Enable State
+ *
+ * @param IRQn: Interrupt Numbers
+ *
+ * @return 1 - Interrupt Enable
+ * 0 - Interrupt Disable
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetStatusIRQ(IRQn_Type IRQn)
+{
+ return((uint32_t) ((NVIC->ISR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn NVIC_GetPendingIRQ
+ *
+ * @brief Get Interrupt Pending State
+ *
+ * @param IRQn: Interrupt Numbers
+ *
+ * @return 1 - Interrupt Pending Enable
+ * 0 - Interrupt Pending Disable
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
+{
+ return((uint32_t) ((NVIC->IPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn NVIC_SetPendingIRQ
+ *
+ * @brief Set Interrupt Pending
+ *
+ * @param IRQn: Interrupt Numbers
+ *
+ * @return None
+ */
+RV_STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
+{
+ NVIC->IPSR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn NVIC_ClearPendingIRQ
+ *
+ * @brief Clear Interrupt Pending
+ *
+ * @param IRQn: Interrupt Numbers
+ *
+ * @return None
+ */
+RV_STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
+{
+ NVIC->IPRR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
+}
+
+/*********************************************************************
+ * @fn NVIC_GetActive
+ *
+ * @brief Get Interrupt Active State
+ *
+ * @param IRQn: Interrupt Numbers
+ *
+ * @return 1 - Interrupt Active
+ * 0 - Interrupt No Active
+ */
+RV_STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
+{
+ return((uint32_t)((NVIC->IACTR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
+}
+
+/*********************************************************************
+ * @fn NVIC_SetPriority
+ *
+ * @brief Set Interrupt Priority
+ *
+ * @param IRQn - Interrupt Numbers
+ * priority -
+ * bit7 - pre-emption priority
+ * bit6~bit4 - subpriority
+ * @return None
+ */
+RV_STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint8_t priority)
+{
+ NVIC->IPRIOR[(uint32_t)(IRQn)] = priority;
+}
+
+/*********************************************************************
+ * @fn __WFI
+ *
+ * @brief Wait for Interrupt
+ *
+ * @return None
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFI(void)
+{
+ NVIC->SCTLR &= ~(1<<3); // wfi
+ asm volatile ("wfi");
+}
+
+/*********************************************************************
+ * @fn __WFE
+ *
+ * @brief Wait for Events
+ *
+ * @return None
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFE(void)
+{
+ uint32_t t;
+
+ t = NVIC->SCTLR;
+ NVIC->SCTLR |= (1<<3)|(1<<5); // (wfi->wfe)+(__sev)
+ NVIC->SCTLR = (NVIC->SCTLR & ~(1<<5)) | ( t & (1<<5));
+ asm volatile ("wfi");
+ asm volatile ("wfi");
+}
+
+/*********************************************************************
+ * @fn SetVTFIRQ
+ *
+ * @brief Set VTF Interrupt
+ *
+ * @param add - VTF interrupt service function base address.
+ * IRQn -Interrupt Numbers
+ * num - VTF Interrupt Numbers
+ * NewState - DISABLE or ENABLE
+ * @return None
+ */
+RV_STATIC_INLINE void SetVTFIRQ(uint32_t addr, IRQn_Type IRQn, uint8_t num, FunctionalState NewState){
+ if(num > 3) return ;
+
+ if (NewState != DISABLE)
+ {
+ NVIC->VTFIDR[num] = IRQn;
+ NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)|0x1);
+ }
+ else{
+ NVIC->VTFIDR[num] = IRQn;
+ NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)&(~0x1));
+ }
+}
+
+/*********************************************************************
+ * @fn NVIC_SystemReset
+ *
+ * @brief Initiate a system reset request
+ *
+ * @return None
+ */
+RV_STATIC_INLINE void NVIC_SystemReset(void)
+{
+ NVIC->CFGR = NVIC_KEY3|(1<<7);
+}
+
+
+/* Core_Exported_Functions */
+extern uint32_t __get_FFLAGS(void);
+extern void __set_FFLAGS(uint32_t value);
+extern uint32_t __get_FRM(void);
+extern void __set_FRM(uint32_t value);
+extern uint32_t __get_FCSR(void);
+extern void __set_FCSR(uint32_t value);
+extern uint32_t __get_MSTATUS(void);
+extern void __set_MSTATUS(uint32_t value);
+extern uint32_t __get_MISA(void);
+extern void __set_MISA(uint32_t value);
+extern uint32_t __get_MIE(void);
+extern void __set_MIE(uint32_t value);
+extern uint32_t __get_MTVEC(void);
+extern void __set_MTVEC(uint32_t value);
+extern uint32_t __get_MSCRATCH(void);
+extern void __set_MSCRATCH(uint32_t value);
+extern uint32_t __get_MEPC(void);
+extern void __set_MEPC(uint32_t value);
+extern uint32_t __get_MCAUSE(void);
+extern void __set_MCAUSE(uint32_t value);
+extern uint32_t __get_MTVAL(void);
+extern void __set_MTVAL(uint32_t value);
+extern uint32_t __get_MIP(void);
+extern void __set_MIP(uint32_t value);
+extern uint32_t __get_MCYCLE(void);
+extern void __set_MCYCLE(uint32_t value);
+extern uint32_t __get_MCYCLEH(void);
+extern void __set_MCYCLEH(uint32_t value);
+extern uint32_t __get_MINSTRET(void);
+extern void __set_MINSTRET(uint32_t value);
+extern uint32_t __get_MINSTRETH(void);
+extern void __set_MINSTRETH(uint32_t value);
+extern uint32_t __get_MVENDORID(void);
+extern uint32_t __get_MARCHID(void);
+extern uint32_t __get_MIMPID(void);
+extern uint32_t __get_MHARTID(void);
+extern uint32_t __get_SP(void);
+
+
+#endif
+
+
+
+
+
diff --git a/hw/bsp/ch32v307/family.c b/hw/bsp/ch32v307/family.c
new file mode 100644
index 000000000..ea1c252c4
--- /dev/null
+++ b/hw/bsp/ch32v307/family.c
@@ -0,0 +1,160 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill
+ *
+ * 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.
+ */
+
+#include "stdio.h"
+#include "debug_uart.h"
+#include "ch32v30x.h"
+
+#include "../board.h"
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+
+void USBHS_IRQHandler(void) __attribute__((naked));
+void USBHS_IRQHandler(void) {
+ __asm volatile ("call USBHS_IRQHandler_impl; mret");
+}
+
+__attribute__ ((used)) void USBHS_IRQHandler_impl(void) {
+ tud_int_handler(0);
+}
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+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;
+}
+
+void board_init(void) {
+
+ /* Disable interrupts during init */
+ __disable_irq();
+
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+ SysTick_Config(SystemCoreClock / 1000);
+#endif
+
+ USART_Printf_Init(115200);
+
+ RCC_USBCLK48MConfig(RCC_USBCLK48MCLKSource_USBPHY);
+ RCC_USBHSPLLCLKConfig(RCC_HSBHSPLLCLKSource_HSE);
+ RCC_USBHSConfig(RCC_USBPLL_Div2);
+ RCC_USBHSPLLCKREFCLKConfig(RCC_USBHSPLLCKREFCLK_4M);
+ RCC_USBHSPHYPLLALIVEcmd(ENABLE);
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHS, ENABLE);
+
+ GPIO_InitTypeDef GPIO_InitStructure = {0};
+
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
+ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
+ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
+ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+ GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+ /* Enable interrupts globaly */
+ __enable_irq();
+
+ board_delay(2);
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+
+volatile uint32_t system_ticks = 0;
+
+/* Small workaround to support HW stack save/restore */
+void SysTick_Handler(void) __attribute__((naked));
+void SysTick_Handler(void) {
+ __asm volatile ("call SysTick_Handler_impl; mret");
+}
+
+__attribute__((used)) void SysTick_Handler_impl(void) {
+ SysTick->SR=0;
+ system_ticks++;
+}
+
+uint32_t board_millis(void) { return system_ticks; }
+
+#endif
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state) {
+ (void) state;
+
+ GPIO_WriteBit(GPIOC, GPIO_Pin_0, state);
+}
+
+uint32_t board_button_read(void) {
+ return false;
+}
+
+int board_uart_read(uint8_t* buf, int len) {
+ (void)buf;
+ (void)len;
+ return 0;
+}
+
+int board_uart_write(void const* buf, int len) {
+ int txsize = len;
+ while (txsize--) {
+ uart_write(*(uint8_t const*)buf);
+ buf++;
+ }
+ return len;
+}
+
+
+
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief Reports the name of the source file and the source line number
+ * where the assert_param error has occurred.
+ * @param file: pointer to the source file name
+ * @param line: assert_param error line source number
+ * @retval None
+ */
+void assert_failed(char* file, uint32_t line) {
+ /* USER CODE BEGIN 6 */
+ /* User can add his own implementation to report the file name and line
+ number,
+ tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line)
+ */
+ /* USER CODE END 6 */
+}
+#endif /* USE_FULL_ASSERT */
diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
new file mode 100644
index 000000000..dfb4853d9
--- /dev/null
+++ b/hw/bsp/ch32v307/family.mk
@@ -0,0 +1,62 @@
+# https://www.embecosm.com/resources/tool-chain-downloads/#riscv-stable
+#CROSS_COMPILE ?= riscv32-unknown-elf-
+
+# Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack
+CROSS_COMPILE ?= riscv-none-embed-
+
+# Submodules
+CH32V307_SDK = hw/mcu/wch/ch32v307
+DEPS_SUBMODULES += $(CH32V307_SDK)
+
+# WCH-SDK paths
+CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC
+CH32V307_SDK_SRC_TOP = $(TOP)/$(CH32V307_SDK_SRC)
+CH32V307_STARTUP_ASM = $(CH32V307_SDK_SRC)/Startup
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+SKIP_NANOLIB = 1
+
+CFLAGS += \
+ -flto \
+ -march=rv32imac \
+ -mabi=ilp32 \
+ -msmall-data-limit=8 \
+ -mno-save-restore -Os \
+ -fmessage-length=0 \
+ -fsigned-char \
+ -ffunction-sections \
+ -fdata-sections \
+ -nostdlib -nostartfiles \
+ -DCFG_TUSB_MCU=OPT_MCU_CH32VF307 \
+ -Xlinker --gc-sections \
+ -DBOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED
+
+LDFLAGS += \
+ -Xlinker --gc-sections --specs=nano.specs --specs=nosys.specs
+
+SRC_C += \
+ src/portable/wch/ch32v307/usb_dc_usbhs.c \
+ $(CH32V307_SDK_SRC_TOP)/Core/core_riscv.c \
+ $(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_gpio.c \
+ $(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_misc.c \
+ $(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_rcc.c \
+ $(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_usart.c
+
+SRC_S += \
+ $(CH32V307_STARTUP_ASM)/startup_ch32v30x_D8C.S
+
+INC += \
+ src/portable/wch/ch32v307 \
+ $(TOP)/$(BOARD_PATH)/.. \
+ $(TOP)/$(BOARD_PATH) \
+ $(CH32V307_SDK_SRC_TOP)/Peripheral/inc \
+ $(CH32V307_SDK_SRC_TOP)/Debug \
+ $(CH32V307_SDK_SRC_TOP)
+
+# For freeRTOS port source
+FREERTOS_PORT = RISC-V
+
+# flash target ROM bootloader
+flash: $(BUILD)/$(PROJECT).elf
+ openocd -f wch-riscv.cfg -c init -c halt -c "program $< 0x08000000" -c reset -c exit
diff --git a/hw/bsp/ch32v307/system_ch32v30x.c b/hw/bsp/ch32v307/system_ch32v30x.c
new file mode 100644
index 000000000..12b18d7b8
--- /dev/null
+++ b/hw/bsp/ch32v307/system_ch32v30x.c
@@ -0,0 +1,776 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name : system_ch32v30x.c
+* Author : WCH
+* Version : V1.0.0
+* Date : 2021/06/06
+* Description : CH32V30x Device Peripheral Access Layer System Source File.
+* For HSE = 8Mhz
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*********************************************************************************/
+#include "ch32v30x.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_FREQ_HSE HSE_VALUE
+/* #define SYSCLK_FREQ_24MHz 24000000 */
+//#define SYSCLK_FREQ_48MHz 48000000
+/* #define SYSCLK_FREQ_56MHz 56000000 */
+//#define SYSCLK_FREQ_72MHz 72000000
+//#define SYSCLK_FREQ_96MHz 96000000
+//#define SYSCLK_FREQ_120MHz 120000000
+#define SYSCLK_FREQ_144MHz 144000000
+
+/* Clock Definitions */
+#ifdef SYSCLK_FREQ_HSE
+ uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_24MHz
+ uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_48MHz
+ uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_56MHz
+ uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_72MHz
+ uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /* System Clock Frequency (Core Clock) */
+
+#elif defined SYSCLK_FREQ_96MHz
+ uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_120MHz
+ uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_144MHz
+ uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz; /* System Clock Frequency (Core Clock) */
+
+#else /* HSI Selected as System Clock source */
+ uint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */
+#endif
+
+__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+
+
+/* system_private_function_proto_types */
+static void SetSysClock(void);
+
+#ifdef SYSCLK_FREQ_HSE
+ static void SetSysClockToHSE(void);
+#elif defined SYSCLK_FREQ_24MHz
+ static void SetSysClockTo24(void);
+#elif defined SYSCLK_FREQ_48MHz
+ static void SetSysClockTo48(void);
+#elif defined SYSCLK_FREQ_56MHz
+ static void SetSysClockTo56(void);
+#elif defined SYSCLK_FREQ_72MHz
+ static void SetSysClockTo72(void);
+
+#elif defined SYSCLK_FREQ_96MHz
+ static void SetSysClockTo96(void);
+#elif defined SYSCLK_FREQ_120MHz
+ static void SetSysClockTo120(void);
+#elif defined SYSCLK_FREQ_144MHz
+ static void SetSysClockTo144(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;
+
+#ifdef CH32V30x_D8C
+ RCC->CFGR0 &= (uint32_t)0xF8FF0000;
+#else
+ RCC->CFGR0 &= (uint32_t)0xF0FF0000;
+#endif
+
+ RCC->CTLR &= (uint32_t)0xFEF6FFFF;
+ RCC->CTLR &= (uint32_t)0xFFFBFFFF;
+ RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
+
+#ifdef CH32V30x_D8C
+ RCC->CTLR &= (uint32_t)0xEBFFFFFF;
+ RCC->INTR = 0x00FF0000;
+ RCC->CFGR2 = 0x00000000;
+#else
+ RCC->INTR = 0x009F0000;
+#endif
+ SetSysClock();
+}
+
+/*********************************************************************
+ * @fn SystemCoreClockUpdate
+ *
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ *
+ * @return none
+ */
+void SystemCoreClockUpdate (void)
+{
+ uint32_t tmp = 0, pllmull = 0, pllsource = 0, Pll_6_5 = 0;
+
+ tmp = RCC->CFGR0 & RCC_SWS;
+
+ switch (tmp)
+ {
+ case 0x00:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case 0x04:
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case 0x08:
+ pllmull = RCC->CFGR0 & RCC_PLLMULL;
+ pllsource = RCC->CFGR0 & RCC_PLLSRC;
+ pllmull = ( pllmull >> 18) + 2;
+
+#ifdef CH32V30x_D8
+ if(pllmull == 17) pllmull = 18;
+#else
+ if(pllmull == 2) pllmull = 18;
+ if(pllmull == 15){
+ pllmull = 13; /* *6.5 */
+ Pll_6_5 = 1;
+ }
+ if(pllmull == 16) pllmull = 15;
+ if(pllmull == 17) pllmull = 16;
+#endif
+
+ if (pllsource == 0x00)
+ {
+ SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
+ }
+ else
+ {
+ if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
+ {
+ SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
+ }
+ else
+ {
+ SystemCoreClock = HSE_VALUE * pllmull;
+ }
+ }
+
+ if(Pll_6_5 == 1) SystemCoreClock = (SystemCoreClock / 2);
+
+ break;
+ default:
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+
+ tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
+ SystemCoreClock >>= tmp;
+}
+
+/*********************************************************************
+ * @fn SetSysClock
+ *
+ * @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClock(void)
+{
+#ifdef SYSCLK_FREQ_HSE
+ SetSysClockToHSE();
+#elif defined SYSCLK_FREQ_24MHz
+ SetSysClockTo24();
+#elif defined SYSCLK_FREQ_48MHz
+ SetSysClockTo48();
+#elif defined SYSCLK_FREQ_56MHz
+ SetSysClockTo56();
+#elif defined SYSCLK_FREQ_72MHz
+ SetSysClockTo72();
+#elif defined SYSCLK_FREQ_96MHz
+ SetSysClockTo96();
+#elif defined SYSCLK_FREQ_120MHz
+ SetSysClockTo120();
+#elif defined SYSCLK_FREQ_144MHz
+ SetSysClockTo144();
+
+#endif
+
+ /* If none of the define above is enabled, the HSI is used as System clock
+ * source (default after reset)
+ */
+}
+
+
+#ifdef SYSCLK_FREQ_HSE
+
+/*********************************************************************
+ * @fn SetSysClockToHSE
+ *
+ * @brief Sets HSE as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockToHSE(void)
+{
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 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)
+ {
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
+
+ /* Select HSE as system clock source */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
+ RCC->CFGR0 |= (uint32_t)RCC_SW_HSE;
+
+ /* Wait till HSE is used as system clock source */
+ while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04)
+ {
+ }
+ }
+ 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_FREQ_24MHz
+
+/*********************************************************************
+ * @fn SetSysClockTo24
+ *
+ * @brief Sets System clock frequency to 24MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo24(void)
+{
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 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)
+ {
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
+
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL3);
+#else
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL3_EXTEN);
+#endif
+ /* Enable PLL */
+ RCC->CTLR |= RCC_PLLON;
+
+ /* Wait till PLL is ready */
+ while((RCC->CTLR & RCC_PLLRDY) == 0)
+ {
+ }
+ /* Select PLL as system clock source */
+ 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_FREQ_48MHz
+
+/*********************************************************************
+ * @fn SetSysClockTo48
+ *
+ * @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo48(void)
+{
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 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)
+ {
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+ /* PLL configuration: PLLCLK = HSE * 6 = 48 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6);
+#else
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6_EXTEN);
+#endif
+
+ /* Enable PLL */
+ RCC->CTLR |= RCC_PLLON;
+ /* Wait till PLL is ready */
+ while((RCC->CTLR & RCC_PLLRDY) == 0)
+ {
+ }
+ /* Select PLL as system clock source */
+ 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_FREQ_56MHz
+
+/*********************************************************************
+ * @fn SetSysClockTo56
+ *
+ * @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo56(void)
+{
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 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)
+ {
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+ /* PLL configuration: PLLCLK = HSE * 7 = 56 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7);
+#else
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7_EXTEN);
+#endif
+
+ /* Enable PLL */
+ RCC->CTLR |= RCC_PLLON;
+ /* Wait till PLL is ready */
+ while((RCC->CTLR & RCC_PLLRDY) == 0)
+ {
+ }
+
+ /* Select PLL as system clock source */
+ 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_FREQ_72MHz
+
+/*********************************************************************
+ * @fn SetSysClockTo72
+ *
+ * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo72(void)
+{
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 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)
+ {
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+ /* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9);
+#else
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9_EXTEN);
+#endif
+
+ /* Enable PLL */
+ RCC->CTLR |= RCC_PLLON;
+ /* Wait till PLL is ready */
+ while((RCC->CTLR & RCC_PLLRDY) == 0)
+ {
+ }
+ /* Select PLL as system clock source */
+ 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_FREQ_96MHz
+
+/*********************************************************************
+ * @fn SetSysClockTo96
+ *
+ * @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo96(void)
+{
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 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)
+ {
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+ /* PLL configuration: PLLCLK = HSE * 12 = 96 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12);
+#else
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12_EXTEN);
+#endif
+
+ /* Enable PLL */
+ RCC->CTLR |= RCC_PLLON;
+ /* Wait till PLL is ready */
+ while((RCC->CTLR & RCC_PLLRDY) == 0)
+ {
+ }
+ /* Select PLL as system clock source */
+ 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_FREQ_120MHz
+
+/*********************************************************************
+ * @fn SetSysClockTo120
+ *
+ * @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo120(void)
+{
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 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)
+ {
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+ /* PLL configuration: PLLCLK = HSE * 15 = 120 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15);
+#else
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15_EXTEN);
+#endif
+
+ /* Enable PLL */
+ RCC->CTLR |= RCC_PLLON;
+ /* Wait till PLL is ready */
+ while((RCC->CTLR & RCC_PLLRDY) == 0)
+ {
+ }
+ /* Select PLL as system clock source */
+ 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_FREQ_144MHz
+
+/*********************************************************************
+ * @fn SetSysClockTo144
+ *
+ * @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo144(void)
+{
+ __IO uint32_t StartUpCounter = 0, HSEStatus = 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)
+ {
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+ /* PLL configuration: PLLCLK = HSE * 18 = 144 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+#ifdef CH32V30x_D8
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18);
+#else
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18_EXTEN);
+#endif
+
+ /* Enable PLL */
+ RCC->CTLR |= RCC_PLLON;
+ /* Wait till PLL is ready */
+ while((RCC->CTLR & RCC_PLLRDY) == 0)
+ {
+ }
+ /* Select PLL as system clock source */
+ 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
+ */
+ }
+}
+
+
+#endif
diff --git a/hw/bsp/ch32v307/system_ch32v30x.h b/hw/bsp/ch32v307/system_ch32v30x.h
new file mode 100644
index 000000000..0e0ef4e51
--- /dev/null
+++ b/hw/bsp/ch32v307/system_ch32v30x.h
@@ -0,0 +1,30 @@
+/********************************** (C) COPYRIGHT *******************************
+* File Name : system_ch32v30x.h
+* Author : WCH
+* Version : V1.0.0
+* Date : 2021/06/06
+* Description : CH32V30x Device Peripheral Access Layer System Header File.
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* SPDX-License-Identifier: Apache-2.0
+*******************************************************************************/
+#ifndef __SYSTEM_CH32V30x_H
+#define __SYSTEM_CH32V30x_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */
+
+/* System_Exported_Functions */
+extern void SystemInit(void);
+extern void SystemCoreClockUpdate(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__CH32V30x_SYSTEM_H */
+
+
+
diff --git a/hw/mcu/wch/ch32v307 b/hw/mcu/wch/ch32v307
new file mode 160000
+Subproject 17761f5cf9dbbf2dcf665b7c04934188add2008
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 8eb4ad475..84d629eac 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -266,6 +266,10 @@
#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
#define TUP_DCD_ENDPOINT_MAX 4
+//------------- WCH -------------//
+#elif TU_CHECK_MCU(OPT_MCU_CH32VF307)
+ #define TUP_DCD_ENDPOINT_MAX 8
+
#endif
//--------------------------------------------------------------------+
diff --git a/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h b/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
new file mode 100644
index 000000000..1b7c0e791
--- /dev/null
+++ b/src/portable/wch/ch32v307/usb_ch32_usbhs_reg.h
@@ -0,0 +1,345 @@
+#ifndef _USB_CH32_USBHS_REG_H
+#define _USB_CH32_USBHS_REG_H
+
+#include <ch32v30x.h>
+
+/******************* GLOBAL ******************/
+
+// USB CONTROL
+#define USBHS_CONTROL_OFFSET 0x00
+#define USBHS_DMA_EN (1 << 0)
+#define USBHS_ALL_CLR (1 << 1)
+#define USBHS_FORCE_RST (1 << 2)
+#define USBHS_INT_BUSY_EN (1 << 3)
+#define USBHS_DEV_PU_EN (1 << 4)
+#define USBHS_SPEED_MASK (3 << 5)
+#define USBHS_FULL_SPEED (0 << 5)
+#define USBHS_HIGH_SPEED (1 << 5)
+#define USBHS_LOW_SPEED (2 << 5)
+#define USBHS_HOST_MODE (1 << 7)
+
+// USB_INT_EN
+#define USBHS_INT_EN_OFFSET 0x02
+#define USBHS_BUS_RST_EN (1 << 0)
+#define USBHS_DETECT_EN (1 << 0)
+#define USBHS_TRANSFER_EN (1 << 1)
+#define USBHS_SUSPEND_EN (1 << 2)
+#define USBHS_SOF_ACT_EN (1 << 3)
+#define USBHS_FIFO_OV_EN (1 << 4)
+#define USBHS_SETUP_ACT_EN (1 << 5)
+#define USBHS_ISO_ACT_EN (1 << 6)
+#define USBHS_DEV_NAK_EN (1 << 7)
+
+// USB DEV AD
+#define USBHS_DEV_AD_OFFSET 0x03
+// USB FRAME_NO
+#define USBHS_FRAME_NO_OFFSET 0x04
+// USB SUSPEND
+#define USBHS_SUSPEND_OFFSET 0x06
+#define USBHS_DEV_REMOTE_WAKEUP (1 << 2)
+#define USBHS_LINESTATE_MASK (2 << 4) /* Read Only */
+
+// RESERVED0
+
+// USB SPEED TYPE
+#define USBHS_SPEED_TYPE_OFFSET 0x08
+#define USBSPEED_MASK (0x03)
+
+// USB_MIS_ST
+#define USBHS_MIS_ST_OFFSET 0x09
+#define USBHS_SPLIT_CAN (1 << 0)
+#define USBHS_ATTACH (1 << 1)
+#define USBHS_SUSPEND (1 << 2)
+#define USBHS_BUS_RESET (1 << 3)
+#define USBHS_R_FIFO_RDY (1 << 4)
+#define USBHS_SIE_FREE (1 << 5)
+#define USBHS_SOF_ACT (1 << 6)
+#define USBHS_SOF_PRES (1 << 7)
+
+// INT_FLAG
+#define USBHS_INT_FLAG_OFFSET 0x0A
+#define USBHS_BUS_RST_FLAG (1 << 0)
+#define USBHS_DETECT_FLAG (1 << 0)
+#define USBHS_TRANSFER_FLAG (1 << 1)
+#define USBHS_SUSPEND_FLAG (1 << 2)
+#define USBHS_HST_SOF_FLAG (1 << 3)
+#define USBHS_FIFO_OV_FLAG (1 << 4)
+#define USBHS_SETUP_FLAG (1 << 5)
+#define USBHS_ISO_ACT_FLAG (1 << 6)
+
+// INT_ST
+#define USBHS_INT_ST_OFFSET 0x0B
+#define USBHS_DEV_UIS_IS_NAK (1 << 7)
+#define USBHS_DEV_UIS_TOG_OK (1 << 6)
+#define MASK_UIS_TOKEN (3 << 4)
+#define MASK_UIS_ENDP (0x0F)
+#define MASK_UIS_H_RES (0x0F)
+
+#define USBHS_TOGGLE_OK (0x40)
+#define USBHS_HOST_RES (0x0f)
+
+//USB_RX_LEN
+#define USBHS_RX_LEN_OFFSET 0x0C
+/******************* DEVICE ******************/
+
+//UEP_CONFIG
+#define USBHS_UEP_CONFIG_OFFSET 0x10
+#define USBHS_EP0_T_EN (1 << 0)
+#define USBHS_EP0_R_EN (1 << 16)
+
+#define USBHS_EP1_T_EN (1 << 1)
+#define USBHS_EP1_R_EN (1 << 17)
+
+#define USBHS_EP2_T_EN (1 << 2)
+#define USBHS_EP2_R_EN (1 << 18)
+
+#define USBHS_EP3_T_EN (1 << 3)
+#define USBHS_EP3_R_EN (1 << 19)
+
+#define USBHS_EP4_T_EN (1 << 4)
+#define USBHS_EP4_R_EN (1 << 20)
+
+#define USBHS_EP5_T_EN (1 << 5)
+#define USBHS_EP5_R_EN (1 << 21)
+
+#define USBHS_EP6_T_EN (1 << 6)
+#define USBHS_EP6_R_EN (1 << 22)
+
+#define USBHS_EP7_T_EN (1 << 7)
+#define USBHS_EP7_R_EN (1 << 23)
+
+#define USBHS_EP8_T_EN (1 << 8)
+#define USBHS_EP8_R_EN (1 << 24)
+
+#define USBHS_EP9_T_EN (1 << 9)
+#define USBHS_EP9_R_EN (1 << 25)
+
+#define USBHS_EP10_T_EN (1 << 10)
+#define USBHS_EP10_R_EN (1 << 26)
+
+#define USBHS_EP11_T_EN (1 << 11)
+#define USBHS_EP11_R_EN (1 << 27)
+
+#define USBHS_EP12_T_EN (1 << 12)
+#define USBHS_EP12_R_EN (1 << 28)
+
+#define USBHS_EP13_T_EN (1 << 13)
+#define USBHS_EP13_R_EN (1 << 29)
+
+#define USBHS_EP14_T_EN (1 << 14)
+#define USBHS_EP14_R_EN (1 << 30)
+
+#define USBHS_EP15_T_EN (1 << 15)
+#define USBHS_EP15_R_EN (1 << 31)
+
+//UEP_TYPE
+#define USBHS_UEP_TYPE_OFFSET 0x14
+#define USBHS_EP0_T_TYP (1 << 0)
+#define USBHS_EP0_R_TYP (1 << 16)
+
+#define USBHS_EP1_T_TYP (1 << 1)
+#define USBHS_EP1_R_TYP (1 << 17)
+
+#define USBHS_EP2_T_TYP (1 << 2)
+#define USBHS_EP2_R_TYP (1 << 18)
+
+#define USBHS_EP3_T_TYP (1 << 3)
+#define USBHS_EP3_R_TYP (1 << 19)
+
+#define USBHS_EP4_T_TYP (1 << 4)
+#define USBHS_EP4_R_TYP (1 << 20)
+
+#define USBHS_EP5_T_TYP (1 << 5)
+#define USBHS_EP5_R_TYP (1 << 21)
+
+#define USBHS_EP6_T_TYP (1 << 6)
+#define USBHS_EP6_R_TYP (1 << 22)
+
+#define USBHS_EP7_T_TYP (1 << 7)
+#define USBHS_EP7_R_TYP (1 << 23)
+
+#define USBHS_EP8_T_TYP (1 << 8)
+#define USBHS_EP8_R_TYP (1 << 24)
+
+#define USBHS_EP9_T_TYP (1 << 8)
+#define USBHS_EP9_R_TYP (1 << 25)
+
+#define USBHS_EP10_T_TYP (1 << 10)
+#define USBHS_EP10_R_TYP (1 << 26)
+
+#define USBHS_EP11_T_TYP (1 << 11)
+#define USBHS_EP11_R_TYP (1 << 27)
+
+#define USBHS_EP12_T_TYP (1 << 12)
+#define USBHS_EP12_R_TYP (1 << 28)
+
+#define USBHS_EP13_T_TYP (1 << 13)
+#define USBHS_EP13_R_TYP (1 << 29)
+
+#define USBHS_EP14_T_TYP (1 << 14)
+#define USBHS_EP14_R_TYP (1 << 30)
+
+#define USBHS_EP15_T_TYP (1 << 15)
+#define USBHS_EP15_R_TYP (1 << 31)
+
+/* BUF_MOD UEP1~15 */
+#define USBHS_BUF_MOD_OFFSET 0x18
+#define USBHS_EP0_BUF_MOD (1 << 0)
+#define USBHS_EP0_ISO_BUF_MOD (1 << 16)
+
+#define USBHS_EP1_BUF_MOD (1 << 1)
+#define USBHS_EP1_ISO_BUF_MOD (1 << 17)
+
+#define USBHS_EP2_BUF_MOD (1 << 2)
+#define USBHS_EP2_ISO_BUF_MOD (1 << 18)
+
+#define USBHS_EP3_BUF_MOD (1 << 3)
+#define USBHS_EP3_ISO_BUF_MOD (1 << 19)
+
+#define USBHS_EP4_BUF_MOD (1 << 4)
+#define USBHS_EP4_ISO_BUF_MOD (1 << 20)
+
+#define USBHS_EP5_BUF_MOD (1 << 5)
+#define USBHS_EP5_ISO_BUF_MOD (1 << 21)
+
+#define USBHS_EP6_BUF_MOD (1 << 6)
+#define USBHS_EP6_ISO_BUF_MOD (1 << 22)
+
+#define USBHS_EP7_BUF_MOD (1 << 7)
+#define USBHS_EP7_ISO_BUF_MOD (1 << 23)
+
+#define USBHS_EP8_BUF_MOD (1 << 8)
+#define USBHS_EP8_ISO_BUF_MOD (1 << 24)
+
+#define USBHS_EP9_BUF_MOD (1 << 9)
+#define USBHS_EP9_ISO_BUF_MOD (1 << 25)
+
+#define USBHS_EP10_BUF_MOD (1 << 10)
+#define USBHS_EP10_ISO_BUF_MOD (1 << 26)
+
+#define USBHS_EP11_BUF_MOD (1 << 11)
+#define USBHS_EP11_ISO_BUF_MOD (1 << 27)
+
+#define USBHS_EP12_BUF_MOD (1 << 12)
+#define USBHS_EP12_ISO_BUF_MOD (1 << 28)
+
+#define USBHS_EP13_BUF_MOD (1 << 13)
+#define USBHS_EP13_ISO_BUF_MOD (1 << 29)
+
+#define USBHS_EP14_BUF_MOD (1 << 14)
+#define USBHS_EP14_ISO_BUF_MOD (1 << 30)
+
+#define USBHS_EP15_BUF_MOD (1 << 15)
+#define USBHS_EP15_ISO_BUF_MOD (1 << 31)
+//USBHS_EPn_T_EN USBHS_EPn_R_EN USBHS_EPn_BUF_MOD 锟斤拷锟斤拷锟斤拷锟斤拷UEPn_DMA为锟斤拷始锟斤拷址锟缴碉拷锟斤拷锟斤拷锟斤拷锟�
+// 0 0 x 锟剿点被锟斤拷锟矫o拷未锟矫碉拷UEPn_*_DMA锟斤拷锟斤拷锟斤拷锟斤拷
+// 1 0 0 锟斤拷锟秸o拷OUT锟斤拷锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_RX_DMA
+// 1 0 1 bUEPn_RX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA锟斤拷bUEPn_RX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA
+// 0 1 0 锟斤拷锟斤拷(IN)锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_TX_DMA锟斤拷
+// 0 1 1 bUEPn_TX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA锟斤拷bUEPn_TX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA
+
+/* USB0_DMA */
+#define USBHS_UEP0_DMA_OFFSET(n) (0x1C) // endpoint 0 DMA buffer address
+
+/* USBX_RX_DMA */
+#define USBHS_UEPx_RX_DMA_OFFSET(n) (0x1C + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_TX_DMA_OFFSET(n) (0x58 + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_MAX_LEN_OFFSET(n) (0x98 + 4 * (n)) // endpoint x DMA buffer address
+
+#define USBHS_UEPx_T_LEN_OFFSET(n) (0xD8 + 4 * (n)) // endpoint x DMA buffer address
+#define USBHS_UEPx_TX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 2) // endpoint x DMA buffer address
+#define USBHS_UEPx_RX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 3) // endpoint x DMA buffer address
+
+// UEPn_T_LEN
+#define USBHS_EP_T_LEN_MASK (0x7FF)
+
+//UEPn_TX_CTRL
+#define USBHS_EP_T_RES_MASK (3 << 0)
+#define USBHS_EP_T_RES_ACK (0 << 0)
+#define USBHS_EP_T_RES_NYET (1 << 0)
+#define USBHS_EP_T_RES_NAK (2 << 0)
+#define USBHS_EP_T_RES_STALL (3 << 0)
+
+#define USBHS_EP_T_TOG_MASK (3 << 3)
+#define USBHS_EP_T_TOG_0 (0 << 3)
+#define USBHS_EP_T_TOG_1 (1 << 3)
+#define USBHS_EP_T_TOG_2 (2 << 3)
+#define USBHS_EP_T_TOG_M (3 << 3)
+
+#define USBHS_EP_T_AUTOTOG (1 << 5)
+
+//UEPn_RX_CTRL
+#define USBHS_EP_R_RES_MASK (3 << 0)
+#define USBHS_EP_R_RES_ACK (0 << 0)
+#define USBHS_EP_R_RES_NYET (1 << 0)
+#define USBHS_EP_R_RES_NAK (2 << 0)
+#define USBHS_EP_R_RES_STALL (3 << 0)
+
+#define USBHS_EP_R_TOG_MASK (3 << 3)
+#define USBHS_EP_R_TOG_0 (0 << 3)
+#define USBHS_EP_R_TOG_1 (1 << 3)
+#define USBHS_EP_R_TOG_2 (2 << 3)
+#define USBHS_EP_R_TOG_M (3 << 3)
+
+#define USBHS_EP_R_AUTOTOG (1 << 5)
+
+#define USBHS_TOG_MATCH (1 << 6)
+
+/******************* HOST ******************/
+// USB HOST_CTRL
+#define USBHS_SEND_BUS_RESET (1 << 0)
+#define USBHS_SEND_BUS_SUSPEND (1 << 1)
+#define USBHS_SEND_BUS_RESUME (1 << 2)
+#define USBHS_REMOTE_WAKE (1 << 3)
+#define USBHS_PHY_SUSPENDM (1 << 4)
+#define USBHS_UH_SOFT_FREE (1 << 6)
+#define USBHS_SEND_SOF_EN (1 << 7)
+
+//UH_CONFIG
+#define USBHS_HOST_TX_EN (1 << 3)
+#define USBHS_HOST_RX_EN (1 << 18)
+
+// HOST_EP_TYPE
+#define USBHS_ENDP_TX_ISO (1 << 3)
+#define USBHS_ENDP_RX_ISO (1 << (16 + 2))
+
+// R32_UH_EP_PID
+#define USBHS_HOST_MASK_TOKEN (0x0f)
+#define USBHS_HOST_MASK_ENDP (0x0f << 4)
+
+//R8_UH_RX_CTRL
+#define USBHS_EP_R_RES_MASK (3 << 0)
+#define USBHS_EP_R_RES_ACK (0 << 0)
+#define USBHS_EP_R_RES_NYET (1 << 0)
+#define USBHS_EP_R_RES_NAK (2 << 0)
+#define USBHS_EP_R_RES_STALL (3 << 0)
+
+#define USBHS_UH_R_RES_NO (1 << 2)
+#define USBHS_UH_R_TOG_1 (1 << 3)
+#define USBHS_UH_R_TOG_2 (2 << 3)
+#define USBHS_UH_R_TOG_3 (3 << 3)
+#define USBHS_UH_R_TOG_AUTO (1 << 5)
+#define USBHS_UH_R_DATA_NO (1 << 6)
+//R8_UH_TX_CTRL
+#define USBHS_UH_T_RES_MASK (3 << 0)
+#define USBHS_UH_T_RES_ACK (0 << 0)
+#define USBHS_UH_T_RES_NYET (1 << 0)
+#define USBHS_UH_T_RES_NAK (2 << 0)
+#define USBHS_UH_T_RES_STALL (3 << 0)
+
+#define USBHS_UH_T_RES_NO (1 << 2)
+#define USBHS_UH_T_TOG_1 (1 << 3)
+#define USBHS_UH_T_TOG_2 (2 << 3)
+#define USBHS_UH_T_TOG_3 (3 << 3)
+#define USBHS_UH_T_TOG_AUTO (1 << 5)
+#define USBHS_UH_T_DATA_NO (1 << 6)
+
+// 00: OUT, 01:SOF, 10:IN, 11:SETUP
+#define PID_OUT 0
+#define PID_SOF 1
+#define PID_IN 2
+#define PID_SETUP 3
+
+#endif
diff --git a/src/portable/wch/ch32v307/usb_dc_usbhs.c b/src/portable/wch/ch32v307/usb_dc_usbhs.c
new file mode 100644
index 000000000..32645dc5f
--- /dev/null
+++ b/src/portable/wch/ch32v307/usb_dc_usbhs.c
@@ -0,0 +1,388 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2022 Greg Davill
+ *
+ * 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.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32VF307)
+#include "device/dcd.h"
+
+#include "usb_ch32_usbhs_reg.h"
+#include "core_riscv.h"
+
+// Max number of bi-directional endpoints including EP0
+#define EP_MAX 16
+
+typedef struct {
+ uint8_t *buffer;
+ // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
+ uint16_t total_len;
+ uint16_t queued_len;
+ uint16_t max_size;
+ bool short_packet;
+} xfer_ctl_t;
+
+#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 */
+__attribute__((aligned(4))) uint8_t setup[8]; // ep0(64)
+__attribute__((aligned(4))) uint8_t EP0_DatabufHD[64]; // ep0(64)
+
+volatile uint8_t mps_over_flag = 0;
+volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01;
+
+void dcd_init(uint8_t rhport) {
+ (void)rhport;
+
+ memset(&xfer_status, 0, sizeof(xfer_status));
+
+ // usb_dc_low_level_init();
+
+ USBHSD->HOST_CTRL = 0x00;
+ USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
+
+ USBHSD->CONTROL = 0;
+#if 1
+ USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
+#else
+ 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_DETECT_EN | USBHS_SUSPEND_EN;
+
+ /* ALL endpoint enable */
+ USBHSD->ENDP_CONFIG = 0xffffffff;
+
+ USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
+ USBHSD->ENDP_TYPE = 0x00;
+ USBHSD->BUF_MODE = 0x00;
+
+ USBHSD->UEP0_MAX_LEN = 64;
+
+ USBHSD->UEP0_DMA = (uint32_t)EP0_DatabufHD;
+
+ USBHSD->UEP0_TX_LEN = 0;
+ USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK;
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
+
+ for (int ep = 1; ep < EP_MAX; ep++) {
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
+ EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+
+ EP_RX_MAX_LEN(ep) = 512;
+ }
+
+ USBHSD->DEV_AD = 0;
+ USBHSD->CONTROL |= USBHS_DEV_PU_EN;
+}
+
+void dcd_int_enable(uint8_t rhport) {
+ (void)rhport;
+
+ NVIC_EnableIRQ(USBHS_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void)rhport;
+
+ NVIC_DisableIRQ(USBHS_IRQn);
+}
+
+void dcd_edpt_close_all(uint8_t rhport) {
+ (void)rhport;
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+ (void)dev_addr;
+
+ // Response with zlp status
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+}
+
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
+ (void)rhport;
+
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ USBHSD->DEV_AD = (uint8_t)request->wValue;
+ }
+
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK;
+ EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK;
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) {
+ (void)rhport;
+
+ uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
+ uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
+
+ TU_ASSERT(epnum < EP_MAX);
+
+ xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->max_size = tu_edpt_packet_size(desc_edpt);
+
+ if (epnum != 0) {
+ if (tu_edpt_dir(desc_edpt->bEndpointAddress) == TUSB_DIR_OUT) {
+ EP_RX_CTRL(epnum) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_ACK;
+ } else {
+ EP_TX_LEN(epnum) = 0;
+ EP_TX_CTRL(epnum) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ }
+ }
+
+ return true;
+}
+
+int usbd_ep_close(const uint8_t ep) {
+ (void)ep;
+
+ return 0;
+}
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void)rhport;
+
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ if (epnum == 0) {
+ if (dir == TUSB_DIR_OUT) {
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL;
+ } else {
+ USBHSD->UEP0_TX_LEN = 0;
+ USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL;
+ }
+ } else {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL;
+
+ } else {
+ EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_STALL;
+ }
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void)rhport;
+
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ if (epnum == 0) {
+ if (dir == TUSB_DIR_OUT) {
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
+ } else {
+ }
+ } else {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~(USBHS_EP_R_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_ACK;
+
+ } else {
+ EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK;
+ }
+ }
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
+ (void)rhport;
+ uint8_t const epnum = tu_edpt_number(ep_addr);
+ uint8_t const dir = tu_edpt_dir(ep_addr);
+
+ xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
+ xfer->buffer = buffer;
+ // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ xfer->short_packet = false;
+
+ // uint16_t num_packets = (total_bytes / xfer->max_size);
+ uint16_t short_packet_size = total_bytes % (xfer->max_size + 1);
+
+ // Zero-size packet is special case.
+ if (short_packet_size == 0 || (total_bytes == 0)) {
+ xfer->short_packet = true;
+ }
+
+ if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
+ if (!total_bytes) {
+ xfer->short_packet = true;
+ if (epnum == 0) {
+ USBHSD->UEP0_TX_LEN = 0;
+ USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
+ USBHS_Dev_Endp0_Tog ^= 1;
+ } else {
+ EP_TX_LEN(epnum) = 0;
+ EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
+ }
+ } else {
+ if (epnum == 0) {
+ xfer->queued_len += short_packet_size;
+ memcpy(&EP0_DatabufHD[0], buffer, short_packet_size);
+
+ USBHSD->UEP0_TX_LEN = short_packet_size;
+ USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
+ USBHS_Dev_Endp0_Tog ^= 1;
+ } else {
+ xfer->queued_len += short_packet_size;
+
+ EP_TX_DMA_ADDR(epnum) = (uint32_t)buffer;
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << epnum);
+ EP_TX_LEN(epnum) = short_packet_size;
+ EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
+ }
+ }
+ } else { /* TUSB_DIR_OUT */
+ if (epnum == 0) {
+ uint32_t read_count = USBHSD->RX_LEN;
+ read_count = TU_MIN(read_count, total_bytes);
+
+ if ((total_bytes == 8)) {
+ read_count = 8;
+ memcpy(buffer, &EP0_DatabufHD[0], 8);
+ } else {
+ memcpy(buffer, &EP0_DatabufHD[0], read_count);
+ }
+ } else {
+ EP_RX_DMA_ADDR(epnum) = (uint32_t)xfer->buffer;
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << epnum);
+ }
+
+ // usbd_ep_read(ep_addr, buffer, total_bytes, &ret_bytes);
+ }
+ return true;
+}
+
+
+static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size) {
+ // xfer->queued_len = xfer->total_len - remaining;
+
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t to_recv_size;
+
+ if (remaining <= xfer->max_size) {
+ // Avoid buffer overflow.
+ to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
+ } else {
+ // Room for full packet, choose recv_size based on what the microcontroller
+ // claims.
+ to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
+ }
+
+ if (to_recv_size) {
+ }
+
+ xfer->queued_len += xfer_size;
+
+ // Per USB spec, a short OUT packet (including length 0) is always
+ // indicative of the end of a transfer (at least for ctl, bulk, int).
+ xfer->short_packet = (xfer_size < xfer->max_size);
+}
+
+void dcd_int_handler(uint8_t rhport) {
+ (void)rhport;
+
+ uint32_t end_num, rx_token;
+ uint8_t intflag = 0;
+
+ intflag = USBHSD->INT_FG;
+
+ if (intflag & USBHS_TRANSFER_FLAG) {
+
+ end_num = (USBHSD->INT_ST) & MASK_UIS_ENDP;
+ rx_token = (((USBHSD->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03;
+
+ uint8_t endp = end_num | (rx_token == PID_IN ? TUSB_DIR_IN_MASK : 0);
+
+ xfer_ctl_t *xfer = XFER_CTL_BASE(end_num, tu_edpt_dir(endp));
+
+ if (rx_token == PID_OUT) {
+ uint16_t rx_len = USBHSD->RX_LEN;
+
+ receive_packet(xfer, rx_len);
+
+ if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
+ xfer->short_packet = false;
+
+ dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ }
+
+ if (end_num == 0) {
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+ }
+
+ } else if (rx_token == PID_IN) {
+ if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
+ xfer->short_packet = false;
+ xfer->total_len = 0;
+ dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+
+ EP_TX_CTRL(end_num) = (EP_TX_CTRL(end_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK;
+
+ if (end_num == 0) {
+ }
+ } else {
+ dcd_edpt_xfer(0, endp, xfer->buffer + xfer->queued_len, xfer->total_len - xfer->queued_len);
+ }
+ }
+
+ USBHSD->INT_FG = USBHS_TRANSFER_FLAG; /* Clear flag */
+ } else if (intflag & USBHS_SETUP_FLAG) {
+ USBHS_Dev_Endp0_Tog = 1;
+ dcd_event_setup_received(0, EP0_DatabufHD, true);
+
+ USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
+ } else if (intflag & USBHS_DETECT_FLAG) {
+ USBHS_Dev_Endp0_Tog = 1;
+
+ xfer_status[0][TUSB_DIR_OUT].max_size = 64;
+ xfer_status[0][TUSB_DIR_IN].max_size = 64;
+
+ dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
+
+ USBHSD->DEV_AD = 0;
+ USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+
+ USBHSD->INT_FG = USBHS_DETECT_FLAG; /* Clear flag */
+ } else if (intflag & USBHS_SUSPEND_FLAG) {
+ dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPEND };
+ dcd_event_handler(&event, true);
+
+ USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
+ }
+}
+
+#endif \ No newline at end of file
diff --git a/src/tusb_option.h b/src/tusb_option.h
index bd87a953c..ffeec2241 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -149,6 +149,9 @@
// Allwinner
#define OPT_MCU_F1C100S 2100 ///< Allwinner F1C100s family
+// WCH
+#define OPT_MCU_CH32VF307 2200 ///< WCH CH32V307 config
+
// Helper to check if configured MCU is one of listed
// Apply _TU_CHECK_MCU with || as separator to list of input
#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m)