summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorMatthew Tran <[email protected]>2023-11-19 18:26:40 -0800
committerhathach <[email protected]>2024-05-15 20:01:00 +0700
commitdb60fa1c63ae58c205e43e144253dab6815bb2d1 (patch)
treef15653fde2d8eb2e2c43eee8eec0bc687a068720 /hw
parentcf532d14792411fd40ad3433fe0ce9959887ef4b (diff)
add CH32V20x USB OTG/FS driver
Diffstat (limited to 'hw')
-rw-r--r--hw/bsp/ch32v20x/boards/nanoch32v203/board.h17
-rw-r--r--hw/bsp/ch32v20x/boards/nanoch32v203/board.mk5
-rw-r--r--hw/bsp/ch32v20x/ch32v20x_conf.h36
-rw-r--r--hw/bsp/ch32v20x/ch32v20x_it.h15
-rw-r--r--hw/bsp/ch32v20x/core_riscv.h572
-rw-r--r--hw/bsp/ch32v20x/family.c82
-rw-r--r--hw/bsp/ch32v20x/family.mk50
-rw-r--r--hw/bsp/ch32v20x/system_ch32v20x.c976
-rw-r--r--hw/bsp/ch32v20x/system_ch32v20x.h29
-rw-r--r--hw/bsp/ch32v20x/wch-riscv.cfg18
-rw-r--r--hw/bsp/ch32v307/family.mk5
-rw-r--r--hw/bsp/fomu/family.mk4
-rw-r--r--hw/bsp/gd32vf103/family.mk5
13 files changed, 1814 insertions, 0 deletions
diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.h b/hw/bsp/ch32v20x/boards/nanoch32v203/board.h
new file mode 100644
index 000000000..c8d28d90f
--- /dev/null
+++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.h
@@ -0,0 +1,17 @@
+#ifndef BOARD_H_
+#define BOARD_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LED_PORT GPIOA
+#define LED_PIN GPIO_Pin_15
+#define LED_STATE_ON 0
+#define LED_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk b/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk
new file mode 100644
index 000000000..75dc05457
--- /dev/null
+++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk
@@ -0,0 +1,5 @@
+CFLAGS += \
+ -DCH32V20x_D6
+
+SRC_S += \
+ $(CH32V20X_SDK_SRC)/Startup/startup_ch32v20x_D6.S
diff --git a/hw/bsp/ch32v20x/ch32v20x_conf.h b/hw/bsp/ch32v20x/ch32v20x_conf.h
new file mode 100644
index 000000000..949297fe6
--- /dev/null
+++ b/hw/bsp/ch32v20x/ch32v20x_conf.h
@@ -0,0 +1,36 @@
+/********************************** (C) COPYRIGHT *******************************
+ * File Name : ch32v20x_conf.h
+ * Author : WCH
+ * Version : V1.0.0
+ * Date : 2021/06/06
+ * Description : Library configuration file.
+*********************************************************************************
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* Attention: This software (modified or not) and binary are used for
+* microcontroller manufactured by Nanjing Qinheng Microelectronics.
+*******************************************************************************/
+#ifndef __CH32V20x_CONF_H
+#define __CH32V20x_CONF_H
+
+#include "ch32v20x_adc.h"
+#include "ch32v20x_bkp.h"
+#include "ch32v20x_can.h"
+#include "ch32v20x_crc.h"
+#include "ch32v20x_dbgmcu.h"
+#include "ch32v20x_dma.h"
+#include "ch32v20x_exti.h"
+#include "ch32v20x_flash.h"
+#include "ch32v20x_gpio.h"
+#include "ch32v20x_i2c.h"
+#include "ch32v20x_iwdg.h"
+#include "ch32v20x_pwr.h"
+#include "ch32v20x_rcc.h"
+#include "ch32v20x_rtc.h"
+#include "ch32v20x_spi.h"
+#include "ch32v20x_tim.h"
+#include "ch32v20x_usart.h"
+#include "ch32v20x_wwdg.h"
+#include "ch32v20x_it.h"
+#include "ch32v20x_misc.h"
+
+#endif /* __CH32V20x_CONF_H */
diff --git a/hw/bsp/ch32v20x/ch32v20x_it.h b/hw/bsp/ch32v20x/ch32v20x_it.h
new file mode 100644
index 000000000..e49c61ae2
--- /dev/null
+++ b/hw/bsp/ch32v20x/ch32v20x_it.h
@@ -0,0 +1,15 @@
+/********************************** (C) COPYRIGHT *******************************
+ * File Name : ch32v20x_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.
+* Attention: This software (modified or not) and binary are used for
+* microcontroller manufactured by Nanjing Qinheng Microelectronics.
+*******************************************************************************/
+#ifndef __CH32V20x_IT_H
+#define __CH32V20x_IT_H
+
+#endif /* __CH32V20x_IT_H */
diff --git a/hw/bsp/ch32v20x/core_riscv.h b/hw/bsp/ch32v20x/core_riscv.h
new file mode 100644
index 000000000..be1b52a6c
--- /dev/null
+++ b/hw/bsp/ch32v20x/core_riscv.h
@@ -0,0 +1,572 @@
+/********************************** (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 CH32V20x
+*********************************************************************************
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* Attention: This software (modified or not) and binary are used for
+* microcontroller manufactured by Nanjing Qinheng Microelectronics.
+*******************************************************************************/
+#ifndef __CORE_RISCV_H__
+#define __CORE_RISCV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 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 {NoREADY = 0, READY = !NoREADY} 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;
+ __IO 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 uint32_t CTLR;
+ __IO uint32_t SR;
+ __IO uint64_t CNT;
+ __IO uint64_t 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
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __enable_irq(void)
+{
+ __asm volatile ("csrw 0x800, %0" : : "r" (0x6088) );
+}
+
+/*********************************************************************
+ * @fn __disable_irq
+ *
+ * @brief Disable Global Interrupt
+ *
+ * @return none
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __disable_irq(void)
+{
+ __asm volatile ("csrw 0x800, %0" : : "r" (0x6000) );
+}
+
+/*********************************************************************
+ * @fn __NOP
+ *
+ * @brief nop
+ *
+ * @return none
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __NOP(void)
+{
+ __asm volatile ("nop");
+}
+
+/*********************************************************************
+ * @fn NVIC_EnableIRQ
+ *
+ * @brief Disable Interrupt
+ *
+ * @param IRQn - Interrupt Numbers
+ *
+ * @return none
+ */
+__attribute__( ( always_inline ) ) 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
+ */
+__attribute__( ( always_inline ) ) 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 Pending Enable
+ * 0 - Interrupt Pending Disable
+ */
+__attribute__( ( always_inline ) ) 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
+ */
+__attribute__( ( always_inline ) ) 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
+ */
+__attribute__( ( always_inline ) ) 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
+ */
+__attribute__( ( always_inline ) ) 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
+ */
+__attribute__( ( always_inline ) ) 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
+ * bit[6:5] - Subpriority
+ *
+ * @return none
+ */
+__attribute__( ( always_inline ) ) 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 _SEV
+ *
+ * @brief Set Event
+ *
+ * @return none
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void _SEV(void)
+{
+ uint32_t t;
+
+ t = NVIC->SCTLR;
+ NVIC->SCTLR |= (1<<3)|(1<<5);
+ NVIC->SCTLR = (NVIC->SCTLR & ~(1<<5)) | ( t & (1<<5));
+}
+
+/*********************************************************************
+ * @fn _WFE
+ *
+ * @brief Wait for Events
+ *
+ * @return none
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void _WFE(void)
+{
+ NVIC->SCTLR |= (1<<3);
+ asm volatile ("wfi");
+}
+
+/*********************************************************************
+ * @fn __WFE
+ *
+ * @brief Wait for Events
+ *
+ * @return none
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFE(void)
+{
+ _SEV();
+ _WFE();
+ _WFE();
+}
+
+/*********************************************************************
+ * @fn SetVTFIRQ
+ *
+ * @brief Set VTF Interrupt
+ *
+ * @param addr - VTF interrupt service function base address.
+ * IRQn - Interrupt Numbers
+ * num - VTF Interrupt Numbers
+ * NewState - DISABLE or ENABLE
+ *
+ * @return none
+ */
+__attribute__( ( always_inline ) ) 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
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE void NVIC_SystemReset(void)
+{
+ NVIC->CFGR = NVIC_KEY3|(1<<7);
+}
+
+/*********************************************************************
+ * @fn __AMOADD_W
+ *
+ * @brief Atomic Add with 32bit value
+ * Atomically ADD 32bit value with value in memory using amoadd.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * value - value to be ADDed
+ *
+ * @return return memory value + add value
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOADD_W(volatile int32_t *addr, int32_t value)
+{
+ int32_t result;
+
+ __asm volatile ("amoadd.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(value) : "memory");
+ return *addr;
+}
+
+/*********************************************************************
+ * @fn __AMOAND_W
+ *
+ * @brief Atomic And with 32bit value
+ * Atomically AND 32bit value with value in memory using amoand.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * value - value to be ANDed
+ *
+ * @return return memory value & and value
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOAND_W(volatile int32_t *addr, int32_t value)
+{
+ int32_t result;
+
+ __asm volatile ("amoand.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(value) : "memory");
+ return *addr;
+}
+
+/*********************************************************************
+ * @fn __AMOMAX_W
+ *
+ * @brief Atomic signed MAX with 32bit value
+ * Atomically signed max compare 32bit value with value in memory using amomax.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * value - value to be compared
+ *
+ * @return the bigger value
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOMAX_W(volatile int32_t *addr, int32_t value)
+{
+ int32_t result;
+
+ __asm volatile ("amomax.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(value) : "memory");
+ return *addr;
+}
+
+/*********************************************************************
+ * @fn __AMOMAXU_W
+ *
+ * @brief Atomic unsigned MAX with 32bit value
+ * Atomically unsigned max compare 32bit value with value in memory using amomaxu.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * value - value to be compared
+ *
+ * @return return the bigger value
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t __AMOMAXU_W(volatile uint32_t *addr, uint32_t value)
+{
+ uint32_t result;
+
+ __asm volatile ("amomaxu.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(value) : "memory");
+ return *addr;
+}
+
+/*********************************************************************
+ * @fn __AMOMIN_W
+ *
+ * @brief Atomic signed MIN with 32bit value
+ * Atomically signed min compare 32bit value with value in memory using amomin.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * value - value to be compared
+ *
+ * @return the smaller value
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOMIN_W(volatile int32_t *addr, int32_t value)
+{
+ int32_t result;
+
+ __asm volatile ("amomin.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(value) : "memory");
+ return *addr;
+}
+
+/*********************************************************************
+ * @fn __AMOMINU_W
+ *
+ * @brief Atomic unsigned MIN with 32bit value
+ * Atomically unsigned min compare 32bit value with value in memory using amominu.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * value - value to be compared
+ *
+ * @return the smaller value
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t __AMOMINU_W(volatile uint32_t *addr, uint32_t value)
+{
+ uint32_t result;
+
+ __asm volatile ("amominu.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(value) : "memory");
+ return *addr;
+}
+
+/*********************************************************************
+ * @fn __AMOOR_W
+ *
+ * @brief Atomic OR with 32bit value
+ * Atomically OR 32bit value with value in memory using amoor.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * value - value to be ORed
+ *
+ * @return return memory value | and value
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOOR_W(volatile int32_t *addr, int32_t value)
+{
+ int32_t result;
+
+ __asm volatile ("amoor.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(value) : "memory");
+ return *addr;
+}
+
+/*********************************************************************
+ * @fn __AMOSWAP_W
+ *
+ * @brief Atomically swap new 32bit value into memory using amoswap.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * newval - New value to be stored into the address
+ *
+ * @return return the original value in memory
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t __AMOSWAP_W(volatile uint32_t *addr, uint32_t newval)
+{
+ uint32_t result;
+
+ __asm volatile ("amoswap.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(newval) : "memory");
+ return result;
+}
+
+/*********************************************************************
+ * @fn __AMOXOR_W
+ *
+ * @brief Atomic XOR with 32bit value
+ * Atomically XOR 32bit value with value in memory using amoxor.d.
+ *
+ * @param addr - Address pointer to data, address need to be 4byte aligned
+ * value - value to be XORed
+ *
+ * @return return memory value ^ and value
+ */
+__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOXOR_W(volatile int32_t *addr, int32_t value)
+{
+ int32_t result;
+
+ __asm volatile ("amoxor.w %0, %2, %1" : \
+ "=r"(result), "+A"(*addr) : "r"(value) : "memory");
+ return *addr;
+}
+
+/* Core_Exported_Functions */
+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_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_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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c
new file mode 100644
index 000000000..247dacde6
--- /dev/null
+++ b/hw/bsp/ch32v20x/family.c
@@ -0,0 +1,82 @@
+#include <stdio.h>
+#include "ch32v20x.h"
+#include "bsp/board_api.h"
+#include "board.h"
+
+__attribute__((interrupt))
+void USBHD_IRQHandler(void) {
+ tud_int_handler(0);
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+
+volatile uint32_t system_ticks = 0;
+
+__attribute__((interrupt))
+void SysTick_Handler(void) {
+ SysTick->SR = 0;
+ system_ticks++;
+}
+
+uint32_t SysTick_Config(uint32_t ticks) {
+ NVIC_EnableIRQ(SysTicK_IRQn);
+ SysTick->CTLR = 0;
+ SysTick->SR = 0;
+ SysTick->CNT = 0;
+ SysTick->CMP = ticks-1;
+ SysTick->CTLR = 0xF;
+ return 0;
+}
+
+uint32_t board_millis(void) {
+ return system_ticks;
+}
+
+#endif
+
+void board_init(void) {
+ __disable_irq();
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+ SysTick_Config(SystemCoreClock / 1000);
+#endif
+
+ switch (SystemCoreClock) {
+ case 48000000: RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div1); break;
+ case 96000000: RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div2); break;
+ case 144000000: RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div3); break;
+ default: TU_ASSERT(0,); break;
+ }
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_OTG_FS, ENABLE);
+
+ LED_CLOCK_EN();
+ GPIO_InitTypeDef GPIO_InitStructure = {
+ .GPIO_Pin = LED_PIN,
+ .GPIO_Mode = GPIO_Mode_Out_OD,
+ .GPIO_Speed = GPIO_Speed_50MHz,
+ };
+ GPIO_Init(LED_PORT, &GPIO_InitStructure);
+
+ __enable_irq();
+ board_delay(2);
+}
+
+void board_led_write(bool state) {
+ GPIO_WriteBit(LED_PORT, LED_PIN, 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) {
+ (void) buf;
+ (void) len;
+ return len;
+}
diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk
new file mode 100644
index 000000000..2d94f19fb
--- /dev/null
+++ b/hw/bsp/ch32v20x/family.mk
@@ -0,0 +1,50 @@
+# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
+CROSS_COMPILE ?= riscv-none-elf-
+
+# Submodules
+CH32V20X_SDK = hw/mcu/wch/ch32v20x
+DEPS_SUBMODULES += $(CH32V20X_SDK)
+
+# WCH-SDK paths
+CH32V20X_SDK_SRC = $(CH32V20X_SDK)/EVT/EXAM/SRC
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+CFLAGS += \
+ -march=rv32imac_zicsr \
+ -mabi=ilp32 \
+ -mcmodel=medany \
+ -ffunction-sections \
+ -fdata-sections \
+ -ffat-lto-objects \
+ -flto \
+ -nostdlib -nostartfiles \
+ -DCFG_TUSB_MCU=OPT_MCU_CH32V20X \
+ -DBOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED \
+
+LDFLAGS_GCC += \
+ -Wl,--gc-sections \
+ -specs=nosys.specs \
+ -specs=nano.specs \
+
+LD_FILE = $(CH32V20X_SDK_SRC)/Ld/Link.ld
+
+SRC_C += \
+ src/portable/wch/dcd_ch32_usbfs.c \
+ $(CH32V20X_SDK_SRC)/Core/core_riscv.c \
+ $(CH32V20X_SDK_SRC)/Peripheral/src/ch32v20x_gpio.c \
+ $(CH32V20X_SDK_SRC)/Peripheral/src/ch32v20x_misc.c \
+ $(CH32V20X_SDK_SRC)/Peripheral/src/ch32v20x_rcc.c \
+ $(CH32V20X_SDK_SRC)/Peripheral/src/ch32v20x_usart.c \
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/$(CH32V20X_SDK_SRC)/Peripheral/inc \
+
+FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V
+
+# wch-link is not supported yet in official openOCD yet. We need to either use
+# 1. download openocd as part of mounriver studio http://www.mounriver.com/download or
+# 2. compiled from modified source https://github.com/dragonlock2/miscboards/blob/main/wch/SDK/riscv-openocd.tar.xz
+flash: $(BUILD)/$(PROJECT).elf
+ openocd -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "flash write_image $<" -c reset -c exit
diff --git a/hw/bsp/ch32v20x/system_ch32v20x.c b/hw/bsp/ch32v20x/system_ch32v20x.c
new file mode 100644
index 000000000..588f3165a
--- /dev/null
+++ b/hw/bsp/ch32v20x/system_ch32v20x.c
@@ -0,0 +1,976 @@
+/********************************** (C) COPYRIGHT *******************************
+ * File Name : system_ch32v20x.c
+ * Author : WCH
+ * Version : V1.0.0
+ * Date : 2021/06/06
+ * Description : CH32V20x Device Peripheral Access Layer System Source File.
+ * For HSE = 32Mhz (CH32V208x/CH32V203RBT6)
+ * For HSE = 8Mhz (other CH32V203x)
+*********************************************************************************
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* Attention: This software (modified or not) and binary are used for
+* microcontroller manufactured by Nanjing Qinheng Microelectronics.
+*******************************************************************************/
+#include "ch32v20x.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_48MHz_HSE 48000000
+//#define SYSCLK_FREQ_56MHz_HSE 56000000
+//#define SYSCLK_FREQ_72MHz_HSE 72000000
+#define SYSCLK_FREQ_96MHz_HSE 96000000
+//#define SYSCLK_FREQ_120MHz_HSE 120000000
+//#define SYSCLK_FREQ_144MHz_HSE 144000000
+//#define SYSCLK_FREQ_HSI HSI_VALUE
+//#define SYSCLK_FREQ_48MHz_HSI 48000000
+//#define SYSCLK_FREQ_56MHz_HSI 56000000
+//#define SYSCLK_FREQ_72MHz_HSI 72000000
+//#define SYSCLK_FREQ_96MHz_HSI 96000000
+//#define SYSCLK_FREQ_120MHz_HSI 120000000
+//#define SYSCLK_FREQ_144MHz_HSI 144000000
+
+/* Clock Definitions */
+#ifdef SYSCLK_FREQ_HSE
+uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_48MHz_HSE
+uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSE; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_56MHz_HSE
+uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSE; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_72MHz_HSE
+uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSE; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_96MHz_HSE
+uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSE; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_120MHz_HSE
+uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSE; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_144MHz_HSE
+uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSE; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_48MHz_HSI
+uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSI; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_56MHz_HSI
+uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSI; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_72MHz_HSI
+uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSI; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_96MHz_HSI
+uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSI; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_120MHz_HSI
+uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSI; /* System Clock Frequency (Core Clock) */
+#elif defined SYSCLK_FREQ_144MHz_HSI
+uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSI; /* System Clock Frequency (Core Clock) */
+#else
+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_48MHz_HSE
+static void SetSysClockTo48_HSE( void );
+#elif defined SYSCLK_FREQ_56MHz_HSE
+static void SetSysClockTo56_HSE( void );
+#elif defined SYSCLK_FREQ_72MHz_HSE
+static void SetSysClockTo72_HSE( void );
+#elif defined SYSCLK_FREQ_96MHz_HSE
+static void SetSysClockTo96_HSE( void );
+#elif defined SYSCLK_FREQ_120MHz_HSE
+static void SetSysClockTo120_HSE( void );
+#elif defined SYSCLK_FREQ_144MHz_HSE
+static void SetSysClockTo144_HSE( void );
+#elif defined SYSCLK_FREQ_48MHz_HSI
+static void SetSysClockTo48_HSI( void );
+#elif defined SYSCLK_FREQ_56MHz_HSI
+static void SetSysClockTo56_HSI( void );
+#elif defined SYSCLK_FREQ_72MHz_HSI
+static void SetSysClockTo72_HSI( void );
+#elif defined SYSCLK_FREQ_96MHz_HSI
+static void SetSysClockTo96_HSI( void );
+#elif defined SYSCLK_FREQ_120MHz_HSI
+static void SetSysClockTo120_HSI( void );
+#elif defined SYSCLK_FREQ_144MHz_HSI
+static void SetSysClockTo144_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)0xF8FF0000;
+ RCC->CTLR &= (uint32_t)0xFEF6FFFF;
+ RCC->CTLR &= (uint32_t)0xFFFBFFFF;
+ RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
+ RCC->INTR = 0x009F0000;
+ 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;
+
+ if(pllmull == 17) pllmull = 18;
+
+ if (pllsource == 0x00)
+ {
+ if(EXTEN->EXTEN_CTR & EXTEN_PLL_HSI_PRE){
+ SystemCoreClock = HSI_VALUE * pllmull;
+ }
+ else{
+ SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
+ }
+ }
+ else
+ {
+#if defined (CH32V20x_D8W)
+ if((RCC->CFGR0 & (3<<22)) == (3<<22))
+ {
+ SystemCoreClock = ((HSE_VALUE>>1)) * pllmull;
+ }
+ else
+#endif
+ if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
+ {
+#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
+ SystemCoreClock = ((HSE_VALUE>>2) >> 1) * pllmull;
+#else
+ SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
+#endif
+ }
+ else
+ {
+#if defined (CH32V20x_D8) || defined (CH32V20x_D8W)
+ SystemCoreClock = (HSE_VALUE>>2) * pllmull;
+#else
+ SystemCoreClock = HSE_VALUE * pllmull;
+#endif
+ }
+ }
+
+ 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_48MHz_HSE
+ SetSysClockTo48_HSE();
+#elif defined SYSCLK_FREQ_56MHz_HSE
+ SetSysClockTo56_HSE();
+#elif defined SYSCLK_FREQ_72MHz_HSE
+ SetSysClockTo72_HSE();
+#elif defined SYSCLK_FREQ_96MHz_HSE
+ SetSysClockTo96_HSE();
+#elif defined SYSCLK_FREQ_120MHz_HSE
+ SetSysClockTo120_HSE();
+#elif defined SYSCLK_FREQ_144MHz_HSE
+ SetSysClockTo144_HSE();
+#elif defined SYSCLK_FREQ_48MHz_HSI
+ SetSysClockTo48_HSI();
+#elif defined SYSCLK_FREQ_56MHz_HSI
+ SetSysClockTo56_HSI();
+#elif defined SYSCLK_FREQ_72MHz_HSI
+ SetSysClockTo72_HSI();
+#elif defined SYSCLK_FREQ_96MHz_HSI
+ SetSysClockTo96_HSI();
+#elif defined SYSCLK_FREQ_120MHz_HSI
+ SetSysClockTo120_HSI();
+#elif defined SYSCLK_FREQ_144MHz_HSI
+ SetSysClockTo144_HSI();
+
+#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
+ * CH32V20x_D6 (HSE=8MHZ)
+ * CH32V20x_D8 (HSE=32MHZ)
+ * CH32V20x_D8W (HSE=32MHZ)
+ */
+ 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_48MHz_HSE
+
+/*********************************************************************
+ * @fn SetSysClockTo48_HSE
+ *
+ * @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo48_HSE(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;
+
+ /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 6 = 48 MHz (HSE=8MHZ)
+ * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ)
+ * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ)
+ */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6);
+
+ /* 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_HSE
+
+/*********************************************************************
+ * @fn SetSysClockTo56_HSE
+ *
+ * @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo56_HSE(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;
+
+ /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 7 = 56 MHz (HSE=8MHZ)
+ * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ)
+ * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ)
+ */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7);
+
+ /* 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_HSE
+
+/*********************************************************************
+ * @fn SetSysClockTo72_HSE
+ *
+ * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo72_HSE(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;
+
+ /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 9 = 72 MHz (HSE=8MHZ)
+ * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ)
+ * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ)
+ */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9);
+
+ /* 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_HSE
+
+/*********************************************************************
+ * @fn SetSysClockTo96_HSE
+ *
+ * @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo96_HSE(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;
+
+ /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 12 = 96 MHz (HSE=8MHZ)
+ * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ)
+ * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ)
+ */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12);
+
+ /* 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_HSE
+
+/*********************************************************************
+ * @fn SetSysClockTo120_HSE
+ *
+ * @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo120_HSE(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)
+ {
+#if defined (CH32V20x_D8W)
+ RCC->CFGR0 |= (uint32_t)(3<<22);
+ /* HCLK = SYSCLK/2 */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2;
+#else
+ /* HCLK = SYSCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
+#endif
+ /* PCLK2 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
+ /* PCLK1 = HCLK */
+ RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
+
+ /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 15 = 120 MHz (HSE=8MHZ)
+ * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 15 = 120 MHz (HSE=32MHZ)
+ * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/2 * 15 = 240 MHz (HSE=32MHZ)
+ */
+ RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15);
+
+ /* 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_HSE
+
+/*********************************************************************
+ * @fn SetSysClockTo144_HSE
+ *
+ * @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo144_HSE(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;
+
+ /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 18 = 144 MHz (HSE=8MHZ)
+ * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ)
+ * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ)
+ */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18);
+
+ /* 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_HSI
+
+/*********************************************************************
+ * @fn SetSysClockTo48_HSI
+ *
+ * @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo48_HSI(void)
+{
+ EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
+
+ /* 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 = HSI * 6 = 48 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL6);
+
+ /* 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)
+ {
+ }
+}
+
+#elif defined SYSCLK_FREQ_56MHz_HSI
+
+/*********************************************************************
+ * @fn SetSysClockTo56_HSI
+ *
+ * @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo56_HSI(void)
+{
+ EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
+
+ /* 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 = HSI * 7 = 48 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL7);
+
+ /* 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)
+ {
+ }
+}
+
+#elif defined SYSCLK_FREQ_72MHz_HSI
+
+/*********************************************************************
+ * @fn SetSysClockTo72_HSI
+ *
+ * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo72_HSI(void)
+{
+ EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
+
+ /* 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 = HSI * 9 = 72 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL9);
+
+ /* 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)
+ {
+ }
+}
+
+#elif defined SYSCLK_FREQ_96MHz_HSI
+
+/*********************************************************************
+ * @fn SetSysClockTo96_HSI
+ *
+ * @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo96_HSI(void)
+{
+ EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
+
+ /* 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 = HSI * 12 = 96 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL12);
+
+ /* 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)
+ {
+ }
+}
+
+#elif defined SYSCLK_FREQ_120MHz_HSI
+
+/*********************************************************************
+ * @fn SetSysClockTo120_HSI
+ *
+ * @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo120_HSI(void)
+{
+ EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
+
+ /* 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 = HSI * 15 = 120 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
+ RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL15);
+
+ /* 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)
+ {
+ }
+}
+#elif defined SYSCLK_FREQ_144MHz_HSI
+
+/*********************************************************************
+ * @fn SetSysClockTo144_HSI
+ *
+ * @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
+ *
+ * @return none
+ */
+static void SetSysClockTo144_HSI(void)
+{
+ EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE;
+
+ /* 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 = HSI * 18 = 144 MHz */
+ RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
+
+ RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL18);
+
+ /* 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)
+ {
+ }
+}
+
+#endif
diff --git a/hw/bsp/ch32v20x/system_ch32v20x.h b/hw/bsp/ch32v20x/system_ch32v20x.h
new file mode 100644
index 000000000..eec7ccb15
--- /dev/null
+++ b/hw/bsp/ch32v20x/system_ch32v20x.h
@@ -0,0 +1,29 @@
+/********************************** (C) COPYRIGHT *******************************
+ * File Name : system_ch32v20x.h
+ * Author : WCH
+ * Version : V1.0.0
+ * Date : 2021/06/06
+ * Description : CH32V20x Device Peripheral Access Layer System Header File.
+*********************************************************************************
+* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
+* Attention: This software (modified or not) and binary are used for
+* microcontroller manufactured by Nanjing Qinheng Microelectronics.
+*******************************************************************************/
+#ifndef __SYSTEM_ch32v20x_H
+#define __SYSTEM_ch32v20x_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 /*__CH32V20x_SYSTEM_H */
diff --git a/hw/bsp/ch32v20x/wch-riscv.cfg b/hw/bsp/ch32v20x/wch-riscv.cfg
new file mode 100644
index 000000000..56a18d77e
--- /dev/null
+++ b/hw/bsp/ch32v20x/wch-riscv.cfg
@@ -0,0 +1,18 @@
+#interface wlink
+adapter driver wlinke
+adapter speed 6000
+transport select sdi
+
+wlink_set_address 0x00000000
+set _CHIPNAME wch_riscv
+sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001
+
+set _TARGETNAME $_CHIPNAME.cpu
+
+target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME
+$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 10000 -work-area-backup 1
+set _FLASHNAME $_CHIPNAME.flash
+
+flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0
+
+echo "Ready for Remote Connections"
diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk
index 003b90539..7232bfa08 100644
--- a/hw/bsp/ch32v307/family.mk
+++ b/hw/bsp/ch32v307/family.mk
@@ -4,6 +4,9 @@
# Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack
CROSS_COMPILE ?= riscv-none-embed-
+# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
+#CROSS_COMPILE ?= riscv-none-elf-
+
# Submodules
CH32V307_SDK = hw/mcu/wch/ch32v307
@@ -13,6 +16,8 @@ CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= rv32imac-ilp32
+# -march=rv32imac_zicsr
+
CFLAGS += \
-flto \
-msmall-data-limit=8 \
diff --git a/hw/bsp/fomu/family.mk b/hw/bsp/fomu/family.mk
index d4b6eaea6..78f20d7db 100644
--- a/hw/bsp/fomu/family.mk
+++ b/hw/bsp/fomu/family.mk
@@ -1,6 +1,10 @@
# Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack
CROSS_COMPILE = riscv-none-embed-
+# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
+# CROSS_COMPILE = riscv-none-elf-
+# -march=rv32i_zicsr
+
CPU_CORE ?= rv32i-ilp32
CFLAGS += \
diff --git a/hw/bsp/gd32vf103/family.mk b/hw/bsp/gd32vf103/family.mk
index 28e48a6b5..646564eae 100644
--- a/hw/bsp/gd32vf103/family.mk
+++ b/hw/bsp/gd32vf103/family.mk
@@ -7,6 +7,9 @@
# Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack
CROSS_COMPILE ?= riscv-none-embed-
+# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
+# CROSS_COMPILE ?= riscv-none-elf-
+
# Submodules
NUCLEI_SDK = hw/mcu/gd/nuclei-sdk
@@ -19,6 +22,8 @@ STARTUP_ASM = $(GD32VF103_SDK_SOC)/Common/Source/GCC
include $(TOP)/$(BOARD_PATH)/board.mk
CPU_CORE ?= rv32imac-ilp32
+# -march=rv32imac_zicsr
+
CFLAGS += \
-mcmodel=medlow \
-mstrict-align \