1/*!2 \file system_gd32e23x.c3 \brief CMSIS Cortex-M23 Device Peripheral Access Layer Source File for4 GD32E23x Device Series5*/67/* Copyright (c) 2012 ARM LIMITED8 Copyright (c) 2026, GigaDevice Semiconductor Inc.910 All rights reserved.11 Redistribution and use in source and binary forms, with or without12 modification, are permitted provided that the following conditions are met:13 - Redistributions of source code must retain the above copyright14 notice, this list of conditions and the following disclaimer.15 - Redistributions in binary form must reproduce the above copyright16 notice, this list of conditions and the following disclaimer in the17 documentation and/or other materials provided with the distribution.18 - Neither the name of ARM nor the names of its contributors may be used19 to endorse or promote products derived from this software without20 specific prior written permission.21 *22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"23 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE24 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE25 ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE26 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR27 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF28 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS29 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN30 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE32 POSSIBILITY OF SUCH DAMAGE.33 ---------------------------------------------------------------------------*/3435/* This file refers the CMSIS standard, some adjustments are made according to GigaDevice chips */3637#include "gd32e23x.h"3839/* system frequency define */40#define __IRC8M (IRC8M_VALUE) /* internal 8 MHz RC oscillator frequency */41#define __HXTAL (HXTAL_VALUE) /* high speed crystal oscillator frequency */42#define __SYS_OSC_CLK (__IRC8M) /* main oscillator frequency */4344#define VECT_TAB_OFFSET (uint32_t)0x00 /* vector table base offset */4546/* select a system clock by uncommenting the following line */47/* 本板 OSCIN/OSCOUT(PF0/PF1)未接晶振。使用 HXTAL 会在等时钟稳定时死循环。 */48//#define __SYSTEM_CLOCK_8M_HXTAL (__HXTAL)49//#define __SYSTEM_CLOCK_8M_IRC8M (__IRC8M)50//#define __SYSTEM_CLOCK_72M_PLL_HXTAL (uint32_t)(72000000)51#define __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2 (uint32_t)(72000000)5253/* The following is to prevent Vcore fluctuations caused by frequency switching.54 It is strongly recommended to include it to avoid issues caused by self-removal.55*/56#define RCU_MODIFY(__delay) do{ \57 volatile uint32_t i,reg; \58 if(0U != (__delay)){ \59 reg = RCU_CFG0; \60 reg &= ~(RCU_CFG0_AHBPSC); \61 /* CK_AHB = SYSCLK/2 */ \62 reg |= RCU_AHB_CKSYS_DIV2; \63 RCU_CFG0 = reg; \64 for(i=0U; i<(__delay); i++){ \65 } \66 reg = RCU_CFG0; \67 reg &= ~(RCU_CFG0_AHBPSC); \68 reg |= RCU_AHB_CKSYS_DIV4; \69 /* CK_AHB = SYSCLK/4 */ \70 RCU_CFG0 = reg; \71 for(i=0U; i<(__delay); i++){ \72 } \73 } \74 }while(0U)7576#define RCU_MODIFY_UP_2(__delay) do{ \77 volatile uint32_t i,reg; \78 if(0U != (__delay)){ \79 for(i=0U; i<(__delay); i++){ \80 } \81 reg = RCU_CFG0; \82 reg &= ~(RCU_CFG0_AHBPSC); \83 reg |= RCU_AHB_CKSYS_DIV2; \84 RCU_CFG0 = reg; \85 for(i=0U; i<(__delay); i++){ \86 } \87 reg = RCU_CFG0; \88 reg &= ~(RCU_CFG0_AHBPSC); \89 reg |= RCU_AHB_CKSYS_DIV1; \90 RCU_CFG0 = reg; \91 } \92 }while(0U)9394#define SEL_IRC8M 0x00U95#define SEL_HXTAL 0x01U96#define SEL_PLL 0x02U9798/* set the system clock frequency and declare the system clock configuration function */99#ifdef __SYSTEM_CLOCK_8M_HXTAL100uint32_t SystemCoreClock = __SYSTEM_CLOCK_8M_HXTAL;101static void system_clock_8m_hxtal(void);102103#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)104uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_HXTAL;105static void system_clock_72m_hxtal(void);106107#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)108uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2;109static void system_clock_72m_irc8m(void);110111#else112uint32_t SystemCoreClock = __SYSTEM_CLOCK_8M_IRC8M;113static void system_clock_8m_irc8m(void);114#endif /* __SYSTEM_CLOCK_8M_HXTAL */115116/* configure the system clock */117static void system_clock_config(void);118static void _soft_delay_(uint32_t time);119120/* software delay to prevent the impact of Vcore fluctuations.121 It is strongly recommended to include it to avoid issues caused by self-removal. */122static void _soft_delay_(uint32_t time)123{124 __IO uint32_t i;125 for(i=0U; i<time*10U; i++){126 }127}128129/*!130 \brief setup the microcontroller system, initialize the system131 \param[in] none132 \param[out] none133 \retval none134 \note This function contains scenarios leading to an infinite loop.135 Modify according to the use's actual usage scenarios.136*/137void SystemInit(void)138{139 /* enable IRC8M */140 RCU_CTL0 |= RCU_CTL0_IRC8MEN;141 while(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){142 }143 if(((RCU_CFG0 & RCU_CFG0_SCSS) == RCU_SCSS_PLL)){144 RCU_MODIFY(0x80U);145 }146 RCU_CFG0 &= ~RCU_CFG0_SCS;147 _soft_delay_(100U);148 RCU_CTL0 &= ~(RCU_CTL0_HXTALEN | RCU_CTL0_CKMEN | RCU_CTL0_PLLEN | RCU_CTL0_HXTALBPS);149 /* reset RCU */150 RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |\151 RCU_CFG0_ADCPSC | RCU_CFG0_CKOUTSEL | RCU_CFG0_CKOUTDIV | RCU_CFG0_PLLDV);152 RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4 | RCU_CFG0_PLLDV);153 RCU_CFG1 &= ~(RCU_CFG1_PREDV);154 RCU_CFG2 &= ~(RCU_CFG2_USART0SEL | RCU_CFG2_ADCSEL);155 RCU_CFG2 &= ~RCU_CFG2_IRC28MDIV;156 RCU_CFG2 &= ~RCU_CFG2_ADCPSC2;157 RCU_CTL1 &= ~RCU_CTL1_IRC28MEN;158 RCU_INT = 0x00000000U;159160 /* configure system clock */161 system_clock_config();162 163#ifdef VECT_TAB_SRAM164 nvic_vector_table_set(NVIC_VECTTAB_RAM,VECT_TAB_OFFSET);165#else166 nvic_vector_table_set(NVIC_VECTTAB_FLASH,VECT_TAB_OFFSET);167#endif168}169170/*!171 \brief configure the system clock172 \param[in] none173 \param[out] none174 \retval none175*/176static void system_clock_config(void)177{178#ifdef __SYSTEM_CLOCK_8M_HXTAL179 system_clock_8m_hxtal();180#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)181 system_clock_72m_hxtal();182#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)183 system_clock_72m_irc8m();184#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC48M_DIV2)185 system_clock_72m_irc48m();186#else187 system_clock_8m_irc8m();188#endif /* __SYSTEM_CLOCK_8M_HXTAL */189}190191#ifdef __SYSTEM_CLOCK_8M_HXTAL192/*!193 \brief configure the system clock to 8M by HXTAL194 \param[in] none195 \param[out] none196 \retval none197 \note This function contains scenarios leading to an infinite loop.198 Modify according to the use's actual usage scenarios.199*/200static void system_clock_8m_hxtal(void)201{202 uint32_t timeout = 0U;203 uint32_t stab_flag = 0U;204 __IO uint32_t reg_temp;205206 /* enable HXTAL */207 RCU_CTL0 |= RCU_CTL0_HXTALEN;208 209 /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */210 do{211 timeout++;212 stab_flag = (RCU_CTL0 & RCU_CTL0_HXTALSTB);213 }214 while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout)); 215 /* if fail */216 if(0U == (RCU_CTL0 & RCU_CTL0_HXTALSTB)){217 while(1){218 }219 }220 221 /* HXTAL is stable */222 /* AHB = SYSCLK */223 RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;224 /* APB2 = AHB */225 RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;226 /* APB1 = AHB */227 RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;228229 reg_temp = RCU_CFG0;230 /* select HXTAL as system clock */231 reg_temp &= ~RCU_CFG0_SCS;232 reg_temp |= RCU_CKSYSSRC_HXTAL;233 RCU_CFG0 = reg_temp;234 235 /* wait until HXTAL is selected as system clock */236 while(RCU_SCSS_HXTAL != (RCU_CFG0 & RCU_CFG0_SCSS)){237 }238}239240#elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)241/*!242 \brief configure the system clock to 72M by PLL which selects HXTAL as its clock source243 \param[in] none244 \param[out] none245 \retval none246 \note This function contains scenarios leading to an infinite loop.247 Modify according to the use's actual usage scenarios.248*/249static void system_clock_72m_hxtal(void)250{251 uint32_t timeout = 0U;252 uint32_t stab_flag = 0U;253 __IO uint32_t reg_temp;254 255 /* enable HXTAL */256 RCU_CTL0 |= RCU_CTL0_HXTALEN;257258 /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */259 do{260 timeout++;261 stab_flag = (RCU_CTL0 & RCU_CTL0_HXTALSTB);262 }263 while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));264 /* if fail */265 if(0U == (RCU_CTL0 & RCU_CTL0_HXTALSTB)){266 while(1){267 }268 }269 270 FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT_2;271 272 /* HXTAL is stable */273 /* AHB = SYSCLK/4 */274 RCU_CFG0 |= RCU_AHB_CKSYS_DIV4;275 /* APB2 = AHB */276 RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;277 /* APB1 = AHB */278 RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;279280 /* PLL = HXTAL * 9 = 72 MHz */281 RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLDV);282 RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL9);283284 /* enable PLL */285 RCU_CTL0 |= RCU_CTL0_PLLEN;286287 /* wait until PLL is stable */288 while(0U == (RCU_CTL0 & RCU_CTL0_PLLSTB)){289 }290291 reg_temp = RCU_CFG0;292 /* select PLL as system clock */293 reg_temp &= ~RCU_CFG0_SCS;294 reg_temp |= RCU_CKSYSSRC_PLL;295 RCU_CFG0 = reg_temp;296297 /* wait until PLL is selected as system clock */298 while(RCU_SCSS_PLL != (RCU_CFG0 & RCU_CFG0_SCSS)){299 }300301 RCU_MODIFY_UP_2(0x80U);302}303304#elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M_DIV2)305/*!306 \brief configure the system clock to 72M by PLL which selects IRC8M/2 as its clock source307 \param[in] none308 \param[out] none309 \retval none310 \note This function contains scenarios leading to an infinite loop.311 Modify according to the use's actual usage scenarios.312*/313static void system_clock_72m_irc8m(void)314{315 uint32_t timeout = 0U;316 uint32_t stab_flag = 0U;317 __IO uint32_t reg_temp;318 319 /* enable IRC8M */320 RCU_CTL0 |= RCU_CTL0_IRC8MEN;321322 /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */323 do{324 timeout++;325 stab_flag = (RCU_CTL0 & RCU_CTL0_IRC8MSTB);326 }327 while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));328329 /* if fail */330 if(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){331 while(1){332 }333 }334335 FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT_2;336 337 /* AHB = SYSCLK/4 */338 RCU_CFG0 |= RCU_AHB_CKSYS_DIV4;339 /* APB2 = AHB */340 RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;341 /* APB1 = AHB */342 RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;343 /* PLL = (IRC8M/2) * 18 = 72 MHz */344 RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF);345 RCU_CFG0 |= (RCU_PLLSRC_IRC8M_DIV2 | RCU_PLL_MUL18);346 347 /* enable PLL */348 RCU_CTL0 |= RCU_CTL0_PLLEN;349350 /* wait until PLL is stable */351 while(0U == (RCU_CTL0 & RCU_CTL0_PLLSTB)){352 }353354 reg_temp = RCU_CFG0;355 /* select PLL as system clock */356 reg_temp &= ~RCU_CFG0_SCS;357 reg_temp |= RCU_CKSYSSRC_PLL;358 RCU_CFG0 = reg_temp;359360 /* wait until PLL is selected as system clock */361 while(RCU_SCSS_PLL != (RCU_CFG0 & RCU_CFG0_SCSS)){362 }363364 RCU_MODIFY_UP_2(0x80);365}366367#else368/*!369 \brief configure the system clock to 8M by IRC8M370 \param[in] none371 \param[out] none372 \retval none373 \note This function contains scenarios leading to an infinite loop.374 Modify according to the use's actual usage scenarios.375*/376static void system_clock_8m_irc8m(void)377{378 uint32_t timeout = 0U;379 uint32_t stab_flag = 0U;380 __IO uint32_t reg_temp;381 382 /* enable IRC8M */383 RCU_CTL0 |= RCU_CTL0_IRC8MEN;384385 /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */386 do{387 timeout++;388 stab_flag = (RCU_CTL0 & RCU_CTL0_IRC8MSTB);389 }390 while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));391392 /* if fail */393 if(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){394 while(1){395 }396 }397398 /* AHB = SYSCLK */399 RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;400 /* APB2 = AHB */401 RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;402 /* APB1 = AHB */403 RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;404 405 reg_temp = RCU_CFG0;406 /* select IRC8M as system clock */407 reg_temp &= ~RCU_CFG0_SCS;408 reg_temp |= RCU_CKSYSSRC_IRC8M;409 RCU_CFG0 = reg_temp;410 411 /* wait until IRC8M is selected as system clock */412 while(RCU_SCSS_IRC8M != (RCU_CFG0 & RCU_CFG0_SCSS)){413 }414}415#endif /* __SYSTEM_CLOCK_8M_HXTAL */416417/*!418 \brief update the SystemCoreClock with current core clock retrieved from cpu registers419 \param[in] none420 \param[out] none421 \retval none422*/423void SystemCoreClockUpdate (void)424{425 uint32_t sws = 0U;426 uint32_t pllmf = 0U, pllmf4 = 0U, pllsel = 0U, prediv = 0U, idx = 0U, clk_exp = 0U;427 /* exponent of AHB clock divider */428 const uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};429430 sws = GET_BITS(RCU_CFG0, 2, 3);431 switch(sws){432 /* IRC8M is selected as CK_SYS */433 case SEL_IRC8M:434 SystemCoreClock = IRC8M_VALUE;435 break;436 /* HXTAL is selected as CK_SYS */437 case SEL_HXTAL:438 SystemCoreClock = HXTAL_VALUE;439 break;440 /* PLL is selected as CK_SYS */441 case SEL_PLL:442 /* get the value of PLLMF[3:0] */443 pllmf = GET_BITS(RCU_CFG0, 18, 21);444 pllmf4 = GET_BITS(RCU_CFG0, 27, 27);445 /* high 16 bits */446 if(1U == pllmf4){447 pllmf += 17U;448 }else if(15U == pllmf){449 pllmf = 16U;450 } else {451 pllmf += 2U;452 }453 454 /* PLL clock source selection, HXTAL or IRC8M/2 */455 pllsel = GET_BITS(RCU_CFG0, 16, 16);456 if(0U != pllsel){457 prediv = (GET_BITS(RCU_CFG1, 0, 3) + 1U);458 SystemCoreClock = (HXTAL_VALUE / prediv) * pllmf;459 } else {460 SystemCoreClock = (IRC8M_VALUE >> 1) * pllmf;461 }462 break;463 /* IRC8M is selected as CK_SYS */464 default:465 SystemCoreClock = IRC8M_VALUE;466 break;467 }468 /* calculate AHB clock frequency */469 idx = GET_BITS(RCU_CFG0, 4, 7);470 clk_exp = ahb_exp[idx];471 SystemCoreClock >>= clk_exp;472}473474#ifdef __FIRMWARE_VERSION_DEFINE475/*!476 \brief get firmware version477 \param[in] none478 \param[out] none479 \retval firmware version480*/481uint32_t gd32e23x_firmware_version_get(void)482{483 return (uint32_t)__GD32E23x_STDPERIPH_VERSION;484}485#endif /* __FIRMWARE_VERSION_DEFINE */