Add WCH CH32V307 port

Add WCH mcu submodule
Add CH32V307V-R1-1v0 bsp
This commit is contained in:
Greg Davill 2022-03-21 10:01:11 +10:30
parent ae531a79f6
commit fccbcfc889
17 changed files with 2410 additions and 0 deletions

3
.gitmodules vendored
View File

@ -146,3 +146,6 @@
[submodule "hw/mcu/allwinner"]
path = hw/mcu/allwinner
url = https://github.com/hathach/allwinner_driver.git
[submodule "hw/mcu/wch/ch32v307"]
path = hw/mcu/wch/ch32v307
url = https://github.com/openwch/ch32v307.git

View File

@ -0,0 +1,3 @@
LINKER_SCRIPTS = $(CH32V307_SDK_SRC)/Ld
LD_FILE = $(LINKER_SCRIPTS)/Link.ld # CH32V307

View File

@ -0,0 +1,110 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 Greg Davill
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#include "debug_uart.h"
#include <ch32v30x.h>
#define UART_RINGBUFFER_SIZE_TX 64
#define UART_RINGBUFFER_MASK_TX (UART_RINGBUFFER_SIZE_TX-1)
static char tx_buf[UART_RINGBUFFER_SIZE_TX];
static unsigned int tx_produce;
static volatile unsigned int tx_consume;
void USART1_IRQHandler(void) __attribute__((naked));
void USART1_IRQHandler(void) {
__asm volatile ("call USART1_IRQHandler_impl; mret");
}
__attribute__((used)) void USART1_IRQHandler_impl(void)
{
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)
{
USART_ClearITPendingBit(USART1, USART_IT_TC);
if(tx_consume != tx_produce) {
USART_SendData(USART1, tx_buf[tx_consume]);
tx_consume = (tx_consume + 1) & UART_RINGBUFFER_MASK_TX;
}
}
}
void uart_write(char c)
{
unsigned int tx_produce_next = (tx_produce + 1) & UART_RINGBUFFER_MASK_TX;
NVIC_DisableIRQ(USART1_IRQn);
if((tx_consume != tx_produce) || (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)) {
tx_buf[tx_produce] = c;
tx_produce = tx_produce_next;
} else {
USART_SendData(USART1, c);
}
NVIC_EnableIRQ(USART1_IRQn);
}
void uart_sync(void)
{
while(tx_consume != tx_produce);
}
void USART_Printf_Init(uint32_t baudrate)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
tx_produce = 0;
tx_consume = 0;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baudrate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_TC, ENABLE);
USART_Cmd(USART1, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure = {0};
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

View File

@ -0,0 +1,31 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 Greg Davill
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#include <stdint.h>
void uart_write(char c);
void uart_sync(void);
void USART_Printf_Init(uint32_t baudrate);

View File

@ -0,0 +1,43 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v30x_conf.h
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : Library configuration file.
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#ifndef __CH32V30x_CONF_H
#define __CH32V30x_CONF_H
#include "ch32v30x_adc.h"
#include "ch32v30x_bkp.h"
#include "ch32v30x_can.h"
#include "ch32v30x_crc.h"
#include "ch32v30x_dac.h"
#include "ch32v30x_dbgmcu.h"
#include "ch32v30x_dma.h"
#include "ch32v30x_exti.h"
#include "ch32v30x_flash.h"
#include "ch32v30x_fsmc.h"
#include "ch32v30x_gpio.h"
#include "ch32v30x_i2c.h"
#include "ch32v30x_iwdg.h"
#include "ch32v30x_pwr.h"
#include "ch32v30x_rcc.h"
#include "ch32v30x_rtc.h"
#include "ch32v30x_sdio.h"
#include "ch32v30x_spi.h"
#include "ch32v30x_tim.h"
#include "ch32v30x_usart.h"
#include "ch32v30x_wwdg.h"
#include "ch32v30x_it.h"
#include "ch32v30x_misc.h"
#endif /* __CH32V30x_CONF_H */

View File

@ -0,0 +1,49 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v30x_it.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : Main Interrupt Service Routines.
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#include "ch32v30x_it.h"
void NMI_Handler(void) __attribute__((naked));
void HardFault_Handler(void) __attribute__((naked));
/*********************************************************************
* @fn NMI_Handler
*
* @brief This function handles NMI exception.
*
* @return none
*/
void NMI_Handle(void){
__asm volatile ("call NMI_Handler_impl; mret");
}
__attribute__((used)) void NMI_Handler_impl(void)
{
}
/*********************************************************************
* @fn HardFault_Handler
*
* @brief This function handles Hard Fault exception.
*
* @return none
*/
void HardFault_Handler(void){
__asm volatile ("call HardFault_Handler_impl; mret");
}
__attribute__((used)) void HardFault_Handler_impl(void)
{
while (1)
{
}
}

View File

@ -0,0 +1,18 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : ch32v30x_it.h
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : This file contains the headers of the interrupt handlers.
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#ifndef __CH32V30x_IT_H
#define __CH32V30x_IT_H
#include "debug.h"
#endif /* __CH32V30x_IT_H */

View File

@ -0,0 +1,384 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : core_riscv.h
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : RISC-V Core Peripheral Access Layer Header File for CH32V30x
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#ifndef __CORE_RISCV_H__
#define __CORE_RISCV_H__
/* IO definitions */
#ifdef __cplusplus
#define __I volatile /* defines 'read only' permissions */
#else
#define __I volatile const /* defines 'read only' permissions */
#endif
#define __O volatile /* defines 'write only' permissions */
#define __IO volatile /* defines 'read / write' permissions */
/* Standard Peripheral Library old types (maintained for legacy purpose) */
typedef __I uint64_t vuc64; /* Read Only */
typedef __I uint32_t vuc32; /* Read Only */
typedef __I uint16_t vuc16; /* Read Only */
typedef __I uint8_t vuc8; /* Read Only */
typedef const uint64_t uc64; /* Read Only */
typedef const uint32_t uc32; /* Read Only */
typedef const uint16_t uc16; /* Read Only */
typedef const uint8_t uc8; /* Read Only */
typedef __I int64_t vsc64; /* Read Only */
typedef __I int32_t vsc32; /* Read Only */
typedef __I int16_t vsc16; /* Read Only */
typedef __I int8_t vsc8; /* Read Only */
typedef const int64_t sc64; /* Read Only */
typedef const int32_t sc32; /* Read Only */
typedef const int16_t sc16; /* Read Only */
typedef const int8_t sc8; /* Read Only */
typedef __IO uint64_t vu64;
typedef __IO uint32_t vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t vu8;
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef __IO int64_t vs64;
typedef __IO int32_t vs32;
typedef __IO int16_t vs16;
typedef __IO int8_t vs8;
typedef int64_t s64;
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
#define RV_STATIC_INLINE static inline
/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */
typedef struct{
__I uint32_t ISR[8];
__I uint32_t IPR[8];
__IO uint32_t ITHRESDR;
__IO uint32_t RESERVED;
__IO uint32_t CFGR;
__I uint32_t GISR;
uint8_t VTFIDR[4];
uint8_t RESERVED0[12];
__IO uint32_t VTFADDR[4];
uint8_t RESERVED1[0x90];
__O uint32_t IENR[8];
uint8_t RESERVED2[0x60];
__O uint32_t IRER[8];
uint8_t RESERVED3[0x60];
__O uint32_t IPSR[8];
uint8_t RESERVED4[0x60];
__O uint32_t IPRR[8];
uint8_t RESERVED5[0x60];
__IO uint32_t IACTR[8];
uint8_t RESERVED6[0xE0];
__IO uint8_t IPRIOR[256];
uint8_t RESERVED7[0x810];
__IO uint32_t SCTLR;
}PFIC_Type;
/* memory mapped structure for SysTick */
typedef struct
{
__IO u32 CTLR;
__IO u32 SR;
__IO u64 CNT;
__IO u64 CMP;
}SysTick_Type;
#define PFIC ((PFIC_Type *) 0xE000E000 )
#define NVIC PFIC
#define NVIC_KEY1 ((uint32_t)0xFA050000)
#define NVIC_KEY2 ((uint32_t)0xBCAF0000)
#define NVIC_KEY3 ((uint32_t)0xBEEF0000)
#define SysTick ((SysTick_Type *) 0xE000F000)
/*********************************************************************
* @fn __enable_irq
*
* @brief Enable Global Interrupt
*
* @return none
*/
RV_STATIC_INLINE void __enable_irq(void)
{
__asm volatile ("csrw 0x800, %0" : : "r" (0x6088) );
}
/*********************************************************************
* @fn __disable_irq
*
* @brief Disable Global Interrupt
*
* @return none
*/
RV_STATIC_INLINE void __disable_irq(void)
{
__asm volatile ("csrw 0x800, %0" : : "r" (0x6000) );
}
/*********************************************************************
* @fn __NOP
*
* @brief nop
*
* @return none
*/
RV_STATIC_INLINE void __NOP(void)
{
__asm volatile ("nop");
}
/*********************************************************************
* @fn NVIC_EnableIRQ
*
* @brief Enable Interrupt
*
* @param IRQn: Interrupt Numbers
*
* @return none
*/
RV_STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn)
{
NVIC->IENR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/*********************************************************************
* @fn NVIC_DisableIRQ
*
* @brief Disable Interrupt
*
* @param IRQn: Interrupt Numbers
*
* @return none
*/
RV_STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn)
{
NVIC->IRER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/*********************************************************************
* @fn NVIC_GetStatusIRQ
*
* @brief Get Interrupt Enable State
*
* @param IRQn: Interrupt Numbers
*
* @return 1 - Interrupt Enable
* 0 - Interrupt Disable
*/
RV_STATIC_INLINE uint32_t NVIC_GetStatusIRQ(IRQn_Type IRQn)
{
return((uint32_t) ((NVIC->ISR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
/*********************************************************************
* @fn NVIC_GetPendingIRQ
*
* @brief Get Interrupt Pending State
*
* @param IRQn: Interrupt Numbers
*
* @return 1 - Interrupt Pending Enable
* 0 - Interrupt Pending Disable
*/
RV_STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)
{
return((uint32_t) ((NVIC->IPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
/*********************************************************************
* @fn NVIC_SetPendingIRQ
*
* @brief Set Interrupt Pending
*
* @param IRQn: Interrupt Numbers
*
* @return None
*/
RV_STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)
{
NVIC->IPSR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/*********************************************************************
* @fn NVIC_ClearPendingIRQ
*
* @brief Clear Interrupt Pending
*
* @param IRQn: Interrupt Numbers
*
* @return None
*/
RV_STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
{
NVIC->IPRR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F));
}
/*********************************************************************
* @fn NVIC_GetActive
*
* @brief Get Interrupt Active State
*
* @param IRQn: Interrupt Numbers
*
* @return 1 - Interrupt Active
* 0 - Interrupt No Active
*/
RV_STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
{
return((uint32_t)((NVIC->IACTR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0));
}
/*********************************************************************
* @fn NVIC_SetPriority
*
* @brief Set Interrupt Priority
*
* @param IRQn - Interrupt Numbers
* priority -
* bit7 - pre-emption priority
* bit6~bit4 - subpriority
* @return None
*/
RV_STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint8_t priority)
{
NVIC->IPRIOR[(uint32_t)(IRQn)] = priority;
}
/*********************************************************************
* @fn __WFI
*
* @brief Wait for Interrupt
*
* @return None
*/
__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFI(void)
{
NVIC->SCTLR &= ~(1<<3); // wfi
asm volatile ("wfi");
}
/*********************************************************************
* @fn __WFE
*
* @brief Wait for Events
*
* @return None
*/
__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFE(void)
{
uint32_t t;
t = NVIC->SCTLR;
NVIC->SCTLR |= (1<<3)|(1<<5); // (wfi->wfe)+(__sev)
NVIC->SCTLR = (NVIC->SCTLR & ~(1<<5)) | ( t & (1<<5));
asm volatile ("wfi");
asm volatile ("wfi");
}
/*********************************************************************
* @fn SetVTFIRQ
*
* @brief Set VTF Interrupt
*
* @param add - VTF interrupt service function base address.
* IRQn -Interrupt Numbers
* num - VTF Interrupt Numbers
* NewState - DISABLE or ENABLE
* @return None
*/
RV_STATIC_INLINE void SetVTFIRQ(uint32_t addr, IRQn_Type IRQn, uint8_t num, FunctionalState NewState){
if(num > 3) return ;
if (NewState != DISABLE)
{
NVIC->VTFIDR[num] = IRQn;
NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)|0x1);
}
else{
NVIC->VTFIDR[num] = IRQn;
NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)&(~0x1));
}
}
/*********************************************************************
* @fn NVIC_SystemReset
*
* @brief Initiate a system reset request
*
* @return None
*/
RV_STATIC_INLINE void NVIC_SystemReset(void)
{
NVIC->CFGR = NVIC_KEY3|(1<<7);
}
/* Core_Exported_Functions */
extern uint32_t __get_FFLAGS(void);
extern void __set_FFLAGS(uint32_t value);
extern uint32_t __get_FRM(void);
extern void __set_FRM(uint32_t value);
extern uint32_t __get_FCSR(void);
extern void __set_FCSR(uint32_t value);
extern uint32_t __get_MSTATUS(void);
extern void __set_MSTATUS(uint32_t value);
extern uint32_t __get_MISA(void);
extern void __set_MISA(uint32_t value);
extern uint32_t __get_MIE(void);
extern void __set_MIE(uint32_t value);
extern uint32_t __get_MTVEC(void);
extern void __set_MTVEC(uint32_t value);
extern uint32_t __get_MSCRATCH(void);
extern void __set_MSCRATCH(uint32_t value);
extern uint32_t __get_MEPC(void);
extern void __set_MEPC(uint32_t value);
extern uint32_t __get_MCAUSE(void);
extern void __set_MCAUSE(uint32_t value);
extern uint32_t __get_MTVAL(void);
extern void __set_MTVAL(uint32_t value);
extern uint32_t __get_MIP(void);
extern void __set_MIP(uint32_t value);
extern uint32_t __get_MCYCLE(void);
extern void __set_MCYCLE(uint32_t value);
extern uint32_t __get_MCYCLEH(void);
extern void __set_MCYCLEH(uint32_t value);
extern uint32_t __get_MINSTRET(void);
extern void __set_MINSTRET(uint32_t value);
extern uint32_t __get_MINSTRETH(void);
extern void __set_MINSTRETH(uint32_t value);
extern uint32_t __get_MVENDORID(void);
extern uint32_t __get_MARCHID(void);
extern uint32_t __get_MIMPID(void);
extern uint32_t __get_MHARTID(void);
extern uint32_t __get_SP(void);
#endif

160
hw/bsp/ch32v307/family.c Normal file
View File

@ -0,0 +1,160 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 Greg Davill
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#include "stdio.h"
#include "debug_uart.h"
#include "ch32v30x.h"
#include "../board.h"
//--------------------------------------------------------------------+
// Forward USB interrupt events to TinyUSB IRQ Handler
//--------------------------------------------------------------------+
void USBHS_IRQHandler(void) __attribute__((naked));
void USBHS_IRQHandler(void) {
__asm volatile ("call USBHS_IRQHandler_impl; mret");
}
__attribute__ ((used)) void USBHS_IRQHandler_impl(void) {
tud_int_handler(0);
}
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM
//--------------------------------------------------------------------+
uint32_t SysTick_Config(uint32_t ticks)
{
NVIC_EnableIRQ(SysTicK_IRQn);
SysTick->CTLR=0;
SysTick->SR=0;
SysTick->CNT=0;
SysTick->CMP=ticks-1;
SysTick->CTLR=0xF;
return 0;
}
void board_init(void) {
/* Disable interrupts during init */
__disable_irq();
#if CFG_TUSB_OS == OPT_OS_NONE
SysTick_Config(SystemCoreClock / 1000);
#endif
USART_Printf_Init(115200);
RCC_USBCLK48MConfig(RCC_USBCLK48MCLKSource_USBPHY);
RCC_USBHSPLLCLKConfig(RCC_HSBHSPLLCLKSource_HSE);
RCC_USBHSConfig(RCC_USBPLL_Div2);
RCC_USBHSPLLCKREFCLKConfig(RCC_USBHSPLLCKREFCLK_4M);
RCC_USBHSPHYPLLALIVEcmd(ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHS, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Enable interrupts globaly */
__enable_irq();
board_delay(2);
}
#if CFG_TUSB_OS == OPT_OS_NONE
volatile uint32_t system_ticks = 0;
/* Small workaround to support HW stack save/restore */
void SysTick_Handler(void) __attribute__((naked));
void SysTick_Handler(void) {
__asm volatile ("call SysTick_Handler_impl; mret");
}
__attribute__((used)) void SysTick_Handler_impl(void) {
SysTick->SR=0;
system_ticks++;
}
uint32_t board_millis(void) { return system_ticks; }
#endif
//--------------------------------------------------------------------+
// Board porting API
//--------------------------------------------------------------------+
void board_led_write(bool state) {
(void) state;
GPIO_WriteBit(GPIOC, GPIO_Pin_0, state);
}
uint32_t board_button_read(void) {
return false;
}
int board_uart_read(uint8_t* buf, int len) {
(void)buf;
(void)len;
return 0;
}
int board_uart_write(void const* buf, int len) {
int txsize = len;
while (txsize--) {
uart_write(*(uint8_t const*)buf);
buf++;
}
return len;
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(char* file, uint32_t line) {
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line
number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line)
*/
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

62
hw/bsp/ch32v307/family.mk Normal file
View File

@ -0,0 +1,62 @@
# https://www.embecosm.com/resources/tool-chain-downloads/#riscv-stable
#CROSS_COMPILE ?= riscv32-unknown-elf-
# Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack
CROSS_COMPILE ?= riscv-none-embed-
# Submodules
CH32V307_SDK = hw/mcu/wch/ch32v307
DEPS_SUBMODULES += $(CH32V307_SDK)
# WCH-SDK paths
CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC
CH32V307_SDK_SRC_TOP = $(TOP)/$(CH32V307_SDK_SRC)
CH32V307_STARTUP_ASM = $(CH32V307_SDK_SRC)/Startup
include $(TOP)/$(BOARD_PATH)/board.mk
SKIP_NANOLIB = 1
CFLAGS += \
-flto \
-march=rv32imac \
-mabi=ilp32 \
-msmall-data-limit=8 \
-mno-save-restore -Os \
-fmessage-length=0 \
-fsigned-char \
-ffunction-sections \
-fdata-sections \
-nostdlib -nostartfiles \
-DCFG_TUSB_MCU=OPT_MCU_CH32VF307 \
-Xlinker --gc-sections \
-DBOARD_DEVICE_RHPORT_SPEED=OPT_MODE_HIGH_SPEED
LDFLAGS += \
-Xlinker --gc-sections --specs=nano.specs --specs=nosys.specs
SRC_C += \
src/portable/wch/ch32v307/usb_dc_usbhs.c \
$(CH32V307_SDK_SRC_TOP)/Core/core_riscv.c \
$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_gpio.c \
$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_misc.c \
$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_rcc.c \
$(CH32V307_SDK_SRC_TOP)/Peripheral/src/ch32v30x_usart.c
SRC_S += \
$(CH32V307_STARTUP_ASM)/startup_ch32v30x_D8C.S
INC += \
src/portable/wch/ch32v307 \
$(TOP)/$(BOARD_PATH)/.. \
$(TOP)/$(BOARD_PATH) \
$(CH32V307_SDK_SRC_TOP)/Peripheral/inc \
$(CH32V307_SDK_SRC_TOP)/Debug \
$(CH32V307_SDK_SRC_TOP)
# For freeRTOS port source
FREERTOS_PORT = RISC-V
# flash target ROM bootloader
flash: $(BUILD)/$(PROJECT).elf
openocd -f wch-riscv.cfg -c init -c halt -c "program $< 0x08000000" -c reset -c exit

View File

@ -0,0 +1,776 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : system_ch32v30x.c
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : CH32V30x Device Peripheral Access Layer System Source File.
* For HSE = 8Mhz
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*********************************************************************************/
#include "ch32v30x.h"
/*
* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after
* reset the HSI is used as SYSCLK source).
* If none of the define below is enabled, the HSI is used as System clock source.
*/
// #define SYSCLK_FREQ_HSE HSE_VALUE
/* #define SYSCLK_FREQ_24MHz 24000000 */
//#define SYSCLK_FREQ_48MHz 48000000
/* #define SYSCLK_FREQ_56MHz 56000000 */
//#define SYSCLK_FREQ_72MHz 72000000
//#define SYSCLK_FREQ_96MHz 96000000
//#define SYSCLK_FREQ_120MHz 120000000
#define SYSCLK_FREQ_144MHz 144000000
/* Clock Definitions */
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_96MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_120MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz; /* System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_144MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz; /* System Clock Frequency (Core Clock) */
#else /* HSI Selected as System Clock source */
uint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */
#endif
__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
/* system_private_function_proto_types */
static void SetSysClock(void);
#ifdef SYSCLK_FREQ_HSE
static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_24MHz
static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_48MHz
static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
static void SetSysClockTo56(void);
#elif defined SYSCLK_FREQ_72MHz
static void SetSysClockTo72(void);
#elif defined SYSCLK_FREQ_96MHz
static void SetSysClockTo96(void);
#elif defined SYSCLK_FREQ_120MHz
static void SetSysClockTo120(void);
#elif defined SYSCLK_FREQ_144MHz
static void SetSysClockTo144(void);
#endif
/*********************************************************************
* @fn SystemInit
*
* @brief Setup the microcontroller system Initialize the Embedded Flash Interface,
* the PLL and update the SystemCoreClock variable.
*
* @return none
*/
void SystemInit (void)
{
RCC->CTLR |= (uint32_t)0x00000001;
#ifdef CH32V30x_D8C
RCC->CFGR0 &= (uint32_t)0xF8FF0000;
#else
RCC->CFGR0 &= (uint32_t)0xF0FF0000;
#endif
RCC->CTLR &= (uint32_t)0xFEF6FFFF;
RCC->CTLR &= (uint32_t)0xFFFBFFFF;
RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
#ifdef CH32V30x_D8C
RCC->CTLR &= (uint32_t)0xEBFFFFFF;
RCC->INTR = 0x00FF0000;
RCC->CFGR2 = 0x00000000;
#else
RCC->INTR = 0x009F0000;
#endif
SetSysClock();
}
/*********************************************************************
* @fn SystemCoreClockUpdate
*
* @brief Update SystemCoreClock variable according to Clock Register Values.
*
* @return none
*/
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, Pll_6_5 = 0;
tmp = RCC->CFGR0 & RCC_SWS;
switch (tmp)
{
case 0x00:
SystemCoreClock = HSI_VALUE;
break;
case 0x04:
SystemCoreClock = HSE_VALUE;
break;
case 0x08:
pllmull = RCC->CFGR0 & RCC_PLLMULL;
pllsource = RCC->CFGR0 & RCC_PLLSRC;
pllmull = ( pllmull >> 18) + 2;
#ifdef CH32V30x_D8
if(pllmull == 17) pllmull = 18;
#else
if(pllmull == 2) pllmull = 18;
if(pllmull == 15){
pllmull = 13; /* *6.5 */
Pll_6_5 = 1;
}
if(pllmull == 16) pllmull = 15;
if(pllmull == 17) pllmull = 16;
#endif
if (pllsource == 0x00)
{
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
}
else
{
if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
{
SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
}
else
{
SystemCoreClock = HSE_VALUE * pllmull;
}
}
if(Pll_6_5 == 1) SystemCoreClock = (SystemCoreClock / 2);
break;
default:
SystemCoreClock = HSI_VALUE;
break;
}
tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
SystemCoreClock >>= tmp;
}
/*********************************************************************
* @fn SetSysClock
*
* @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#elif defined SYSCLK_FREQ_96MHz
SetSysClockTo96();
#elif defined SYSCLK_FREQ_120MHz
SetSysClockTo120();
#elif defined SYSCLK_FREQ_144MHz
SetSysClockTo144();
#endif
/* If none of the define above is enabled, the HSI is used as System clock
* source (default after reset)
*/
}
#ifdef SYSCLK_FREQ_HSE
/*********************************************************************
* @fn SetSysClockToHSE
*
* @brief Sets HSE as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockToHSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
/* Select HSE as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_HSE;
/* Wait till HSE is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04)
{
}
}
else
{
/* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_24MHz
/*********************************************************************
* @fn SetSysClockTo24
*
* @brief Sets System clock frequency to 24MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo24(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
#ifdef CH32V30x_D8
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL3);
#else
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL3_EXTEN);
#endif
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_48MHz
/*********************************************************************
* @fn SetSysClockTo48
*
* @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo48(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSE * 6 = 48 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
#ifdef CH32V30x_D8
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6);
#else
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6_EXTEN);
#endif
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_56MHz
/*********************************************************************
* @fn SetSysClockTo56
*
* @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo56(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSE * 7 = 56 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
#ifdef CH32V30x_D8
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7);
#else
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7_EXTEN);
#endif
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_72MHz
/*********************************************************************
* @fn SetSysClockTo72
*
* @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
#ifdef CH32V30x_D8
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9);
#else
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9_EXTEN);
#endif
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_96MHz
/*********************************************************************
* @fn SetSysClockTo96
*
* @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo96(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSE * 12 = 96 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
#ifdef CH32V30x_D8
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12);
#else
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12_EXTEN);
#endif
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_120MHz
/*********************************************************************
* @fn SetSysClockTo120
*
* @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo120(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSE * 15 = 120 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
#ifdef CH32V30x_D8
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15);
#else
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15_EXTEN);
#endif
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#elif defined SYSCLK_FREQ_144MHz
/*********************************************************************
* @fn SetSysClockTo144
*
* @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
*
* @return none
*/
static void SetSysClockTo144(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CTLR |= ((uint32_t)RCC_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CTLR & RCC_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CTLR & RCC_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
/* HCLK = SYSCLK */
RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
/* PLL configuration: PLLCLK = HSE * 18 = 144 MHz */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE |
RCC_PLLMULL));
#ifdef CH32V30x_D8
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18);
#else
RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18_EXTEN);
#endif
/* Enable PLL */
RCC->CTLR |= RCC_PLLON;
/* Wait till PLL is ready */
while((RCC->CTLR & RCC_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
{
}
}
else
{
/*
* If HSE fails to start-up, the application will have wrong clock
* configuration. User can add here some code to deal with this error
*/
}
}
#endif

View File

@ -0,0 +1,30 @@
/********************************** (C) COPYRIGHT *******************************
* File Name : system_ch32v30x.h
* Author : WCH
* Version : V1.0.0
* Date : 2021/06/06
* Description : CH32V30x Device Peripheral Access Layer System Header File.
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/
#ifndef __SYSTEM_CH32V30x_H
#define __SYSTEM_CH32V30x_H
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */
/* System_Exported_Functions */
extern void SystemInit(void);
extern void SystemCoreClockUpdate(void);
#ifdef __cplusplus
}
#endif
#endif /*__CH32V30x_SYSTEM_H */

1
hw/mcu/wch/ch32v307 Submodule

@ -0,0 +1 @@
Subproject commit 17761f5cf9dbbf2dcf665b7c04934188add20082

View File

@ -266,6 +266,10 @@
#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
#define TUP_DCD_ENDPOINT_MAX 4
//------------- WCH -------------//
#elif TU_CHECK_MCU(OPT_MCU_CH32VF307)
#define TUP_DCD_ENDPOINT_MAX 8
#endif
//--------------------------------------------------------------------+

View File

@ -0,0 +1,345 @@
#ifndef _USB_CH32_USBHS_REG_H
#define _USB_CH32_USBHS_REG_H
#include <ch32v30x.h>
/******************* GLOBAL ******************/
// USB CONTROL
#define USBHS_CONTROL_OFFSET 0x00
#define USBHS_DMA_EN (1 << 0)
#define USBHS_ALL_CLR (1 << 1)
#define USBHS_FORCE_RST (1 << 2)
#define USBHS_INT_BUSY_EN (1 << 3)
#define USBHS_DEV_PU_EN (1 << 4)
#define USBHS_SPEED_MASK (3 << 5)
#define USBHS_FULL_SPEED (0 << 5)
#define USBHS_HIGH_SPEED (1 << 5)
#define USBHS_LOW_SPEED (2 << 5)
#define USBHS_HOST_MODE (1 << 7)
// USB_INT_EN
#define USBHS_INT_EN_OFFSET 0x02
#define USBHS_BUS_RST_EN (1 << 0)
#define USBHS_DETECT_EN (1 << 0)
#define USBHS_TRANSFER_EN (1 << 1)
#define USBHS_SUSPEND_EN (1 << 2)
#define USBHS_SOF_ACT_EN (1 << 3)
#define USBHS_FIFO_OV_EN (1 << 4)
#define USBHS_SETUP_ACT_EN (1 << 5)
#define USBHS_ISO_ACT_EN (1 << 6)
#define USBHS_DEV_NAK_EN (1 << 7)
// USB DEV AD
#define USBHS_DEV_AD_OFFSET 0x03
// USB FRAME_NO
#define USBHS_FRAME_NO_OFFSET 0x04
// USB SUSPEND
#define USBHS_SUSPEND_OFFSET 0x06
#define USBHS_DEV_REMOTE_WAKEUP (1 << 2)
#define USBHS_LINESTATE_MASK (2 << 4) /* Read Only */
// RESERVED0
// USB SPEED TYPE
#define USBHS_SPEED_TYPE_OFFSET 0x08
#define USBSPEED_MASK (0x03)
// USB_MIS_ST
#define USBHS_MIS_ST_OFFSET 0x09
#define USBHS_SPLIT_CAN (1 << 0)
#define USBHS_ATTACH (1 << 1)
#define USBHS_SUSPEND (1 << 2)
#define USBHS_BUS_RESET (1 << 3)
#define USBHS_R_FIFO_RDY (1 << 4)
#define USBHS_SIE_FREE (1 << 5)
#define USBHS_SOF_ACT (1 << 6)
#define USBHS_SOF_PRES (1 << 7)
// INT_FLAG
#define USBHS_INT_FLAG_OFFSET 0x0A
#define USBHS_BUS_RST_FLAG (1 << 0)
#define USBHS_DETECT_FLAG (1 << 0)
#define USBHS_TRANSFER_FLAG (1 << 1)
#define USBHS_SUSPEND_FLAG (1 << 2)
#define USBHS_HST_SOF_FLAG (1 << 3)
#define USBHS_FIFO_OV_FLAG (1 << 4)
#define USBHS_SETUP_FLAG (1 << 5)
#define USBHS_ISO_ACT_FLAG (1 << 6)
// INT_ST
#define USBHS_INT_ST_OFFSET 0x0B
#define USBHS_DEV_UIS_IS_NAK (1 << 7)
#define USBHS_DEV_UIS_TOG_OK (1 << 6)
#define MASK_UIS_TOKEN (3 << 4)
#define MASK_UIS_ENDP (0x0F)
#define MASK_UIS_H_RES (0x0F)
#define USBHS_TOGGLE_OK (0x40)
#define USBHS_HOST_RES (0x0f)
//USB_RX_LEN
#define USBHS_RX_LEN_OFFSET 0x0C
/******************* DEVICE ******************/
//UEP_CONFIG
#define USBHS_UEP_CONFIG_OFFSET 0x10
#define USBHS_EP0_T_EN (1 << 0)
#define USBHS_EP0_R_EN (1 << 16)
#define USBHS_EP1_T_EN (1 << 1)
#define USBHS_EP1_R_EN (1 << 17)
#define USBHS_EP2_T_EN (1 << 2)
#define USBHS_EP2_R_EN (1 << 18)
#define USBHS_EP3_T_EN (1 << 3)
#define USBHS_EP3_R_EN (1 << 19)
#define USBHS_EP4_T_EN (1 << 4)
#define USBHS_EP4_R_EN (1 << 20)
#define USBHS_EP5_T_EN (1 << 5)
#define USBHS_EP5_R_EN (1 << 21)
#define USBHS_EP6_T_EN (1 << 6)
#define USBHS_EP6_R_EN (1 << 22)
#define USBHS_EP7_T_EN (1 << 7)
#define USBHS_EP7_R_EN (1 << 23)
#define USBHS_EP8_T_EN (1 << 8)
#define USBHS_EP8_R_EN (1 << 24)
#define USBHS_EP9_T_EN (1 << 9)
#define USBHS_EP9_R_EN (1 << 25)
#define USBHS_EP10_T_EN (1 << 10)
#define USBHS_EP10_R_EN (1 << 26)
#define USBHS_EP11_T_EN (1 << 11)
#define USBHS_EP11_R_EN (1 << 27)
#define USBHS_EP12_T_EN (1 << 12)
#define USBHS_EP12_R_EN (1 << 28)
#define USBHS_EP13_T_EN (1 << 13)
#define USBHS_EP13_R_EN (1 << 29)
#define USBHS_EP14_T_EN (1 << 14)
#define USBHS_EP14_R_EN (1 << 30)
#define USBHS_EP15_T_EN (1 << 15)
#define USBHS_EP15_R_EN (1 << 31)
//UEP_TYPE
#define USBHS_UEP_TYPE_OFFSET 0x14
#define USBHS_EP0_T_TYP (1 << 0)
#define USBHS_EP0_R_TYP (1 << 16)
#define USBHS_EP1_T_TYP (1 << 1)
#define USBHS_EP1_R_TYP (1 << 17)
#define USBHS_EP2_T_TYP (1 << 2)
#define USBHS_EP2_R_TYP (1 << 18)
#define USBHS_EP3_T_TYP (1 << 3)
#define USBHS_EP3_R_TYP (1 << 19)
#define USBHS_EP4_T_TYP (1 << 4)
#define USBHS_EP4_R_TYP (1 << 20)
#define USBHS_EP5_T_TYP (1 << 5)
#define USBHS_EP5_R_TYP (1 << 21)
#define USBHS_EP6_T_TYP (1 << 6)
#define USBHS_EP6_R_TYP (1 << 22)
#define USBHS_EP7_T_TYP (1 << 7)
#define USBHS_EP7_R_TYP (1 << 23)
#define USBHS_EP8_T_TYP (1 << 8)
#define USBHS_EP8_R_TYP (1 << 24)
#define USBHS_EP9_T_TYP (1 << 8)
#define USBHS_EP9_R_TYP (1 << 25)
#define USBHS_EP10_T_TYP (1 << 10)
#define USBHS_EP10_R_TYP (1 << 26)
#define USBHS_EP11_T_TYP (1 << 11)
#define USBHS_EP11_R_TYP (1 << 27)
#define USBHS_EP12_T_TYP (1 << 12)
#define USBHS_EP12_R_TYP (1 << 28)
#define USBHS_EP13_T_TYP (1 << 13)
#define USBHS_EP13_R_TYP (1 << 29)
#define USBHS_EP14_T_TYP (1 << 14)
#define USBHS_EP14_R_TYP (1 << 30)
#define USBHS_EP15_T_TYP (1 << 15)
#define USBHS_EP15_R_TYP (1 << 31)
/* BUF_MOD UEP1~15 */
#define USBHS_BUF_MOD_OFFSET 0x18
#define USBHS_EP0_BUF_MOD (1 << 0)
#define USBHS_EP0_ISO_BUF_MOD (1 << 16)
#define USBHS_EP1_BUF_MOD (1 << 1)
#define USBHS_EP1_ISO_BUF_MOD (1 << 17)
#define USBHS_EP2_BUF_MOD (1 << 2)
#define USBHS_EP2_ISO_BUF_MOD (1 << 18)
#define USBHS_EP3_BUF_MOD (1 << 3)
#define USBHS_EP3_ISO_BUF_MOD (1 << 19)
#define USBHS_EP4_BUF_MOD (1 << 4)
#define USBHS_EP4_ISO_BUF_MOD (1 << 20)
#define USBHS_EP5_BUF_MOD (1 << 5)
#define USBHS_EP5_ISO_BUF_MOD (1 << 21)
#define USBHS_EP6_BUF_MOD (1 << 6)
#define USBHS_EP6_ISO_BUF_MOD (1 << 22)
#define USBHS_EP7_BUF_MOD (1 << 7)
#define USBHS_EP7_ISO_BUF_MOD (1 << 23)
#define USBHS_EP8_BUF_MOD (1 << 8)
#define USBHS_EP8_ISO_BUF_MOD (1 << 24)
#define USBHS_EP9_BUF_MOD (1 << 9)
#define USBHS_EP9_ISO_BUF_MOD (1 << 25)
#define USBHS_EP10_BUF_MOD (1 << 10)
#define USBHS_EP10_ISO_BUF_MOD (1 << 26)
#define USBHS_EP11_BUF_MOD (1 << 11)
#define USBHS_EP11_ISO_BUF_MOD (1 << 27)
#define USBHS_EP12_BUF_MOD (1 << 12)
#define USBHS_EP12_ISO_BUF_MOD (1 << 28)
#define USBHS_EP13_BUF_MOD (1 << 13)
#define USBHS_EP13_ISO_BUF_MOD (1 << 29)
#define USBHS_EP14_BUF_MOD (1 << 14)
#define USBHS_EP14_ISO_BUF_MOD (1 << 30)
#define USBHS_EP15_BUF_MOD (1 << 15)
#define USBHS_EP15_ISO_BUF_MOD (1 << 31)
//USBHS_EPn_T_EN USBHS_EPn_R_EN USBHS_EPn_BUF_MOD 锟斤拷锟斤拷锟斤拷锟斤拷UEPn_DMA为锟斤拷始锟斤拷址锟缴碉拷锟斤拷锟斤拷锟斤拷锟<E68BB7>
// 0 0 x 锟剿点被锟斤拷锟矫拷未锟矫碉拷UEPn_*_DMA锟斤拷锟斤拷锟斤拷锟斤拷
// 1 0 0 锟斤拷锟秸拷OUT锟斤拷锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_RX_DMA
// 1 0 1 bUEPn_RX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA锟斤拷bUEPn_RX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA
// 0 1 0 锟斤拷锟斤拷(IN)锟斤拷锟斤拷锟斤拷锟阶碉拷址为UEPn_TX_DMA锟斤拷
// 0 1 1 bUEPn_TX_TOG[0]=0,使锟矫伙拷锟斤拷锟斤拷UEPn_TX_DMA锟斤拷bUEPn_TX_TOG[0]=1,使锟矫伙拷锟斤拷锟斤拷UEPn_RX_DMA
/* USB0_DMA */
#define USBHS_UEP0_DMA_OFFSET(n) (0x1C) // endpoint 0 DMA buffer address
/* USBX_RX_DMA */
#define USBHS_UEPx_RX_DMA_OFFSET(n) (0x1C + 4 * (n)) // endpoint x DMA buffer address
#define USBHS_UEPx_TX_DMA_OFFSET(n) (0x58 + 4 * (n)) // endpoint x DMA buffer address
#define USBHS_UEPx_MAX_LEN_OFFSET(n) (0x98 + 4 * (n)) // endpoint x DMA buffer address
#define USBHS_UEPx_T_LEN_OFFSET(n) (0xD8 + 4 * (n)) // endpoint x DMA buffer address
#define USBHS_UEPx_TX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 2) // endpoint x DMA buffer address
#define USBHS_UEPx_RX_CTRL_OFFSET(n) (0xD8 + 4 * (n) + 3) // endpoint x DMA buffer address
// UEPn_T_LEN
#define USBHS_EP_T_LEN_MASK (0x7FF)
//UEPn_TX_CTRL
#define USBHS_EP_T_RES_MASK (3 << 0)
#define USBHS_EP_T_RES_ACK (0 << 0)
#define USBHS_EP_T_RES_NYET (1 << 0)
#define USBHS_EP_T_RES_NAK (2 << 0)
#define USBHS_EP_T_RES_STALL (3 << 0)
#define USBHS_EP_T_TOG_MASK (3 << 3)
#define USBHS_EP_T_TOG_0 (0 << 3)
#define USBHS_EP_T_TOG_1 (1 << 3)
#define USBHS_EP_T_TOG_2 (2 << 3)
#define USBHS_EP_T_TOG_M (3 << 3)
#define USBHS_EP_T_AUTOTOG (1 << 5)
//UEPn_RX_CTRL
#define USBHS_EP_R_RES_MASK (3 << 0)
#define USBHS_EP_R_RES_ACK (0 << 0)
#define USBHS_EP_R_RES_NYET (1 << 0)
#define USBHS_EP_R_RES_NAK (2 << 0)
#define USBHS_EP_R_RES_STALL (3 << 0)
#define USBHS_EP_R_TOG_MASK (3 << 3)
#define USBHS_EP_R_TOG_0 (0 << 3)
#define USBHS_EP_R_TOG_1 (1 << 3)
#define USBHS_EP_R_TOG_2 (2 << 3)
#define USBHS_EP_R_TOG_M (3 << 3)
#define USBHS_EP_R_AUTOTOG (1 << 5)
#define USBHS_TOG_MATCH (1 << 6)
/******************* HOST ******************/
// USB HOST_CTRL
#define USBHS_SEND_BUS_RESET (1 << 0)
#define USBHS_SEND_BUS_SUSPEND (1 << 1)
#define USBHS_SEND_BUS_RESUME (1 << 2)
#define USBHS_REMOTE_WAKE (1 << 3)
#define USBHS_PHY_SUSPENDM (1 << 4)
#define USBHS_UH_SOFT_FREE (1 << 6)
#define USBHS_SEND_SOF_EN (1 << 7)
//UH_CONFIG
#define USBHS_HOST_TX_EN (1 << 3)
#define USBHS_HOST_RX_EN (1 << 18)
// HOST_EP_TYPE
#define USBHS_ENDP_TX_ISO (1 << 3)
#define USBHS_ENDP_RX_ISO (1 << (16 + 2))
// R32_UH_EP_PID
#define USBHS_HOST_MASK_TOKEN (0x0f)
#define USBHS_HOST_MASK_ENDP (0x0f << 4)
//R8_UH_RX_CTRL
#define USBHS_EP_R_RES_MASK (3 << 0)
#define USBHS_EP_R_RES_ACK (0 << 0)
#define USBHS_EP_R_RES_NYET (1 << 0)
#define USBHS_EP_R_RES_NAK (2 << 0)
#define USBHS_EP_R_RES_STALL (3 << 0)
#define USBHS_UH_R_RES_NO (1 << 2)
#define USBHS_UH_R_TOG_1 (1 << 3)
#define USBHS_UH_R_TOG_2 (2 << 3)
#define USBHS_UH_R_TOG_3 (3 << 3)
#define USBHS_UH_R_TOG_AUTO (1 << 5)
#define USBHS_UH_R_DATA_NO (1 << 6)
//R8_UH_TX_CTRL
#define USBHS_UH_T_RES_MASK (3 << 0)
#define USBHS_UH_T_RES_ACK (0 << 0)
#define USBHS_UH_T_RES_NYET (1 << 0)
#define USBHS_UH_T_RES_NAK (2 << 0)
#define USBHS_UH_T_RES_STALL (3 << 0)
#define USBHS_UH_T_RES_NO (1 << 2)
#define USBHS_UH_T_TOG_1 (1 << 3)
#define USBHS_UH_T_TOG_2 (2 << 3)
#define USBHS_UH_T_TOG_3 (3 << 3)
#define USBHS_UH_T_TOG_AUTO (1 << 5)
#define USBHS_UH_T_DATA_NO (1 << 6)
// 00: OUT, 01:SOF, 10:IN, 11:SETUP
#define PID_OUT 0
#define PID_SOF 1
#define PID_IN 2
#define PID_SETUP 3
#endif

View File

@ -0,0 +1,388 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2022 Greg Davill
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This file is part of the TinyUSB stack.
*/
#include "tusb_option.h"
#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32VF307)
#include "device/dcd.h"
#include "usb_ch32_usbhs_reg.h"
#include "core_riscv.h"
// Max number of bi-directional endpoints including EP0
#define EP_MAX 16
typedef struct {
uint8_t *buffer;
// tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
uint16_t total_len;
uint16_t queued_len;
uint16_t max_size;
bool short_packet;
} xfer_ctl_t;
#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
static xfer_ctl_t xfer_status[EP_MAX][2];
#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep)*2)
#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep)*4)
#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep)*4)
#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep)*2)
#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
/* Endpoint Buffer */
__attribute__((aligned(4))) uint8_t setup[8]; // ep0(64)
__attribute__((aligned(4))) uint8_t EP0_DatabufHD[64]; // ep0(64)
volatile uint8_t mps_over_flag = 0;
volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01;
void dcd_init(uint8_t rhport) {
(void)rhport;
memset(&xfer_status, 0, sizeof(xfer_status));
// usb_dc_low_level_init();
USBHSD->HOST_CTRL = 0x00;
USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
USBHSD->CONTROL = 0;
#if 1
USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
#else
USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
#endif
USBHSD->INT_EN = 0;
USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_DETECT_EN | USBHS_SUSPEND_EN;
/* ALL endpoint enable */
USBHSD->ENDP_CONFIG = 0xffffffff;
USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
USBHSD->ENDP_TYPE = 0x00;
USBHSD->BUF_MODE = 0x00;
USBHSD->UEP0_MAX_LEN = 64;
USBHSD->UEP0_DMA = (uint32_t)EP0_DatabufHD;
USBHSD->UEP0_TX_LEN = 0;
USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK;
USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
for (int ep = 1; ep < EP_MAX; ep++) {
EP_TX_LEN(ep) = 0;
EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
EP_RX_MAX_LEN(ep) = 512;
}
USBHSD->DEV_AD = 0;
USBHSD->CONTROL |= USBHS_DEV_PU_EN;
}
void dcd_int_enable(uint8_t rhport) {
(void)rhport;
NVIC_EnableIRQ(USBHS_IRQn);
}
void dcd_int_disable(uint8_t rhport) {
(void)rhport;
NVIC_DisableIRQ(USBHS_IRQn);
}
void dcd_edpt_close_all(uint8_t rhport) {
(void)rhport;
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
(void)dev_addr;
// Response with zlp status
dcd_edpt_xfer(rhport, 0x80, NULL, 0);
}
void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
(void)rhport;
if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
request->bRequest == TUSB_REQ_SET_ADDRESS) {
USBHSD->DEV_AD = (uint8_t)request->wValue;
}
EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK;
EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK;
}
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) {
(void)rhport;
uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
TU_ASSERT(epnum < EP_MAX);
xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
xfer->max_size = tu_edpt_packet_size(desc_edpt);
if (epnum != 0) {
if (tu_edpt_dir(desc_edpt->bEndpointAddress) == TUSB_DIR_OUT) {
EP_RX_CTRL(epnum) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_ACK;
} else {
EP_TX_LEN(epnum) = 0;
EP_TX_CTRL(epnum) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
}
}
return true;
}
int usbd_ep_close(const uint8_t ep) {
(void)ep;
return 0;
}
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
(void)rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
if (epnum == 0) {
if (dir == TUSB_DIR_OUT) {
USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL;
} else {
USBHSD->UEP0_TX_LEN = 0;
USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL;
}
} else {
if (dir == TUSB_DIR_OUT) {
EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL;
} else {
EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_STALL;
}
}
}
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
(void)rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
if (epnum == 0) {
if (dir == TUSB_DIR_OUT) {
USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
} else {
}
} else {
if (dir == TUSB_DIR_OUT) {
EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~(USBHS_EP_R_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_ACK;
} else {
EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK;
}
}
}
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
(void)rhport;
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
xfer->buffer = buffer;
// xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
xfer->total_len = total_bytes;
xfer->queued_len = 0;
xfer->short_packet = false;
// uint16_t num_packets = (total_bytes / xfer->max_size);
uint16_t short_packet_size = total_bytes % (xfer->max_size + 1);
// Zero-size packet is special case.
if (short_packet_size == 0 || (total_bytes == 0)) {
xfer->short_packet = true;
}
if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
if (!total_bytes) {
xfer->short_packet = true;
if (epnum == 0) {
USBHSD->UEP0_TX_LEN = 0;
USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
USBHS_Dev_Endp0_Tog ^= 1;
} else {
EP_TX_LEN(epnum) = 0;
EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
}
} else {
if (epnum == 0) {
xfer->queued_len += short_packet_size;
memcpy(&EP0_DatabufHD[0], buffer, short_packet_size);
USBHSD->UEP0_TX_LEN = short_packet_size;
USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
USBHS_Dev_Endp0_Tog ^= 1;
} else {
xfer->queued_len += short_packet_size;
EP_TX_DMA_ADDR(epnum) = (uint32_t)buffer;
USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << epnum);
EP_TX_LEN(epnum) = short_packet_size;
EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
}
}
} else { /* TUSB_DIR_OUT */
if (epnum == 0) {
uint32_t read_count = USBHSD->RX_LEN;
read_count = TU_MIN(read_count, total_bytes);
if ((total_bytes == 8)) {
read_count = 8;
memcpy(buffer, &EP0_DatabufHD[0], 8);
} else {
memcpy(buffer, &EP0_DatabufHD[0], read_count);
}
} else {
EP_RX_DMA_ADDR(epnum) = (uint32_t)xfer->buffer;
USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << epnum);
}
// usbd_ep_read(ep_addr, buffer, total_bytes, &ret_bytes);
}
return true;
}
static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size) {
// xfer->queued_len = xfer->total_len - remaining;
uint16_t remaining = xfer->total_len - xfer->queued_len;
uint16_t to_recv_size;
if (remaining <= xfer->max_size) {
// Avoid buffer overflow.
to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
} else {
// Room for full packet, choose recv_size based on what the microcontroller
// claims.
to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
}
if (to_recv_size) {
}
xfer->queued_len += xfer_size;
// Per USB spec, a short OUT packet (including length 0) is always
// indicative of the end of a transfer (at least for ctl, bulk, int).
xfer->short_packet = (xfer_size < xfer->max_size);
}
void dcd_int_handler(uint8_t rhport) {
(void)rhport;
uint32_t end_num, rx_token;
uint8_t intflag = 0;
intflag = USBHSD->INT_FG;
if (intflag & USBHS_TRANSFER_FLAG) {
end_num = (USBHSD->INT_ST) & MASK_UIS_ENDP;
rx_token = (((USBHSD->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03;
uint8_t endp = end_num | (rx_token == PID_IN ? TUSB_DIR_IN_MASK : 0);
xfer_ctl_t *xfer = XFER_CTL_BASE(end_num, tu_edpt_dir(endp));
if (rx_token == PID_OUT) {
uint16_t rx_len = USBHSD->RX_LEN;
receive_packet(xfer, rx_len);
if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
xfer->short_packet = false;
dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
}
if (end_num == 0) {
USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
}
} else if (rx_token == PID_IN) {
if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
xfer->short_packet = false;
xfer->total_len = 0;
dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
EP_TX_CTRL(end_num) = (EP_TX_CTRL(end_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK;
if (end_num == 0) {
}
} else {
dcd_edpt_xfer(0, endp, xfer->buffer + xfer->queued_len, xfer->total_len - xfer->queued_len);
}
}
USBHSD->INT_FG = USBHS_TRANSFER_FLAG; /* Clear flag */
} else if (intflag & USBHS_SETUP_FLAG) {
USBHS_Dev_Endp0_Tog = 1;
dcd_event_setup_received(0, EP0_DatabufHD, true);
USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
} else if (intflag & USBHS_DETECT_FLAG) {
USBHS_Dev_Endp0_Tog = 1;
xfer_status[0][TUSB_DIR_OUT].max_size = 64;
xfer_status[0][TUSB_DIR_IN].max_size = 64;
dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
USBHSD->DEV_AD = 0;
USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
USBHSD->INT_FG = USBHS_DETECT_FLAG; /* Clear flag */
} else if (intflag & USBHS_SUSPEND_FLAG) {
dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPEND };
dcd_event_handler(&event, true);
USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
}
}
#endif

View File

@ -149,6 +149,9 @@
// Allwinner
#define OPT_MCU_F1C100S 2100 ///< Allwinner F1C100s family
// WCH
#define OPT_MCU_CH32VF307 2200 ///< WCH CH32V307 config
// Helper to check if configured MCU is one of listed
// Apply _TU_CHECK_MCU with || as separator to list of input
#define _TU_CHECK_MCU(_m) (CFG_TUSB_MCU == _m)