From db60fa1c63ae58c205e43e144253dab6815bb2d1 Mon Sep 17 00:00:00 2001 From: Matthew Tran Date: Sun, 19 Nov 2023 18:26:40 -0800 Subject: [PATCH 1/9] add CH32V20x USB OTG/FS driver --- .gitignore | 1 + README.rst | 2 +- docs/reference/dependencies.rst | 1 + docs/reference/supported.rst | 6 +- examples/device/cdc_msc_freertos/skip.txt | 1 + .../device/hid_composite_freertos/skip.txt | 1 + examples/device/msc_dual_lun/skip.txt | 1 + examples/device/video_capture/skip.txt | 1 + hw/bsp/ch32v20x/boards/nanoch32v203/board.h | 17 + hw/bsp/ch32v20x/boards/nanoch32v203/board.mk | 5 + hw/bsp/ch32v20x/ch32v20x_conf.h | 36 + hw/bsp/ch32v20x/ch32v20x_it.h | 15 + hw/bsp/ch32v20x/core_riscv.h | 572 ++++++++++ hw/bsp/ch32v20x/family.c | 82 ++ hw/bsp/ch32v20x/family.mk | 50 + hw/bsp/ch32v20x/system_ch32v20x.c | 976 ++++++++++++++++++ hw/bsp/ch32v20x/system_ch32v20x.h | 29 + hw/bsp/ch32v20x/wch-riscv.cfg | 18 + hw/bsp/ch32v307/family.mk | 5 + hw/bsp/fomu/family.mk | 4 + hw/bsp/gd32vf103/family.mk | 5 + src/class/video/video_device.c | 2 +- src/common/tusb_mcu.h | 4 + src/portable/wch/ch32_usbfs_reg.h | 77 ++ src/portable/wch/dcd_ch32_usbfs.c | 304 ++++++ src/tusb_option.h | 1 + tools/get_deps.py | 3 + tools/iar_template.ipcf | 1 + 28 files changed, 2215 insertions(+), 5 deletions(-) create mode 100644 hw/bsp/ch32v20x/boards/nanoch32v203/board.h create mode 100644 hw/bsp/ch32v20x/boards/nanoch32v203/board.mk create mode 100644 hw/bsp/ch32v20x/ch32v20x_conf.h create mode 100644 hw/bsp/ch32v20x/ch32v20x_it.h create mode 100644 hw/bsp/ch32v20x/core_riscv.h create mode 100644 hw/bsp/ch32v20x/family.c create mode 100644 hw/bsp/ch32v20x/family.mk create mode 100644 hw/bsp/ch32v20x/system_ch32v20x.c create mode 100644 hw/bsp/ch32v20x/system_ch32v20x.h create mode 100644 hw/bsp/ch32v20x/wch-riscv.cfg create mode 100644 src/portable/wch/ch32_usbfs_reg.h create mode 100644 src/portable/wch/dcd_ch32_usbfs.c diff --git a/.gitignore b/.gitignore index 56ae7600f..7a37d65dc 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/README.rst b/README.rst index 8c3145d33..dbe75adc8 100644 --- a/README.rst +++ b/README.rst @@ -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 diff --git a/docs/reference/dependencies.rst b/docs/reference/dependencies.rst index 6ba6692e9..3a98594ff 100644 --- a/docs/reference/dependencies.rst +++ b/docs/reference/dependencies.rst @@ -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 diff --git a/docs/reference/supported.rst b/docs/reference/supported.rst index 7e7be25a4..3ca203e88 100644 --- a/docs/reference/supported.rst +++ b/docs/reference/supported.rst @@ -128,9 +128,9 @@ Supported MCUs +--------------+-----------------------+--------+------+-----------+-------------------+--------------+ | ValentyUSB | eptri | ✔ | ✖ | ✖ | eptri | | +--------------+-----------------------+--------+------+-----------+-------------------+--------------+ -| WCH | CH32V307 | ✔ | | ✔ | ch32v307 | | -| +-----------------------+--------+------+-----------+-------------------+--------------+ -| | CH32F20x | ✔ | | ✔ | ch32f205 | | +| WCH | CH32F20x | ✔ | | ✔ | ch32f205 | | +| | CH32V20x | ✔ | | ✖ | ch32v20x | | +| | CH32V307 | ✔ | | ✔ | ch32v307 | | +--------------+-----------------------+--------+------+-----------+-------------------+--------------+ diff --git a/examples/device/cdc_msc_freertos/skip.txt b/examples/device/cdc_msc_freertos/skip.txt index eb434c23b..457ddb760 100644 --- a/examples/device/cdc_msc_freertos/skip.txt +++ b/examples/device/cdc_msc_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:CH32V307 mcu:CXD56 mcu:F1C100S diff --git a/examples/device/hid_composite_freertos/skip.txt b/examples/device/hid_composite_freertos/skip.txt index a6f96b288..6aaa27661 100644 --- a/examples/device/hid_composite_freertos/skip.txt +++ b/examples/device/hid_composite_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:CH32V307 mcu:CXD56 mcu:F1C100S diff --git a/examples/device/msc_dual_lun/skip.txt b/examples/device/msc_dual_lun/skip.txt index a9e3a99b1..4d607dc05 100644 --- a/examples/device/msc_dual_lun/skip.txt +++ b/examples/device/msc_dual_lun/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:SAMD11 mcu:MKL25ZXX family:espressif diff --git a/examples/device/video_capture/skip.txt b/examples/device/video_capture/skip.txt index 5898664a2..714cabeec 100644 --- a/examples/device/video_capture/skip.txt +++ b/examples/device/video_capture/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:MSP430x5xx mcu:NUC121 mcu:SAMD11 diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.h b/hw/bsp/ch32v20x/boards/nanoch32v203/board.h new file mode 100644 index 000000000..c8d28d90f --- /dev/null +++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.h @@ -0,0 +1,17 @@ +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define LED_PORT GPIOA +#define LED_PIN GPIO_Pin_15 +#define LED_STATE_ON 0 +#define LED_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk b/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk new file mode 100644 index 000000000..75dc05457 --- /dev/null +++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk @@ -0,0 +1,5 @@ +CFLAGS += \ + -DCH32V20x_D6 + +SRC_S += \ + $(CH32V20X_SDK_SRC)/Startup/startup_ch32v20x_D6.S diff --git a/hw/bsp/ch32v20x/ch32v20x_conf.h b/hw/bsp/ch32v20x/ch32v20x_conf.h new file mode 100644 index 000000000..949297fe6 --- /dev/null +++ b/hw/bsp/ch32v20x/ch32v20x_conf.h @@ -0,0 +1,36 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : ch32v20x_conf.h + * Author : WCH + * Version : V1.0.0 + * Date : 2021/06/06 + * Description : Library configuration file. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __CH32V20x_CONF_H +#define __CH32V20x_CONF_H + +#include "ch32v20x_adc.h" +#include "ch32v20x_bkp.h" +#include "ch32v20x_can.h" +#include "ch32v20x_crc.h" +#include "ch32v20x_dbgmcu.h" +#include "ch32v20x_dma.h" +#include "ch32v20x_exti.h" +#include "ch32v20x_flash.h" +#include "ch32v20x_gpio.h" +#include "ch32v20x_i2c.h" +#include "ch32v20x_iwdg.h" +#include "ch32v20x_pwr.h" +#include "ch32v20x_rcc.h" +#include "ch32v20x_rtc.h" +#include "ch32v20x_spi.h" +#include "ch32v20x_tim.h" +#include "ch32v20x_usart.h" +#include "ch32v20x_wwdg.h" +#include "ch32v20x_it.h" +#include "ch32v20x_misc.h" + +#endif /* __CH32V20x_CONF_H */ diff --git a/hw/bsp/ch32v20x/ch32v20x_it.h b/hw/bsp/ch32v20x/ch32v20x_it.h new file mode 100644 index 000000000..e49c61ae2 --- /dev/null +++ b/hw/bsp/ch32v20x/ch32v20x_it.h @@ -0,0 +1,15 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : ch32v20x_it.h + * Author : WCH + * Version : V1.0.0 + * Date : 2021/06/06 + * Description : This file contains the headers of the interrupt handlers. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __CH32V20x_IT_H +#define __CH32V20x_IT_H + +#endif /* __CH32V20x_IT_H */ diff --git a/hw/bsp/ch32v20x/core_riscv.h b/hw/bsp/ch32v20x/core_riscv.h new file mode 100644 index 000000000..be1b52a6c --- /dev/null +++ b/hw/bsp/ch32v20x/core_riscv.h @@ -0,0 +1,572 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : core_riscv.h + * Author : WCH + * Version : V1.0.0 + * Date : 2021/06/06 + * Description : RISC-V Core Peripheral Access Layer Header File for CH32V20x +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __CORE_RISCV_H__ +#define __CORE_RISCV_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* IO definitions */ +#ifdef __cplusplus + #define __I volatile /* defines 'read only' permissions */ +#else + #define __I volatile const /* defines 'read only' permissions */ +#endif +#define __O volatile /* defines 'write only' permissions */ +#define __IO volatile /* defines 'read / write' permissions */ + +/* Standard Peripheral Library old types (maintained for legacy purpose) */ +typedef __I uint64_t vuc64; /* Read Only */ +typedef __I uint32_t vuc32; /* Read Only */ +typedef __I uint16_t vuc16; /* Read Only */ +typedef __I uint8_t vuc8; /* Read Only */ + +typedef const uint64_t uc64; /* Read Only */ +typedef const uint32_t uc32; /* Read Only */ +typedef const uint16_t uc16; /* Read Only */ +typedef const uint8_t uc8; /* Read Only */ + +typedef __I int64_t vsc64; /* Read Only */ +typedef __I int32_t vsc32; /* Read Only */ +typedef __I int16_t vsc16; /* Read Only */ +typedef __I int8_t vsc8; /* Read Only */ + +typedef const int64_t sc64; /* Read Only */ +typedef const int32_t sc32; /* Read Only */ +typedef const int16_t sc16; /* Read Only */ +typedef const int8_t sc8; /* Read Only */ + +typedef __IO uint64_t vu64; +typedef __IO uint32_t vu32; +typedef __IO uint16_t vu16; +typedef __IO uint8_t vu8; + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +typedef __IO int64_t vs64; +typedef __IO int32_t vs32; +typedef __IO int16_t vs16; +typedef __IO int8_t vs8; + +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; + +typedef enum {NoREADY = 0, READY = !NoREADY} ErrorStatus; + +typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; + +typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus; + +#define RV_STATIC_INLINE static inline + +/* memory mapped structure for Program Fast Interrupt Controller (PFIC) */ +typedef struct{ + __I uint32_t ISR[8]; + __I uint32_t IPR[8]; + __IO uint32_t ITHRESDR; + __IO uint32_t RESERVED; + __IO uint32_t CFGR; + __I uint32_t GISR; + __IO uint8_t VTFIDR[4]; + uint8_t RESERVED0[12]; + __IO uint32_t VTFADDR[4]; + uint8_t RESERVED1[0x90]; + __O uint32_t IENR[8]; + uint8_t RESERVED2[0x60]; + __O uint32_t IRER[8]; + uint8_t RESERVED3[0x60]; + __O uint32_t IPSR[8]; + uint8_t RESERVED4[0x60]; + __O uint32_t IPRR[8]; + uint8_t RESERVED5[0x60]; + __IO uint32_t IACTR[8]; + uint8_t RESERVED6[0xE0]; + __IO uint8_t IPRIOR[256]; + uint8_t RESERVED7[0x810]; + __IO uint32_t SCTLR; +}PFIC_Type; + +/* memory mapped structure for SysTick */ +typedef struct +{ + __IO uint32_t CTLR; + __IO uint32_t SR; + __IO uint64_t CNT; + __IO uint64_t CMP; +}SysTick_Type; + +#define PFIC ((PFIC_Type *) 0xE000E000 ) +#define NVIC PFIC +#define NVIC_KEY1 ((uint32_t)0xFA050000) +#define NVIC_KEY2 ((uint32_t)0xBCAF0000) +#define NVIC_KEY3 ((uint32_t)0xBEEF0000) + +#define SysTick ((SysTick_Type *) 0xE000F000) + +/********************************************************************* + * @fn __enable_irq + * + * @brief Enable Global Interrupt + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __enable_irq(void) +{ + __asm volatile ("csrw 0x800, %0" : : "r" (0x6088) ); +} + +/********************************************************************* + * @fn __disable_irq + * + * @brief Disable Global Interrupt + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __disable_irq(void) +{ + __asm volatile ("csrw 0x800, %0" : : "r" (0x6000) ); +} + +/********************************************************************* + * @fn __NOP + * + * @brief nop + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __NOP(void) +{ + __asm volatile ("nop"); +} + +/********************************************************************* + * @fn NVIC_EnableIRQ + * + * @brief Disable Interrupt + * + * @param IRQn - Interrupt Numbers + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->IENR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); +} + +/********************************************************************* + * @fn NVIC_DisableIRQ + * + * @brief Disable Interrupt + * + * @param IRQn - Interrupt Numbers + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->IRER[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); +} + +/********************************************************************* + * @fn NVIC_GetStatusIRQ + * + * @brief Get Interrupt Enable State + * + * @param IRQn - Interrupt Numbers + * + * @return 1 - Interrupt Pending Enable + * 0 - Interrupt Pending Disable + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t NVIC_GetStatusIRQ(IRQn_Type IRQn) +{ + return((uint32_t) ((NVIC->ISR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0)); +} + +/********************************************************************* + * @fn NVIC_GetPendingIRQ + * + * @brief Get Interrupt Pending State + * + * @param IRQn - Interrupt Numbers + * + * @return 1 - Interrupt Pending Enable + * 0 - Interrupt Pending Disable + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t) ((NVIC->IPR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0)); +} + +/********************************************************************* + * @fn NVIC_SetPendingIRQ + * + * @brief Set Interrupt Pending + * + * @param IRQn - Interrupt Numbers + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->IPSR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); +} + +/********************************************************************* + * @fn NVIC_ClearPendingIRQ + * + * @brief Clear Interrupt Pending + * + * @param IRQn - Interrupt Numbers + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->IPRR[((uint32_t)(IRQn) >> 5)] = (1 << ((uint32_t)(IRQn) & 0x1F)); +} + +/********************************************************************* + * @fn NVIC_GetActive + * + * @brief Get Interrupt Active State + * + * @param IRQn - Interrupt Numbers + * + * @return 1 - Interrupt Active + * 0 - Interrupt No Active + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn) +{ + return((uint32_t)((NVIC->IACTR[(uint32_t)(IRQn) >> 5] & (1 << ((uint32_t)(IRQn) & 0x1F)))?1:0)); +} + +/********************************************************************* + * @fn NVIC_SetPriority + * + * @brief Set Interrupt Priority + * + * @param IRQn - Interrupt Numbers + * priority - bit7 - Pre-emption Priority + * bit[6:5] - Subpriority + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint8_t priority) +{ + NVIC->IPRIOR[(uint32_t)(IRQn)] = priority; +} + +/********************************************************************* + * @fn __WFI + * + * @brief Wait for Interrupt + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFI(void) +{ + NVIC->SCTLR &= ~(1<<3); // wfi + asm volatile ("wfi"); +} + +/********************************************************************* + * @fn _SEV + * + * @brief Set Event + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void _SEV(void) +{ + uint32_t t; + + t = NVIC->SCTLR; + NVIC->SCTLR |= (1<<3)|(1<<5); + NVIC->SCTLR = (NVIC->SCTLR & ~(1<<5)) | ( t & (1<<5)); +} + +/********************************************************************* + * @fn _WFE + * + * @brief Wait for Events + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void _WFE(void) +{ + NVIC->SCTLR |= (1<<3); + asm volatile ("wfi"); +} + +/********************************************************************* + * @fn __WFE + * + * @brief Wait for Events + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void __WFE(void) +{ + _SEV(); + _WFE(); + _WFE(); +} + +/********************************************************************* + * @fn SetVTFIRQ + * + * @brief Set VTF Interrupt + * + * @param addr - VTF interrupt service function base address. + * IRQn - Interrupt Numbers + * num - VTF Interrupt Numbers + * NewState - DISABLE or ENABLE + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void SetVTFIRQ(uint32_t addr, IRQn_Type IRQn, uint8_t num, FunctionalState NewState){ + if(num > 3) return ; + + if (NewState != DISABLE) + { + NVIC->VTFIDR[num] = IRQn; + NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)|0x1); + } + else{ + NVIC->VTFIDR[num] = IRQn; + NVIC->VTFADDR[num] = ((addr&0xFFFFFFFE)&(~0x1)); + } +} + +/********************************************************************* + * @fn NVIC_SystemReset + * + * @brief Initiate a system reset request + * + * @return none + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE void NVIC_SystemReset(void) +{ + NVIC->CFGR = NVIC_KEY3|(1<<7); +} + +/********************************************************************* + * @fn __AMOADD_W + * + * @brief Atomic Add with 32bit value + * Atomically ADD 32bit value with value in memory using amoadd.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * value - value to be ADDed + * + * @return return memory value + add value + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOADD_W(volatile int32_t *addr, int32_t value) +{ + int32_t result; + + __asm volatile ("amoadd.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(value) : "memory"); + return *addr; +} + +/********************************************************************* + * @fn __AMOAND_W + * + * @brief Atomic And with 32bit value + * Atomically AND 32bit value with value in memory using amoand.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * value - value to be ANDed + * + * @return return memory value & and value + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOAND_W(volatile int32_t *addr, int32_t value) +{ + int32_t result; + + __asm volatile ("amoand.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(value) : "memory"); + return *addr; +} + +/********************************************************************* + * @fn __AMOMAX_W + * + * @brief Atomic signed MAX with 32bit value + * Atomically signed max compare 32bit value with value in memory using amomax.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * value - value to be compared + * + * @return the bigger value + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOMAX_W(volatile int32_t *addr, int32_t value) +{ + int32_t result; + + __asm volatile ("amomax.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(value) : "memory"); + return *addr; +} + +/********************************************************************* + * @fn __AMOMAXU_W + * + * @brief Atomic unsigned MAX with 32bit value + * Atomically unsigned max compare 32bit value with value in memory using amomaxu.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * value - value to be compared + * + * @return return the bigger value + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t __AMOMAXU_W(volatile uint32_t *addr, uint32_t value) +{ + uint32_t result; + + __asm volatile ("amomaxu.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(value) : "memory"); + return *addr; +} + +/********************************************************************* + * @fn __AMOMIN_W + * + * @brief Atomic signed MIN with 32bit value + * Atomically signed min compare 32bit value with value in memory using amomin.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * value - value to be compared + * + * @return the smaller value + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOMIN_W(volatile int32_t *addr, int32_t value) +{ + int32_t result; + + __asm volatile ("amomin.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(value) : "memory"); + return *addr; +} + +/********************************************************************* + * @fn __AMOMINU_W + * + * @brief Atomic unsigned MIN with 32bit value + * Atomically unsigned min compare 32bit value with value in memory using amominu.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * value - value to be compared + * + * @return the smaller value + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t __AMOMINU_W(volatile uint32_t *addr, uint32_t value) +{ + uint32_t result; + + __asm volatile ("amominu.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(value) : "memory"); + return *addr; +} + +/********************************************************************* + * @fn __AMOOR_W + * + * @brief Atomic OR with 32bit value + * Atomically OR 32bit value with value in memory using amoor.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * value - value to be ORed + * + * @return return memory value | and value + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOOR_W(volatile int32_t *addr, int32_t value) +{ + int32_t result; + + __asm volatile ("amoor.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(value) : "memory"); + return *addr; +} + +/********************************************************************* + * @fn __AMOSWAP_W + * + * @brief Atomically swap new 32bit value into memory using amoswap.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * newval - New value to be stored into the address + * + * @return return the original value in memory + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE uint32_t __AMOSWAP_W(volatile uint32_t *addr, uint32_t newval) +{ + uint32_t result; + + __asm volatile ("amoswap.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(newval) : "memory"); + return result; +} + +/********************************************************************* + * @fn __AMOXOR_W + * + * @brief Atomic XOR with 32bit value + * Atomically XOR 32bit value with value in memory using amoxor.d. + * + * @param addr - Address pointer to data, address need to be 4byte aligned + * value - value to be XORed + * + * @return return memory value ^ and value + */ +__attribute__( ( always_inline ) ) RV_STATIC_INLINE int32_t __AMOXOR_W(volatile int32_t *addr, int32_t value) +{ + int32_t result; + + __asm volatile ("amoxor.w %0, %2, %1" : \ + "=r"(result), "+A"(*addr) : "r"(value) : "memory"); + return *addr; +} + +/* Core_Exported_Functions */ +extern uint32_t __get_MSTATUS(void); +extern void __set_MSTATUS(uint32_t value); +extern uint32_t __get_MISA(void); +extern void __set_MISA(uint32_t value); +extern uint32_t __get_MTVEC(void); +extern void __set_MTVEC(uint32_t value); +extern uint32_t __get_MSCRATCH(void); +extern void __set_MSCRATCH(uint32_t value); +extern uint32_t __get_MEPC(void); +extern void __set_MEPC(uint32_t value); +extern uint32_t __get_MCAUSE(void); +extern void __set_MCAUSE(uint32_t value); +extern uint32_t __get_MTVAL(void); +extern void __set_MTVAL(uint32_t value); +extern uint32_t __get_MVENDORID(void); +extern uint32_t __get_MARCHID(void); +extern uint32_t __get_MIMPID(void); +extern uint32_t __get_MHARTID(void); +extern uint32_t __get_SP(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch32v20x/family.c b/hw/bsp/ch32v20x/family.c new file mode 100644 index 000000000..247dacde6 --- /dev/null +++ b/hw/bsp/ch32v20x/family.c @@ -0,0 +1,82 @@ +#include +#include "ch32v20x.h" +#include "bsp/board_api.h" +#include "board.h" + +__attribute__((interrupt)) +void USBHD_IRQHandler(void) { + tud_int_handler(0); +} + +#if CFG_TUSB_OS == OPT_OS_NONE + +volatile uint32_t system_ticks = 0; + +__attribute__((interrupt)) +void SysTick_Handler(void) { + SysTick->SR = 0; + system_ticks++; +} + +uint32_t SysTick_Config(uint32_t ticks) { + NVIC_EnableIRQ(SysTicK_IRQn); + SysTick->CTLR = 0; + SysTick->SR = 0; + SysTick->CNT = 0; + SysTick->CMP = ticks-1; + SysTick->CTLR = 0xF; + return 0; +} + +uint32_t board_millis(void) { + return system_ticks; +} + +#endif + +void board_init(void) { + __disable_irq(); + +#if CFG_TUSB_OS == OPT_OS_NONE + SysTick_Config(SystemCoreClock / 1000); +#endif + + switch (SystemCoreClock) { + case 48000000: RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div1); break; + case 96000000: RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div2); break; + case 144000000: RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_Div3); break; + default: TU_ASSERT(0,); break; + } + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_OTG_FS, ENABLE); + + LED_CLOCK_EN(); + GPIO_InitTypeDef GPIO_InitStructure = { + .GPIO_Pin = LED_PIN, + .GPIO_Mode = GPIO_Mode_Out_OD, + .GPIO_Speed = GPIO_Speed_50MHz, + }; + GPIO_Init(LED_PORT, &GPIO_InitStructure); + + __enable_irq(); + board_delay(2); +} + +void board_led_write(bool state) { + GPIO_WriteBit(LED_PORT, LED_PIN, state); +} + +uint32_t board_button_read(void) { + return false; +} + +int board_uart_read(uint8_t *buf, int len) { + (void) buf; + (void) len; + return 0; +} + +int board_uart_write(void const *buf, int len) { + (void) buf; + (void) len; + return len; +} diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk new file mode 100644 index 000000000..2d94f19fb --- /dev/null +++ b/hw/bsp/ch32v20x/family.mk @@ -0,0 +1,50 @@ +# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +CROSS_COMPILE ?= riscv-none-elf- + +# Submodules +CH32V20X_SDK = hw/mcu/wch/ch32v20x +DEPS_SUBMODULES += $(CH32V20X_SDK) + +# WCH-SDK paths +CH32V20X_SDK_SRC = $(CH32V20X_SDK)/EVT/EXAM/SRC + +include $(TOP)/$(BOARD_PATH)/board.mk + +CFLAGS += \ + -march=rv32imac_zicsr \ + -mabi=ilp32 \ + -mcmodel=medany \ + -ffunction-sections \ + -fdata-sections \ + -ffat-lto-objects \ + -flto \ + -nostdlib -nostartfiles \ + -DCFG_TUSB_MCU=OPT_MCU_CH32V20X \ + -DBOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED \ + +LDFLAGS_GCC += \ + -Wl,--gc-sections \ + -specs=nosys.specs \ + -specs=nano.specs \ + +LD_FILE = $(CH32V20X_SDK_SRC)/Ld/Link.ld + +SRC_C += \ + src/portable/wch/dcd_ch32_usbfs.c \ + $(CH32V20X_SDK_SRC)/Core/core_riscv.c \ + $(CH32V20X_SDK_SRC)/Peripheral/src/ch32v20x_gpio.c \ + $(CH32V20X_SDK_SRC)/Peripheral/src/ch32v20x_misc.c \ + $(CH32V20X_SDK_SRC)/Peripheral/src/ch32v20x_rcc.c \ + $(CH32V20X_SDK_SRC)/Peripheral/src/ch32v20x_usart.c \ + +INC += \ + $(TOP)/$(BOARD_PATH) \ + $(TOP)/$(CH32V20X_SDK_SRC)/Peripheral/inc \ + +FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V + +# wch-link is not supported yet in official openOCD yet. We need to either use +# 1. download openocd as part of mounriver studio http://www.mounriver.com/download or +# 2. compiled from modified source https://github.com/dragonlock2/miscboards/blob/main/wch/SDK/riscv-openocd.tar.xz +flash: $(BUILD)/$(PROJECT).elf + openocd -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "flash write_image $<" -c reset -c exit diff --git a/hw/bsp/ch32v20x/system_ch32v20x.c b/hw/bsp/ch32v20x/system_ch32v20x.c new file mode 100644 index 000000000..588f3165a --- /dev/null +++ b/hw/bsp/ch32v20x/system_ch32v20x.c @@ -0,0 +1,976 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : system_ch32v20x.c + * Author : WCH + * Version : V1.0.0 + * Date : 2021/06/06 + * Description : CH32V20x Device Peripheral Access Layer System Source File. + * For HSE = 32Mhz (CH32V208x/CH32V203RBT6) + * For HSE = 8Mhz (other CH32V203x) +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#include "ch32v20x.h" + +/* +* Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after +* reset the HSI is used as SYSCLK source). +* If none of the define below is enabled, the HSI is used as System clock source. +*/ +//#define SYSCLK_FREQ_HSE HSE_VALUE +//#define SYSCLK_FREQ_48MHz_HSE 48000000 +//#define SYSCLK_FREQ_56MHz_HSE 56000000 +//#define SYSCLK_FREQ_72MHz_HSE 72000000 +#define SYSCLK_FREQ_96MHz_HSE 96000000 +//#define SYSCLK_FREQ_120MHz_HSE 120000000 +//#define SYSCLK_FREQ_144MHz_HSE 144000000 +//#define SYSCLK_FREQ_HSI HSI_VALUE +//#define SYSCLK_FREQ_48MHz_HSI 48000000 +//#define SYSCLK_FREQ_56MHz_HSI 56000000 +//#define SYSCLK_FREQ_72MHz_HSI 72000000 +//#define SYSCLK_FREQ_96MHz_HSI 96000000 +//#define SYSCLK_FREQ_120MHz_HSI 120000000 +//#define SYSCLK_FREQ_144MHz_HSI 144000000 + +/* Clock Definitions */ +#ifdef SYSCLK_FREQ_HSE +uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_48MHz_HSE +uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSE; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_56MHz_HSE +uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSE; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_72MHz_HSE +uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSE; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_96MHz_HSE +uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSE; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_120MHz_HSE +uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSE; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_144MHz_HSE +uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSE; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_48MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz_HSI; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_56MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz_HSI; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_72MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz_HSI; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_96MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_96MHz_HSI; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_120MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_120MHz_HSI; /* System Clock Frequency (Core Clock) */ +#elif defined SYSCLK_FREQ_144MHz_HSI +uint32_t SystemCoreClock = SYSCLK_FREQ_144MHz_HSI; /* System Clock Frequency (Core Clock) */ +#else +uint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */ + +#endif + +__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; + +/* system_private_function_proto_types */ +static void SetSysClock(void); + +#ifdef SYSCLK_FREQ_HSE +static void SetSysClockToHSE( void ); +#elif defined SYSCLK_FREQ_48MHz_HSE +static void SetSysClockTo48_HSE( void ); +#elif defined SYSCLK_FREQ_56MHz_HSE +static void SetSysClockTo56_HSE( void ); +#elif defined SYSCLK_FREQ_72MHz_HSE +static void SetSysClockTo72_HSE( void ); +#elif defined SYSCLK_FREQ_96MHz_HSE +static void SetSysClockTo96_HSE( void ); +#elif defined SYSCLK_FREQ_120MHz_HSE +static void SetSysClockTo120_HSE( void ); +#elif defined SYSCLK_FREQ_144MHz_HSE +static void SetSysClockTo144_HSE( void ); +#elif defined SYSCLK_FREQ_48MHz_HSI +static void SetSysClockTo48_HSI( void ); +#elif defined SYSCLK_FREQ_56MHz_HSI +static void SetSysClockTo56_HSI( void ); +#elif defined SYSCLK_FREQ_72MHz_HSI +static void SetSysClockTo72_HSI( void ); +#elif defined SYSCLK_FREQ_96MHz_HSI +static void SetSysClockTo96_HSI( void ); +#elif defined SYSCLK_FREQ_120MHz_HSI +static void SetSysClockTo120_HSI( void ); +#elif defined SYSCLK_FREQ_144MHz_HSI +static void SetSysClockTo144_HSI( void ); + +#endif + +/********************************************************************* + * @fn SystemInit + * + * @brief Setup the microcontroller system Initialize the Embedded Flash Interface, + * the PLL and update the SystemCoreClock variable. + * + * @return none + */ +void SystemInit (void) +{ + RCC->CTLR |= (uint32_t)0x00000001; + RCC->CFGR0 &= (uint32_t)0xF8FF0000; + RCC->CTLR &= (uint32_t)0xFEF6FFFF; + RCC->CTLR &= (uint32_t)0xFFFBFFFF; + RCC->CFGR0 &= (uint32_t)0xFF80FFFF; + RCC->INTR = 0x009F0000; + SetSysClock(); +} + +/********************************************************************* + * @fn SystemCoreClockUpdate + * + * @brief Update SystemCoreClock variable according to Clock Register Values. + * + * @return none + */ +void SystemCoreClockUpdate (void) +{ + uint32_t tmp = 0, pllmull = 0, pllsource = 0, Pll_6_5 = 0; + + tmp = RCC->CFGR0 & RCC_SWS; + + switch (tmp) + { + case 0x00: + SystemCoreClock = HSI_VALUE; + break; + case 0x04: + SystemCoreClock = HSE_VALUE; + break; + case 0x08: + pllmull = RCC->CFGR0 & RCC_PLLMULL; + pllsource = RCC->CFGR0 & RCC_PLLSRC; + pllmull = ( pllmull >> 18) + 2; + + if(pllmull == 17) pllmull = 18; + + if (pllsource == 0x00) + { + if(EXTEN->EXTEN_CTR & EXTEN_PLL_HSI_PRE){ + SystemCoreClock = HSI_VALUE * pllmull; + } + else{ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + } + } + else + { +#if defined (CH32V20x_D8W) + if((RCC->CFGR0 & (3<<22)) == (3<<22)) + { + SystemCoreClock = ((HSE_VALUE>>1)) * pllmull; + } + else +#endif + if ((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET) + { +#if defined (CH32V20x_D8) || defined (CH32V20x_D8W) + SystemCoreClock = ((HSE_VALUE>>2) >> 1) * pllmull; +#else + SystemCoreClock = (HSE_VALUE >> 1) * pllmull; +#endif + } + else + { +#if defined (CH32V20x_D8) || defined (CH32V20x_D8W) + SystemCoreClock = (HSE_VALUE>>2) * pllmull; +#else + SystemCoreClock = HSE_VALUE * pllmull; +#endif + } + } + + if(Pll_6_5 == 1) SystemCoreClock = (SystemCoreClock / 2); + + break; + default: + SystemCoreClock = HSI_VALUE; + break; + } + + tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)]; + SystemCoreClock >>= tmp; +} + +/********************************************************************* + * @fn SetSysClock + * + * @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClock(void) +{ +#ifdef SYSCLK_FREQ_HSE + SetSysClockToHSE(); +#elif defined SYSCLK_FREQ_48MHz_HSE + SetSysClockTo48_HSE(); +#elif defined SYSCLK_FREQ_56MHz_HSE + SetSysClockTo56_HSE(); +#elif defined SYSCLK_FREQ_72MHz_HSE + SetSysClockTo72_HSE(); +#elif defined SYSCLK_FREQ_96MHz_HSE + SetSysClockTo96_HSE(); +#elif defined SYSCLK_FREQ_120MHz_HSE + SetSysClockTo120_HSE(); +#elif defined SYSCLK_FREQ_144MHz_HSE + SetSysClockTo144_HSE(); +#elif defined SYSCLK_FREQ_48MHz_HSI + SetSysClockTo48_HSI(); +#elif defined SYSCLK_FREQ_56MHz_HSI + SetSysClockTo56_HSI(); +#elif defined SYSCLK_FREQ_72MHz_HSI + SetSysClockTo72_HSI(); +#elif defined SYSCLK_FREQ_96MHz_HSI + SetSysClockTo96_HSI(); +#elif defined SYSCLK_FREQ_120MHz_HSI + SetSysClockTo120_HSI(); +#elif defined SYSCLK_FREQ_144MHz_HSI + SetSysClockTo144_HSI(); + +#endif + + /* If none of the define above is enabled, the HSI is used as System clock + * source (default after reset) + */ +} + +#ifdef SYSCLK_FREQ_HSE + +/********************************************************************* + * @fn SetSysClockToHSE + * + * @brief Sets HSE as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockToHSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1; + + /* Select HSE as system clock source + * CH32V20x_D6 (HSE=8MHZ) + * CH32V20x_D8 (HSE=32MHZ) + * CH32V20x_D8W (HSE=32MHZ) + */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_HSE; + + /* Wait till HSE is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04) + { + } + } + else + { + /* If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_FREQ_48MHz_HSE + +/********************************************************************* + * @fn SetSysClockTo48_HSE + * + * @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo48_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 6 = 48 MHz (HSE=8MHZ) + * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ) + * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 6 = 48 MHz (HSE=32MHZ) + */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL6); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + } + else + { + /* + * If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_FREQ_56MHz_HSE + +/********************************************************************* + * @fn SetSysClockTo56_HSE + * + * @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo56_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 7 = 56 MHz (HSE=8MHZ) + * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ) + * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 7 = 56 MHz (HSE=32MHZ) + */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL7); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + } + else + { + /* + * If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_FREQ_72MHz_HSE + +/********************************************************************* + * @fn SetSysClockTo72_HSE + * + * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo72_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 9 = 72 MHz (HSE=8MHZ) + * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ) + * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 9 = 72 MHz (HSE=32MHZ) + */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | + RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL9); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + } + else + { + /* + * If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_FREQ_96MHz_HSE + +/********************************************************************* + * @fn SetSysClockTo96_HSE + * + * @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo96_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 12 = 96 MHz (HSE=8MHZ) + * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ) + * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 12 = 96 MHz (HSE=32MHZ) + */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | + RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL12); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + } + else + { + /* + * If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_FREQ_120MHz_HSE + +/********************************************************************* + * @fn SetSysClockTo120_HSE + * + * @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo120_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if(HSEStatus == (uint32_t)0x01) + { +#if defined (CH32V20x_D8W) + RCC->CFGR0 |= (uint32_t)(3<<22); + /* HCLK = SYSCLK/2 */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV2; +#else + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; +#endif + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 15 = 120 MHz (HSE=8MHZ) + * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 15 = 120 MHz (HSE=32MHZ) + * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/2 * 15 = 240 MHz (HSE=32MHZ) + */ + RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE | + RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL15); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + } + else + { + /* + * If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} +#elif defined SYSCLK_FREQ_144MHz_HSE + +/********************************************************************* + * @fn SetSysClockTo144_HSE + * + * @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo144_HSE(void) +{ + __IO uint32_t StartUpCounter = 0, HSEStatus = 0; + + RCC->CTLR |= ((uint32_t)RCC_HSEON); + + /* Wait till HSE is ready and if Time out is reached exit */ + do + { + HSEStatus = RCC->CTLR & RCC_HSERDY; + StartUpCounter++; + } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); + + if ((RCC->CTLR & RCC_HSERDY) != RESET) + { + HSEStatus = (uint32_t)0x01; + } + else + { + HSEStatus = (uint32_t)0x00; + } + + if (HSEStatus == (uint32_t)0x01) + { + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* CH32V20x_D6-PLL configuration: PLLCLK = HSE * 18 = 144 MHz (HSE=8MHZ) + * CH32V20x_D8-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ) + * CH32V20x_D8W-PLL configuration: PLLCLK = HSE/4 * 18 = 144 MHz (HSE=32MHZ) + */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | + RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } + } + else + { + /* + * If HSE fails to start-up, the application will have wrong clock + * configuration. User can add here some code to deal with this error + */ + } +} + +#elif defined SYSCLK_FREQ_48MHz_HSI + +/********************************************************************* + * @fn SetSysClockTo48_HSI + * + * @brief Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo48_HSI(void) +{ + EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE; + + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* PLL configuration: PLLCLK = HSI * 6 = 48 MHz */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL6); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} + +#elif defined SYSCLK_FREQ_56MHz_HSI + +/********************************************************************* + * @fn SetSysClockTo56_HSI + * + * @brief Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo56_HSI(void) +{ + EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE; + + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* PLL configuration: PLLCLK = HSI * 7 = 48 MHz */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL7); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} + +#elif defined SYSCLK_FREQ_72MHz_HSI + +/********************************************************************* + * @fn SetSysClockTo72_HSI + * + * @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo72_HSI(void) +{ + EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE; + + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* PLL configuration: PLLCLK = HSI * 9 = 72 MHz */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL9); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} + +#elif defined SYSCLK_FREQ_96MHz_HSI + +/********************************************************************* + * @fn SetSysClockTo96_HSI + * + * @brief Sets System clock frequency to 96MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo96_HSI(void) +{ + EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE; + + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* PLL configuration: PLLCLK = HSI * 12 = 96 MHz */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL12); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} + +#elif defined SYSCLK_FREQ_120MHz_HSI + +/********************************************************************* + * @fn SetSysClockTo120_HSI + * + * @brief Sets System clock frequency to 120MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo120_HSI(void) +{ + EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE; + + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* PLL configuration: PLLCLK = HSI * 15 = 120 MHz */ + RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE | + RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL15); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} +#elif defined SYSCLK_FREQ_144MHz_HSI + +/********************************************************************* + * @fn SetSysClockTo144_HSI + * + * @brief Sets System clock frequency to 144MHz and configure HCLK, PCLK2 and PCLK1 prescalers. + * + * @return none + */ +static void SetSysClockTo144_HSI(void) +{ + EXTEN->EXTEN_CTR |= EXTEN_PLL_HSI_PRE; + + /* HCLK = SYSCLK */ + RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1; + /* PCLK2 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1; + /* PCLK1 = HCLK */ + RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2; + + /* PLL configuration: PLLCLK = HSI * 18 = 144 MHz */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL)); + + RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSI_Div2 | RCC_PLLMULL18); + + /* Enable PLL */ + RCC->CTLR |= RCC_PLLON; + /* Wait till PLL is ready */ + while((RCC->CTLR & RCC_PLLRDY) == 0) + { + } + /* Select PLL as system clock source */ + RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW)); + RCC->CFGR0 |= (uint32_t)RCC_SW_PLL; + /* Wait till PLL is used as system clock source */ + while ((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08) + { + } +} + +#endif diff --git a/hw/bsp/ch32v20x/system_ch32v20x.h b/hw/bsp/ch32v20x/system_ch32v20x.h new file mode 100644 index 000000000..eec7ccb15 --- /dev/null +++ b/hw/bsp/ch32v20x/system_ch32v20x.h @@ -0,0 +1,29 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : system_ch32v20x.h + * Author : WCH + * Version : V1.0.0 + * Date : 2021/06/06 + * Description : CH32V20x Device Peripheral Access Layer System Header File. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __SYSTEM_ch32v20x_H +#define __SYSTEM_ch32v20x_H + +#ifdef __cplusplus + extern "C" { +#endif + +extern uint32_t SystemCoreClock; /* System Clock Frequency (Core Clock) */ + +/* System_Exported_Functions */ +extern void SystemInit(void); +extern void SystemCoreClockUpdate(void); + +#ifdef __cplusplus +} +#endif + +#endif /*__CH32V20x_SYSTEM_H */ diff --git a/hw/bsp/ch32v20x/wch-riscv.cfg b/hw/bsp/ch32v20x/wch-riscv.cfg new file mode 100644 index 000000000..56a18d77e --- /dev/null +++ b/hw/bsp/ch32v20x/wch-riscv.cfg @@ -0,0 +1,18 @@ +#interface wlink +adapter driver wlinke +adapter speed 6000 +transport select sdi + +wlink_set_address 0x00000000 +set _CHIPNAME wch_riscv +sdi newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 wch_riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x20000000 -work-area-size 10000 -work-area-backup 1 +set _FLASHNAME $_CHIPNAME.flash + +flash bank $_FLASHNAME wch_riscv 0x00000000 0 0 0 $_TARGETNAME.0 + +echo "Ready for Remote Connections" diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk index 003b90539..7232bfa08 100644 --- a/hw/bsp/ch32v307/family.mk +++ b/hw/bsp/ch32v307/family.mk @@ -4,6 +4,9 @@ # Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack CROSS_COMPILE ?= riscv-none-embed- +# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +#CROSS_COMPILE ?= riscv-none-elf- + # Submodules CH32V307_SDK = hw/mcu/wch/ch32v307 @@ -13,6 +16,8 @@ CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= rv32imac-ilp32 +# -march=rv32imac_zicsr + CFLAGS += \ -flto \ -msmall-data-limit=8 \ diff --git a/hw/bsp/fomu/family.mk b/hw/bsp/fomu/family.mk index d4b6eaea6..78f20d7db 100644 --- a/hw/bsp/fomu/family.mk +++ b/hw/bsp/fomu/family.mk @@ -1,6 +1,10 @@ # Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack CROSS_COMPILE = riscv-none-embed- +# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +# CROSS_COMPILE = riscv-none-elf- +# -march=rv32i_zicsr + CPU_CORE ?= rv32i-ilp32 CFLAGS += \ diff --git a/hw/bsp/gd32vf103/family.mk b/hw/bsp/gd32vf103/family.mk index 28e48a6b5..646564eae 100644 --- a/hw/bsp/gd32vf103/family.mk +++ b/hw/bsp/gd32vf103/family.mk @@ -7,6 +7,9 @@ # Toolchain from https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack CROSS_COMPILE ?= riscv-none-embed- +# Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +# CROSS_COMPILE ?= riscv-none-elf- + # Submodules NUCLEI_SDK = hw/mcu/gd/nuclei-sdk @@ -19,6 +22,8 @@ STARTUP_ASM = $(GD32VF103_SDK_SOC)/Common/Source/GCC include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= rv32imac-ilp32 +# -march=rv32imac_zicsr + CFLAGS += \ -mcmodel=medlow \ -mstrict-align \ diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 4218835aa..974289b69 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -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; diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index 3a7d6ad33..eab112015 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -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 diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h new file mode 100644 index 000000000..3b8e49ae2 --- /dev/null +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -0,0 +1,77 @@ +#ifndef USB_CH32_USBFS_REG_H +#define USB_CH32_USBFS_REG_H + +#if (CFG_TUSB_MCU == OPT_MCU_CH32V20X) +#include +#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 diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c new file mode 100644 index 000000000..256c46696 --- /dev/null +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -0,0 +1,304 @@ +#include "tusb_option.h" + +#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32V20X) + +#include +#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) diff --git a/src/tusb_option.h b/src/tusb_option.h index 058427e0e..3d04825a4 100644 --- a/src/tusb_option.h +++ b/src/tusb_option.h @@ -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 diff --git a/tools/get_deps.py b/tools/get_deps.py index 87c1c5ccd..cf15126b3 100644 --- a/tools/get_deps.py +++ b/tools/get_deps.py @@ -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'], diff --git a/tools/iar_template.ipcf b/tools/iar_template.ipcf index e72ec0ce2..33a6ef045 100644 --- a/tools/iar_template.ipcf +++ b/tools/iar_template.ipcf @@ -239,6 +239,7 @@ $TUSB_DIR$/src/portable/valentyusb/eptri/dcd_eptri.h + $TUSB_DIR$/src/portable/wch/dcd_ch32_usbfs.c $TUSB_DIR$/src/portable/wch/dcd_ch32_usbhs.c $TUSB_DIR$/src/portable/wch/ch32_usbhs_reg.h From 2a67ce773dcd68f7f8c4c07fce2e6e4f7947e03d Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 15 May 2024 20:13:00 +0700 Subject: [PATCH 2/9] change default risv-gcc to riscv-none-elf- and add _zicsr extension add cmake for ch32v20x, skip freertos examples for CH32V20X, also skip net webserver due to lack of RAM update to use openocd with wlinke adapter --- .github/workflows/ci_set_matrix.py | 4 +- .idea/cmake.xml | 4 +- .../build_system/cmake/cpu/rv32i-ilp32.cmake | 4 +- .../cmake/cpu/rv32imac-ilp32.cmake | 4 +- .../cmake/toolchain/riscv_gcc.cmake | 19 ++- examples/build_system/make/cpu/rv32i-ilp32.mk | 11 +- .../build_system/make/cpu/rv32imac-ilp32.mk | 10 +- .../audio_4_channel_mic_freertos/skip.txt | 1 + examples/device/audio_test_freertos/skip.txt | 1 + examples/device/net_lwip_webserver/skip.txt | 1 + examples/device/video_capture_2ch/skip.txt | 1 + .../ch32v20x/boards/nanoch32v203/board.cmake | 7 ++ hw/bsp/ch32v20x/family.cmake | 109 ++++++++++++++++++ hw/bsp/ch32v20x/family.mk | 17 ++- hw/bsp/ch32v20x/wch-riscv.cfg | 1 - hw/bsp/ch32v307/family.cmake | 1 - hw/bsp/ch32v307/family.mk | 8 +- hw/bsp/ch32v307/wch-riscv.cfg | 16 +-- hw/bsp/family_support.cmake | 1 + hw/bsp/fomu/family.mk | 6 +- hw/bsp/gd32vf103/family.mk | 7 +- src/portable/wch/dcd_ch32_usbfs.c | 8 ++ 22 files changed, 191 insertions(+), 50 deletions(-) create mode 100644 hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake create mode 100644 hw/bsp/ch32v20x/family.cmake diff --git a/.github/workflows/ci_set_matrix.py b/.github/workflows/ci_set_matrix.py index 62239c9ad..c6f4e8fe2 100644 --- a/.github/workflows/ci_set_matrix.py +++ b/.github/workflows/ci_set_matrix.py @@ -7,14 +7,14 @@ toolchain_list = { "arm-iar": "", "arm-gcc": "", "msp430-gcc": "http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSPGCC/9_2_0_0/export/msp430-gcc-9.2.0.50_linux64.tar.bz2", - "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/download/v10.1.0-1.1/xpack-riscv-none-embed-gcc-10.1.0-1.1-linux-x64.tar.gz", + "riscv-gcc": "https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v13.2.0-2/xpack-riscv-none-elf-gcc-13.2.0-2-linux-x64.tar.gz" } # family: [supported toolchain] family_list = { "broadcom_32bit": ["arm-gcc"], "broadcom_64bit": ["aarch64-gcc"], - "ch32v307 fomu gd32vf103": ["riscv-gcc"], + "ch32v20x ch32v307 fomu gd32vf103": ["riscv-gcc"], "imxrt": ["arm-gcc", "arm-clang"], "kinetis_k kinetis_kl kinetis_k32l2": ["arm-gcc", "arm-clang"], "lpc11 lpc13 lpc15": ["arm-gcc", "arm-clang"], diff --git a/.idea/cmake.xml b/.idea/cmake.xml index bb13a0466..a34f19e1f 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -66,6 +66,7 @@ + @@ -103,6 +104,7 @@ + @@ -120,7 +122,6 @@ - @@ -130,6 +131,7 @@ + \ No newline at end of file diff --git a/examples/build_system/cmake/cpu/rv32i-ilp32.cmake b/examples/build_system/cmake/cpu/rv32i-ilp32.cmake index b4889e6ff..605c40ba1 100644 --- a/examples/build_system/cmake/cpu/rv32i-ilp32.cmake +++ b/examples/build_system/cmake/cpu/rv32i-ilp32.cmake @@ -1,13 +1,13 @@ if (TOOLCHAIN STREQUAL "gcc") set(TOOLCHAIN_COMMON_FLAGS - -march=rv32i + -march=rv32i_zicsr -mabi=ilp32 ) set(FREERTOS_PORT GCC_RISC_V CACHE INTERNAL "") elseif (TOOLCHAIN STREQUAL "clang") set(TOOLCHAIN_COMMON_FLAGS - -march=rv32i + -march=rv32i_zicsr -mabi=ilp32 ) set(FREERTOS_PORT GCC_RISC_V CACHE INTERNAL "") diff --git a/examples/build_system/cmake/cpu/rv32imac-ilp32.cmake b/examples/build_system/cmake/cpu/rv32imac-ilp32.cmake index dd1bc0af7..584d90519 100644 --- a/examples/build_system/cmake/cpu/rv32imac-ilp32.cmake +++ b/examples/build_system/cmake/cpu/rv32imac-ilp32.cmake @@ -1,13 +1,13 @@ if (TOOLCHAIN STREQUAL "gcc") set(TOOLCHAIN_COMMON_FLAGS - -march=rv32imac + -march=rv32imac_zicsr -mabi=ilp32 ) set(FREERTOS_PORT GCC_RISC_V CACHE INTERNAL "") elseif (TOOLCHAIN STREQUAL "clang") set(TOOLCHAIN_COMMON_FLAGS - -march=rv32imac + -march=rv32imac_zicsr -mabi=ilp32 ) set(FREERTOS_PORT GCC_RISC_V CACHE INTERNAL "") diff --git a/examples/build_system/cmake/toolchain/riscv_gcc.cmake b/examples/build_system/cmake/toolchain/riscv_gcc.cmake index 904b27294..d788df023 100644 --- a/examples/build_system/cmake/toolchain/riscv_gcc.cmake +++ b/examples/build_system/cmake/toolchain/riscv_gcc.cmake @@ -1,15 +1,24 @@ +# default Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack +if (NOT DEFINED CROSS_COMPILE) + set(CROSS_COMPILE "riscv-none-elf-") +endif () + if (NOT DEFINED CMAKE_C_COMPILER) - set(CMAKE_C_COMPILER "riscv-none-embed-gcc") + set(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc) +endif () + +if (NOT DEFINED CMAKE_C_COMPILER) + set(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc) endif () if (NOT DEFINED CMAKE_CXX_COMPILER) - set(CMAKE_CXX_COMPILER "riscv-none-embed-g++") + set(CMAKE_CXX_COMPILER ${CROSS_COMPILE}g++) endif () set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) -set(CMAKE_SIZE "riscv-none-embed-size" CACHE FILEPATH "") -set(CMAKE_OBJCOPY "riscv-none-embed-objcopy" CACHE FILEPATH "") -set(CMAKE_OBJDUMP "riscv-none-embed-objdump" CACHE FILEPATH "") +set(CMAKE_SIZE ${CROSS_COMPILE}size CACHE FILEPATH "") +set(CMAKE_OBJCOPY ${CROSS_COMPILE}objcopy CACHE FILEPATH "") +set(CMAKE_OBJDUMP ${CROSS_COMPILE}objdump CACHE FILEPATH "") include(${CMAKE_CURRENT_LIST_DIR}/common.cmake) diff --git a/examples/build_system/make/cpu/rv32i-ilp32.mk b/examples/build_system/make/cpu/rv32i-ilp32.mk index a465baf4c..af764afc5 100644 --- a/examples/build_system/make/cpu/rv32i-ilp32.mk +++ b/examples/build_system/make/cpu/rv32i-ilp32.mk @@ -1,12 +1,15 @@ ifeq ($(TOOLCHAIN),gcc) CFLAGS += \ - -march=rv32i \ + -march=rv32i_zicsr \ + -mabi=ilp32 \ + +else ifeq ($(TOOLCHAIN),clang) + CFLAGS += \ + -march=rv32i_zicsr \ -mabi=ilp32 \ else ifeq ($(TOOLCHAIN),iar) - #CFLAGS += --cpu cortex-a53 - #ASFLAGS += --cpu cortex-a53 - + $(error not support) endif # For freeRTOS port source diff --git a/examples/build_system/make/cpu/rv32imac-ilp32.mk b/examples/build_system/make/cpu/rv32imac-ilp32.mk index 2b6493e48..19c322ebc 100644 --- a/examples/build_system/make/cpu/rv32imac-ilp32.mk +++ b/examples/build_system/make/cpu/rv32imac-ilp32.mk @@ -1,11 +1,15 @@ ifeq ($(TOOLCHAIN),gcc) CFLAGS += \ - -march=rv32imac \ + -march=rv32imac_zicsr \ + -mabi=ilp32 \ + +else ifeq ($(TOOLCHAIN),clang) + CFLAGS += \ + -march=rv32imac_zicsr \ -mabi=ilp32 \ else ifeq ($(TOOLCHAIN),iar) - #CFLAGS += --cpu cortex-a53 - #ASFLAGS += --cpu cortex-a53 + $(error not support) endif diff --git a/examples/device/audio_4_channel_mic_freertos/skip.txt b/examples/device/audio_4_channel_mic_freertos/skip.txt index 0b689192d..4769af009 100644 --- a/examples/device/audio_4_channel_mic_freertos/skip.txt +++ b/examples/device/audio_4_channel_mic_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:CH32V307 mcu:CXD56 mcu:F1C100S diff --git a/examples/device/audio_test_freertos/skip.txt b/examples/device/audio_test_freertos/skip.txt index a6f96b288..6aaa27661 100644 --- a/examples/device/audio_test_freertos/skip.txt +++ b/examples/device/audio_test_freertos/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:CH32V307 mcu:CXD56 mcu:F1C100S diff --git a/examples/device/net_lwip_webserver/skip.txt b/examples/device/net_lwip_webserver/skip.txt index 43cdab71a..51af58667 100644 --- a/examples/device/net_lwip_webserver/skip.txt +++ b/examples/device/net_lwip_webserver/skip.txt @@ -1,3 +1,4 @@ +mcu:CH32V20X mcu:LPC11UXX mcu:LPC13XX mcu:LPC15XX diff --git a/examples/device/video_capture_2ch/skip.txt b/examples/device/video_capture_2ch/skip.txt index 86697899b..1786297f9 100644 --- a/examples/device/video_capture_2ch/skip.txt +++ b/examples/device/video_capture_2ch/skip.txt @@ -2,6 +2,7 @@ mcu:MSP430x5xx mcu:NUC121 mcu:SAMD11 mcu:GD32VF103 +mcu:CH32V20X mcu:CH32V307 mcu:STM32L0 family:espressif diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake b/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake new file mode 100644 index 000000000..2699f3e15 --- /dev/null +++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake @@ -0,0 +1,7 @@ +set(MCU_VARIANT D6) + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + CH32V20x_D6 + ) +endfunction() diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake new file mode 100644 index 000000000..fb39e3630 --- /dev/null +++ b/hw/bsp/ch32v20x/family.cmake @@ -0,0 +1,109 @@ +include_guard() + +set(CH32_FAMILY ch32v20x) +set(SDK_DIR ${TOP}/hw/mcu/wch/${CH32_FAMILY}/EVT/EXAM/SRC) + +# include board specific +include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) + +# toolchain set up +set(CMAKE_SYSTEM_PROCESSOR rv32imac-ilp32 CACHE INTERNAL "System Processor") +set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TOOLCHAIN}.cmake) + +set(FAMILY_MCUS CH32V20X CACHE INTERNAL "") +set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") + +#------------------------------------ +# BOARD_TARGET +#------------------------------------ +# only need to be built ONCE for all examples +function(add_board_target BOARD_TARGET) + if (TARGET ${BOARD_TARGET}) + return() + endif() + + if (NOT DEFINED LD_FILE_GNU) + set(LD_FILE_GNU ${SDK_DIR}/Ld/Link.ld) + endif () + set(LD_FILE_Clang ${LD_FILE_GNU}) + + if (NOT DEFINED STARTUP_FILE_GNU) + set(STARTUP_FILE_GNU ${SDK_DIR}/Startup/startup_${CH32_FAMILY}_${MCU_VARIANT}.S) + endif () + set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) + + add_library(${BOARD_TARGET} STATIC + ${SDK_DIR}/Core/core_riscv.c + ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_gpio.c + ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_misc.c + ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_rcc.c + ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_usart.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_${CH32_FAMILY}.c + ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} + ) + target_include_directories(${BOARD_TARGET} PUBLIC + ${SDK_DIR}/Peripheral/inc + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ) + target_compile_definitions(${BOARD_TARGET} PUBLIC + BOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED + ) + + update_board(${BOARD_TARGET}) + + if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + target_compile_options(${BOARD_TARGET} PUBLIC + -mcmodel=medany + ) + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--script=${LD_FILE_GNU}" + -nostartfiles + --specs=nosys.specs --specs=nano.specs + ) + elseif (CMAKE_C_COMPILER_ID STREQUAL "Clang") + message(FATAL_ERROR "Clang is not supported for MSP432E4") + elseif (CMAKE_C_COMPILER_ID STREQUAL "IAR") + target_link_options(${BOARD_TARGET} PUBLIC + "LINKER:--config=${LD_FILE_IAR}" + ) + endif () +endfunction() + + +#------------------------------------ +# Functions +#------------------------------------ +function(family_configure_example TARGET RTOS) + family_configure_common(${TARGET} ${RTOS}) + + # Board target + add_board_target(board_${BOARD}) + + #---------- Port Specific ---------- + # These files are built for each example since it depends on example's tusb_config.h + target_sources(${TARGET} PUBLIC + # BSP + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/family.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../board.c + ) + target_include_directories(${TARGET} PUBLIC + # family, hw, board + ${CMAKE_CURRENT_FUNCTION_LIST_DIR} + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../../ + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/boards/${BOARD} + ) + + # Add TinyUSB target and port source + family_add_tinyusb(${TARGET} OPT_MCU_CH32V20X ${RTOS}) + target_sources(${TARGET}-tinyusb PUBLIC + ${TOP}/src/portable/wch/dcd_ch32_usbfs.c + ) + target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) + + # Link dependencies + target_link_libraries(${TARGET} PUBLIC board_${BOARD} ${TARGET}-tinyusb) + + # Flashing + family_add_bin_hex(${TARGET}) + family_flash_openocd_wch(${TARGET}) +endfunction() diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk index 2d94f19fb..7e290bb18 100644 --- a/hw/bsp/ch32v20x/family.mk +++ b/hw/bsp/ch32v20x/family.mk @@ -1,3 +1,9 @@ +# https://www.embecosm.com/resources/tool-chain-downloads/#riscv-stable +#CROSS_COMPILE ?= riscv32-unknown-elf- + +# Toolchain from https://nucleisys.com/download.php +#CROSS_COMPILE ?= riscv-nuclei-elf- + # Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack CROSS_COMPILE ?= riscv-none-elf- @@ -9,23 +15,21 @@ DEPS_SUBMODULES += $(CH32V20X_SDK) CH32V20X_SDK_SRC = $(CH32V20X_SDK)/EVT/EXAM/SRC include $(TOP)/$(BOARD_PATH)/board.mk +CPU_CORE ?= rv32imac-ilp32 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 \ + -nostdlib -nostartfiles \ + --specs=nosys.specs --specs=nano.specs \ LD_FILE = $(CH32V20X_SDK_SRC)/Ld/Link.ld @@ -46,5 +50,6 @@ 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 +OPENOCD ?= $(HOME)/app/riscv-openocd-wch/src/openocd flash: $(BUILD)/$(PROJECT).elf - openocd -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "flash write_image $<" -c reset -c exit + $(OPENOCD) -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "flash write_image $<" -c reset -c exit diff --git a/hw/bsp/ch32v20x/wch-riscv.cfg b/hw/bsp/ch32v20x/wch-riscv.cfg index 56a18d77e..aa35aa9c5 100644 --- a/hw/bsp/ch32v20x/wch-riscv.cfg +++ b/hw/bsp/ch32v20x/wch-riscv.cfg @@ -1,4 +1,3 @@ -#interface wlink adapter driver wlinke adapter speed 6000 transport select sdi diff --git a/hw/bsp/ch32v307/family.cmake b/hw/bsp/ch32v307/family.cmake index 87a0f2eba..fb478d387 100644 --- a/hw/bsp/ch32v307/family.cmake +++ b/hw/bsp/ch32v307/family.cmake @@ -11,7 +11,6 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TO set(FAMILY_MCUS CH32V307 CACHE INTERNAL "") set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") -set(OPENOCD_OPTION2 "-c wlink_reset_resume") #------------------------------------ # BOARD_TARGET diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk index 7232bfa08..df9ded4a0 100644 --- a/hw/bsp/ch32v307/family.mk +++ b/hw/bsp/ch32v307/family.mk @@ -1,11 +1,11 @@ # 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- +# Toolchain from https://nucleisys.com/download.php +#CROSS_COMPILE ?= riscv-nuclei-elf- # Toolchain from https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack -#CROSS_COMPILE ?= riscv-none-elf- +CROSS_COMPILE ?= riscv-none-elf- # Submodules CH32V307_SDK = hw/mcu/wch/ch32v307 @@ -16,8 +16,6 @@ CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= rv32imac-ilp32 -# -march=rv32imac_zicsr - CFLAGS += \ -flto \ -msmall-data-limit=8 \ diff --git a/hw/bsp/ch32v307/wch-riscv.cfg b/hw/bsp/ch32v307/wch-riscv.cfg index 0d24d16ca..aa35aa9c5 100644 --- a/hw/bsp/ch32v307/wch-riscv.cfg +++ b/hw/bsp/ch32v307/wch-riscv.cfg @@ -1,13 +1,15 @@ -#interface wlink -adapter driver wlink -wlink_set -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x00001 +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 riscv -chain-position $_TARGETNAME -$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 +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 diff --git a/hw/bsp/family_support.cmake b/hw/bsp/family_support.cmake index df4f616ef..6eef5b88b 100644 --- a/hw/bsp/family_support.cmake +++ b/hw/bsp/family_support.cmake @@ -440,6 +440,7 @@ function(family_flash_openocd TARGET) endfunction() # Add flash openocd-wch target +# compiled from https://github.com/hathach/riscv-openocd-wch or https://github.com/dragonlock2/miscboards/blob/main/wch/SDK/riscv-openocd.tar.xz function(family_flash_openocd_wch TARGET) if (NOT DEFINED OPENOCD) set(OPENOCD $ENV{HOME}/app/riscv-openocd-wch/src/openocd) diff --git a/hw/bsp/fomu/family.mk b/hw/bsp/fomu/family.mk index 78f20d7db..69a546964 100644 --- a/hw/bsp/fomu/family.mk +++ b/hw/bsp/fomu/family.mk @@ -1,9 +1,5 @@ -# 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 +CROSS_COMPILE = riscv-none-elf- CPU_CORE ?= rv32i-ilp32 diff --git a/hw/bsp/gd32vf103/family.mk b/hw/bsp/gd32vf103/family.mk index 646564eae..48588886c 100644 --- a/hw/bsp/gd32vf103/family.mk +++ b/hw/bsp/gd32vf103/family.mk @@ -4,11 +4,8 @@ # Toolchain from https://nucleisys.com/download.php #CROSS_COMPILE ?= riscv-nuclei-elf- -# 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- +CROSS_COMPILE ?= riscv-none-elf- # Submodules NUCLEI_SDK = hw/mcu/gd/nuclei-sdk @@ -22,8 +19,6 @@ 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 \ diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 256c46696..83f625e21 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -201,6 +201,14 @@ void dcd_disconnect(uint8_t rhport) { USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN; } +void dcd_sof_enable(uint8_t rhport, bool en) +{ + (void) rhport; + (void) en; + + // TODO implement later +} + 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 && From ab5f2768773634efe8c79add7e009e2e2ca63279 Mon Sep 17 00:00:00 2001 From: Matthew Tran Date: Fri, 17 May 2024 09:52:06 -0700 Subject: [PATCH 3/9] fix ep0 stall not clearing --- src/portable/wch/dcd_ch32_usbfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 83f625e21..3af3ff6d7 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -148,6 +148,8 @@ void dcd_int_handler(uint8_t rhport) { case PID_SETUP: data.ep0_tog = true; + dcd_edpt_clear_stall(rhport, tu_edpt_addr(0, TUSB_DIR_IN)); // setup clears stall + dcd_edpt_clear_stall(rhport, tu_edpt_addr(0, TUSB_DIR_OUT)); dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true); break; } @@ -261,10 +263,12 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to uint8_t dir = tu_edpt_dir(ep_addr); struct usb_xfer *xfer = &data.xfer[ep][dir]; + dcd_int_disable(rhport); xfer->valid = true; xfer->buffer = buffer; xfer->len = total_bytes; xfer->processed_len = 0; + dcd_int_enable(rhport); if (dir == TUSB_DIR_IN) { update_in(rhport, ep, true); From 5fee292606e4c5502b2172328c02d5df24eb0c7c Mon Sep 17 00:00:00 2001 From: hathach Date: Fri, 17 May 2024 16:13:59 +0700 Subject: [PATCH 4/9] temp code --- hw/bsp/ch32v307/family.c | 25 +++++++++++++++++++++++++ hw/bsp/ch32v307/family.cmake | 23 ++++++++++++++--------- src/common/tusb_mcu.h | 4 ++-- src/portable/wch/ch32_usbfs_reg.h | 9 ++++++++- src/portable/wch/dcd_ch32_usbfs.c | 2 +- 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/hw/bsp/ch32v307/family.c b/hw/bsp/ch32v307/family.c index 245fa5674..50e48e7df 100644 --- a/hw/bsp/ch32v307/family.c +++ b/hw/bsp/ch32v307/family.c @@ -46,6 +46,18 @@ __attribute__ ((used)) void USBHS_IRQHandler_impl (void) tud_int_handler(0); } + +void OTG_FS_IRQHandler (void) __attribute__((naked)); +void OTG_FS_IRQHandler (void) +{ + __asm volatile ("call OTG_FS_IRQHandler_impl; mret"); +} + +__attribute__ ((used)) void OTG_FS_IRQHandler_impl (void) +{ + tud_int_handler(0); +} + //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ @@ -72,6 +84,7 @@ void board_init(void) { usart_printf_init(115200); + #if 0 RCC_USBCLK48MConfig(RCC_USBCLK48MCLKSource_USBPHY); RCC_USBHSPLLCLKConfig(RCC_HSBHSPLLCLKSource_HSE); RCC_USBHSConfig(RCC_USBPLL_Div2); @@ -79,6 +92,18 @@ void board_init(void) { RCC_USBHSPHYPLLALIVEcmd(ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHS, ENABLE); + #else + uint8_t otg_div; + switch (SystemCoreClock) { + case 48000000: otg_div = RCC_OTGFSCLKSource_PLLCLK_Div1; break; + case 96000000: otg_div = RCC_OTGFSCLKSource_PLLCLK_Div2; break; + case 144000000: otg_div = RCC_OTGFSCLKSource_PLLCLK_Div3; break; + default: TU_ASSERT(0,); break; + } + RCC_OTGFSCLKConfig(otg_div); + RCC_AHBPeriphClockCmd(RCC_AHBPeriph_OTG_FS, ENABLE); + #endif + GPIO_InitTypeDef GPIO_InitStructure = {0}; // LED diff --git a/hw/bsp/ch32v307/family.cmake b/hw/bsp/ch32v307/family.cmake index fb478d387..8a4bd7730 100644 --- a/hw/bsp/ch32v307/family.cmake +++ b/hw/bsp/ch32v307/family.cmake @@ -1,5 +1,6 @@ include_guard() +set(CH32_FAMILY ch32v30x) set(SDK_DIR ${TOP}/hw/mcu/wch/ch32v307/EVT/EXAM/SRC) # include board specific @@ -12,6 +13,8 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TO set(FAMILY_MCUS CH32V307 CACHE INTERNAL "") set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") +# Port0 Fullspeed, Port1 Highspeed + #------------------------------------ # BOARD_TARGET #------------------------------------ @@ -27,18 +30,18 @@ function(add_board_target BOARD_TARGET) set(LD_FILE_Clang ${LD_FILE_GNU}) if (NOT DEFINED STARTUP_FILE_GNU) - set(STARTUP_FILE_GNU ${SDK_DIR}/Startup/startup_ch32v30x_D8C.S) + set(STARTUP_FILE_GNU ${SDK_DIR}/Startup/startup_${CH32_FAMILY}_D8C.S) endif () set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) add_library(${BOARD_TARGET} STATIC ${SDK_DIR}/Core/core_riscv.c - ${SDK_DIR}/Peripheral/src/ch32v30x_gpio.c - ${SDK_DIR}/Peripheral/src/ch32v30x_misc.c - ${SDK_DIR}/Peripheral/src/ch32v30x_rcc.c - ${SDK_DIR}/Peripheral/src/ch32v30x_usart.c - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/ch32v30x_it.c - ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_ch32v30x.c + ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_gpio.c + ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_misc.c + ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_rcc.c + ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_usart.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${CH32_FAMILY}_it.c + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_${CH32_FAMILY}.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${BOARD_TARGET} PUBLIC @@ -46,7 +49,8 @@ function(add_board_target BOARD_TARGET) ${CMAKE_CURRENT_FUNCTION_LIST_DIR} ) target_compile_definitions(${BOARD_TARGET} PUBLIC - BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + #BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + BOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED ) update_board(${BOARD_TARGET}) @@ -100,7 +104,8 @@ function(family_configure_example TARGET RTOS) # Add TinyUSB target and port source family_add_tinyusb(${TARGET} OPT_MCU_CH32V307 ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC - ${TOP}/src/portable/wch/dcd_ch32_usbhs.c + #${TOP}/src/portable/wch/dcd_ch32_usbhs.c + ${TOP}/src/portable/wch/dcd_ch32_usbfs.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index eab112015..e313fea05 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -404,8 +404,8 @@ //------------- WCH -------------// #elif TU_CHECK_MCU(OPT_MCU_CH32V307) - #define TUP_DCD_ENDPOINT_MAX 16 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_DCD_ENDPOINT_MAX 8 +// #define TUP_RHPORT_HIGHSPEED 1 #elif TU_CHECK_MCU(OPT_MCU_CH32F20X) #define TUP_DCD_ENDPOINT_MAX 16 diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index 3b8e49ae2..d5341f3a8 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -1,8 +1,15 @@ #ifndef USB_CH32_USBFS_REG_H #define USB_CH32_USBFS_REG_H -#if (CFG_TUSB_MCU == OPT_MCU_CH32V20X) +#if (CFG_TUSB_MCU == OPT_MCU_CH32V307) +#include +#define USBHD_IRQn OTG_FS_IRQn + +#elif (CFG_TUSB_MCU == OPT_MCU_CH32V20X) #include + +#elif (CFG_TUSB_MCU == OPT_MCU_CH32F20X) +#include #endif // CTRL diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 3af3ff6d7..3e4b6cae5 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -1,6 +1,6 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32V20X) +#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32V20X || CFG_TUSB_MCU == OPT_MCU_CH32V307) #include #include "device/dcd.h" From 4a5fee503b1e3783301cde9b605ef30052623327 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 20 May 2024 13:24:24 +0700 Subject: [PATCH 5/9] - update ch203 family to allow to specify flash and ram size. Introduce - add ch32v203_ro_1v0 board - CFG_EXAMPLE_MSC_DUAL_READONLY to build msc_dual_lun for ch32v203 --- examples/device/msc_dual_lun/skip.txt | 1 - .../device/msc_dual_lun/src/msc_disk_dual.c | 85 ++++++++----------- .../boards/ch32v203_r0_1v0/board.cmake | 10 +++ .../ch32v20x/boards/ch32v203_r0_1v0/board.h | 17 ++++ .../ch32v20x/boards/ch32v203_r0_1v0/board.mk | 7 ++ .../ch32v20x/boards/nanoch32v203/board.cmake | 5 +- hw/bsp/ch32v20x/boards/nanoch32v203/board.mk | 10 ++- hw/bsp/ch32v20x/family.cmake | 22 +++-- hw/bsp/ch32v20x/family.mk | 27 +++--- hw/bsp/ch32v20x/linker/ch32v20x.ld | 1 + 10 files changed, 106 insertions(+), 79 deletions(-) create mode 100644 hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.cmake create mode 100644 hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.h create mode 100644 hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.mk create mode 100644 hw/bsp/ch32v20x/linker/ch32v20x.ld diff --git a/examples/device/msc_dual_lun/skip.txt b/examples/device/msc_dual_lun/skip.txt index 4d607dc05..a9e3a99b1 100644 --- a/examples/device/msc_dual_lun/skip.txt +++ b/examples/device/msc_dual_lun/skip.txt @@ -1,4 +1,3 @@ -mcu:CH32V20X mcu:SAMD11 mcu:MKL25ZXX family:espressif diff --git a/examples/device/msc_dual_lun/src/msc_disk_dual.c b/examples/device/msc_dual_lun/src/msc_disk_dual.c index 4f0f6410f..81f1d3346 100644 --- a/examples/device/msc_dual_lun/src/msc_disk_dual.c +++ b/examples/device/msc_dual_lun/src/msc_disk_dual.c @@ -34,9 +34,13 @@ // Some MCU doesn't have enough 8KB SRAM to store the whole disk // We will use Flash as read-only disk with board that has // CFG_EXAMPLE_MSC_READONLY defined +#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY) + #define MSC_CONST const +#else + #define MSC_CONST +#endif -enum -{ +enum { DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount DISK_BLOCK_SIZE = 512 }; @@ -51,10 +55,7 @@ If you find any bugs or get any questions, feel free to file an\r\n\ issue at github.com/hathach/tinyusb" -#ifdef CFG_EXAMPLE_MSC_READONLY -const -#endif -uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = +MSC_CONST uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { //------------- Block0: Boot Sector -------------// // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; @@ -132,10 +133,7 @@ uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = If you find any bugs or get any questions, feel free to file an\r\n\ issue at github.com/hathach/tinyusb" -#ifdef CFG_EXAMPLE_MSC_READONLY -const -#endif -uint8_t msc_disk1[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = +MSC_CONST uint8_t msc_disk1[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = { //------------- Block0: Boot Sector -------------// // byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM; @@ -206,15 +204,13 @@ uint8_t msc_disk1[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] = }; // Invoked to determine max LUN -uint8_t tud_msc_get_maxlun_cb(void) -{ +uint8_t tud_msc_get_maxlun_cb(void) { return 2; // dual LUN } // Invoked when received SCSI_CMD_INQUIRY // Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively -void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) -{ +void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) { (void) lun; // use same ID for both LUNs const char vid[] = "TinyUSB"; @@ -228,8 +224,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 // Invoked when received Test Unit Ready command. // return true allowing host to read/write this LUN e.g SD card inserted -bool tud_msc_test_unit_ready_cb(uint8_t lun) -{ +bool tud_msc_test_unit_ready_cb(uint8_t lun) { if ( lun == 1 && board_button_read() ) return false; return true; // RAM disk is always ready @@ -237,8 +232,7 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) // Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size // Application update block count and block size -void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) -{ +void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) { (void) lun; *block_count = DISK_BLOCK_NUM; @@ -248,18 +242,14 @@ void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_siz // Invoked when received Start Stop Unit command // - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage // - Start = 1 : active mode, if load_eject = 1 : load disk storage -bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) -{ +bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) { (void) lun; (void) power_condition; - if ( load_eject ) - { - if (start) - { + if (load_eject) { + if (start) { // load disk storage - }else - { + } else { // unload disk storage } } @@ -269,10 +259,9 @@ bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, boo // Callback invoked when received READ10 command. // Copy disk's data to buffer (up to bufsize) and return number of copied bytes. -int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) -{ +int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) { // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) return -1; + if (lba >= DISK_BLOCK_NUM) return -1; uint8_t const* addr = (lun ? msc_disk1[lba] : msc_disk0[lba]) + offset; memcpy(buffer, addr, bufsize); @@ -280,11 +269,10 @@ int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buff return (int32_t) bufsize; } -bool tud_msc_is_writable_cb (uint8_t lun) -{ +bool tud_msc_is_writable_cb(uint8_t lun) { (void) lun; -#ifdef CFG_EXAMPLE_MSC_READONLY +#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY) return false; #else return true; @@ -293,16 +281,18 @@ bool tud_msc_is_writable_cb (uint8_t lun) // Callback invoked when received WRITE10 command. // Process data in buffer to disk's storage and return number of written bytes -int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) -{ +int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) { // out of ramdisk - if ( lba >= DISK_BLOCK_NUM ) return -1; + if (lba >= DISK_BLOCK_NUM) return -1; -#ifndef CFG_EXAMPLE_MSC_READONLY +#if defined(CFG_EXAMPLE_MSC_READONLY) || defined(CFG_EXAMPLE_MSC_DUAL_READONLY) + (void) lun; + (void) lba; + (void) offset; + (void) buffer; +#else uint8_t* addr = (lun ? msc_disk1[lba] : msc_disk0[lba]) + offset; memcpy(addr, buffer, bufsize); -#else - (void) lun; (void) lba; (void) offset; (void) buffer; #endif return (int32_t) bufsize; @@ -311,8 +301,7 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* // Callback invoked when received an SCSI command not in built-in list below // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE // - READ10 and WRITE10 has their own callbacks -int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) -{ +int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) { // read10 & write10 has their own callback and MUST not be handled here void const* response = NULL; @@ -321,27 +310,23 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, // most scsi handled is input bool in_xfer = true; - switch (scsi_cmd[0]) - { + switch (scsi_cmd[0]) { default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // negative means error -> tinyusb could stall and/or response with failed status resplen = -1; - break; + break; } // return resplen must not larger than bufsize - if ( resplen > bufsize ) resplen = bufsize; + if (resplen > bufsize) resplen = bufsize; - if ( response && (resplen > 0) ) - { - if(in_xfer) - { + if (response && (resplen > 0)) { + if (in_xfer) { memcpy(buffer, response, (size_t) resplen); - }else - { + } else { // SCSI output } } diff --git a/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.cmake b/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.cmake new file mode 100644 index 000000000..8d3e0326e --- /dev/null +++ b/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.cmake @@ -0,0 +1,10 @@ +set(MCU_VARIANT D6) + +set(LD_FLASH_SIZE 64K) +set(LD_RAM_SIZE 20K) + +function(update_board TARGET) + target_compile_definitions(${TARGET} PUBLIC + CFG_EXAMPLE_MSC_DUAL_READONLY + ) +endfunction() diff --git a/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.h b/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.h new file mode 100644 index 000000000..c8d28d90f --- /dev/null +++ b/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.h @@ -0,0 +1,17 @@ +#ifndef BOARD_H_ +#define BOARD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define LED_PORT GPIOA +#define LED_PIN GPIO_Pin_15 +#define LED_STATE_ON 0 +#define LED_CLOCK_EN() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.mk b/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.mk new file mode 100644 index 000000000..7d7462312 --- /dev/null +++ b/hw/bsp/ch32v20x/boards/ch32v203_r0_1v0/board.mk @@ -0,0 +1,7 @@ +MCU_VARIANT = D6 + +CFLAGS += -DCFG_EXAMPLE_MSC_DUAL_READONLY + +LDFLAGS += \ + -Wl,--defsym=__flash_size=64K \ + -Wl,--defsym=__ram_size=20K \ diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake b/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake index 2699f3e15..8d3e0326e 100644 --- a/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake +++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.cmake @@ -1,7 +1,10 @@ set(MCU_VARIANT D6) +set(LD_FLASH_SIZE 64K) +set(LD_RAM_SIZE 20K) + function(update_board TARGET) target_compile_definitions(${TARGET} PUBLIC - CH32V20x_D6 + CFG_EXAMPLE_MSC_DUAL_READONLY ) endfunction() diff --git a/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk b/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk index 75dc05457..7d7462312 100644 --- a/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk +++ b/hw/bsp/ch32v20x/boards/nanoch32v203/board.mk @@ -1,5 +1,7 @@ -CFLAGS += \ - -DCH32V20x_D6 +MCU_VARIANT = D6 -SRC_S += \ - $(CH32V20X_SDK_SRC)/Startup/startup_ch32v20x_D6.S +CFLAGS += -DCFG_EXAMPLE_MSC_DUAL_READONLY + +LDFLAGS += \ + -Wl,--defsym=__flash_size=64K \ + -Wl,--defsym=__ram_size=20K \ diff --git a/hw/bsp/ch32v20x/family.cmake b/hw/bsp/ch32v20x/family.cmake index fb39e3630..80b035fc0 100644 --- a/hw/bsp/ch32v20x/family.cmake +++ b/hw/bsp/ch32v20x/family.cmake @@ -1,7 +1,8 @@ include_guard() set(CH32_FAMILY ch32v20x) -set(SDK_DIR ${TOP}/hw/mcu/wch/${CH32_FAMILY}/EVT/EXAM/SRC) +set(SDK_DIR ${TOP}/hw/mcu/wch/${CH32_FAMILY}) +set(SDK_SRC_DIR ${SDK_DIR}/EVT/EXAM/SRC) # include board specific include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) @@ -23,29 +24,30 @@ function(add_board_target BOARD_TARGET) endif() if (NOT DEFINED LD_FILE_GNU) - set(LD_FILE_GNU ${SDK_DIR}/Ld/Link.ld) + set(LD_FILE_GNU ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/linker/${CH32_FAMILY}.ld) endif () set(LD_FILE_Clang ${LD_FILE_GNU}) if (NOT DEFINED STARTUP_FILE_GNU) - set(STARTUP_FILE_GNU ${SDK_DIR}/Startup/startup_${CH32_FAMILY}_${MCU_VARIANT}.S) + set(STARTUP_FILE_GNU ${SDK_SRC_DIR}/Startup/startup_${CH32_FAMILY}_${MCU_VARIANT}.S) endif () set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) add_library(${BOARD_TARGET} STATIC - ${SDK_DIR}/Core/core_riscv.c - ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_gpio.c - ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_misc.c - ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_rcc.c - ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_usart.c + ${SDK_SRC_DIR}/Core/core_riscv.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_gpio.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_misc.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_rcc.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_usart.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_${CH32_FAMILY}.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${BOARD_TARGET} PUBLIC - ${SDK_DIR}/Peripheral/inc + ${SDK_SRC_DIR}/Peripheral/inc ${CMAKE_CURRENT_FUNCTION_LIST_DIR} ) target_compile_definitions(${BOARD_TARGET} PUBLIC + CH32V20x_${MCU_VARIANT} BOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED ) @@ -57,6 +59,8 @@ function(add_board_target BOARD_TARGET) ) target_link_options(${BOARD_TARGET} PUBLIC "LINKER:--script=${LD_FILE_GNU}" + -Wl,--defsym=__flash_size=${LD_FLASH_SIZE} + -Wl,--defsym=__ram_size=${LD_RAM_SIZE} -nostartfiles --specs=nosys.specs --specs=nano.specs ) diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk index 7e290bb18..6b09fdac7 100644 --- a/hw/bsp/ch32v20x/family.mk +++ b/hw/bsp/ch32v20x/family.mk @@ -7,12 +7,9 @@ # 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 +CH32_FAMILY = ch32v20x +SDK_DIR = hw/mcu/wch/ch32v20x +SDK_SRC_DIR = $(SDK_DIR)/EVT/EXAM/SRC include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= rv32imac-ilp32 @@ -23,27 +20,29 @@ CFLAGS += \ -fdata-sections \ -ffat-lto-objects \ -flto \ + -DCH32V20x_${MCU_VARIANT} \ -DCFG_TUSB_MCU=OPT_MCU_CH32V20X \ -DBOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED \ LDFLAGS_GCC += \ - -Wl,--gc-sections \ -nostdlib -nostartfiles \ --specs=nosys.specs --specs=nano.specs \ -LD_FILE = $(CH32V20X_SDK_SRC)/Ld/Link.ld +LD_FILE = $(FAMILY_PATH)/linker/${CH32_FAMILY}.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 \ + $(SDK_SRC_DIR)/Core/core_riscv.c \ + $(SDK_SRC_DIR)/Peripheral/src/ch32v20x_gpio.c \ + $(SDK_SRC_DIR)/Peripheral/src/ch32v20x_misc.c \ + $(SDK_SRC_DIR)/Peripheral/src/ch32v20x_rcc.c \ + $(SDK_SRC_DIR)/Peripheral/src/ch32v20x_usart.c \ + +SRC_S += $(SDK_SRC_DIR)/Startup/startup_ch32v20x_${MCU_VARIANT}.S INC += \ $(TOP)/$(BOARD_PATH) \ - $(TOP)/$(CH32V20X_SDK_SRC)/Peripheral/inc \ + $(TOP)/$(SDK_SRC_DIR)/Peripheral/inc \ FREERTOS_PORTABLE_SRC = $(FREERTOS_PORTABLE_PATH)/RISC-V diff --git a/hw/bsp/ch32v20x/linker/ch32v20x.ld b/hw/bsp/ch32v20x/linker/ch32v20x.ld new file mode 100644 index 000000000..6ee2fa1c7 --- /dev/null +++ b/hw/bsp/ch32v20x/linker/ch32v20x.ld @@ -0,0 +1 @@ +/* Define default values if not already defined */ __FLASH_SIZE = DEFINED(__flash_size) ? __flash_size : 64K; __RAM_SIZE = DEFINED(__ram_size) ? __ram_size : 20K; MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = __FLASH_SIZE RAM (xrw) : ORIGIN = 0x20000000, LENGTH = __RAM_SIZE } ENTRY( _start ) __stack_size = 2048; PROVIDE( _stack_size = __stack_size ); SECTIONS { .init : { _sinit = .; . = ALIGN(4); KEEP(*(SORT_NONE(.init))) . = ALIGN(4); _einit = .; } >FLASH AT>FLASH .vector : { *(.vector); . = ALIGN(64); } >FLASH AT>FLASH .text : { . = ALIGN(4); *(.text) *(.text.*) *(.rodata) *(.rodata*) *(.gnu.linkonce.t.*) . = ALIGN(4); } >FLASH AT>FLASH .fini : { KEEP(*(SORT_NONE(.fini))) . = ALIGN(4); } >FLASH AT>FLASH PROVIDE( _etext = . ); PROVIDE( _eitcm = . ); .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } >FLASH AT>FLASH .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) PROVIDE_HIDDEN (__init_array_end = .); } >FLASH AT>FLASH .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) PROVIDE_HIDDEN (__fini_array_end = .); } >FLASH AT>FLASH .ctors : { /* gcc uses crtbegin.o to find the start of the constructors, so we make sure it is first. Because this is a wildcard, it doesn't matter if the user does not actually link against crtbegin.o; the linker won't look for a file to match a wildcard. The wildcard also means that it doesn't matter which directory crtbegin.o is in. */ KEEP (*crtbegin.o(.ctors)) KEEP (*crtbegin?.o(.ctors)) /* We don't want to include the .ctor section from the crtend.o file until after the sorted ctors. The .ctor section from the crtend file contains the end of ctors marker and it must be last */ KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) KEEP (*(SORT(.ctors.*))) KEEP (*(.ctors)) } >FLASH AT>FLASH .dtors : { KEEP (*crtbegin.o(.dtors)) KEEP (*crtbegin?.o(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) KEEP (*(SORT(.dtors.*))) KEEP (*(.dtors)) } >FLASH AT>FLASH .dalign : { . = ALIGN(4); PROVIDE(_data_vma = .); } >RAM AT>FLASH .dlalign : { . = ALIGN(4); PROVIDE(_data_lma = .); } >FLASH AT>FLASH .data : { *(.gnu.linkonce.r.*) *(.data .data.*) *(.gnu.linkonce.d.*) . = ALIGN(8); PROVIDE( __global_pointer$ = . + 0x800 ); *(.sdata .sdata.*) *(.sdata2.*) *(.gnu.linkonce.s.*) . = ALIGN(8); *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata .srodata.*) . = ALIGN(4); PROVIDE( _edata = .); } >RAM AT>FLASH .bss : { . = ALIGN(4); PROVIDE( _sbss = .); *(.sbss*) *(.gnu.linkonce.sb.*) *(.bss*) *(.gnu.linkonce.b.*) *(COMMON*) . = ALIGN(4); PROVIDE( _ebss = .); } >RAM AT>FLASH PROVIDE( _end = _ebss); PROVIDE( end = . ); .stack ORIGIN(RAM) + LENGTH(RAM) - __stack_size : { PROVIDE( _heap_end = . ); . = ALIGN(4); PROVIDE(_susrstack = . ); . = . + __stack_size; PROVIDE( _eusrstack = .); } >RAM } From b19295c1c15de676e7cebd5bd5b6aa53887c6a56 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 20 May 2024 17:26:04 +0700 Subject: [PATCH 6/9] use correct wch usbhs, usbfs for ch32v307 using CFG_TUD_MAX_SPEED --- examples/build_system/make/rules.mk | 11 +++++ hw/bsp/ch32v20x/family.mk | 10 +--- hw/bsp/ch32v307/family.c | 77 ++++++++++------------------- hw/bsp/ch32v307/family.cmake | 27 +++++----- hw/bsp/ch32v307/family.mk | 61 ++++++++++------------- src/common/tusb_mcu.h | 16 ++++-- src/portable/wch/ch32_usbhs_reg.h | 4 +- src/portable/wch/dcd_ch32_usbfs.c | 3 +- src/portable/wch/dcd_ch32_usbhs.c | 6 +-- 9 files changed, 98 insertions(+), 117 deletions(-) diff --git a/examples/build_system/make/rules.mk b/examples/build_system/make/rules.mk index 7b6b339ed..102c6db0c 100644 --- a/examples/build_system/make/rules.mk +++ b/examples/build_system/make/rules.mk @@ -134,6 +134,17 @@ OPENOCD_OPTION ?= flash-openocd: $(BUILD)/$(PROJECT).elf openocd $(OPENOCD_OPTION) -c "program $< verify reset exit" +# --------------- openocd-wch ----------------- +# wch-linke 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 https://github.com/hathach/riscv-openocd-wch or +# https://github.com/dragonlock2/miscboards/blob/main/wch/SDK/riscv-openocd.tar.xz +# with ./configure --disable-werror --enable-wlinke --enable-ch347=no +OPENOCD_WCH ?= /home/${USER}/app/riscv-openocd-wch/src/openocd +OPENOCD_WCH_OPTION ?= +flash-openocd-wch: $(BUILD)/$(PROJECT).elf + $(OPENOCD_WCH) $(OPENOCD_WCH_OPTION) -c init -c halt -c "flash write_image $<" -c reset -c exit + # --------------- dfu-util ----------------- DFU_UTIL_OPTION ?= -a 0 flash-dfu-util: $(BUILD)/$(PROJECT).bin diff --git a/hw/bsp/ch32v20x/family.mk b/hw/bsp/ch32v20x/family.mk index 6b09fdac7..5c8b31a1c 100644 --- a/hw/bsp/ch32v20x/family.mk +++ b/hw/bsp/ch32v20x/family.mk @@ -16,8 +16,6 @@ CPU_CORE ?= rv32imac-ilp32 CFLAGS += \ -mcmodel=medany \ - -ffunction-sections \ - -fdata-sections \ -ffat-lto-objects \ -flto \ -DCH32V20x_${MCU_VARIANT} \ @@ -46,9 +44,5 @@ 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 -OPENOCD ?= $(HOME)/app/riscv-openocd-wch/src/openocd -flash: $(BUILD)/$(PROJECT).elf - $(OPENOCD) -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "flash write_image $<" -c reset -c exit +OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg +flash: flash-openocd-wch diff --git a/hw/bsp/ch32v307/family.c b/hw/bsp/ch32v307/family.c index 50e48e7df..fe37ea8e3 100644 --- a/hw/bsp/ch32v307/family.c +++ b/hw/bsp/ch32v307/family.c @@ -35,41 +35,31 @@ // 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"); -} +// TODO maybe having FS as port0, HS as port1 -__attribute__ ((used)) void USBHS_IRQHandler_impl (void) -{ +__attribute__((interrupt)) void USBHS_IRQHandler(void) { + #if CFG_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED tud_int_handler(0); + #endif } - -void OTG_FS_IRQHandler (void) __attribute__((naked)); -void OTG_FS_IRQHandler (void) -{ - __asm volatile ("call OTG_FS_IRQHandler_impl; mret"); -} - -__attribute__ ((used)) void OTG_FS_IRQHandler_impl (void) -{ +__attribute__((interrupt)) void OTG_FS_IRQHandler(void) { + #if CFG_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED tud_int_handler(0); + #endif } //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM //--------------------------------------------------------------------+ -uint32_t SysTick_Config(uint32_t 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; + SysTick->CTLR = 0; + SysTick->SR = 0; + SysTick->CNT = 0; + SysTick->CMP = ticks - 1; + SysTick->CTLR = 0xF; return 0; } @@ -82,17 +72,17 @@ void board_init(void) { SysTick_Config(SystemCoreClock / 1000); #endif - usart_printf_init(115200); + usart_printf_init(115200); - #if 0 +#if CFG_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED + // Use Highspeed USB 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); - - #else +#else uint8_t otg_div; switch (SystemCoreClock) { case 48000000: otg_div = RCC_OTGFSCLKSource_PLLCLK_Div1; break; @@ -102,7 +92,7 @@ void board_init(void) { } RCC_OTGFSCLKConfig(otg_div); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_OTG_FS, ENABLE); - #endif +#endif GPIO_InitTypeDef GPIO_InitStructure = {0}; @@ -127,24 +117,14 @@ void board_init(void) { } #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) -{ +__attribute__((interrupt)) void SysTick_Handler(void) { SysTick->SR = 0; system_ticks++; } -uint32_t board_millis (void) -{ +uint32_t board_millis(void) { return system_ticks; } @@ -154,36 +134,29 @@ uint32_t board_millis (void) // Board porting API //--------------------------------------------------------------------+ -void board_led_write (bool state) -{ +void board_led_write(bool state) { GPIO_WriteBit(LED_PORT, LED_PIN, state); } -uint32_t board_button_read (void) -{ +uint32_t board_button_read(void) { return BUTTON_STATE_ACTIVE == GPIO_ReadInputDataBit(BUTTON_PORT, BUTTON_PIN); } -int board_uart_read (uint8_t *buf, int len) -{ +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 board_uart_write(void const* buf, int len) { int txsize = len; - while ( txsize-- ) - { + 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 diff --git a/hw/bsp/ch32v307/family.cmake b/hw/bsp/ch32v307/family.cmake index 8a4bd7730..fd475c987 100644 --- a/hw/bsp/ch32v307/family.cmake +++ b/hw/bsp/ch32v307/family.cmake @@ -1,7 +1,8 @@ include_guard() set(CH32_FAMILY ch32v30x) -set(SDK_DIR ${TOP}/hw/mcu/wch/ch32v307/EVT/EXAM/SRC) +set(SDK_DIR ${TOP}/hw/mcu/wch/ch32v307) +set(SDK_SRC_DIR ${SDK_DIR}/EVT/EXAM/SRC) # include board specific include(${CMAKE_CURRENT_LIST_DIR}/boards/${BOARD}/board.cmake) @@ -13,7 +14,10 @@ set(CMAKE_TOOLCHAIN_FILE ${TOP}/examples/build_system/cmake/toolchain/riscv_${TO set(FAMILY_MCUS CH32V307 CACHE INTERNAL "") set(OPENOCD_OPTION "-f ${CMAKE_CURRENT_LIST_DIR}/wch-riscv.cfg") -# Port0 Fullspeed, Port1 Highspeed +# default to highspeed +if (NOT DEFINED SPEED) + set(SPEED high) +endif() #------------------------------------ # BOARD_TARGET @@ -30,27 +34,26 @@ function(add_board_target BOARD_TARGET) set(LD_FILE_Clang ${LD_FILE_GNU}) if (NOT DEFINED STARTUP_FILE_GNU) - set(STARTUP_FILE_GNU ${SDK_DIR}/Startup/startup_${CH32_FAMILY}_D8C.S) + set(STARTUP_FILE_GNU ${SDK_SRC_DIR}/Startup/startup_${CH32_FAMILY}_D8C.S) endif () set(STARTUP_FILE_Clang ${STARTUP_FILE_GNU}) add_library(${BOARD_TARGET} STATIC - ${SDK_DIR}/Core/core_riscv.c - ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_gpio.c - ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_misc.c - ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_rcc.c - ${SDK_DIR}/Peripheral/src/${CH32_FAMILY}_usart.c + ${SDK_SRC_DIR}/Core/core_riscv.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_gpio.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_misc.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_rcc.c + ${SDK_SRC_DIR}/Peripheral/src/${CH32_FAMILY}_usart.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/${CH32_FAMILY}_it.c ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/system_${CH32_FAMILY}.c ${STARTUP_FILE_${CMAKE_C_COMPILER_ID}} ) target_include_directories(${BOARD_TARGET} PUBLIC - ${SDK_DIR}/Peripheral/inc + ${SDK_SRC_DIR}/Peripheral/inc ${CMAKE_CURRENT_FUNCTION_LIST_DIR} ) target_compile_definitions(${BOARD_TARGET} PUBLIC - #BOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED - BOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED + BOARD_TUD_MAX_SPEED=$,OPT_MODE_HIGH_SPEED,OPT_MODE_FULL_SPEED> ) update_board(${BOARD_TARGET}) @@ -104,7 +107,7 @@ function(family_configure_example TARGET RTOS) # Add TinyUSB target and port source family_add_tinyusb(${TARGET} OPT_MCU_CH32V307 ${RTOS}) target_sources(${TARGET}-tinyusb PUBLIC - #${TOP}/src/portable/wch/dcd_ch32_usbhs.c + ${TOP}/src/portable/wch/dcd_ch32_usbhs.c ${TOP}/src/portable/wch/dcd_ch32_usbfs.c ) target_link_libraries(${TARGET}-tinyusb PUBLIC board_${BOARD}) diff --git a/hw/bsp/ch32v307/family.mk b/hw/bsp/ch32v307/family.mk index df9ded4a0..2dbe0c46a 100644 --- a/hw/bsp/ch32v307/family.mk +++ b/hw/bsp/ch32v307/family.mk @@ -7,63 +7,54 @@ # 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 - -# WCH-SDK paths -CH32V307_SDK_SRC = $(CH32V307_SDK)/EVT/EXAM/SRC +CH32_FAMILY = ch32v30x +SDK_DIR = hw/mcu/wch/ch32v307 +SDK_SRC_DIR = $(SDK_DIR)/EVT/EXAM/SRC include $(TOP)/$(BOARD_PATH)/board.mk CPU_CORE ?= rv32imac-ilp32 +# default to use high speed port, unless specified in board.mk or command line +SPEED ?= high + CFLAGS += \ -flto \ -msmall-data-limit=8 \ - -mno-save-restore -Os \ + -mno-save-restore \ -fmessage-length=0 \ -fsigned-char \ - -ffunction-sections \ - -fdata-sections \ -DCFG_TUSB_MCU=OPT_MCU_CH32V307 \ - -Xlinker --gc-sections \ - -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + +ifeq ($(SPEED),high) + CFLAGS += -DBOARD_TUD_MAX_SPEED=OPT_MODE_HIGH_SPEED + $(info "Using USBHS driver for HighSpeed mode") +else + CFLAGS += -DBOARD_TUD_MAX_SPEED=OPT_MODE_FULL_SPEED + $(info "Using USBFS driver for FullSpeed mode") +endif LDFLAGS_GCC += \ -nostdlib -nostartfiles \ - --specs=nosys.specs --specs=nano.specs + --specs=nosys.specs --specs=nano.specs \ SRC_C += \ src/portable/wch/dcd_ch32_usbhs.c \ - $(CH32V307_SDK_SRC)/Core/core_riscv.c \ - $(CH32V307_SDK_SRC)/Peripheral/src/ch32v30x_gpio.c \ - $(CH32V307_SDK_SRC)/Peripheral/src/ch32v30x_misc.c \ - $(CH32V307_SDK_SRC)/Peripheral/src/ch32v30x_rcc.c \ - $(CH32V307_SDK_SRC)/Peripheral/src/ch32v30x_usart.c + src/portable/wch/dcd_ch32_usbfs.c \ + $(SDK_SRC_DIR)/Core/core_riscv.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_gpio.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_misc.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_rcc.c \ + $(SDK_SRC_DIR)/Peripheral/src/${CH32_FAMILY}_usart.c SRC_S += \ - $(CH32V307_SDK_SRC)/Startup/startup_ch32v30x_D8C.S + $(SDK_SRC_DIR)/Startup/startup_${CH32_FAMILY}_D8C.S INC += \ $(TOP)/$(BOARD_PATH) \ - $(TOP)/$(CH32V307_SDK_SRC)/Peripheral/inc + $(TOP)/$(SDK_SRC_DIR)/Peripheral/inc # For freeRTOS port source 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/kprasadvnsi/riscv-openocd-wch -# -# Note: For Linux, somehow openocd in mounriver studio does not seem to have wch-link enable, -# therefore we need to compile it from source as follows: -# git clone https://github.com/kprasadvnsi/riscv-openocd-wch -# cd riscv-openocd-wch -# ./bootstrap -# ./configure CFLAGS="-Wno-error" --enable-wlink -# make -# openocd binaries will be generated in riscv-openocd-wch/src - -# flash target ROM bootloader -OPENOCD_WCH = /home/${USER}/app/riscv-openocd-wch/src/openocd -flash: $(BUILD)/$(PROJECT).elf - $(OPENOCD_WCH) -f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg -c init -c halt -c "program $<" -c wlink_reset_resume -c exit +OPENOCD_WCH_OPTION=-f $(TOP)/$(FAMILY_PATH)/wch-riscv.cfg +flash: flash-openocd-wch diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h index e313fea05..d928e44e8 100644 --- a/src/common/tusb_mcu.h +++ b/src/common/tusb_mcu.h @@ -404,14 +404,22 @@ //------------- WCH -------------// #elif TU_CHECK_MCU(OPT_MCU_CH32V307) - #define TUP_DCD_ENDPOINT_MAX 8 -// #define TUP_RHPORT_HIGHSPEED 1 + // v307 support both FS and HS + #define TUP_USBIP_WCH_USBHS + #define TUP_USBIP_WCH_USBFS + + #define TUP_RHPORT_HIGHSPEED 1 // default to highspeed + #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED ? 16 : 8) #elif TU_CHECK_MCU(OPT_MCU_CH32F20X) - #define TUP_DCD_ENDPOINT_MAX 16 - #define TUP_RHPORT_HIGHSPEED 1 + #define TUP_USBIP_WCH_USBHS + #define TUP_USBIP_WCH_USBFS + + #define TUP_RHPORT_HIGHSPEED 1 // default to highspeed + #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED ? 16 : 8) #elif TU_CHECK_MCU(OPT_MCU_CH32V20X) + #define TUP_USBIP_WCH_USBFS #define TUP_DCD_ENDPOINT_MAX 8 #endif diff --git a/src/portable/wch/ch32_usbhs_reg.h b/src/portable/wch/ch32_usbhs_reg.h index 9b956231f..6ae91ec71 100644 --- a/src/portable/wch/ch32_usbhs_reg.h +++ b/src/portable/wch/ch32_usbhs_reg.h @@ -2,9 +2,9 @@ #define _USB_CH32_USBHS_REG_H #if (CFG_TUSB_MCU == OPT_MCU_CH32V307) -#include + #include #elif (CFG_TUSB_MCU == OPT_MCU_CH32F20X) -#include + #include #endif /******************* GLOBAL ******************/ diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 3e4b6cae5..413fe92c9 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -1,6 +1,7 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && (CFG_TUSB_MCU == OPT_MCU_CH32V20X || CFG_TUSB_MCU == OPT_MCU_CH32V307) +// Note: CH32 can have both USB FS and HS, only use this driver if CFG_TUD_MAX_SPEED is full speed +#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBFS) && (CFG_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED) #include #include "device/dcd.h" diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c index 68e2179e9..9a12fc97f 100644 --- a/src/portable/wch/dcd_ch32_usbhs.c +++ b/src/portable/wch/dcd_ch32_usbhs.c @@ -26,11 +26,11 @@ #include "tusb_option.h" -#if CFG_TUD_ENABLED && ((CFG_TUSB_MCU == OPT_MCU_CH32V307) || (CFG_TUSB_MCU == OPT_MCU_CH32F20X)) -#include "device/dcd.h" - +// Note: CH32 can have both USB FS and HS, only use this driver if CFG_TUD_MAX_SPEED is high speed +#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && (CFG_TUD_MAX_SPEED == OPT_MODE_HIGH_SPEED) #include "ch32_usbhs_reg.h" +#include "device/dcd.h" // Max number of bi-directional endpoints including EP0 #define EP_MAX 16 From 07d879378f052386699aba1eb41f04d4d32fb865 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 20 May 2024 17:32:40 +0700 Subject: [PATCH 7/9] code format add missing MIT license --- .idea/cmake.xml | 2 + src/portable/wch/ch32_usbfs_reg.h | 41 ++- src/portable/wch/ch32_usbhs_reg.h | 35 ++- src/portable/wch/dcd_ch32_usbfs.c | 460 ++++++++++++++++-------------- 4 files changed, 311 insertions(+), 227 deletions(-) diff --git a/.idea/cmake.xml b/.idea/cmake.xml index a34f19e1f..d96b46853 100644 --- a/.idea/cmake.xml +++ b/.idea/cmake.xml @@ -132,6 +132,8 @@ + + \ No newline at end of file diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h index d5341f3a8..0a50a6169 100644 --- a/src/portable/wch/ch32_usbfs_reg.h +++ b/src/portable/wch/ch32_usbfs_reg.h @@ -1,15 +1,42 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Matthew Tran + * Copyright (c) 2024 hathach + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + #ifndef USB_CH32_USBFS_REG_H #define USB_CH32_USBFS_REG_H -#if (CFG_TUSB_MCU == OPT_MCU_CH32V307) -#include -#define USBHD_IRQn OTG_FS_IRQn +#if CFG_TUSB_MCU == OPT_MCU_CH32V307 + #include + #define USBHD_IRQn OTG_FS_IRQn -#elif (CFG_TUSB_MCU == OPT_MCU_CH32V20X) -#include +#elif CFG_TUSB_MCU == OPT_MCU_CH32V20X + #include -#elif (CFG_TUSB_MCU == OPT_MCU_CH32F20X) -#include +#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X + #include #endif // CTRL diff --git a/src/portable/wch/ch32_usbhs_reg.h b/src/portable/wch/ch32_usbhs_reg.h index 6ae91ec71..a3a41bb6a 100644 --- a/src/portable/wch/ch32_usbhs_reg.h +++ b/src/portable/wch/ch32_usbhs_reg.h @@ -1,9 +1,36 @@ -#ifndef _USB_CH32_USBHS_REG_H -#define _USB_CH32_USBHS_REG_H +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Matthew Tran + * Copyright (c) 2024 hathach + * + * 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. + */ -#if (CFG_TUSB_MCU == OPT_MCU_CH32V307) +#ifndef USB_CH32_USBHS_REG_H +#define USB_CH32_USBHS_REG_H + +#if CFG_TUSB_MCU == OPT_MCU_CH32V307 #include -#elif (CFG_TUSB_MCU == OPT_MCU_CH32F20X) +#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X #include #endif diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c index 413fe92c9..dafe4414e 100644 --- a/src/portable/wch/dcd_ch32_usbfs.c +++ b/src/portable/wch/dcd_ch32_usbfs.c @@ -1,9 +1,35 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2024 Matthew Tran + * Copyright (c) 2024 hathach + * + * 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" // Note: CH32 can have both USB FS and HS, only use this driver if CFG_TUD_MAX_SPEED is full speed #if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBFS) && (CFG_TUD_MAX_SPEED == OPT_MODE_FULL_SPEED) -#include #include "device/dcd.h" #include "ch32_usbfs_reg.h" @@ -17,301 +43,303 @@ /* private data */ struct usb_xfer { - bool valid; - uint8_t *buffer; - size_t len; - size_t processed_len; - size_t max_size; + 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; + 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; + 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); - } + 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; - } + 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; + // 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; + 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; + // 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; + // 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]; + 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); + 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); + (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; - } + 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_IN: + update_in(rhport, ep, false); + break; - case PID_SETUP: - data.ep0_tog = true; - dcd_edpt_clear_stall(rhport, tu_edpt_addr(0, TUSB_DIR_IN)); // setup clears stall - dcd_edpt_clear_stall(rhport, tu_edpt_addr(0, TUSB_DIR_OUT)); - 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; + case PID_SETUP: + // setup clears stall + EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK; 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; + 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) rhport; + NVIC_EnableIRQ(USBHD_IRQn); } void dcd_int_disable(uint8_t rhport) { - (void) rhport; - NVIC_DisableIRQ(USBHD_IRQn); + (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) dev_addr; + dcd_edpt_xfer(rhport, 0x80, NULL, 0); // zlp status response } void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; - // TODO optional + (void) rhport; + // TODO optional } void dcd_connect(uint8_t rhport) { - (void) rhport; - USBOTG_FS->BASE_CTRL |= USBFS_CTRL_DEV_PUEN; + (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) rhport; + USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN; } -void dcd_sof_enable(uint8_t rhport, bool en) -{ +void dcd_sof_enable(uint8_t rhport, bool en) { (void) rhport; (void) en; // TODO implement later } -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; +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); +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); + 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; - } + 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; + } + return true; } void dcd_edpt_close_all(uint8_t rhport) { - (void) rhport; - // TODO optional + (void) rhport; + // TODO optional } void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) { - (void) rhport; - (void) ep_addr; - // TODO optional + (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); +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]; - dcd_int_disable(rhport); - xfer->valid = true; - xfer->buffer = buffer; - xfer->len = total_bytes; - xfer->processed_len = 0; - dcd_int_enable(rhport); + struct usb_xfer* xfer = &data.xfer[ep][dir]; + dcd_int_disable(rhport); + xfer->valid = true; + xfer->buffer = buffer; + xfer->len = total_bytes; + xfer->processed_len = 0; + dcd_int_enable(rhport); - if (dir == TUSB_DIR_IN) { - update_in(rhport, ep, true); - } - return true; + 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; - } + (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 { - 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; - } + 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; - } + (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) +#endif From 3b144be37fc3e146e68f4182bf18a1b460afeba6 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 20 May 2024 18:05:45 +0700 Subject: [PATCH 8/9] try fixing codeql --- examples/device/msc_dual_lun/src/msc_disk_dual.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/device/msc_dual_lun/src/msc_disk_dual.c b/examples/device/msc_dual_lun/src/msc_disk_dual.c index 81f1d3346..b44b77c6c 100644 --- a/examples/device/msc_dual_lun/src/msc_disk_dual.c +++ b/examples/device/msc_dual_lun/src/msc_disk_dual.c @@ -300,10 +300,8 @@ int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* // Callback invoked when received an SCSI command not in built-in list below // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE -// - READ10 and WRITE10 has their own callbacks +// - READ10 and WRITE10 has their own callbacks (MUST not be handled here) int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) { - // read10 & write10 has their own callback and MUST not be handled here - void const* response = NULL; int32_t resplen = 0; @@ -316,8 +314,7 @@ int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, u tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); // negative means error -> tinyusb could stall and/or response with failed status - resplen = -1; - break; + return -1; } // return resplen must not larger than bufsize From 10b1e38404c044345e9ea0f3e5c678af94eb0f0a Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 20 May 2024 18:30:38 +0700 Subject: [PATCH 9/9] revert unrelated changes to video_device.c --- src/class/video/video_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 974289b69..4218835aa 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -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 = 0; + uint_fast32_t interval, interval_ms; switch (request) { case VIDEO_REQUEST_GET_MAX: { uint_fast32_t min_interval, max_interval;