Files
2026-10-11 21:48:59 +08:00

1353 lines
43 KiB
C

/******************************************************************************
* @file system_gd32vf103.c
* @brief NMSIS Nuclei Core Device Peripheral Access Layer Source File for
* Device gd32vf103
* @version V1.00
* @date 22. Nov 2019
******************************************************************************/
/*
* Copyright (c) 2009-2018 Arm Limited. All rights reserved.
* Copyright (c) 2019 Nuclei Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include "nuclei_sdk_hal.h"
/*----------------------------------------------------------------------------
Define clocks
*----------------------------------------------------------------------------*/
/* ToDo: add here your necessary defines for device initialization
following is an example for different system frequencies */
// When using nuclei-sdk build system, refer to SoC/gd32vf103/build.mk
// SYSTEM_CLOCK is defined via SYSCLK make variable
// SYSCLK_USING_IRC8M will be defined when CLKSRC=irc8m
#ifndef SYSTEM_CLOCK
#define SYSTEM_CLOCK 108000000
#endif
/**
* \defgroup NMSIS_Core_SystemAndClock System and Clock Configuration
* \brief Functions for system and clock setup available in system_<device>.c.
* \details
* Nuclei provides a template file **system_Device.c** that must be adapted by
* the silicon vendor to match their actual device. As a <b>minimum requirement</b>,
* this file must provide:
* - A device-specific system configuration function, \ref SystemInit().
* - A global variable that contains the system frequency, \ref SystemCoreClock.
*
* The file configures the device and, typically, initializes the oscillator (PLL) that is part
* of the microcontroller device. This file might export other functions or variables that provide
* a more flexible configuration of the microcontroller system.
*
* \note Please pay special attention to the static variable \c SystemCoreClock. This variable might be
* used throughout the whole system initialization and runtime to calculate frequency/time related values.
* Thus one must assure that the variable always reflects the actual system clock speed.
*
* \attention
* Be aware that a value stored to \c SystemCoreClock during low level initialization (i.e. \c SystemInit()) might get
* overwritten by C libray startup code and/or .bss section initialization.
* Thus its highly recommended to call \ref SystemCoreClockUpdate at the beginning of the user \c main() routine.
*
* @{
*/
/*----------------------------------------------------------------------------
System Core Clock Variable
*----------------------------------------------------------------------------*/
/* ToDo: initialize SystemCoreClock with the system core clock frequency value
achieved after system intitialization.
This means system core clock frequency after call to SystemInit() */
/**
* \brief Variable to hold the system core clock value
* \details
* Holds the system core clock, which is the system clock frequency supplied to the SysTick
* timer and the processor core clock. This variable can be used by debuggers to query the
* frequency of the debug timer or to configure the trace clock speed.
*
* \attention
* Compilers must be configured to avoid removing this variable in case the application
* program is not using it. Debugging systems require the variable to be physically
* present in memory so that it can be examined to configure the debugger.
*/
/*----------------------------------------------------------------------------
Clock functions
*----------------------------------------------------------------------------*/
/* 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 */
/********************************************************************/
/* select a system clock by uncommenting the following line */
#ifdef SYSCLK_USING_IRC8M
/* use IRC8M */
#if SYSTEM_CLOCK == 48000000
#define __SYSTEM_CLOCK_48M_PLL_IRC8M (uint32_t)(48000000)
#elif SYSTEM_CLOCK == 72000000
#define __SYSTEM_CLOCK_72M_PLL_IRC8M (uint32_t)(72000000)
#elif SYSTEM_CLOCK == 108000000
#define __SYSTEM_CLOCK_108M_PLL_IRC8M (uint32_t)(108000000)
#else
#error "Need to define correct SYSTEM_CLOCK for using IRC8M"
#endif
#else /* SYSCLK_USING_IRC8M */
/* use HXTAL */
#if SYSTEM_CLOCK == 24000000
#define __SYSTEM_CLOCK_24M_PLL_HXTAL (uint32_t)(24000000)
#elif SYSTEM_CLOCK == 36000000
#define __SYSTEM_CLOCK_36M_PLL_HXTAL (uint32_t)(36000000)
#elif SYSTEM_CLOCK == 48000000
#define __SYSTEM_CLOCK_48M_PLL_HXTAL (uint32_t)(48000000)
#elif SYSTEM_CLOCK == 56000000
#define __SYSTEM_CLOCK_56M_PLL_HXTAL (uint32_t)(56000000)
#elif SYSTEM_CLOCK == 72000000
#define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
#elif SYSTEM_CLOCK == 96000000
#define __SYSTEM_CLOCK_96M_PLL_HXTAL (uint32_t)(96000000)
#elif SYSTEM_CLOCK == 108000000
#define __SYSTEM_CLOCK_108M_PLL_HXTAL (uint32_t)(108000000)
#else
#warning "using HXTAL_VALUE as __SYSTEM_CLOCK_HXTAL for using HXTAL"
#define __SYSTEM_CLOCK_HXTAL (HXTAL_VALUE)
#endif
#endif
/********************************************************************/
/* set the system clock frequency and declare the system clock configuration function */
#ifdef __SYSTEM_CLOCK_48M_PLL_IRC8M
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_IRC8M;
static void system_clock_48m_irc8m(void);
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_IRC8M;
static void system_clock_72m_irc8m(void);
#elif defined (__SYSTEM_CLOCK_108M_PLL_IRC8M)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_108M_PLL_IRC8M;
static void system_clock_108m_irc8m(void);
#elif defined (__SYSTEM_CLOCK_HXTAL)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_HXTAL;
static void system_clock_hxtal(void);
#elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_24M_PLL_HXTAL;
static void system_clock_24m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_36M_PLL_HXTAL)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_36M_PLL_HXTAL;
static void system_clock_36m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_HXTAL;
static void system_clock_48m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_56M_PLL_HXTAL)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_56M_PLL_HXTAL;
static void system_clock_56m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_HXTAL;
static void system_clock_72m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_96M_PLL_HXTAL)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_96M_PLL_HXTAL;
static void system_clock_96m_hxtal(void);
#elif defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)
volatile uint32_t SystemCoreClock = __SYSTEM_CLOCK_108M_PLL_HXTAL;
static void system_clock_108m_hxtal(void);
#else
volatile uint32_t SystemCoreClock = IRC8M_VALUE;
#endif /* __SYSTEM_CLOCK_48M_PLL_IRC8M */
/*!
\brief configure the system clock
\param[in] none
\param[out] none
\retval none
*/
void system_clock_config(void)
{
#ifdef __SYSTEM_CLOCK_HXTAL
system_clock_hxtal();
#elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
system_clock_24m_hxtal();
#elif defined (__SYSTEM_CLOCK_36M_PLL_HXTAL)
system_clock_36m_hxtal();
#elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
system_clock_48m_hxtal();
#elif defined (__SYSTEM_CLOCK_56M_PLL_HXTAL)
system_clock_56m_hxtal();
#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
system_clock_72m_hxtal();
#elif defined (__SYSTEM_CLOCK_96M_PLL_HXTAL)
system_clock_96m_hxtal();
#elif defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)
system_clock_108m_hxtal();
#elif defined (__SYSTEM_CLOCK_48M_PLL_IRC8M)
system_clock_48m_irc8m();
#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
system_clock_72m_irc8m();
#elif defined (__SYSTEM_CLOCK_108M_PLL_IRC8M)
system_clock_108m_irc8m();
#endif /* __SYSTEM_CLOCK_HXTAL */
}
/**
* \brief Function to Initialize the system.
* \details
* Initializes the microcontroller system. Typically, this function configures the
* oscillator (PLL) that is part of the microcontroller device. For systems
* with a variable clock speed, it updates the variable \ref SystemCoreClock.
* SystemInit is called from the file <b>startup<i>_device</i></b>.
*/
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;
}
}
#ifdef __SYSTEM_CLOCK_HXTAL
/*!
\brief configure the system clock to HXTAL
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_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){
}
}
/* 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;
/* select HXTAL as system clock */
RCU_CFG0 &= ~RCU_CFG0_SCS;
RCU_CFG0 |= RCU_CKSYSSRC_HXTAL;
/* wait until HXTAL is selected as system clock */
while(0 == (RCU_CFG0 & RCU_SCSS_HXTAL)){
}
}
#elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
/*!
\brief configure the system clock to 24M 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_24m_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) * 6 = 24 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL6);
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_36M_PLL_HXTAL)
/*!
\brief configure the system clock to 36M 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_36m_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) * 9 = 36 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL9);
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_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_56M_PLL_HXTAL)
/*!
\brief configure the system clock to 56M 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_56m_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) * 14 = 56 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL14);
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)){
}
}
#elif defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)
/*!
\brief configure the system clock to 108M 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_108m_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) * 27 = 108 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL27);
if(HXTAL_VALUE==25000000){
/* CK_PREDIV0 = (CK_HXTAL)/5 *8 /10 = 4 MHz */
RCU_CFG1 &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PREDV0);
RCU_CFG1 |= (RCU_PREDV0SRC_CKPLL1 | RCU_PREDV1_DIV5 | RCU_PLL1_MUL8 | RCU_PREDV0_DIV10);
/* enable PLL1 */
RCU_CTL |= RCU_CTL_PLL1EN;
/* wait till PLL1 is ready */
while(0U == (RCU_CTL & RCU_CTL_PLL1STB)){
}
/* enable PLL1 */
RCU_CTL |= RCU_CTL_PLL2EN;
/* wait till PLL1 is ready */
while(0U == (RCU_CTL & RCU_CTL_PLL2STB)){
}
}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 | RCU_PREDV1_DIV2 | RCU_PLL1_MUL20 | RCU_PLL2_MUL20);
/* enable PLL1 */
RCU_CTL |= RCU_CTL_PLL1EN;
/* wait till PLL1 is ready */
while(0U == (RCU_CTL & RCU_CTL_PLL1STB)){
}
/* enable PLL2 */
RCU_CTL |= RCU_CTL_PLL2EN;
/* wait till PLL1 is ready */
while(0U == (RCU_CTL & RCU_CTL_PLL2STB)){
}
}
/* 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_48M_PLL_IRC8M)
/*!
\brief configure the system clock to 48M by PLL which selects IRC8M as its clock source
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_48m_irc8m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
/* enable IRC8M */
RCU_CTL |= RCU_CTL_IRC8MEN;
/* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
}
while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){
while(1){
}
}
/* IRC8M 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_IRC8M/2) * 12 = 48 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
RCU_CFG0 |= RCU_PLL_MUL12;
/* 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_IRC8M)
/*!
\brief configure the system clock to 72M by PLL which selects IRC8M as its clock source
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_72m_irc8m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
/* enable IRC8M */
RCU_CTL |= RCU_CTL_IRC8MEN;
/* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
}
while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){
while(1){
}
}
/* IRC8M 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_IRC8M/2) * 18 = 72 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
RCU_CFG0 |= RCU_PLL_MUL18;
/* 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_108M_PLL_IRC8M)
/*!
\brief configure the system clock to 108M by PLL which selects IRC8M as its clock source
\param[in] none
\param[out] none
\retval none
*/
static void system_clock_108m_irc8m(void)
{
uint32_t timeout = 0U;
uint32_t stab_flag = 0U;
/* enable IRC8M */
RCU_CTL |= RCU_CTL_IRC8MEN;
/* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
do{
timeout++;
stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
}
while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
/* if fail */
if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){
while(1){
}
}
/* IRC8M 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_IRC8M/2) * 27 = 108 MHz */
RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
RCU_CFG0 |= RCU_PLL_MUL27;
/* 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_MTVAL));
Exception_DumpFrame(sp, PRV_M);
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) {
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) {
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) {
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 */
void SystemBannerPrint(void)
{
#if defined(NUCLEI_BANNER) && (NUCLEI_BANNER == 1)
printf("Nuclei SDK Build Time: %s, %s\r\n", __DATE__, __TIME__);
#ifdef DOWNLOAD_MODE_STRING
printf("Download Mode: %s\r\n", DOWNLOAD_MODE_STRING);
#endif
printf("CPU Frequency %" PRIu32 " Hz\r\n", SystemCoreClock);
#endif
}
/**
* \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 Dump Exception Frame
* \details
* This function provided feature to dump exception frame stored in stack.
*/
void Exception_DumpFrame(unsigned long sp, uint8_t mode)
{
EXC_Frame_Type *exc_frame = (EXC_Frame_Type *)sp;
#ifndef __riscv_32e
printf("ra: 0x%lx, tp: 0x%lx, t0: 0x%lx, t1: 0x%lx, t2: 0x%lx, t3: 0x%lx, t4: 0x%lx, t5: 0x%lx, t6: 0x%lx\n" \
"a0: 0x%lx, a1: 0x%lx, a2: 0x%lx, a3: 0x%lx, a4: 0x%lx, a5: 0x%lx, a6: 0x%lx, a7: 0x%lx\n" \
"cause: 0x%lx, epc: 0x%lx, subm: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0, \
exc_frame->t1, exc_frame->t2, exc_frame->t3, exc_frame->t4, exc_frame->t5, exc_frame->t6, \
exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, exc_frame->a4, exc_frame->a5, \
exc_frame->a6, exc_frame->a7, exc_frame->cause, exc_frame->epc, exc_frame->subm);
#else
printf("ra: 0x%lx, tp: 0x%lx, t0: 0x%lx, t1: 0x%lx, t2: 0x%lx\n" \
"a0: 0x%lx, a1: 0x%lx, a2: 0x%lx, a3: 0x%lx, a4: 0x%lx, a5: 0x%lx\n" \
"cause: 0x%lx, epc: 0x%lx, subm: 0x%lx\n", exc_frame->ra, exc_frame->tp, exc_frame->t0, \
exc_frame->t1, exc_frame->t2, exc_frame->a0, exc_frame->a1, exc_frame->a2, exc_frame->a3, \
exc_frame->a4, exc_frame->a5, exc_frame->cause, exc_frame->epc, exc_frame->subm);
#endif
}
/**
* \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)
{
/* TODO: Add your own initialization code here, called before main */
// No need to get SystemCoreClock now, it is initialized by PLL it get it via this function
//SystemCoreClock = get_cpu_freq();
/* configure USART */
gd_com_init(SOC_DEBUG_UART);
/* Display banner after UART initialized */
SystemBannerPrint();
/* 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 */
#if defined(SIMULATION_MODE)
extern void simulation_exit(int status);
simulation_exit(status);
#endif
}
/**
* \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 */