|
|
@@ -0,0 +1,1256 @@
|
|
|
+/*!
|
|
|
+ \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 "gd32vf103_libopt.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 */
|
|
|
+
|
|
|
+/* select a system clock by uncommenting the following line */
|
|
|
+/* use IRC8M */
|
|
|
+//#define __SYSTEM_CLOCK_48M_PLL_IRC8M (uint32_t)(48000000)
|
|
|
+//#define __SYSTEM_CLOCK_72M_PLL_IRC8M (uint32_t)(72000000)
|
|
|
+//#define __SYSTEM_CLOCK_108M_PLL_IRC8M (uint32_t)(108000000)
|
|
|
+
|
|
|
+/********************************************************************/
|
|
|
+//#define __SYSTEM_CLOCK_HXTAL (HXTAL_VALUE)
|
|
|
+//#define __SYSTEM_CLOCK_24M_PLL_HXTAL (uint32_t)(24000000)
|
|
|
+/********************************************************************/
|
|
|
+
|
|
|
+//#define __SYSTEM_CLOCK_36M_PLL_HXTAL (uint32_t)(36000000)
|
|
|
+//#define __SYSTEM_CLOCK_48M_PLL_HXTAL (uint32_t)(48000000)
|
|
|
+//#define __SYSTEM_CLOCK_56M_PLL_HXTAL (uint32_t)(56000000)
|
|
|
+//#define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)
|
|
|
+#define __SYSTEM_CLOCK_96M_PLL_HXTAL (uint32_t)(96000000)
|
|
|
+//#define __SYSTEM_CLOCK_108M_PLL_HXTAL (uint32_t)(108000000)
|
|
|
+
|
|
|
+/*#define SEL_IRC8M 0x00U
|
|
|
+#define SEL_HXTAL 0x01U
|
|
|
+#define SEL_PLL 0x02U*/
|
|
|
+
|
|
|
+/* set the system clock frequency and declare the system clock configuration function */
|
|
|
+#ifdef __SYSTEM_CLOCK_48M_PLL_IRC8M
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_IRC8M;
|
|
|
+static void system_clock_48m_irc8m(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_IRC8M;
|
|
|
+static void system_clock_72m_irc8m(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_108M_PLL_IRC8M)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_108M_PLL_IRC8M;
|
|
|
+static void system_clock_108m_irc8m(void);
|
|
|
+
|
|
|
+#elif defined (__SYSTEM_CLOCK_HXTAL)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_HXTAL;
|
|
|
+static void system_clock_hxtal(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_24M_PLL_HXTAL;
|
|
|
+static void system_clock_24m_hxtal(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_36M_PLL_HXTAL)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_36M_PLL_HXTAL;
|
|
|
+static void system_clock_36m_hxtal(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_HXTAL;
|
|
|
+static void system_clock_48m_hxtal(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_56M_PLL_HXTAL)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_56M_PLL_HXTAL;
|
|
|
+static void system_clock_56m_hxtal(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_HXTAL;
|
|
|
+static void system_clock_72m_hxtal(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_96M_PLL_HXTAL)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_96M_PLL_HXTAL;
|
|
|
+static void system_clock_96m_hxtal(void);
|
|
|
+#elif defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)
|
|
|
+uint32_t SystemCoreClock = __SYSTEM_CLOCK_108M_PLL_HXTAL;
|
|
|
+static void system_clock_108m_hxtal(void);
|
|
|
+#else
|
|
|
+uint32_t SystemCoreClock = IRC8M_VALUE;
|
|
|
+#endif /* __SYSTEM_CLOCK_48M_PLL_IRC8M */
|
|
|
+
|
|
|
+/* 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)
|
|
|
+{
|
|
|
+#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 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;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#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_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 */
|
|
|
+
|
|
|
+void SystemBannerPrint(void)
|
|
|
+{
|
|
|
+#if defined(NUCLEI_BANNER) && (NUCLEI_BANNER == 1)
|
|
|
+#ifndef DOWNLOAD_MODE
|
|
|
+#error DOWNLOAD_MODE is not defined via build system, please check!
|
|
|
+#endif
|
|
|
+ const char* download_modes[] = {"FLASHXIP", "FLASH", "ILM", "DDR"};
|
|
|
+ printf("Nuclei SDK Build Time: %s, %s\r\n", __DATE__, __TIME__);
|
|
|
+ printf("Download Mode: %s\r\n", download_modes[DOWNLOAD_MODE]);
|
|
|
+ printf("CPU Frequency %d 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 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 */
|
|
|
+ //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 */
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * \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 */
|