| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |  \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 */ | 
					
						
							| 
									
										
										
										
											2021-08-15 17:19:25 +07:00
										 |  |  | #include "board.h"
 | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* 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 */
 | 
					
						
							| 
									
										
										
										
											2021-08-07 11:03:16 +02:00
										 |  |  | #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); | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							| 
									
										
										
										
											2021-08-07 11:03:16 +02:00
										 |  |  | #error No valid system clock configuration set!
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* 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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-08-07 11:03:16 +02:00
										 |  |  | #if defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
 | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2023-03-17 16:12:49 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  |     /* 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 */ | 
					
						
							| 
									
										
										
										
											2023-03-17 16:12:49 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2023-03-17 16:12:49 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  |         /* HXTAL is selected as CK_SYS */ | 
					
						
							|  |  |  |         case SEL_HXTAL: | 
					
						
							|  |  |  |             SystemCoreClock = HXTAL_VALUE; | 
					
						
							|  |  |  |             break; | 
					
						
							| 
									
										
										
										
											2023-03-17 16:12:49 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  |         /* 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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-07 11:03:16 +02:00
										 |  |  | #if defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
 | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  | /*!
 | 
					
						
							|  |  |  |     \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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-17 16:12:49 +07:00
										 |  |  |     /* CK_PLL = (CK_PREDIV0) * 18 = 72 MHz */ | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2022-12-04 13:58:47 +07:00
										 |  |  |  * \param [in]  lvl         interrupt level | 
					
						
							| 
									
										
										
										
											2021-07-10 11:17:24 +02:00
										 |  |  |  * \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 */ |