summaryrefslogtreecommitdiffstats
path: root/tinyusb/hw/bsp/gd32vf103
diff options
context:
space:
mode:
Diffstat (limited to 'tinyusb/hw/bsp/gd32vf103')
-rwxr-xr-xtinyusb/hw/bsp/gd32vf103/boards/sipeed_longan_nano/board.h20
-rwxr-xr-xtinyusb/hw/bsp/gd32vf103/boards/sipeed_longan_nano/board.mk13
-rwxr-xr-xtinyusb/hw/bsp/gd32vf103/family.c197
-rwxr-xr-xtinyusb/hw/bsp/gd32vf103/family.mk68
-rwxr-xr-xtinyusb/hw/bsp/gd32vf103/system_gd32vf103.c668
5 files changed, 966 insertions, 0 deletions
diff --git a/tinyusb/hw/bsp/gd32vf103/boards/sipeed_longan_nano/board.h b/tinyusb/hw/bsp/gd32vf103/boards/sipeed_longan_nano/board.h
new file mode 100755
index 00000000..fae7c40b
--- /dev/null
+++ b/tinyusb/hw/bsp/gd32vf103/boards/sipeed_longan_nano/board.h
@@ -0,0 +1,20 @@
+#ifndef _NUCLEI_SDK_HAL_H
+#define _NUCLEI_SDK_HAL_H
+
+#include "gd32vf103c_longan_nano.h"
+
+// 4 bits for interrupt level, 0 for priority.
+// level 0 = lowest priority, level 15 = highest priority.
+#define __ECLIC_INTCTLBITS 4
+
+#define __SYSTEM_CLOCK 72000000
+#define HXTAL_VALUE ((uint32_t)8000000)
+
+#define SOC_DEBUG_UART GD32_COM0
+
+#define DBG_KEY_UNLOCK 0x4B5A6978
+#define DBG_CMD_RESET 0x1
+#define DBG_KEY REG32(DBG + 0x0C)
+#define DBG_CMD REG32(DBG + 0x08)
+
+#endif
diff --git a/tinyusb/hw/bsp/gd32vf103/boards/sipeed_longan_nano/board.mk b/tinyusb/hw/bsp/gd32vf103/boards/sipeed_longan_nano/board.mk
new file mode 100755
index 00000000..3b894445
--- /dev/null
+++ b/tinyusb/hw/bsp/gd32vf103/boards/sipeed_longan_nano/board.mk
@@ -0,0 +1,13 @@
+LONGAN_NANO_SDK_BSP = $(GD32VF103_SDK_SOC)/Board/gd32vf103c_longan_nano
+LINKER_SCRIPTS = $(LONGAN_NANO_SDK_BSP)/Source/GCC
+
+# All source paths should be relative to the top level.
+LD_FILE = $(LINKER_SCRIPTS)/gcc_gd32vf103xb_flashxip.ld # Longan Nano 128k ROM 32k RAM
+#LD_FILE = $(LINKER_SCRIPTS)/gcc_gd32vf103x8_flashxip.ld # Longan Nano Lite 64k ROM 20k RAM
+
+SRC_C += $(LONGAN_NANO_SDK_BSP)/Source/gd32vf103c_longan_nano.c
+INC += $(TOP)/$(LONGAN_NANO_SDK_BSP)/Include
+
+# Longan Nano 128k ROM 32k RAM
+JLINK_DEVICE = gd32vf103cbt6
+#JLINK_DEVICE = gd32vf103c8t6 # Longan Nano Lite 64k ROM 20k RAM
diff --git a/tinyusb/hw/bsp/gd32vf103/family.c b/tinyusb/hw/bsp/gd32vf103/family.c
new file mode 100755
index 00000000..d76fb9a2
--- /dev/null
+++ b/tinyusb/hw/bsp/gd32vf103/family.c
@@ -0,0 +1,197 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * 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 "board.h"
+#include "drv_usb_hw.h"
+#include "drv_usb_dev.h"
+
+#include "../board.h"
+
+//--------------------------------------------------------------------+
+// Forward USB interrupt events to TinyUSB IRQ Handler
+//--------------------------------------------------------------------+
+
+void USBFS_IRQHandler(void) { tud_int_handler(0); }
+
+//--------------------------------------------------------------------+
+// MACRO TYPEDEF CONSTANT ENUM
+//--------------------------------------------------------------------+
+
+#define USB_NO_VBUS_PIN
+
+// According to GD32VF103 user manual clock tree:
+// Systick clock = AHB clock / 4.
+#define TIMER_TICKS ((SystemCoreClock / 4) / 1000)
+
+#define BUTTON_PORT GPIOA
+#define BUTTON_PIN GPIO_PIN_0
+#define BUTTON_STATE_ACTIVE 1
+
+#define UART_DEV SOC_DEBUG_UART
+
+#define LED_PIN LED_R
+
+void board_init(void) {
+ /* Disable interrupts during init */
+ __disable_irq();
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+ SysTick_Config(TIMER_TICKS);
+#endif
+
+ rcu_periph_clock_enable(RCU_GPIOA);
+ rcu_periph_clock_enable(RCU_GPIOB);
+ rcu_periph_clock_enable(RCU_GPIOC);
+ rcu_periph_clock_enable(RCU_GPIOD);
+ rcu_periph_clock_enable(RCU_AF);
+
+#ifdef BUTTON_PIN
+ gpio_init(BUTTON_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, BUTTON_PIN);
+#endif
+
+#ifdef LED_PIN
+ gd_led_init(LED_PIN);
+#endif
+
+#if defined(UART_DEV)
+ gd_com_init(UART_DEV);
+#endif
+
+ /* USB D+ and D- pins don't need to be configured. */
+ /* Configure VBUS Pin */
+#ifndef USB_NO_VBUS_PIN
+ gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
+#endif
+
+ /* This for ID line debug */
+ // gpio_init(GPIOA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
+
+ /* Enable USB OTG clock */
+ usb_rcu_config();
+
+ /* Reset USB OTG peripheral */
+ rcu_periph_reset_enable(RCU_USBFSRST);
+ rcu_periph_reset_disable(RCU_USBFSRST);
+
+ /* Configure USBFS IRQ */
+ ECLIC_Register_IRQ(USBFS_IRQn, ECLIC_NON_VECTOR_INTERRUPT,
+ ECLIC_POSTIVE_EDGE_TRIGGER, 3, 0, NULL);
+
+ /* Retrieve otg core registers */
+ usb_gr* otg_core_regs = (usb_gr*)(USBFS_REG_BASE + USB_REG_OFFSET_CORE);
+
+#ifdef USB_NO_VBUS_PIN
+ /* Disable VBUS sense*/
+ otg_core_regs->GCCFG |= GCCFG_VBUSIG | GCCFG_PWRON | GCCFG_VBUSBCEN;
+#else
+ /* Enable VBUS sense via pin PA9 */
+ otg_core_regs->GCCFG |= GCCFG_VBUSIG | GCCFG_PWRON | GCCFG_VBUSBCEN;
+ otg_core_regs->GCCFG &= ~GCCFG_VBUSIG;
+#endif
+
+ /* Enable interrupts globaly */
+ __enable_irq();
+}
+
+void gd32vf103_reset(void) {
+ /* The MTIMER unit of the GD32VF103 doesn't have the MSFRST
+ * register to generate a software reset request.
+ * BUT instead two undocumented registers in the debug peripheral
+ * that allow issueing a software reset.
+ * https://github.com/esmil/gd32vf103inator/blob/master/include/gd32vf103/dbg.h
+ */
+ DBG_KEY = DBG_KEY_UNLOCK;
+ DBG_CMD = DBG_CMD_RESET;
+}
+
+//--------------------------------------------------------------------+
+// Board porting API
+//--------------------------------------------------------------------+
+
+void board_led_write(bool state) {
+ state ? gd_led_on(LED_PIN) : gd_led_off(LED_PIN);
+}
+
+uint32_t board_button_read(void) {
+ return BUTTON_STATE_ACTIVE == gpio_input_bit_get(BUTTON_PORT, BUTTON_PIN);
+}
+
+int board_uart_read(uint8_t* buf, int len) {
+#if defined(UART_DEV)
+ int rxsize = len;
+ while (rxsize--) {
+ *(uint8_t*)buf = usart_read(UART_DEV);
+ buf++;
+ }
+ return len;
+#else
+ (void)buf;
+ (void)len;
+ return 0;
+#endif
+}
+
+int board_uart_write(void const* buf, int len) {
+#if defined(UART_DEV)
+ int txsize = len;
+ while (txsize--) {
+ usart_write(UART_DEV, *(uint8_t*)buf);
+ buf++;
+ }
+ return len;
+#else
+ (void)buf;
+ (void)len;
+ return 0;
+#endif
+}
+
+#if CFG_TUSB_OS == OPT_OS_NONE
+volatile uint32_t system_ticks = 0;
+void eclic_mtip_handler(void) {
+ system_ticks++;
+ SysTick_Reload(TIMER_TICKS);
+}
+uint32_t board_millis(void) { return system_ticks; }
+#endif
+
+#ifdef USE_FULL_ASSERT
+/**
+ * @brief Reports the name of the source file and the source line number
+ * where the assert_param error has occurred.
+ * @param file: pointer to the source file name
+ * @param line: assert_param error line source number
+ * @retval None
+ */
+void assert_failed(char* file, uint32_t line) {
+ /* USER CODE BEGIN 6 */
+ /* User can add his own implementation to report the file name and line
+ number,
+ tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line)
+ */
+ /* USER CODE END 6 */
+}
+#endif /* USE_FULL_ASSERT */
diff --git a/tinyusb/hw/bsp/gd32vf103/family.mk b/tinyusb/hw/bsp/gd32vf103/family.mk
new file mode 100755
index 00000000..9148e7f8
--- /dev/null
+++ b/tinyusb/hw/bsp/gd32vf103/family.mk
@@ -0,0 +1,68 @@
+# 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-embed-gcc-xpack
+CROSS_COMPILE ?= riscv-none-embed-
+
+# Submodules
+NUCLEI_SDK = hw/mcu/gd/nuclei-sdk
+DEPS_SUBMODULES += $(NUCLEI_SDK)
+
+# Nuclei-SDK paths
+GD32VF103_SDK_SOC = $(NUCLEI_SDK)/SoC/gd32vf103
+GD32VF103_SDK_DRIVER = $(GD32VF103_SDK_SOC)/Common/Source/Drivers
+LIBC_STUBS = $(GD32VF103_SDK_SOC)/Common/Source/Stubs
+STARTUP_ASM = $(GD32VF103_SDK_SOC)/Common/Source/GCC
+
+include $(TOP)/$(BOARD_PATH)/board.mk
+
+SKIP_NANOLIB = 1
+
+CFLAGS += \
+ -march=rv32imac \
+ -mabi=ilp32 \
+ -mcmodel=medlow \
+ -mstrict-align \
+ -nostdlib -nostartfiles \
+ -DCFG_TUSB_MCU=OPT_MCU_GD32VF103 \
+ -DDOWNLOAD_MODE=DOWNLOAD_MODE_FLASHXIP \
+ -DGD32VF103
+
+# mcu driver cause following warnings
+CFLAGS += -Wno-error=unused-parameter
+
+SRC_C += \
+ src/portable/st/synopsys/dcd_synopsys.c \
+ $(GD32VF103_SDK_DRIVER)/gd32vf103_rcu.c \
+ $(GD32VF103_SDK_DRIVER)/gd32vf103_gpio.c \
+ $(GD32VF103_SDK_DRIVER)/Usb/gd32vf103_usb_hw.c \
+ $(GD32VF103_SDK_DRIVER)/gd32vf103_usart.c \
+ $(LIBC_STUBS)/sbrk.c \
+ $(LIBC_STUBS)/close.c \
+ $(LIBC_STUBS)/isatty.c \
+ $(LIBC_STUBS)/fstat.c \
+ $(LIBC_STUBS)/lseek.c \
+ $(LIBC_STUBS)/read.c
+
+SRC_S += \
+ $(STARTUP_ASM)/startup_gd32vf103.S \
+ $(STARTUP_ASM)/intexc_gd32vf103.S
+
+INC += \
+ $(TOP)/$(BOARD_PATH) \
+ $(TOP)/$(NUCLEI_SDK)/NMSIS/Core/Include \
+ $(TOP)/$(GD32VF103_SDK_SOC)/Common/Include \
+ $(TOP)/$(GD32VF103_SDK_SOC)/Common/Include/Usb
+
+# For freeRTOS port source
+FREERTOS_PORT = RISC-V
+
+# For flash-jlink target
+JLINK_IF = jtag
+
+# flash target ROM bootloader
+flash: $(BUILD)/$(PROJECT).bin
+ dfu-util -R -a 0 --dfuse-address 0x08000000 -D $<
diff --git a/tinyusb/hw/bsp/gd32vf103/system_gd32vf103.c b/tinyusb/hw/bsp/gd32vf103/system_gd32vf103.c
new file mode 100755
index 00000000..29518a54
--- /dev/null
+++ b/tinyusb/hw/bsp/gd32vf103/system_gd32vf103.c
@@ -0,0 +1,668 @@
+/*!
+ \file system_gd32vf103.h
+\brief RISC-V Device Peripheral Access Layer Source File for
+ GD32VF103 Device Series
+
+*/
+
+/*
+ Copyright (c) 2020, GigaDevice Semiconductor Inc.
+
+ Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ 3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+*/
+
+/* This file refers the RISC-V standard, some adjustments are made according to GigaDevice chips */
+#include "board.h"
+
+/* system frequency define */
+#define __IRC8M (IRC8M_VALUE) /* internal 8 MHz RC oscillator frequency */
+#define __HXTAL (HXTAL_VALUE) /* high speed crystal oscillator frequency */
+#define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */
+#define __SYSTEM_CLOCK_HXTAL (HXTAL_VALUE)
+
+#if !defined(__SYSTEM_CLOCK)
+#define __SYSTEM_CLOCK 72000000
+#endif
+
+#if __SYSTEM_CLOCK == 48000000
+ #define __SYSTEM_CLOCK_48M_PLL_HXTAL (uint32_t)(48000000)
+ uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_HXTAL;
+ static void system_clock_48m_hxtal(void);
+
+#elif __SYSTEM_CLOCK == 72000000
+ #define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
+ uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_HXTAL;
+ static void system_clock_72m_hxtal(void);
+
+#elif __SYSTEM_CLOCK == 96000000
+ #define __SYSTEM_CLOCK_96M_PLL_HXTAL (uint32_t)(96000000)
+ uint32_t SystemCoreClock = __SYSTEM_CLOCK_96M_PLL_HXTAL;
+ static void system_clock_96m_hxtal(void);
+
+#else
+#error No valid system clock configuration set!
+#endif
+
+/* configure the system clock */
+static void system_clock_config(void);
+
+/*!
+ \brief configure the system clock
+ \param[in] none
+ \param[out] none
+ \retval none
+*/
+static void system_clock_config(void)
+{
+#if defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
+ system_clock_48m_hxtal();
+#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
+ system_clock_72m_hxtal();
+#elif defined (__SYSTEM_CLOCK_96M_PLL_HXTAL)
+ system_clock_96m_hxtal();
+#endif /* __SYSTEM_CLOCK_HXTAL */
+}
+
+/*!
+ \brief setup the microcontroller system, initialize the system
+ \param[in] none
+ \param[out] none
+ \retval none
+*/
+void SystemInit(void)
+{
+ /* reset the RCC clock configuration to the default reset state */
+ /* enable IRC8M */
+ RCU_CTL |= RCU_CTL_IRC8MEN;
+
+ /* reset SCS, AHBPSC, APB1PSC, APB2PSC, ADCPSC, CKOUT0SEL bits */
+ RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |
+ RCU_CFG0_ADCPSC | RCU_CFG0_ADCPSC_2 | RCU_CFG0_CKOUT0SEL);
+
+ /* reset HXTALEN, CKMEN, PLLEN bits */
+ RCU_CTL &= ~(RCU_CTL_HXTALEN | RCU_CTL_CKMEN | RCU_CTL_PLLEN);
+
+ /* Reset HXTALBPS bit */
+ RCU_CTL &= ~(RCU_CTL_HXTALBPS);
+
+ /* reset PLLSEL, PREDV0_LSB, PLLMF, USBFSPSC bits */
+
+ RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0_LSB | RCU_CFG0_PLLMF |
+ RCU_CFG0_USBFSPSC | RCU_CFG0_PLLMF_4);
+ RCU_CFG1 = 0x00000000U;
+
+ /* Reset HXTALEN, CKMEN, PLLEN, PLL1EN and PLL2EN bits */
+ RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_PLL1EN | RCU_CTL_PLL2EN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN);
+ /* disable all interrupts */
+ RCU_INT = 0x00FF0000U;
+
+ /* Configure the System clock source, PLL Multiplier, AHB/APBx prescalers and Flash settings */
+ system_clock_config();
+}
+
+/*!
+ \brief update the SystemCoreClock with current core clock retrieved from cpu registers
+ \param[in] none
+ \param[out] none
+ \retval none
+*/
+void SystemCoreClockUpdate(void)
+{
+ uint32_t scss;
+ uint32_t pllsel, predv0sel, pllmf, ck_src;
+ uint32_t predv0, predv1, pll1mf;
+
+ scss = GET_BITS(RCU_CFG0, 2, 3);
+
+ switch (scss)
+ {
+ /* IRC8M is selected as CK_SYS */
+ case SEL_IRC8M:
+ SystemCoreClock = IRC8M_VALUE;
+ break;
+
+ /* HXTAL is selected as CK_SYS */
+ case SEL_HXTAL:
+ SystemCoreClock = HXTAL_VALUE;
+ break;
+
+ /* PLL is selected as CK_SYS */
+ case SEL_PLL:
+ /* PLL clock source selection, HXTAL or IRC8M/2 */
+ pllsel = (RCU_CFG0 & RCU_CFG0_PLLSEL);
+
+
+ if(RCU_PLLSRC_IRC8M_DIV2 == pllsel){
+ /* PLL clock source is IRC8M/2 */
+ ck_src = IRC8M_VALUE / 2U;
+ }else{
+ /* PLL clock source is HXTAL */
+ ck_src = HXTAL_VALUE;
+
+ predv0sel = (RCU_CFG1 & RCU_CFG1_PREDV0SEL);
+
+ /* source clock use PLL1 */
+ if(RCU_PREDV0SRC_CKPLL1 == predv0sel){
+ predv1 = ((RCU_CFG1 & RCU_CFG1_PREDV1) >> 4) + 1U;
+ pll1mf = ((RCU_CFG1 & RCU_CFG1_PLL1MF) >> 8) + 2U;
+ if(17U == pll1mf){
+ pll1mf = 20U;
+ }
+ ck_src = (ck_src / predv1) * pll1mf;
+ }
+ predv0 = (RCU_CFG1 & RCU_CFG1_PREDV0) + 1U;
+ ck_src /= predv0;
+ }
+
+ /* PLL multiplication factor */
+ pllmf = GET_BITS(RCU_CFG0, 18, 21);
+
+ if((RCU_CFG0 & RCU_CFG0_PLLMF_4)){
+ pllmf |= 0x10U;
+ }
+
+ if(pllmf >= 15U){
+ pllmf += 1U;
+ }else{
+ pllmf += 2U;
+ }
+
+ SystemCoreClock = ck_src * pllmf;
+
+ if(15U == pllmf){
+ /* PLL source clock multiply by 6.5 */
+ SystemCoreClock = ck_src * 6U + ck_src / 2U;
+ }
+
+ break;
+
+ /* IRC8M is selected as CK_SYS */
+ default:
+ SystemCoreClock = IRC8M_VALUE;
+ break;
+ }
+}
+
+#if defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
+/*!
+ \brief configure the system clock to 48M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+ \param[in] none
+ \param[out] none
+ \retval none
+*/
+static void system_clock_48m_hxtal(void)
+{
+ uint32_t timeout = 0U;
+ uint32_t stab_flag = 0U;
+
+ /* enable HXTAL */
+ RCU_CTL |= RCU_CTL_HXTALEN;
+
+ /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+ do{
+ timeout++;
+ stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+ }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+ /* if fail */
+ if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+ while(1){
+ }
+ }
+
+ /* HXTAL is stable */
+ /* AHB = SYSCLK */
+ RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+ /* APB2 = AHB/1 */
+ RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+ /* APB1 = AHB/2 */
+ RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+ /* CK_PLL = (CK_PREDIV0) * 12 = 48 MHz */
+ RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+ RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL12);
+
+ if(HXTAL_VALUE==25000000){
+
+ /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+ RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+ RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+
+ /* enable PLL1 */
+ RCU_CTL |= RCU_CTL_PLL1EN;
+ /* wait till PLL1 is ready */
+ while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+ }
+
+ }else if(HXTAL_VALUE==8000000){
+ RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+ RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+ }
+
+
+
+ /* enable PLL */
+ RCU_CTL |= RCU_CTL_PLLEN;
+
+ /* wait until PLL is stable */
+ while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+ }
+
+ /* select PLL as system clock */
+ RCU_CFG0 &= ~RCU_CFG0_SCS;
+ RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+ /* wait until PLL is selected as system clock */
+ while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+ }
+}
+
+#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
+/*!
+ \brief configure the system clock to 72M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+ \param[in] none
+ \param[out] none
+ \retval none
+*/
+static void system_clock_72m_hxtal(void)
+{
+ uint32_t timeout = 0U;
+ uint32_t stab_flag = 0U;
+
+ /* enable HXTAL */
+ RCU_CTL |= RCU_CTL_HXTALEN;
+
+ /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+ do{
+ timeout++;
+ stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+ }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+ /* if fail */
+ if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+ while(1){
+ }
+ }
+
+ /* HXTAL is stable */
+ /* AHB = SYSCLK */
+ RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+ /* APB2 = AHB/1 */
+ RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+ /* APB1 = AHB/2 */
+ RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+ /* CK_PLL = (CK_PREDIV0) * 18 = 72 MHz */
+ RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+ RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL18);
+
+
+ if(HXTAL_VALUE==25000000){
+
+ /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+ RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+ RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+
+ /* enable PLL1 */
+ RCU_CTL |= RCU_CTL_PLL1EN;
+ /* wait till PLL1 is ready */
+ while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+ }
+
+ }else if(HXTAL_VALUE==8000000){
+ RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+ RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+ }
+
+ /* enable PLL */
+ RCU_CTL |= RCU_CTL_PLLEN;
+
+ /* wait until PLL is stable */
+ while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+ }
+
+ /* select PLL as system clock */
+ RCU_CFG0 &= ~RCU_CFG0_SCS;
+ RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+ /* wait until PLL is selected as system clock */
+ while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+ }
+}
+
+#elif defined (__SYSTEM_CLOCK_96M_PLL_HXTAL)
+/*!
+ \brief configure the system clock to 96M by PLL which selects HXTAL(MD/HD/XD:8M; CL:25M) as its clock source
+ \param[in] none
+ \param[out] none
+ \retval none
+*/
+static void system_clock_96m_hxtal(void)
+{
+ uint32_t timeout = 0U;
+ uint32_t stab_flag = 0U;
+
+ /* enable HXTAL */
+ RCU_CTL |= RCU_CTL_HXTALEN;
+
+ /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
+ do{
+ timeout++;
+ stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
+ }while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
+
+ /* if fail */
+ if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)){
+ while(1){
+ }
+ }
+
+ /* HXTAL is stable */
+ /* AHB = SYSCLK */
+ RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
+ /* APB2 = AHB/1 */
+ RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
+ /* APB1 = AHB/2 */
+ RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
+
+ if(HXTAL_VALUE==25000000){
+
+ /* CK_PLL = (CK_PREDIV0) * 24 = 96 MHz */
+ RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+ RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL24);
+
+ /* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
+ RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV1 | RCU_CFG1_PREDV0);
+ RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PLL1_MUL8 | RCU_PREDV1_DIV5 | RCU_PREDV0_DIV10);
+ /* enable PLL1 */
+ RCU_CTL |= RCU_CTL_PLL1EN;
+ /* wait till PLL1 is ready */
+ while((RCU_CTL & RCU_CTL_PLL1STB) == 0){
+ }
+
+ }else if(HXTAL_VALUE==8000000){
+ /* CK_PLL = (CK_PREDIV0) * 24 = 96 MHz */
+ RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
+ RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL24);
+
+ RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
+ RCU_CFG1 |= (RCU_PREDV0SRC_HXTAL | RCU_PREDV0_DIV2 );
+ }
+
+ /* enable PLL */
+ RCU_CTL |= RCU_CTL_PLLEN;
+
+ /* wait until PLL is stable */
+ while(0U == (RCU_CTL & RCU_CTL_PLLSTB)){
+ }
+
+ /* select PLL as system clock */
+ RCU_CFG0 &= ~RCU_CFG0_SCS;
+ RCU_CFG0 |= RCU_CKSYSSRC_PLL;
+
+ /* wait until PLL is selected as system clock */
+ while(0U == (RCU_CFG0 & RCU_SCSS_PLL)){
+ }
+}
+
+#endif
+
+/**
+ * \defgroup NMSIS_Core_IntExcNMI_Handling Interrupt and Exception and NMI Handling
+ * \brief Functions for interrupt, exception and nmi handle available in system_<device>.c.
+ * \details
+ * Nuclei provide a template for interrupt, exception and NMI handling. Silicon Vendor could adapat according
+ * to their requirement. Silicon vendor could implement interface for different exception code and
+ * replace current implementation.
+ *
+ * @{
+ */
+/** \brief Max exception handler number, don't include the NMI(0xFFF) one */
+#define MAX_SYSTEM_EXCEPTION_NUM 12
+/**
+ * \brief Store the exception handlers for each exception ID
+ * \note
+ * - This SystemExceptionHandlers are used to store all the handlers for all
+ * the exception codes Nuclei N/NX core provided.
+ * - Exception code 0 - 11, totally 12 exceptions are mapped to SystemExceptionHandlers[0:11]
+ * - Exception for NMI is also re-routed to exception handling(exception code 0xFFF) in startup code configuration, the handler itself is mapped to SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM]
+ */
+static unsigned long SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM + 1];
+
+/**
+ * \brief Exception Handler Function Typedef
+ * \note
+ * This typedef is only used internal in this system_gd32vf103.c file.
+ * It is used to do type conversion for registered exception handler before calling it.
+ */
+typedef void (*EXC_HANDLER)(unsigned long mcause, unsigned long sp);
+
+/**
+ * \brief System Default Exception Handler
+ * \details
+ * This function provided a default exception and NMI handling code for all exception ids.
+ * By default, It will just print some information for debug, Vendor can customize it according to its requirements.
+ */
+static void system_default_exception_handler(unsigned long mcause, unsigned long sp)
+{
+ /* TODO: Uncomment this if you have implement printf function */
+ /*printf("MCAUSE: 0x%lx\r\n", mcause);
+ printf("MEPC : 0x%lx\r\n", __RV_CSR_READ(CSR_MEPC));
+ printf("MTVAL : 0x%lx\r\n", __RV_CSR_READ(CSR_MBADADDR));*/
+ while (1);
+}
+
+/**
+ * \brief Initialize all the default core exception handlers
+ * \details
+ * The core exception handler for each exception id will be initialized to \ref system_default_exception_handler.
+ * \note
+ * Called in \ref _init function, used to initialize default exception handlers for all exception IDs
+ */
+static void Exception_Init(void)
+{
+ for (int i = 0; i < MAX_SYSTEM_EXCEPTION_NUM + 1; i++) {
+ SystemExceptionHandlers[i] = (unsigned long)system_default_exception_handler;
+ }
+}
+
+/**
+ * \brief Register an exception handler for exception code EXCn
+ * \details
+ * * For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will be registered into SystemExceptionHandlers[EXCn-1].
+ * * For EXCn == NMI_EXCn, it will be registered into SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM].
+ * \param EXCn See \ref EXCn_Type
+ * \param exc_handler The exception handler for this exception code EXCn
+ */
+void Exception_Register_EXC(uint32_t EXCn, unsigned long exc_handler)
+{
+ if ((EXCn < MAX_SYSTEM_EXCEPTION_NUM) && (EXCn != 0)) {
+ SystemExceptionHandlers[EXCn] = exc_handler;
+ } else if (EXCn == NMI_EXCn) {
+ SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM] = exc_handler;
+ }
+}
+
+/**
+ * \brief Get current exception handler for exception code EXCn
+ * \details
+ * * For EXCn < \ref MAX_SYSTEM_EXCEPTION_NUM, it will return SystemExceptionHandlers[EXCn-1].
+ * * For EXCn == NMI_EXCn, it will return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM].
+ * \param EXCn See \ref EXCn_Type
+ * \return Current exception handler for exception code EXCn, if not found, return 0.
+ */
+unsigned long Exception_Get_EXC(uint32_t EXCn)
+{
+ if ((EXCn < MAX_SYSTEM_EXCEPTION_NUM) && (EXCn != 0)) {
+ return SystemExceptionHandlers[EXCn];
+ } else if (EXCn == NMI_EXCn) {
+ return SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * \brief Common NMI and Exception handler entry
+ * \details
+ * This function provided a command entry for NMI and exception. Silicon Vendor could modify
+ * this template implementation according to requirement.
+ * \remarks
+ * - RISCV provided common entry for all types of exception. This is proposed code template
+ * for exception entry function, Silicon Vendor could modify the implementation.
+ * - For the core_exception_handler template, we provided exception register function \ref Exception_Register_EXC
+ * which can help developer to register your exception handler for specific exception number.
+ */
+uint32_t core_exception_handler(unsigned long mcause, unsigned long sp)
+{
+ uint32_t EXCn = (uint32_t)(mcause & 0X00000fff);
+ EXC_HANDLER exc_handler;
+
+ if ((EXCn < MAX_SYSTEM_EXCEPTION_NUM) && (EXCn > 0)) {
+ exc_handler = (EXC_HANDLER)SystemExceptionHandlers[EXCn];
+ } else if (EXCn == NMI_EXCn) {
+ exc_handler = (EXC_HANDLER)SystemExceptionHandlers[MAX_SYSTEM_EXCEPTION_NUM];
+ } else {
+ exc_handler = (EXC_HANDLER)system_default_exception_handler;
+ }
+ if (exc_handler != NULL) {
+ exc_handler(mcause, sp);
+ }
+ return 0;
+}
+/** @} */ /* End of Doxygen Group NMSIS_Core_ExceptionAndNMI */
+
+/**
+ * \brief initialize eclic config
+ * \details
+ * Eclic need initialize after boot up, Vendor could also change the initialization
+ * configuration.
+ */
+void ECLIC_Init(void)
+{
+ /* TODO: Add your own initialization code here. This function will be called by main */
+ ECLIC_SetMth(0);
+ ECLIC_SetCfgNlbits(__ECLIC_INTCTLBITS);
+}
+
+/**
+ * \brief Initialize a specific IRQ and register the handler
+ * \details
+ * This function set vector mode, trigger mode and polarity, interrupt level and priority,
+ * assign handler for specific IRQn.
+ * \param [in] IRQn NMI interrupt handler address
+ * \param [in] shv \ref ECLIC_NON_VECTOR_INTERRUPT means non-vector mode, and \ref ECLIC_VECTOR_INTERRUPT is vector mode
+ * \param [in] trig_mode see \ref ECLIC_TRIGGER_Type
+ * \param [in] lvl interupt level
+ * \param [in] priority interrupt priority
+ * \param [in] handler interrupt handler, if NULL, handler will not be installed
+ * \return -1 means invalid input parameter. 0 means successful.
+ * \remarks
+ * - This function use to configure specific eclic interrupt and register its interrupt handler and enable its interrupt.
+ * - If the vector table is placed in read-only section(FLASHXIP mode), handler could not be installed
+ */
+int32_t ECLIC_Register_IRQ(IRQn_Type IRQn, uint8_t shv, ECLIC_TRIGGER_Type trig_mode, uint8_t lvl, uint8_t priority, void* handler)
+{
+ if ((IRQn > SOC_INT_MAX) || (shv > ECLIC_VECTOR_INTERRUPT) \
+ || (trig_mode > ECLIC_NEGTIVE_EDGE_TRIGGER)) {
+ return -1;
+ }
+
+ /* set interrupt vector mode */
+ ECLIC_SetShvIRQ(IRQn, shv);
+ /* set interrupt trigger mode and polarity */
+ ECLIC_SetTrigIRQ(IRQn, trig_mode);
+ /* set interrupt level */
+ ECLIC_SetLevelIRQ(IRQn, lvl);
+ /* set interrupt priority */
+ ECLIC_SetPriorityIRQ(IRQn, priority);
+ if (handler != NULL) {
+ /* set interrupt handler entry to vector table */
+ ECLIC_SetVector(IRQn, (rv_csr_t)handler);
+ }
+ /* enable interrupt */
+ ECLIC_EnableIRQ(IRQn);
+ return 0;
+}
+/** @} */ /* End of Doxygen Group NMSIS_Core_ExceptionAndNMI */
+
+/**
+ * \brief early init function before main
+ * \details
+ * This function is executed right before main function.
+ * For RISC-V gnu toolchain, _init function might not be called
+ * by __libc_init_array function, so we defined a new function
+ * to do initialization
+ */
+void _premain_init(void)
+{
+ /* Initialize exception default handlers */
+ Exception_Init();
+ /* ECLIC initialization, mainly MTH and NLBIT */
+ ECLIC_Init();
+}
+
+/**
+ * \brief finish function after main
+ * \param [in] status status code return from main
+ * \details
+ * This function is executed right after main function.
+ * For RISC-V gnu toolchain, _fini function might not be called
+ * by __libc_fini_array function, so we defined a new function
+ * to do initialization
+ */
+void _postmain_fini(int status)
+{
+ /* TODO: Add your own finishing code here, called after main */
+}
+
+/**
+ * \brief _init function called in __libc_init_array()
+ * \details
+ * This `__libc_init_array()` function is called during startup code,
+ * user need to implement this function, otherwise when link it will
+ * error init.c:(.text.__libc_init_array+0x26): undefined reference to `_init'
+ * \note
+ * Please use \ref _premain_init function now
+ */
+void _init(void)
+{
+ /* Don't put any code here, please use _premain_init now */
+}
+
+/**
+ * \brief _fini function called in __libc_fini_array()
+ * \details
+ * This `__libc_fini_array()` function is called when exit main.
+ * user need to implement this function, otherwise when link it will
+ * error fini.c:(.text.__libc_fini_array+0x28): undefined reference to `_fini'
+ * \note
+ * Please use \ref _postmain_fini function now
+ */
+void _fini(void)
+{
+ /* Don't put any code here, please use _postmain_fini now */
+}
+
+/** @} */ /* End of Doxygen Group NMSIS_Core_SystemAndClock */