mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-17 05:32:55 +08:00
add CH32V20x USB OTG/FS driver
This commit is contained in:
parent
cf532d1479
commit
db60fa1c63
1
.gitignore
vendored
1
.gitignore
vendored
@ -82,6 +82,7 @@ hw/mcu/st/stm32l5xx_hal_driver
|
||||
hw/mcu/st/stm32u5xx_hal_driver
|
||||
hw/mcu/st/stm32wbxx_hal_driver
|
||||
hw/mcu/ti
|
||||
hw/mcu/wch/ch32v20x
|
||||
hw/mcu/wch/ch32v307
|
||||
hw/mcu/wch/ch32f20x
|
||||
lib/CMSIS_5
|
||||
|
@ -157,7 +157,7 @@ Following CPUs are supported, check out `Supported Devices`_ for comprehensive l
|
||||
+--------------+------------------------------------------------------------+
|
||||
| ValentyUSB | eptri |
|
||||
+--------------+------------------------------------------------------------+
|
||||
| WCH | CH32F20x, CH32V307, |
|
||||
| WCH | CH32F20x, CH32V20x, CH32V307 |
|
||||
+--------------+------------------------------------------------------------+
|
||||
|
||||
License
|
||||
|
@ -55,6 +55,7 @@ hw/mcu/st/stm32u5xx_hal_driver https://github.com/STMicroelectronics/
|
||||
hw/mcu/st/stm32wbxx_hal_driver https://github.com/STMicroelectronics/stm32wbxx_hal_driver.git 2c5f06638be516c1b772f768456ba637f077bac8 stm32wb
|
||||
hw/mcu/ti https://github.com/hathach/ti_driver.git 143ed6cc20a7615d042b03b21e070197d473e6e5 msp430 msp432e4 tm4c123
|
||||
hw/mcu/wch/ch32f20x https://github.com/openwch/ch32f20x.git 77c4095087e5ed2c548ec9058e655d0b8757663b ch32f20x
|
||||
hw/mcu/wch/ch32v20x https://github.com/openwch/ch32v20x.git de6d68c654340d7f27b00cebbfc9aa2740a1abc2 ch32v20x
|
||||
hw/mcu/wch/ch32v307 https://github.com/openwch/ch32v307.git 17761f5cf9dbbf2dcf665b7c04934188add20082 ch32v307
|
||||
lib/CMSIS_5 https://github.com/ARM-software/CMSIS_5.git 20285262657d1b482d132d20d755c8c330d55c1f imxrt kinetis_k32l2 kinetis_kl lpc51 lpc54 lpc55 mcx mm32 msp432e4 nrf ra saml2xstm32f0 stm32f1 stm32f2 stm32f3 stm32f4 stm32f7 stm32g0 stm32g4 stm32h7 stm32l0 stm32l1 stm32l4 stm32l5 stm32u5 stm32wb
|
||||
lib/FreeRTOS-Kernel https://github.com/FreeRTOS/FreeRTOS-Kernel.git 4ff01a7a4a51f53b44496aefee1e3c0071b7b173 all
|
||||
|
@ -128,9 +128,9 @@ Supported MCUs
|
||||
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
|
||||
| ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | |
|
||||
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
|
||||
| WCH | CH32V307 | ✔ | | ✔ | ch32v307 | |
|
||||
| +-----------------------+--------+------+-----------+-------------------+--------------+
|
||||
| | CH32F20x | ✔ | | ✔ | ch32f205 | |
|
||||
| WCH | CH32F20x | ✔ | | ✔ | ch32f205 | |
|
||||
| | CH32V20x | ✔ | | ✖ | ch32v20x | |
|
||||
| | CH32V307 | ✔ | | ✔ | ch32v307 | |
|
||||
+--------------+-----------------------+--------+------+-----------+-------------------+--------------+
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
mcu:CH32V20X
|
||||
mcu:CH32V307
|
||||
mcu:CXD56
|
||||
mcu:F1C100S
|
||||
|
@ -1,3 +1,4 @@
|
||||
mcu:CH32V20X
|
||||
mcu:CH32V307
|
||||
mcu:CXD56
|
||||
mcu:F1C100S
|
||||
|
@ -1,3 +1,4 @@
|
||||
mcu:CH32V20X
|
||||
mcu:SAMD11
|
||||
mcu:MKL25ZXX
|
||||
family:espressif
|
||||
|
@ -1,3 +1,4 @@
|
||||
mcu:CH32V20X
|
||||
mcu:MSP430x5xx
|
||||
mcu:NUC121
|
||||
mcu:SAMD11
|
||||
|
17
hw/bsp/ch32v20x/boards/nanoch32v203/board.h
Normal file
17
hw/bsp/ch32v20x/boards/nanoch32v203/board.h
Normal file
@ -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
|
5
hw/bsp/ch32v20x/boards/nanoch32v203/board.mk
Normal file
5
hw/bsp/ch32v20x/boards/nanoch32v203/board.mk
Normal file
@ -0,0 +1,5 @@
|
||||
CFLAGS += \
|
||||
-DCH32V20x_D6
|
||||
|
||||
SRC_S += \
|
||||
$(CH32V20X_SDK_SRC)/Startup/startup_ch32v20x_D6.S
|
36
hw/bsp/ch32v20x/ch32v20x_conf.h
Normal file
36
hw/bsp/ch32v20x/ch32v20x_conf.h
Normal file
@ -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 */
|
15
hw/bsp/ch32v20x/ch32v20x_it.h
Normal file
15
hw/bsp/ch32v20x/ch32v20x_it.h
Normal file
@ -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 */
|
572
hw/bsp/ch32v20x/core_riscv.h
Normal file
572
hw/bsp/ch32v20x/core_riscv.h
Normal file
@ -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
|
82
hw/bsp/ch32v20x/family.c
Normal file
82
hw/bsp/ch32v20x/family.c
Normal file
@ -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;
|
||||
}
|
50
hw/bsp/ch32v20x/family.mk
Normal file
50
hw/bsp/ch32v20x/family.mk
Normal file
@ -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
|
976
hw/bsp/ch32v20x/system_ch32v20x.c
Normal file
976
hw/bsp/ch32v20x/system_ch32v20x.c
Normal file
@ -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
|
29
hw/bsp/ch32v20x/system_ch32v20x.h
Normal file
29
hw/bsp/ch32v20x/system_ch32v20x.h
Normal file
@ -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 */
|
18
hw/bsp/ch32v20x/wch-riscv.cfg
Normal file
18
hw/bsp/ch32v20x/wch-riscv.cfg
Normal file
@ -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"
|
@ -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 \
|
||||
|
@ -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 += \
|
||||
|
@ -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 \
|
||||
|
@ -609,7 +609,7 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *
|
||||
tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
|
||||
tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
|
||||
|
||||
uint_fast32_t interval, interval_ms;
|
||||
uint_fast32_t interval, interval_ms = 0;
|
||||
switch (request) {
|
||||
case VIDEO_REQUEST_GET_MAX: {
|
||||
uint_fast32_t min_interval, max_interval;
|
||||
|
@ -410,6 +410,10 @@
|
||||
#elif TU_CHECK_MCU(OPT_MCU_CH32F20X)
|
||||
#define TUP_DCD_ENDPOINT_MAX 16
|
||||
#define TUP_RHPORT_HIGHSPEED 1
|
||||
|
||||
#elif TU_CHECK_MCU(OPT_MCU_CH32V20X)
|
||||
#define TUP_DCD_ENDPOINT_MAX 8
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
77
src/portable/wch/ch32_usbfs_reg.h
Normal file
77
src/portable/wch/ch32_usbfs_reg.h
Normal file
@ -0,0 +1,77 @@
|
||||
#ifndef USB_CH32_USBFS_REG_H
|
||||
#define USB_CH32_USBFS_REG_H
|
||||
|
||||
#if (CFG_TUSB_MCU == OPT_MCU_CH32V20X)
|
||||
#include <ch32v20x.h>
|
||||
#endif
|
||||
|
||||
// CTRL
|
||||
#define USBFS_CTRL_DMA_EN (1 << 0)
|
||||
#define USBFS_CTRL_CLR_ALL (1 << 1)
|
||||
#define USBFS_CTRL_RESET_SIE (1 << 2)
|
||||
#define USBFS_CTRL_INT_BUSY (1 << 3)
|
||||
#define USBFS_CTRL_SYS_CTRL (1 << 4)
|
||||
#define USBFS_CTRL_DEV_PUEN (1 << 5)
|
||||
#define USBFS_CTRL_LOW_SPEED (1 << 6)
|
||||
#define USBFS_CTRL_HOST_MODE (1 << 7)
|
||||
|
||||
// INT_EN
|
||||
#define USBFS_INT_EN_BUS_RST (1 << 0)
|
||||
#define USBFS_INT_EN_DETECT (1 << 0)
|
||||
#define USBFS_INT_EN_TRANSFER (1 << 1)
|
||||
#define USBFS_INT_EN_SUSPEND (1 << 2)
|
||||
#define USBFS_INT_EN_HST_SOF (1 << 3)
|
||||
#define USBFS_INT_EN_FIFO_OV (1 << 4)
|
||||
#define USBFS_INT_EN_DEV_NAK (1 << 6)
|
||||
#define USBFS_INT_EN_DEV_SOF (1 << 7)
|
||||
|
||||
// INT_FG
|
||||
#define USBFS_INT_FG_BUS_RST (1 << 0)
|
||||
#define USBFS_INT_FG_DETECT (1 << 0)
|
||||
#define USBFS_INT_FG_TRANSFER (1 << 1)
|
||||
#define USBFS_INT_FG_SUSPEND (1 << 2)
|
||||
#define USBFS_INT_FG_HST_SOF (1 << 3)
|
||||
#define USBFS_INT_FG_FIFO_OV (1 << 4)
|
||||
#define USBFS_INT_FG_SIE_FREE (1 << 5)
|
||||
#define USBFS_INT_FG_TOG_OK (1 << 6)
|
||||
#define USBFS_INT_FG_IS_NAK (1 << 7)
|
||||
|
||||
// INT_ST
|
||||
#define USBFS_INT_ST_MASK_UIS_ENDP(x) (((x) >> 0) & 0x0F)
|
||||
#define USBFS_INT_ST_MASK_UIS_TOKEN(x) (((x) >> 4) & 0x03)
|
||||
|
||||
// UDEV_CTRL
|
||||
#define USBFS_UDEV_CTRL_PORT_EN (1 << 0)
|
||||
#define USBFS_UDEV_CTRL_GP_BIT (1 << 1)
|
||||
#define USBFS_UDEV_CTRL_LOW_SPEED (1 << 2)
|
||||
#define USBFS_UDEV_CTRL_DM_PIN (1 << 4)
|
||||
#define USBFS_UDEV_CTRL_DP_PIN (1 << 5)
|
||||
#define USBFS_UDEV_CTRL_PD_DIS (1 << 7)
|
||||
|
||||
// TX_CTRL
|
||||
#define USBFS_EP_T_RES_MASK (3 << 0)
|
||||
#define USBFS_EP_T_TOG (1 << 2)
|
||||
#define USBFS_EP_T_AUTO_TOG (1 << 3)
|
||||
|
||||
#define USBFS_EP_T_RES_ACK (0 << 0)
|
||||
#define USBFS_EP_T_RES_NYET (1 << 0)
|
||||
#define USBFS_EP_T_RES_NAK (2 << 0)
|
||||
#define USBFS_EP_T_RES_STALL (3 << 0)
|
||||
|
||||
// RX_CTRL
|
||||
#define USBFS_EP_R_RES_MASK (3 << 0)
|
||||
#define USBFS_EP_R_TOG (1 << 2)
|
||||
#define USBFS_EP_R_AUTO_TOG (1 << 3)
|
||||
|
||||
#define USBFS_EP_R_RES_ACK (0 << 0)
|
||||
#define USBFS_EP_R_RES_NYET (1 << 0)
|
||||
#define USBFS_EP_R_RES_NAK (2 << 0)
|
||||
#define USBFS_EP_R_RES_STALL (3 << 0)
|
||||
|
||||
// token PID
|
||||
#define PID_OUT 0
|
||||
#define PID_SOF 1
|
||||
#define PID_IN 2
|
||||
#define PID_SETUP 3
|
||||
|
||||
#endif // USB_CH32_USBFS_REG_H
|
304
src/portable/wch/dcd_ch32_usbfs.c
Normal file
304
src/portable/wch/dcd_ch32_usbfs.c
Normal file
@ -0,0 +1,304 @@
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32V20X)
|
||||
|
||||
#include <stdio.h>
|
||||
#include "device/dcd.h"
|
||||
#include "ch32_usbfs_reg.h"
|
||||
|
||||
/* private defines */
|
||||
#define EP_MAX (8)
|
||||
|
||||
#define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep])
|
||||
#define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep])
|
||||
#define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep])
|
||||
#define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep])
|
||||
|
||||
/* private data */
|
||||
struct usb_xfer {
|
||||
bool valid;
|
||||
uint8_t *buffer;
|
||||
size_t len;
|
||||
size_t processed_len;
|
||||
size_t max_size;
|
||||
};
|
||||
|
||||
static struct {
|
||||
bool ep0_tog;
|
||||
bool isochronous[EP_MAX];
|
||||
struct usb_xfer xfer[EP_MAX][2];
|
||||
TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64];
|
||||
TU_ATTR_ALIGNED(4) struct {
|
||||
// OUT transfers >64 bytes will overwrite queued IN data!
|
||||
uint8_t out[64];
|
||||
uint8_t in[1023];
|
||||
uint8_t pad;
|
||||
} ep3_buffer;
|
||||
} data;
|
||||
|
||||
/* private helpers */
|
||||
static void update_in(uint8_t rhport, uint8_t ep, bool force) {
|
||||
struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_IN];
|
||||
if (xfer->valid) {
|
||||
if (force || xfer->len) {
|
||||
size_t len = TU_MIN(xfer->max_size, xfer->len);
|
||||
if (ep == 0) {
|
||||
memcpy(data.buffer[ep][TUSB_DIR_OUT], xfer->buffer, len); // ep0 uses same chunk
|
||||
} else if (ep == 3) {
|
||||
memcpy(data.ep3_buffer.in, xfer->buffer, len);
|
||||
} else {
|
||||
memcpy(data.buffer[ep][TUSB_DIR_IN], xfer->buffer, len);
|
||||
}
|
||||
xfer->buffer += len;
|
||||
xfer->len -= len;
|
||||
xfer->processed_len += len;
|
||||
|
||||
EP_TX_LEN(ep) = len;
|
||||
if (ep == 0) {
|
||||
EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0);
|
||||
data.ep0_tog = !data.ep0_tog;
|
||||
} else if (data.isochronous[ep]) {
|
||||
EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET;
|
||||
} else {
|
||||
EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK;
|
||||
}
|
||||
} else {
|
||||
xfer->valid = false;
|
||||
EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK;
|
||||
dcd_event_xfer_complete(rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len,
|
||||
XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
|
||||
struct usb_xfer *xfer = &data.xfer[ep][TUSB_DIR_OUT];
|
||||
if (xfer->valid) {
|
||||
size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len));
|
||||
if (ep == 3) {
|
||||
memcpy(xfer->buffer, data.ep3_buffer.out, len);
|
||||
} else {
|
||||
memcpy(xfer->buffer, data.buffer[ep][TUSB_DIR_OUT], len);
|
||||
}
|
||||
xfer->buffer += len;
|
||||
xfer->len -= len;
|
||||
xfer->processed_len += len;
|
||||
|
||||
if (xfer->len == 0 || len < xfer->max_size) {
|
||||
xfer->valid = false;
|
||||
dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, true);
|
||||
}
|
||||
|
||||
if (ep == 0) {
|
||||
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* public functions */
|
||||
void dcd_init(uint8_t rhport) {
|
||||
// init registers
|
||||
USBOTG_FS->BASE_CTRL = USBFS_CTRL_SYS_CTRL | USBFS_CTRL_INT_BUSY | USBFS_CTRL_DMA_EN;
|
||||
USBOTG_FS->UDEV_CTRL = USBFS_UDEV_CTRL_PD_DIS | USBFS_UDEV_CTRL_PORT_EN;
|
||||
USBOTG_FS->DEV_ADDR = 0x00;
|
||||
|
||||
USBOTG_FS->INT_FG = 0xFF;
|
||||
USBOTG_FS->INT_EN = USBFS_INT_EN_BUS_RST | USBFS_INT_EN_TRANSFER | USBFS_INT_EN_SUSPEND;
|
||||
|
||||
// setup endpoint 0
|
||||
EP_DMA(0) = (uint32_t) &data.buffer[0][0];
|
||||
EP_TX_LEN(0) = 0;
|
||||
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
|
||||
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
|
||||
|
||||
// enable other endpoints but NAK everything
|
||||
USBOTG_FS->UEP4_1_MOD = 0xCC;
|
||||
USBOTG_FS->UEP2_3_MOD = 0xCC;
|
||||
USBOTG_FS->UEP5_6_MOD = 0xCC;
|
||||
USBOTG_FS->UEP7_MOD = 0x0C;
|
||||
|
||||
for (uint8_t ep = 1; ep < EP_MAX; ep++) {
|
||||
EP_DMA(ep) = (uint32_t) &data.buffer[ep][0];
|
||||
EP_TX_LEN(ep) = 0;
|
||||
EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
|
||||
EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK;
|
||||
}
|
||||
EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0];
|
||||
|
||||
dcd_connect(rhport);
|
||||
}
|
||||
|
||||
void dcd_int_handler(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
uint8_t status = USBOTG_FS->INT_FG;
|
||||
if (status & USBFS_INT_FG_TRANSFER) {
|
||||
uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST);
|
||||
uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST);
|
||||
|
||||
switch (token) {
|
||||
case PID_OUT: {
|
||||
uint16_t rx_len = USBOTG_FS->RX_LEN;
|
||||
update_out(rhport, ep, rx_len);
|
||||
break;
|
||||
}
|
||||
|
||||
case PID_IN:
|
||||
update_in(rhport, ep, false);
|
||||
break;
|
||||
|
||||
case PID_SETUP:
|
||||
data.ep0_tog = true;
|
||||
dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true);
|
||||
break;
|
||||
}
|
||||
|
||||
USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER;
|
||||
} else if (status & USBFS_INT_FG_BUS_RST) {
|
||||
data.ep0_tog = true;
|
||||
data.xfer[0][TUSB_DIR_OUT].max_size = 64;
|
||||
data.xfer[0][TUSB_DIR_IN].max_size = 64;
|
||||
|
||||
dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
|
||||
|
||||
USBOTG_FS->DEV_ADDR = 0x00;
|
||||
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
|
||||
|
||||
USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST;
|
||||
} else if (status & USBFS_INT_FG_SUSPEND) {
|
||||
dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPEND };
|
||||
dcd_event_handler(&event, true);
|
||||
USBOTG_FS->INT_FG = USBFS_INT_FG_SUSPEND;
|
||||
}
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
NVIC_EnableIRQ(USBHD_IRQn);
|
||||
}
|
||||
|
||||
void dcd_int_disable(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
NVIC_DisableIRQ(USBHD_IRQn);
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
|
||||
(void) dev_addr;
|
||||
dcd_edpt_xfer(rhport, 0x80, NULL, 0); // zlp status response
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
// TODO optional
|
||||
}
|
||||
|
||||
void dcd_connect(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
USBOTG_FS->BASE_CTRL |= USBFS_CTRL_DEV_PUEN;
|
||||
}
|
||||
|
||||
void dcd_disconnect(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN;
|
||||
}
|
||||
|
||||
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) {
|
||||
USBOTG_FS->DEV_ADDR = (uint8_t) request->wValue;
|
||||
}
|
||||
EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
|
||||
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
|
||||
}
|
||||
|
||||
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep) {
|
||||
(void) rhport;
|
||||
uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress);
|
||||
uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress);
|
||||
TU_ASSERT(ep < EP_MAX);
|
||||
|
||||
data.isochronous[ep] = desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS;
|
||||
data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep);
|
||||
|
||||
if (ep != 0) {
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
if (data.isochronous[ep]) {
|
||||
EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET;
|
||||
} else {
|
||||
EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK;
|
||||
}
|
||||
} else {
|
||||
EP_TX_LEN(ep) = 0;
|
||||
EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_edpt_close_all(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
// TODO optional
|
||||
}
|
||||
|
||||
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
(void) ep_addr;
|
||||
// TODO optional
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
|
||||
(void) rhport;
|
||||
uint8_t ep = tu_edpt_number(ep_addr);
|
||||
uint8_t dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
struct usb_xfer *xfer = &data.xfer[ep][dir];
|
||||
xfer->valid = true;
|
||||
xfer->buffer = buffer;
|
||||
xfer->len = total_bytes;
|
||||
xfer->processed_len = 0;
|
||||
|
||||
if (dir == TUSB_DIR_IN) {
|
||||
update_in(rhport, ep, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
uint8_t ep = tu_edpt_number(ep_addr);
|
||||
uint8_t dir = tu_edpt_dir(ep_addr);
|
||||
if (ep == 0) {
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL;
|
||||
} else {
|
||||
EP_TX_LEN(0) = 0;
|
||||
EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL;
|
||||
}
|
||||
} else {
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_STALL;
|
||||
} else {
|
||||
EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~USBFS_EP_T_RES_MASK) | USBFS_EP_T_RES_STALL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
|
||||
(void) rhport;
|
||||
uint8_t ep = tu_edpt_number(ep_addr);
|
||||
uint8_t dir = tu_edpt_dir(ep_addr);
|
||||
if (ep == 0) {
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
|
||||
}
|
||||
} else {
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~(USBFS_EP_R_RES_MASK | USBFS_EP_R_TOG)) | USBFS_EP_R_RES_ACK;
|
||||
} else {
|
||||
EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK | USBFS_EP_T_TOG)) | USBFS_EP_T_RES_NAK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32V20X)
|
@ -181,6 +181,7 @@
|
||||
// WCH
|
||||
#define OPT_MCU_CH32V307 2200 ///< WCH CH32V307
|
||||
#define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x
|
||||
#define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X
|
||||
|
||||
|
||||
// NXP LPC MCX
|
||||
|
@ -168,6 +168,9 @@ deps_optional = {
|
||||
'hw/mcu/ti': ['https://github.com/hathach/ti_driver.git',
|
||||
'143ed6cc20a7615d042b03b21e070197d473e6e5',
|
||||
'msp430 msp432e4 tm4c'],
|
||||
'hw/mcu/wch/ch32v20x': ['https://github.com/openwch/ch32v20x.git',
|
||||
'de6d68c654340d7f27b00cebbfc9aa2740a1abc2',
|
||||
'ch32v20x'],
|
||||
'hw/mcu/wch/ch32v307': ['https://github.com/openwch/ch32v307.git',
|
||||
'17761f5cf9dbbf2dcf665b7c04934188add20082',
|
||||
'ch32v307'],
|
||||
|
@ -239,6 +239,7 @@
|
||||
<path>$TUSB_DIR$/src/portable/valentyusb/eptri/dcd_eptri.h</path>
|
||||
</group>
|
||||
<group name="src/portable/wch">
|
||||
<path>$TUSB_DIR$/src/portable/wch/dcd_ch32_usbfs.c</path>
|
||||
<path>$TUSB_DIR$/src/portable/wch/dcd_ch32_usbhs.c</path>
|
||||
<path>$TUSB_DIR$/src/portable/wch/ch32_usbhs_reg.h</path>
|
||||
</group>
|
||||
|
Loading…
x
Reference in New Issue
Block a user