initial:从GD32C103移植(未测试)

This commit is contained in:
cbb
2026-05-06 01:17:42 +08:00
commit 77fc3f44b0
98 changed files with 59481 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# Clangd
.clangd
# uv2csolution generated log file
uv2csolution.log
# CMSIS Solution files and folders not to be tracked
# generated RTE files
**/RTE/_*/RTE_Components.h
**/RTE/_*/Pre_Include_*.h
# default directory of build artifacts
**/out
# directory containing intermediate files to be regenerated
**/tmp
# Update config files must be merged before commit
*.update@*
# cbuild output files
*.cbuild.yml
*.cbuild-idx.yml
*.cbuild-run.yml
*.cbuild-set.yml
# .vscode JSON and debug adapter files generated by CMSIS Solution
.vscode/cmsis.json
.vscode/launch.json
.vscode/tasks.json
.vscode/settings.json
.cmd.jlink
# legacy intermediate project file
*.cprj
+14
View File
@@ -0,0 +1,14 @@
cbuild-pack:
resolved-packs:
- resolved-pack: ARM::CMSIS@6.1.0
selected-by-pack:
- ARM::CMSIS
- resolved-pack: ARM::CMSIS-DSP@1.16.2
selected-by-pack:
- ARM::CMSIS-DSP
- resolved-pack: ARM::CMSIS-NN@4.1.0
selected-by-pack:
- ARM::CMSIS-NN
- resolved-pack: GigaDevice::GD32E50x_DFP@1.9.0
selected-by-pack:
- GigaDevice::GD32E50x_DFP
+47
View File
@@ -0,0 +1,47 @@
# A solution is a collection of related projects that share same base configuration.
solution:
created-for: CMSIS-Toolbox@2.13.0
cdefault: # use CMSIS-Toolbox default Compiler options
# Compilers that can be selected
select-compiler:
- compiler: AC6
- compiler: GCC
- compiler: IAR
- compiler: CLANG
# List of miscellaneous tool-specific controls
misc:
- for-compiler: AC6 # GDB requires DWARF 5, remove when using uVision Debugger
C-CPP:
- -gdwarf-5
ASM:
- -gdwarf-5
# List different hardware targets that are used to deploy the solution.
target-types:
- type: GD32E508VE
device: GD32E508VE
target-set:
- set:
images:
- project-context: GD32E50X_BOOT.Debug
debugger:
name: ST-Link@pyOCD
clock: 4000000
protocol: swd
# List of different build configurations.
build-types:
- type: Debug
debug: on
optimize: none
- type: Release
debug: off
optimize: balanced
# List related projects.
projects:
- project: GD32E50X_BOOT/GD32E50X_BOOT.cproject.yml
compiler: AC6
+71
View File
@@ -0,0 +1,71 @@
# A project translates into one executable or library.
project:
groups:
- group: Source Files
files:
- file: ./main.h
- file: ./main.cpp
- group: sys
files:
- file: ./sys/aes128.h
- file: ./sys/aes128.cpp
- file: ./sys/systick.h
- file: ./sys/systick.cpp
- file: ./sys/initial.h
- file: ./sys/initial.cpp
- file: ./sys/OTA.h
- file: ./sys/OTA.cpp
- file: ./sys/config.h
- group: device
files:
- file: ./device/Can.h
- file: ./device/Can.cpp
output:
type:
- elf
- hex
- map
components:
- component: CMSIS:CORE
- component: Device:GD32E50x_StdPeripherals:ADC
- component: Device:GD32E50x_StdPeripherals:CAN
- component: Device:GD32E50x_StdPeripherals:CRC
- component: Device:GD32E50x_StdPeripherals:CTC
- component: Device:GD32E50x_StdPeripherals:DBG
- component: Device:GD32E50x_StdPeripherals:DMA
- component: Device:GD32E50x_StdPeripherals:FMC
- component: Device:GD32E50x_StdPeripherals:MISC
- component: Device:GD32E50x_StdPeripherals:PMU
- component: Device:GD32E50x_StdPeripherals:RCU
- component: Device:GD32E50x_StdPeripherals:TIMER
- component: Device:GD32E50x_StdPeripherals:USART
- component: Device:GD32E50x_libopt
- component: Device:Startup
- component: Device:GD32E50x_StdPeripherals:GPIO
- component: Device:GD32E50x_StdPeripherals:EXTI
misc:
- for-compiler: AC6
C-CPP:
- -DGD32E508
- -DGD32E50X
- -gdwarf-5
- -D__MICROLIB
- -fshort-enums
- -fshort-wchar
- -Wno-register
C:
- -std=gnu11
CPP:
- -std=gnu++17
ASM:
- -DGD32E508
- -DGD32E50X
- -gdwarf-5
- -D__MICROLIB
Link:
- --library_type=microlib
- --entry=Reset_Handler
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* ----------------------------------------------------------------------------
Stack seal size definition
*----------------------------------------------------------------------------*/
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
#define __STACKSEAL_SIZE 8
#else
#define __STACKSEAL_SIZE 0
#endif
/*----------------------------------------------------------------------------
Scatter File Definitions definition
*----------------------------------------------------------------------------*/
LR_ROM0 __ROM0_BASE __ROM0_SIZE {
ER_ROM0 __ROM0_BASE __ROM0_SIZE {
*.o (RESET, +First)
*(InRoot$$Sections)
*(+RO +XO)
}
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
ER_CMSE_VENEER AlignExpr(+0, 32) (__ROM0_SIZE - AlignExpr(ImageLength(ER_ROM0), 32)) {
*(Veneer$$CMSE)
}
#endif
RW_NOINIT __RAM0_BASE UNINIT (__RAM0_SIZE - __HEAP_SIZE - __STACK_SIZE - __STACKSEAL_SIZE) {
*.o(.bss.noinit)
*.o(.bss.noinit.*)
}
RW_RAM0 AlignExpr(+0, 8) (__RAM0_SIZE - __HEAP_SIZE - __STACK_SIZE - __STACKSEAL_SIZE - AlignExpr(ImageLength(RW_NOINIT), 8)) {
*(+RW +ZI)
}
#if __HEAP_SIZE > 0
ARM_LIB_HEAP (AlignExpr(+0, 8)) EMPTY __HEAP_SIZE { ; Reserve empty region for heap
}
#endif
ARM_LIB_STACK (__RAM0_BASE + __RAM0_SIZE - __STACKSEAL_SIZE) EMPTY -__STACK_SIZE { ; Reserve empty region for stack
}
#if __STACKSEAL_SIZE > 0
STACKSEAL +0 EMPTY __STACKSEAL_SIZE { ; Reserve empty region for stack seal immediately after stack
}
#endif
#if __RAM1_SIZE > 0
RW_RAM1 __RAM1_BASE __RAM1_SIZE {
.ANY (+RW +ZI)
}
#endif
#if __RAM2_SIZE > 0
RW_RAM2 __RAM2_BASE __RAM2_SIZE {
.ANY (+RW +ZI)
}
#endif
#if __RAM3_SIZE > 0
RW_RAM3 __RAM3_BASE __RAM3_SIZE {
.ANY (+RW +ZI)
}
#endif
}
#if __ROM1_SIZE > 0
LR_ROM1 __ROM1_BASE __ROM1_SIZE {
ER_ROM1 +0 __ROM1_SIZE {
.ANY (+RO +XO)
}
}
#endif
#if __ROM2_SIZE > 0
LR_ROM2 __ROM2_BASE __ROM2_SIZE {
ER_ROM2 +0 __ROM2_SIZE {
.ANY (+RO +XO)
}
}
#endif
#if __ROM3_SIZE > 0
LR_ROM3 __ROM3_BASE __ROM3_SIZE {
ER_ROM3 +0 __ROM3_SIZE {
.ANY (+RO +XO)
}
}
#endif
@@ -0,0 +1,239 @@
/*!
\file gd32e503z_eval.c
\brief firmware functions to manage leds, keys, COM ports
\version 2025-07-09, V1.6.1, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e503z_eval.h"
/* private variables */
static uint32_t GPIO_PORT[LEDn] = {LED1_GPIO_PORT, LED2_GPIO_PORT,
LED3_GPIO_PORT, LED4_GPIO_PORT};
static uint32_t GPIO_PIN[LEDn] = {LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN};
static rcu_periph_enum COM_CLK[COMn] = {EVAL_COM0_CLK};
static uint32_t COM_TX_PIN[COMn] = {EVAL_COM0_TX_PIN};
static uint32_t COM_RX_PIN[COMn] = {EVAL_COM0_RX_PIN};
static uint32_t COM_GPIO_PORT[COMn] = {EVAL_COM0_GPIO_PORT};
static rcu_periph_enum COM_GPIO_CLK[COMn] = {EVAL_COM0_GPIO_CLK};
static rcu_periph_enum GPIO_CLK[LEDn] = {LED1_GPIO_CLK, LED2_GPIO_CLK,
LED3_GPIO_CLK, LED4_GPIO_CLK};
static uint32_t KEY_PORT[KEYn] = {KEY_A_GPIO_PORT,
KEY_B_GPIO_PORT,
KEY_C_GPIO_PORT,
KEY_D_GPIO_PORT,
KEY_CET_GPIO_PORT};
static uint32_t KEY_PIN[KEYn] = {KEY_A_PIN,
KEY_B_PIN,
KEY_C_PIN,
KEY_D_PIN,
KEY_CET_PIN};
static rcu_periph_enum KEY_CLK[KEYn] = {KEY_A_GPIO_CLK,
KEY_B_GPIO_CLK,
KEY_C_GPIO_CLK,
KEY_D_GPIO_CLK,
KEY_CET_GPIO_CLK};
static exti_line_enum KEY_EXTI_LINE[KEYn] = {KEY_A_EXTI_LINE,
KEY_B_EXTI_LINE,
KEY_C_EXTI_LINE,
KEY_D_EXTI_LINE,
KEY_CET_EXTI_LINE};
static uint8_t KEY_PORT_SOURCE[KEYn] = {KEY_A_EXTI_PORT_SOURCE,
KEY_B_EXTI_PORT_SOURCE,
KEY_C_EXTI_PORT_SOURCE,
KEY_D_EXTI_PORT_SOURCE,
KEY_CET_EXTI_PORT_SOURCE};
static uint8_t KEY_PIN_SOURCE[KEYn] = {KEY_A_EXTI_PIN_SOURCE,
KEY_B_EXTI_PIN_SOURCE,
KEY_C_EXTI_PIN_SOURCE,
KEY_D_EXTI_PIN_SOURCE,
KEY_CET_EXTI_PIN_SOURCE};
static const IRQn_Type KEY_IRQn[KEYn] = {KEY_A_EXTI_IRQn,
KEY_B_EXTI_IRQn,
KEY_C_EXTI_IRQn,
KEY_D_EXTI_IRQn,
KEY_CET_EXTI_IRQn};
/*!
\brief configure led GPIO
\param[in] lednum: specify the led to be configured
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_init (led_typedef_enum lednum)
{
/* enable the led clock */
rcu_periph_clock_enable(GPIO_CLK[lednum]);
/* configure led GPIO port */
gpio_init(GPIO_PORT[lednum], GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,GPIO_PIN[lednum]);
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn on selected led
\param[in] lednum: specify the led to be turned on
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_on(led_typedef_enum lednum)
{
GPIO_BOP(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn off selected led
\param[in] lednum: specify the led to be turned off
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_off(led_typedef_enum lednum)
{
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief toggle selected led
\param[in] lednum: specify the led to be toggled
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_toggle(led_typedef_enum lednum)
{
gpio_bit_write(GPIO_PORT[lednum], GPIO_PIN[lednum],
(bit_status)(1-gpio_input_bit_get(GPIO_PORT[lednum], GPIO_PIN[lednum])));
}
/*!
\brief configure key
\param[in] key_num: specify the key to be configured
\arg KEY_A: wakeup key
\arg KEY_B: tamper key
\arg KEY_C: user key
\arg KEY_D: extension key
\arg KEY_CET: extension key
\param[in] key_mode: specify button mode
\arg KEY_MODE_GPIO: key will be used as simple IO
\arg KEY_MODE_EXTI: key will be connected to EXTI line with interrupt
\param[out] none
\retval none
*/
void gd_eval_key_init(key_typedef_enum key_num, keymode_typedef_enum key_mode)
{
/* enable the key clock */
rcu_periph_clock_enable(KEY_CLK[key_num]);
rcu_periph_clock_enable(RCU_AF);
/* configure button pin as input */
gpio_init(KEY_PORT[key_num], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, KEY_PIN[key_num]);
if(key_mode == KEY_MODE_EXTI) {
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(KEY_IRQn[key_num], 2U, 0U);
/* connect key EXTI line to key GPIO pin */
gpio_exti_source_select(KEY_PORT_SOURCE[key_num], KEY_PIN_SOURCE[key_num]);
/* configure key EXTI line */
exti_init(KEY_EXTI_LINE[key_num], EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(KEY_EXTI_LINE[key_num]);
}
}
/*!
\brief return the selected key state
\param[in] key: specify the key to be checked
\arg KEY_A: wakeup key
\arg KEY_B: tamper key
\arg KEY_C: user key
\arg KEY_D: extension key
\arg KEY_CET: extension key
\param[out] none
\retval the key's GPIO pin value
*/
uint8_t gd_eval_key_state_get(key_typedef_enum key)
{
return gpio_input_bit_get(KEY_PORT[key], KEY_PIN[key]);
}
/*!
\brief configure COM port
\param[in] com: COM on the board
\arg EVAL_COM0: COM0 on the board
\param[out] none
\retval none
*/
void gd_eval_com_init(uint32_t com)
{
uint32_t com_id = 0U;
if(EVAL_COM0 == com){
com_id = 0U;
}else{
while(1);
}
/* enable GPIO clock */
rcu_periph_clock_enable(COM_GPIO_CLK[com_id]);
/* enable USART clock */
rcu_periph_clock_enable(COM_CLK[com_id]);
/* connect port to USARTx_Tx */
gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, COM_TX_PIN[com_id]);
/* connect port to USARTx_Rx */
gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, COM_RX_PIN[com_id]);
/* USART configure */
usart_deinit(com);
usart_baudrate_set(com, 115200U);
usart_receive_config(com, USART_RECEIVE_ENABLE);
usart_transmit_config(com, USART_TRANSMIT_ENABLE);
usart_enable(com);
}
@@ -0,0 +1,239 @@
/*!
\file gd32e503z_eval.c
\brief firmware functions to manage leds, keys, COM ports
\version 2025-07-09, V1.6.1, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e503z_eval.h"
/* private variables */
static uint32_t GPIO_PORT[LEDn] = {LED1_GPIO_PORT, LED2_GPIO_PORT,
LED3_GPIO_PORT, LED4_GPIO_PORT};
static uint32_t GPIO_PIN[LEDn] = {LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN};
static rcu_periph_enum COM_CLK[COMn] = {EVAL_COM0_CLK};
static uint32_t COM_TX_PIN[COMn] = {EVAL_COM0_TX_PIN};
static uint32_t COM_RX_PIN[COMn] = {EVAL_COM0_RX_PIN};
static uint32_t COM_GPIO_PORT[COMn] = {EVAL_COM0_GPIO_PORT};
static rcu_periph_enum COM_GPIO_CLK[COMn] = {EVAL_COM0_GPIO_CLK};
static rcu_periph_enum GPIO_CLK[LEDn] = {LED1_GPIO_CLK, LED2_GPIO_CLK,
LED3_GPIO_CLK, LED4_GPIO_CLK};
static uint32_t KEY_PORT[KEYn] = {KEY_A_GPIO_PORT,
KEY_B_GPIO_PORT,
KEY_C_GPIO_PORT,
KEY_D_GPIO_PORT,
KEY_CET_GPIO_PORT};
static uint32_t KEY_PIN[KEYn] = {KEY_A_PIN,
KEY_B_PIN,
KEY_C_PIN,
KEY_D_PIN,
KEY_CET_PIN};
static rcu_periph_enum KEY_CLK[KEYn] = {KEY_A_GPIO_CLK,
KEY_B_GPIO_CLK,
KEY_C_GPIO_CLK,
KEY_D_GPIO_CLK,
KEY_CET_GPIO_CLK};
static exti_line_enum KEY_EXTI_LINE[KEYn] = {KEY_A_EXTI_LINE,
KEY_B_EXTI_LINE,
KEY_C_EXTI_LINE,
KEY_D_EXTI_LINE,
KEY_CET_EXTI_LINE};
static uint8_t KEY_PORT_SOURCE[KEYn] = {KEY_A_EXTI_PORT_SOURCE,
KEY_B_EXTI_PORT_SOURCE,
KEY_C_EXTI_PORT_SOURCE,
KEY_D_EXTI_PORT_SOURCE,
KEY_CET_EXTI_PORT_SOURCE};
static uint8_t KEY_PIN_SOURCE[KEYn] = {KEY_A_EXTI_PIN_SOURCE,
KEY_B_EXTI_PIN_SOURCE,
KEY_C_EXTI_PIN_SOURCE,
KEY_D_EXTI_PIN_SOURCE,
KEY_CET_EXTI_PIN_SOURCE};
static const IRQn_Type KEY_IRQn[KEYn] = {KEY_A_EXTI_IRQn,
KEY_B_EXTI_IRQn,
KEY_C_EXTI_IRQn,
KEY_D_EXTI_IRQn,
KEY_CET_EXTI_IRQn};
/*!
\brief configure led GPIO
\param[in] lednum: specify the led to be configured
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_init (led_typedef_enum lednum)
{
/* enable the led clock */
rcu_periph_clock_enable(GPIO_CLK[lednum]);
/* configure led GPIO port */
gpio_init(GPIO_PORT[lednum], GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,GPIO_PIN[lednum]);
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn on selected led
\param[in] lednum: specify the led to be turned on
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_on(led_typedef_enum lednum)
{
GPIO_BOP(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn off selected led
\param[in] lednum: specify the led to be turned off
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_off(led_typedef_enum lednum)
{
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief toggle selected led
\param[in] lednum: specify the led to be toggled
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_toggle(led_typedef_enum lednum)
{
gpio_bit_write(GPIO_PORT[lednum], GPIO_PIN[lednum],
(bit_status)(1-gpio_input_bit_get(GPIO_PORT[lednum], GPIO_PIN[lednum])));
}
/*!
\brief configure key
\param[in] key_num: specify the key to be configured
\arg KEY_A: wakeup key
\arg KEY_B: tamper key
\arg KEY_C: user key
\arg KEY_D: extension key
\arg KEY_CET: extension key
\param[in] key_mode: specify button mode
\arg KEY_MODE_GPIO: key will be used as simple IO
\arg KEY_MODE_EXTI: key will be connected to EXTI line with interrupt
\param[out] none
\retval none
*/
void gd_eval_key_init(key_typedef_enum key_num, keymode_typedef_enum key_mode)
{
/* enable the key clock */
rcu_periph_clock_enable(KEY_CLK[key_num]);
rcu_periph_clock_enable(RCU_AF);
/* configure button pin as input */
gpio_init(KEY_PORT[key_num], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, KEY_PIN[key_num]);
if(key_mode == KEY_MODE_EXTI) {
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(KEY_IRQn[key_num], 2U, 0U);
/* connect key EXTI line to key GPIO pin */
gpio_exti_source_select(KEY_PORT_SOURCE[key_num], KEY_PIN_SOURCE[key_num]);
/* configure key EXTI line */
exti_init(KEY_EXTI_LINE[key_num], EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(KEY_EXTI_LINE[key_num]);
}
}
/*!
\brief return the selected key state
\param[in] key: specify the key to be checked
\arg KEY_A: wakeup key
\arg KEY_B: tamper key
\arg KEY_C: user key
\arg KEY_D: extension key
\arg KEY_CET: extension key
\param[out] none
\retval the key's GPIO pin value
*/
uint8_t gd_eval_key_state_get(key_typedef_enum key)
{
return gpio_input_bit_get(KEY_PORT[key], KEY_PIN[key]);
}
/*!
\brief configure COM port
\param[in] com: COM on the board
\arg EVAL_COM0: COM0 on the board
\param[out] none
\retval none
*/
void gd_eval_com_init(uint32_t com)
{
uint32_t com_id = 0U;
if(EVAL_COM0 == com){
com_id = 0U;
}else{
while(1);
}
/* enable GPIO clock */
rcu_periph_clock_enable(COM_GPIO_CLK[com_id]);
/* enable USART clock */
rcu_periph_clock_enable(COM_CLK[com_id]);
/* connect port to USARTx_Tx */
gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, COM_TX_PIN[com_id]);
/* connect port to USARTx_Rx */
gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, COM_RX_PIN[com_id]);
/* USART configure */
usart_deinit(com);
usart_baudrate_set(com, 115200U);
usart_receive_config(com, USART_RECEIVE_ENABLE);
usart_transmit_config(com, USART_TRANSMIT_ENABLE);
usart_enable(com);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,239 @@
/*!
\file gd32e50x_crc.c
\brief CRC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_crc.h"
/*!
\brief deinitialize CRC calculation unit
\param[in] none
\param[out] none
\retval none
*/
void crc_deinit(void)
{
CRC_IDATA = (uint32_t)0xFFFFFFFFU;
CRC_DATA = (uint32_t)0xFFFFFFFFU;
CRC_FDATA = (uint32_t)0x00000000U;
CRC_POLY = (uint32_t)0x04C11DB7U;
CRC_CTL = CRC_CTL_RST;
}
/*!
\brief reset data register to the value of initializaiton data register
\param[in] none
\param[out] none
\retval none
*/
void crc_data_register_reset(void)
{
CRC_CTL |= (uint32_t)CRC_CTL_RST;
}
/*!
\brief enable the reverse operation of output data
\param[in] none
\param[out] none
\retval none
*/
void crc_reverse_output_data_enable(void)
{
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
CRC_CTL |= (uint32_t)CRC_CTL_REV_O;
}
/*!
\brief disable the reverse operation of output data
\param[in] none
\param[out] none
\retval none
*/
void crc_reverse_output_data_disable(void)
{
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
}
/*!
\brief configure the CRC input data function
\param[in] data_reverse: specify input data reverse function
only one parameter can be selected which is shown as below:
\arg CRC_INPUT_DATA_NOT: input data is not reversed
\arg CRC_INPUT_DATA_BYTE: input data is reversed on 8 bits
\arg CRC_INPUT_DATA_HALFWORD: input data is reversed on 16 bits
\arg CRC_INPUT_DATA_WORD: input data is reversed on 32 bits
\param[out] none
\retval none
*/
void crc_input_data_reverse_config(uint32_t data_reverse)
{
CRC_CTL &= (uint32_t)(~CRC_CTL_REV_I);
CRC_CTL |= (uint32_t)data_reverse;
}
/*!
\brief read the data register
\param[in] none
\param[out] none
\retval 32-bit value of the data register
*/
uint32_t crc_data_register_read(void)
{
uint32_t data;
data = CRC_DATA;
return (data);
}
/*!
\brief read the free data register
\param[in] none
\param[out] none
\retval 8-bit value of the free data register
*/
uint8_t crc_free_data_register_read(void)
{
uint8_t fdata;
fdata = (uint8_t)CRC_FDATA;
return (fdata);
}
/*!
\brief write the free data register
\param[in] free_data: specify 8-bit data
\param[out] none
\retval none
*/
void crc_free_data_register_write(uint8_t free_data)
{
CRC_FDATA = (uint32_t)free_data;
}
/*!
\brief write the initializaiton data register
\param[in] init_data: specify 32-bit data
\param[out] none
\retval none
*/
void crc_init_data_register_write(uint32_t init_data)
{
CRC_IDATA = (uint32_t)init_data;
}
/*!
\brief configure the CRC size of polynomial function
\param[in] poly_size: size of polynomial
only one parameter can be selected which is shown as below:
\arg CRC_CTL_PS_32: 32-bit polynomial for CRC calculation
\arg CRC_CTL_PS_16: 16-bit polynomial for CRC calculation
\arg CRC_CTL_PS_8: 8-bit polynomial for CRC calculation
\arg CRC_CTL_PS_7: 7-bit polynomial for CRC calculation
\param[out] none
\retval none
*/
void crc_polynomial_size_set(uint32_t poly_size)
{
CRC_CTL &= (uint32_t)(~(CRC_CTL_PS));
CRC_CTL |= (uint32_t)poly_size;
}
/*!
\brief configure the CRC polynomial value function
\param[in] poly: configurable polynomial value
\param[out] none
\retval none
*/
void crc_polynomial_set(uint32_t poly)
{
CRC_POLY &= (uint32_t)(~CRC_POLY_POLY);
CRC_POLY = poly;
}
/*!
\brief CRC calculate single data
\param[in] sdata: specify input data data
\param[in] data_format: input data format
only one parameter can be selected which is shown as below:
\arg INPUT_FORMAT_WORD: input data in word format
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
\arg INPUT_FORMAT_BYTE: input data in byte format
\param[out] none
\retval CRC calculate value
*/
uint32_t crc_single_data_calculate(uint32_t sdata, uint8_t data_format)
{
if(INPUT_FORMAT_WORD == data_format){
REG32(CRC) = sdata;
}else if(INPUT_FORMAT_HALFWORD == data_format){
REG16(CRC) = (uint16_t)sdata;
}else{
REG8(CRC) = (uint8_t)sdata;
}
return(CRC_DATA);
}
/*!
\brief CRC calculate a data array
\param[in] array: pointer to the input data array
\param[in] size: size of the array
\param[in] data_format: input data format
only one parameter can be selected which is shown as below:
\arg INPUT_FORMAT_WORD: input data in word format
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
\arg INPUT_FORMAT_BYTE: input data in byte format
\param[out] none
\retval CRC calculate value
*/
uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format)
{
uint32_t index;
uint32_t data = (uint32_t)array;
if(INPUT_FORMAT_WORD == data_format) {
for(index = 0U; index < size; index++) {
REG32(CRC) = *(uint32_t *)data;
data += 4U;
}
} else if(INPUT_FORMAT_HALFWORD == data_format) {
for(index = 0U; index < size; index++) {
REG16(CRC) = *(uint16_t *)data;
data += 2U;
}
} else {
for(index = 0U; index < size; index++) {
REG8(CRC) = *(uint8_t *)data;
data += 1U;
}
}
return (CRC_DATA);
}
@@ -0,0 +1,239 @@
/*!
\file gd32e50x_crc.c
\brief CRC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_crc.h"
/*!
\brief deinitialize CRC calculation unit
\param[in] none
\param[out] none
\retval none
*/
void crc_deinit(void)
{
CRC_IDATA = (uint32_t)0xFFFFFFFFU;
CRC_DATA = (uint32_t)0xFFFFFFFFU;
CRC_FDATA = (uint32_t)0x00000000U;
CRC_POLY = (uint32_t)0x04C11DB7U;
CRC_CTL = CRC_CTL_RST;
}
/*!
\brief reset data register to the value of initializaiton data register
\param[in] none
\param[out] none
\retval none
*/
void crc_data_register_reset(void)
{
CRC_CTL |= (uint32_t)CRC_CTL_RST;
}
/*!
\brief enable the reverse operation of output data
\param[in] none
\param[out] none
\retval none
*/
void crc_reverse_output_data_enable(void)
{
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
CRC_CTL |= (uint32_t)CRC_CTL_REV_O;
}
/*!
\brief disable the reverse operation of output data
\param[in] none
\param[out] none
\retval none
*/
void crc_reverse_output_data_disable(void)
{
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
}
/*!
\brief configure the CRC input data function
\param[in] data_reverse: specify input data reverse function
only one parameter can be selected which is shown as below:
\arg CRC_INPUT_DATA_NOT: input data is not reversed
\arg CRC_INPUT_DATA_BYTE: input data is reversed on 8 bits
\arg CRC_INPUT_DATA_HALFWORD: input data is reversed on 16 bits
\arg CRC_INPUT_DATA_WORD: input data is reversed on 32 bits
\param[out] none
\retval none
*/
void crc_input_data_reverse_config(uint32_t data_reverse)
{
CRC_CTL &= (uint32_t)(~CRC_CTL_REV_I);
CRC_CTL |= (uint32_t)data_reverse;
}
/*!
\brief read the data register
\param[in] none
\param[out] none
\retval 32-bit value of the data register
*/
uint32_t crc_data_register_read(void)
{
uint32_t data;
data = CRC_DATA;
return (data);
}
/*!
\brief read the free data register
\param[in] none
\param[out] none
\retval 8-bit value of the free data register
*/
uint8_t crc_free_data_register_read(void)
{
uint8_t fdata;
fdata = (uint8_t)CRC_FDATA;
return (fdata);
}
/*!
\brief write the free data register
\param[in] free_data: specify 8-bit data
\param[out] none
\retval none
*/
void crc_free_data_register_write(uint8_t free_data)
{
CRC_FDATA = (uint32_t)free_data;
}
/*!
\brief write the initializaiton data register
\param[in] init_data: specify 32-bit data
\param[out] none
\retval none
*/
void crc_init_data_register_write(uint32_t init_data)
{
CRC_IDATA = (uint32_t)init_data;
}
/*!
\brief configure the CRC size of polynomial function
\param[in] poly_size: size of polynomial
only one parameter can be selected which is shown as below:
\arg CRC_CTL_PS_32: 32-bit polynomial for CRC calculation
\arg CRC_CTL_PS_16: 16-bit polynomial for CRC calculation
\arg CRC_CTL_PS_8: 8-bit polynomial for CRC calculation
\arg CRC_CTL_PS_7: 7-bit polynomial for CRC calculation
\param[out] none
\retval none
*/
void crc_polynomial_size_set(uint32_t poly_size)
{
CRC_CTL &= (uint32_t)(~(CRC_CTL_PS));
CRC_CTL |= (uint32_t)poly_size;
}
/*!
\brief configure the CRC polynomial value function
\param[in] poly: configurable polynomial value
\param[out] none
\retval none
*/
void crc_polynomial_set(uint32_t poly)
{
CRC_POLY &= (uint32_t)(~CRC_POLY_POLY);
CRC_POLY = poly;
}
/*!
\brief CRC calculate single data
\param[in] sdata: specify input data data
\param[in] data_format: input data format
only one parameter can be selected which is shown as below:
\arg INPUT_FORMAT_WORD: input data in word format
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
\arg INPUT_FORMAT_BYTE: input data in byte format
\param[out] none
\retval CRC calculate value
*/
uint32_t crc_single_data_calculate(uint32_t sdata, uint8_t data_format)
{
if(INPUT_FORMAT_WORD == data_format){
REG32(CRC) = sdata;
}else if(INPUT_FORMAT_HALFWORD == data_format){
REG16(CRC) = (uint16_t)sdata;
}else{
REG8(CRC) = (uint8_t)sdata;
}
return(CRC_DATA);
}
/*!
\brief CRC calculate a data array
\param[in] array: pointer to the input data array
\param[in] size: size of the array
\param[in] data_format: input data format
only one parameter can be selected which is shown as below:
\arg INPUT_FORMAT_WORD: input data in word format
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
\arg INPUT_FORMAT_BYTE: input data in byte format
\param[out] none
\retval CRC calculate value
*/
uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format)
{
uint32_t index;
uint32_t data = (uint32_t)array;
if(INPUT_FORMAT_WORD == data_format) {
for(index = 0U; index < size; index++) {
REG32(CRC) = *(uint32_t *)data;
data += 4U;
}
} else if(INPUT_FORMAT_HALFWORD == data_format) {
for(index = 0U; index < size; index++) {
REG16(CRC) = *(uint16_t *)data;
data += 2U;
}
} else {
for(index = 0U; index < size; index++) {
REG8(CRC) = *(uint8_t *)data;
data += 1U;
}
}
return (CRC_DATA);
}
@@ -0,0 +1,388 @@
/*!
\file gd32e50x_ctc.c
\brief CTC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_ctc.h"
#define CTC_FLAG_MASK ((uint32_t)0x00000700U)
/* CTC register bit offset */
#define CTC_TRIMVALUE_OFFSET ((uint32_t)8U)
#define CTC_TRIM_VALUE_OFFSET ((uint32_t)8U)
#define CTC_REFCAP_OFFSET ((uint32_t)16U)
#define CTC_LIMIT_VALUE_OFFSET ((uint32_t)16U)
/*!
\brief reset CTC clock trim controller
\param[in] none
\param[out] none
\retval none
*/
void ctc_deinit(void)
{
/* reset CTC */
rcu_periph_reset_enable(RCU_CTCRST);
rcu_periph_reset_disable(RCU_CTCRST);
}
/*!
\brief enable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_enable(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_CNTEN;
}
/*!
\brief disable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_disable(void)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_CNTEN);
}
/*!
\brief configure the IRC48M trim value
\param[in] trim_value: 6-bit IRC48M trim value
\arg 0x00 - 0x3F
\param[out] none
\retval none
*/
void ctc_irc48m_trim_value_config(uint8_t trim_value)
{
/* clear TRIMVALUE bits */
CTC_CTL0 &= (~(uint32_t)CTC_CTL0_TRIMVALUE);
/* set TRIMVALUE bits */
CTC_CTL0 |= ((uint32_t)trim_value << CTC_TRIM_VALUE_OFFSET);
}
/*!
\brief generate software reference source sync pulse
\param[in] none
\param[out] none
\retval none
*/
void ctc_software_refsource_pulse_generate(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_SWREFPUL;
}
/*!
\brief configure hardware automatically trim mode
\param[in] hardmode:
only one parameter can be selected which is shown as below:
\arg CTC_HARDWARE_TRIM_MODE_ENABLE: hardware automatically trim mode enable
\arg CTC_HARDWARE_TRIM_MODE_DISABLE: hardware automatically trim mode disable
\param[out] none
\retval none
*/
void ctc_hardware_trim_mode_config(uint32_t hardmode)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_AUTOTRIM);
CTC_CTL0 |= (uint32_t)hardmode;
}
/*!
\brief configure reference signal source polarity
\param[in] polarity:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_POLARITY_FALLING: reference signal source polarity is falling edge
\arg CTC_REFSOURCE_POLARITY_RISING: reference signal source polarity is rising edge
\param[out] none
\retval none
*/
void ctc_refsource_polarity_config(uint32_t polarity)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPOL);
CTC_CTL1 |= (uint32_t)polarity;
}
/*!
\brief select reference signal source
\param[in] refs:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_GPIO: GPIO is selected
\arg CTC_REFSOURCE_LXTAL: LXTAL is selected
\param[out] none
\retval none
*/
void ctc_refsource_signal_select(uint32_t refs)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFSEL);
CTC_CTL1 |= (uint32_t)refs;
}
/*!
\brief configure reference signal source prescaler
\param[in] prescaler:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_PSC_OFF: reference signal not divided
\arg CTC_REFSOURCE_PSC_DIV2: reference signal divided by 2
\arg CTC_REFSOURCE_PSC_DIV4: reference signal divided by 4
\arg CTC_REFSOURCE_PSC_DIV8: reference signal divided by 8
\arg CTC_REFSOURCE_PSC_DIV16: reference signal divided by 16
\arg CTC_REFSOURCE_PSC_DIV32: reference signal divided by 32
\arg CTC_REFSOURCE_PSC_DIV64: reference signal divided by 64
\arg CTC_REFSOURCE_PSC_DIV128: reference signal divided by 128
\param[out] none
\retval none
*/
void ctc_refsource_prescaler_config(uint32_t prescaler)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPSC);
CTC_CTL1 |= (uint32_t)prescaler;
}
/*!
\brief configure clock trim base limit value
\param[in] limit_value: 8-bit clock trim base limit value
\arg 0x00 - 0xFF
\param[out] none
\retval none
*/
void ctc_clock_limit_value_config(uint8_t limit_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_CKLIM);
CTC_CTL1 |= (uint32_t)((uint32_t)limit_value << CTC_LIMIT_VALUE_OFFSET);
}
/*!
\brief configure CTC counter reload value
\param[in] reload_value: 16-bit CTC counter reload value
\arg 0x0000 - 0xFFFF
\param[out] none
\retval none
*/
void ctc_counter_reload_value_config(uint16_t reload_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_RLVALUE);
CTC_CTL1 |= (uint32_t)reload_value;
}
/*!
\brief read CTC counter capture value when reference sync pulse occurred
\param[in] none
\param[out] none
\retval the 16-bit CTC counter capture value
*/
uint16_t ctc_counter_capture_value_read(void)
{
uint16_t capture_value = 0U;
capture_value = (uint16_t)((CTC_STAT & CTC_STAT_REFCAP)>> CTC_REFCAP_OFFSET);
return (capture_value);
}
/*!
\brief read CTC trim counter direction when reference sync pulse occurred
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
\arg SET: CTC trim counter direction is down-counting
\arg RESET: CTC trim counter direction is up-counting
*/
FlagStatus ctc_counter_direction_read(void)
{
if(RESET != (CTC_STAT & CTC_STAT_REFDIR)){
return SET;
}else{
return RESET;
}
}
/*!
\brief read CTC counter reload value
\param[in] none
\param[out] none
\retval the 16-bit CTC counter reload value
*/
uint16_t ctc_counter_reload_value_read(void)
{
uint16_t reload_value = 0U;
reload_value = (uint16_t)(CTC_CTL1 & CTC_CTL1_RLVALUE);
return (reload_value);
}
/*!
\brief read the IRC48M trim value
\param[in] none
\param[out] none
\retval the 6-bit IRC48M trim value
*/
uint8_t ctc_irc48m_trim_value_read(void)
{
uint8_t trim_value = 0U;
trim_value = (uint8_t)((CTC_CTL0 & CTC_CTL0_TRIMVALUE) >> CTC_TRIMVALUE_OFFSET);
return (trim_value);
}
/*!
\brief get CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error bit
\arg CTC_FLAG_REFMISS: reference sync pulse miss
\arg CTC_FLAG_TRIMERR: trim value error bit
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_flag_get(uint32_t flag)
{
if(RESET != (CTC_STAT & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error bit
\arg CTC_FLAG_REFMISS: reference sync pulse miss
\arg CTC_FLAG_TRIMERR: trim value error bit
\param[out] none
\retval none
*/
void ctc_flag_clear(uint32_t flag)
{
if(RESET != (flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= flag;
}
}
/*!
\brief enable the CTC interrupt
\param[in] interrupt: CTC interrupt enable
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt enable
\arg CTC_INT_CKWARN: clock trim warning interrupt enable
\arg CTC_INT_ERR: error interrupt enable
\arg CTC_INT_EREF: expect reference interrupt enable
\param[out] none
\retval none
*/
void ctc_interrupt_enable(uint32_t interrupt)
{
CTC_CTL0 |= (uint32_t)interrupt;
}
/*!
\brief disable the CTC interrupt
\param[in] interrupt: CTC interrupt enable source
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt enable
\arg CTC_INT_CKWARN: clock trim warning interrupt enable
\arg CTC_INT_ERR: error interrupt enable
\arg CTC_INT_EREF: expect reference interrupt enable
\param[out] none
\retval none
*/
void ctc_interrupt_disable(uint32_t interrupt)
{
CTC_CTL0 &= (uint32_t)(~interrupt);
}
/*!
\brief get CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt
\arg CTC_INT_FLAG_ERR: error interrupt
\arg CTC_INT_FLAG_EREF: expect reference interrupt
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_interrupt_flag_get(uint32_t int_flag)
{
uint32_t interrupt_flag = 0U, intenable = 0U;
/* check whether the interrupt is enabled */
if(RESET != (int_flag & CTC_FLAG_MASK)){
intenable = CTC_CTL0 & CTC_CTL0_ERRIE;
}else{
intenable = CTC_CTL0 & int_flag;
}
/* get interrupt flag status */
interrupt_flag = CTC_STAT & int_flag;
if(interrupt_flag && intenable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt
\arg CTC_INT_FLAG_ERR: error interrupt
\arg CTC_INT_FLAG_EREF: expect reference interrupt
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt
\param[out] none
\retval none
*/
void ctc_interrupt_flag_clear(uint32_t int_flag)
{
if(RESET != (int_flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= int_flag;
}
}
@@ -0,0 +1,388 @@
/*!
\file gd32e50x_ctc.c
\brief CTC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_ctc.h"
#define CTC_FLAG_MASK ((uint32_t)0x00000700U)
/* CTC register bit offset */
#define CTC_TRIMVALUE_OFFSET ((uint32_t)8U)
#define CTC_TRIM_VALUE_OFFSET ((uint32_t)8U)
#define CTC_REFCAP_OFFSET ((uint32_t)16U)
#define CTC_LIMIT_VALUE_OFFSET ((uint32_t)16U)
/*!
\brief reset CTC clock trim controller
\param[in] none
\param[out] none
\retval none
*/
void ctc_deinit(void)
{
/* reset CTC */
rcu_periph_reset_enable(RCU_CTCRST);
rcu_periph_reset_disable(RCU_CTCRST);
}
/*!
\brief enable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_enable(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_CNTEN;
}
/*!
\brief disable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_disable(void)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_CNTEN);
}
/*!
\brief configure the IRC48M trim value
\param[in] trim_value: 6-bit IRC48M trim value
\arg 0x00 - 0x3F
\param[out] none
\retval none
*/
void ctc_irc48m_trim_value_config(uint8_t trim_value)
{
/* clear TRIMVALUE bits */
CTC_CTL0 &= (~(uint32_t)CTC_CTL0_TRIMVALUE);
/* set TRIMVALUE bits */
CTC_CTL0 |= ((uint32_t)trim_value << CTC_TRIM_VALUE_OFFSET);
}
/*!
\brief generate software reference source sync pulse
\param[in] none
\param[out] none
\retval none
*/
void ctc_software_refsource_pulse_generate(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_SWREFPUL;
}
/*!
\brief configure hardware automatically trim mode
\param[in] hardmode:
only one parameter can be selected which is shown as below:
\arg CTC_HARDWARE_TRIM_MODE_ENABLE: hardware automatically trim mode enable
\arg CTC_HARDWARE_TRIM_MODE_DISABLE: hardware automatically trim mode disable
\param[out] none
\retval none
*/
void ctc_hardware_trim_mode_config(uint32_t hardmode)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_AUTOTRIM);
CTC_CTL0 |= (uint32_t)hardmode;
}
/*!
\brief configure reference signal source polarity
\param[in] polarity:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_POLARITY_FALLING: reference signal source polarity is falling edge
\arg CTC_REFSOURCE_POLARITY_RISING: reference signal source polarity is rising edge
\param[out] none
\retval none
*/
void ctc_refsource_polarity_config(uint32_t polarity)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPOL);
CTC_CTL1 |= (uint32_t)polarity;
}
/*!
\brief select reference signal source
\param[in] refs:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_GPIO: GPIO is selected
\arg CTC_REFSOURCE_LXTAL: LXTAL is selected
\param[out] none
\retval none
*/
void ctc_refsource_signal_select(uint32_t refs)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFSEL);
CTC_CTL1 |= (uint32_t)refs;
}
/*!
\brief configure reference signal source prescaler
\param[in] prescaler:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_PSC_OFF: reference signal not divided
\arg CTC_REFSOURCE_PSC_DIV2: reference signal divided by 2
\arg CTC_REFSOURCE_PSC_DIV4: reference signal divided by 4
\arg CTC_REFSOURCE_PSC_DIV8: reference signal divided by 8
\arg CTC_REFSOURCE_PSC_DIV16: reference signal divided by 16
\arg CTC_REFSOURCE_PSC_DIV32: reference signal divided by 32
\arg CTC_REFSOURCE_PSC_DIV64: reference signal divided by 64
\arg CTC_REFSOURCE_PSC_DIV128: reference signal divided by 128
\param[out] none
\retval none
*/
void ctc_refsource_prescaler_config(uint32_t prescaler)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPSC);
CTC_CTL1 |= (uint32_t)prescaler;
}
/*!
\brief configure clock trim base limit value
\param[in] limit_value: 8-bit clock trim base limit value
\arg 0x00 - 0xFF
\param[out] none
\retval none
*/
void ctc_clock_limit_value_config(uint8_t limit_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_CKLIM);
CTC_CTL1 |= (uint32_t)((uint32_t)limit_value << CTC_LIMIT_VALUE_OFFSET);
}
/*!
\brief configure CTC counter reload value
\param[in] reload_value: 16-bit CTC counter reload value
\arg 0x0000 - 0xFFFF
\param[out] none
\retval none
*/
void ctc_counter_reload_value_config(uint16_t reload_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_RLVALUE);
CTC_CTL1 |= (uint32_t)reload_value;
}
/*!
\brief read CTC counter capture value when reference sync pulse occurred
\param[in] none
\param[out] none
\retval the 16-bit CTC counter capture value
*/
uint16_t ctc_counter_capture_value_read(void)
{
uint16_t capture_value = 0U;
capture_value = (uint16_t)((CTC_STAT & CTC_STAT_REFCAP)>> CTC_REFCAP_OFFSET);
return (capture_value);
}
/*!
\brief read CTC trim counter direction when reference sync pulse occurred
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
\arg SET: CTC trim counter direction is down-counting
\arg RESET: CTC trim counter direction is up-counting
*/
FlagStatus ctc_counter_direction_read(void)
{
if(RESET != (CTC_STAT & CTC_STAT_REFDIR)){
return SET;
}else{
return RESET;
}
}
/*!
\brief read CTC counter reload value
\param[in] none
\param[out] none
\retval the 16-bit CTC counter reload value
*/
uint16_t ctc_counter_reload_value_read(void)
{
uint16_t reload_value = 0U;
reload_value = (uint16_t)(CTC_CTL1 & CTC_CTL1_RLVALUE);
return (reload_value);
}
/*!
\brief read the IRC48M trim value
\param[in] none
\param[out] none
\retval the 6-bit IRC48M trim value
*/
uint8_t ctc_irc48m_trim_value_read(void)
{
uint8_t trim_value = 0U;
trim_value = (uint8_t)((CTC_CTL0 & CTC_CTL0_TRIMVALUE) >> CTC_TRIMVALUE_OFFSET);
return (trim_value);
}
/*!
\brief get CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error bit
\arg CTC_FLAG_REFMISS: reference sync pulse miss
\arg CTC_FLAG_TRIMERR: trim value error bit
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_flag_get(uint32_t flag)
{
if(RESET != (CTC_STAT & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error bit
\arg CTC_FLAG_REFMISS: reference sync pulse miss
\arg CTC_FLAG_TRIMERR: trim value error bit
\param[out] none
\retval none
*/
void ctc_flag_clear(uint32_t flag)
{
if(RESET != (flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= flag;
}
}
/*!
\brief enable the CTC interrupt
\param[in] interrupt: CTC interrupt enable
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt enable
\arg CTC_INT_CKWARN: clock trim warning interrupt enable
\arg CTC_INT_ERR: error interrupt enable
\arg CTC_INT_EREF: expect reference interrupt enable
\param[out] none
\retval none
*/
void ctc_interrupt_enable(uint32_t interrupt)
{
CTC_CTL0 |= (uint32_t)interrupt;
}
/*!
\brief disable the CTC interrupt
\param[in] interrupt: CTC interrupt enable source
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt enable
\arg CTC_INT_CKWARN: clock trim warning interrupt enable
\arg CTC_INT_ERR: error interrupt enable
\arg CTC_INT_EREF: expect reference interrupt enable
\param[out] none
\retval none
*/
void ctc_interrupt_disable(uint32_t interrupt)
{
CTC_CTL0 &= (uint32_t)(~interrupt);
}
/*!
\brief get CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt
\arg CTC_INT_FLAG_ERR: error interrupt
\arg CTC_INT_FLAG_EREF: expect reference interrupt
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_interrupt_flag_get(uint32_t int_flag)
{
uint32_t interrupt_flag = 0U, intenable = 0U;
/* check whether the interrupt is enabled */
if(RESET != (int_flag & CTC_FLAG_MASK)){
intenable = CTC_CTL0 & CTC_CTL0_ERRIE;
}else{
intenable = CTC_CTL0 & int_flag;
}
/* get interrupt flag status */
interrupt_flag = CTC_STAT & int_flag;
if(interrupt_flag && intenable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt
\arg CTC_INT_FLAG_ERR: error interrupt
\arg CTC_INT_FLAG_EREF: expect reference interrupt
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt
\param[out] none
\retval none
*/
void ctc_interrupt_flag_clear(uint32_t int_flag)
{
if(RESET != (int_flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= int_flag;
}
}
@@ -0,0 +1,148 @@
/*!
\file gd32e50x_dbg.c
\brief DBG driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_dbg.h"
#define DBG_RESET_VAL ((uint32_t)0x00000000U) /*!< DBG reset value */
/*!
\brief deinitialize the DBG
\param[in] none
\param[out] none
\retval none
*/
void dbg_deinit(void)
{
DBG_CTL = DBG_RESET_VAL;
}
/*!
\brief read DBG_ID code register
\param[in] none
\param[out] none
\retval DBG_ID code
*/
uint32_t dbg_id_get(void)
{
return DBG_ID;
}
/*!
\brief enable low power behavior when the mcu is in debug mode
\param[in] dbg_low_power:
one or more parameters can be selected which are shown as below:
\arg DBG_LOW_POWER_SLEEP: keep debugger connection during sleep mode
\arg DBG_LOW_POWER_DEEPSLEEP: keep debugger connection during deepsleep mode
\arg DBG_LOW_POWER_STANDBY: keep debugger connection during standby mode
\param[out] none
\retval none
*/
void dbg_low_power_enable(uint32_t dbg_low_power)
{
DBG_CTL |= dbg_low_power;
}
/*!
\brief disable low power behavior when the mcu is in debug mode
\param[in] dbg_low_power:
one or more parameters can be selected which are shown as below:
\arg DBG_LOW_POWER_SLEEP: do not keep debugger connection during sleep mode
\arg DBG_LOW_POWER_DEEPSLEEP: do not keep debugger connection during deepsleep mode
\arg DBG_LOW_POWER_STANDBY: do not keep debugger connection during standby mode
\param[out] none
\retval none
*/
void dbg_low_power_disable(uint32_t dbg_low_power)
{
DBG_CTL &= ~dbg_low_power;
}
/*!
\brief enable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which is shown as below:
\arg DBG_FWDGT_HOLD : hold FWDGT counter when core is halted
\arg DBG_WWDGT_HOLD : hold WWDGT counter when core is halted
\arg DBG_CANx_HOLD (x=0,1,2 CAN2 is only available for CL series, CANx are not available for GD32EPRT series): hold CANx receive register counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2): hold I2Cx smbus timeout when core is halted
\arg DBG_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13, TIMER8..13 are not available for GD32EPRT series): hold TIMERx counter when core is halted
\arg DBG_SHRTIMER_HOLD : hold SHRTIMER counter when core is halted, except for GD32EPRT series
\param[out] none
\retval none
*/
void dbg_periph_enable(dbg_periph_enum dbg_periph)
{
DBG_REG_VAL(dbg_periph) |= BIT(DBG_BIT_POS(dbg_periph));
}
/*!
\brief disable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which is shown as below:
\arg DBG_FWDGT_HOLD : hold FWDGT counter when core is halted
\arg DBG_WWDGT_HOLD : hold WWDGT counter when core is halted
\arg DBG_CANx_HOLD (x=0,1,2 CAN2 is only available for CL series, CANx are not available for GD32EPRT series): hold CANx receive register counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2): hold I2Cx smbus timeout when core is halted
\arg DBG_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13,TIMER8..13 are not available for GD32EPRT series): hold TIMERx counter when core is halted
\arg DBG_SHRTIMER_HOLD : hold SHRTIMER counter when core is halted, except for GD32EPRT series
\param[out] none
\retval none
*/
void dbg_periph_disable(dbg_periph_enum dbg_periph)
{
DBG_REG_VAL(dbg_periph) &= ~BIT(DBG_BIT_POS(dbg_periph));
}
/*!
\brief enable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_enable(void)
{
DBG_CTL |= DBG_CTL_TRACE_IOEN;
}
/*!
\brief disable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_disable(void)
{
DBG_CTL &= ~DBG_CTL_TRACE_IOEN;
}
@@ -0,0 +1,148 @@
/*!
\file gd32e50x_dbg.c
\brief DBG driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_dbg.h"
#define DBG_RESET_VAL ((uint32_t)0x00000000U) /*!< DBG reset value */
/*!
\brief deinitialize the DBG
\param[in] none
\param[out] none
\retval none
*/
void dbg_deinit(void)
{
DBG_CTL = DBG_RESET_VAL;
}
/*!
\brief read DBG_ID code register
\param[in] none
\param[out] none
\retval DBG_ID code
*/
uint32_t dbg_id_get(void)
{
return DBG_ID;
}
/*!
\brief enable low power behavior when the mcu is in debug mode
\param[in] dbg_low_power:
one or more parameters can be selected which are shown as below:
\arg DBG_LOW_POWER_SLEEP: keep debugger connection during sleep mode
\arg DBG_LOW_POWER_DEEPSLEEP: keep debugger connection during deepsleep mode
\arg DBG_LOW_POWER_STANDBY: keep debugger connection during standby mode
\param[out] none
\retval none
*/
void dbg_low_power_enable(uint32_t dbg_low_power)
{
DBG_CTL |= dbg_low_power;
}
/*!
\brief disable low power behavior when the mcu is in debug mode
\param[in] dbg_low_power:
one or more parameters can be selected which are shown as below:
\arg DBG_LOW_POWER_SLEEP: do not keep debugger connection during sleep mode
\arg DBG_LOW_POWER_DEEPSLEEP: do not keep debugger connection during deepsleep mode
\arg DBG_LOW_POWER_STANDBY: do not keep debugger connection during standby mode
\param[out] none
\retval none
*/
void dbg_low_power_disable(uint32_t dbg_low_power)
{
DBG_CTL &= ~dbg_low_power;
}
/*!
\brief enable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which is shown as below:
\arg DBG_FWDGT_HOLD : hold FWDGT counter when core is halted
\arg DBG_WWDGT_HOLD : hold WWDGT counter when core is halted
\arg DBG_CANx_HOLD (x=0,1,2 CAN2 is only available for CL series, CANx are not available for GD32EPRT series): hold CANx receive register counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2): hold I2Cx smbus timeout when core is halted
\arg DBG_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13, TIMER8..13 are not available for GD32EPRT series): hold TIMERx counter when core is halted
\arg DBG_SHRTIMER_HOLD : hold SHRTIMER counter when core is halted, except for GD32EPRT series
\param[out] none
\retval none
*/
void dbg_periph_enable(dbg_periph_enum dbg_periph)
{
DBG_REG_VAL(dbg_periph) |= BIT(DBG_BIT_POS(dbg_periph));
}
/*!
\brief disable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which is shown as below:
\arg DBG_FWDGT_HOLD : hold FWDGT counter when core is halted
\arg DBG_WWDGT_HOLD : hold WWDGT counter when core is halted
\arg DBG_CANx_HOLD (x=0,1,2 CAN2 is only available for CL series, CANx are not available for GD32EPRT series): hold CANx receive register counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2): hold I2Cx smbus timeout when core is halted
\arg DBG_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13,TIMER8..13 are not available for GD32EPRT series): hold TIMERx counter when core is halted
\arg DBG_SHRTIMER_HOLD : hold SHRTIMER counter when core is halted, except for GD32EPRT series
\param[out] none
\retval none
*/
void dbg_periph_disable(dbg_periph_enum dbg_periph)
{
DBG_REG_VAL(dbg_periph) &= ~BIT(DBG_BIT_POS(dbg_periph));
}
/*!
\brief enable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_enable(void)
{
DBG_CTL |= DBG_CTL_TRACE_IOEN;
}
/*!
\brief disable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_disable(void)
{
DBG_CTL &= ~DBG_CTL_TRACE_IOEN;
}
@@ -0,0 +1,752 @@
/*!
\file gd32e50x_dma.c
\brief DMA driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_dma.h"
#include <stdlib.h>
#define DMA_WRONG_HANDLE while(1){}
/* check whether peripheral matches channels or not */
static ErrStatus dma_periph_and_channel_check(uint32_t dma_periph, dma_channel_enum channelx);
/*!
\brief deinitialize DMA a channel registers
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel is deinitialized
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_deinit(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* disable DMA a channel */
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CHEN;
/* reset DMA channel registers */
DMA_CHCTL(dma_periph, channelx) = DMA_CHCTL_RESET_VALUE;
DMA_CHCNT(dma_periph, channelx) = DMA_CHCNT_RESET_VALUE;
DMA_CHPADDR(dma_periph, channelx) = DMA_CHPADDR_RESET_VALUE;
DMA_CHMADDR(dma_periph, channelx) = DMA_CHMADDR_RESET_VALUE;
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(DMA_CHINTF_RESET_VALUE, channelx);
}
/*!
\brief initialize the parameters of DMA struct with the default values
\param[in] init_struct: the initialization data needed to initialize DMA channel
\param[out] none
\retval none
*/
void dma_struct_para_init(dma_parameter_struct* init_struct)
{
if(NULL == init_struct){
DMA_WRONG_HANDLE
}
/* set the DMA struct with the default values */
init_struct->periph_addr = 0U;
init_struct->periph_width = 0U;
init_struct->periph_inc = DMA_PERIPH_INCREASE_DISABLE;
init_struct->memory_addr = 0U;
init_struct->memory_width = 0U;
init_struct->memory_inc = DMA_MEMORY_INCREASE_DISABLE;
init_struct->number = 0U;
init_struct->direction = DMA_PERIPHERAL_TO_MEMORY;
init_struct->priority = DMA_PRIORITY_LOW;
}
/*!
\brief initialize DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel is initialized
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] init_struct: the data needed to initialize DMA channel
periph_addr: peripheral base address
periph_width: DMA_PERIPHERAL_WIDTH_8BIT, DMA_PERIPHERAL_WIDTH_16BIT, DMA_PERIPHERAL_WIDTH_32BIT
periph_inc: DMA_PERIPH_INCREASE_ENABLE, DMA_PERIPH_INCREASE_DISABLE
memory_addr: memory base address
memory_width: DMA_MEMORY_WIDTH_8BIT, DMA_MEMORY_WIDTH_16BIT, DMA_MEMORY_WIDTH_32BIT
memory_inc: DMA_MEMORY_INCREASE_ENABLE, DMA_MEMORY_INCREASE_DISABLE
direction: DMA_PERIPHERAL_TO_MEMORY, DMA_MEMORY_TO_PERIPHERAL
number: the number of remaining data to be transferred by the DMA
priority: DMA_PRIORITY_LOW, DMA_PRIORITY_MEDIUM, DMA_PRIORITY_HIGH, DMA_PRIORITY_ULTRA_HIGH
\param[out] none
\retval none
*/
void dma_init(uint32_t dma_periph, dma_channel_enum channelx, dma_parameter_struct* init_struct)
{
uint32_t ctl;
if(NULL == init_struct){
DMA_WRONG_HANDLE
}
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* configure peripheral base address */
DMA_CHPADDR(dma_periph, channelx) = init_struct->periph_addr;
/* configure memory base address */
DMA_CHMADDR(dma_periph, channelx) = init_struct->memory_addr;
/* configure the number of remaining data to be transferred */
DMA_CHCNT(dma_periph, channelx) = (init_struct->number & DMA_CHANNEL_CNT_MASK);
/* configure peripheral transfer width,memory transfer width and priority */
ctl = DMA_CHCTL(dma_periph, channelx);
ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO);
ctl |= (init_struct->periph_width | init_struct->memory_width | init_struct->priority);
DMA_CHCTL(dma_periph, channelx) = ctl;
/* configure peripheral increasing mode */
if(DMA_PERIPH_INCREASE_ENABLE == init_struct->periph_inc){
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_PNAGA;
}else{
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_PNAGA;
}
/* configure memory increasing mode */
if(DMA_MEMORY_INCREASE_ENABLE == init_struct->memory_inc){
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_MNAGA;
}else{
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_MNAGA;
}
/* configure the direction of data transfer */
if(DMA_PERIPHERAL_TO_MEMORY == init_struct->direction){
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_DIR;
}else{
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_DIR;
}
}
/*!
\brief enable DMA circulation mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_circulation_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_CMEN;
}
/*!
\brief disable DMA circulation mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_circulation_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CMEN;
}
/*!
\brief enable memory to memory mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_to_memory_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_M2M;
}
/*!
\brief disable memory to memory mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_to_memory_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_M2M;
}
/*!
\brief enable DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_channel_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_CHEN;
}
/*!
\brief disable DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_channel_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CHEN;
}
/*!
\brief set DMA peripheral base address
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set peripheral base address
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] address: peripheral base address
\param[out] none
\retval none
*/
void dma_periph_address_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t address)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHPADDR(dma_periph, channelx) = address;
}
/*!
\brief set DMA memory base address
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set memory base address
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] address: memory base address
\param[out] none
\retval none
*/
void dma_memory_address_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t address)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHMADDR(dma_periph, channelx) = address;
}
/*!
\brief set the number of remaining data to be transferred by the DMA
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set number
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] number: the number of remaining data to be transferred by the DMA, 0x00000000-0x0000FFFF
\param[out] none
\retval none
*/
void dma_transfer_number_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t number)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCNT(dma_periph, channelx) = (number & DMA_CHANNEL_CNT_MASK);
}
/*!
\brief get the number of remaining data to be transferred by the DMA
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set number
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval uint32_t: the number of remaining data to be transferred by the DMA, 0x00000000-0x0000FFFF
*/
uint32_t dma_transfer_number_get(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
return (uint32_t)DMA_CHCNT(dma_periph, channelx);
}
/*!
\brief configure priority level of DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] priority: priority Level of this channel
only one parameter can be selected which is shown as below:
\arg DMA_PRIORITY_LOW: low priority
\arg DMA_PRIORITY_MEDIUM: medium priority
\arg DMA_PRIORITY_HIGH: high priority
\arg DMA_PRIORITY_ULTRA_HIGH: ultra high priority
\param[out] none
\retval none
*/
void dma_priority_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t priority)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_PRIO;
ctl |= priority;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief configure transfer data size of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] mwidth: transfer data width of memory
only one parameter can be selected which is shown as below:
\arg DMA_MEMORY_WIDTH_8BIT: transfer data width of memory is 8-bit
\arg DMA_MEMORY_WIDTH_16BIT: transfer data width of memory is 16-bit
\arg DMA_MEMORY_WIDTH_32BIT: transfer data width of memory is 32-bit
\param[out] none
\retval none
*/
void dma_memory_width_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t mwidth)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_MWIDTH;
ctl |= mwidth;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief configure transfer data size of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] pwidth: transfer data width of peripheral
only one parameter can be selected which is shown as below:
\arg DMA_PERIPHERAL_WIDTH_8BIT: transfer data width of peripheral is 8-bit
\arg DMA_PERIPHERAL_WIDTH_16BIT: transfer data width of peripheral is 16-bit
\arg DMA_PERIPHERAL_WIDTH_32BIT: transfer data width of peripheral is 32-bit
\param[out] none
\retval none
*/
void dma_periph_width_config (uint32_t dma_periph, dma_channel_enum channelx, uint32_t pwidth)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_PWIDTH;
ctl |= pwidth;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief enable next address increasement algorithm of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_increase_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_MNAGA;
}
/*!
\brief disable next address increasement algorithm of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_increase_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_MNAGA;
}
/*!
\brief enable next address increasement algorithm of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_periph_increase_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_PNAGA;
}
/*!
\brief disable next address increasement algorithm of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_periph_increase_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_PNAGA;
}
/*!
\brief configure the direction of data transfer on the channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] direction: specify the direction of data transfer
only one parameter can be selected which is shown as below:
\arg DMA_PERIPHERAL_TO_MEMORY: read from peripheral and write to memory
\arg DMA_MEMORY_TO_PERIPHERAL: read from memory and write to peripheral
\param[out] none
\retval none
*/
void dma_transfer_direction_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t direction)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
if(DMA_PERIPHERAL_TO_MEMORY == direction){
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_DIR;
}else {
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_DIR;
}
}
/*!
\brief check DMA flag is set or not
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to get flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_FLAG_G: global interrupt flag of channel
\arg DMA_FLAG_FTF: full transfer finish flag of channel
\arg DMA_FLAG_HTF: half transfer finish flag of channel
\arg DMA_FLAG_ERR: error flag of channel
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dma_flag_get(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
FlagStatus reval;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
if(RESET != (DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx))){
reval = SET;
}else{
reval = RESET;
}
return reval;
}
/*!
\brief clear a DMA channel flag
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to clear flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_FLAG_G: global interrupt flag of channel
\arg DMA_FLAG_FTF: full transfer finish flag of channel
\arg DMA_FLAG_HTF: half transfer finish flag of channel
\arg DMA_FLAG_ERR: error flag of channel
\param[out] none
\retval none
*/
void dma_flag_clear(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(flag, channelx);
}
/*!
\brief enable DMA interrupt
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] source: specify which interrupt to enbale
one or more parameters can be selected which are shown as below
\arg DMA_INT_FTF: channel full transfer finish interrupt
\arg DMA_INT_HTF: channel half transfer finish interrupt
\arg DMA_INT_ERR: channel error interrupt
\param[out] none
\retval none
*/
void dma_interrupt_enable(uint32_t dma_periph, dma_channel_enum channelx, uint32_t source)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= source;
}
/*!
\brief disable DMA interrupt
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] source: specify which interrupt to disbale
one or more parameters can be selected which are shown as below
\arg DMA_INT_FTF: channel full transfer finish interrupt
\arg DMA_INT_HTF: channel half transfer finish interrupt
\arg DMA_INT_ERR: channel error interrupt
\param[out] none
\retval none
*/
void dma_interrupt_disable(uint32_t dma_periph, dma_channel_enum channelx, uint32_t source)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~source;
}
/*!
\brief check DMA flag and interrupt enable bit is set or not
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to get flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_INT_FLAG_FTF: full transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_HTF: half transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_ERR: error interrupt flag of channel
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dma_interrupt_flag_get(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
switch(flag){
case DMA_INT_FLAG_FTF:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_FTFIE;
break;
case DMA_INT_FLAG_HTF:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_HTFIE;
break;
case DMA_INT_FLAG_ERR:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_ERRIE;
break;
default:
DMA_WRONG_HANDLE
}
if(interrupt_flag && interrupt_enable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear a DMA channel flag
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to clear flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_INT_FLAG_G: global interrupt flag of channel
\arg DMA_INT_FLAG_FTF: full transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_HTF: half transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_ERR: error interrupt flag of channel
\param[out] none
\retval none
*/
void dma_interrupt_flag_clear(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(flag, channelx);
}
/*!
\brief check whether peripheral and channels match
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA_CHx(x=0..6)
\param[out] none
\retval none
*/
static ErrStatus dma_periph_and_channel_check(uint32_t dma_periph, dma_channel_enum channelx)
{
ErrStatus val = SUCCESS;
if(DMA1 == dma_periph){
/* for DMA1, the channel is from DMA_CH0 to DMA_CH4 */
if(channelx > DMA_CH4){
val = ERROR;
}
}
return val;
}
@@ -0,0 +1,752 @@
/*!
\file gd32e50x_dma.c
\brief DMA driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_dma.h"
#include <stdlib.h>
#define DMA_WRONG_HANDLE while(1){}
/* check whether peripheral matches channels or not */
static ErrStatus dma_periph_and_channel_check(uint32_t dma_periph, dma_channel_enum channelx);
/*!
\brief deinitialize DMA a channel registers
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel is deinitialized
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_deinit(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* disable DMA a channel */
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CHEN;
/* reset DMA channel registers */
DMA_CHCTL(dma_periph, channelx) = DMA_CHCTL_RESET_VALUE;
DMA_CHCNT(dma_periph, channelx) = DMA_CHCNT_RESET_VALUE;
DMA_CHPADDR(dma_periph, channelx) = DMA_CHPADDR_RESET_VALUE;
DMA_CHMADDR(dma_periph, channelx) = DMA_CHMADDR_RESET_VALUE;
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(DMA_CHINTF_RESET_VALUE, channelx);
}
/*!
\brief initialize the parameters of DMA struct with the default values
\param[in] init_struct: the initialization data needed to initialize DMA channel
\param[out] none
\retval none
*/
void dma_struct_para_init(dma_parameter_struct* init_struct)
{
if(NULL == init_struct){
DMA_WRONG_HANDLE
}
/* set the DMA struct with the default values */
init_struct->periph_addr = 0U;
init_struct->periph_width = 0U;
init_struct->periph_inc = DMA_PERIPH_INCREASE_DISABLE;
init_struct->memory_addr = 0U;
init_struct->memory_width = 0U;
init_struct->memory_inc = DMA_MEMORY_INCREASE_DISABLE;
init_struct->number = 0U;
init_struct->direction = DMA_PERIPHERAL_TO_MEMORY;
init_struct->priority = DMA_PRIORITY_LOW;
}
/*!
\brief initialize DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel is initialized
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] init_struct: the data needed to initialize DMA channel
periph_addr: peripheral base address
periph_width: DMA_PERIPHERAL_WIDTH_8BIT, DMA_PERIPHERAL_WIDTH_16BIT, DMA_PERIPHERAL_WIDTH_32BIT
periph_inc: DMA_PERIPH_INCREASE_ENABLE, DMA_PERIPH_INCREASE_DISABLE
memory_addr: memory base address
memory_width: DMA_MEMORY_WIDTH_8BIT, DMA_MEMORY_WIDTH_16BIT, DMA_MEMORY_WIDTH_32BIT
memory_inc: DMA_MEMORY_INCREASE_ENABLE, DMA_MEMORY_INCREASE_DISABLE
direction: DMA_PERIPHERAL_TO_MEMORY, DMA_MEMORY_TO_PERIPHERAL
number: the number of remaining data to be transferred by the DMA
priority: DMA_PRIORITY_LOW, DMA_PRIORITY_MEDIUM, DMA_PRIORITY_HIGH, DMA_PRIORITY_ULTRA_HIGH
\param[out] none
\retval none
*/
void dma_init(uint32_t dma_periph, dma_channel_enum channelx, dma_parameter_struct* init_struct)
{
uint32_t ctl;
if(NULL == init_struct){
DMA_WRONG_HANDLE
}
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* configure peripheral base address */
DMA_CHPADDR(dma_periph, channelx) = init_struct->periph_addr;
/* configure memory base address */
DMA_CHMADDR(dma_periph, channelx) = init_struct->memory_addr;
/* configure the number of remaining data to be transferred */
DMA_CHCNT(dma_periph, channelx) = (init_struct->number & DMA_CHANNEL_CNT_MASK);
/* configure peripheral transfer width,memory transfer width and priority */
ctl = DMA_CHCTL(dma_periph, channelx);
ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO);
ctl |= (init_struct->periph_width | init_struct->memory_width | init_struct->priority);
DMA_CHCTL(dma_periph, channelx) = ctl;
/* configure peripheral increasing mode */
if(DMA_PERIPH_INCREASE_ENABLE == init_struct->periph_inc){
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_PNAGA;
}else{
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_PNAGA;
}
/* configure memory increasing mode */
if(DMA_MEMORY_INCREASE_ENABLE == init_struct->memory_inc){
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_MNAGA;
}else{
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_MNAGA;
}
/* configure the direction of data transfer */
if(DMA_PERIPHERAL_TO_MEMORY == init_struct->direction){
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_DIR;
}else{
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_DIR;
}
}
/*!
\brief enable DMA circulation mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_circulation_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_CMEN;
}
/*!
\brief disable DMA circulation mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_circulation_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CMEN;
}
/*!
\brief enable memory to memory mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_to_memory_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_M2M;
}
/*!
\brief disable memory to memory mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_to_memory_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_M2M;
}
/*!
\brief enable DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_channel_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_CHEN;
}
/*!
\brief disable DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_channel_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CHEN;
}
/*!
\brief set DMA peripheral base address
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set peripheral base address
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] address: peripheral base address
\param[out] none
\retval none
*/
void dma_periph_address_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t address)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHPADDR(dma_periph, channelx) = address;
}
/*!
\brief set DMA memory base address
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set memory base address
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] address: memory base address
\param[out] none
\retval none
*/
void dma_memory_address_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t address)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHMADDR(dma_periph, channelx) = address;
}
/*!
\brief set the number of remaining data to be transferred by the DMA
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set number
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] number: the number of remaining data to be transferred by the DMA, 0x00000000-0x0000FFFF
\param[out] none
\retval none
*/
void dma_transfer_number_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t number)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCNT(dma_periph, channelx) = (number & DMA_CHANNEL_CNT_MASK);
}
/*!
\brief get the number of remaining data to be transferred by the DMA
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set number
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval uint32_t: the number of remaining data to be transferred by the DMA, 0x00000000-0x0000FFFF
*/
uint32_t dma_transfer_number_get(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
return (uint32_t)DMA_CHCNT(dma_periph, channelx);
}
/*!
\brief configure priority level of DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] priority: priority Level of this channel
only one parameter can be selected which is shown as below:
\arg DMA_PRIORITY_LOW: low priority
\arg DMA_PRIORITY_MEDIUM: medium priority
\arg DMA_PRIORITY_HIGH: high priority
\arg DMA_PRIORITY_ULTRA_HIGH: ultra high priority
\param[out] none
\retval none
*/
void dma_priority_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t priority)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_PRIO;
ctl |= priority;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief configure transfer data size of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] mwidth: transfer data width of memory
only one parameter can be selected which is shown as below:
\arg DMA_MEMORY_WIDTH_8BIT: transfer data width of memory is 8-bit
\arg DMA_MEMORY_WIDTH_16BIT: transfer data width of memory is 16-bit
\arg DMA_MEMORY_WIDTH_32BIT: transfer data width of memory is 32-bit
\param[out] none
\retval none
*/
void dma_memory_width_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t mwidth)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_MWIDTH;
ctl |= mwidth;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief configure transfer data size of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] pwidth: transfer data width of peripheral
only one parameter can be selected which is shown as below:
\arg DMA_PERIPHERAL_WIDTH_8BIT: transfer data width of peripheral is 8-bit
\arg DMA_PERIPHERAL_WIDTH_16BIT: transfer data width of peripheral is 16-bit
\arg DMA_PERIPHERAL_WIDTH_32BIT: transfer data width of peripheral is 32-bit
\param[out] none
\retval none
*/
void dma_periph_width_config (uint32_t dma_periph, dma_channel_enum channelx, uint32_t pwidth)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_PWIDTH;
ctl |= pwidth;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief enable next address increasement algorithm of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_increase_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_MNAGA;
}
/*!
\brief disable next address increasement algorithm of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_increase_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_MNAGA;
}
/*!
\brief enable next address increasement algorithm of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_periph_increase_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_PNAGA;
}
/*!
\brief disable next address increasement algorithm of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_periph_increase_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_PNAGA;
}
/*!
\brief configure the direction of data transfer on the channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] direction: specify the direction of data transfer
only one parameter can be selected which is shown as below:
\arg DMA_PERIPHERAL_TO_MEMORY: read from peripheral and write to memory
\arg DMA_MEMORY_TO_PERIPHERAL: read from memory and write to peripheral
\param[out] none
\retval none
*/
void dma_transfer_direction_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t direction)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
if(DMA_PERIPHERAL_TO_MEMORY == direction){
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_DIR;
}else {
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_DIR;
}
}
/*!
\brief check DMA flag is set or not
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to get flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_FLAG_G: global interrupt flag of channel
\arg DMA_FLAG_FTF: full transfer finish flag of channel
\arg DMA_FLAG_HTF: half transfer finish flag of channel
\arg DMA_FLAG_ERR: error flag of channel
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dma_flag_get(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
FlagStatus reval;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
if(RESET != (DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx))){
reval = SET;
}else{
reval = RESET;
}
return reval;
}
/*!
\brief clear a DMA channel flag
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to clear flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_FLAG_G: global interrupt flag of channel
\arg DMA_FLAG_FTF: full transfer finish flag of channel
\arg DMA_FLAG_HTF: half transfer finish flag of channel
\arg DMA_FLAG_ERR: error flag of channel
\param[out] none
\retval none
*/
void dma_flag_clear(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(flag, channelx);
}
/*!
\brief enable DMA interrupt
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] source: specify which interrupt to enbale
one or more parameters can be selected which are shown as below
\arg DMA_INT_FTF: channel full transfer finish interrupt
\arg DMA_INT_HTF: channel half transfer finish interrupt
\arg DMA_INT_ERR: channel error interrupt
\param[out] none
\retval none
*/
void dma_interrupt_enable(uint32_t dma_periph, dma_channel_enum channelx, uint32_t source)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= source;
}
/*!
\brief disable DMA interrupt
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] source: specify which interrupt to disbale
one or more parameters can be selected which are shown as below
\arg DMA_INT_FTF: channel full transfer finish interrupt
\arg DMA_INT_HTF: channel half transfer finish interrupt
\arg DMA_INT_ERR: channel error interrupt
\param[out] none
\retval none
*/
void dma_interrupt_disable(uint32_t dma_periph, dma_channel_enum channelx, uint32_t source)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~source;
}
/*!
\brief check DMA flag and interrupt enable bit is set or not
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to get flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_INT_FLAG_FTF: full transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_HTF: half transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_ERR: error interrupt flag of channel
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dma_interrupt_flag_get(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
switch(flag){
case DMA_INT_FLAG_FTF:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_FTFIE;
break;
case DMA_INT_FLAG_HTF:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_HTFIE;
break;
case DMA_INT_FLAG_ERR:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_ERRIE;
break;
default:
DMA_WRONG_HANDLE
}
if(interrupt_flag && interrupt_enable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear a DMA channel flag
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to clear flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_INT_FLAG_G: global interrupt flag of channel
\arg DMA_INT_FLAG_FTF: full transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_HTF: half transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_ERR: error interrupt flag of channel
\param[out] none
\retval none
*/
void dma_interrupt_flag_clear(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(flag, channelx);
}
/*!
\brief check whether peripheral and channels match
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA_CHx(x=0..6)
\param[out] none
\retval none
*/
static ErrStatus dma_periph_and_channel_check(uint32_t dma_periph, dma_channel_enum channelx)
{
ErrStatus val = SUCCESS;
if(DMA1 == dma_periph){
/* for DMA1, the channel is from DMA_CH0 to DMA_CH4 */
if(channelx > DMA_CH4){
val = ERROR;
}
}
return val;
}
@@ -0,0 +1,249 @@
/*!
\file gd32e50x_exti.c
\brief EXTI driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_exti.h"
#define EXTI_REG_RESET_VALUE ((uint32_t)0x00000000U)
/*!
\brief deinitialize the EXTI
\param[in] none
\param[out] none
\retval none
*/
void exti_deinit(void)
{
/* reset the value of all the EXTI registers */
EXTI_INTEN = EXTI_REG_RESET_VALUE;
EXTI_EVEN = EXTI_REG_RESET_VALUE;
EXTI_RTEN = EXTI_REG_RESET_VALUE;
EXTI_FTEN = EXTI_REG_RESET_VALUE;
EXTI_SWIEV = EXTI_REG_RESET_VALUE;
}
/*!
\brief initialize the EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[in] mode: interrupt or event mode, refer to exti_mode_enum
only one parameter can be selected which is shown as below:
\arg EXTI_INTERRUPT: interrupt mode
\arg EXTI_EVENT: event mode
\param[in] trig_type: interrupt trigger type, refer to exti_trig_type_enum
only one parameter can be selected which is shown as below:
\arg EXTI_TRIG_RISING: rising edge trigger
\arg EXTI_TRIG_FALLING: falling trigger
\arg EXTI_TRIG_BOTH: rising and falling trigger
\arg EXTI_TRIG_NONE: without rising edge or falling edge trigger
\param[out] none
\retval none
*/
void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type)
{
/* reset the EXTI line x */
EXTI_INTEN &= ~(uint32_t)linex;
EXTI_EVEN &= ~(uint32_t)linex;
EXTI_RTEN &= ~(uint32_t)linex;
EXTI_FTEN &= ~(uint32_t)linex;
/* set the EXTI mode and enable the interrupts or events from EXTI line x */
switch(mode){
case EXTI_INTERRUPT:
EXTI_INTEN |= (uint32_t)linex;
break;
case EXTI_EVENT:
EXTI_EVEN |= (uint32_t)linex;
break;
default:
break;
}
/* set the EXTI trigger type */
switch(trig_type){
case EXTI_TRIG_RISING:
EXTI_RTEN |= (uint32_t)linex;
EXTI_FTEN &= ~(uint32_t)linex;
break;
case EXTI_TRIG_FALLING:
EXTI_RTEN &= ~(uint32_t)linex;
EXTI_FTEN |= (uint32_t)linex;
break;
case EXTI_TRIG_BOTH:
EXTI_RTEN |= (uint32_t)linex;
EXTI_FTEN |= (uint32_t)linex;
break;
case EXTI_TRIG_NONE:
default:
break;
}
}
/*!
\brief enable the interrupts from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_enable(exti_line_enum linex)
{
EXTI_INTEN |= (uint32_t)linex;
}
/*!
\brief disable the interrupt from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_disable(exti_line_enum linex)
{
EXTI_INTEN &= ~(uint32_t)linex;
}
/*!
\brief enable the events from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_event_enable(exti_line_enum linex)
{
EXTI_EVEN |= (uint32_t)linex;
}
/*!
\brief disable the events from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_event_disable(exti_line_enum linex)
{
EXTI_EVEN &= ~(uint32_t)linex;
}
/*!
\brief enable the software interrupt event from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_enable(exti_line_enum linex)
{
EXTI_SWIEV |= (uint32_t)linex;
}
/*!
\brief disable the software interrupt event from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_disable(exti_line_enum linex)
{
EXTI_SWIEV &= ~(uint32_t)linex;
}
/*!
\brief get EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval FlagStatus: status of flag (RESET or SET)
*/
FlagStatus exti_flag_get(exti_line_enum linex)
{
if(RESET != (EXTI_PD & (uint32_t)linex)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_flag_clear(exti_line_enum linex)
{
EXTI_PD = (uint32_t)linex;
}
/*!
\brief get EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval FlagStatus: status of flag (RESET or SET)
*/
FlagStatus exti_interrupt_flag_get(exti_line_enum linex)
{
if(RESET != (EXTI_PD & (uint32_t)linex)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_flag_clear(exti_line_enum linex)
{
EXTI_PD = (uint32_t)linex;
}
@@ -0,0 +1,249 @@
/*!
\file gd32e50x_exti.c
\brief EXTI driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_exti.h"
#define EXTI_REG_RESET_VALUE ((uint32_t)0x00000000U)
/*!
\brief deinitialize the EXTI
\param[in] none
\param[out] none
\retval none
*/
void exti_deinit(void)
{
/* reset the value of all the EXTI registers */
EXTI_INTEN = EXTI_REG_RESET_VALUE;
EXTI_EVEN = EXTI_REG_RESET_VALUE;
EXTI_RTEN = EXTI_REG_RESET_VALUE;
EXTI_FTEN = EXTI_REG_RESET_VALUE;
EXTI_SWIEV = EXTI_REG_RESET_VALUE;
}
/*!
\brief initialize the EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[in] mode: interrupt or event mode, refer to exti_mode_enum
only one parameter can be selected which is shown as below:
\arg EXTI_INTERRUPT: interrupt mode
\arg EXTI_EVENT: event mode
\param[in] trig_type: interrupt trigger type, refer to exti_trig_type_enum
only one parameter can be selected which is shown as below:
\arg EXTI_TRIG_RISING: rising edge trigger
\arg EXTI_TRIG_FALLING: falling trigger
\arg EXTI_TRIG_BOTH: rising and falling trigger
\arg EXTI_TRIG_NONE: without rising edge or falling edge trigger
\param[out] none
\retval none
*/
void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type)
{
/* reset the EXTI line x */
EXTI_INTEN &= ~(uint32_t)linex;
EXTI_EVEN &= ~(uint32_t)linex;
EXTI_RTEN &= ~(uint32_t)linex;
EXTI_FTEN &= ~(uint32_t)linex;
/* set the EXTI mode and enable the interrupts or events from EXTI line x */
switch(mode){
case EXTI_INTERRUPT:
EXTI_INTEN |= (uint32_t)linex;
break;
case EXTI_EVENT:
EXTI_EVEN |= (uint32_t)linex;
break;
default:
break;
}
/* set the EXTI trigger type */
switch(trig_type){
case EXTI_TRIG_RISING:
EXTI_RTEN |= (uint32_t)linex;
EXTI_FTEN &= ~(uint32_t)linex;
break;
case EXTI_TRIG_FALLING:
EXTI_RTEN &= ~(uint32_t)linex;
EXTI_FTEN |= (uint32_t)linex;
break;
case EXTI_TRIG_BOTH:
EXTI_RTEN |= (uint32_t)linex;
EXTI_FTEN |= (uint32_t)linex;
break;
case EXTI_TRIG_NONE:
default:
break;
}
}
/*!
\brief enable the interrupts from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_enable(exti_line_enum linex)
{
EXTI_INTEN |= (uint32_t)linex;
}
/*!
\brief disable the interrupt from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_disable(exti_line_enum linex)
{
EXTI_INTEN &= ~(uint32_t)linex;
}
/*!
\brief enable the events from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_event_enable(exti_line_enum linex)
{
EXTI_EVEN |= (uint32_t)linex;
}
/*!
\brief disable the events from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_event_disable(exti_line_enum linex)
{
EXTI_EVEN &= ~(uint32_t)linex;
}
/*!
\brief enable the software interrupt event from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_enable(exti_line_enum linex)
{
EXTI_SWIEV |= (uint32_t)linex;
}
/*!
\brief disable the software interrupt event from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_disable(exti_line_enum linex)
{
EXTI_SWIEV &= ~(uint32_t)linex;
}
/*!
\brief get EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval FlagStatus: status of flag (RESET or SET)
*/
FlagStatus exti_flag_get(exti_line_enum linex)
{
if(RESET != (EXTI_PD & (uint32_t)linex)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_flag_clear(exti_line_enum linex)
{
EXTI_PD = (uint32_t)linex;
}
/*!
\brief get EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval FlagStatus: status of flag (RESET or SET)
*/
FlagStatus exti_interrupt_flag_get(exti_line_enum linex)
{
if(RESET != (EXTI_PD & (uint32_t)linex)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_flag_clear(exti_line_enum linex)
{
EXTI_PD = (uint32_t)linex;
}
@@ -0,0 +1,875 @@
/*!
\file gd32e50x_fmc.c
\brief FMC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_fmc.h"
/* FMC mask */
#define LOW_8BITS_MASK ((uint32_t)0x000000FFU)
#define HIGH_8BITS_MASK ((uint32_t)0x0000FF00U)
#define LOW_8BITS_MASK1 ((uint32_t)0x00FF0000U)
#define HIGH_8BITS_MASK1 ((uint32_t)0xFF000000U)
#define LOW_16BITS_MASK ((uint32_t)0x0000FFFFU)
#define HIGH_16BITS_MASK ((uint32_t)0xFFFF0000U)
/* USER of option bytes mask */
#define OB_USER_MASK ((uint8_t)0x38U)
/* default offset */
#define FMC_OBSTAT_USER_OFFSET 2U
#define FMC_OBSTAT_DATA_OFFSET 10U
/* return the FMC state */
static fmc_state_enum fmc_state_get(void);
/* check FMC ready or not */
static fmc_state_enum fmc_ready_wait(uint32_t timeout);
/*!
\brief unlock the main FMC operation
it is better to used in pairs with fmc_lock
\param[in] none
\param[out] none
\retval none
*/
void fmc_unlock(void)
{
if(RESET != (FMC_CTL & FMC_CTL_LK)){
/* write the FMC unlock key */
FMC_KEY = UNLOCK_KEY0;
FMC_KEY = UNLOCK_KEY1;
}
}
/*!
\brief lock the main FMC operation
it is better to used in pairs with fmc_unlock after an operation
\param[in] none
\param[out] none
\retval none
*/
void fmc_lock(void)
{
/* set the LK bit */
FMC_CTL |= FMC_CTL_LK;
}
/*!
\brief set the wait state
\param[in] wscnt: wait state
only one parameter can be selected which is shown as below:
\arg FMC_WAIT_STATE_0: 0 wait state added
\arg FMC_WAIT_STATE_1: 1 wait state added
\arg FMC_WAIT_STATE_2: 2 wait state added
\arg FMC_WAIT_STATE_3: 3 wait state added
\arg FMC_WAIT_STATE_4: 4 wait state added
\param[out] none
\retval none
*/
void fmc_wscnt_set(uint32_t wscnt)
{
uint32_t ws;
ws = FMC_WS;
/* set the wait state counter value */
ws &= ~FMC_WS_WSCNT;
FMC_WS = (ws | wscnt);
}
/*!
\brief enable pre-fetch
\param[in] none
\param[out] none
\retval none
*/
void fmc_prefetch_enable(void)
{
FMC_WS |= FMC_WS_PFEN;
}
/*!
\brief disable pre-fetch
\param[in] none
\param[out] none
\retval none
*/
void fmc_prefetch_disable(void)
{
FMC_WS &= ~FMC_WS_PFEN;
}
/*!
\brief enable IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_enable(void)
{
FMC_WS |= FMC_WS_ICEN;
}
/*!
\brief disable IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_disable(void)
{
FMC_WS &= ~FMC_WS_ICEN;
}
/*!
\brief reset IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_reset(void)
{
FMC_WS |= FMC_WS_ICRST;
}
/*!
\brief enable DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_enable(void)
{
FMC_WS |= FMC_WS_DCEN;
}
/*!
\brief disable DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_disable(void)
{
FMC_WS &= ~FMC_WS_DCEN;
}
/*!
\brief reset DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_reset(void)
{
FMC_WS |= FMC_WS_DCRST;
}
/*!
\brief FMC erase page
\param[in] page_address: target page address
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_page_erase(uint32_t page_address)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* start page erase */
FMC_CTL |= FMC_CTL_PER;
FMC_ADDR = page_address;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PER bit */
FMC_CTL &= ~FMC_CTL_PER;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC erase whole chip
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_mass_erase(void)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* start chip erase */
FMC_CTL |= FMC_CTL_MER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the MER bit */
FMC_CTL &= ~FMC_CTL_MER;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC program a word at the corresponding address
\param[in] address: address to program
\param[in] data: word to program
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* set the PG bit to start program */
FMC_CTL |= FMC_CTL_PG;
REG32(address) = data;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PG bit */
FMC_CTL &= ~FMC_CTL_PG;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief unlock the option bytes operation
it is better to used in pairs with ob_lock
\param[in] none
\param[out] none
\retval none
*/
void ob_unlock(void)
{
if(RESET == (FMC_CTL & FMC_CTL_OBWEN)){
/* write the FMC ob unlock key */
FMC_OBKEY = UNLOCK_KEY0;
FMC_OBKEY = UNLOCK_KEY1;
}
}
/*!
\brief lock the option bytes operation
it is better to used in pairs with ob_unlock after an operation
\param[in] none
\param[out] none
\retval none
*/
void ob_lock(void)
{
/* reset the OBWEN bit */
FMC_CTL &= ~FMC_CTL_OBWEN;
}
/*!
\brief erase the option bytes
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_erase(void)
{
uint32_t temp_spc;
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
/* set the OBPG bit */
FMC_CTL |= FMC_CTL_OBPG;
/* restore the last get option bytes security protection code */
OB_SPC_USER = (temp_spc & LOW_8BITS_MASK) | LOW_8BITS_MASK1;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief enable write protection
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_wp: specify sector to be write protected
only one parameter can be selected which are shown as below:
\arg OB_WP_NONE: disable all write protection
\arg OB_WP_x(x=0..31): write protect specify sector
\arg OB_WP_ALL: write protect all sector
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
ob_wp = (uint32_t)(~ob_wp);
op_byte[2] = (ob_wp & LOW_8BITS_MASK) | ((ob_wp & HIGH_8BITS_MASK) << 8);
op_byte[3] = ((ob_wp & LOW_8BITS_MASK1) >> 16) | ((ob_wp & HIGH_8BITS_MASK1) >> 8);
if(FMC_READY == fmc_state){
/* start erase the option byte */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief configure security protection
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_spc: specify security protection
only one parameter can be selected which is shown as below:
\arg FMC_NSPC: no security protection
\arg FMC_LSPC: low security protection
\arg FMC_HSPC: high security protection
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER & LOW_16BITS_MASK;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
op_byte[0] = ((uint32_t)(ob_spc)) | ((op_byte[0] & HIGH_16BITS_MASK));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief program option bytes USER
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_fwdgt: option bytes free watchdog value
only one parameter can be selected which is shown as below:
\arg OB_FWDGT_SW: software free watchdog
\arg OB_FWDGT_HW: hardware free watchdog
\param[in] ob_deepsleep: option bytes deepsleep reset value
only one parameter can be selected which is shown as below:
\arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
\arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
\param[in] ob_stdby:option bytes standby reset value
only one parameter can be selected which is shown as below:
\arg OB_STDBY_NRST: no reset when entering standby mode
\arg OB_STDBY_RST: generate a reset instead of entering standby mode
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_user_write(uint8_t ob_fwdgt, uint8_t ob_deepsleep, uint8_t ob_stdby)
{
uint32_t temp_spc;
uint8_t temp;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
temp = ((uint8_t)((uint8_t)(((uint8_t)(ob_fwdgt) | ob_deepsleep) | ob_stdby)) | (OB_USER_MASK));
op_byte[0] = ((uint32_t)(temp) << 16U) | ((op_byte[0] & LOW_16BITS_MASK));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief program option bytes DATA
\param[in] data: the byte to be programmed
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_data_program(uint16_t ob_data)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
op_byte[1] = (uint32_t)((ob_data & LOW_8BITS_MASK) | ((ob_data & HIGH_8BITS_MASK) << 8));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief get the value of option bytes USER
\param[in] none
\param[out] none
\retval the option bytes USER value
*/
uint8_t ob_user_get(void)
{
/* return the FMC user option bytes value */
return (uint8_t)(FMC_OBSTAT >> FMC_OBSTAT_USER_OFFSET);
}
/*!
\brief get the value of option bytes DATA
\param[in] none
\param[out] none
\retval the option bytes DATA value
*/
uint16_t ob_data_get(void)
{
return (uint16_t)(FMC_OBSTAT >> FMC_OBSTAT_DATA_OFFSET);
}
/*!
\brief get the value of option bytes write protection
\param[in] none
\param[out] none
\retval the write protection option bytes value
*/
uint32_t ob_write_protection_get(void)
{
/* return the FMC write protection option bytes value */
return FMC_WP;
}
/*!
\brief get the FMC option bytes security protection state
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ob_security_protection_flag_get(void)
{
FlagStatus spc_state = RESET;
if(RESET != (FMC_OBSTAT & FMC_OBSTAT_SPC)){
spc_state = SET;
}else{
spc_state = RESET;
}
return spc_state;
}
/*!
\brief get FMC flag status
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_BUSY: FMC busy flag
\arg FMC_FLAG_PGERR: FMC program error flag
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag
\arg FMC_FLAG_END: FMC end of operation flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(FMC_STAT & flag){
status = SET;
}
/* return the state of corresponding FMC flag */
return status;
}
/*!
\brief clear the FMC flag
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_PGERR: FMC program error flag
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag
\arg FMC_FLAG_END: FMC end of operation flag
\param[out] none
\retval none
*/
void fmc_flag_clear(uint32_t flag)
{
/* clear the flags */
FMC_STAT = flag;
}
/*!
\brief enable FMC interrupt
\param[in] interrupt: the FMC interrupt
only one parameter can be selected which is shown as below:
\arg FMC_INT_END: FMC end of operation interrupt
\arg FMC_INT_ERR: FMC error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_enable(uint32_t interrupt)
{
FMC_CTL |= interrupt;
}
/*!
\brief disable FMC interrupt
\param[in] interrupt: the FMC interrupt
only one parameter can be selected which is shown as below:
\arg FMC_INT_END: FMC end of operation interrupt
\arg FMC_INT_ERR: FMC error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_disable(uint32_t interrupt)
{
FMC_CTL &= ~(uint32_t)interrupt;
}
/*!
\brief get FMC interrupt flag
\param[in] flag: FMC interrupt flag
only one parameter can be selected which is shown as below:
\arg FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
\arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
\arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_interrupt_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(FMC_STAT & flag){
status = SET;
}
/* return the state of corresponding FMC flag */
return status;
}
/*!
\brief clear FMC interrupt flag
\param[in] flag: FMC interrupt flag
one or more parameters can be selected which is shown as below:
\arg FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
\arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
\arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
\param[out] none
\retval none
*/
void fmc_interrupt_flag_clear(uint32_t flag)
{
/* clear the flag */
FMC_STAT = flag;
}
/*!
\brief get the FMC state
\param[in] none
\param[out] none
\retval state of FMC, refer to fmc_state_enum
*/
static fmc_state_enum fmc_state_get(void)
{
fmc_state_enum fmc_state = FMC_READY;
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)){
fmc_state = FMC_BUSY;
}else{
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)){
fmc_state = FMC_WPERR;
}else{
if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGERR))){
fmc_state = FMC_PGERR;
}else{
if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGAERR))){
fmc_state = FMC_PGAERR;
}
}
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief check whether FMC is ready or not
\param[in] timeout: timeout count
\param[out] none
\retval state of FMC, refer to fmc_state_enum
*/
static fmc_state_enum fmc_ready_wait(uint32_t timeout)
{
fmc_state_enum fmc_state = FMC_BUSY;
/* wait for FMC ready */
do{
/* get FMC state */
fmc_state = fmc_state_get();
timeout--;
}while((FMC_BUSY == fmc_state) && (0x00U != timeout));
if(FMC_BUSY == fmc_state){
fmc_state = FMC_TOERR;
}
/* return the FMC state */
return fmc_state;
}
@@ -0,0 +1,875 @@
/*!
\file gd32e50x_fmc.c
\brief FMC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_fmc.h"
/* FMC mask */
#define LOW_8BITS_MASK ((uint32_t)0x000000FFU)
#define HIGH_8BITS_MASK ((uint32_t)0x0000FF00U)
#define LOW_8BITS_MASK1 ((uint32_t)0x00FF0000U)
#define HIGH_8BITS_MASK1 ((uint32_t)0xFF000000U)
#define LOW_16BITS_MASK ((uint32_t)0x0000FFFFU)
#define HIGH_16BITS_MASK ((uint32_t)0xFFFF0000U)
/* USER of option bytes mask */
#define OB_USER_MASK ((uint8_t)0x38U)
/* default offset */
#define FMC_OBSTAT_USER_OFFSET 2U
#define FMC_OBSTAT_DATA_OFFSET 10U
/* return the FMC state */
static fmc_state_enum fmc_state_get(void);
/* check FMC ready or not */
static fmc_state_enum fmc_ready_wait(uint32_t timeout);
/*!
\brief unlock the main FMC operation
it is better to used in pairs with fmc_lock
\param[in] none
\param[out] none
\retval none
*/
void fmc_unlock(void)
{
if(RESET != (FMC_CTL & FMC_CTL_LK)){
/* write the FMC unlock key */
FMC_KEY = UNLOCK_KEY0;
FMC_KEY = UNLOCK_KEY1;
}
}
/*!
\brief lock the main FMC operation
it is better to used in pairs with fmc_unlock after an operation
\param[in] none
\param[out] none
\retval none
*/
void fmc_lock(void)
{
/* set the LK bit */
FMC_CTL |= FMC_CTL_LK;
}
/*!
\brief set the wait state
\param[in] wscnt: wait state
only one parameter can be selected which is shown as below:
\arg FMC_WAIT_STATE_0: 0 wait state added
\arg FMC_WAIT_STATE_1: 1 wait state added
\arg FMC_WAIT_STATE_2: 2 wait state added
\arg FMC_WAIT_STATE_3: 3 wait state added
\arg FMC_WAIT_STATE_4: 4 wait state added
\param[out] none
\retval none
*/
void fmc_wscnt_set(uint32_t wscnt)
{
uint32_t ws;
ws = FMC_WS;
/* set the wait state counter value */
ws &= ~FMC_WS_WSCNT;
FMC_WS = (ws | wscnt);
}
/*!
\brief enable pre-fetch
\param[in] none
\param[out] none
\retval none
*/
void fmc_prefetch_enable(void)
{
FMC_WS |= FMC_WS_PFEN;
}
/*!
\brief disable pre-fetch
\param[in] none
\param[out] none
\retval none
*/
void fmc_prefetch_disable(void)
{
FMC_WS &= ~FMC_WS_PFEN;
}
/*!
\brief enable IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_enable(void)
{
FMC_WS |= FMC_WS_ICEN;
}
/*!
\brief disable IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_disable(void)
{
FMC_WS &= ~FMC_WS_ICEN;
}
/*!
\brief reset IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_reset(void)
{
FMC_WS |= FMC_WS_ICRST;
}
/*!
\brief enable DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_enable(void)
{
FMC_WS |= FMC_WS_DCEN;
}
/*!
\brief disable DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_disable(void)
{
FMC_WS &= ~FMC_WS_DCEN;
}
/*!
\brief reset DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_reset(void)
{
FMC_WS |= FMC_WS_DCRST;
}
/*!
\brief FMC erase page
\param[in] page_address: target page address
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_page_erase(uint32_t page_address)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* start page erase */
FMC_CTL |= FMC_CTL_PER;
FMC_ADDR = page_address;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PER bit */
FMC_CTL &= ~FMC_CTL_PER;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC erase whole chip
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_mass_erase(void)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* start chip erase */
FMC_CTL |= FMC_CTL_MER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the MER bit */
FMC_CTL &= ~FMC_CTL_MER;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC program a word at the corresponding address
\param[in] address: address to program
\param[in] data: word to program
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* set the PG bit to start program */
FMC_CTL |= FMC_CTL_PG;
REG32(address) = data;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PG bit */
FMC_CTL &= ~FMC_CTL_PG;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief unlock the option bytes operation
it is better to used in pairs with ob_lock
\param[in] none
\param[out] none
\retval none
*/
void ob_unlock(void)
{
if(RESET == (FMC_CTL & FMC_CTL_OBWEN)){
/* write the FMC ob unlock key */
FMC_OBKEY = UNLOCK_KEY0;
FMC_OBKEY = UNLOCK_KEY1;
}
}
/*!
\brief lock the option bytes operation
it is better to used in pairs with ob_unlock after an operation
\param[in] none
\param[out] none
\retval none
*/
void ob_lock(void)
{
/* reset the OBWEN bit */
FMC_CTL &= ~FMC_CTL_OBWEN;
}
/*!
\brief erase the option bytes
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_erase(void)
{
uint32_t temp_spc;
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
/* set the OBPG bit */
FMC_CTL |= FMC_CTL_OBPG;
/* restore the last get option bytes security protection code */
OB_SPC_USER = (temp_spc & LOW_8BITS_MASK) | LOW_8BITS_MASK1;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief enable write protection
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_wp: specify sector to be write protected
only one parameter can be selected which are shown as below:
\arg OB_WP_NONE: disable all write protection
\arg OB_WP_x(x=0..31): write protect specify sector
\arg OB_WP_ALL: write protect all sector
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
ob_wp = (uint32_t)(~ob_wp);
op_byte[2] = (ob_wp & LOW_8BITS_MASK) | ((ob_wp & HIGH_8BITS_MASK) << 8);
op_byte[3] = ((ob_wp & LOW_8BITS_MASK1) >> 16) | ((ob_wp & HIGH_8BITS_MASK1) >> 8);
if(FMC_READY == fmc_state){
/* start erase the option byte */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief configure security protection
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_spc: specify security protection
only one parameter can be selected which is shown as below:
\arg FMC_NSPC: no security protection
\arg FMC_LSPC: low security protection
\arg FMC_HSPC: high security protection
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER & LOW_16BITS_MASK;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
op_byte[0] = ((uint32_t)(ob_spc)) | ((op_byte[0] & HIGH_16BITS_MASK));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief program option bytes USER
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_fwdgt: option bytes free watchdog value
only one parameter can be selected which is shown as below:
\arg OB_FWDGT_SW: software free watchdog
\arg OB_FWDGT_HW: hardware free watchdog
\param[in] ob_deepsleep: option bytes deepsleep reset value
only one parameter can be selected which is shown as below:
\arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
\arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
\param[in] ob_stdby:option bytes standby reset value
only one parameter can be selected which is shown as below:
\arg OB_STDBY_NRST: no reset when entering standby mode
\arg OB_STDBY_RST: generate a reset instead of entering standby mode
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_user_write(uint8_t ob_fwdgt, uint8_t ob_deepsleep, uint8_t ob_stdby)
{
uint32_t temp_spc;
uint8_t temp;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
temp = ((uint8_t)((uint8_t)(((uint8_t)(ob_fwdgt) | ob_deepsleep) | ob_stdby)) | (OB_USER_MASK));
op_byte[0] = ((uint32_t)(temp) << 16U) | ((op_byte[0] & LOW_16BITS_MASK));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief program option bytes DATA
\param[in] data: the byte to be programmed
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_data_program(uint16_t ob_data)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
op_byte[1] = (uint32_t)((ob_data & LOW_8BITS_MASK) | ((ob_data & HIGH_8BITS_MASK) << 8));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief get the value of option bytes USER
\param[in] none
\param[out] none
\retval the option bytes USER value
*/
uint8_t ob_user_get(void)
{
/* return the FMC user option bytes value */
return (uint8_t)(FMC_OBSTAT >> FMC_OBSTAT_USER_OFFSET);
}
/*!
\brief get the value of option bytes DATA
\param[in] none
\param[out] none
\retval the option bytes DATA value
*/
uint16_t ob_data_get(void)
{
return (uint16_t)(FMC_OBSTAT >> FMC_OBSTAT_DATA_OFFSET);
}
/*!
\brief get the value of option bytes write protection
\param[in] none
\param[out] none
\retval the write protection option bytes value
*/
uint32_t ob_write_protection_get(void)
{
/* return the FMC write protection option bytes value */
return FMC_WP;
}
/*!
\brief get the FMC option bytes security protection state
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ob_security_protection_flag_get(void)
{
FlagStatus spc_state = RESET;
if(RESET != (FMC_OBSTAT & FMC_OBSTAT_SPC)){
spc_state = SET;
}else{
spc_state = RESET;
}
return spc_state;
}
/*!
\brief get FMC flag status
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_BUSY: FMC busy flag
\arg FMC_FLAG_PGERR: FMC program error flag
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag
\arg FMC_FLAG_END: FMC end of operation flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(FMC_STAT & flag){
status = SET;
}
/* return the state of corresponding FMC flag */
return status;
}
/*!
\brief clear the FMC flag
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_PGERR: FMC program error flag
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag
\arg FMC_FLAG_END: FMC end of operation flag
\param[out] none
\retval none
*/
void fmc_flag_clear(uint32_t flag)
{
/* clear the flags */
FMC_STAT = flag;
}
/*!
\brief enable FMC interrupt
\param[in] interrupt: the FMC interrupt
only one parameter can be selected which is shown as below:
\arg FMC_INT_END: FMC end of operation interrupt
\arg FMC_INT_ERR: FMC error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_enable(uint32_t interrupt)
{
FMC_CTL |= interrupt;
}
/*!
\brief disable FMC interrupt
\param[in] interrupt: the FMC interrupt
only one parameter can be selected which is shown as below:
\arg FMC_INT_END: FMC end of operation interrupt
\arg FMC_INT_ERR: FMC error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_disable(uint32_t interrupt)
{
FMC_CTL &= ~(uint32_t)interrupt;
}
/*!
\brief get FMC interrupt flag
\param[in] flag: FMC interrupt flag
only one parameter can be selected which is shown as below:
\arg FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
\arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
\arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_interrupt_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(FMC_STAT & flag){
status = SET;
}
/* return the state of corresponding FMC flag */
return status;
}
/*!
\brief clear FMC interrupt flag
\param[in] flag: FMC interrupt flag
one or more parameters can be selected which is shown as below:
\arg FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
\arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
\arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
\param[out] none
\retval none
*/
void fmc_interrupt_flag_clear(uint32_t flag)
{
/* clear the flag */
FMC_STAT = flag;
}
/*!
\brief get the FMC state
\param[in] none
\param[out] none
\retval state of FMC, refer to fmc_state_enum
*/
static fmc_state_enum fmc_state_get(void)
{
fmc_state_enum fmc_state = FMC_READY;
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)){
fmc_state = FMC_BUSY;
}else{
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)){
fmc_state = FMC_WPERR;
}else{
if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGERR))){
fmc_state = FMC_PGERR;
}else{
if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGAERR))){
fmc_state = FMC_PGAERR;
}
}
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief check whether FMC is ready or not
\param[in] timeout: timeout count
\param[out] none
\retval state of FMC, refer to fmc_state_enum
*/
static fmc_state_enum fmc_ready_wait(uint32_t timeout)
{
fmc_state_enum fmc_state = FMC_BUSY;
/* wait for FMC ready */
do{
/* get FMC state */
fmc_state = fmc_state_get();
timeout--;
}while((FMC_BUSY == fmc_state) && (0x00U != timeout));
if(FMC_BUSY == fmc_state){
fmc_state = FMC_TOERR;
}
/* return the FMC state */
return fmc_state;
}
@@ -0,0 +1,227 @@
/*!
\file gd32e50x_fwdgt.c
\brief FWDGT driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_fwdgt.h"
/*!
\brief enable write access to FWDGT_PSC and FWDGT_RLD
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_write_enable(void)
{
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
}
/*!
\brief disable write access to FWDGT_PSC and FWDGT_RLD
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_write_disable(void)
{
FWDGT_CTL = FWDGT_WRITEACCESS_DISABLE;
}
/*!
\brief start the free watchdog timer counter
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_enable(void)
{
FWDGT_CTL = FWDGT_KEY_ENABLE;
}
/*!
\brief configure the free watchdog timer counter prescaler value
\param[in] prescaler_value: specify prescaler value
only one parameter can be selected which is shown as below:
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_prescaler_value_config(uint16_t prescaler_value)
{
uint32_t timeout = FWDGT_PSC_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* enable write access to FWDGT_PSC */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT */
FWDGT_PSC = (uint32_t)prescaler_value;
/* wait until the PUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
return status;
}
/*!
\brief configure the free watchdog timer counter reload value
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_reload_value_config(uint16_t reload_value)
{
uint32_t timeout = FWDGT_RLD_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* enable write access to FWDGT_RLD */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT_RLD */
FWDGT_RLD = RLD_RLD(reload_value);
/* wait until the RUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
return status;
}
/*!
\brief reload the counter of FWDGT
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_counter_reload(void)
{
FWDGT_CTL = FWDGT_KEY_RELOAD;
}
/*!
\brief configure counter reload value, and prescaler divider value
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
\param[in] prescaler_value: FWDGT prescaler value
only one parameter can be selected which is shown as below:
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_config(uint16_t reload_value, uint8_t prescaler_value)
{
uint32_t timeout = FWDGT_PSC_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* start the free watchdog timer counter */
FWDGT_CTL = FWDGT_KEY_ENABLE;
/* enable write access to FWDGT_PSC,and FWDGT_RLD */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT PSC */
FWDGT_PSC = (uint32_t)prescaler_value;
/* wait until the PUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
if(SUCCESS == status) {
/* configure FWDGT_RLD */
FWDGT_RLD = RLD_RLD(reload_value);
/* wait until the RUD flag to be reset */
timeout = FWDGT_RLD_TIMEOUT;
do {
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
}
if(SUCCESS == status) {
/* reload the counter */
FWDGT_CTL = FWDGT_KEY_RELOAD;
}
return status;
}
/*!
\brief get flag state of FWDGT
\param[in] flag: flag to get
only one parameter can be selected which is shown as below:
\arg FWDGT_FLAG_PUD: a write operation to FWDGT_PSC register is on going
\arg FWDGT_FLAG_RUD: a write operation to FWDGT_RLD register is on going
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fwdgt_flag_get(uint16_t flag)
{
FlagStatus flag_status = RESET;
if(FWDGT_STAT & flag) {
flag_status = SET;
}
return flag_status;
}
@@ -0,0 +1,227 @@
/*!
\file gd32e50x_fwdgt.c
\brief FWDGT driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_fwdgt.h"
/*!
\brief enable write access to FWDGT_PSC and FWDGT_RLD
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_write_enable(void)
{
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
}
/*!
\brief disable write access to FWDGT_PSC and FWDGT_RLD
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_write_disable(void)
{
FWDGT_CTL = FWDGT_WRITEACCESS_DISABLE;
}
/*!
\brief start the free watchdog timer counter
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_enable(void)
{
FWDGT_CTL = FWDGT_KEY_ENABLE;
}
/*!
\brief configure the free watchdog timer counter prescaler value
\param[in] prescaler_value: specify prescaler value
only one parameter can be selected which is shown as below:
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_prescaler_value_config(uint16_t prescaler_value)
{
uint32_t timeout = FWDGT_PSC_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* enable write access to FWDGT_PSC */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT */
FWDGT_PSC = (uint32_t)prescaler_value;
/* wait until the PUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
return status;
}
/*!
\brief configure the free watchdog timer counter reload value
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_reload_value_config(uint16_t reload_value)
{
uint32_t timeout = FWDGT_RLD_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* enable write access to FWDGT_RLD */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT_RLD */
FWDGT_RLD = RLD_RLD(reload_value);
/* wait until the RUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
return status;
}
/*!
\brief reload the counter of FWDGT
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_counter_reload(void)
{
FWDGT_CTL = FWDGT_KEY_RELOAD;
}
/*!
\brief configure counter reload value, and prescaler divider value
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
\param[in] prescaler_value: FWDGT prescaler value
only one parameter can be selected which is shown as below:
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_config(uint16_t reload_value, uint8_t prescaler_value)
{
uint32_t timeout = FWDGT_PSC_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* start the free watchdog timer counter */
FWDGT_CTL = FWDGT_KEY_ENABLE;
/* enable write access to FWDGT_PSC,and FWDGT_RLD */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT PSC */
FWDGT_PSC = (uint32_t)prescaler_value;
/* wait until the PUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
if(SUCCESS == status) {
/* configure FWDGT_RLD */
FWDGT_RLD = RLD_RLD(reload_value);
/* wait until the RUD flag to be reset */
timeout = FWDGT_RLD_TIMEOUT;
do {
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
}
if(SUCCESS == status) {
/* reload the counter */
FWDGT_CTL = FWDGT_KEY_RELOAD;
}
return status;
}
/*!
\brief get flag state of FWDGT
\param[in] flag: flag to get
only one parameter can be selected which is shown as below:
\arg FWDGT_FLAG_PUD: a write operation to FWDGT_PSC register is on going
\arg FWDGT_FLAG_RUD: a write operation to FWDGT_RLD register is on going
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fwdgt_flag_get(uint16_t flag)
{
FlagStatus flag_status = RESET;
if(FWDGT_STAT & flag) {
flag_status = SET;
}
return flag_status;
}
@@ -0,0 +1,699 @@
/*!
\file gd32e50x_gpio.c
\brief GPIO driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_gpio.h"
#define AFIO_EXTI_SOURCE_MASK ((uint8_t)0x03U) /*!< AFIO exti source selection mask*/
#define AFIO_EXTI_SOURCE_FIELDS ((uint8_t)0x04U) /*!< select AFIO exti source registers */
#define LSB_16BIT_MASK ((uint16_t)0xFFFFU) /*!< LSB 16-bit mask */
#define PCF_POSITION_MASK ((uint32_t)0x000F0000U) /*!< AFIO_PCF register position mask */
#define PCF_SWJCFG_MASK ((uint32_t)0xF8FFFFFFU) /*!< AFIO_PCF register SWJCFG mask */
#define PCF_LOCATION1_MASK ((uint32_t)0x00200000U) /*!< AFIO_PCF register location1 mask */
#define PCF_LOCATION2_MASK ((uint32_t)0x00100000U) /*!< AFIO_PCF register location2 mask */
#define AFIO_PCF1_FIELDS ((uint32_t)0x80000000U) /*!< select AFIO_PCF1 register */
#define GPIO_OUTPUT_PORT_OFFSET ((uint32_t)4U) /*!< GPIO event output port offset*/
/*!
\brief reset GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval none
*/
void gpio_deinit(uint32_t gpio_periph)
{
switch(gpio_periph){
case GPIOA:
/* reset GPIOA */
rcu_periph_reset_enable(RCU_GPIOARST);
rcu_periph_reset_disable(RCU_GPIOARST);
break;
case GPIOB:
/* reset GPIOB */
rcu_periph_reset_enable(RCU_GPIOBRST);
rcu_periph_reset_disable(RCU_GPIOBRST);
break;
case GPIOC:
/* reset GPIOC */
rcu_periph_reset_enable(RCU_GPIOCRST);
rcu_periph_reset_disable(RCU_GPIOCRST);
break;
case GPIOD:
/* reset GPIOD */
rcu_periph_reset_enable(RCU_GPIODRST);
rcu_periph_reset_disable(RCU_GPIODRST);
break;
case GPIOE:
/* reset GPIOE */
rcu_periph_reset_enable(RCU_GPIOERST);
rcu_periph_reset_disable(RCU_GPIOERST);
break;
case GPIOF:
/* reset GPIOF */
rcu_periph_reset_enable(RCU_GPIOFRST);
rcu_periph_reset_disable(RCU_GPIOFRST);
break;
case GPIOG:
/* reset GPIOG */
rcu_periph_reset_enable(RCU_GPIOGRST);
rcu_periph_reset_disable(RCU_GPIOGRST);
break;
default:
break;
}
}
/*!
\brief reset alternate function I/O(AFIO)
\param[in] none
\param[out] none
\retval none
*/
void gpio_afio_deinit(void)
{
rcu_periph_reset_enable(RCU_AFRST);
rcu_periph_reset_disable(RCU_AFRST);
}
/*!
\brief GPIO parameter initialization
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] mode: gpio pin mode
only one parameter can be selected which is shown as below:
\arg GPIO_MODE_AIN: analog input mode
\arg GPIO_MODE_IN_FLOATING: floating input mode
\arg GPIO_MODE_IPD: pull-down input mode
\arg GPIO_MODE_IPU: pull-up input mode
\arg GPIO_MODE_OUT_OD: GPIO output with open-drain
\arg GPIO_MODE_OUT_PP: GPIO output with push-pull
\arg GPIO_MODE_AF_OD: AFIO output with open-drain
\arg GPIO_MODE_AF_PP: AFIO output with push-pull
\param[in] speed: gpio output max speed value
only one parameter can be selected which is shown as below:
\arg GPIO_OSPEED_10MHZ: output max speed 10MHz
\arg GPIO_OSPEED_2MHZ: output max speed 2MHz
\arg GPIO_OSPEED_50MHZ: output max speed 50MHz
\arg GPIO_OSPEED_MAX: output max speed more than 50MHz
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_init(uint32_t gpio_periph, uint32_t mode, uint32_t speed, uint32_t pin)
{
uint16_t i;
uint32_t temp_mode = 0U;
uint32_t reg = 0U;
/* GPIO mode configuration */
temp_mode = (uint32_t)(mode & ((uint32_t)0x0FU));
/* GPIO speed configuration */
if(((uint32_t)0x00U) != ((uint32_t)mode & ((uint32_t)0x10U))){
/* output mode max speed */
if(GPIO_OSPEED_MAX == (uint32_t)speed){
temp_mode |= (uint32_t)0x03U;
/* set the corresponding SPD bit */
GPIOx_SPD(gpio_periph) |= (uint32_t)pin ;
}else{
/* output mode max speed:10MHz,2MHz,50MHz */
temp_mode |= (uint32_t)speed;
}
}
/* configure the eight low port pins with GPIO_CTL0 */
for(i = 0U;i < 8U;i++){
if((1U << i) & pin){
reg = GPIO_CTL0(gpio_periph);
/* clear the specified pin mode bits */
reg &= ~GPIO_MODE_MASK(i);
/* set the specified pin mode bits */
reg |= GPIO_MODE_SET(i, temp_mode);
/* set IPD or IPU */
if(GPIO_MODE_IPD == mode){
/* reset the corresponding OCTL bit */
GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin);
}else{
/* set the corresponding OCTL bit */
if(GPIO_MODE_IPU == mode){
GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin);
}
}
/* set GPIO_CTL0 register */
GPIO_CTL0(gpio_periph) = reg;
}
}
/* configure the eight high port pins with GPIO_CTL1 */
for(i = 8U;i < 16U;i++){
if((1U << i) & pin){
reg = GPIO_CTL1(gpio_periph);
/* clear the specified pin mode bits */
reg &= ~GPIO_MODE_MASK(i - 8U);
/* set the specified pin mode bits */
reg |= GPIO_MODE_SET(i - 8U, temp_mode);
/* set IPD or IPU */
if(GPIO_MODE_IPD == mode){
/* reset the corresponding OCTL bit */
GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin);
}else{
/* set the corresponding OCTL bit */
if(GPIO_MODE_IPU == mode){
GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin);
}
}
/* set GPIO_CTL1 register */
GPIO_CTL1(gpio_periph) = reg;
}
}
}
/*!
\brief set GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_set(uint32_t gpio_periph,uint32_t pin)
{
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}
/*!
\brief reset GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_reset(uint32_t gpio_periph,uint32_t pin)
{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
/*!
\brief write data to the specified GPIO pin
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[in] bit_value: SET or RESET
\arg RESET: clear the port pin
\arg SET: set the port pin
\param[out] none
\retval none
*/
void gpio_bit_write(uint32_t gpio_periph,uint32_t pin,bit_status bit_value)
{
if(RESET != bit_value){
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}else{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
}
/*!
\brief write data to the specified GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] data: specify the value to be written to the port output data register
\param[out] none
\retval none
*/
void gpio_port_write(uint32_t gpio_periph,uint16_t data)
{
GPIO_OCTL(gpio_periph) = (uint32_t)data;
}
/*!
\brief get GPIO pin input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval input status of gpio pin: SET or RESET
*/
FlagStatus gpio_input_bit_get(uint32_t gpio_periph,uint32_t pin)
{
if((uint32_t)RESET != (GPIO_ISTAT(gpio_periph)&(pin))){
return SET;
}else{
return RESET;
}
}
/*!
\brief get GPIO port input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval input status of gpio all pins
*/
uint16_t gpio_input_port_get(uint32_t gpio_periph)
{
return (uint16_t)(GPIO_ISTAT(gpio_periph));
}
/*!
\brief get GPIO pin output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval output status of gpio pin: SET or RESET
*/
FlagStatus gpio_output_bit_get(uint32_t gpio_periph,uint32_t pin)
{
if((uint32_t)RESET !=(GPIO_OCTL(gpio_periph)&(pin))){
return SET;
}else{
return RESET;
}
}
/*!
\brief get GPIO port output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval output status of gpio all pins
*/
uint16_t gpio_output_port_get(uint32_t gpio_periph)
{
return ((uint16_t)GPIO_OCTL(gpio_periph));
}
/*!
\brief configure GPIO pin remap
\param[in] gpio_remap: select the pin to remap
only one parameter can be selected which are shown as below:
\arg GPIO_SPI0_REMAP: SPI0 remapping
\arg GPIO_I2C0_REMAP: I2C0 remapping
\arg GPIO_USART0_REMAP: USART0 remapping
\arg GPIO_USART1_REMAP: USART1 remapping
\arg GPIO_USART2_PARTIAL_REMAP: USART2 partial remapping
\arg GPIO_USART2_FULL_REMAP: USART2 full remapping
\arg GPIO_TIMER0_PARTIAL_REMAP: TIMER0 partial remapping
\arg GPIO_TIMER0_FULL_REMAP: TIMER0 full remapping
\arg GPIO_TIMER1_PARTIAL_REMAP0: TIMER1 partial remapping
\arg GPIO_TIMER1_PARTIAL_REMAP1: TIMER1 partial remapping
\arg GPIO_TIMER1_FULL_REMAP: TIMER1 full remapping
\arg GPIO_TIMER2_PARTIAL_REMAP: TIMER2 partial remapping
\arg GPIO_TIMER2_FULL_REMAP: TIMER2 full remapping
\arg GPIO_TIMER3_REMAP: TIMER3 remapping
\arg GPIO_CAN0_PARTIAL_REMAP: CAN0 partial remapping(not support on GD32EPRT devices)
\arg GPIO_CAN0_FULL_REMAP: CAN0 full remapping(not support on GD32EPRT devices)
\arg GPIO_PD01_REMAP: PD01 remapping
\arg GPIO_TIMER4CH3_IREMAP: TIMER4 channel3 internal remapping
\arg GPIO_ADC0_ETRGRT_REMAP: ADC0 external trigger routine conversion remapping(only for GD32E50X_HD devices)
\arg GPIO_ADC1_ETRGRT_REMAP: ADC1 external trigger routine conversion remapping(only for GD32E50X_HD devices)
\arg GPIO_ENET_REMAP: ENET remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_CAN1_REMAP: CAN1 remapping(not support on GD32EPRT devices)
\arg GPIO_SWJ_NONJTRST_REMAP: full SWJ(JTAG-DP + SW-DP),but without NJTRST
\arg GPIO_SWJ_SWDPENABLE_REMAP: JTAG-DP disabled and SW-DP enabled
\arg GPIO_SWJ_DISABLE_REMAP: JTAG-DP disabled and SW-DP disabled
\arg GPIO_SPI2_REMAP: SPI2 remapping
\arg GPIO_TIMER1ITR1_REMAP: TIMER1 internal trigger 1 remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_PTP_PPS_REMAP: ethernet PTP PPS remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_TIMER8_REMAP: TIMER8 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER9_REMAP: TIMER9 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER10_REMAP: TIMER10 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER12_REMAP: TIMER12 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER13_REMAP: TIMER13 remapping(not support on GD32EPRT devices)
\arg GPIO_EXMC_NADV_REMAP: EXMC_NADV connect/disconnect
\arg GPIO_CTC_REMAP0: CTC remapping(PD15)
\arg GPIO_CTC_REMAP1: CTC remapping(PF0)
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void gpio_pin_remap_config(uint32_t remap, ControlStatus newvalue)
{
uint32_t remap1 = 0U, remap2 = 0U, temp_reg = 0U, temp_mask = 0U;
if(((uint32_t)0x80000000U) == (remap & 0x80000000U)){
/* get AFIO_PCF1 regiter value */
temp_reg = AFIO_PCF1;
}else{
/* get AFIO_PCF0 regiter value */
temp_reg = AFIO_PCF0;
}
temp_mask = (remap & PCF_POSITION_MASK) >> 0x10U;
remap1 = remap & LSB_16BIT_MASK;
/* judge pin remap type */
if((PCF_LOCATION1_MASK | PCF_LOCATION2_MASK) == (remap & (PCF_LOCATION1_MASK | PCF_LOCATION2_MASK))){
temp_reg &= PCF_SWJCFG_MASK;
AFIO_PCF0 &= PCF_SWJCFG_MASK;
}else if(PCF_LOCATION2_MASK == (remap & PCF_LOCATION2_MASK)){
remap2 = ((uint32_t)0x03U) << temp_mask;
temp_reg &= ~remap2;
temp_reg |= ~PCF_SWJCFG_MASK;
}else{
temp_reg &= ~(remap1 << ((remap >> 0x15U)*0x10U));
temp_reg |= ~PCF_SWJCFG_MASK;
}
/* set pin remap value */
if(DISABLE != newvalue){
temp_reg |= (remap1 << ((remap >> 0x15U)*0x10U));
}
if(AFIO_PCF1_FIELDS == (remap & AFIO_PCF1_FIELDS)){
/* set AFIO_PCF1 regiter value */
AFIO_PCF1 = temp_reg;
}else{
/* set AFIO_PCF0 regiter value */
AFIO_PCF0 = temp_reg;
}
}
/*!
\brief configure AFIO port alternate function
\param[in] afio_function: select the port AFIO function(SHRTIMER not support on GD32EPRT devices)
only one parameter can be selected which are shown as below:
\arg AFIO_PA2_CMP1_CFG: configure PA2 alternate function to CMP1
\arg AFIO_PA3_USBHS_CFG: configure PA3 alternate function to USBHS
\arg AFIO_PA5_USBHS_CFG: configure PA5 alternate function to USBHS
\arg AFIO_PA8_I2C2_CFG: configure PA8 alternate function to I2C2
\arg AFIO_PA8_SHRTIMER_CFG: configure PA8 alternate function to SHRTIMER
\arg AFIO_PA9_CAN2_CFG: configure PA9 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PA9_I2C2_CFG: configure PA9 alternate function to I2C2
\arg AFIO_PA9_SHRTIMER_CFG: configure PA9 alternate function to SHRTIMER
\arg AFIO_PA10_CAN2_CFG: configure PA10 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PA10_CMP5_CFG: configure PA10 alternate function to CMP5
\arg AFIO_PA10_SHRTIMER_CFG: configure PA10 alternate function to SHRTIMER
\arg AFIO_PA11_USART5_CFG: configure PA11 alternate function to USART5
\arg AFIO_PA11_SHRTIMER_CFG: configure PA11 alternate function to SHRTIMER
\arg AFIO_PA12_CMP1_CFG: configure PA12 alternate function to CMP1
\arg AFIO_PA12_USART5_CFG: configure PA12 alternate function to USART5
\arg AFIO_PA12_SHRTIMER_CFG: configure PA12 alternate function to SHRTIMER
\arg AFIO_PA15_SHRTIMER_CFG: configure PA15 alternate function to SHRTIMER
\arg AFIO_PB0_USBHS_CFG: configure PB0 alternate function to USBHS
\arg AFIO_PB1_CMP3_CFG: configure PB1 alternate function to CMP3
\arg AFIO_PB1_USBHS_CFG: configure PB1 alternate function to USBHS
\arg AFIO_PB1_SHRTIMER_CFG: configure PB1 alternate function to SHRTIMER
\arg AFIO_PB2_USBHS_CFG: configure PB2 alternate function to USBHS
\arg AFIO_PB2_SHRTIMER_CFG: configure PB2 alternate function to SHRTIMER
\arg AFIO_PB3_SHRTIMER_CFG: configure PB3 alternate function to SHRTIMER
\arg AFIO_PB4_I2S2_CFG: configure PB4 alternate function to I2S2
\arg AFIO_PB4_I2C2_CFG: configure PB4 alternate function to I2C2
\arg AFIO_PB4_SHRTIMER_CFG: configure PB4 alternate function to SHRTIMER
\arg AFIO_PB5_I2C2_CFG: configure PB5 alternate function to I2C2
\arg AFIO_PB5_USBHS_CFG: configure PB5 alternate function to USBHS
\arg AFIO_PB5_SHRTIMER_CFG: configure PB5 alternate function to SHRTIMER
\arg AFIO_PB6_SHRTIMER_CFG: configure PB6 alternate function to SHRTIMER
\arg AFIO_PB7_SHRTIMER_CFG: configure PB7 alternate function to SHRTIMER
\arg AFIO_PB8_I2C2_CFG: configure PB8 alternate function to I2C2
\arg AFIO_PB8_SHRTIMER_CFG: configure PB8 alternate function to SHRTIMER
\arg AFIO_PB9_CMP1_CFG: configure PB9 alternate function to CMP1
\arg AFIO_PB9_SHRTIMER_CFG: configure PB9 alternate function to SHRTIMER
\arg AFIO_PB10_CAN2_CFG: configure PB10 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PB10_USBHS_CFG: configure PB10 alternate function to USBHS
\arg AFIO_PB10_SHRTIMER_CFG: configure PB10 alternate function to SHRTIMER
\arg AFIO_PB11_CAN2_CFG: configure PB11 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PB11_USBHS_CFG: configure PB11 alternate function to USBHS
\arg AFIO_PB11_SHRTIMER_CFG: configure PB11 alternate function to SHRTIMER
\arg AFIO_PB12_USBHS_CFG: configure PB12 alternate function to USBHS
\arg AFIO_PB12_SHRTIMER_CFG: configure PB12 alternate function to SHRTIMER
\arg AFIO_PB13_USBHS_CFG: configure PB13 alternate function to USBHS
\arg AFIO_PB13_SHRTIMER_CFG: configure PB13 alternate function to SHRTIMER
\arg AFIO_PB14_I2S1_CFG: configure PB14 alternate function to I2S1
\arg AFIO_PB14_SHRTIMER_CFG: configure PB14 alternate function to SHRTIMER
\arg AFIO_PB15_SHRTIMER_CFG: configure PB15 alternate function to SHRTIMER
\arg AFIO_PC0_USBHS_CFG: configure PC0 alternate function to USBHS
\arg AFIO_PC2_I2S1_CFG: configure PC2 alternate function to I2S1
\arg AFIO_PC2_USBHS_CFG: configure PC2 alternate function to USBHS
\arg AFIO_PC3_USBHS_CFG: configure PC3 alternate function to USBHS
\arg AFIO_PC6_CMP5_CFG: configure PC6 alternate function to CMP5
\arg AFIO_PC6_USART5_CFG: configure PC6 alternate function to USART5
\arg AFIO_PC6_SHRTIMER_CFG: configure PC6 alternate function to SHRTIMER
\arg AFIO_PC7_USART5_CFG: configure PC7 alternate function to USART5
\arg AFIO_PC7_SHRTIMER_CFG: configure PC7 alternate function to SHRTIMER
\arg AFIO_PC8_USART5_CFG: configure PC8 alternate function to USART5
\arg AFIO_PC8_SHRTIMER_CFG: configure PC8 alternate function to SHRTIMER
\arg AFIO_PC9_I2C2_CFG: configure PC9 alternate function to I2C2
\arg AFIO_PC9_SHRTIMER_CFG: configure PC9 alternate function to SHRTIMER
\arg AFIO_PC10_I2C2_CFG: configure PC10 alternate function to I2C2
\arg AFIO_PC11_I2S2_CFG: configure PC11 alternate function to I2S2
\arg AFIO_PC11_SHRTIMER_CFG: configure PC11 alternate function to SHRTIMER
\arg AFIO_PC12_SHRTIMER_CFG: configure PC12 alternate function to SHRTIMER
\arg AFIO_PD4_SHRTIMER_CFG: configure PD4 alternate function to SHRTIMER
\arg AFIO_PD5_SHRTIMER_CFG: configure PD5 alternate function to SHRTIMER
\arg AFIO_PE0_CAN2_CFG: configure PE0 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PE0_SHRTIMER_CFG: configure PE0 alternate function to SHRTIMER
\arg AFIO_PE1_CAN2_CFG: configure PE1 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PE1_SHRTIMER_CFG: configure PE1 alternate function to SHRTIMER
\arg AFIO_PE8_CMP1_CFG: configure PE8 alternate function to CMP1
\arg AFIO_PE9_CMP3_CFG: configure PE9 alternate function to CMP3
\arg AFIO_PE10_CMP5_CFG: configure PE10 alternate function to CMP5
\arg AFIO_PE11_CMP5_CFG: configure PE11 alternate function to CMP5
\arg AFIO_PE12_CMP3_CFG: configure PE12 alternate function to CMP3
\arg AFIO_PE13_CMP1_CFG: configure PE13 alternate function to CMP1
\arg AFIO_PG6_SHRTIMER_CFG: configure PG6 alternate function to SHRTIMER
\arg AFIO_PG7_USART5_CFG: configure PG7 alternate function to USART5
\arg AFIO_PG7_SHRTIMER_CFG: configure PG7 alternate function to SHRTIMER
\arg AFIO_PG9_USART5_CFG: configure PG9 alternate function to USART5
\arg AFIO_PG10_SHRTIMER_CFG: configure PG10 alternate function to SHRTIMER
\arg AFIO_PG11_SHRTIMER_CFG: configure PG11 alternate function to SHRTIMER
\arg AFIO_PG12_SHRTIMER_CFG: configure PG12 alternate function to SHRTIMER
\arg AFIO_PG13_SHRTIMER_CFG: configure PG13 alternate function to SHRTIMER
\arg AFIO_PG14_USART5_CFG: configure PG14 alternate function to USART5
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void gpio_afio_port_config(uint32_t afio_function, ControlStatus newvalue)
{
uint32_t remap1 = 0U, remap2 = 0U, temp_reg = 0U, temp_mask = 0U;
/* get AFIO_PCFx(x=A,B,C,D,E,G) regiter value */
temp_reg = REG32(AFIO+0x0000003CU+((afio_function>>24)<<2));
temp_mask = (afio_function & PCF_POSITION_MASK) >> 0x10U;
remap1 = afio_function & LSB_16BIT_MASK;
/* judge port function select type */
if(afio_function & PCF_LOCATION2_MASK){
remap2 = ((uint32_t)0x03U) << temp_mask;
remap2 = (remap2 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
temp_reg &= ~remap2;
}else{
temp_reg &= ~(remap1 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
}
/* set pin remap value */
if(DISABLE != newvalue){
temp_reg |= (remap1 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
}
/* set AFIO_PCFx(x=A,B,C,D,E,G) regiter value */
REG32(AFIO+0x0000003CU+((afio_function>>24)<<2)) = temp_reg;
}
#if (defined(GD32E50X_CL) || defined(GD32E508) || defined(GD32EPRT))
/*!
\brief select ethernet MII or RMII PHY
\param[in] enet_sel: ethernet MII or RMII PHY selection
\arg GPIO_ENET_PHY_MII: configure ethernet MAC for connection with an MII PHY
\arg GPIO_ENET_PHY_RMII: configure ethernet MAC for connection with an RMII PHY
\param[out] none
\retval none
*/
void gpio_ethernet_phy_select(uint32_t enet_sel)
{
/* clear AFIO_PCF0_ENET_PHY_SEL bit */
AFIO_PCF0 &= (uint32_t)(~AFIO_PCF0_ENET_PHY_SEL);
/* select MII or RMII PHY */
AFIO_PCF0 |= (uint32_t)enet_sel;
}
#endif /* GD32E50X_CL||GD32E508||GD32EPRT */
/*!
\brief select GPIO pin exti sources
\param[in] output_port: gpio event output port
only one parameter can be selected which are shown as below:
\arg GPIO_PORT_SOURCE_GPIOA: output port source A
\arg GPIO_PORT_SOURCE_GPIOB: output port source B
\arg GPIO_PORT_SOURCE_GPIOC: output port source C
\arg GPIO_PORT_SOURCE_GPIOD: output port source D
\arg GPIO_PORT_SOURCE_GPIOE: output port source E
\arg GPIO_PORT_SOURCE_GPIOF: output port source F
\arg GPIO_PORT_SOURCE_GPIOG: output port source G
\param[in] output_pin: GPIO output pin source
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_SOURCE_x(x=0..15)
\param[out] none
\retval none
*/
void gpio_exti_source_select(uint8_t output_port, uint8_t output_pin)
{
uint32_t source = 0U;
source = ((uint32_t)0x0FU) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK));
/* select EXTI sources */
if(GPIO_PIN_SOURCE_4 > output_pin){
/* select EXTI0/EXTI1/EXTI2/EXTI3 */
AFIO_EXTISS0 &= ~source;
AFIO_EXTISS0 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else if(GPIO_PIN_SOURCE_8 > output_pin){
/* select EXTI4/EXTI5/EXTI6/EXTI7 */
AFIO_EXTISS1 &= ~source;
AFIO_EXTISS1 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else if(GPIO_PIN_SOURCE_12 > output_pin){
/* select EXTI8/EXTI9/EXTI10/EXTI11 */
AFIO_EXTISS2 &= ~source;
AFIO_EXTISS2 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else{
/* select EXTI12/EXTI13/EXTI14/EXTI15 */
AFIO_EXTISS3 &= ~source;
AFIO_EXTISS3 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}
}
/*!
\brief configure GPIO pin event output
\param[in] output_port: gpio event output port
only one parameter can be selected which are shown as below:
\arg GPIO_EVENT_PORT_GPIOA: event output port A
\arg GPIO_EVENT_PORT_GPIOB: event output port B
\arg GPIO_EVENT_PORT_GPIOC: event output port C
\arg GPIO_EVENT_PORT_GPIOD: event output port D
\arg GPIO_EVENT_PORT_GPIOE: event output port E
\param[in] output_pin: GPIO event output pin
only one parameter can be selected which are shown as below:
\arg GPIO_EVENT_PIN_x(x=0..15)
\param[out] none
\retval none
*/
void gpio_event_output_config(uint8_t output_port, uint8_t output_pin)
{
uint32_t reg = 0U;
reg = AFIO_EC;
/* clear AFIO_EC_PORT and AFIO_EC_PIN bits */
reg &= (uint32_t)(~(AFIO_EC_PORT|AFIO_EC_PIN));
reg |= (uint32_t)((uint32_t)output_port << GPIO_OUTPUT_PORT_OFFSET);
reg |= (uint32_t)output_pin;
AFIO_EC = reg;
}
/*!
\brief enable GPIO pin event output
\param[in] none
\param[out] none
\retval none
*/
void gpio_event_output_enable(void)
{
AFIO_EC |= AFIO_EC_EOE;
}
/*!
\brief disable GPIO pin event output
\param[in] none
\param[out] none
\retval none
*/
void gpio_event_output_disable(void)
{
AFIO_EC &= (uint32_t)(~AFIO_EC_EOE);
}
/*!
\brief lock GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_pin_lock(uint32_t gpio_periph,uint32_t pin)
{
uint32_t lock = 0x00010000U;
lock |= pin;
/* lock key writing sequence: write 1 -> write 0 -> write 1 -> read 0 -> read 1 */
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
GPIO_LOCK(gpio_periph) = (uint32_t)pin;
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
lock = GPIO_LOCK(gpio_periph);
lock = GPIO_LOCK(gpio_periph);
}
/*!
\brief configure the I/O compensation cell
\param[in] compensation: specifies the I/O compensation cell mode
only one parameter can be selected which are shown as below:
\arg GPIO_COMPENSATION_ENABLE: I/O compensation cell is enabled
\arg GPIO_COMPENSATION_DISABLE: I/O compensation cell is disabled
\param[out] none
\retval none
*/
void gpio_compensation_config(uint32_t compensation)
{
uint32_t reg;
reg = AFIO_CPSCTL;
/* reset the AFIO_CPSCTL_CPS_EN bit and set according to gpio_compensation */
reg &= ~AFIO_CPSCTL_CPS_EN;
AFIO_CPSCTL = (reg | compensation);
}
/*!
\brief check the I/O compensation cell is ready or not
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus gpio_compensation_flag_get(void)
{
if(((uint32_t)RESET) != (AFIO_CPSCTL & AFIO_CPSCTL_CPS_RDY)){
return SET;
}else{
return RESET;
}
}
@@ -0,0 +1,699 @@
/*!
\file gd32e50x_gpio.c
\brief GPIO driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_gpio.h"
#define AFIO_EXTI_SOURCE_MASK ((uint8_t)0x03U) /*!< AFIO exti source selection mask*/
#define AFIO_EXTI_SOURCE_FIELDS ((uint8_t)0x04U) /*!< select AFIO exti source registers */
#define LSB_16BIT_MASK ((uint16_t)0xFFFFU) /*!< LSB 16-bit mask */
#define PCF_POSITION_MASK ((uint32_t)0x000F0000U) /*!< AFIO_PCF register position mask */
#define PCF_SWJCFG_MASK ((uint32_t)0xF8FFFFFFU) /*!< AFIO_PCF register SWJCFG mask */
#define PCF_LOCATION1_MASK ((uint32_t)0x00200000U) /*!< AFIO_PCF register location1 mask */
#define PCF_LOCATION2_MASK ((uint32_t)0x00100000U) /*!< AFIO_PCF register location2 mask */
#define AFIO_PCF1_FIELDS ((uint32_t)0x80000000U) /*!< select AFIO_PCF1 register */
#define GPIO_OUTPUT_PORT_OFFSET ((uint32_t)4U) /*!< GPIO event output port offset*/
/*!
\brief reset GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval none
*/
void gpio_deinit(uint32_t gpio_periph)
{
switch(gpio_periph){
case GPIOA:
/* reset GPIOA */
rcu_periph_reset_enable(RCU_GPIOARST);
rcu_periph_reset_disable(RCU_GPIOARST);
break;
case GPIOB:
/* reset GPIOB */
rcu_periph_reset_enable(RCU_GPIOBRST);
rcu_periph_reset_disable(RCU_GPIOBRST);
break;
case GPIOC:
/* reset GPIOC */
rcu_periph_reset_enable(RCU_GPIOCRST);
rcu_periph_reset_disable(RCU_GPIOCRST);
break;
case GPIOD:
/* reset GPIOD */
rcu_periph_reset_enable(RCU_GPIODRST);
rcu_periph_reset_disable(RCU_GPIODRST);
break;
case GPIOE:
/* reset GPIOE */
rcu_periph_reset_enable(RCU_GPIOERST);
rcu_periph_reset_disable(RCU_GPIOERST);
break;
case GPIOF:
/* reset GPIOF */
rcu_periph_reset_enable(RCU_GPIOFRST);
rcu_periph_reset_disable(RCU_GPIOFRST);
break;
case GPIOG:
/* reset GPIOG */
rcu_periph_reset_enable(RCU_GPIOGRST);
rcu_periph_reset_disable(RCU_GPIOGRST);
break;
default:
break;
}
}
/*!
\brief reset alternate function I/O(AFIO)
\param[in] none
\param[out] none
\retval none
*/
void gpio_afio_deinit(void)
{
rcu_periph_reset_enable(RCU_AFRST);
rcu_periph_reset_disable(RCU_AFRST);
}
/*!
\brief GPIO parameter initialization
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] mode: gpio pin mode
only one parameter can be selected which is shown as below:
\arg GPIO_MODE_AIN: analog input mode
\arg GPIO_MODE_IN_FLOATING: floating input mode
\arg GPIO_MODE_IPD: pull-down input mode
\arg GPIO_MODE_IPU: pull-up input mode
\arg GPIO_MODE_OUT_OD: GPIO output with open-drain
\arg GPIO_MODE_OUT_PP: GPIO output with push-pull
\arg GPIO_MODE_AF_OD: AFIO output with open-drain
\arg GPIO_MODE_AF_PP: AFIO output with push-pull
\param[in] speed: gpio output max speed value
only one parameter can be selected which is shown as below:
\arg GPIO_OSPEED_10MHZ: output max speed 10MHz
\arg GPIO_OSPEED_2MHZ: output max speed 2MHz
\arg GPIO_OSPEED_50MHZ: output max speed 50MHz
\arg GPIO_OSPEED_MAX: output max speed more than 50MHz
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_init(uint32_t gpio_periph, uint32_t mode, uint32_t speed, uint32_t pin)
{
uint16_t i;
uint32_t temp_mode = 0U;
uint32_t reg = 0U;
/* GPIO mode configuration */
temp_mode = (uint32_t)(mode & ((uint32_t)0x0FU));
/* GPIO speed configuration */
if(((uint32_t)0x00U) != ((uint32_t)mode & ((uint32_t)0x10U))){
/* output mode max speed */
if(GPIO_OSPEED_MAX == (uint32_t)speed){
temp_mode |= (uint32_t)0x03U;
/* set the corresponding SPD bit */
GPIOx_SPD(gpio_periph) |= (uint32_t)pin ;
}else{
/* output mode max speed:10MHz,2MHz,50MHz */
temp_mode |= (uint32_t)speed;
}
}
/* configure the eight low port pins with GPIO_CTL0 */
for(i = 0U;i < 8U;i++){
if((1U << i) & pin){
reg = GPIO_CTL0(gpio_periph);
/* clear the specified pin mode bits */
reg &= ~GPIO_MODE_MASK(i);
/* set the specified pin mode bits */
reg |= GPIO_MODE_SET(i, temp_mode);
/* set IPD or IPU */
if(GPIO_MODE_IPD == mode){
/* reset the corresponding OCTL bit */
GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin);
}else{
/* set the corresponding OCTL bit */
if(GPIO_MODE_IPU == mode){
GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin);
}
}
/* set GPIO_CTL0 register */
GPIO_CTL0(gpio_periph) = reg;
}
}
/* configure the eight high port pins with GPIO_CTL1 */
for(i = 8U;i < 16U;i++){
if((1U << i) & pin){
reg = GPIO_CTL1(gpio_periph);
/* clear the specified pin mode bits */
reg &= ~GPIO_MODE_MASK(i - 8U);
/* set the specified pin mode bits */
reg |= GPIO_MODE_SET(i - 8U, temp_mode);
/* set IPD or IPU */
if(GPIO_MODE_IPD == mode){
/* reset the corresponding OCTL bit */
GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin);
}else{
/* set the corresponding OCTL bit */
if(GPIO_MODE_IPU == mode){
GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin);
}
}
/* set GPIO_CTL1 register */
GPIO_CTL1(gpio_periph) = reg;
}
}
}
/*!
\brief set GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_set(uint32_t gpio_periph,uint32_t pin)
{
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}
/*!
\brief reset GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_reset(uint32_t gpio_periph,uint32_t pin)
{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
/*!
\brief write data to the specified GPIO pin
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[in] bit_value: SET or RESET
\arg RESET: clear the port pin
\arg SET: set the port pin
\param[out] none
\retval none
*/
void gpio_bit_write(uint32_t gpio_periph,uint32_t pin,bit_status bit_value)
{
if(RESET != bit_value){
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}else{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
}
/*!
\brief write data to the specified GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] data: specify the value to be written to the port output data register
\param[out] none
\retval none
*/
void gpio_port_write(uint32_t gpio_periph,uint16_t data)
{
GPIO_OCTL(gpio_periph) = (uint32_t)data;
}
/*!
\brief get GPIO pin input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval input status of gpio pin: SET or RESET
*/
FlagStatus gpio_input_bit_get(uint32_t gpio_periph,uint32_t pin)
{
if((uint32_t)RESET != (GPIO_ISTAT(gpio_periph)&(pin))){
return SET;
}else{
return RESET;
}
}
/*!
\brief get GPIO port input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval input status of gpio all pins
*/
uint16_t gpio_input_port_get(uint32_t gpio_periph)
{
return (uint16_t)(GPIO_ISTAT(gpio_periph));
}
/*!
\brief get GPIO pin output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval output status of gpio pin: SET or RESET
*/
FlagStatus gpio_output_bit_get(uint32_t gpio_periph,uint32_t pin)
{
if((uint32_t)RESET !=(GPIO_OCTL(gpio_periph)&(pin))){
return SET;
}else{
return RESET;
}
}
/*!
\brief get GPIO port output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval output status of gpio all pins
*/
uint16_t gpio_output_port_get(uint32_t gpio_periph)
{
return ((uint16_t)GPIO_OCTL(gpio_periph));
}
/*!
\brief configure GPIO pin remap
\param[in] gpio_remap: select the pin to remap
only one parameter can be selected which are shown as below:
\arg GPIO_SPI0_REMAP: SPI0 remapping
\arg GPIO_I2C0_REMAP: I2C0 remapping
\arg GPIO_USART0_REMAP: USART0 remapping
\arg GPIO_USART1_REMAP: USART1 remapping
\arg GPIO_USART2_PARTIAL_REMAP: USART2 partial remapping
\arg GPIO_USART2_FULL_REMAP: USART2 full remapping
\arg GPIO_TIMER0_PARTIAL_REMAP: TIMER0 partial remapping
\arg GPIO_TIMER0_FULL_REMAP: TIMER0 full remapping
\arg GPIO_TIMER1_PARTIAL_REMAP0: TIMER1 partial remapping
\arg GPIO_TIMER1_PARTIAL_REMAP1: TIMER1 partial remapping
\arg GPIO_TIMER1_FULL_REMAP: TIMER1 full remapping
\arg GPIO_TIMER2_PARTIAL_REMAP: TIMER2 partial remapping
\arg GPIO_TIMER2_FULL_REMAP: TIMER2 full remapping
\arg GPIO_TIMER3_REMAP: TIMER3 remapping
\arg GPIO_CAN0_PARTIAL_REMAP: CAN0 partial remapping(not support on GD32EPRT devices)
\arg GPIO_CAN0_FULL_REMAP: CAN0 full remapping(not support on GD32EPRT devices)
\arg GPIO_PD01_REMAP: PD01 remapping
\arg GPIO_TIMER4CH3_IREMAP: TIMER4 channel3 internal remapping
\arg GPIO_ADC0_ETRGRT_REMAP: ADC0 external trigger routine conversion remapping(only for GD32E50X_HD devices)
\arg GPIO_ADC1_ETRGRT_REMAP: ADC1 external trigger routine conversion remapping(only for GD32E50X_HD devices)
\arg GPIO_ENET_REMAP: ENET remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_CAN1_REMAP: CAN1 remapping(not support on GD32EPRT devices)
\arg GPIO_SWJ_NONJTRST_REMAP: full SWJ(JTAG-DP + SW-DP),but without NJTRST
\arg GPIO_SWJ_SWDPENABLE_REMAP: JTAG-DP disabled and SW-DP enabled
\arg GPIO_SWJ_DISABLE_REMAP: JTAG-DP disabled and SW-DP disabled
\arg GPIO_SPI2_REMAP: SPI2 remapping
\arg GPIO_TIMER1ITR1_REMAP: TIMER1 internal trigger 1 remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_PTP_PPS_REMAP: ethernet PTP PPS remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_TIMER8_REMAP: TIMER8 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER9_REMAP: TIMER9 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER10_REMAP: TIMER10 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER12_REMAP: TIMER12 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER13_REMAP: TIMER13 remapping(not support on GD32EPRT devices)
\arg GPIO_EXMC_NADV_REMAP: EXMC_NADV connect/disconnect
\arg GPIO_CTC_REMAP0: CTC remapping(PD15)
\arg GPIO_CTC_REMAP1: CTC remapping(PF0)
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void gpio_pin_remap_config(uint32_t remap, ControlStatus newvalue)
{
uint32_t remap1 = 0U, remap2 = 0U, temp_reg = 0U, temp_mask = 0U;
if(((uint32_t)0x80000000U) == (remap & 0x80000000U)){
/* get AFIO_PCF1 regiter value */
temp_reg = AFIO_PCF1;
}else{
/* get AFIO_PCF0 regiter value */
temp_reg = AFIO_PCF0;
}
temp_mask = (remap & PCF_POSITION_MASK) >> 0x10U;
remap1 = remap & LSB_16BIT_MASK;
/* judge pin remap type */
if((PCF_LOCATION1_MASK | PCF_LOCATION2_MASK) == (remap & (PCF_LOCATION1_MASK | PCF_LOCATION2_MASK))){
temp_reg &= PCF_SWJCFG_MASK;
AFIO_PCF0 &= PCF_SWJCFG_MASK;
}else if(PCF_LOCATION2_MASK == (remap & PCF_LOCATION2_MASK)){
remap2 = ((uint32_t)0x03U) << temp_mask;
temp_reg &= ~remap2;
temp_reg |= ~PCF_SWJCFG_MASK;
}else{
temp_reg &= ~(remap1 << ((remap >> 0x15U)*0x10U));
temp_reg |= ~PCF_SWJCFG_MASK;
}
/* set pin remap value */
if(DISABLE != newvalue){
temp_reg |= (remap1 << ((remap >> 0x15U)*0x10U));
}
if(AFIO_PCF1_FIELDS == (remap & AFIO_PCF1_FIELDS)){
/* set AFIO_PCF1 regiter value */
AFIO_PCF1 = temp_reg;
}else{
/* set AFIO_PCF0 regiter value */
AFIO_PCF0 = temp_reg;
}
}
/*!
\brief configure AFIO port alternate function
\param[in] afio_function: select the port AFIO function(SHRTIMER not support on GD32EPRT devices)
only one parameter can be selected which are shown as below:
\arg AFIO_PA2_CMP1_CFG: configure PA2 alternate function to CMP1
\arg AFIO_PA3_USBHS_CFG: configure PA3 alternate function to USBHS
\arg AFIO_PA5_USBHS_CFG: configure PA5 alternate function to USBHS
\arg AFIO_PA8_I2C2_CFG: configure PA8 alternate function to I2C2
\arg AFIO_PA8_SHRTIMER_CFG: configure PA8 alternate function to SHRTIMER
\arg AFIO_PA9_CAN2_CFG: configure PA9 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PA9_I2C2_CFG: configure PA9 alternate function to I2C2
\arg AFIO_PA9_SHRTIMER_CFG: configure PA9 alternate function to SHRTIMER
\arg AFIO_PA10_CAN2_CFG: configure PA10 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PA10_CMP5_CFG: configure PA10 alternate function to CMP5
\arg AFIO_PA10_SHRTIMER_CFG: configure PA10 alternate function to SHRTIMER
\arg AFIO_PA11_USART5_CFG: configure PA11 alternate function to USART5
\arg AFIO_PA11_SHRTIMER_CFG: configure PA11 alternate function to SHRTIMER
\arg AFIO_PA12_CMP1_CFG: configure PA12 alternate function to CMP1
\arg AFIO_PA12_USART5_CFG: configure PA12 alternate function to USART5
\arg AFIO_PA12_SHRTIMER_CFG: configure PA12 alternate function to SHRTIMER
\arg AFIO_PA15_SHRTIMER_CFG: configure PA15 alternate function to SHRTIMER
\arg AFIO_PB0_USBHS_CFG: configure PB0 alternate function to USBHS
\arg AFIO_PB1_CMP3_CFG: configure PB1 alternate function to CMP3
\arg AFIO_PB1_USBHS_CFG: configure PB1 alternate function to USBHS
\arg AFIO_PB1_SHRTIMER_CFG: configure PB1 alternate function to SHRTIMER
\arg AFIO_PB2_USBHS_CFG: configure PB2 alternate function to USBHS
\arg AFIO_PB2_SHRTIMER_CFG: configure PB2 alternate function to SHRTIMER
\arg AFIO_PB3_SHRTIMER_CFG: configure PB3 alternate function to SHRTIMER
\arg AFIO_PB4_I2S2_CFG: configure PB4 alternate function to I2S2
\arg AFIO_PB4_I2C2_CFG: configure PB4 alternate function to I2C2
\arg AFIO_PB4_SHRTIMER_CFG: configure PB4 alternate function to SHRTIMER
\arg AFIO_PB5_I2C2_CFG: configure PB5 alternate function to I2C2
\arg AFIO_PB5_USBHS_CFG: configure PB5 alternate function to USBHS
\arg AFIO_PB5_SHRTIMER_CFG: configure PB5 alternate function to SHRTIMER
\arg AFIO_PB6_SHRTIMER_CFG: configure PB6 alternate function to SHRTIMER
\arg AFIO_PB7_SHRTIMER_CFG: configure PB7 alternate function to SHRTIMER
\arg AFIO_PB8_I2C2_CFG: configure PB8 alternate function to I2C2
\arg AFIO_PB8_SHRTIMER_CFG: configure PB8 alternate function to SHRTIMER
\arg AFIO_PB9_CMP1_CFG: configure PB9 alternate function to CMP1
\arg AFIO_PB9_SHRTIMER_CFG: configure PB9 alternate function to SHRTIMER
\arg AFIO_PB10_CAN2_CFG: configure PB10 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PB10_USBHS_CFG: configure PB10 alternate function to USBHS
\arg AFIO_PB10_SHRTIMER_CFG: configure PB10 alternate function to SHRTIMER
\arg AFIO_PB11_CAN2_CFG: configure PB11 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PB11_USBHS_CFG: configure PB11 alternate function to USBHS
\arg AFIO_PB11_SHRTIMER_CFG: configure PB11 alternate function to SHRTIMER
\arg AFIO_PB12_USBHS_CFG: configure PB12 alternate function to USBHS
\arg AFIO_PB12_SHRTIMER_CFG: configure PB12 alternate function to SHRTIMER
\arg AFIO_PB13_USBHS_CFG: configure PB13 alternate function to USBHS
\arg AFIO_PB13_SHRTIMER_CFG: configure PB13 alternate function to SHRTIMER
\arg AFIO_PB14_I2S1_CFG: configure PB14 alternate function to I2S1
\arg AFIO_PB14_SHRTIMER_CFG: configure PB14 alternate function to SHRTIMER
\arg AFIO_PB15_SHRTIMER_CFG: configure PB15 alternate function to SHRTIMER
\arg AFIO_PC0_USBHS_CFG: configure PC0 alternate function to USBHS
\arg AFIO_PC2_I2S1_CFG: configure PC2 alternate function to I2S1
\arg AFIO_PC2_USBHS_CFG: configure PC2 alternate function to USBHS
\arg AFIO_PC3_USBHS_CFG: configure PC3 alternate function to USBHS
\arg AFIO_PC6_CMP5_CFG: configure PC6 alternate function to CMP5
\arg AFIO_PC6_USART5_CFG: configure PC6 alternate function to USART5
\arg AFIO_PC6_SHRTIMER_CFG: configure PC6 alternate function to SHRTIMER
\arg AFIO_PC7_USART5_CFG: configure PC7 alternate function to USART5
\arg AFIO_PC7_SHRTIMER_CFG: configure PC7 alternate function to SHRTIMER
\arg AFIO_PC8_USART5_CFG: configure PC8 alternate function to USART5
\arg AFIO_PC8_SHRTIMER_CFG: configure PC8 alternate function to SHRTIMER
\arg AFIO_PC9_I2C2_CFG: configure PC9 alternate function to I2C2
\arg AFIO_PC9_SHRTIMER_CFG: configure PC9 alternate function to SHRTIMER
\arg AFIO_PC10_I2C2_CFG: configure PC10 alternate function to I2C2
\arg AFIO_PC11_I2S2_CFG: configure PC11 alternate function to I2S2
\arg AFIO_PC11_SHRTIMER_CFG: configure PC11 alternate function to SHRTIMER
\arg AFIO_PC12_SHRTIMER_CFG: configure PC12 alternate function to SHRTIMER
\arg AFIO_PD4_SHRTIMER_CFG: configure PD4 alternate function to SHRTIMER
\arg AFIO_PD5_SHRTIMER_CFG: configure PD5 alternate function to SHRTIMER
\arg AFIO_PE0_CAN2_CFG: configure PE0 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PE0_SHRTIMER_CFG: configure PE0 alternate function to SHRTIMER
\arg AFIO_PE1_CAN2_CFG: configure PE1 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PE1_SHRTIMER_CFG: configure PE1 alternate function to SHRTIMER
\arg AFIO_PE8_CMP1_CFG: configure PE8 alternate function to CMP1
\arg AFIO_PE9_CMP3_CFG: configure PE9 alternate function to CMP3
\arg AFIO_PE10_CMP5_CFG: configure PE10 alternate function to CMP5
\arg AFIO_PE11_CMP5_CFG: configure PE11 alternate function to CMP5
\arg AFIO_PE12_CMP3_CFG: configure PE12 alternate function to CMP3
\arg AFIO_PE13_CMP1_CFG: configure PE13 alternate function to CMP1
\arg AFIO_PG6_SHRTIMER_CFG: configure PG6 alternate function to SHRTIMER
\arg AFIO_PG7_USART5_CFG: configure PG7 alternate function to USART5
\arg AFIO_PG7_SHRTIMER_CFG: configure PG7 alternate function to SHRTIMER
\arg AFIO_PG9_USART5_CFG: configure PG9 alternate function to USART5
\arg AFIO_PG10_SHRTIMER_CFG: configure PG10 alternate function to SHRTIMER
\arg AFIO_PG11_SHRTIMER_CFG: configure PG11 alternate function to SHRTIMER
\arg AFIO_PG12_SHRTIMER_CFG: configure PG12 alternate function to SHRTIMER
\arg AFIO_PG13_SHRTIMER_CFG: configure PG13 alternate function to SHRTIMER
\arg AFIO_PG14_USART5_CFG: configure PG14 alternate function to USART5
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void gpio_afio_port_config(uint32_t afio_function, ControlStatus newvalue)
{
uint32_t remap1 = 0U, remap2 = 0U, temp_reg = 0U, temp_mask = 0U;
/* get AFIO_PCFx(x=A,B,C,D,E,G) regiter value */
temp_reg = REG32(AFIO+0x0000003CU+((afio_function>>24)<<2));
temp_mask = (afio_function & PCF_POSITION_MASK) >> 0x10U;
remap1 = afio_function & LSB_16BIT_MASK;
/* judge port function select type */
if(afio_function & PCF_LOCATION2_MASK){
remap2 = ((uint32_t)0x03U) << temp_mask;
remap2 = (remap2 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
temp_reg &= ~remap2;
}else{
temp_reg &= ~(remap1 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
}
/* set pin remap value */
if(DISABLE != newvalue){
temp_reg |= (remap1 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
}
/* set AFIO_PCFx(x=A,B,C,D,E,G) regiter value */
REG32(AFIO+0x0000003CU+((afio_function>>24)<<2)) = temp_reg;
}
#if (defined(GD32E50X_CL) || defined(GD32E508) || defined(GD32EPRT))
/*!
\brief select ethernet MII or RMII PHY
\param[in] enet_sel: ethernet MII or RMII PHY selection
\arg GPIO_ENET_PHY_MII: configure ethernet MAC for connection with an MII PHY
\arg GPIO_ENET_PHY_RMII: configure ethernet MAC for connection with an RMII PHY
\param[out] none
\retval none
*/
void gpio_ethernet_phy_select(uint32_t enet_sel)
{
/* clear AFIO_PCF0_ENET_PHY_SEL bit */
AFIO_PCF0 &= (uint32_t)(~AFIO_PCF0_ENET_PHY_SEL);
/* select MII or RMII PHY */
AFIO_PCF0 |= (uint32_t)enet_sel;
}
#endif /* GD32E50X_CL||GD32E508||GD32EPRT */
/*!
\brief select GPIO pin exti sources
\param[in] output_port: gpio event output port
only one parameter can be selected which are shown as below:
\arg GPIO_PORT_SOURCE_GPIOA: output port source A
\arg GPIO_PORT_SOURCE_GPIOB: output port source B
\arg GPIO_PORT_SOURCE_GPIOC: output port source C
\arg GPIO_PORT_SOURCE_GPIOD: output port source D
\arg GPIO_PORT_SOURCE_GPIOE: output port source E
\arg GPIO_PORT_SOURCE_GPIOF: output port source F
\arg GPIO_PORT_SOURCE_GPIOG: output port source G
\param[in] output_pin: GPIO output pin source
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_SOURCE_x(x=0..15)
\param[out] none
\retval none
*/
void gpio_exti_source_select(uint8_t output_port, uint8_t output_pin)
{
uint32_t source = 0U;
source = ((uint32_t)0x0FU) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK));
/* select EXTI sources */
if(GPIO_PIN_SOURCE_4 > output_pin){
/* select EXTI0/EXTI1/EXTI2/EXTI3 */
AFIO_EXTISS0 &= ~source;
AFIO_EXTISS0 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else if(GPIO_PIN_SOURCE_8 > output_pin){
/* select EXTI4/EXTI5/EXTI6/EXTI7 */
AFIO_EXTISS1 &= ~source;
AFIO_EXTISS1 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else if(GPIO_PIN_SOURCE_12 > output_pin){
/* select EXTI8/EXTI9/EXTI10/EXTI11 */
AFIO_EXTISS2 &= ~source;
AFIO_EXTISS2 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else{
/* select EXTI12/EXTI13/EXTI14/EXTI15 */
AFIO_EXTISS3 &= ~source;
AFIO_EXTISS3 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}
}
/*!
\brief configure GPIO pin event output
\param[in] output_port: gpio event output port
only one parameter can be selected which are shown as below:
\arg GPIO_EVENT_PORT_GPIOA: event output port A
\arg GPIO_EVENT_PORT_GPIOB: event output port B
\arg GPIO_EVENT_PORT_GPIOC: event output port C
\arg GPIO_EVENT_PORT_GPIOD: event output port D
\arg GPIO_EVENT_PORT_GPIOE: event output port E
\param[in] output_pin: GPIO event output pin
only one parameter can be selected which are shown as below:
\arg GPIO_EVENT_PIN_x(x=0..15)
\param[out] none
\retval none
*/
void gpio_event_output_config(uint8_t output_port, uint8_t output_pin)
{
uint32_t reg = 0U;
reg = AFIO_EC;
/* clear AFIO_EC_PORT and AFIO_EC_PIN bits */
reg &= (uint32_t)(~(AFIO_EC_PORT|AFIO_EC_PIN));
reg |= (uint32_t)((uint32_t)output_port << GPIO_OUTPUT_PORT_OFFSET);
reg |= (uint32_t)output_pin;
AFIO_EC = reg;
}
/*!
\brief enable GPIO pin event output
\param[in] none
\param[out] none
\retval none
*/
void gpio_event_output_enable(void)
{
AFIO_EC |= AFIO_EC_EOE;
}
/*!
\brief disable GPIO pin event output
\param[in] none
\param[out] none
\retval none
*/
void gpio_event_output_disable(void)
{
AFIO_EC &= (uint32_t)(~AFIO_EC_EOE);
}
/*!
\brief lock GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_pin_lock(uint32_t gpio_periph,uint32_t pin)
{
uint32_t lock = 0x00010000U;
lock |= pin;
/* lock key writing sequence: write 1 -> write 0 -> write 1 -> read 0 -> read 1 */
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
GPIO_LOCK(gpio_periph) = (uint32_t)pin;
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
lock = GPIO_LOCK(gpio_periph);
lock = GPIO_LOCK(gpio_periph);
}
/*!
\brief configure the I/O compensation cell
\param[in] compensation: specifies the I/O compensation cell mode
only one parameter can be selected which are shown as below:
\arg GPIO_COMPENSATION_ENABLE: I/O compensation cell is enabled
\arg GPIO_COMPENSATION_DISABLE: I/O compensation cell is disabled
\param[out] none
\retval none
*/
void gpio_compensation_config(uint32_t compensation)
{
uint32_t reg;
reg = AFIO_CPSCTL;
/* reset the AFIO_CPSCTL_CPS_EN bit and set according to gpio_compensation */
reg &= ~AFIO_CPSCTL_CPS_EN;
AFIO_CPSCTL = (reg | compensation);
}
/*!
\brief check the I/O compensation cell is ready or not
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus gpio_compensation_flag_get(void)
{
if(((uint32_t)RESET) != (AFIO_CPSCTL & AFIO_CPSCTL_CPS_RDY)){
return SET;
}else{
return RESET;
}
}
@@ -0,0 +1,180 @@
/*!
\file gd32e50x_misc.c
\brief MISC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_misc.h"
/*!
\brief set the priority group
\param[in] nvic_prigroup: the NVIC priority group
\arg NVIC_PRIGROUP_PRE0_SUB4:0 bits for pre-emption priority 4 bits for subpriority
\arg NVIC_PRIGROUP_PRE1_SUB3:1 bits for pre-emption priority 3 bits for subpriority
\arg NVIC_PRIGROUP_PRE2_SUB2:2 bits for pre-emption priority 2 bits for subpriority
\arg NVIC_PRIGROUP_PRE3_SUB1:3 bits for pre-emption priority 1 bits for subpriority
\arg NVIC_PRIGROUP_PRE4_SUB0:4 bits for pre-emption priority 0 bits for subpriority
\param[out] none
\retval none
*/
void nvic_priority_group_set(uint32_t nvic_prigroup)
{
/* set the priority group value */
SCB->AIRCR = NVIC_AIRCR_VECTKEY_MASK | nvic_prigroup;
}
/*!
\brief enable NVIC request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[in] nvic_irq_pre_priority: the pre-emption priority needed to set
\param[in] nvic_irq_sub_priority: the subpriority needed to set
\param[out] none
\retval none
*/
void nvic_irq_enable(IRQn_Type nvic_irq, uint8_t nvic_irq_pre_priority,
uint8_t nvic_irq_sub_priority)
{
uint32_t nvic_prigroup, nvic_priority;
/* check current priority group */
switch(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) {
case NVIC_PRIGROUP_PRE0_SUB4:
case NVIC_PRIGROUP_PRE1_SUB3:
case NVIC_PRIGROUP_PRE2_SUB2:
case NVIC_PRIGROUP_PRE3_SUB1:
case NVIC_PRIGROUP_PRE4_SUB0:
break;
default:
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
break;
}
/* get the priority group value */
nvic_prigroup = NVIC_GetPriorityGrouping();
/* encoding the pre-emption, subpriority priority */
nvic_priority = NVIC_EncodePriority(nvic_prigroup, (uint32_t)nvic_irq_pre_priority, (uint32_t)nvic_irq_sub_priority);
/* set priority */
NVIC_SetPriority(nvic_irq, nvic_priority);
/* enable the selected IRQ */
NVIC_EnableIRQ(nvic_irq);
}
/*!
\brief disable NVIC request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[out] none
\retval none
*/
void nvic_irq_disable(IRQn_Type nvic_irq)
{
/* disable the selected IRQ.*/
NVIC_DisableIRQ((IRQn_Type)nvic_irq);
}
/*!
\brief initiates a system reset request to reset the MCU
\param[in] none
\param[out] none
\retval none
*/
void nvic_system_reset(void)
{
NVIC_SystemReset();
}
/*!
\brief set the NVIC vector table base address
\param[in] nvic_vict_tab: the RAM or FLASH base address
\arg NVIC_VECTTAB_RAM: RAM base address
\are NVIC_VECTTAB_FLASH: Flash base address
\param[in] offset: Vector Table offset
\param[out] none
\retval none
*/
void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
{
SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
__DSB();
}
/*!
\brief set the state of the low power mode
\param[in] lowpower_mode: the low power mode state
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system always enter low power
mode by exiting from ISR
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the DEEPSLEEP mode
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode can be woke up
by all the enable and disable interrupts
\param[out] none
\retval none
*/
void system_lowpower_set(uint8_t lowpower_mode)
{
SCB->SCR |= (uint32_t)lowpower_mode;
}
/*!
\brief reset the state of the low power mode
\param[in] lowpower_mode: the low power mode state
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system will exit low power
mode by exiting from ISR
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the SLEEP mode
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode only can be
woke up by the enable interrupts
\param[out] none
\retval none
*/
void system_lowpower_reset(uint8_t lowpower_mode)
{
SCB->SCR &= (~(uint32_t)lowpower_mode);
}
/*!
\brief set the systick clock source
\param[in] systick_clksource: the systick clock source needed to choose
\arg SYSTICK_CLKSOURCE_HCLK: systick clock source is from HCLK
\arg SYSTICK_CLKSOURCE_HCLK_DIV8: systick clock source is from HCLK/8
\param[out] none
\retval none
*/
void systick_clksource_set(uint32_t systick_clksource)
{
if(SYSTICK_CLKSOURCE_HCLK == systick_clksource ){
/* set the systick clock source from HCLK */
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
}else{
/* set the systick clock source from HCLK/8 */
SysTick->CTRL &= SYSTICK_CLKSOURCE_HCLK_DIV8;
}
}
@@ -0,0 +1,180 @@
/*!
\file gd32e50x_misc.c
\brief MISC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_misc.h"
/*!
\brief set the priority group
\param[in] nvic_prigroup: the NVIC priority group
\arg NVIC_PRIGROUP_PRE0_SUB4:0 bits for pre-emption priority 4 bits for subpriority
\arg NVIC_PRIGROUP_PRE1_SUB3:1 bits for pre-emption priority 3 bits for subpriority
\arg NVIC_PRIGROUP_PRE2_SUB2:2 bits for pre-emption priority 2 bits for subpriority
\arg NVIC_PRIGROUP_PRE3_SUB1:3 bits for pre-emption priority 1 bits for subpriority
\arg NVIC_PRIGROUP_PRE4_SUB0:4 bits for pre-emption priority 0 bits for subpriority
\param[out] none
\retval none
*/
void nvic_priority_group_set(uint32_t nvic_prigroup)
{
/* set the priority group value */
SCB->AIRCR = NVIC_AIRCR_VECTKEY_MASK | nvic_prigroup;
}
/*!
\brief enable NVIC request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[in] nvic_irq_pre_priority: the pre-emption priority needed to set
\param[in] nvic_irq_sub_priority: the subpriority needed to set
\param[out] none
\retval none
*/
void nvic_irq_enable(IRQn_Type nvic_irq, uint8_t nvic_irq_pre_priority,
uint8_t nvic_irq_sub_priority)
{
uint32_t nvic_prigroup, nvic_priority;
/* check current priority group */
switch(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) {
case NVIC_PRIGROUP_PRE0_SUB4:
case NVIC_PRIGROUP_PRE1_SUB3:
case NVIC_PRIGROUP_PRE2_SUB2:
case NVIC_PRIGROUP_PRE3_SUB1:
case NVIC_PRIGROUP_PRE4_SUB0:
break;
default:
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
break;
}
/* get the priority group value */
nvic_prigroup = NVIC_GetPriorityGrouping();
/* encoding the pre-emption, subpriority priority */
nvic_priority = NVIC_EncodePriority(nvic_prigroup, (uint32_t)nvic_irq_pre_priority, (uint32_t)nvic_irq_sub_priority);
/* set priority */
NVIC_SetPriority(nvic_irq, nvic_priority);
/* enable the selected IRQ */
NVIC_EnableIRQ(nvic_irq);
}
/*!
\brief disable NVIC request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[out] none
\retval none
*/
void nvic_irq_disable(IRQn_Type nvic_irq)
{
/* disable the selected IRQ.*/
NVIC_DisableIRQ((IRQn_Type)nvic_irq);
}
/*!
\brief initiates a system reset request to reset the MCU
\param[in] none
\param[out] none
\retval none
*/
void nvic_system_reset(void)
{
NVIC_SystemReset();
}
/*!
\brief set the NVIC vector table base address
\param[in] nvic_vict_tab: the RAM or FLASH base address
\arg NVIC_VECTTAB_RAM: RAM base address
\are NVIC_VECTTAB_FLASH: Flash base address
\param[in] offset: Vector Table offset
\param[out] none
\retval none
*/
void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
{
SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
__DSB();
}
/*!
\brief set the state of the low power mode
\param[in] lowpower_mode: the low power mode state
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system always enter low power
mode by exiting from ISR
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the DEEPSLEEP mode
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode can be woke up
by all the enable and disable interrupts
\param[out] none
\retval none
*/
void system_lowpower_set(uint8_t lowpower_mode)
{
SCB->SCR |= (uint32_t)lowpower_mode;
}
/*!
\brief reset the state of the low power mode
\param[in] lowpower_mode: the low power mode state
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system will exit low power
mode by exiting from ISR
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the SLEEP mode
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode only can be
woke up by the enable interrupts
\param[out] none
\retval none
*/
void system_lowpower_reset(uint8_t lowpower_mode)
{
SCB->SCR &= (~(uint32_t)lowpower_mode);
}
/*!
\brief set the systick clock source
\param[in] systick_clksource: the systick clock source needed to choose
\arg SYSTICK_CLKSOURCE_HCLK: systick clock source is from HCLK
\arg SYSTICK_CLKSOURCE_HCLK_DIV8: systick clock source is from HCLK/8
\param[out] none
\retval none
*/
void systick_clksource_set(uint32_t systick_clksource)
{
if(SYSTICK_CLKSOURCE_HCLK == systick_clksource ){
/* set the systick clock source from HCLK */
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
}else{
/* set the systick clock source from HCLK/8 */
SysTick->CTRL &= SYSTICK_CLKSOURCE_HCLK_DIV8;
}
}
@@ -0,0 +1,522 @@
/*!
\file gd32e50x_pmu.c
\brief PMU driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_pmu.h"
/*!
\brief reset PMU registers
\param[in] none
\param[out] none
\retval none
*/
void pmu_deinit(void)
{
/* reset PMU */
rcu_periph_reset_enable(RCU_PMURST);
rcu_periph_reset_disable(RCU_PMURST);
}
/*!
\brief select low voltage detector threshold
\param[in] lvdt_n:
only one parameter can be selected which is shown as below:
\arg PMU_LVDT_0: voltage threshold is 2.1V
\arg PMU_LVDT_1: voltage threshold is 2.3V
\arg PMU_LVDT_2: voltage threshold is 2.4V
\arg PMU_LVDT_3: voltage threshold is 2.6V
\arg PMU_LVDT_4: voltage threshold is 2.7V
\arg PMU_LVDT_5: voltage threshold is 2.9V
\arg PMU_LVDT_6: voltage threshold is 3.0V
\arg PMU_LVDT_7: voltage threshold is 3.1V
\param[out] none
\retval none
*/
void pmu_lvd_select(uint32_t lvdt_n)
{
/* disable LVD */
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
/* clear LVDT bits */
PMU_CTL0 &= ~PMU_CTL0_LVDT;
/* set LVDT bits according to lvdt_n */
PMU_CTL0 |= lvdt_n;
/* enable LVD */
PMU_CTL0 |= PMU_CTL0_LVDEN;
}
/*!
\brief disable PMU LVD
\param[in] none
\param[out] none
\retval none
*/
void pmu_lvd_disable(void)
{
/* disable LVD */
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
}
/*!
\brief enable high-driver mode
this bit set by software only when IRC8M or HXTAL used as system clock
\param[in] none
\param[out] none
\retval none
*/
void pmu_highdriver_mode_enable(void)
{
PMU_CTL0 |= PMU_CTL0_HDEN;
}
/*!
\brief disable high-driver mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_highdriver_mode_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_HDEN;
}
/*!
\brief switch high-driver mode
this bit set by software only when IRC8M or HXTAL used as system clock
\param[in] highdr_switch:
only one parameter can be selected which is shown as below:
\arg PMU_HIGHDR_SWITCH_NONE: disable high-driver mode switch
\arg PMU_HIGHDR_SWITCH_EN: enable high-driver mode switch
\param[out] none
\retval none
*/
void pmu_highdriver_switch_select(uint32_t highdr_switch)
{
/* wait for HDRF flag set */
while(SET != pmu_flag_get(PMU_FLAG_HDRF)){
}
PMU_CTL0 &= ~PMU_CTL0_HDS;
PMU_CTL0 |= highdr_switch;
}
/*!
\brief enable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_lowdriver_mode_enable(void)
{
PMU_CTL0 |= PMU_CTL0_LDEN;
}
/*!
\brief disable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_lowdriver_mode_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_LDEN;
}
/*!
\brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use low power LDO
\param[in] mode:
only one parameter can be selected which is shown as below:
\arg PMU_NORMALDR_LOWPWR: normal driver when use low power LDO
\arg PMU_LOWDR_LOWPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
\param[out] none
\retval none
*/
void pmu_lowpower_driver_config(uint32_t mode)
{
PMU_CTL0 &= ~PMU_CTL0_LDLP;
PMU_CTL0 |= mode;
}
/*!
\brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use normal power LDO
\param[in] mode:
only one parameter can be selected which is shown as below:
\arg PMU_NORMALDR_NORMALPWR: normal driver when use normal power LDO
\arg PMU_LOWDR_NORMALPWR: low-driver mode enabled when LDEN is 11 and use normal power LDO
\param[out] none
\retval none
*/
void pmu_normalpower_driver_config(uint32_t mode)
{
PMU_CTL0 &= ~PMU_CTL0_LDNP;
PMU_CTL0 |= mode;
}
/*!
\brief PMU work at sleep mode
\param[in] sleepmodecmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_sleepmode(uint8_t sleepmodecmd)
{
/* clear sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
/* select WFI or WFE command to enter sleep mode */
if(WFI_CMD == sleepmodecmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
}
/*!
\brief PMU work at deepsleep mode
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep mode
\param[in] deepsleepmodecmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmodecmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 1/2 mode enable bits */
PMU_CTL1 &= ~(PMU_CTL1_DPMOD1 | PMU_CTL1_DPMOD2);
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode */
if(WFI_CMD == deepsleepmodecmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
/*!
\brief PMU work at deepsleep mode 1
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 1
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 1
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 1 mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 1 mode
\param[in] deepsleepmode1cmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode_1(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode1cmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 2 mode enable bit */
PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
/* enable deep-sleep 1 mode */
PMU_CTL1 |= PMU_CTL1_DPMOD1;
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep 1 mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode 1 */
if(WFI_CMD == deepsleepmode1cmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
}
/*!
\brief PMU work at deepsleep mode 2
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 2
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 2
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 2 mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 2 mode
\param[in] deepsleepmode2cmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode_2(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode2cmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 1 mode enable bit */
PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
/* enable deep-sleep 2 mode */
PMU_CTL1 |= PMU_CTL1_DPMOD2;
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep 2 mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode 2 */
if(WFI_CMD == deepsleepmode2cmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
}
/*!
\brief pmu work at standby mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_to_standbymode(void)
{
/* set stbmod bit */
PMU_CTL0 |= PMU_CTL0_STBMOD;
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
REG32( 0xE000E010U ) &= 0x00010004U;
REG32( 0xE000E180U ) = 0XFFFFFFF7U;
REG32( 0xE000E184U ) = 0XFFFFFDFFU;
REG32( 0xE000E188U ) = 0xFFFFFFFFU;
/* select WFI command to enter standby mode */
__WFI();
}
/*!
\brief enable PMU wakeup pin
\param[in] wakeup_pin:
one or more parameters can be selected which are shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
\arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
\arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
\arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
\arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
\param[out] none
\retval none
*/
void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
{
PMU_CS0 |= wakeup_pin;
}
/*!
\brief disable PMU wakeup pin
\param[in] wakeup_pin:
one or more parameters can be selected which are shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
\arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
\arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
\arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
\arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
\param[out] none
\retval none
*/
void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
{
PMU_CS0 &= ~(wakeup_pin);
}
/*!
\brief enable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_enable(void)
{
PMU_CTL0 |= PMU_CTL0_BKPWEN;
}
/*!
\brief disable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_BKPWEN;
}
/*!
\brief get flag state
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg PMU_FLAG_WAKEUP: wakeup flag
\arg PMU_FLAG_STANDBY: standby flag
\arg PMU_FLAG_LVD: lvd flag
\arg PMU_FLAG_HDRF: high-driver ready flag
\arg PMU_FLAG_HDSRF: high-driver switch ready flag
\arg PMU_FLAG_LDRF: low-driver mode ready flag
\arg PMU_FLAG_DEEPSLEEP_1: deep-sleep 1 mode status flag
\arg PMU_FLAG_DEEPSLEEP_2: deep-sleep 2 mode status flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus pmu_flag_get(uint32_t flag)
{
FlagStatus ret = RESET;
if(RESET != (flag & BIT(31))){
flag &= ~BIT(31);
if(PMU_CS1 & flag){
ret = SET;
}
}else{
if(PMU_CS0 & flag){
ret = SET;
}
}
return ret;
}
/*!
\brief clear flag bit
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg PMU_FLAG_RESET_WAKEUP: reset wakeup flag
\arg PMU_FLAG_RESET_STANDBY: reset standby flag
\arg PMU_FLAG_RESET_DEEPSLEEP_1: reset deep-sleep 1 mode status flag
\arg PMU_FLAG_RESET_DEEPSLEEP_2: reset deep-sleep 2 mode status flag
\param[out] none
\retval none
*/
void pmu_flag_clear(uint32_t flag)
{
switch(flag){
case PMU_FLAG_RESET_WAKEUP:
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
break;
case PMU_FLAG_RESET_STANDBY:
/* reset standby flag */
PMU_CTL0 |= PMU_CTL0_STBRST;
break;
case PMU_FLAG_RESET_DEEPSLEEP_1:
/* reset deep-sleep 1 mode status flag */
PMU_CS1 &= ~PMU_CS1_DPF1;
break;
case PMU_FLAG_RESET_DEEPSLEEP_2:
/* reset deep-sleep 2 mode status flag */
PMU_CS1 &= ~PMU_CS1_DPF2;
break;
default :
break;
}
}
@@ -0,0 +1,522 @@
/*!
\file gd32e50x_pmu.c
\brief PMU driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_pmu.h"
/*!
\brief reset PMU registers
\param[in] none
\param[out] none
\retval none
*/
void pmu_deinit(void)
{
/* reset PMU */
rcu_periph_reset_enable(RCU_PMURST);
rcu_periph_reset_disable(RCU_PMURST);
}
/*!
\brief select low voltage detector threshold
\param[in] lvdt_n:
only one parameter can be selected which is shown as below:
\arg PMU_LVDT_0: voltage threshold is 2.1V
\arg PMU_LVDT_1: voltage threshold is 2.3V
\arg PMU_LVDT_2: voltage threshold is 2.4V
\arg PMU_LVDT_3: voltage threshold is 2.6V
\arg PMU_LVDT_4: voltage threshold is 2.7V
\arg PMU_LVDT_5: voltage threshold is 2.9V
\arg PMU_LVDT_6: voltage threshold is 3.0V
\arg PMU_LVDT_7: voltage threshold is 3.1V
\param[out] none
\retval none
*/
void pmu_lvd_select(uint32_t lvdt_n)
{
/* disable LVD */
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
/* clear LVDT bits */
PMU_CTL0 &= ~PMU_CTL0_LVDT;
/* set LVDT bits according to lvdt_n */
PMU_CTL0 |= lvdt_n;
/* enable LVD */
PMU_CTL0 |= PMU_CTL0_LVDEN;
}
/*!
\brief disable PMU LVD
\param[in] none
\param[out] none
\retval none
*/
void pmu_lvd_disable(void)
{
/* disable LVD */
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
}
/*!
\brief enable high-driver mode
this bit set by software only when IRC8M or HXTAL used as system clock
\param[in] none
\param[out] none
\retval none
*/
void pmu_highdriver_mode_enable(void)
{
PMU_CTL0 |= PMU_CTL0_HDEN;
}
/*!
\brief disable high-driver mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_highdriver_mode_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_HDEN;
}
/*!
\brief switch high-driver mode
this bit set by software only when IRC8M or HXTAL used as system clock
\param[in] highdr_switch:
only one parameter can be selected which is shown as below:
\arg PMU_HIGHDR_SWITCH_NONE: disable high-driver mode switch
\arg PMU_HIGHDR_SWITCH_EN: enable high-driver mode switch
\param[out] none
\retval none
*/
void pmu_highdriver_switch_select(uint32_t highdr_switch)
{
/* wait for HDRF flag set */
while(SET != pmu_flag_get(PMU_FLAG_HDRF)){
}
PMU_CTL0 &= ~PMU_CTL0_HDS;
PMU_CTL0 |= highdr_switch;
}
/*!
\brief enable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_lowdriver_mode_enable(void)
{
PMU_CTL0 |= PMU_CTL0_LDEN;
}
/*!
\brief disable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_lowdriver_mode_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_LDEN;
}
/*!
\brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use low power LDO
\param[in] mode:
only one parameter can be selected which is shown as below:
\arg PMU_NORMALDR_LOWPWR: normal driver when use low power LDO
\arg PMU_LOWDR_LOWPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
\param[out] none
\retval none
*/
void pmu_lowpower_driver_config(uint32_t mode)
{
PMU_CTL0 &= ~PMU_CTL0_LDLP;
PMU_CTL0 |= mode;
}
/*!
\brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use normal power LDO
\param[in] mode:
only one parameter can be selected which is shown as below:
\arg PMU_NORMALDR_NORMALPWR: normal driver when use normal power LDO
\arg PMU_LOWDR_NORMALPWR: low-driver mode enabled when LDEN is 11 and use normal power LDO
\param[out] none
\retval none
*/
void pmu_normalpower_driver_config(uint32_t mode)
{
PMU_CTL0 &= ~PMU_CTL0_LDNP;
PMU_CTL0 |= mode;
}
/*!
\brief PMU work at sleep mode
\param[in] sleepmodecmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_sleepmode(uint8_t sleepmodecmd)
{
/* clear sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
/* select WFI or WFE command to enter sleep mode */
if(WFI_CMD == sleepmodecmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
}
/*!
\brief PMU work at deepsleep mode
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep mode
\param[in] deepsleepmodecmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmodecmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 1/2 mode enable bits */
PMU_CTL1 &= ~(PMU_CTL1_DPMOD1 | PMU_CTL1_DPMOD2);
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode */
if(WFI_CMD == deepsleepmodecmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
/*!
\brief PMU work at deepsleep mode 1
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 1
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 1
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 1 mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 1 mode
\param[in] deepsleepmode1cmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode_1(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode1cmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 2 mode enable bit */
PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
/* enable deep-sleep 1 mode */
PMU_CTL1 |= PMU_CTL1_DPMOD1;
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep 1 mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode 1 */
if(WFI_CMD == deepsleepmode1cmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
}
/*!
\brief PMU work at deepsleep mode 2
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 2
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 2
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 2 mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 2 mode
\param[in] deepsleepmode2cmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode_2(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode2cmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 1 mode enable bit */
PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
/* enable deep-sleep 2 mode */
PMU_CTL1 |= PMU_CTL1_DPMOD2;
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep 2 mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode 2 */
if(WFI_CMD == deepsleepmode2cmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
}
/*!
\brief pmu work at standby mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_to_standbymode(void)
{
/* set stbmod bit */
PMU_CTL0 |= PMU_CTL0_STBMOD;
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
REG32( 0xE000E010U ) &= 0x00010004U;
REG32( 0xE000E180U ) = 0XFFFFFFF7U;
REG32( 0xE000E184U ) = 0XFFFFFDFFU;
REG32( 0xE000E188U ) = 0xFFFFFFFFU;
/* select WFI command to enter standby mode */
__WFI();
}
/*!
\brief enable PMU wakeup pin
\param[in] wakeup_pin:
one or more parameters can be selected which are shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
\arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
\arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
\arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
\arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
\param[out] none
\retval none
*/
void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
{
PMU_CS0 |= wakeup_pin;
}
/*!
\brief disable PMU wakeup pin
\param[in] wakeup_pin:
one or more parameters can be selected which are shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
\arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
\arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
\arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
\arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
\param[out] none
\retval none
*/
void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
{
PMU_CS0 &= ~(wakeup_pin);
}
/*!
\brief enable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_enable(void)
{
PMU_CTL0 |= PMU_CTL0_BKPWEN;
}
/*!
\brief disable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_BKPWEN;
}
/*!
\brief get flag state
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg PMU_FLAG_WAKEUP: wakeup flag
\arg PMU_FLAG_STANDBY: standby flag
\arg PMU_FLAG_LVD: lvd flag
\arg PMU_FLAG_HDRF: high-driver ready flag
\arg PMU_FLAG_HDSRF: high-driver switch ready flag
\arg PMU_FLAG_LDRF: low-driver mode ready flag
\arg PMU_FLAG_DEEPSLEEP_1: deep-sleep 1 mode status flag
\arg PMU_FLAG_DEEPSLEEP_2: deep-sleep 2 mode status flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus pmu_flag_get(uint32_t flag)
{
FlagStatus ret = RESET;
if(RESET != (flag & BIT(31))){
flag &= ~BIT(31);
if(PMU_CS1 & flag){
ret = SET;
}
}else{
if(PMU_CS0 & flag){
ret = SET;
}
}
return ret;
}
/*!
\brief clear flag bit
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg PMU_FLAG_RESET_WAKEUP: reset wakeup flag
\arg PMU_FLAG_RESET_STANDBY: reset standby flag
\arg PMU_FLAG_RESET_DEEPSLEEP_1: reset deep-sleep 1 mode status flag
\arg PMU_FLAG_RESET_DEEPSLEEP_2: reset deep-sleep 2 mode status flag
\param[out] none
\retval none
*/
void pmu_flag_clear(uint32_t flag)
{
switch(flag){
case PMU_FLAG_RESET_WAKEUP:
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
break;
case PMU_FLAG_RESET_STANDBY:
/* reset standby flag */
PMU_CTL0 |= PMU_CTL0_STBRST;
break;
case PMU_FLAG_RESET_DEEPSLEEP_1:
/* reset deep-sleep 1 mode status flag */
PMU_CS1 &= ~PMU_CS1_DPF1;
break;
case PMU_FLAG_RESET_DEEPSLEEP_2:
/* reset deep-sleep 2 mode status flag */
PMU_CS1 &= ~PMU_CS1_DPF2;
break;
default :
break;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,101 @@
#ifndef REGIONS_GD32E508VE_H
#define REGIONS_GD32E508VE_H
//-------- <<< Use Configuration Wizard in Context Menu >>> --------------------
//------ With VS Code: Open Preview for Configuration Wizard -------------------
// <n> Auto-generated using information from packs
// <i> Device Family Pack (DFP): GigaDevice::GD32E50x_DFP@1.9.0
// <h> ROM Configuration
// =======================
// <h> __ROM0 (is rx memory: IROM1 from DFP)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region. Default: 0x08000000
// <i> Contains Startup and Vector Table
#define __ROM0_BASE 0x08000000
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region. Default: 0x00080000
#define __ROM0_SIZE 0x00080000
// </h>
// <h> __ROM1 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __ROM1_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __ROM1_SIZE 0x0
// </h>
// <h> __ROM2 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __ROM2_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __ROM2_SIZE 0x0
// </h>
// <h> __ROM3 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __ROM3_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __ROM3_SIZE 0x0
// </h>
// </h>
// <h> RAM Configuration
// =======================
// <h> __RAM0 (is rwx memory: IRAM1 from DFP)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region. Default: 0x20000000
// <i> Contains uninitialized RAM, Stack, and Heap
#define __RAM0_BASE 0x20000000
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region. Default: 0x00020000
#define __RAM0_SIZE 0x00020000
// </h>
// <h> __RAM1 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __RAM1_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __RAM1_SIZE 0x0
// </h>
// <h> __RAM2 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __RAM2_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __RAM2_SIZE 0x0
// </h>
// <h> __RAM3 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __RAM3_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __RAM3_SIZE 0x0
// </h>
// </h>
// <h> Stack / Heap Configuration
// <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
// <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
#define __STACK_SIZE 0x00000200
#define __HEAP_SIZE 0x00000C00
// </h>
#endif /* REGIONS_GD32E508VE_H */
@@ -0,0 +1,434 @@
;/*!
; \file startup_gd32e50x_cl.s
; \brief start up file
;
; \version 2025-07-09, V1.6.1, firmware for GD32E50x
;*/
;
;/*
; * Copyright (c) 2009-2018 Arm Limited. All rights reserved.
; * Copyright (c) 2023, GigaDevice Semiconductor Inc.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Licensed under the Apache License, Version 2.0 (the License); you may
; * not use this file except in compliance with the License.
; * You may obtain a copy of the License at
; *
; * www.apache.org/licenses/LICENSE-2.0
; *
; * Unless required by applicable law or agreed to in writing, software
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; * See the License for the specific language governing permissions and
; * limitations under the License.
; */
;/* This file refers the CMSIS standard, some adjustments are made according to GigaDevice chips */
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x00000800
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000400
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
; /* reset Vector Mapped to at Address 0 */
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; /* external interrupts handler */
DCD WWDGT_IRQHandler ; 16:Window Watchdog Timer
DCD LVD_IRQHandler ; 17:LVD through EXTI Line detect
DCD TAMPER_IRQHandler ; 18:Tamper through EXTI Line detect
DCD RTC_IRQHandler ; 19:RTC through EXTI Line
DCD FMC_IRQHandler ; 20:FMC
DCD RCU_CTC_IRQHandler ; 21:RCU and CTC
DCD EXTI0_IRQHandler ; 22:EXTI Line 0
DCD EXTI1_IRQHandler ; 23:EXTI Line 1
DCD EXTI2_IRQHandler ; 24:EXTI Line 2
DCD EXTI3_IRQHandler ; 25:EXTI Line 3
DCD EXTI4_IRQHandler ; 26:EXTI Line 4
DCD DMA0_Channel0_IRQHandler ; 27:DMA0 Channel0
DCD DMA0_Channel1_IRQHandler ; 28:DMA0 Channel1
DCD DMA0_Channel2_IRQHandler ; 29:DMA0 Channel2
DCD DMA0_Channel3_IRQHandler ; 30:DMA0 Channel3
DCD DMA0_Channel4_IRQHandler ; 31:DMA0 Channel4
DCD DMA0_Channel5_IRQHandler ; 32:DMA0 Channel5
DCD DMA0_Channel6_IRQHandler ; 33:DMA0 Channel6
DCD ADC0_1_IRQHandler ; 34:ADC0 and ADC1
DCD CAN0_TX_IRQHandler ; 35:CAN0 TX
DCD CAN0_RX0_IRQHandler ; 36:CAN0 RX0
DCD CAN0_RX1_IRQHandler ; 37:CAN0 RX1
DCD CAN0_EWMC_IRQHandler ; 38:CAN0 EWMC
DCD EXTI5_9_IRQHandler ; 39:EXTI5 to EXTI9
DCD TIMER0_BRK_TIMER8_IRQHandler ; 40:TIMER0 Break and TIMER8
DCD TIMER0_UP_TIMER9_IRQHandler ; 41:TIMER0 Update and TIMER9
DCD TIMER0_TRG_CMT_TIMER10_IRQHandler ; 42:TIMER0 Trigger and Commutation and TIMER10
DCD TIMER0_Channel_IRQHandler ; 43:TIMER0 Channel Capture Compare
DCD TIMER1_IRQHandler ; 44:TIMER1
DCD TIMER2_IRQHandler ; 45:TIMER2
DCD TIMER3_IRQHandler ; 46:TIMER3
DCD I2C0_EV_IRQHandler ; 47:I2C0 Event
DCD I2C0_ER_IRQHandler ; 48:I2C0 Error
DCD I2C1_EV_IRQHandler ; 49:I2C1 Event
DCD I2C1_ER_IRQHandler ; 50:I2C1 Error
DCD SPI0_IRQHandler ; 51:SPI0
DCD SPI1_I2S1ADD_IRQHandler ; 52:SPI1 or I2S1ADD
DCD USART0_IRQHandler ; 53:USART0
DCD USART1_IRQHandler ; 54:USART1
DCD USART2_IRQHandler ; 55:USART2
DCD EXTI10_15_IRQHandler ; 56:EXTI10 to EXTI15
DCD RTC_Alarm_IRQHandler ; 57:RTC Alarm
DCD USBHS_WKUP_IRQHandler ; 58:USBHS Wakeup
DCD TIMER7_BRK_TIMER11_IRQHandler ; 59:TIMER7 Break and TIMER11
DCD TIMER7_UP_TIMER12_IRQHandler ; 60:TIMER7 Update and TIMER12
DCD TIMER7_TRG_CMT_TIMER13_IRQHandler ; 61:TIMER7 Trigger and Commutation and TIMER13
DCD TIMER7_Channel_IRQHandler ; 62:TIMER7 Channel Capture Compare
DCD 0 ; Reserved
DCD EXMC_IRQHandler ; 64:EXMC
DCD 0 ; Reserved
DCD TIMER4_IRQHandler ; 66:TIMER4
DCD SPI2_I2S2ADD_IRQHandler ; 67:SPI2 or I2S2ADD
DCD UART3_IRQHandler ; 68:UART3
DCD UART4_IRQHandler ; 69:UART4
DCD TIMER5_DAC_IRQHandler ; 70:TIMER5 or DAC
DCD TIMER6_IRQHandler ; 71:TIMER6
DCD DMA1_Channel0_IRQHandler ; 72:DMA1 Channel0
DCD DMA1_Channel1_IRQHandler ; 73:DMA1 Channel1
DCD DMA1_Channel2_IRQHandler ; 74:DMA1 Channel2
DCD DMA1_Channel3_IRQHandler ; 75:DMA1 Channel3
DCD DMA1_Channel4_IRQHandler ; 76:DMA1 Channel4
DCD ENET_IRQHandler ; 77:Ethernet
DCD ENET_WKUP_IRQHandler ; 78:Ethernet Wakeup through EXTI Line
DCD CAN1_TX_IRQHandler ; 79:CAN1 TX
DCD CAN1_RX0_IRQHandler ; 80:CAN1 RX0
DCD CAN1_RX1_IRQHandler ; 81:CAN1 RX1
DCD CAN1_EWMC_IRQHandler ; 82:CAN1 EWMC
DCD USBHS_IRQHandler ; 83:USBHS
DCD 0 ; Reserved
DCD SHRTIMER_IRQ2_IRQHandler ; 85:SHRTIMER IRQ2
DCD SHRTIMER_IRQ3_IRQHandler ; 86:SHRTIMER IRQ3
DCD SHRTIMER_IRQ4_IRQHandler ; 87:SHRTIMER IRQ4
DCD SHRTIMER_IRQ5_IRQHandler ; 88:SHRTIMER IRQ5
DCD SHRTIMER_IRQ6_IRQHandler ; 89:SHRTIMER IRQ6
DCD USBHS_EP1_OUT_IRQHandler ; 90:USBHS end point 1 out
DCD USBHS_EP1_IN_IRQHandler ; 91:USBHS end point 1 in
DCD SHRTIMER_IRQ0_IRQHandler ; 92:SHRTIMER IRQ0
DCD SHRTIMER_IRQ1_IRQHandler ; 93:SHRTIMER IRQ1
DCD CAN2_TX_IRQHandler ; 94:CAN2 TX
DCD CAN2_RX0_IRQHandler ; 95:CAN2 RX0
DCD CAN2_RX1_IRQHandler ; 96:CAN2 RX1
DCD CAN2_EWMC_IRQHandler ; 97:CAN2 EWMC
DCD I2C2_EV_IRQHandler ; 98:I2C2 Event
DCD I2C2_ER_IRQHandler ; 99:I2C2 Error
DCD USART5_IRQHandler ; 100:USART5
DCD I2C2_WKUP_IRQHandler ; 101:I2C2 Wakeup
DCD USART5_WKUP_IRQHandler ; 102:USART5 Wakeup
DCD TMU_IRQHandler ; 103:TMU
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
;/* reset Handler */
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
;/* dummy Exception Handlers */
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemManage_Handler\
PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler\
PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler\
PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler\
PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
; /* external interrupts handler */
EXPORT WWDGT_IRQHandler [WEAK]
EXPORT LVD_IRQHandler [WEAK]
EXPORT TAMPER_IRQHandler [WEAK]
EXPORT RTC_IRQHandler [WEAK]
EXPORT FMC_IRQHandler [WEAK]
EXPORT RCU_CTC_IRQHandler [WEAK]
EXPORT EXTI0_IRQHandler [WEAK]
EXPORT EXTI1_IRQHandler [WEAK]
EXPORT EXTI2_IRQHandler [WEAK]
EXPORT EXTI3_IRQHandler [WEAK]
EXPORT EXTI4_IRQHandler [WEAK]
EXPORT DMA0_Channel0_IRQHandler [WEAK]
EXPORT DMA0_Channel1_IRQHandler [WEAK]
EXPORT DMA0_Channel2_IRQHandler [WEAK]
EXPORT DMA0_Channel3_IRQHandler [WEAK]
EXPORT DMA0_Channel4_IRQHandler [WEAK]
EXPORT DMA0_Channel5_IRQHandler [WEAK]
EXPORT DMA0_Channel6_IRQHandler [WEAK]
EXPORT ADC0_1_IRQHandler [WEAK]
EXPORT CAN0_TX_IRQHandler [WEAK]
EXPORT CAN0_RX0_IRQHandler [WEAK]
EXPORT CAN0_RX1_IRQHandler [WEAK]
EXPORT CAN0_EWMC_IRQHandler [WEAK]
EXPORT EXTI5_9_IRQHandler [WEAK]
EXPORT TIMER0_BRK_TIMER8_IRQHandler [WEAK]
EXPORT TIMER0_UP_TIMER9_IRQHandler [WEAK]
EXPORT TIMER0_TRG_CMT_TIMER10_IRQHandler [WEAK]
EXPORT TIMER0_Channel_IRQHandler [WEAK]
EXPORT TIMER1_IRQHandler [WEAK]
EXPORT TIMER2_IRQHandler [WEAK]
EXPORT TIMER3_IRQHandler [WEAK]
EXPORT I2C0_EV_IRQHandler [WEAK]
EXPORT I2C0_ER_IRQHandler [WEAK]
EXPORT I2C1_EV_IRQHandler [WEAK]
EXPORT I2C1_ER_IRQHandler [WEAK]
EXPORT SPI0_IRQHandler [WEAK]
EXPORT SPI1_I2S1ADD_IRQHandler [WEAK]
EXPORT USART0_IRQHandler [WEAK]
EXPORT USART1_IRQHandler [WEAK]
EXPORT USART2_IRQHandler [WEAK]
EXPORT EXTI10_15_IRQHandler [WEAK]
EXPORT RTC_Alarm_IRQHandler [WEAK]
EXPORT USBHS_WKUP_IRQHandler [WEAK]
EXPORT TIMER7_BRK_TIMER11_IRQHandler [WEAK]
EXPORT TIMER7_UP_TIMER12_IRQHandler [WEAK]
EXPORT TIMER7_TRG_CMT_TIMER13_IRQHandler [WEAK]
EXPORT TIMER7_Channel_IRQHandler [WEAK]
EXPORT EXMC_IRQHandler [WEAK]
EXPORT TIMER4_IRQHandler [WEAK]
EXPORT SPI2_I2S2ADD_IRQHandler [WEAK]
EXPORT UART3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT TIMER5_DAC_IRQHandler [WEAK]
EXPORT TIMER6_IRQHandler [WEAK]
EXPORT DMA1_Channel0_IRQHandler [WEAK]
EXPORT DMA1_Channel1_IRQHandler [WEAK]
EXPORT DMA1_Channel2_IRQHandler [WEAK]
EXPORT DMA1_Channel3_IRQHandler [WEAK]
EXPORT DMA1_Channel4_IRQHandler [WEAK]
EXPORT ENET_IRQHandler [WEAK]
EXPORT ENET_WKUP_IRQHandler [WEAK]
EXPORT CAN1_TX_IRQHandler [WEAK]
EXPORT CAN1_RX0_IRQHandler [WEAK]
EXPORT CAN1_RX1_IRQHandler [WEAK]
EXPORT CAN1_EWMC_IRQHandler [WEAK]
EXPORT USBHS_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ2_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ3_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ4_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ5_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ6_IRQHandler [WEAK]
EXPORT USBHS_EP1_OUT_IRQHandler [WEAK]
EXPORT USBHS_EP1_IN_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ0_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ1_IRQHandler [WEAK]
EXPORT CAN2_TX_IRQHandler [WEAK]
EXPORT CAN2_RX0_IRQHandler [WEAK]
EXPORT CAN2_RX1_IRQHandler [WEAK]
EXPORT CAN2_EWMC_IRQHandler [WEAK]
EXPORT I2C2_EV_IRQHandler [WEAK]
EXPORT I2C2_ER_IRQHandler [WEAK]
EXPORT USART5_IRQHandler [WEAK]
EXPORT I2C2_WKUP_IRQHandler [WEAK]
EXPORT USART5_WKUP_IRQHandler [WEAK]
EXPORT TMU_IRQHandler [WEAK]
;/* external interrupts handler */
WWDGT_IRQHandler
LVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FMC_IRQHandler
RCU_CTC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA0_Channel0_IRQHandler
DMA0_Channel1_IRQHandler
DMA0_Channel2_IRQHandler
DMA0_Channel3_IRQHandler
DMA0_Channel4_IRQHandler
DMA0_Channel5_IRQHandler
DMA0_Channel6_IRQHandler
ADC0_1_IRQHandler
CAN0_TX_IRQHandler
CAN0_RX0_IRQHandler
CAN0_RX1_IRQHandler
CAN0_EWMC_IRQHandler
EXTI5_9_IRQHandler
TIMER0_BRK_TIMER8_IRQHandler
TIMER0_UP_TIMER9_IRQHandler
TIMER0_TRG_CMT_TIMER10_IRQHandler
TIMER0_Channel_IRQHandler
TIMER1_IRQHandler
TIMER2_IRQHandler
TIMER3_IRQHandler
I2C0_EV_IRQHandler
I2C0_ER_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
SPI0_IRQHandler
SPI1_I2S1ADD_IRQHandler
USART0_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
EXTI10_15_IRQHandler
RTC_Alarm_IRQHandler
USBHS_WKUP_IRQHandler
TIMER7_BRK_TIMER11_IRQHandler
TIMER7_UP_TIMER12_IRQHandler
TIMER7_TRG_CMT_TIMER13_IRQHandler
TIMER7_Channel_IRQHandler
EXMC_IRQHandler
TIMER4_IRQHandler
SPI2_I2S2ADD_IRQHandler
UART3_IRQHandler
UART4_IRQHandler
TIMER5_DAC_IRQHandler
TIMER6_IRQHandler
DMA1_Channel0_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
ENET_IRQHandler
ENET_WKUP_IRQHandler
CAN1_TX_IRQHandler
CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_EWMC_IRQHandler
USBHS_IRQHandler
SHRTIMER_IRQ2_IRQHandler
SHRTIMER_IRQ3_IRQHandler
SHRTIMER_IRQ4_IRQHandler
SHRTIMER_IRQ5_IRQHandler
SHRTIMER_IRQ6_IRQHandler
USBHS_EP1_OUT_IRQHandler
USBHS_EP1_IN_IRQHandler
SHRTIMER_IRQ0_IRQHandler
SHRTIMER_IRQ1_IRQHandler
CAN2_TX_IRQHandler
CAN2_RX0_IRQHandler
CAN2_RX1_IRQHandler
CAN2_EWMC_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
USART5_IRQHandler
I2C2_WKUP_IRQHandler
USART5_WKUP_IRQHandler
TMU_IRQHandler
B .
ENDP
ALIGN
; user Initial Stack & Heap
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap PROC
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDP
ALIGN
ENDIF
END
@@ -0,0 +1,434 @@
;/*!
; \file startup_gd32e50x_cl.s
; \brief start up file
;
; \version 2025-07-09, V1.6.1, firmware for GD32E50x
;*/
;
;/*
; * Copyright (c) 2009-2018 Arm Limited. All rights reserved.
; * Copyright (c) 2023, GigaDevice Semiconductor Inc.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Licensed under the Apache License, Version 2.0 (the License); you may
; * not use this file except in compliance with the License.
; * You may obtain a copy of the License at
; *
; * www.apache.org/licenses/LICENSE-2.0
; *
; * Unless required by applicable law or agreed to in writing, software
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; * See the License for the specific language governing permissions and
; * limitations under the License.
; */
;/* This file refers the CMSIS standard, some adjustments are made according to GigaDevice chips */
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x00000800
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000400
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
; /* reset Vector Mapped to at Address 0 */
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; /* external interrupts handler */
DCD WWDGT_IRQHandler ; 16:Window Watchdog Timer
DCD LVD_IRQHandler ; 17:LVD through EXTI Line detect
DCD TAMPER_IRQHandler ; 18:Tamper through EXTI Line detect
DCD RTC_IRQHandler ; 19:RTC through EXTI Line
DCD FMC_IRQHandler ; 20:FMC
DCD RCU_CTC_IRQHandler ; 21:RCU and CTC
DCD EXTI0_IRQHandler ; 22:EXTI Line 0
DCD EXTI1_IRQHandler ; 23:EXTI Line 1
DCD EXTI2_IRQHandler ; 24:EXTI Line 2
DCD EXTI3_IRQHandler ; 25:EXTI Line 3
DCD EXTI4_IRQHandler ; 26:EXTI Line 4
DCD DMA0_Channel0_IRQHandler ; 27:DMA0 Channel0
DCD DMA0_Channel1_IRQHandler ; 28:DMA0 Channel1
DCD DMA0_Channel2_IRQHandler ; 29:DMA0 Channel2
DCD DMA0_Channel3_IRQHandler ; 30:DMA0 Channel3
DCD DMA0_Channel4_IRQHandler ; 31:DMA0 Channel4
DCD DMA0_Channel5_IRQHandler ; 32:DMA0 Channel5
DCD DMA0_Channel6_IRQHandler ; 33:DMA0 Channel6
DCD ADC0_1_IRQHandler ; 34:ADC0 and ADC1
DCD CAN0_TX_IRQHandler ; 35:CAN0 TX
DCD CAN0_RX0_IRQHandler ; 36:CAN0 RX0
DCD CAN0_RX1_IRQHandler ; 37:CAN0 RX1
DCD CAN0_EWMC_IRQHandler ; 38:CAN0 EWMC
DCD EXTI5_9_IRQHandler ; 39:EXTI5 to EXTI9
DCD TIMER0_BRK_TIMER8_IRQHandler ; 40:TIMER0 Break and TIMER8
DCD TIMER0_UP_TIMER9_IRQHandler ; 41:TIMER0 Update and TIMER9
DCD TIMER0_TRG_CMT_TIMER10_IRQHandler ; 42:TIMER0 Trigger and Commutation and TIMER10
DCD TIMER0_Channel_IRQHandler ; 43:TIMER0 Channel Capture Compare
DCD TIMER1_IRQHandler ; 44:TIMER1
DCD TIMER2_IRQHandler ; 45:TIMER2
DCD TIMER3_IRQHandler ; 46:TIMER3
DCD I2C0_EV_IRQHandler ; 47:I2C0 Event
DCD I2C0_ER_IRQHandler ; 48:I2C0 Error
DCD I2C1_EV_IRQHandler ; 49:I2C1 Event
DCD I2C1_ER_IRQHandler ; 50:I2C1 Error
DCD SPI0_IRQHandler ; 51:SPI0
DCD SPI1_I2S1ADD_IRQHandler ; 52:SPI1 or I2S1ADD
DCD USART0_IRQHandler ; 53:USART0
DCD USART1_IRQHandler ; 54:USART1
DCD USART2_IRQHandler ; 55:USART2
DCD EXTI10_15_IRQHandler ; 56:EXTI10 to EXTI15
DCD RTC_Alarm_IRQHandler ; 57:RTC Alarm
DCD USBHS_WKUP_IRQHandler ; 58:USBHS Wakeup
DCD TIMER7_BRK_TIMER11_IRQHandler ; 59:TIMER7 Break and TIMER11
DCD TIMER7_UP_TIMER12_IRQHandler ; 60:TIMER7 Update and TIMER12
DCD TIMER7_TRG_CMT_TIMER13_IRQHandler ; 61:TIMER7 Trigger and Commutation and TIMER13
DCD TIMER7_Channel_IRQHandler ; 62:TIMER7 Channel Capture Compare
DCD 0 ; Reserved
DCD EXMC_IRQHandler ; 64:EXMC
DCD 0 ; Reserved
DCD TIMER4_IRQHandler ; 66:TIMER4
DCD SPI2_I2S2ADD_IRQHandler ; 67:SPI2 or I2S2ADD
DCD UART3_IRQHandler ; 68:UART3
DCD UART4_IRQHandler ; 69:UART4
DCD TIMER5_DAC_IRQHandler ; 70:TIMER5 or DAC
DCD TIMER6_IRQHandler ; 71:TIMER6
DCD DMA1_Channel0_IRQHandler ; 72:DMA1 Channel0
DCD DMA1_Channel1_IRQHandler ; 73:DMA1 Channel1
DCD DMA1_Channel2_IRQHandler ; 74:DMA1 Channel2
DCD DMA1_Channel3_IRQHandler ; 75:DMA1 Channel3
DCD DMA1_Channel4_IRQHandler ; 76:DMA1 Channel4
DCD ENET_IRQHandler ; 77:Ethernet
DCD ENET_WKUP_IRQHandler ; 78:Ethernet Wakeup through EXTI Line
DCD CAN1_TX_IRQHandler ; 79:CAN1 TX
DCD CAN1_RX0_IRQHandler ; 80:CAN1 RX0
DCD CAN1_RX1_IRQHandler ; 81:CAN1 RX1
DCD CAN1_EWMC_IRQHandler ; 82:CAN1 EWMC
DCD USBHS_IRQHandler ; 83:USBHS
DCD 0 ; Reserved
DCD SHRTIMER_IRQ2_IRQHandler ; 85:SHRTIMER IRQ2
DCD SHRTIMER_IRQ3_IRQHandler ; 86:SHRTIMER IRQ3
DCD SHRTIMER_IRQ4_IRQHandler ; 87:SHRTIMER IRQ4
DCD SHRTIMER_IRQ5_IRQHandler ; 88:SHRTIMER IRQ5
DCD SHRTIMER_IRQ6_IRQHandler ; 89:SHRTIMER IRQ6
DCD USBHS_EP1_OUT_IRQHandler ; 90:USBHS end point 1 out
DCD USBHS_EP1_IN_IRQHandler ; 91:USBHS end point 1 in
DCD SHRTIMER_IRQ0_IRQHandler ; 92:SHRTIMER IRQ0
DCD SHRTIMER_IRQ1_IRQHandler ; 93:SHRTIMER IRQ1
DCD CAN2_TX_IRQHandler ; 94:CAN2 TX
DCD CAN2_RX0_IRQHandler ; 95:CAN2 RX0
DCD CAN2_RX1_IRQHandler ; 96:CAN2 RX1
DCD CAN2_EWMC_IRQHandler ; 97:CAN2 EWMC
DCD I2C2_EV_IRQHandler ; 98:I2C2 Event
DCD I2C2_ER_IRQHandler ; 99:I2C2 Error
DCD USART5_IRQHandler ; 100:USART5
DCD I2C2_WKUP_IRQHandler ; 101:I2C2 Wakeup
DCD USART5_WKUP_IRQHandler ; 102:USART5 Wakeup
DCD TMU_IRQHandler ; 103:TMU
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
;/* reset Handler */
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
;/* dummy Exception Handlers */
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemManage_Handler\
PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler\
PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler\
PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler\
PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
; /* external interrupts handler */
EXPORT WWDGT_IRQHandler [WEAK]
EXPORT LVD_IRQHandler [WEAK]
EXPORT TAMPER_IRQHandler [WEAK]
EXPORT RTC_IRQHandler [WEAK]
EXPORT FMC_IRQHandler [WEAK]
EXPORT RCU_CTC_IRQHandler [WEAK]
EXPORT EXTI0_IRQHandler [WEAK]
EXPORT EXTI1_IRQHandler [WEAK]
EXPORT EXTI2_IRQHandler [WEAK]
EXPORT EXTI3_IRQHandler [WEAK]
EXPORT EXTI4_IRQHandler [WEAK]
EXPORT DMA0_Channel0_IRQHandler [WEAK]
EXPORT DMA0_Channel1_IRQHandler [WEAK]
EXPORT DMA0_Channel2_IRQHandler [WEAK]
EXPORT DMA0_Channel3_IRQHandler [WEAK]
EXPORT DMA0_Channel4_IRQHandler [WEAK]
EXPORT DMA0_Channel5_IRQHandler [WEAK]
EXPORT DMA0_Channel6_IRQHandler [WEAK]
EXPORT ADC0_1_IRQHandler [WEAK]
EXPORT CAN0_TX_IRQHandler [WEAK]
EXPORT CAN0_RX0_IRQHandler [WEAK]
EXPORT CAN0_RX1_IRQHandler [WEAK]
EXPORT CAN0_EWMC_IRQHandler [WEAK]
EXPORT EXTI5_9_IRQHandler [WEAK]
EXPORT TIMER0_BRK_TIMER8_IRQHandler [WEAK]
EXPORT TIMER0_UP_TIMER9_IRQHandler [WEAK]
EXPORT TIMER0_TRG_CMT_TIMER10_IRQHandler [WEAK]
EXPORT TIMER0_Channel_IRQHandler [WEAK]
EXPORT TIMER1_IRQHandler [WEAK]
EXPORT TIMER2_IRQHandler [WEAK]
EXPORT TIMER3_IRQHandler [WEAK]
EXPORT I2C0_EV_IRQHandler [WEAK]
EXPORT I2C0_ER_IRQHandler [WEAK]
EXPORT I2C1_EV_IRQHandler [WEAK]
EXPORT I2C1_ER_IRQHandler [WEAK]
EXPORT SPI0_IRQHandler [WEAK]
EXPORT SPI1_I2S1ADD_IRQHandler [WEAK]
EXPORT USART0_IRQHandler [WEAK]
EXPORT USART1_IRQHandler [WEAK]
EXPORT USART2_IRQHandler [WEAK]
EXPORT EXTI10_15_IRQHandler [WEAK]
EXPORT RTC_Alarm_IRQHandler [WEAK]
EXPORT USBHS_WKUP_IRQHandler [WEAK]
EXPORT TIMER7_BRK_TIMER11_IRQHandler [WEAK]
EXPORT TIMER7_UP_TIMER12_IRQHandler [WEAK]
EXPORT TIMER7_TRG_CMT_TIMER13_IRQHandler [WEAK]
EXPORT TIMER7_Channel_IRQHandler [WEAK]
EXPORT EXMC_IRQHandler [WEAK]
EXPORT TIMER4_IRQHandler [WEAK]
EXPORT SPI2_I2S2ADD_IRQHandler [WEAK]
EXPORT UART3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT TIMER5_DAC_IRQHandler [WEAK]
EXPORT TIMER6_IRQHandler [WEAK]
EXPORT DMA1_Channel0_IRQHandler [WEAK]
EXPORT DMA1_Channel1_IRQHandler [WEAK]
EXPORT DMA1_Channel2_IRQHandler [WEAK]
EXPORT DMA1_Channel3_IRQHandler [WEAK]
EXPORT DMA1_Channel4_IRQHandler [WEAK]
EXPORT ENET_IRQHandler [WEAK]
EXPORT ENET_WKUP_IRQHandler [WEAK]
EXPORT CAN1_TX_IRQHandler [WEAK]
EXPORT CAN1_RX0_IRQHandler [WEAK]
EXPORT CAN1_RX1_IRQHandler [WEAK]
EXPORT CAN1_EWMC_IRQHandler [WEAK]
EXPORT USBHS_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ2_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ3_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ4_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ5_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ6_IRQHandler [WEAK]
EXPORT USBHS_EP1_OUT_IRQHandler [WEAK]
EXPORT USBHS_EP1_IN_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ0_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ1_IRQHandler [WEAK]
EXPORT CAN2_TX_IRQHandler [WEAK]
EXPORT CAN2_RX0_IRQHandler [WEAK]
EXPORT CAN2_RX1_IRQHandler [WEAK]
EXPORT CAN2_EWMC_IRQHandler [WEAK]
EXPORT I2C2_EV_IRQHandler [WEAK]
EXPORT I2C2_ER_IRQHandler [WEAK]
EXPORT USART5_IRQHandler [WEAK]
EXPORT I2C2_WKUP_IRQHandler [WEAK]
EXPORT USART5_WKUP_IRQHandler [WEAK]
EXPORT TMU_IRQHandler [WEAK]
;/* external interrupts handler */
WWDGT_IRQHandler
LVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FMC_IRQHandler
RCU_CTC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA0_Channel0_IRQHandler
DMA0_Channel1_IRQHandler
DMA0_Channel2_IRQHandler
DMA0_Channel3_IRQHandler
DMA0_Channel4_IRQHandler
DMA0_Channel5_IRQHandler
DMA0_Channel6_IRQHandler
ADC0_1_IRQHandler
CAN0_TX_IRQHandler
CAN0_RX0_IRQHandler
CAN0_RX1_IRQHandler
CAN0_EWMC_IRQHandler
EXTI5_9_IRQHandler
TIMER0_BRK_TIMER8_IRQHandler
TIMER0_UP_TIMER9_IRQHandler
TIMER0_TRG_CMT_TIMER10_IRQHandler
TIMER0_Channel_IRQHandler
TIMER1_IRQHandler
TIMER2_IRQHandler
TIMER3_IRQHandler
I2C0_EV_IRQHandler
I2C0_ER_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
SPI0_IRQHandler
SPI1_I2S1ADD_IRQHandler
USART0_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
EXTI10_15_IRQHandler
RTC_Alarm_IRQHandler
USBHS_WKUP_IRQHandler
TIMER7_BRK_TIMER11_IRQHandler
TIMER7_UP_TIMER12_IRQHandler
TIMER7_TRG_CMT_TIMER13_IRQHandler
TIMER7_Channel_IRQHandler
EXMC_IRQHandler
TIMER4_IRQHandler
SPI2_I2S2ADD_IRQHandler
UART3_IRQHandler
UART4_IRQHandler
TIMER5_DAC_IRQHandler
TIMER6_IRQHandler
DMA1_Channel0_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
ENET_IRQHandler
ENET_WKUP_IRQHandler
CAN1_TX_IRQHandler
CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_EWMC_IRQHandler
USBHS_IRQHandler
SHRTIMER_IRQ2_IRQHandler
SHRTIMER_IRQ3_IRQHandler
SHRTIMER_IRQ4_IRQHandler
SHRTIMER_IRQ5_IRQHandler
SHRTIMER_IRQ6_IRQHandler
USBHS_EP1_OUT_IRQHandler
USBHS_EP1_IN_IRQHandler
SHRTIMER_IRQ0_IRQHandler
SHRTIMER_IRQ1_IRQHandler
CAN2_TX_IRQHandler
CAN2_RX0_IRQHandler
CAN2_RX1_IRQHandler
CAN2_EWMC_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
USART5_IRQHandler
I2C2_WKUP_IRQHandler
USART5_WKUP_IRQHandler
TMU_IRQHandler
B .
ENDP
ALIGN
; user Initial Stack & Heap
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap PROC
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDP
ALIGN
ENDIF
END
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,48 @@
/*
* CSOLUTION generated file: DO NOT EDIT!
* Generated by: csolution version 2.13.0+p3-g40b6564e
*
* Project: 'GD32E50X_BOOT.Debug+GD32E508VE'
* Target: 'Debug+GD32E508VE'
*/
#ifndef RTE_COMPONENTS_H
#define RTE_COMPONENTS_H
/*
* Define the Device Header File:
*/
#define CMSIS_device_header "gd32e50x.h"
/* GigaDevice::Device:GD32E50x_StdPeripherals:ADC@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_ADC
/* GigaDevice::Device:GD32E50x_StdPeripherals:CAN@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_CAN
/* GigaDevice::Device:GD32E50x_StdPeripherals:CRC@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_CRC
/* GigaDevice::Device:GD32E50x_StdPeripherals:DBG@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_DBG
/* GigaDevice::Device:GD32E50x_StdPeripherals:DMA@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_DMA
/* GigaDevice::Device:GD32E50x_StdPeripherals:EXTI@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_EXTI
/* GigaDevice::Device:GD32E50x_StdPeripherals:FMC@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_FMC
/* GigaDevice::Device:GD32E50x_StdPeripherals:FWDGT@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_FWDGT
/* GigaDevice::Device:GD32E50x_StdPeripherals:GPIO@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_GPIO
/* GigaDevice::Device:GD32E50x_StdPeripherals:MISC@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_MISC
/* GigaDevice::Device:GD32E50x_StdPeripherals:PMU@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_PMU
/* GigaDevice::Device:GD32E50x_StdPeripherals:RCU@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_RCU
/* GigaDevice::Device:GD32E50x_StdPeripherals:TIMER@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_TIMER
/* GigaDevice::Device:GD32E50x_StdPeripherals:USART@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_USART
#endif /* RTE_COMPONENTS_H */
+266
View File
@@ -0,0 +1,266 @@
#include "Can.h"
#include "sys/OTA.h"
#include "sys/config.h"
#include "gd32e50x.h"
#include "gd32e50x_can.h"
#include "gd32e50x_gpio.h"
#include "gd32e50x_rcu.h"
#include "gd32e50x_misc.h"
#include <string.h>
CAN_transmiter CAN0_transmiter;
extern OTAHandler ota;
#define CAN_TX_QUEUE_SIZE 8
typedef struct {
u32 id;
u8 length;
u8 data[64];
u8 valid;
} can_tx_queue_item_t;
static can_tx_queue_item_t tx_queue[CAN_TX_QUEUE_SIZE];
static volatile u8 tx_queue_head = 0;
static volatile u8 tx_queue_tail = 0;
static volatile u8 tx_queue_count = 0;
static can_trasnmit_message_struct queue_transmit_message;
u8 can_gpio_init(void) {
rcu_periph_clock_enable(RCU_CAN0);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_AF);
gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_pin_remap_config(GPIO_CAN0_PARTIAL_REMAP, ENABLE);
gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
gpio_bit_reset(GPIOB, GPIO_PIN_13);
return 0;
}
void can_dma_init(void) {
/* Reserved: current receive path uses direct FIFO read to avoid DMA race. */
}
void canfd_config(void) {
can_parameter_struct can_parameter;
can_fdframe_struct can_fd_parameter;
can_fd_tdc_struct can_fd_tdc_parameter;
can_filter_parameter_struct can_filter;
can_gpio_init();
can_dma_init();
can_deinit(CAN0);
can_struct_para_init(CAN_INIT_STRUCT, &can_parameter);
can_parameter.time_triggered = DISABLE;
can_parameter.auto_bus_off_recovery = DISABLE;
can_parameter.auto_wake_up = DISABLE;
can_parameter.auto_retrans = ENABLE;
can_parameter.rec_fifo_overwrite = ENABLE;
can_parameter.trans_fifo_order = ENABLE;
can_parameter.working_mode = CAN_NORMAL_MODE;
can_parameter.resync_jump_width = CAN_BT_SJW_1TQ;
can_parameter.time_segment_1 = CAN_BT_BS1_7TQ;
can_parameter.time_segment_2 = CAN_BT_BS2_2TQ;
can_parameter.prescaler = 6;
can_init(CAN0, &can_parameter);
can_struct_para_init(CAN_FD_FRAME_STRUCT, &can_fd_parameter);
can_fd_parameter.fd_frame = ENABLE;
can_fd_parameter.excp_event_detect = ENABLE;
can_fd_parameter.delay_compensation = ENABLE;
can_fd_tdc_parameter.tdc_filter = 0x04;
can_fd_tdc_parameter.tdc_mode = CAN_TDCMOD_CALC_AND_OFFSET;
can_fd_tdc_parameter.tdc_offset = 0x04;
can_fd_parameter.p_delay_compensation = &can_fd_tdc_parameter;
can_fd_parameter.iso_bosch = CAN_FDMOD_ISO;
can_fd_parameter.esi_mode = CAN_ESIMOD_HARDWARE;
can_fd_parameter.data_resync_jump_width = CAN_BT_SJW_1TQ;
can_fd_parameter.data_time_segment_1 = CAN_BT_BS1_3TQ;
can_fd_parameter.data_time_segment_2 = CAN_BT_BS2_1TQ;
can_fd_parameter.data_prescaler = 6;
can_fd_init(CAN0, &can_fd_parameter);
can_struct_para_init(CAN_FILTER_STRUCT, &can_filter);
can_filter.filter_mode = CAN_FILTERMODE_MASK;
can_filter.filter_bits = CAN_FILTERBITS_32BIT;
can_filter.filter_list_high = 0x0000;
can_filter.filter_list_low = 0x0000;
can_filter.filter_mask_high = 0x0000;
can_filter.filter_mask_low = 0x0000;
can_filter.filter_fifo_number = CAN_FIFO0;
can_filter.filter_enable = ENABLE;
can_filter.filter_number = 0;
can_filter_init(CAN0, &can_filter);
nvic_irq_enable(CAN0_RX0_IRQn, 1U, 0U);
nvic_irq_enable(CAN0_TX_IRQn, 1U, 1U);
can_interrupt_enable(CAN0, CAN_INTEN_RFNEIE0);
}
u8 CAN_transmiter::init(void) {
canfd_config();
can_struct_para_init(CAN_TX_MESSAGE_STRUCT, &transmit_message);
can_struct_para_init(CAN_RX_MESSAGE_STRUCT, &receive_message);
can0_receive_count = 0;
can0_send_flag = RESET;
memset(transmit_data, 0, sizeof(transmit_data));
return 0;
}
void CAN_transmiter::communication_check(void) {
if (SET == can0_send_flag) {
can0_send_flag = RESET;
}
if (can0_receive_count > 0) {
can0_receive_count--;
ota.handleOTAMessage(receive_message.rx_efid, receive_message.rx_data,
receive_message.rx_dlen);
}
}
static u8 CAN_TX_QueuePush(u32 id, u8 length, u8 *data) {
if (tx_queue_count >= CAN_TX_QUEUE_SIZE) {
return 0;
}
tx_queue[tx_queue_tail].id = id;
tx_queue[tx_queue_tail].length = length;
memset(tx_queue[tx_queue_tail].data, 0, sizeof(tx_queue[tx_queue_tail].data));
for (u8 i = 0; i < length && i < 64U; ++i) {
tx_queue[tx_queue_tail].data[i] = data[i];
}
tx_queue[tx_queue_tail].valid = 1U;
tx_queue_tail = (tx_queue_tail + 1U) % CAN_TX_QUEUE_SIZE;
tx_queue_count++;
return 1;
}
static u8 CAN_TX_QueuePop(can_tx_queue_item_t *item) {
if (tx_queue_count == 0U) {
return 0;
}
*item = tx_queue[tx_queue_head];
tx_queue[tx_queue_head].valid = 0U;
tx_queue_head = (tx_queue_head + 1U) % CAN_TX_QUEUE_SIZE;
tx_queue_count--;
return 1;
}
u8 CAN_transmiter::CANFD_AsyncSend(u32 id, u8 length, u8 *data) {
u8 valid_length = length;
if (!(CAN_CTL(CAN0) & CAN_CTL_DFZ)) {
return 0;
}
if (data == NULL) {
return 0;
}
if (length > 8U) {
if (length < 13U) valid_length = 12U;
else if (length < 17U) valid_length = 16U;
else if (length < 21U) valid_length = 20U;
else if (length < 25U) valid_length = 24U;
else if (length < 33U) valid_length = 32U;
else if (length < 49U) valid_length = 48U;
else if (length < 65U) valid_length = 64U;
else return 0;
}
transmit_message.tx_ft = CAN_FT_DATA;
transmit_message.tx_ff = CAN_FF_EXTENDED;
transmit_message.tx_efid = id;
transmit_message.tx_dlen = valid_length;
transmit_message.fd_flag = CAN_FDF_FDFRAME;
transmit_message.fd_brs = ENABLE;
transmit_message.fd_esi = DISABLE;
for (u8 i = 0; i < valid_length; ++i) {
transmit_message.tx_data[i] = (i < length) ? data[i] : 0U;
}
transmit_mailbox = can_message_transmit(CAN0, &transmit_message);
if (transmit_mailbox == CAN_NOMAILBOX) {
return CAN_TX_QueuePush(id, valid_length, data);
}
can_interrupt_enable(CAN0, CAN_INTEN_TMEIE);
return 1;
}
u8 CAN_transmiter::sendDATA_ACK(u32 packet_num, u8 *data) {
(void)packet_num;
memset(transmit_data, 0, sizeof(transmit_data));
transmit_data[0] = 0xBA;
transmit_data[1] = 0xC0;
for (int i = 2; i < 6; ++i) {
transmit_data[i] = data[i - 2];
}
return CANFD_AsyncSend(CANFD_OTA_ACK_ID, 6, transmit_data);
}
u8 CAN_transmiter::sendBackup() {
return CANFD_AsyncSend(CANFD_OTA_ACK_ID, 0, transmit_data);
}
u8 CAN_transmiter::sendDATA_ACK(u32 packet_num, bool if_success) {
(void)packet_num;
memset(transmit_data, 0, 4);
if (if_success) {
transmit_data[0] = 0x01;
transmit_data[1] = 0x00;
}
return CANFD_AsyncSend(CANFD_OTA_ACK_ID, 4, transmit_data);
}
void CAN0_RX0_IRQHandler(void) {
if (can_interrupt_flag_get(CAN0, CAN_INT_FLAG_RFL0) != RESET) {
can_interrupt_flag_clear(CAN0, CAN_INT_FLAG_RFL0);
can_receive_message_struct temp_message;
can_message_receive(CAN0, CAN_FIFO0, &temp_message);
if (temp_message.rx_efid == CANFD_OTA_DATA_ID ||
temp_message.rx_efid == CANFD_OTA_REQ_ID ||
temp_message.rx_efid == CANFD_OTA_ACK_ID ||
temp_message.rx_efid == CANFD_OTA_WAIT_ID ||
temp_message.rx_efid == CANFD_OTA_CANCEL_ID) {
CAN0_transmiter.receive_message = temp_message;
if (CAN0_transmiter.can0_receive_count < 255U) {
CAN0_transmiter.can0_receive_count++;
}
}
}
if (can_interrupt_flag_get(CAN0, CAN_INT_FLAG_RFF0) != RESET) {
can_interrupt_flag_clear(CAN0, CAN_INT_FLAG_RFF0);
}
if (can_interrupt_flag_get(CAN0, CAN_INT_FLAG_RFO0) != RESET) {
can_interrupt_flag_clear(CAN0, CAN_INT_FLAG_RFO0);
}
}
void CAN0_TX_IRQHandler(void) {
if (can_flag_get(CAN0, CAN_FLAG_TME0) != RESET ||
can_flag_get(CAN0, CAN_FLAG_TME1) != RESET ||
can_flag_get(CAN0, CAN_FLAG_TME2) != RESET) {
can_tx_queue_item_t next_msg;
if (CAN_TX_QueuePop(&next_msg)) {
queue_transmit_message.tx_ft = CAN_FT_DATA;
queue_transmit_message.tx_ff = CAN_FF_EXTENDED;
queue_transmit_message.tx_efid = next_msg.id;
queue_transmit_message.tx_dlen = next_msg.length;
queue_transmit_message.fd_flag = CAN_FDF_FDFRAME;
queue_transmit_message.fd_brs = ENABLE;
queue_transmit_message.fd_esi = DISABLE;
for (u8 i = 0; i < next_msg.length; ++i) {
queue_transmit_message.tx_data[i] = next_msg.data[i];
}
can_message_transmit(CAN0, &queue_transmit_message);
} else {
can_interrupt_disable(CAN0, CAN_INTEN_TMEIE);
}
can_flag_clear(CAN0, CAN_FLAG_TME0);
can_flag_clear(CAN0, CAN_FLAG_TME1);
can_flag_clear(CAN0, CAN_FLAG_TME2);
}
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef _CAN_H
#define _CAN_H
#include <stdint.h>
#include "sys/config.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "gd32e50x_can.h"
#include <stdio.h>
u8 can_gpio_init(void);
void canfd_config(void);
void can_dma_init(void);
void CAN0_RX0_IRQHandler(void);
void CAN0_TX_IRQHandler(void);
class CAN_transmiter {
private:
can_trasnmit_message_struct transmit_message;
u8 transmit_mailbox = CAN_NOMAILBOX;
u8 transmit_data[64];
public:
u8 init(void);
can_receive_message_struct receive_message;
volatile u8 can0_receive_count;
volatile FlagStatus can0_send_flag;
void communication_check();
u8 CANFD_AsyncSend(u32 ID, u8 length, u8 *data);
u8 sendDATA_ACK(u32 packet_num, bool if_success);
u8 sendDATA_ACK(u32 packet_num, u8 *data);
u8 sendBackup();
};
#ifdef __cplusplus
}
#endif
#endif
+75
View File
@@ -0,0 +1,75 @@
#include "main.h"
#include "device/Can.h"
#include "sys/config.h"
#include "gd32e50x.h"
#include "sys/OTA.h"
#include "sys/initial.h"
#include "sys/systick.h"
extern CAN_transmiter CAN0_transmiter;
extern OTAHandler ota;
BootloaderSystem sys;
void BootloaderSystem::initHardware() {
systick_config();
USART0_init();
CAN0_transmiter.init();
check_sleep();
}
void BootloaderSystem::run() {
volatile uint32_t *flash_ptr = (volatile uint32_t *)n_APP_LATEST_EN_ADDR;
uint32_t app_enable = *flash_ptr;
flash_ptr = (volatile uint32_t *)n_APP_LATEST_CHECK_ADDR;
uint32_t app_check = *flash_ptr;
if (app_check == OTA_AVAL && app_enable == OTA_AVAL) {
ota.jumpToApplication();
} else if (app_check == OTA_AVAL && app_enable == OTA_NOT_AVAL) {
uint32_t delay_count = 0;
int ota_requested = 0;
while (delay_count < APP_DELAY_BOOT_TIME) {
CAN0_transmiter.communication_check();
ota.process();
if (ota.isActive()) {
ota_requested = 1;
break;
}
delay_1ms(10);
delay_count += 10;
}
if (ota_requested) {
while (1) {
CAN0_transmiter.communication_check();
ota.process();
}
} else {
ota.jumpToApplication();
}
} else {
flash_ptr = (volatile uint32_t *)n_APP_BACKUP_AVAL_ADDR;
uint32_t back_aval = *flash_ptr;
flash_ptr = (volatile uint32_t *)n_APP_BACKUP_CHECK_ADDR;
uint32_t back_check = *flash_ptr;
if (back_check == OTA_AVAL && back_aval == OTA_AVAL) {
CAN0_transmiter.sendBackup();
move_app_data();
ota.jumpToApplication();
} else {
while (1) {
CAN0_transmiter.communication_check();
ota.process();
}
}
}
}
int main(void) {
sys.initHardware();
sys.run();
while (1) {
}
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef MAIN_H
#define MAIN_H
#include <stdint.h>
class BootloaderSystem {
public:
void initHardware();
void run();
};
#endif
+411
View File
@@ -0,0 +1,411 @@
#include "OTA.h"
#include "Can.h"
#include "aes128.h"
#include "config.h"
#include "core_cm33.h"
#include "gd32e50x.h"
#include "gd32e50x_can.h"
#include "gd32e50x_crc.h"
#include "gd32e50x_fmc.h"
#include "gd32e50x_rcu.h"
#include "initial.h"
#include "systick.h"
#include <stdio.h>
#include <string.h>
extern CAN_transmiter CAN0_transmiter;
OTAHandler ota;
static inline fmc_state_enum write_ADDRESS(u32 address, u32 data) {
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);
fmc_state_enum status = fmc_word_program(address, data);
fmc_lock();
return status;
}
u8 OTA_SET(u32 addr, u32 data) {
fmc_state_enum fmc_status;
u32 temp_val[OTA_CONFIG_NUM];
volatile u32 *flash_ptr = (volatile u32 *)addr;
temp_val[0] = *flash_ptr;
if (temp_val[0] == data) {
return FLASH_EEPROM_OK;
}
if (data == OTA_AVAL) {
fmc_status = write_ADDRESS(addr, data);
if (fmc_status == FMC_READY) {
return FLASH_EEPROM_OK;
}
}
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
temp_val[0] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
temp_val[1] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_EN_ADDR;
temp_val[2] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_EN_ADDR;
temp_val[3] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
temp_val[4] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
temp_val[5] = *flash_ptr;
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);
fmc_status = fmc_page_erase(OTA_CONFIG_PAGE_ADDR);
if (fmc_status != FMC_READY) {
fmc_lock();
return FLASH_EEPROM_ERROR;
}
for (int i = 0; i < OTA_CONFIG_NUM; ++i) {
u32 current_addr = n_APP_LATEST_AVAL_ADDR + 4U * (u32)i;
if (current_addr != addr && temp_val[i] != OTA_NOT_AVAL) {
fmc_status = fmc_word_program(current_addr, temp_val[i]);
if (fmc_status != FMC_READY) {
fmc_lock();
return FLASH_EEPROM_ERROR;
}
}
}
if (data != OTA_NOT_AVAL) {
fmc_status = fmc_word_program(addr, data);
if (fmc_status != FMC_READY) {
fmc_lock();
return FLASH_EEPROM_ERROR;
}
}
fmc_lock();
return FLASH_EEPROM_OK;
}
static inline uint32_t extract_u32_from_4bytes(const uint8_t *array) {
return ((uint32_t)array[3] << 24) | ((uint32_t)array[2] << 16) |
((uint32_t)array[1] << 8) | (uint32_t)array[0];
}
void OTAHandler::init() {
}
void OTAHandler::process() {
if (pending_flash_erase) {
pending_flash_erase = false;
eraseApplicationArea();
ota_state = OTA_STATE_RECEIVING_FIRMWARE;
}
if (ota_state == OTA_STATE_IDLE) {
ota_time = 0;
static u8 zero[1] = {0};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_WAIT_ID, 0, zero);
delay_1ms(10);
return;
} else {
delay_1us(100);
ota_time++;
}
if (ota_time > OTA_TIMEOUT) {
ota_time = 0;
ota_state = OTA_STATE_IDLE;
ota_error = OTA_ERROR_TIMEOUT;
volatile u32 *flash_ptr = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
u32 if_checked = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
u32 if_aval = *flash_ptr;
send_error_frame(OTA_ERROR_TIMEOUT);
if (if_checked == OTA_AVAL && if_aval == OTA_AVAL) {
OTA_SET(n_APP_LATEST_AVAL_ADDR, OTA_AVAL);
jumpToApplication();
}
}
}
bool validateApplication() {
u32 *app_vector = (u32 *)APPLATEST_START_ADDR;
u32 stack_ptr = app_vector[0];
u32 reset_handler = app_vector[1];
bool stack_valid = (stack_ptr >= 0x20000000U && stack_ptr < 0x20020000U);
bool reset_valid = (reset_handler >= APPLATEST_START_ADDR &&
reset_handler < (APPLATEST_START_ADDR + APP_MAX_SIZE));
return stack_valid && reset_valid;
}
void OTAHandler::jumpToApplication() {
if (!validateApplication()) {
return;
}
OTA_SET(n_APP_LATEST_AVAL_ADDR, OTA_AVAL);
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_AVAL);
for (int i = 0; i < 8; ++i) {
NVIC->ICER[i] = 0xFFFFFFFFU;
NVIC->ICPR[i] = 0xFFFFFFFFU;
}
can_deinit(CAN0);
rcu_system_clock_source_config(RCU_CKSYSSRC_IRC8M);
rcu_periph_clock_disable(RCU_GPIOA);
rcu_periph_clock_disable(RCU_GPIOB);
rcu_periph_clock_disable(RCU_GPIOC);
rcu_periph_clock_disable(RCU_USART0);
rcu_periph_clock_disable(RCU_CAN0);
rcu_periph_clock_disable(RCU_TIMER0);
rcu_periph_clock_disable(RCU_DMA0);
SCB->VTOR = APPLATEST_START_ADDR;
uint32_t msp_value = *(__IO uint32_t *)APPLATEST_START_ADDR;
uint32_t reset_handler = *(__IO uint32_t *)(APPLATEST_START_ADDR + 4U);
typedef void (*AppEntryFunc)(void);
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
__set_MSP(msp_value);
rcu_all_reset_flag_clear();
app_entry();
}
void OTAHandler::eraseApplicationArea() {
OTA_SET(n_APP_LATEST_CHECK_ADDR, OTA_NOT_AVAL);
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_NOT_AVAL);
OTA_SET(n_APP_LATEST_AVAL_ADDR, OTA_NOT_AVAL);
__disable_irq();
fmc_unlock();
for (u32 addr = APPLATEST_START_ADDR;
addr < (APPLATEST_START_ADDR + APP_MAX_SIZE); addr += FMC_PAGE_SIZE) {
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);
fmc_state_enum status = fmc_page_erase(addr);
if (status != FMC_READY) {
ota_error = OTA_ERROR_FLASH_ERROR;
send_error_frame(OTA_ERROR_FLASH_ERROR);
break;
}
}
fmc_lock();
__enable_irq();
}
void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
fmc_unlock();
u32 write_addr = APPLATEST_START_ADDR + offset;
u32 i = 0;
for (; i + 4U <= size; i += 4U) {
(void)fmc_word_program(write_addr + i, *(u32 *)&data[i]);
}
if (i < size) {
u32 word = 0xFFFFFFFFU;
memcpy(&word, &data[i], size - i);
(void)fmc_word_program(write_addr + i, word);
}
fmc_lock();
}
void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
if (id == CANFD_OTA_CANCEL_ID) {
ota_state = OTA_STATE_IDLE;
ota_time = 0;
ota_error = OTA_ERROR_NONE;
return;
} else if (id == CANFD_OTA_DATA_ID) {
ota_time = 0;
if (len == 64U && ota_state == OTA_STATE_RECEIVING_FIRMWARE) {
u32 receive_session_num = extract_u32_from_4bytes(data);
(void)receive_session_num;
u32 receive_packet_num = extract_u32_from_4bytes(data + 4);
u32 receive_IFEND = extract_u32_from_4bytes(data + 56);
const u8 *receive_encrypted_data = data + 8;
const u8 *receive_dataCRC32 = data + 60;
u8 decrypted_data[OTA_PACKET_SIZE];
u8 calculated_dataCRC32[4];
aes128_set_key(&aes_ctx, current_K_session);
aes128_ecb_decrypt_48bytes(&aes_ctx, receive_encrypted_data, decrypted_data);
calculate_crc32_with_key(current_K_session, decrypted_data, calculated_dataCRC32);
if (memcmp(receive_dataCRC32, calculated_dataCRC32, SIZE_U32) != 0) {
ota_error = OTA_ERROR_INVALID_CRC;
send_error_frame(OTA_ERROR_INVALID_CRC);
receive_packet_num -= 1U;
} else {
u32 offset = receive_packet_num * OTA_PACKET_SIZE;
if (offset + OTA_PACKET_SIZE <= APP_MAX_SIZE) {
writeApplicationData(offset, decrypted_data, OTA_PACKET_SIZE);
} else {
ota_error = OTA_ERROR_INVALID_SIZE;
ota_state = OTA_STATE_IDLE;
send_error_frame(OTA_ERROR_INVALID_SIZE);
}
}
if (receive_IFEND == 0xFFFFFFFFU) {
u8 pack_number[4] = {0xFF, 0xFF, 0xFF, 0xFF};
CAN0_transmiter.sendDATA_ACK(CANFD_OTA_ACK_ID, pack_number);
ota_state = OTA_STATE_FINISHED;
jumpToApplication();
return;
}
u32 request_packet = receive_packet_num + 1U;
u8 pack_number[4];
memcpy(pack_number, &request_packet, 4);
CAN0_transmiter.sendDATA_ACK(CANFD_OTA_ACK_ID, pack_number);
} else if (len == 4U && ota_state == OTA_STATE_CHECKING_FIRMWARE) {
u32 new_size = *(u32 *)data;
if (new_size <= APP_MAX_SIZE) {
expected_size = new_size;
received_size = 0;
} else {
ota_error = OTA_ERROR_INVALID_SIZE;
ota_state = OTA_STATE_IDLE;
send_error_frame(OTA_ERROR_INVALID_SIZE);
return;
}
pending_flash_erase = true;
u8 send_data[6] = {0xBA, 0xC0, 0x00, 0x00, 0x00, 0x00};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 6, send_data);
} else if (len == 2U && ota_state == OTA_STATE_FINISHED) {
} else {
ota_error = OTA_ERROR_INVALID_PACKET;
ota_state = OTA_STATE_IDLE;
send_error_frame(OTA_ERROR_INVALID_PACKET);
}
} else if (id == CANFD_OTA_REQ_ID) {
ota_time = 0;
if (data[0] == 0x00U && data[1] == 0xACU && len == 2U && ota_state == OTA_STATE_IDLE) {
u8 send_data[2] = {0x00, 0xAC};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, send_data);
ota_state = OTA_STATE_WAITING_RANDOM;
} else if (len == 16U && ota_state == OTA_STATE_WAITING_RANDOM) {
for (u8 i = 0; i < 16U; ++i) {
nonce_server[i] = data[i];
}
getDeviceSerialNumber(device_uid);
aes128_set_key(&aes_ctx, K_master);
u8 K_session[16];
aes128_encrypt_block(&aes_ctx, nonce_server, K_session);
u8 encrypted_Ksession[16];
u8 temp_block[AES_BLOCK_SIZE];
aes128_encrypt_block(&aes_ctx, K_session, temp_block);
memcpy(encrypted_Ksession, temp_block, 16);
u8 handshake_response[36];
memcpy(handshake_response, device_uid, 12);
memcpy(handshake_response + 12, nonce_server + 8, 8);
memcpy(handshake_response + 20, encrypted_Ksession, 16);
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 36, handshake_response);
memcpy(current_K_session, K_session, 16);
ota_state = OTA_STATE_WAITING_CONFIRM;
} else if (len == 16U && ota_state == OTA_STATE_WAITING_CONFIRM) {
u8 plaintext[16];
u8 expected[16];
u8 encrypted_confirm[16];
memcpy(encrypted_confirm, data, 16);
aes128_set_key(&aes_ctx, current_K_session);
aes128_decrypt_block(&aes_ctx, encrypted_confirm, plaintext);
for (int i = 0; i < 16; ++i) {
expected[i] = nonce_server[i] ^ 0x55U;
}
if (memcmp(plaintext, expected, 16) != 0) {
ota_error = OTA_ERROR_INVALID_KEY;
ota_state = OTA_STATE_IDLE;
send_error_frame(OTA_ERROR_INVALID_KEY);
return;
}
u8 send_data[2] = {0xBA, 0xC0};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, send_data);
ota_state = OTA_STATE_CHECKING_FIRMWARE;
} else {
ota_error = OTA_ERROR_INVALID_HANDSHAKE;
ota_state = OTA_STATE_IDLE;
send_error_frame(OTA_ERROR_INVALID_HANDSHAKE);
return;
}
}
}
void send_error_frame(u8 error) {
u8 error_frame[1] = {error};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 1, error_frame);
}
void getDeviceSerialNumber(u8 *buffer) {
volatile uint32_t *lsb = (volatile uint32_t *)DEVICE_SERIAL_ADDR_LSB;
volatile uint32_t *mid = (volatile uint32_t *)DEVICE_SERIAL_ADDR_MID;
volatile uint32_t *msb = (volatile uint32_t *)DEVICE_SERIAL_ADDR_MSB;
uint32_t serial_lsb = *lsb;
uint32_t serial_mid = *mid;
uint32_t serial_msb = *msb;
for (int i = 0; i < 4; ++i) {
buffer[i] = (u8)(serial_lsb >> (i * 8));
buffer[i + 4] = (u8)(serial_mid >> (i * 8));
buffer[i + 8] = (u8)(serial_msb >> (i * 8));
}
}
fmc_state_enum move_app_data() {
fmc_state_enum fmc_status = FMC_READY;
__disable_irq();
fmc_unlock();
uint32_t num_pages = (APP_MAX_SIZE + FMC_PAGE_SIZE - 1U) / FMC_PAGE_SIZE;
for (uint32_t i = 0; i < num_pages; ++i) {
uint32_t page_addr = APPLATEST_START_ADDR + i * FMC_PAGE_SIZE;
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);
fmc_status = fmc_page_erase(page_addr);
if (fmc_status != FMC_READY) {
fmc_lock();
__enable_irq();
return fmc_status;
}
}
crc_deinit();
crc_data_register_reset();
uint32_t src_crc = crc_block_data_calculate((void *)APPBACK_START_ADDR, APP_MAX_SIZE / 4U, INPUT_FORMAT_WORD);
for (uint32_t offset = 0; offset < APP_MAX_SIZE; offset += 4U) {
uint32_t src_data = *(uint32_t *)(APPBACK_START_ADDR + offset);
if (src_data != 0xFFFFFFFFU) {
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);
fmc_status = fmc_word_program(APPLATEST_START_ADDR + offset, src_data);
if (fmc_status != FMC_READY) {
fmc_lock();
__enable_irq();
return fmc_status;
}
}
}
fmc_lock();
__enable_irq();
crc_data_register_reset();
uint32_t dst_crc = crc_block_data_calculate((void *)APPLATEST_START_ADDR, APP_MAX_SIZE / 4U, INPUT_FORMAT_WORD);
if (src_crc != dst_crc) {
return (fmc_state_enum)0xFFU;
}
return fmc_status;
}
void calculate_crc32_with_key(const u8 *key, const u8 *data, u8 *output) {
uint32_t crc = 0xFFFFFFFFU;
for (int i = 0; i < 16; ++i) {
crc ^= key[i];
for (int j = 0; j < 8; ++j) {
crc = (crc >> 1) ^ (0xEDB88320U & (0U - (crc & 1U)));
}
}
for (u32 i = 0; i < OTA_PACKET_SIZE; ++i) {
crc ^= data[i];
for (int j = 0; j < 8; ++j) {
crc = (crc >> 1) ^ (0xEDB88320U & (0U - (crc & 1U)));
}
}
crc ^= 0xFFFFFFFFU;
output[0] = (u8)(crc & 0xFFU);
output[1] = (u8)((crc >> 8) & 0xFFU);
output[2] = (u8)((crc >> 16) & 0xFFU);
output[3] = (u8)((crc >> 24) & 0xFFU);
}
+68
View File
@@ -0,0 +1,68 @@
#ifndef __OTA_H
#define __OTA_H
#include "device/Can.h"
#include "aes128.h"
#include "config.h"
#include "gd32e50x.h"
#include <stdint.h>
class OTAHandler {
public:
u32 ota_stateota_time;
u32 received_size;
u32 expected_size;
void init();
void process();
bool isActive() const { return ota_state != OTA_STATE_IDLE; }
void handleOTAMessage(u32 id, u8 *data, u8 len);
void jumpToApplication();
private:
u32 ota_time;
void eraseApplicationArea();
void writeApplicationData(u32 offset, u8 *data, u32 size);
bool pending_flash_erase = false;
u32 pending_flash_offset = 0;
u8 pending_flash_data[64];
u8 pending_flash_size = 0;
typedef enum {
OTA_STATE_IDLE = 0,
OTA_STATE_WAITING_RANDOM,
OTA_STATE_WAITING_CONFIRM,
OTA_STATE_CHECKING_FIRMWARE,
OTA_STATE_RECEIVING_FIRMWARE,
OTA_STATE_FINISHED
} ota_state_t;
typedef enum {
OTA_ERROR_NONE = 0,
OTA_ERROR_TIMEOUT,
OTA_ERROR_FLASH_ERROR,
OTA_ERROR_INVALID_KEY,
OTA_ERROR_INVALID_PACKET,
OTA_ERROR_INVALID_HANDSHAKE,
OTA_ERROR_INVALID_CRC,
OTA_ERROR_INVALID_SIZE
} ota_error_t;
u8 device_uid[12];
u8 current_K_session[16];
u8 nonce_server[16];
aes128_context aes_ctx;
ota_state_t ota_state = OTA_STATE_IDLE;
ota_error_t ota_error = OTA_ERROR_NONE;
};
void getDeviceSerialNumber(u8 *buffer);
void calculate_crc32_with_key(const u8 *key, const u8 *data, u8 *output);
void send_error_frame(u8 error);
bool validateApplication();
fmc_state_enum move_app_data();
u8 OTA_SET(u32 addr, u32 data);
#endif
+373
View File
@@ -0,0 +1,373 @@
#include "aes128.h"
// S盒 (Substitution Box)
static const u8 sbox[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
0xb0, 0x54, 0xbb, 0x16};
// 逆S盒 (InvSBox)
const u8 inv_sbox[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e,
0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32,
0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49,
0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50,
0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05,
0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,
0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8,
0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b,
0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59,
0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63,
0x55, 0x21, 0x0c, 0x7d};
// 轮常量
static const u8 rcon[10] = {0x01, 0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x80, 0x1b, 0x36};
// 伽罗瓦域乘法 (xtime) - 确保正确
static u8 xtime(u8 x) { return (x << 1) ^ (((x >> 7) & 1) * 0x1b); }
// 关键修复:AES状态矩阵是列优先排列!
// 内存布局应该是:s00, s10, s20, s30, s01, s11, s21, s31, ...
// 而不是行优先
// 轮密钥加 - 无需修改
void add_round_key(u8 *state, const u8 *round_key) {
for (u8 i = 0; i < 16; i++) {
state[i] ^= round_key[i];
}
}
// 字节替换 - 无需修改
void sub_bytes(u8 *state) {
for (u8 i = 0; i < 16; i++) {
state[i] = sbox[state[i]];
}
}
// 行移位 - 修复为列优先排列
void shift_rows(u8 *state) {
u8 temp;
// AES状态矩阵(列优先):
// 列0: state[0], state[1], state[2], state[3] -> 行0,1,2,3
// 列1: state[4], state[5], state[6], state[7] -> 行0,1,2,3
// 列2: state[8], state[9], state[10], state[11] -> 行0,1,2,3
// 列3: state[12], state[13], state[14], state[15] -> 行0,1,2,3
// 第1行(索引0,4,8,12)不移位
// 第2行(索引1,5,9,13)左移1位
temp = state[1];
state[1] = state[5];
state[5] = state[9];
state[9] = state[13];
state[13] = temp;
// 第3行(索引2,6,10,14)左移2位
temp = state[2];
state[2] = state[10];
state[10] = temp;
temp = state[6];
state[6] = state[14];
state[14] = temp;
// 第4行(索引3,7,11,15)左移3位
temp = state[3];
state[3] = state[15];
state[15] = state[11];
state[11] = state[7];
state[7] = temp;
}
// 列混合 - 修复为正确的实现
void mix_columns(u8 *state) {
u8 a[4], b[4];
// 处理每一列
for (u8 col = 0; col < 4; col++) {
// 获取当前列的4个字节
a[0] = state[col * 4 + 0];
a[1] = state[col * 4 + 1];
a[2] = state[col * 4 + 2];
a[3] = state[col * 4 + 3];
// 计算混合后的值
b[0] = xtime(a[0]) ^ xtime(a[1]) ^ a[1] ^ a[2] ^ a[3];
b[1] = a[0] ^ xtime(a[1]) ^ xtime(a[2]) ^ a[2] ^ a[3];
b[2] = a[0] ^ a[1] ^ xtime(a[2]) ^ xtime(a[3]) ^ a[3];
b[3] = xtime(a[0]) ^ a[0] ^ a[1] ^ a[2] ^ xtime(a[3]);
// 存回结果
state[col * 4 + 0] = b[0];
state[col * 4 + 1] = b[1];
state[col * 4 + 2] = b[2];
state[col * 4 + 3] = b[3];
}
}
// 伽罗瓦域乘法 (用于逆列混合)
static u8 gf_mul(u8 a, u8 b) {
u8 p = 0;
u8 high_bit;
while (b) {
if (b & 1) {
p ^= a;
}
high_bit = a & 0x80;
a <<= 1;
if (high_bit) {
a ^= 0x1b; // x^8 + x^4 + x^3 + x + 1
}
b >>= 1;
}
return p;
}
// 逆字节替换
void inv_sub_bytes(u8 *state) {
for (u8 i = 0; i < 16; i++) {
state[i] = inv_sbox[state[i]];
}
}
// 逆行移位 - 与shift_rows对应
void inv_shift_rows(u8 *state) {
u8 temp;
// 第2行右移1位
temp = state[13];
state[13] = state[9];
state[9] = state[5];
state[5] = state[1];
state[1] = temp;
// 第3行右移2位
temp = state[2];
state[2] = state[10];
state[10] = temp;
temp = state[6];
state[6] = state[14];
state[14] = temp;
// 第4行右移3位
temp = state[7];
state[7] = state[11];
state[11] = state[15];
state[15] = state[3];
state[3] = temp;
}
// 逆列混合 - 正确实现
void inv_mix_columns(u8 *state) {
u8 a[4], b[4];
// 处理每一列
for (u8 col = 0; col < 4; col++) {
// 获取当前列的4个字节
a[0] = state[col * 4 + 0];
a[1] = state[col * 4 + 1];
a[2] = state[col * 4 + 2];
a[3] = state[col * 4 + 3];
// 计算逆混合后的值
b[0] = gf_mul(0x0e, a[0]) ^ gf_mul(0x0b, a[1]) ^ gf_mul(0x0d, a[2]) ^
gf_mul(0x09, a[3]);
b[1] = gf_mul(0x09, a[0]) ^ gf_mul(0x0e, a[1]) ^ gf_mul(0x0b, a[2]) ^
gf_mul(0x0d, a[3]);
b[2] = gf_mul(0x0d, a[0]) ^ gf_mul(0x09, a[1]) ^ gf_mul(0x0e, a[2]) ^
gf_mul(0x0b, a[3]);
b[3] = gf_mul(0x0b, a[0]) ^ gf_mul(0x0d, a[1]) ^ gf_mul(0x09, a[2]) ^
gf_mul(0x0e, a[3]);
// 存回结果
state[col * 4 + 0] = b[0];
state[col * 4 + 1] = b[1];
state[col * 4 + 2] = b[2];
state[col * 4 + 3] = b[3];
}
}
// 密钥扩展 - 修复为标准实现
static void key_expansion(aes128_context *ctx) {
u8 temp[4];
u8 i, rcon_iter = 0;
// 复制原始密钥到第一轮密钥
memcpy(ctx->round_keys[0], ctx->key, 16);
// 生成10轮密钥
for (i = 1; i <= 10; i++) {
// 复制前一轮最后一列
temp[0] = ctx->round_keys[i - 1][12];
temp[1] = ctx->round_keys[i - 1][13];
temp[2] = ctx->round_keys[i - 1][14];
temp[3] = ctx->round_keys[i - 1][15];
// 字循环 (RotWord)
u8 t = temp[0];
temp[0] = temp[1];
temp[1] = temp[2];
temp[2] = temp[3];
temp[3] = t;
// 字节替换 (SubWord)
temp[0] = sbox[temp[0]];
temp[1] = sbox[temp[1]];
temp[2] = sbox[temp[2]];
temp[3] = sbox[temp[3]];
// 轮常量异或
temp[0] ^= rcon[i - 1];
// 生成新的第一列
ctx->round_keys[i][0] = ctx->round_keys[i - 1][0] ^ temp[0];
ctx->round_keys[i][1] = ctx->round_keys[i - 1][1] ^ temp[1];
ctx->round_keys[i][2] = ctx->round_keys[i - 1][2] ^ temp[2];
ctx->round_keys[i][3] = ctx->round_keys[i - 1][3] ^ temp[3];
// 生成其他列
for (u8 j = 1; j < 4; j++) {
ctx->round_keys[i][j * 4 + 0] =
ctx->round_keys[i][(j - 1) * 4 + 0] ^
ctx->round_keys[i - 1][j * 4 + 0];
ctx->round_keys[i][j * 4 + 1] =
ctx->round_keys[i][(j - 1) * 4 + 1] ^
ctx->round_keys[i - 1][j * 4 + 1];
ctx->round_keys[i][j * 4 + 2] =
ctx->round_keys[i][(j - 1) * 4 + 2] ^
ctx->round_keys[i - 1][j * 4 + 2];
ctx->round_keys[i][j * 4 + 3] =
ctx->round_keys[i][(j - 1) * 4 + 3] ^
ctx->round_keys[i - 1][j * 4 + 3];
}
}
}
// 设置密钥
void aes128_set_key(aes128_context *ctx, const u8 *key) {
memcpy(ctx->key, key, AES128_KEY_LEN);
key_expansion(ctx);
}
// 加密单个块
void aes128_encrypt_block(aes128_context *ctx, const u8 *input, u8 *output) {
// 复制输入到状态
memcpy(ctx->state, input, AES_BLOCK_SIZE);
// 初始轮密钥加
add_round_key(ctx->state, ctx->round_keys[0]);
// 9轮标准轮
for (u8 round = 1; round <= 9; round++) {
sub_bytes(ctx->state);
shift_rows(ctx->state);
mix_columns(ctx->state);
add_round_key(ctx->state, ctx->round_keys[round]);
}
// 最终轮 (没有mix_columns)
sub_bytes(ctx->state);
shift_rows(ctx->state);
add_round_key(ctx->state, ctx->round_keys[10]);
// 复制结果到输出
memcpy(output, ctx->state, AES_BLOCK_SIZE);
}
// ECB模式加密48字节数据
void aes128_ecb_encrypt_48bytes(aes128_context *ctx, const u8 *input,
u8 *output) {
// 分3块加密 (48 = 16 * 3)
aes128_encrypt_block(ctx, input, output);
aes128_encrypt_block(ctx, input + 16, output + 16);
aes128_encrypt_block(ctx, input + 32, output + 32);
}
// 解密单个块
void aes128_decrypt_block(aes128_context *ctx, const u8 *input, u8 *output) {
// 复制输入到状态
memcpy(ctx->state, input, AES_BLOCK_SIZE);
// 初始轮密钥加(使用最后一轮密钥)
add_round_key(ctx->state, ctx->round_keys[10]);
// 9轮标准解密轮
for (u8 round = 9; round >= 1; round--) {
inv_shift_rows(ctx->state);
inv_sub_bytes(ctx->state);
add_round_key(ctx->state, ctx->round_keys[round]);
inv_mix_columns(ctx->state);
}
// 最终轮(没有inv_mix_columns)
inv_shift_rows(ctx->state);
inv_sub_bytes(ctx->state);
add_round_key(ctx->state, ctx->round_keys[0]);
// 复制结果到输出
memcpy(output, ctx->state, AES_BLOCK_SIZE);
}
// ECB模式解密48字节数据
void aes128_ecb_decrypt_48bytes(aes128_context *ctx, const u8 *input,
u8 *output) {
// 分3块解密 (48 = 16 * 3)
aes128_decrypt_block(ctx, input, output);
aes128_decrypt_block(ctx, input + 16, output + 16);
aes128_decrypt_block(ctx, input + 32, output + 32);
}
// 验证函数:加密后解密,对比原始数据
u8 aes128_verify_encryption(aes128_context *ctx, const u8 *original_data,
size_t length) {
u8 temp_ciphertext[48];
u8 temp_plaintext[48];
u8 result = 1; // 1表示验证成功,0表示失败
// 1. 加密原始数据
aes128_ecb_encrypt_48bytes(ctx, original_data, temp_ciphertext);
// 2. 解密密文
aes128_ecb_decrypt_48bytes(ctx, temp_ciphertext, temp_plaintext);
// 3. 对比原始数据和解密后的数据
for (size_t i = 0; i < length; i++) {
if (original_data[i] != temp_plaintext[i]) {
result = 0; // 验证失败
break;
}
}
return result;
}
+41
View File
@@ -0,0 +1,41 @@
#ifndef __AES_H
#define __AES_H
#include "cstdint"
#include <string.h>
// AES-128 密钥长度 (16 bytes)
#define AES128_KEY_LEN 16
// AES 块大小 (16 bytes)
#define AES_BLOCK_SIZE 16
// AES 状态结构
typedef struct {
u8 key[AES128_KEY_LEN]; // 128位/16字节密钥
u8 round_keys[11][16]; // 10轮 + 初始轮密钥
u8 state[AES_BLOCK_SIZE]; // 状态矩阵
} aes128_context;
// 内部函数声明(需要在头文件中声明,因为解密函数会使用)
void add_round_key(u8 *state, const u8 *round_key);
void sub_bytes(u8 *state);
void shift_rows(u8 *state);
void mix_columns(u8 *state);
void inv_sub_bytes(u8 *state);
void inv_shift_rows(u8 *state);
void inv_mix_columns(u8 *state);
// 公共函数声明
void aes128_set_key(aes128_context *ctx, const u8 *key);
void aes128_encrypt_block(aes128_context *ctx, const u8 *input, u8 *output);
void aes128_ecb_encrypt_48bytes(aes128_context *ctx, const u8 *input,
u8 *output);
void aes128_decrypt_block(aes128_context *ctx, const u8 *input, u8 *output);
void aes128_ecb_decrypt_48bytes(aes128_context *ctx, const u8 *input,
u8 *output);
u8 aes128_verify_encryption(aes128_context *ctx, const u8 *original_data,
size_t length);
// 逆S盒 (用于解密)
extern const u8 inv_sbox[256];
#endif /* __AES_H */
+71
View File
@@ -0,0 +1,71 @@
#ifndef __CONFIG_H__
#define __CONFIG_H__
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
#define EEP_DEBUG 0
#define DEBUG_OTA 0
#define CAN_DEBUG 0
#define SLEEP_DEBUG 0
/* Flash layout for GD32E508VE 512KB boot project */
static const u32 BOOTLOADER_START_ADDR = 0x08000000U;
static const u32 BOOTLOADER_SIZE = 0x00012000U; /* 72KB */
static const u32 APPBACK_START_ADDR = 0x08012000U;
static const u32 APPLATEST_START_ADDR = 0x08046000U;
static const u32 APP_MAX_SIZE = 0x00018000U; /* 96KB */
static const u32 FMC_PAGE_SIZE = 0x00000800U; /* 2KB, GD32E50x */
static const u32 OTA_CONFIG_PAGE_ADDR = 0x0807E000U;
static const u32 SLEEP_CONFIG_START = 0x0807E800U;
static const u32 SLEEP_CONFIG_END = 0x0807F000U;
static const u32 FLASH_EMPTY = 0xFFFFFFFFU;
static const u32 SLEEP_ENABLE = 0x11111111U;
static const u32 SLEEP_DISABLE = 0x00000000U;
static const u32 OTA_CONFIG_NUM = 6U;
static const u32 n_APP_LATEST_AVAL_ADDR = OTA_CONFIG_PAGE_ADDR + 0x00U;
static const u32 n_APP_BACKUP_AVAL_ADDR = OTA_CONFIG_PAGE_ADDR + 0x04U;
static const u32 n_APP_LATEST_EN_ADDR = OTA_CONFIG_PAGE_ADDR + 0x08U;
static const u32 n_APP_BACKUP_EN_ADDR = OTA_CONFIG_PAGE_ADDR + 0x0CU;
static const u32 n_APP_LATEST_CHECK_ADDR = OTA_CONFIG_PAGE_ADDR + 0x10U;
static const u32 n_APP_BACKUP_CHECK_ADDR = OTA_CONFIG_PAGE_ADDR + 0x14U;
static const u32 OTA_NOT_AVAL = 0xFFFFFFFFU;
static const u32 OTA_AVAL = 0x00000000U;
static const u32 FLASH_EEPROM_OK = 0U;
static const u32 FLASH_EEPROM_ERROR = 1U;
static const u32 CANFD_OTA_REQ_ID = 0x00000100U;
static const u32 CANFD_OTA_DATA_ID = 0x00000101U;
static const u32 CANFD_OTA_ACK_ID = 0x00000102U;
static const u32 CANFD_OTA_WAIT_ID = 0x00000103U;
static const u32 CANFD_OTA_CANCEL_ID = 0x00000000U;
/* GD32E50x UID base address */
static const u32 DEVICE_SERIAL_ADDR_LSB = 0x1FFFF7ACU;
static const u32 DEVICE_SERIAL_ADDR_MID = 0x1FFFF7B0U;
static const u32 DEVICE_SERIAL_ADDR_MSB = 0x1FFFF7B4U;
static const u32 OTA_PACKET_SIZE = 48U;
typedef union {
u32 u;
u8 b[4];
} u32_union_t;
static const uint8_t K_master[16] = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
};
static const u32 OTA_TIMEOUT = 10000U;
static const u32 APP_DELAY_BOOT_TIME = 10000U;
static const u8 SIZE_U32 = sizeof(uint32_t);
static const u8 SIZE_FLOAT = sizeof(float);
#endif
+131
View File
@@ -0,0 +1,131 @@
#include "initial.h"
#include "OTA.h"
#include "config.h"
#include "core_cm33.h"
#include "gd32e50x.h"
#include "gd32e50x_exti.h"
#include "gd32e50x_fmc.h"
#include "gd32e50x_gpio.h"
#include "gd32e50x_pmu.h"
#include "gd32e50x_rcu.h"
#include "gd32e50x_usart.h"
#include "systick.h"
u8 USART0_init(void) {
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_USART0);
gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
usart_deinit(USART0);
usart_baudrate_set(USART0, 115200U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
return 1;
}
int fputc(int ch, FILE *f) throw() {
(void)f;
usart_data_transmit(USART0, (uint8_t)ch);
while (RESET == usart_flag_get(USART0, USART_FLAG_TBE)) {
}
return ch;
}
u16 get_reset_cause(void) {
return 0;
}
void unused_pin_init(void) {
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_GPIOC);
}
void print_system_clock_info(void) {
}
void scanAppFlashContent(int print_content, u32 page_count) {
(void)print_content;
(void)page_count;
}
static fmc_state_enum write_ADDRESS(u32 address, u32 data) {
fmc_unlock();
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR | FMC_FLAG_PGERR);
fmc_state_enum status = fmc_word_program(address, data);
fmc_lock();
return status;
}
void enter_deep_sleep(void) {
rcu_periph_clock_disable(RCU_TIMER0);
rcu_periph_clock_disable(RCU_TIMER1);
rcu_periph_clock_disable(RCU_ADC0);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_AF);
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOB, GPIO_PIN_SOURCE_8);
exti_init(EXTI_8, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_enable(EXTI_8);
nvic_irq_enable(EXTI5_9_IRQn, 0U, 0U);
exti_interrupt_flag_clear(EXTI_8);
__enable_irq();
delay_1ms(10U);
pmu_to_deepsleepmode(PMU_LDO_LOWPOWER, PMU_LOWDRIVER_DISABLE, WFI_CMD);
}
void EXTI5_9_IRQHandler(void) {
if (exti_interrupt_flag_get(EXTI_8) != RESET) {
exti_interrupt_flag_clear(EXTI_8);
exti_interrupt_disable(EXTI_8);
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_AVAL);
for (u32 address = SLEEP_CONFIG_END - SIZE_U32; address >= SLEEP_CONFIG_START; address -= SIZE_U32) {
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 sleep_check = *flash_ptr;
if (sleep_check == FLASH_EMPTY && address > SLEEP_CONFIG_START) {
continue;
} else if (sleep_check == SLEEP_ENABLE && address > SLEEP_CONFIG_START) {
if (address == SLEEP_CONFIG_END - SIZE_U32) {
fmc_unlock();
if (fmc_page_erase(SLEEP_CONFIG_START) != FMC_READY) {
fmc_lock();
return;
}
address = SLEEP_CONFIG_START - SIZE_U32;
}
(void)write_ADDRESS(address + SIZE_U32, SLEEP_DISABLE);
break;
} else if (sleep_check == SLEEP_DISABLE) {
break;
} else {
(void)write_ADDRESS(address, SLEEP_DISABLE);
break;
}
}
system_soft_reset();
}
}
int check_sleep(void) {
for (u32 address = SLEEP_CONFIG_END - SIZE_U32; address >= SLEEP_CONFIG_START; address -= SIZE_U32) {
volatile u32 *flash_ptr = (volatile u32 *)address;
u32 sleep_check = *flash_ptr;
if (sleep_check == FLASH_EMPTY) {
continue;
} else if (sleep_check == SLEEP_ENABLE) {
enter_deep_sleep();
return 0;
} else if (sleep_check == SLEEP_DISABLE) {
return 0;
}
}
if (write_ADDRESS(SLEEP_CONFIG_START, SLEEP_DISABLE) != FMC_READY) {
return 1;
}
return 2;
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef _INITIAL_H
#define _INITIAL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include "sys/config.h"
int fputc(int ch, FILE *f) throw();
u8 USART0_init(void);
u16 get_reset_cause(void);
void unused_pin_init(void);
void print_system_clock_info(void);
void enter_deep_sleep(void);
int check_sleep(void);
void EXTI5_9_IRQHandler(void);
void scanAppFlashContent(int print_content, u32 page_count);
#ifdef __cplusplus
}
#endif
#endif
+47
View File
@@ -0,0 +1,47 @@
#include "systick.h"
#include "gd32e50x.h"
static volatile uint32_t delay_countdown;
void systick_config(void) {
if (SysTick_Config(SystemCoreClock / 1000U)) {
while (1) {
}
}
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
void delay_1us(uint32_t count) {
uint32_t cycles = (SystemCoreClock / 4000000UL) * count;
for (uint32_t i = 0; i < cycles; ++i) {
__NOP();
}
}
void delay_1ms(uint32_t count) {
delay_countdown = count;
while (delay_countdown != 0U) {
}
}
void delay_1s(uint32_t count) {
while (count--) {
delay_1ms(1000U);
}
}
void delay_decrement(void) {
if (delay_countdown != 0U) {
delay_countdown--;
}
}
void SysTick_Handler(void) {
delay_decrement();
}
void system_soft_reset(void) {
NVIC_SystemReset();
while (1) {
}
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef SYSTICK_H
#define SYSTICK_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void systick_config(void);
void delay_1ms(uint32_t count);
void delay_1us(uint32_t count);
void delay_1s(uint32_t count);
void delay_decrement(void);
void system_soft_reset(void);
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,45 @@
# A project translates into one executable or library.
project:
groups:
- group: Source Files
files:
- file: ./main.c
# List executable file formats to be generated.
output:
type:
- elf
- hex
- map
packs:
- pack: ARM::CMSIS-DSP
- pack: ARM::CMSIS-NN
- pack: GigaDevice::GD32E50x_DFP
- pack: ARM::CMSIS
components:
- component: CMSIS:CORE
- component: Device:GD32E50x_StdPeripherals:ADC
- component: Device:GD32E50x_StdPeripherals:CAN
- component: Device:GD32E50x_StdPeripherals:CRC
- component: Device:GD32E50x_StdPeripherals:CTC
- component: Device:GD32E50x_StdPeripherals:DBG
- component: Device:GD32E50x_StdPeripherals:FMC
- component: Device:GD32E50x_StdPeripherals:MISC
- component: Device:GD32E50x_StdPeripherals:PMU
- component: Device:GD32E50x_StdPeripherals:RCU
- component: Device:GD32E50x_StdPeripherals:TIMER
- component: Device:GD32E50x_StdPeripherals:USART
- component: Device:GD32E50x_libopt
- component: Device:Startup
- component: Device:GD32E50x_StdPeripherals:DMA
misc:
- for-compiler: AC6
C-CPP:
- -DGD32E50X_CL
- -DGD32E50X
- -gdwarf-5
ASM:
- -DGD32E50X_CL
- -DGD32E50X
- -gdwarf-5
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* ----------------------------------------------------------------------------
Stack seal size definition
*----------------------------------------------------------------------------*/
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
#define __STACKSEAL_SIZE 8
#else
#define __STACKSEAL_SIZE 0
#endif
/*----------------------------------------------------------------------------
Scatter File Definitions definition
*----------------------------------------------------------------------------*/
LR_ROM0 __ROM0_BASE __ROM0_SIZE {
ER_ROM0 __ROM0_BASE __ROM0_SIZE {
*.o (RESET, +First)
*(InRoot$$Sections)
*(+RO +XO)
}
#if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
ER_CMSE_VENEER AlignExpr(+0, 32) (__ROM0_SIZE - AlignExpr(ImageLength(ER_ROM0), 32)) {
*(Veneer$$CMSE)
}
#endif
RW_NOINIT __RAM0_BASE UNINIT (__RAM0_SIZE - __HEAP_SIZE - __STACK_SIZE - __STACKSEAL_SIZE) {
*.o(.bss.noinit)
*.o(.bss.noinit.*)
}
RW_RAM0 AlignExpr(+0, 8) (__RAM0_SIZE - __HEAP_SIZE - __STACK_SIZE - __STACKSEAL_SIZE - AlignExpr(ImageLength(RW_NOINIT), 8)) {
*(+RW +ZI)
}
#if __HEAP_SIZE > 0
ARM_LIB_HEAP (AlignExpr(+0, 8)) EMPTY __HEAP_SIZE { ; Reserve empty region for heap
}
#endif
ARM_LIB_STACK (__RAM0_BASE + __RAM0_SIZE - __STACKSEAL_SIZE) EMPTY -__STACK_SIZE { ; Reserve empty region for stack
}
#if __STACKSEAL_SIZE > 0
STACKSEAL +0 EMPTY __STACKSEAL_SIZE { ; Reserve empty region for stack seal immediately after stack
}
#endif
#if __RAM1_SIZE > 0
RW_RAM1 __RAM1_BASE __RAM1_SIZE {
.ANY (+RW +ZI)
}
#endif
#if __RAM2_SIZE > 0
RW_RAM2 __RAM2_BASE __RAM2_SIZE {
.ANY (+RW +ZI)
}
#endif
#if __RAM3_SIZE > 0
RW_RAM3 __RAM3_BASE __RAM3_SIZE {
.ANY (+RW +ZI)
}
#endif
}
#if __ROM1_SIZE > 0
LR_ROM1 __ROM1_BASE __ROM1_SIZE {
ER_ROM1 +0 __ROM1_SIZE {
.ANY (+RO +XO)
}
}
#endif
#if __ROM2_SIZE > 0
LR_ROM2 __ROM2_BASE __ROM2_SIZE {
ER_ROM2 +0 __ROM2_SIZE {
.ANY (+RO +XO)
}
}
#endif
#if __ROM3_SIZE > 0
LR_ROM3 __ROM3_BASE __ROM3_SIZE {
ER_ROM3 +0 __ROM3_SIZE {
.ANY (+RO +XO)
}
}
#endif
@@ -0,0 +1,239 @@
/*!
\file gd32e503z_eval.c
\brief firmware functions to manage leds, keys, COM ports
\version 2025-07-09, V1.6.1, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e503z_eval.h"
/* private variables */
static uint32_t GPIO_PORT[LEDn] = {LED1_GPIO_PORT, LED2_GPIO_PORT,
LED3_GPIO_PORT, LED4_GPIO_PORT};
static uint32_t GPIO_PIN[LEDn] = {LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN};
static rcu_periph_enum COM_CLK[COMn] = {EVAL_COM0_CLK};
static uint32_t COM_TX_PIN[COMn] = {EVAL_COM0_TX_PIN};
static uint32_t COM_RX_PIN[COMn] = {EVAL_COM0_RX_PIN};
static uint32_t COM_GPIO_PORT[COMn] = {EVAL_COM0_GPIO_PORT};
static rcu_periph_enum COM_GPIO_CLK[COMn] = {EVAL_COM0_GPIO_CLK};
static rcu_periph_enum GPIO_CLK[LEDn] = {LED1_GPIO_CLK, LED2_GPIO_CLK,
LED3_GPIO_CLK, LED4_GPIO_CLK};
static uint32_t KEY_PORT[KEYn] = {KEY_A_GPIO_PORT,
KEY_B_GPIO_PORT,
KEY_C_GPIO_PORT,
KEY_D_GPIO_PORT,
KEY_CET_GPIO_PORT};
static uint32_t KEY_PIN[KEYn] = {KEY_A_PIN,
KEY_B_PIN,
KEY_C_PIN,
KEY_D_PIN,
KEY_CET_PIN};
static rcu_periph_enum KEY_CLK[KEYn] = {KEY_A_GPIO_CLK,
KEY_B_GPIO_CLK,
KEY_C_GPIO_CLK,
KEY_D_GPIO_CLK,
KEY_CET_GPIO_CLK};
static exti_line_enum KEY_EXTI_LINE[KEYn] = {KEY_A_EXTI_LINE,
KEY_B_EXTI_LINE,
KEY_C_EXTI_LINE,
KEY_D_EXTI_LINE,
KEY_CET_EXTI_LINE};
static uint8_t KEY_PORT_SOURCE[KEYn] = {KEY_A_EXTI_PORT_SOURCE,
KEY_B_EXTI_PORT_SOURCE,
KEY_C_EXTI_PORT_SOURCE,
KEY_D_EXTI_PORT_SOURCE,
KEY_CET_EXTI_PORT_SOURCE};
static uint8_t KEY_PIN_SOURCE[KEYn] = {KEY_A_EXTI_PIN_SOURCE,
KEY_B_EXTI_PIN_SOURCE,
KEY_C_EXTI_PIN_SOURCE,
KEY_D_EXTI_PIN_SOURCE,
KEY_CET_EXTI_PIN_SOURCE};
static const IRQn_Type KEY_IRQn[KEYn] = {KEY_A_EXTI_IRQn,
KEY_B_EXTI_IRQn,
KEY_C_EXTI_IRQn,
KEY_D_EXTI_IRQn,
KEY_CET_EXTI_IRQn};
/*!
\brief configure led GPIO
\param[in] lednum: specify the led to be configured
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_init (led_typedef_enum lednum)
{
/* enable the led clock */
rcu_periph_clock_enable(GPIO_CLK[lednum]);
/* configure led GPIO port */
gpio_init(GPIO_PORT[lednum], GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,GPIO_PIN[lednum]);
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn on selected led
\param[in] lednum: specify the led to be turned on
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_on(led_typedef_enum lednum)
{
GPIO_BOP(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn off selected led
\param[in] lednum: specify the led to be turned off
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_off(led_typedef_enum lednum)
{
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief toggle selected led
\param[in] lednum: specify the led to be toggled
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_toggle(led_typedef_enum lednum)
{
gpio_bit_write(GPIO_PORT[lednum], GPIO_PIN[lednum],
(bit_status)(1-gpio_input_bit_get(GPIO_PORT[lednum], GPIO_PIN[lednum])));
}
/*!
\brief configure key
\param[in] key_num: specify the key to be configured
\arg KEY_A: wakeup key
\arg KEY_B: tamper key
\arg KEY_C: user key
\arg KEY_D: extension key
\arg KEY_CET: extension key
\param[in] key_mode: specify button mode
\arg KEY_MODE_GPIO: key will be used as simple IO
\arg KEY_MODE_EXTI: key will be connected to EXTI line with interrupt
\param[out] none
\retval none
*/
void gd_eval_key_init(key_typedef_enum key_num, keymode_typedef_enum key_mode)
{
/* enable the key clock */
rcu_periph_clock_enable(KEY_CLK[key_num]);
rcu_periph_clock_enable(RCU_AF);
/* configure button pin as input */
gpio_init(KEY_PORT[key_num], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, KEY_PIN[key_num]);
if(key_mode == KEY_MODE_EXTI) {
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(KEY_IRQn[key_num], 2U, 0U);
/* connect key EXTI line to key GPIO pin */
gpio_exti_source_select(KEY_PORT_SOURCE[key_num], KEY_PIN_SOURCE[key_num]);
/* configure key EXTI line */
exti_init(KEY_EXTI_LINE[key_num], EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(KEY_EXTI_LINE[key_num]);
}
}
/*!
\brief return the selected key state
\param[in] key: specify the key to be checked
\arg KEY_A: wakeup key
\arg KEY_B: tamper key
\arg KEY_C: user key
\arg KEY_D: extension key
\arg KEY_CET: extension key
\param[out] none
\retval the key's GPIO pin value
*/
uint8_t gd_eval_key_state_get(key_typedef_enum key)
{
return gpio_input_bit_get(KEY_PORT[key], KEY_PIN[key]);
}
/*!
\brief configure COM port
\param[in] com: COM on the board
\arg EVAL_COM0: COM0 on the board
\param[out] none
\retval none
*/
void gd_eval_com_init(uint32_t com)
{
uint32_t com_id = 0U;
if(EVAL_COM0 == com){
com_id = 0U;
}else{
while(1);
}
/* enable GPIO clock */
rcu_periph_clock_enable(COM_GPIO_CLK[com_id]);
/* enable USART clock */
rcu_periph_clock_enable(COM_CLK[com_id]);
/* connect port to USARTx_Tx */
gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, COM_TX_PIN[com_id]);
/* connect port to USARTx_Rx */
gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, COM_RX_PIN[com_id]);
/* USART configure */
usart_deinit(com);
usart_baudrate_set(com, 115200U);
usart_receive_config(com, USART_RECEIVE_ENABLE);
usart_transmit_config(com, USART_TRANSMIT_ENABLE);
usart_enable(com);
}
@@ -0,0 +1,239 @@
/*!
\file gd32e503z_eval.c
\brief firmware functions to manage leds, keys, COM ports
\version 2025-07-09, V1.6.1, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e503z_eval.h"
/* private variables */
static uint32_t GPIO_PORT[LEDn] = {LED1_GPIO_PORT, LED2_GPIO_PORT,
LED3_GPIO_PORT, LED4_GPIO_PORT};
static uint32_t GPIO_PIN[LEDn] = {LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN};
static rcu_periph_enum COM_CLK[COMn] = {EVAL_COM0_CLK};
static uint32_t COM_TX_PIN[COMn] = {EVAL_COM0_TX_PIN};
static uint32_t COM_RX_PIN[COMn] = {EVAL_COM0_RX_PIN};
static uint32_t COM_GPIO_PORT[COMn] = {EVAL_COM0_GPIO_PORT};
static rcu_periph_enum COM_GPIO_CLK[COMn] = {EVAL_COM0_GPIO_CLK};
static rcu_periph_enum GPIO_CLK[LEDn] = {LED1_GPIO_CLK, LED2_GPIO_CLK,
LED3_GPIO_CLK, LED4_GPIO_CLK};
static uint32_t KEY_PORT[KEYn] = {KEY_A_GPIO_PORT,
KEY_B_GPIO_PORT,
KEY_C_GPIO_PORT,
KEY_D_GPIO_PORT,
KEY_CET_GPIO_PORT};
static uint32_t KEY_PIN[KEYn] = {KEY_A_PIN,
KEY_B_PIN,
KEY_C_PIN,
KEY_D_PIN,
KEY_CET_PIN};
static rcu_periph_enum KEY_CLK[KEYn] = {KEY_A_GPIO_CLK,
KEY_B_GPIO_CLK,
KEY_C_GPIO_CLK,
KEY_D_GPIO_CLK,
KEY_CET_GPIO_CLK};
static exti_line_enum KEY_EXTI_LINE[KEYn] = {KEY_A_EXTI_LINE,
KEY_B_EXTI_LINE,
KEY_C_EXTI_LINE,
KEY_D_EXTI_LINE,
KEY_CET_EXTI_LINE};
static uint8_t KEY_PORT_SOURCE[KEYn] = {KEY_A_EXTI_PORT_SOURCE,
KEY_B_EXTI_PORT_SOURCE,
KEY_C_EXTI_PORT_SOURCE,
KEY_D_EXTI_PORT_SOURCE,
KEY_CET_EXTI_PORT_SOURCE};
static uint8_t KEY_PIN_SOURCE[KEYn] = {KEY_A_EXTI_PIN_SOURCE,
KEY_B_EXTI_PIN_SOURCE,
KEY_C_EXTI_PIN_SOURCE,
KEY_D_EXTI_PIN_SOURCE,
KEY_CET_EXTI_PIN_SOURCE};
static const IRQn_Type KEY_IRQn[KEYn] = {KEY_A_EXTI_IRQn,
KEY_B_EXTI_IRQn,
KEY_C_EXTI_IRQn,
KEY_D_EXTI_IRQn,
KEY_CET_EXTI_IRQn};
/*!
\brief configure led GPIO
\param[in] lednum: specify the led to be configured
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_init (led_typedef_enum lednum)
{
/* enable the led clock */
rcu_periph_clock_enable(GPIO_CLK[lednum]);
/* configure led GPIO port */
gpio_init(GPIO_PORT[lednum], GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ,GPIO_PIN[lednum]);
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn on selected led
\param[in] lednum: specify the led to be turned on
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_on(led_typedef_enum lednum)
{
GPIO_BOP(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief turn off selected led
\param[in] lednum: specify the led to be turned off
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_off(led_typedef_enum lednum)
{
GPIO_BC(GPIO_PORT[lednum]) = GPIO_PIN[lednum];
}
/*!
\brief toggle selected led
\param[in] lednum: specify the led to be toggled
\arg LED1
\arg LED2
\arg LED3
\arg LED4
\param[out] none
\retval none
*/
void gd_eval_led_toggle(led_typedef_enum lednum)
{
gpio_bit_write(GPIO_PORT[lednum], GPIO_PIN[lednum],
(bit_status)(1-gpio_input_bit_get(GPIO_PORT[lednum], GPIO_PIN[lednum])));
}
/*!
\brief configure key
\param[in] key_num: specify the key to be configured
\arg KEY_A: wakeup key
\arg KEY_B: tamper key
\arg KEY_C: user key
\arg KEY_D: extension key
\arg KEY_CET: extension key
\param[in] key_mode: specify button mode
\arg KEY_MODE_GPIO: key will be used as simple IO
\arg KEY_MODE_EXTI: key will be connected to EXTI line with interrupt
\param[out] none
\retval none
*/
void gd_eval_key_init(key_typedef_enum key_num, keymode_typedef_enum key_mode)
{
/* enable the key clock */
rcu_periph_clock_enable(KEY_CLK[key_num]);
rcu_periph_clock_enable(RCU_AF);
/* configure button pin as input */
gpio_init(KEY_PORT[key_num], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, KEY_PIN[key_num]);
if(key_mode == KEY_MODE_EXTI) {
/* enable and set key EXTI interrupt to the lowest priority */
nvic_irq_enable(KEY_IRQn[key_num], 2U, 0U);
/* connect key EXTI line to key GPIO pin */
gpio_exti_source_select(KEY_PORT_SOURCE[key_num], KEY_PIN_SOURCE[key_num]);
/* configure key EXTI line */
exti_init(KEY_EXTI_LINE[key_num], EXTI_INTERRUPT, EXTI_TRIG_FALLING);
exti_interrupt_flag_clear(KEY_EXTI_LINE[key_num]);
}
}
/*!
\brief return the selected key state
\param[in] key: specify the key to be checked
\arg KEY_A: wakeup key
\arg KEY_B: tamper key
\arg KEY_C: user key
\arg KEY_D: extension key
\arg KEY_CET: extension key
\param[out] none
\retval the key's GPIO pin value
*/
uint8_t gd_eval_key_state_get(key_typedef_enum key)
{
return gpio_input_bit_get(KEY_PORT[key], KEY_PIN[key]);
}
/*!
\brief configure COM port
\param[in] com: COM on the board
\arg EVAL_COM0: COM0 on the board
\param[out] none
\retval none
*/
void gd_eval_com_init(uint32_t com)
{
uint32_t com_id = 0U;
if(EVAL_COM0 == com){
com_id = 0U;
}else{
while(1);
}
/* enable GPIO clock */
rcu_periph_clock_enable(COM_GPIO_CLK[com_id]);
/* enable USART clock */
rcu_periph_clock_enable(COM_CLK[com_id]);
/* connect port to USARTx_Tx */
gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, COM_TX_PIN[com_id]);
/* connect port to USARTx_Rx */
gpio_init(COM_GPIO_PORT[com_id], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, COM_RX_PIN[com_id]);
/* USART configure */
usart_deinit(com);
usart_baudrate_set(com, 115200U);
usart_receive_config(com, USART_RECEIVE_ENABLE);
usart_transmit_config(com, USART_TRANSMIT_ENABLE);
usart_enable(com);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,239 @@
/*!
\file gd32e50x_crc.c
\brief CRC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_crc.h"
/*!
\brief deinitialize CRC calculation unit
\param[in] none
\param[out] none
\retval none
*/
void crc_deinit(void)
{
CRC_IDATA = (uint32_t)0xFFFFFFFFU;
CRC_DATA = (uint32_t)0xFFFFFFFFU;
CRC_FDATA = (uint32_t)0x00000000U;
CRC_POLY = (uint32_t)0x04C11DB7U;
CRC_CTL = CRC_CTL_RST;
}
/*!
\brief reset data register to the value of initializaiton data register
\param[in] none
\param[out] none
\retval none
*/
void crc_data_register_reset(void)
{
CRC_CTL |= (uint32_t)CRC_CTL_RST;
}
/*!
\brief enable the reverse operation of output data
\param[in] none
\param[out] none
\retval none
*/
void crc_reverse_output_data_enable(void)
{
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
CRC_CTL |= (uint32_t)CRC_CTL_REV_O;
}
/*!
\brief disable the reverse operation of output data
\param[in] none
\param[out] none
\retval none
*/
void crc_reverse_output_data_disable(void)
{
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
}
/*!
\brief configure the CRC input data function
\param[in] data_reverse: specify input data reverse function
only one parameter can be selected which is shown as below:
\arg CRC_INPUT_DATA_NOT: input data is not reversed
\arg CRC_INPUT_DATA_BYTE: input data is reversed on 8 bits
\arg CRC_INPUT_DATA_HALFWORD: input data is reversed on 16 bits
\arg CRC_INPUT_DATA_WORD: input data is reversed on 32 bits
\param[out] none
\retval none
*/
void crc_input_data_reverse_config(uint32_t data_reverse)
{
CRC_CTL &= (uint32_t)(~CRC_CTL_REV_I);
CRC_CTL |= (uint32_t)data_reverse;
}
/*!
\brief read the data register
\param[in] none
\param[out] none
\retval 32-bit value of the data register
*/
uint32_t crc_data_register_read(void)
{
uint32_t data;
data = CRC_DATA;
return (data);
}
/*!
\brief read the free data register
\param[in] none
\param[out] none
\retval 8-bit value of the free data register
*/
uint8_t crc_free_data_register_read(void)
{
uint8_t fdata;
fdata = (uint8_t)CRC_FDATA;
return (fdata);
}
/*!
\brief write the free data register
\param[in] free_data: specify 8-bit data
\param[out] none
\retval none
*/
void crc_free_data_register_write(uint8_t free_data)
{
CRC_FDATA = (uint32_t)free_data;
}
/*!
\brief write the initializaiton data register
\param[in] init_data: specify 32-bit data
\param[out] none
\retval none
*/
void crc_init_data_register_write(uint32_t init_data)
{
CRC_IDATA = (uint32_t)init_data;
}
/*!
\brief configure the CRC size of polynomial function
\param[in] poly_size: size of polynomial
only one parameter can be selected which is shown as below:
\arg CRC_CTL_PS_32: 32-bit polynomial for CRC calculation
\arg CRC_CTL_PS_16: 16-bit polynomial for CRC calculation
\arg CRC_CTL_PS_8: 8-bit polynomial for CRC calculation
\arg CRC_CTL_PS_7: 7-bit polynomial for CRC calculation
\param[out] none
\retval none
*/
void crc_polynomial_size_set(uint32_t poly_size)
{
CRC_CTL &= (uint32_t)(~(CRC_CTL_PS));
CRC_CTL |= (uint32_t)poly_size;
}
/*!
\brief configure the CRC polynomial value function
\param[in] poly: configurable polynomial value
\param[out] none
\retval none
*/
void crc_polynomial_set(uint32_t poly)
{
CRC_POLY &= (uint32_t)(~CRC_POLY_POLY);
CRC_POLY = poly;
}
/*!
\brief CRC calculate single data
\param[in] sdata: specify input data data
\param[in] data_format: input data format
only one parameter can be selected which is shown as below:
\arg INPUT_FORMAT_WORD: input data in word format
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
\arg INPUT_FORMAT_BYTE: input data in byte format
\param[out] none
\retval CRC calculate value
*/
uint32_t crc_single_data_calculate(uint32_t sdata, uint8_t data_format)
{
if(INPUT_FORMAT_WORD == data_format){
REG32(CRC) = sdata;
}else if(INPUT_FORMAT_HALFWORD == data_format){
REG16(CRC) = (uint16_t)sdata;
}else{
REG8(CRC) = (uint8_t)sdata;
}
return(CRC_DATA);
}
/*!
\brief CRC calculate a data array
\param[in] array: pointer to the input data array
\param[in] size: size of the array
\param[in] data_format: input data format
only one parameter can be selected which is shown as below:
\arg INPUT_FORMAT_WORD: input data in word format
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
\arg INPUT_FORMAT_BYTE: input data in byte format
\param[out] none
\retval CRC calculate value
*/
uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format)
{
uint32_t index;
uint32_t data = (uint32_t)array;
if(INPUT_FORMAT_WORD == data_format) {
for(index = 0U; index < size; index++) {
REG32(CRC) = *(uint32_t *)data;
data += 4U;
}
} else if(INPUT_FORMAT_HALFWORD == data_format) {
for(index = 0U; index < size; index++) {
REG16(CRC) = *(uint16_t *)data;
data += 2U;
}
} else {
for(index = 0U; index < size; index++) {
REG8(CRC) = *(uint8_t *)data;
data += 1U;
}
}
return (CRC_DATA);
}
@@ -0,0 +1,239 @@
/*!
\file gd32e50x_crc.c
\brief CRC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_crc.h"
/*!
\brief deinitialize CRC calculation unit
\param[in] none
\param[out] none
\retval none
*/
void crc_deinit(void)
{
CRC_IDATA = (uint32_t)0xFFFFFFFFU;
CRC_DATA = (uint32_t)0xFFFFFFFFU;
CRC_FDATA = (uint32_t)0x00000000U;
CRC_POLY = (uint32_t)0x04C11DB7U;
CRC_CTL = CRC_CTL_RST;
}
/*!
\brief reset data register to the value of initializaiton data register
\param[in] none
\param[out] none
\retval none
*/
void crc_data_register_reset(void)
{
CRC_CTL |= (uint32_t)CRC_CTL_RST;
}
/*!
\brief enable the reverse operation of output data
\param[in] none
\param[out] none
\retval none
*/
void crc_reverse_output_data_enable(void)
{
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
CRC_CTL |= (uint32_t)CRC_CTL_REV_O;
}
/*!
\brief disable the reverse operation of output data
\param[in] none
\param[out] none
\retval none
*/
void crc_reverse_output_data_disable(void)
{
CRC_CTL &= (uint32_t)(~ CRC_CTL_REV_O);
}
/*!
\brief configure the CRC input data function
\param[in] data_reverse: specify input data reverse function
only one parameter can be selected which is shown as below:
\arg CRC_INPUT_DATA_NOT: input data is not reversed
\arg CRC_INPUT_DATA_BYTE: input data is reversed on 8 bits
\arg CRC_INPUT_DATA_HALFWORD: input data is reversed on 16 bits
\arg CRC_INPUT_DATA_WORD: input data is reversed on 32 bits
\param[out] none
\retval none
*/
void crc_input_data_reverse_config(uint32_t data_reverse)
{
CRC_CTL &= (uint32_t)(~CRC_CTL_REV_I);
CRC_CTL |= (uint32_t)data_reverse;
}
/*!
\brief read the data register
\param[in] none
\param[out] none
\retval 32-bit value of the data register
*/
uint32_t crc_data_register_read(void)
{
uint32_t data;
data = CRC_DATA;
return (data);
}
/*!
\brief read the free data register
\param[in] none
\param[out] none
\retval 8-bit value of the free data register
*/
uint8_t crc_free_data_register_read(void)
{
uint8_t fdata;
fdata = (uint8_t)CRC_FDATA;
return (fdata);
}
/*!
\brief write the free data register
\param[in] free_data: specify 8-bit data
\param[out] none
\retval none
*/
void crc_free_data_register_write(uint8_t free_data)
{
CRC_FDATA = (uint32_t)free_data;
}
/*!
\brief write the initializaiton data register
\param[in] init_data: specify 32-bit data
\param[out] none
\retval none
*/
void crc_init_data_register_write(uint32_t init_data)
{
CRC_IDATA = (uint32_t)init_data;
}
/*!
\brief configure the CRC size of polynomial function
\param[in] poly_size: size of polynomial
only one parameter can be selected which is shown as below:
\arg CRC_CTL_PS_32: 32-bit polynomial for CRC calculation
\arg CRC_CTL_PS_16: 16-bit polynomial for CRC calculation
\arg CRC_CTL_PS_8: 8-bit polynomial for CRC calculation
\arg CRC_CTL_PS_7: 7-bit polynomial for CRC calculation
\param[out] none
\retval none
*/
void crc_polynomial_size_set(uint32_t poly_size)
{
CRC_CTL &= (uint32_t)(~(CRC_CTL_PS));
CRC_CTL |= (uint32_t)poly_size;
}
/*!
\brief configure the CRC polynomial value function
\param[in] poly: configurable polynomial value
\param[out] none
\retval none
*/
void crc_polynomial_set(uint32_t poly)
{
CRC_POLY &= (uint32_t)(~CRC_POLY_POLY);
CRC_POLY = poly;
}
/*!
\brief CRC calculate single data
\param[in] sdata: specify input data data
\param[in] data_format: input data format
only one parameter can be selected which is shown as below:
\arg INPUT_FORMAT_WORD: input data in word format
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
\arg INPUT_FORMAT_BYTE: input data in byte format
\param[out] none
\retval CRC calculate value
*/
uint32_t crc_single_data_calculate(uint32_t sdata, uint8_t data_format)
{
if(INPUT_FORMAT_WORD == data_format){
REG32(CRC) = sdata;
}else if(INPUT_FORMAT_HALFWORD == data_format){
REG16(CRC) = (uint16_t)sdata;
}else{
REG8(CRC) = (uint8_t)sdata;
}
return(CRC_DATA);
}
/*!
\brief CRC calculate a data array
\param[in] array: pointer to the input data array
\param[in] size: size of the array
\param[in] data_format: input data format
only one parameter can be selected which is shown as below:
\arg INPUT_FORMAT_WORD: input data in word format
\arg INPUT_FORMAT_HALFWORD: input data in half-word format
\arg INPUT_FORMAT_BYTE: input data in byte format
\param[out] none
\retval CRC calculate value
*/
uint32_t crc_block_data_calculate(void *array, uint32_t size, uint8_t data_format)
{
uint32_t index;
uint32_t data = (uint32_t)array;
if(INPUT_FORMAT_WORD == data_format) {
for(index = 0U; index < size; index++) {
REG32(CRC) = *(uint32_t *)data;
data += 4U;
}
} else if(INPUT_FORMAT_HALFWORD == data_format) {
for(index = 0U; index < size; index++) {
REG16(CRC) = *(uint16_t *)data;
data += 2U;
}
} else {
for(index = 0U; index < size; index++) {
REG8(CRC) = *(uint8_t *)data;
data += 1U;
}
}
return (CRC_DATA);
}
@@ -0,0 +1,388 @@
/*!
\file gd32e50x_ctc.c
\brief CTC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_ctc.h"
#define CTC_FLAG_MASK ((uint32_t)0x00000700U)
/* CTC register bit offset */
#define CTC_TRIMVALUE_OFFSET ((uint32_t)8U)
#define CTC_TRIM_VALUE_OFFSET ((uint32_t)8U)
#define CTC_REFCAP_OFFSET ((uint32_t)16U)
#define CTC_LIMIT_VALUE_OFFSET ((uint32_t)16U)
/*!
\brief reset CTC clock trim controller
\param[in] none
\param[out] none
\retval none
*/
void ctc_deinit(void)
{
/* reset CTC */
rcu_periph_reset_enable(RCU_CTCRST);
rcu_periph_reset_disable(RCU_CTCRST);
}
/*!
\brief enable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_enable(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_CNTEN;
}
/*!
\brief disable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_disable(void)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_CNTEN);
}
/*!
\brief configure the IRC48M trim value
\param[in] trim_value: 6-bit IRC48M trim value
\arg 0x00 - 0x3F
\param[out] none
\retval none
*/
void ctc_irc48m_trim_value_config(uint8_t trim_value)
{
/* clear TRIMVALUE bits */
CTC_CTL0 &= (~(uint32_t)CTC_CTL0_TRIMVALUE);
/* set TRIMVALUE bits */
CTC_CTL0 |= ((uint32_t)trim_value << CTC_TRIM_VALUE_OFFSET);
}
/*!
\brief generate software reference source sync pulse
\param[in] none
\param[out] none
\retval none
*/
void ctc_software_refsource_pulse_generate(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_SWREFPUL;
}
/*!
\brief configure hardware automatically trim mode
\param[in] hardmode:
only one parameter can be selected which is shown as below:
\arg CTC_HARDWARE_TRIM_MODE_ENABLE: hardware automatically trim mode enable
\arg CTC_HARDWARE_TRIM_MODE_DISABLE: hardware automatically trim mode disable
\param[out] none
\retval none
*/
void ctc_hardware_trim_mode_config(uint32_t hardmode)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_AUTOTRIM);
CTC_CTL0 |= (uint32_t)hardmode;
}
/*!
\brief configure reference signal source polarity
\param[in] polarity:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_POLARITY_FALLING: reference signal source polarity is falling edge
\arg CTC_REFSOURCE_POLARITY_RISING: reference signal source polarity is rising edge
\param[out] none
\retval none
*/
void ctc_refsource_polarity_config(uint32_t polarity)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPOL);
CTC_CTL1 |= (uint32_t)polarity;
}
/*!
\brief select reference signal source
\param[in] refs:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_GPIO: GPIO is selected
\arg CTC_REFSOURCE_LXTAL: LXTAL is selected
\param[out] none
\retval none
*/
void ctc_refsource_signal_select(uint32_t refs)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFSEL);
CTC_CTL1 |= (uint32_t)refs;
}
/*!
\brief configure reference signal source prescaler
\param[in] prescaler:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_PSC_OFF: reference signal not divided
\arg CTC_REFSOURCE_PSC_DIV2: reference signal divided by 2
\arg CTC_REFSOURCE_PSC_DIV4: reference signal divided by 4
\arg CTC_REFSOURCE_PSC_DIV8: reference signal divided by 8
\arg CTC_REFSOURCE_PSC_DIV16: reference signal divided by 16
\arg CTC_REFSOURCE_PSC_DIV32: reference signal divided by 32
\arg CTC_REFSOURCE_PSC_DIV64: reference signal divided by 64
\arg CTC_REFSOURCE_PSC_DIV128: reference signal divided by 128
\param[out] none
\retval none
*/
void ctc_refsource_prescaler_config(uint32_t prescaler)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPSC);
CTC_CTL1 |= (uint32_t)prescaler;
}
/*!
\brief configure clock trim base limit value
\param[in] limit_value: 8-bit clock trim base limit value
\arg 0x00 - 0xFF
\param[out] none
\retval none
*/
void ctc_clock_limit_value_config(uint8_t limit_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_CKLIM);
CTC_CTL1 |= (uint32_t)((uint32_t)limit_value << CTC_LIMIT_VALUE_OFFSET);
}
/*!
\brief configure CTC counter reload value
\param[in] reload_value: 16-bit CTC counter reload value
\arg 0x0000 - 0xFFFF
\param[out] none
\retval none
*/
void ctc_counter_reload_value_config(uint16_t reload_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_RLVALUE);
CTC_CTL1 |= (uint32_t)reload_value;
}
/*!
\brief read CTC counter capture value when reference sync pulse occurred
\param[in] none
\param[out] none
\retval the 16-bit CTC counter capture value
*/
uint16_t ctc_counter_capture_value_read(void)
{
uint16_t capture_value = 0U;
capture_value = (uint16_t)((CTC_STAT & CTC_STAT_REFCAP)>> CTC_REFCAP_OFFSET);
return (capture_value);
}
/*!
\brief read CTC trim counter direction when reference sync pulse occurred
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
\arg SET: CTC trim counter direction is down-counting
\arg RESET: CTC trim counter direction is up-counting
*/
FlagStatus ctc_counter_direction_read(void)
{
if(RESET != (CTC_STAT & CTC_STAT_REFDIR)){
return SET;
}else{
return RESET;
}
}
/*!
\brief read CTC counter reload value
\param[in] none
\param[out] none
\retval the 16-bit CTC counter reload value
*/
uint16_t ctc_counter_reload_value_read(void)
{
uint16_t reload_value = 0U;
reload_value = (uint16_t)(CTC_CTL1 & CTC_CTL1_RLVALUE);
return (reload_value);
}
/*!
\brief read the IRC48M trim value
\param[in] none
\param[out] none
\retval the 6-bit IRC48M trim value
*/
uint8_t ctc_irc48m_trim_value_read(void)
{
uint8_t trim_value = 0U;
trim_value = (uint8_t)((CTC_CTL0 & CTC_CTL0_TRIMVALUE) >> CTC_TRIMVALUE_OFFSET);
return (trim_value);
}
/*!
\brief get CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error bit
\arg CTC_FLAG_REFMISS: reference sync pulse miss
\arg CTC_FLAG_TRIMERR: trim value error bit
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_flag_get(uint32_t flag)
{
if(RESET != (CTC_STAT & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error bit
\arg CTC_FLAG_REFMISS: reference sync pulse miss
\arg CTC_FLAG_TRIMERR: trim value error bit
\param[out] none
\retval none
*/
void ctc_flag_clear(uint32_t flag)
{
if(RESET != (flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= flag;
}
}
/*!
\brief enable the CTC interrupt
\param[in] interrupt: CTC interrupt enable
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt enable
\arg CTC_INT_CKWARN: clock trim warning interrupt enable
\arg CTC_INT_ERR: error interrupt enable
\arg CTC_INT_EREF: expect reference interrupt enable
\param[out] none
\retval none
*/
void ctc_interrupt_enable(uint32_t interrupt)
{
CTC_CTL0 |= (uint32_t)interrupt;
}
/*!
\brief disable the CTC interrupt
\param[in] interrupt: CTC interrupt enable source
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt enable
\arg CTC_INT_CKWARN: clock trim warning interrupt enable
\arg CTC_INT_ERR: error interrupt enable
\arg CTC_INT_EREF: expect reference interrupt enable
\param[out] none
\retval none
*/
void ctc_interrupt_disable(uint32_t interrupt)
{
CTC_CTL0 &= (uint32_t)(~interrupt);
}
/*!
\brief get CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt
\arg CTC_INT_FLAG_ERR: error interrupt
\arg CTC_INT_FLAG_EREF: expect reference interrupt
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_interrupt_flag_get(uint32_t int_flag)
{
uint32_t interrupt_flag = 0U, intenable = 0U;
/* check whether the interrupt is enabled */
if(RESET != (int_flag & CTC_FLAG_MASK)){
intenable = CTC_CTL0 & CTC_CTL0_ERRIE;
}else{
intenable = CTC_CTL0 & int_flag;
}
/* get interrupt flag status */
interrupt_flag = CTC_STAT & int_flag;
if(interrupt_flag && intenable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt
\arg CTC_INT_FLAG_ERR: error interrupt
\arg CTC_INT_FLAG_EREF: expect reference interrupt
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt
\param[out] none
\retval none
*/
void ctc_interrupt_flag_clear(uint32_t int_flag)
{
if(RESET != (int_flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= int_flag;
}
}
@@ -0,0 +1,388 @@
/*!
\file gd32e50x_ctc.c
\brief CTC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_ctc.h"
#define CTC_FLAG_MASK ((uint32_t)0x00000700U)
/* CTC register bit offset */
#define CTC_TRIMVALUE_OFFSET ((uint32_t)8U)
#define CTC_TRIM_VALUE_OFFSET ((uint32_t)8U)
#define CTC_REFCAP_OFFSET ((uint32_t)16U)
#define CTC_LIMIT_VALUE_OFFSET ((uint32_t)16U)
/*!
\brief reset CTC clock trim controller
\param[in] none
\param[out] none
\retval none
*/
void ctc_deinit(void)
{
/* reset CTC */
rcu_periph_reset_enable(RCU_CTCRST);
rcu_periph_reset_disable(RCU_CTCRST);
}
/*!
\brief enable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_enable(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_CNTEN;
}
/*!
\brief disable CTC trim counter
\param[in] none
\param[out] none
\retval none
*/
void ctc_counter_disable(void)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_CNTEN);
}
/*!
\brief configure the IRC48M trim value
\param[in] trim_value: 6-bit IRC48M trim value
\arg 0x00 - 0x3F
\param[out] none
\retval none
*/
void ctc_irc48m_trim_value_config(uint8_t trim_value)
{
/* clear TRIMVALUE bits */
CTC_CTL0 &= (~(uint32_t)CTC_CTL0_TRIMVALUE);
/* set TRIMVALUE bits */
CTC_CTL0 |= ((uint32_t)trim_value << CTC_TRIM_VALUE_OFFSET);
}
/*!
\brief generate software reference source sync pulse
\param[in] none
\param[out] none
\retval none
*/
void ctc_software_refsource_pulse_generate(void)
{
CTC_CTL0 |= (uint32_t)CTC_CTL0_SWREFPUL;
}
/*!
\brief configure hardware automatically trim mode
\param[in] hardmode:
only one parameter can be selected which is shown as below:
\arg CTC_HARDWARE_TRIM_MODE_ENABLE: hardware automatically trim mode enable
\arg CTC_HARDWARE_TRIM_MODE_DISABLE: hardware automatically trim mode disable
\param[out] none
\retval none
*/
void ctc_hardware_trim_mode_config(uint32_t hardmode)
{
CTC_CTL0 &= (uint32_t)(~CTC_CTL0_AUTOTRIM);
CTC_CTL0 |= (uint32_t)hardmode;
}
/*!
\brief configure reference signal source polarity
\param[in] polarity:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_POLARITY_FALLING: reference signal source polarity is falling edge
\arg CTC_REFSOURCE_POLARITY_RISING: reference signal source polarity is rising edge
\param[out] none
\retval none
*/
void ctc_refsource_polarity_config(uint32_t polarity)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPOL);
CTC_CTL1 |= (uint32_t)polarity;
}
/*!
\brief select reference signal source
\param[in] refs:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_GPIO: GPIO is selected
\arg CTC_REFSOURCE_LXTAL: LXTAL is selected
\param[out] none
\retval none
*/
void ctc_refsource_signal_select(uint32_t refs)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFSEL);
CTC_CTL1 |= (uint32_t)refs;
}
/*!
\brief configure reference signal source prescaler
\param[in] prescaler:
only one parameter can be selected which is shown as below:
\arg CTC_REFSOURCE_PSC_OFF: reference signal not divided
\arg CTC_REFSOURCE_PSC_DIV2: reference signal divided by 2
\arg CTC_REFSOURCE_PSC_DIV4: reference signal divided by 4
\arg CTC_REFSOURCE_PSC_DIV8: reference signal divided by 8
\arg CTC_REFSOURCE_PSC_DIV16: reference signal divided by 16
\arg CTC_REFSOURCE_PSC_DIV32: reference signal divided by 32
\arg CTC_REFSOURCE_PSC_DIV64: reference signal divided by 64
\arg CTC_REFSOURCE_PSC_DIV128: reference signal divided by 128
\param[out] none
\retval none
*/
void ctc_refsource_prescaler_config(uint32_t prescaler)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_REFPSC);
CTC_CTL1 |= (uint32_t)prescaler;
}
/*!
\brief configure clock trim base limit value
\param[in] limit_value: 8-bit clock trim base limit value
\arg 0x00 - 0xFF
\param[out] none
\retval none
*/
void ctc_clock_limit_value_config(uint8_t limit_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_CKLIM);
CTC_CTL1 |= (uint32_t)((uint32_t)limit_value << CTC_LIMIT_VALUE_OFFSET);
}
/*!
\brief configure CTC counter reload value
\param[in] reload_value: 16-bit CTC counter reload value
\arg 0x0000 - 0xFFFF
\param[out] none
\retval none
*/
void ctc_counter_reload_value_config(uint16_t reload_value)
{
CTC_CTL1 &= (uint32_t)(~CTC_CTL1_RLVALUE);
CTC_CTL1 |= (uint32_t)reload_value;
}
/*!
\brief read CTC counter capture value when reference sync pulse occurred
\param[in] none
\param[out] none
\retval the 16-bit CTC counter capture value
*/
uint16_t ctc_counter_capture_value_read(void)
{
uint16_t capture_value = 0U;
capture_value = (uint16_t)((CTC_STAT & CTC_STAT_REFCAP)>> CTC_REFCAP_OFFSET);
return (capture_value);
}
/*!
\brief read CTC trim counter direction when reference sync pulse occurred
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
\arg SET: CTC trim counter direction is down-counting
\arg RESET: CTC trim counter direction is up-counting
*/
FlagStatus ctc_counter_direction_read(void)
{
if(RESET != (CTC_STAT & CTC_STAT_REFDIR)){
return SET;
}else{
return RESET;
}
}
/*!
\brief read CTC counter reload value
\param[in] none
\param[out] none
\retval the 16-bit CTC counter reload value
*/
uint16_t ctc_counter_reload_value_read(void)
{
uint16_t reload_value = 0U;
reload_value = (uint16_t)(CTC_CTL1 & CTC_CTL1_RLVALUE);
return (reload_value);
}
/*!
\brief read the IRC48M trim value
\param[in] none
\param[out] none
\retval the 6-bit IRC48M trim value
*/
uint8_t ctc_irc48m_trim_value_read(void)
{
uint8_t trim_value = 0U;
trim_value = (uint8_t)((CTC_CTL0 & CTC_CTL0_TRIMVALUE) >> CTC_TRIMVALUE_OFFSET);
return (trim_value);
}
/*!
\brief get CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error bit
\arg CTC_FLAG_REFMISS: reference sync pulse miss
\arg CTC_FLAG_TRIMERR: trim value error bit
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_flag_get(uint32_t flag)
{
if(RESET != (CTC_STAT & flag)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC flag
\param[in] flag: the CTC flag
only one parameter can be selected which is shown as below:
\arg CTC_FLAG_CKOK: clock trim OK flag
\arg CTC_FLAG_CKWARN: clock trim warning flag
\arg CTC_FLAG_ERR: error flag
\arg CTC_FLAG_EREF: expect reference flag
\arg CTC_FLAG_CKERR: clock trim error bit
\arg CTC_FLAG_REFMISS: reference sync pulse miss
\arg CTC_FLAG_TRIMERR: trim value error bit
\param[out] none
\retval none
*/
void ctc_flag_clear(uint32_t flag)
{
if(RESET != (flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= flag;
}
}
/*!
\brief enable the CTC interrupt
\param[in] interrupt: CTC interrupt enable
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt enable
\arg CTC_INT_CKWARN: clock trim warning interrupt enable
\arg CTC_INT_ERR: error interrupt enable
\arg CTC_INT_EREF: expect reference interrupt enable
\param[out] none
\retval none
*/
void ctc_interrupt_enable(uint32_t interrupt)
{
CTC_CTL0 |= (uint32_t)interrupt;
}
/*!
\brief disable the CTC interrupt
\param[in] interrupt: CTC interrupt enable source
one or more parameters can be selected which are shown as below:
\arg CTC_INT_CKOK: clock trim OK interrupt enable
\arg CTC_INT_CKWARN: clock trim warning interrupt enable
\arg CTC_INT_ERR: error interrupt enable
\arg CTC_INT_EREF: expect reference interrupt enable
\param[out] none
\retval none
*/
void ctc_interrupt_disable(uint32_t interrupt)
{
CTC_CTL0 &= (uint32_t)(~interrupt);
}
/*!
\brief get CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt
\arg CTC_INT_FLAG_ERR: error interrupt
\arg CTC_INT_FLAG_EREF: expect reference interrupt
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ctc_interrupt_flag_get(uint32_t int_flag)
{
uint32_t interrupt_flag = 0U, intenable = 0U;
/* check whether the interrupt is enabled */
if(RESET != (int_flag & CTC_FLAG_MASK)){
intenable = CTC_CTL0 & CTC_CTL0_ERRIE;
}else{
intenable = CTC_CTL0 & int_flag;
}
/* get interrupt flag status */
interrupt_flag = CTC_STAT & int_flag;
if(interrupt_flag && intenable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear CTC interrupt flag
\param[in] int_flag: the CTC interrupt flag
only one parameter can be selected which is shown as below:
\arg CTC_INT_FLAG_CKOK: clock trim OK interrupt
\arg CTC_INT_FLAG_CKWARN: clock trim warning interrupt
\arg CTC_INT_FLAG_ERR: error interrupt
\arg CTC_INT_FLAG_EREF: expect reference interrupt
\arg CTC_INT_FLAG_CKERR: clock trim error bit interrupt
\arg CTC_INT_FLAG_REFMISS: reference sync pulse miss interrupt
\arg CTC_INT_FLAG_TRIMERR: trim value error interrupt
\param[out] none
\retval none
*/
void ctc_interrupt_flag_clear(uint32_t int_flag)
{
if(RESET != (int_flag & CTC_FLAG_MASK)){
CTC_INTC |= CTC_INTC_ERRIC;
}else{
CTC_INTC |= int_flag;
}
}
@@ -0,0 +1,148 @@
/*!
\file gd32e50x_dbg.c
\brief DBG driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_dbg.h"
#define DBG_RESET_VAL ((uint32_t)0x00000000U) /*!< DBG reset value */
/*!
\brief deinitialize the DBG
\param[in] none
\param[out] none
\retval none
*/
void dbg_deinit(void)
{
DBG_CTL = DBG_RESET_VAL;
}
/*!
\brief read DBG_ID code register
\param[in] none
\param[out] none
\retval DBG_ID code
*/
uint32_t dbg_id_get(void)
{
return DBG_ID;
}
/*!
\brief enable low power behavior when the mcu is in debug mode
\param[in] dbg_low_power:
one or more parameters can be selected which are shown as below:
\arg DBG_LOW_POWER_SLEEP: keep debugger connection during sleep mode
\arg DBG_LOW_POWER_DEEPSLEEP: keep debugger connection during deepsleep mode
\arg DBG_LOW_POWER_STANDBY: keep debugger connection during standby mode
\param[out] none
\retval none
*/
void dbg_low_power_enable(uint32_t dbg_low_power)
{
DBG_CTL |= dbg_low_power;
}
/*!
\brief disable low power behavior when the mcu is in debug mode
\param[in] dbg_low_power:
one or more parameters can be selected which are shown as below:
\arg DBG_LOW_POWER_SLEEP: do not keep debugger connection during sleep mode
\arg DBG_LOW_POWER_DEEPSLEEP: do not keep debugger connection during deepsleep mode
\arg DBG_LOW_POWER_STANDBY: do not keep debugger connection during standby mode
\param[out] none
\retval none
*/
void dbg_low_power_disable(uint32_t dbg_low_power)
{
DBG_CTL &= ~dbg_low_power;
}
/*!
\brief enable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which is shown as below:
\arg DBG_FWDGT_HOLD : hold FWDGT counter when core is halted
\arg DBG_WWDGT_HOLD : hold WWDGT counter when core is halted
\arg DBG_CANx_HOLD (x=0,1,2 CAN2 is only available for CL series, CANx are not available for GD32EPRT series): hold CANx receive register counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2): hold I2Cx smbus timeout when core is halted
\arg DBG_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13, TIMER8..13 are not available for GD32EPRT series): hold TIMERx counter when core is halted
\arg DBG_SHRTIMER_HOLD : hold SHRTIMER counter when core is halted, except for GD32EPRT series
\param[out] none
\retval none
*/
void dbg_periph_enable(dbg_periph_enum dbg_periph)
{
DBG_REG_VAL(dbg_periph) |= BIT(DBG_BIT_POS(dbg_periph));
}
/*!
\brief disable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which is shown as below:
\arg DBG_FWDGT_HOLD : hold FWDGT counter when core is halted
\arg DBG_WWDGT_HOLD : hold WWDGT counter when core is halted
\arg DBG_CANx_HOLD (x=0,1,2 CAN2 is only available for CL series, CANx are not available for GD32EPRT series): hold CANx receive register counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2): hold I2Cx smbus timeout when core is halted
\arg DBG_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13,TIMER8..13 are not available for GD32EPRT series): hold TIMERx counter when core is halted
\arg DBG_SHRTIMER_HOLD : hold SHRTIMER counter when core is halted, except for GD32EPRT series
\param[out] none
\retval none
*/
void dbg_periph_disable(dbg_periph_enum dbg_periph)
{
DBG_REG_VAL(dbg_periph) &= ~BIT(DBG_BIT_POS(dbg_periph));
}
/*!
\brief enable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_enable(void)
{
DBG_CTL |= DBG_CTL_TRACE_IOEN;
}
/*!
\brief disable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_disable(void)
{
DBG_CTL &= ~DBG_CTL_TRACE_IOEN;
}
@@ -0,0 +1,148 @@
/*!
\file gd32e50x_dbg.c
\brief DBG driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_dbg.h"
#define DBG_RESET_VAL ((uint32_t)0x00000000U) /*!< DBG reset value */
/*!
\brief deinitialize the DBG
\param[in] none
\param[out] none
\retval none
*/
void dbg_deinit(void)
{
DBG_CTL = DBG_RESET_VAL;
}
/*!
\brief read DBG_ID code register
\param[in] none
\param[out] none
\retval DBG_ID code
*/
uint32_t dbg_id_get(void)
{
return DBG_ID;
}
/*!
\brief enable low power behavior when the mcu is in debug mode
\param[in] dbg_low_power:
one or more parameters can be selected which are shown as below:
\arg DBG_LOW_POWER_SLEEP: keep debugger connection during sleep mode
\arg DBG_LOW_POWER_DEEPSLEEP: keep debugger connection during deepsleep mode
\arg DBG_LOW_POWER_STANDBY: keep debugger connection during standby mode
\param[out] none
\retval none
*/
void dbg_low_power_enable(uint32_t dbg_low_power)
{
DBG_CTL |= dbg_low_power;
}
/*!
\brief disable low power behavior when the mcu is in debug mode
\param[in] dbg_low_power:
one or more parameters can be selected which are shown as below:
\arg DBG_LOW_POWER_SLEEP: do not keep debugger connection during sleep mode
\arg DBG_LOW_POWER_DEEPSLEEP: do not keep debugger connection during deepsleep mode
\arg DBG_LOW_POWER_STANDBY: do not keep debugger connection during standby mode
\param[out] none
\retval none
*/
void dbg_low_power_disable(uint32_t dbg_low_power)
{
DBG_CTL &= ~dbg_low_power;
}
/*!
\brief enable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which is shown as below:
\arg DBG_FWDGT_HOLD : hold FWDGT counter when core is halted
\arg DBG_WWDGT_HOLD : hold WWDGT counter when core is halted
\arg DBG_CANx_HOLD (x=0,1,2 CAN2 is only available for CL series, CANx are not available for GD32EPRT series): hold CANx receive register counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2): hold I2Cx smbus timeout when core is halted
\arg DBG_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13, TIMER8..13 are not available for GD32EPRT series): hold TIMERx counter when core is halted
\arg DBG_SHRTIMER_HOLD : hold SHRTIMER counter when core is halted, except for GD32EPRT series
\param[out] none
\retval none
*/
void dbg_periph_enable(dbg_periph_enum dbg_periph)
{
DBG_REG_VAL(dbg_periph) |= BIT(DBG_BIT_POS(dbg_periph));
}
/*!
\brief disable peripheral behavior when the mcu is in debug mode
\param[in] dbg_periph: refer to dbg_periph_enum
only one parameter can be selected which is shown as below:
\arg DBG_FWDGT_HOLD : hold FWDGT counter when core is halted
\arg DBG_WWDGT_HOLD : hold WWDGT counter when core is halted
\arg DBG_CANx_HOLD (x=0,1,2 CAN2 is only available for CL series, CANx are not available for GD32EPRT series): hold CANx receive register counter when core is halted
\arg DBG_I2Cx_HOLD (x=0,1,2): hold I2Cx smbus timeout when core is halted
\arg DBG_TIMERx_HOLD (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13,TIMER8..13 are not available for GD32EPRT series): hold TIMERx counter when core is halted
\arg DBG_SHRTIMER_HOLD : hold SHRTIMER counter when core is halted, except for GD32EPRT series
\param[out] none
\retval none
*/
void dbg_periph_disable(dbg_periph_enum dbg_periph)
{
DBG_REG_VAL(dbg_periph) &= ~BIT(DBG_BIT_POS(dbg_periph));
}
/*!
\brief enable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_enable(void)
{
DBG_CTL |= DBG_CTL_TRACE_IOEN;
}
/*!
\brief disable trace pin assignment
\param[in] none
\param[out] none
\retval none
*/
void dbg_trace_pin_disable(void)
{
DBG_CTL &= ~DBG_CTL_TRACE_IOEN;
}
@@ -0,0 +1,752 @@
/*!
\file gd32e50x_dma.c
\brief DMA driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_dma.h"
#include <stdlib.h>
#define DMA_WRONG_HANDLE while(1){}
/* check whether peripheral matches channels or not */
static ErrStatus dma_periph_and_channel_check(uint32_t dma_periph, dma_channel_enum channelx);
/*!
\brief deinitialize DMA a channel registers
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel is deinitialized
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_deinit(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* disable DMA a channel */
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CHEN;
/* reset DMA channel registers */
DMA_CHCTL(dma_periph, channelx) = DMA_CHCTL_RESET_VALUE;
DMA_CHCNT(dma_periph, channelx) = DMA_CHCNT_RESET_VALUE;
DMA_CHPADDR(dma_periph, channelx) = DMA_CHPADDR_RESET_VALUE;
DMA_CHMADDR(dma_periph, channelx) = DMA_CHMADDR_RESET_VALUE;
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(DMA_CHINTF_RESET_VALUE, channelx);
}
/*!
\brief initialize the parameters of DMA struct with the default values
\param[in] init_struct: the initialization data needed to initialize DMA channel
\param[out] none
\retval none
*/
void dma_struct_para_init(dma_parameter_struct* init_struct)
{
if(NULL == init_struct){
DMA_WRONG_HANDLE
}
/* set the DMA struct with the default values */
init_struct->periph_addr = 0U;
init_struct->periph_width = 0U;
init_struct->periph_inc = DMA_PERIPH_INCREASE_DISABLE;
init_struct->memory_addr = 0U;
init_struct->memory_width = 0U;
init_struct->memory_inc = DMA_MEMORY_INCREASE_DISABLE;
init_struct->number = 0U;
init_struct->direction = DMA_PERIPHERAL_TO_MEMORY;
init_struct->priority = DMA_PRIORITY_LOW;
}
/*!
\brief initialize DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel is initialized
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] init_struct: the data needed to initialize DMA channel
periph_addr: peripheral base address
periph_width: DMA_PERIPHERAL_WIDTH_8BIT, DMA_PERIPHERAL_WIDTH_16BIT, DMA_PERIPHERAL_WIDTH_32BIT
periph_inc: DMA_PERIPH_INCREASE_ENABLE, DMA_PERIPH_INCREASE_DISABLE
memory_addr: memory base address
memory_width: DMA_MEMORY_WIDTH_8BIT, DMA_MEMORY_WIDTH_16BIT, DMA_MEMORY_WIDTH_32BIT
memory_inc: DMA_MEMORY_INCREASE_ENABLE, DMA_MEMORY_INCREASE_DISABLE
direction: DMA_PERIPHERAL_TO_MEMORY, DMA_MEMORY_TO_PERIPHERAL
number: the number of remaining data to be transferred by the DMA
priority: DMA_PRIORITY_LOW, DMA_PRIORITY_MEDIUM, DMA_PRIORITY_HIGH, DMA_PRIORITY_ULTRA_HIGH
\param[out] none
\retval none
*/
void dma_init(uint32_t dma_periph, dma_channel_enum channelx, dma_parameter_struct* init_struct)
{
uint32_t ctl;
if(NULL == init_struct){
DMA_WRONG_HANDLE
}
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* configure peripheral base address */
DMA_CHPADDR(dma_periph, channelx) = init_struct->periph_addr;
/* configure memory base address */
DMA_CHMADDR(dma_periph, channelx) = init_struct->memory_addr;
/* configure the number of remaining data to be transferred */
DMA_CHCNT(dma_periph, channelx) = (init_struct->number & DMA_CHANNEL_CNT_MASK);
/* configure peripheral transfer width,memory transfer width and priority */
ctl = DMA_CHCTL(dma_periph, channelx);
ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO);
ctl |= (init_struct->periph_width | init_struct->memory_width | init_struct->priority);
DMA_CHCTL(dma_periph, channelx) = ctl;
/* configure peripheral increasing mode */
if(DMA_PERIPH_INCREASE_ENABLE == init_struct->periph_inc){
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_PNAGA;
}else{
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_PNAGA;
}
/* configure memory increasing mode */
if(DMA_MEMORY_INCREASE_ENABLE == init_struct->memory_inc){
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_MNAGA;
}else{
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_MNAGA;
}
/* configure the direction of data transfer */
if(DMA_PERIPHERAL_TO_MEMORY == init_struct->direction){
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_DIR;
}else{
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_DIR;
}
}
/*!
\brief enable DMA circulation mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_circulation_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_CMEN;
}
/*!
\brief disable DMA circulation mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_circulation_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CMEN;
}
/*!
\brief enable memory to memory mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_to_memory_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_M2M;
}
/*!
\brief disable memory to memory mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_to_memory_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_M2M;
}
/*!
\brief enable DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_channel_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_CHEN;
}
/*!
\brief disable DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_channel_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CHEN;
}
/*!
\brief set DMA peripheral base address
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set peripheral base address
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] address: peripheral base address
\param[out] none
\retval none
*/
void dma_periph_address_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t address)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHPADDR(dma_periph, channelx) = address;
}
/*!
\brief set DMA memory base address
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set memory base address
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] address: memory base address
\param[out] none
\retval none
*/
void dma_memory_address_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t address)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHMADDR(dma_periph, channelx) = address;
}
/*!
\brief set the number of remaining data to be transferred by the DMA
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set number
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] number: the number of remaining data to be transferred by the DMA, 0x00000000-0x0000FFFF
\param[out] none
\retval none
*/
void dma_transfer_number_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t number)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCNT(dma_periph, channelx) = (number & DMA_CHANNEL_CNT_MASK);
}
/*!
\brief get the number of remaining data to be transferred by the DMA
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set number
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval uint32_t: the number of remaining data to be transferred by the DMA, 0x00000000-0x0000FFFF
*/
uint32_t dma_transfer_number_get(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
return (uint32_t)DMA_CHCNT(dma_periph, channelx);
}
/*!
\brief configure priority level of DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] priority: priority Level of this channel
only one parameter can be selected which is shown as below:
\arg DMA_PRIORITY_LOW: low priority
\arg DMA_PRIORITY_MEDIUM: medium priority
\arg DMA_PRIORITY_HIGH: high priority
\arg DMA_PRIORITY_ULTRA_HIGH: ultra high priority
\param[out] none
\retval none
*/
void dma_priority_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t priority)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_PRIO;
ctl |= priority;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief configure transfer data size of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] mwidth: transfer data width of memory
only one parameter can be selected which is shown as below:
\arg DMA_MEMORY_WIDTH_8BIT: transfer data width of memory is 8-bit
\arg DMA_MEMORY_WIDTH_16BIT: transfer data width of memory is 16-bit
\arg DMA_MEMORY_WIDTH_32BIT: transfer data width of memory is 32-bit
\param[out] none
\retval none
*/
void dma_memory_width_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t mwidth)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_MWIDTH;
ctl |= mwidth;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief configure transfer data size of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] pwidth: transfer data width of peripheral
only one parameter can be selected which is shown as below:
\arg DMA_PERIPHERAL_WIDTH_8BIT: transfer data width of peripheral is 8-bit
\arg DMA_PERIPHERAL_WIDTH_16BIT: transfer data width of peripheral is 16-bit
\arg DMA_PERIPHERAL_WIDTH_32BIT: transfer data width of peripheral is 32-bit
\param[out] none
\retval none
*/
void dma_periph_width_config (uint32_t dma_periph, dma_channel_enum channelx, uint32_t pwidth)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_PWIDTH;
ctl |= pwidth;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief enable next address increasement algorithm of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_increase_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_MNAGA;
}
/*!
\brief disable next address increasement algorithm of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_increase_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_MNAGA;
}
/*!
\brief enable next address increasement algorithm of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_periph_increase_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_PNAGA;
}
/*!
\brief disable next address increasement algorithm of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_periph_increase_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_PNAGA;
}
/*!
\brief configure the direction of data transfer on the channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] direction: specify the direction of data transfer
only one parameter can be selected which is shown as below:
\arg DMA_PERIPHERAL_TO_MEMORY: read from peripheral and write to memory
\arg DMA_MEMORY_TO_PERIPHERAL: read from memory and write to peripheral
\param[out] none
\retval none
*/
void dma_transfer_direction_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t direction)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
if(DMA_PERIPHERAL_TO_MEMORY == direction){
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_DIR;
}else {
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_DIR;
}
}
/*!
\brief check DMA flag is set or not
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to get flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_FLAG_G: global interrupt flag of channel
\arg DMA_FLAG_FTF: full transfer finish flag of channel
\arg DMA_FLAG_HTF: half transfer finish flag of channel
\arg DMA_FLAG_ERR: error flag of channel
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dma_flag_get(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
FlagStatus reval;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
if(RESET != (DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx))){
reval = SET;
}else{
reval = RESET;
}
return reval;
}
/*!
\brief clear a DMA channel flag
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to clear flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_FLAG_G: global interrupt flag of channel
\arg DMA_FLAG_FTF: full transfer finish flag of channel
\arg DMA_FLAG_HTF: half transfer finish flag of channel
\arg DMA_FLAG_ERR: error flag of channel
\param[out] none
\retval none
*/
void dma_flag_clear(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(flag, channelx);
}
/*!
\brief enable DMA interrupt
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] source: specify which interrupt to enbale
one or more parameters can be selected which are shown as below
\arg DMA_INT_FTF: channel full transfer finish interrupt
\arg DMA_INT_HTF: channel half transfer finish interrupt
\arg DMA_INT_ERR: channel error interrupt
\param[out] none
\retval none
*/
void dma_interrupt_enable(uint32_t dma_periph, dma_channel_enum channelx, uint32_t source)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= source;
}
/*!
\brief disable DMA interrupt
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] source: specify which interrupt to disbale
one or more parameters can be selected which are shown as below
\arg DMA_INT_FTF: channel full transfer finish interrupt
\arg DMA_INT_HTF: channel half transfer finish interrupt
\arg DMA_INT_ERR: channel error interrupt
\param[out] none
\retval none
*/
void dma_interrupt_disable(uint32_t dma_periph, dma_channel_enum channelx, uint32_t source)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~source;
}
/*!
\brief check DMA flag and interrupt enable bit is set or not
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to get flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_INT_FLAG_FTF: full transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_HTF: half transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_ERR: error interrupt flag of channel
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dma_interrupt_flag_get(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
switch(flag){
case DMA_INT_FLAG_FTF:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_FTFIE;
break;
case DMA_INT_FLAG_HTF:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_HTFIE;
break;
case DMA_INT_FLAG_ERR:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_ERRIE;
break;
default:
DMA_WRONG_HANDLE
}
if(interrupt_flag && interrupt_enable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear a DMA channel flag
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to clear flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_INT_FLAG_G: global interrupt flag of channel
\arg DMA_INT_FLAG_FTF: full transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_HTF: half transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_ERR: error interrupt flag of channel
\param[out] none
\retval none
*/
void dma_interrupt_flag_clear(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(flag, channelx);
}
/*!
\brief check whether peripheral and channels match
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA_CHx(x=0..6)
\param[out] none
\retval none
*/
static ErrStatus dma_periph_and_channel_check(uint32_t dma_periph, dma_channel_enum channelx)
{
ErrStatus val = SUCCESS;
if(DMA1 == dma_periph){
/* for DMA1, the channel is from DMA_CH0 to DMA_CH4 */
if(channelx > DMA_CH4){
val = ERROR;
}
}
return val;
}
@@ -0,0 +1,752 @@
/*!
\file gd32e50x_dma.c
\brief DMA driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_dma.h"
#include <stdlib.h>
#define DMA_WRONG_HANDLE while(1){}
/* check whether peripheral matches channels or not */
static ErrStatus dma_periph_and_channel_check(uint32_t dma_periph, dma_channel_enum channelx);
/*!
\brief deinitialize DMA a channel registers
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel is deinitialized
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_deinit(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* disable DMA a channel */
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CHEN;
/* reset DMA channel registers */
DMA_CHCTL(dma_periph, channelx) = DMA_CHCTL_RESET_VALUE;
DMA_CHCNT(dma_periph, channelx) = DMA_CHCNT_RESET_VALUE;
DMA_CHPADDR(dma_periph, channelx) = DMA_CHPADDR_RESET_VALUE;
DMA_CHMADDR(dma_periph, channelx) = DMA_CHMADDR_RESET_VALUE;
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(DMA_CHINTF_RESET_VALUE, channelx);
}
/*!
\brief initialize the parameters of DMA struct with the default values
\param[in] init_struct: the initialization data needed to initialize DMA channel
\param[out] none
\retval none
*/
void dma_struct_para_init(dma_parameter_struct* init_struct)
{
if(NULL == init_struct){
DMA_WRONG_HANDLE
}
/* set the DMA struct with the default values */
init_struct->periph_addr = 0U;
init_struct->periph_width = 0U;
init_struct->periph_inc = DMA_PERIPH_INCREASE_DISABLE;
init_struct->memory_addr = 0U;
init_struct->memory_width = 0U;
init_struct->memory_inc = DMA_MEMORY_INCREASE_DISABLE;
init_struct->number = 0U;
init_struct->direction = DMA_PERIPHERAL_TO_MEMORY;
init_struct->priority = DMA_PRIORITY_LOW;
}
/*!
\brief initialize DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel is initialized
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] init_struct: the data needed to initialize DMA channel
periph_addr: peripheral base address
periph_width: DMA_PERIPHERAL_WIDTH_8BIT, DMA_PERIPHERAL_WIDTH_16BIT, DMA_PERIPHERAL_WIDTH_32BIT
periph_inc: DMA_PERIPH_INCREASE_ENABLE, DMA_PERIPH_INCREASE_DISABLE
memory_addr: memory base address
memory_width: DMA_MEMORY_WIDTH_8BIT, DMA_MEMORY_WIDTH_16BIT, DMA_MEMORY_WIDTH_32BIT
memory_inc: DMA_MEMORY_INCREASE_ENABLE, DMA_MEMORY_INCREASE_DISABLE
direction: DMA_PERIPHERAL_TO_MEMORY, DMA_MEMORY_TO_PERIPHERAL
number: the number of remaining data to be transferred by the DMA
priority: DMA_PRIORITY_LOW, DMA_PRIORITY_MEDIUM, DMA_PRIORITY_HIGH, DMA_PRIORITY_ULTRA_HIGH
\param[out] none
\retval none
*/
void dma_init(uint32_t dma_periph, dma_channel_enum channelx, dma_parameter_struct* init_struct)
{
uint32_t ctl;
if(NULL == init_struct){
DMA_WRONG_HANDLE
}
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* configure peripheral base address */
DMA_CHPADDR(dma_periph, channelx) = init_struct->periph_addr;
/* configure memory base address */
DMA_CHMADDR(dma_periph, channelx) = init_struct->memory_addr;
/* configure the number of remaining data to be transferred */
DMA_CHCNT(dma_periph, channelx) = (init_struct->number & DMA_CHANNEL_CNT_MASK);
/* configure peripheral transfer width,memory transfer width and priority */
ctl = DMA_CHCTL(dma_periph, channelx);
ctl &= ~(DMA_CHXCTL_PWIDTH | DMA_CHXCTL_MWIDTH | DMA_CHXCTL_PRIO);
ctl |= (init_struct->periph_width | init_struct->memory_width | init_struct->priority);
DMA_CHCTL(dma_periph, channelx) = ctl;
/* configure peripheral increasing mode */
if(DMA_PERIPH_INCREASE_ENABLE == init_struct->periph_inc){
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_PNAGA;
}else{
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_PNAGA;
}
/* configure memory increasing mode */
if(DMA_MEMORY_INCREASE_ENABLE == init_struct->memory_inc){
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_MNAGA;
}else{
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_MNAGA;
}
/* configure the direction of data transfer */
if(DMA_PERIPHERAL_TO_MEMORY == init_struct->direction){
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_DIR;
}else{
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_DIR;
}
}
/*!
\brief enable DMA circulation mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_circulation_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_CMEN;
}
/*!
\brief disable DMA circulation mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_circulation_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CMEN;
}
/*!
\brief enable memory to memory mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_to_memory_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_M2M;
}
/*!
\brief disable memory to memory mode
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_to_memory_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_M2M;
}
/*!
\brief enable DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_channel_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_CHEN;
}
/*!
\brief disable DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_channel_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_CHEN;
}
/*!
\brief set DMA peripheral base address
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set peripheral base address
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] address: peripheral base address
\param[out] none
\retval none
*/
void dma_periph_address_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t address)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHPADDR(dma_periph, channelx) = address;
}
/*!
\brief set DMA memory base address
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set memory base address
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] address: memory base address
\param[out] none
\retval none
*/
void dma_memory_address_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t address)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHMADDR(dma_periph, channelx) = address;
}
/*!
\brief set the number of remaining data to be transferred by the DMA
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set number
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] number: the number of remaining data to be transferred by the DMA, 0x00000000-0x0000FFFF
\param[out] none
\retval none
*/
void dma_transfer_number_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t number)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCNT(dma_periph, channelx) = (number & DMA_CHANNEL_CNT_MASK);
}
/*!
\brief get the number of remaining data to be transferred by the DMA
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to set number
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval uint32_t: the number of remaining data to be transferred by the DMA, 0x00000000-0x0000FFFF
*/
uint32_t dma_transfer_number_get(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
return (uint32_t)DMA_CHCNT(dma_periph, channelx);
}
/*!
\brief configure priority level of DMA channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] priority: priority Level of this channel
only one parameter can be selected which is shown as below:
\arg DMA_PRIORITY_LOW: low priority
\arg DMA_PRIORITY_MEDIUM: medium priority
\arg DMA_PRIORITY_HIGH: high priority
\arg DMA_PRIORITY_ULTRA_HIGH: ultra high priority
\param[out] none
\retval none
*/
void dma_priority_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t priority)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_PRIO;
ctl |= priority;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief configure transfer data size of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] mwidth: transfer data width of memory
only one parameter can be selected which is shown as below:
\arg DMA_MEMORY_WIDTH_8BIT: transfer data width of memory is 8-bit
\arg DMA_MEMORY_WIDTH_16BIT: transfer data width of memory is 16-bit
\arg DMA_MEMORY_WIDTH_32BIT: transfer data width of memory is 32-bit
\param[out] none
\retval none
*/
void dma_memory_width_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t mwidth)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_MWIDTH;
ctl |= mwidth;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief configure transfer data size of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] pwidth: transfer data width of peripheral
only one parameter can be selected which is shown as below:
\arg DMA_PERIPHERAL_WIDTH_8BIT: transfer data width of peripheral is 8-bit
\arg DMA_PERIPHERAL_WIDTH_16BIT: transfer data width of peripheral is 16-bit
\arg DMA_PERIPHERAL_WIDTH_32BIT: transfer data width of peripheral is 32-bit
\param[out] none
\retval none
*/
void dma_periph_width_config (uint32_t dma_periph, dma_channel_enum channelx, uint32_t pwidth)
{
uint32_t ctl;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
/* acquire DMA_CHxCTL register */
ctl = DMA_CHCTL(dma_periph, channelx);
/* assign regiser */
ctl &= ~DMA_CHXCTL_PWIDTH;
ctl |= pwidth;
DMA_CHCTL(dma_periph, channelx) = ctl;
}
/*!
\brief enable next address increasement algorithm of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_increase_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_MNAGA;
}
/*!
\brief disable next address increasement algorithm of memory
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_memory_increase_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_MNAGA;
}
/*!
\brief enable next address increasement algorithm of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_periph_increase_enable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_PNAGA;
}
/*!
\brief disable next address increasement algorithm of peripheral
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[out] none
\retval none
*/
void dma_periph_increase_disable(uint32_t dma_periph, dma_channel_enum channelx)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_PNAGA;
}
/*!
\brief configure the direction of data transfer on the channel
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] direction: specify the direction of data transfer
only one parameter can be selected which is shown as below:
\arg DMA_PERIPHERAL_TO_MEMORY: read from peripheral and write to memory
\arg DMA_MEMORY_TO_PERIPHERAL: read from memory and write to peripheral
\param[out] none
\retval none
*/
void dma_transfer_direction_config(uint32_t dma_periph, dma_channel_enum channelx, uint32_t direction)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
if(DMA_PERIPHERAL_TO_MEMORY == direction){
DMA_CHCTL(dma_periph, channelx) &= ~DMA_CHXCTL_DIR;
}else {
DMA_CHCTL(dma_periph, channelx) |= DMA_CHXCTL_DIR;
}
}
/*!
\brief check DMA flag is set or not
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to get flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_FLAG_G: global interrupt flag of channel
\arg DMA_FLAG_FTF: full transfer finish flag of channel
\arg DMA_FLAG_HTF: half transfer finish flag of channel
\arg DMA_FLAG_ERR: error flag of channel
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dma_flag_get(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
FlagStatus reval;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
if(RESET != (DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx))){
reval = SET;
}else{
reval = RESET;
}
return reval;
}
/*!
\brief clear a DMA channel flag
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to clear flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_FLAG_G: global interrupt flag of channel
\arg DMA_FLAG_FTF: full transfer finish flag of channel
\arg DMA_FLAG_HTF: half transfer finish flag of channel
\arg DMA_FLAG_ERR: error flag of channel
\param[out] none
\retval none
*/
void dma_flag_clear(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(flag, channelx);
}
/*!
\brief enable DMA interrupt
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] source: specify which interrupt to enbale
one or more parameters can be selected which are shown as below
\arg DMA_INT_FTF: channel full transfer finish interrupt
\arg DMA_INT_HTF: channel half transfer finish interrupt
\arg DMA_INT_ERR: channel error interrupt
\param[out] none
\retval none
*/
void dma_interrupt_enable(uint32_t dma_periph, dma_channel_enum channelx, uint32_t source)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) |= source;
}
/*!
\brief disable DMA interrupt
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] source: specify which interrupt to disbale
one or more parameters can be selected which are shown as below
\arg DMA_INT_FTF: channel full transfer finish interrupt
\arg DMA_INT_HTF: channel half transfer finish interrupt
\arg DMA_INT_ERR: channel error interrupt
\param[out] none
\retval none
*/
void dma_interrupt_disable(uint32_t dma_periph, dma_channel_enum channelx, uint32_t source)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_CHCTL(dma_periph, channelx) &= ~source;
}
/*!
\brief check DMA flag and interrupt enable bit is set or not
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to get flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_INT_FLAG_FTF: full transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_HTF: half transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_ERR: error interrupt flag of channel
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus dma_interrupt_flag_get(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
uint32_t interrupt_enable = 0U, interrupt_flag = 0U;
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
switch(flag){
case DMA_INT_FLAG_FTF:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_FTFIE;
break;
case DMA_INT_FLAG_HTF:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_HTFIE;
break;
case DMA_INT_FLAG_ERR:
interrupt_flag = DMA_INTF(dma_periph) & DMA_FLAG_ADD(flag, channelx);
interrupt_enable = DMA_CHCTL(dma_periph, channelx) & DMA_CHXCTL_ERRIE;
break;
default:
DMA_WRONG_HANDLE
}
if(interrupt_flag && interrupt_enable){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear a DMA channel flag
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel to clear flag
only one parameter can be selected which is shown as below:
\arg DMA0: DMA_CHx(x=0..6), DMA1: DMA_CHx(x=0..4)
\param[in] flag: specify get which flag
only one parameter can be selected which is shown as below:
\arg DMA_INT_FLAG_G: global interrupt flag of channel
\arg DMA_INT_FLAG_FTF: full transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_HTF: half transfer finish interrupt flag of channel
\arg DMA_INT_FLAG_ERR: error interrupt flag of channel
\param[out] none
\retval none
*/
void dma_interrupt_flag_clear(uint32_t dma_periph, dma_channel_enum channelx, uint32_t flag)
{
if(ERROR == dma_periph_and_channel_check(dma_periph, channelx)){
DMA_WRONG_HANDLE
}
DMA_INTC(dma_periph) |= DMA_FLAG_ADD(flag, channelx);
}
/*!
\brief check whether peripheral and channels match
\param[in] dma_periph: DMAx(x=0,1)
\arg DMAx(x=0,1)
\param[in] channelx: specify which DMA channel
only one parameter can be selected which is shown as below:
\arg DMA_CHx(x=0..6)
\param[out] none
\retval none
*/
static ErrStatus dma_periph_and_channel_check(uint32_t dma_periph, dma_channel_enum channelx)
{
ErrStatus val = SUCCESS;
if(DMA1 == dma_periph){
/* for DMA1, the channel is from DMA_CH0 to DMA_CH4 */
if(channelx > DMA_CH4){
val = ERROR;
}
}
return val;
}
@@ -0,0 +1,249 @@
/*!
\file gd32e50x_exti.c
\brief EXTI driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_exti.h"
#define EXTI_REG_RESET_VALUE ((uint32_t)0x00000000U)
/*!
\brief deinitialize the EXTI
\param[in] none
\param[out] none
\retval none
*/
void exti_deinit(void)
{
/* reset the value of all the EXTI registers */
EXTI_INTEN = EXTI_REG_RESET_VALUE;
EXTI_EVEN = EXTI_REG_RESET_VALUE;
EXTI_RTEN = EXTI_REG_RESET_VALUE;
EXTI_FTEN = EXTI_REG_RESET_VALUE;
EXTI_SWIEV = EXTI_REG_RESET_VALUE;
}
/*!
\brief initialize the EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[in] mode: interrupt or event mode, refer to exti_mode_enum
only one parameter can be selected which is shown as below:
\arg EXTI_INTERRUPT: interrupt mode
\arg EXTI_EVENT: event mode
\param[in] trig_type: interrupt trigger type, refer to exti_trig_type_enum
only one parameter can be selected which is shown as below:
\arg EXTI_TRIG_RISING: rising edge trigger
\arg EXTI_TRIG_FALLING: falling trigger
\arg EXTI_TRIG_BOTH: rising and falling trigger
\arg EXTI_TRIG_NONE: without rising edge or falling edge trigger
\param[out] none
\retval none
*/
void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type)
{
/* reset the EXTI line x */
EXTI_INTEN &= ~(uint32_t)linex;
EXTI_EVEN &= ~(uint32_t)linex;
EXTI_RTEN &= ~(uint32_t)linex;
EXTI_FTEN &= ~(uint32_t)linex;
/* set the EXTI mode and enable the interrupts or events from EXTI line x */
switch(mode){
case EXTI_INTERRUPT:
EXTI_INTEN |= (uint32_t)linex;
break;
case EXTI_EVENT:
EXTI_EVEN |= (uint32_t)linex;
break;
default:
break;
}
/* set the EXTI trigger type */
switch(trig_type){
case EXTI_TRIG_RISING:
EXTI_RTEN |= (uint32_t)linex;
EXTI_FTEN &= ~(uint32_t)linex;
break;
case EXTI_TRIG_FALLING:
EXTI_RTEN &= ~(uint32_t)linex;
EXTI_FTEN |= (uint32_t)linex;
break;
case EXTI_TRIG_BOTH:
EXTI_RTEN |= (uint32_t)linex;
EXTI_FTEN |= (uint32_t)linex;
break;
case EXTI_TRIG_NONE:
default:
break;
}
}
/*!
\brief enable the interrupts from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_enable(exti_line_enum linex)
{
EXTI_INTEN |= (uint32_t)linex;
}
/*!
\brief disable the interrupt from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_disable(exti_line_enum linex)
{
EXTI_INTEN &= ~(uint32_t)linex;
}
/*!
\brief enable the events from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_event_enable(exti_line_enum linex)
{
EXTI_EVEN |= (uint32_t)linex;
}
/*!
\brief disable the events from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_event_disable(exti_line_enum linex)
{
EXTI_EVEN &= ~(uint32_t)linex;
}
/*!
\brief enable the software interrupt event from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_enable(exti_line_enum linex)
{
EXTI_SWIEV |= (uint32_t)linex;
}
/*!
\brief disable the software interrupt event from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_disable(exti_line_enum linex)
{
EXTI_SWIEV &= ~(uint32_t)linex;
}
/*!
\brief get EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval FlagStatus: status of flag (RESET or SET)
*/
FlagStatus exti_flag_get(exti_line_enum linex)
{
if(RESET != (EXTI_PD & (uint32_t)linex)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_flag_clear(exti_line_enum linex)
{
EXTI_PD = (uint32_t)linex;
}
/*!
\brief get EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval FlagStatus: status of flag (RESET or SET)
*/
FlagStatus exti_interrupt_flag_get(exti_line_enum linex)
{
if(RESET != (EXTI_PD & (uint32_t)linex)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_flag_clear(exti_line_enum linex)
{
EXTI_PD = (uint32_t)linex;
}
@@ -0,0 +1,249 @@
/*!
\file gd32e50x_exti.c
\brief EXTI driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_exti.h"
#define EXTI_REG_RESET_VALUE ((uint32_t)0x00000000U)
/*!
\brief deinitialize the EXTI
\param[in] none
\param[out] none
\retval none
*/
void exti_deinit(void)
{
/* reset the value of all the EXTI registers */
EXTI_INTEN = EXTI_REG_RESET_VALUE;
EXTI_EVEN = EXTI_REG_RESET_VALUE;
EXTI_RTEN = EXTI_REG_RESET_VALUE;
EXTI_FTEN = EXTI_REG_RESET_VALUE;
EXTI_SWIEV = EXTI_REG_RESET_VALUE;
}
/*!
\brief initialize the EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[in] mode: interrupt or event mode, refer to exti_mode_enum
only one parameter can be selected which is shown as below:
\arg EXTI_INTERRUPT: interrupt mode
\arg EXTI_EVENT: event mode
\param[in] trig_type: interrupt trigger type, refer to exti_trig_type_enum
only one parameter can be selected which is shown as below:
\arg EXTI_TRIG_RISING: rising edge trigger
\arg EXTI_TRIG_FALLING: falling trigger
\arg EXTI_TRIG_BOTH: rising and falling trigger
\arg EXTI_TRIG_NONE: without rising edge or falling edge trigger
\param[out] none
\retval none
*/
void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type)
{
/* reset the EXTI line x */
EXTI_INTEN &= ~(uint32_t)linex;
EXTI_EVEN &= ~(uint32_t)linex;
EXTI_RTEN &= ~(uint32_t)linex;
EXTI_FTEN &= ~(uint32_t)linex;
/* set the EXTI mode and enable the interrupts or events from EXTI line x */
switch(mode){
case EXTI_INTERRUPT:
EXTI_INTEN |= (uint32_t)linex;
break;
case EXTI_EVENT:
EXTI_EVEN |= (uint32_t)linex;
break;
default:
break;
}
/* set the EXTI trigger type */
switch(trig_type){
case EXTI_TRIG_RISING:
EXTI_RTEN |= (uint32_t)linex;
EXTI_FTEN &= ~(uint32_t)linex;
break;
case EXTI_TRIG_FALLING:
EXTI_RTEN &= ~(uint32_t)linex;
EXTI_FTEN |= (uint32_t)linex;
break;
case EXTI_TRIG_BOTH:
EXTI_RTEN |= (uint32_t)linex;
EXTI_FTEN |= (uint32_t)linex;
break;
case EXTI_TRIG_NONE:
default:
break;
}
}
/*!
\brief enable the interrupts from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_enable(exti_line_enum linex)
{
EXTI_INTEN |= (uint32_t)linex;
}
/*!
\brief disable the interrupt from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_disable(exti_line_enum linex)
{
EXTI_INTEN &= ~(uint32_t)linex;
}
/*!
\brief enable the events from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_event_enable(exti_line_enum linex)
{
EXTI_EVEN |= (uint32_t)linex;
}
/*!
\brief disable the events from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_event_disable(exti_line_enum linex)
{
EXTI_EVEN &= ~(uint32_t)linex;
}
/*!
\brief enable the software interrupt event from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_enable(exti_line_enum linex)
{
EXTI_SWIEV |= (uint32_t)linex;
}
/*!
\brief disable the software interrupt event from EXTI line x
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_software_interrupt_disable(exti_line_enum linex)
{
EXTI_SWIEV &= ~(uint32_t)linex;
}
/*!
\brief get EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval FlagStatus: status of flag (RESET or SET)
*/
FlagStatus exti_flag_get(exti_line_enum linex)
{
if(RESET != (EXTI_PD & (uint32_t)linex)){
return SET;
}else{
return RESET;
}
}
/*!
\brief clear EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_flag_clear(exti_line_enum linex)
{
EXTI_PD = (uint32_t)linex;
}
/*!
\brief get EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval FlagStatus: status of flag (RESET or SET)
*/
FlagStatus exti_interrupt_flag_get(exti_line_enum linex)
{
if(RESET != (EXTI_PD & (uint32_t)linex)) {
return SET;
} else {
return RESET;
}
}
/*!
\brief clear EXTI line x interrupt pending flag
\param[in] linex: EXTI line number, refer to exti_line_enum
only one parameter can be selected which is shown as below:
\arg EXTI_x (x=0..21): EXTI line x
\param[out] none
\retval none
*/
void exti_interrupt_flag_clear(exti_line_enum linex)
{
EXTI_PD = (uint32_t)linex;
}
@@ -0,0 +1,875 @@
/*!
\file gd32e50x_fmc.c
\brief FMC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_fmc.h"
/* FMC mask */
#define LOW_8BITS_MASK ((uint32_t)0x000000FFU)
#define HIGH_8BITS_MASK ((uint32_t)0x0000FF00U)
#define LOW_8BITS_MASK1 ((uint32_t)0x00FF0000U)
#define HIGH_8BITS_MASK1 ((uint32_t)0xFF000000U)
#define LOW_16BITS_MASK ((uint32_t)0x0000FFFFU)
#define HIGH_16BITS_MASK ((uint32_t)0xFFFF0000U)
/* USER of option bytes mask */
#define OB_USER_MASK ((uint8_t)0x38U)
/* default offset */
#define FMC_OBSTAT_USER_OFFSET 2U
#define FMC_OBSTAT_DATA_OFFSET 10U
/* return the FMC state */
static fmc_state_enum fmc_state_get(void);
/* check FMC ready or not */
static fmc_state_enum fmc_ready_wait(uint32_t timeout);
/*!
\brief unlock the main FMC operation
it is better to used in pairs with fmc_lock
\param[in] none
\param[out] none
\retval none
*/
void fmc_unlock(void)
{
if(RESET != (FMC_CTL & FMC_CTL_LK)){
/* write the FMC unlock key */
FMC_KEY = UNLOCK_KEY0;
FMC_KEY = UNLOCK_KEY1;
}
}
/*!
\brief lock the main FMC operation
it is better to used in pairs with fmc_unlock after an operation
\param[in] none
\param[out] none
\retval none
*/
void fmc_lock(void)
{
/* set the LK bit */
FMC_CTL |= FMC_CTL_LK;
}
/*!
\brief set the wait state
\param[in] wscnt: wait state
only one parameter can be selected which is shown as below:
\arg FMC_WAIT_STATE_0: 0 wait state added
\arg FMC_WAIT_STATE_1: 1 wait state added
\arg FMC_WAIT_STATE_2: 2 wait state added
\arg FMC_WAIT_STATE_3: 3 wait state added
\arg FMC_WAIT_STATE_4: 4 wait state added
\param[out] none
\retval none
*/
void fmc_wscnt_set(uint32_t wscnt)
{
uint32_t ws;
ws = FMC_WS;
/* set the wait state counter value */
ws &= ~FMC_WS_WSCNT;
FMC_WS = (ws | wscnt);
}
/*!
\brief enable pre-fetch
\param[in] none
\param[out] none
\retval none
*/
void fmc_prefetch_enable(void)
{
FMC_WS |= FMC_WS_PFEN;
}
/*!
\brief disable pre-fetch
\param[in] none
\param[out] none
\retval none
*/
void fmc_prefetch_disable(void)
{
FMC_WS &= ~FMC_WS_PFEN;
}
/*!
\brief enable IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_enable(void)
{
FMC_WS |= FMC_WS_ICEN;
}
/*!
\brief disable IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_disable(void)
{
FMC_WS &= ~FMC_WS_ICEN;
}
/*!
\brief reset IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_reset(void)
{
FMC_WS |= FMC_WS_ICRST;
}
/*!
\brief enable DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_enable(void)
{
FMC_WS |= FMC_WS_DCEN;
}
/*!
\brief disable DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_disable(void)
{
FMC_WS &= ~FMC_WS_DCEN;
}
/*!
\brief reset DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_reset(void)
{
FMC_WS |= FMC_WS_DCRST;
}
/*!
\brief FMC erase page
\param[in] page_address: target page address
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_page_erase(uint32_t page_address)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* start page erase */
FMC_CTL |= FMC_CTL_PER;
FMC_ADDR = page_address;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PER bit */
FMC_CTL &= ~FMC_CTL_PER;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC erase whole chip
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_mass_erase(void)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* start chip erase */
FMC_CTL |= FMC_CTL_MER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the MER bit */
FMC_CTL &= ~FMC_CTL_MER;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC program a word at the corresponding address
\param[in] address: address to program
\param[in] data: word to program
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* set the PG bit to start program */
FMC_CTL |= FMC_CTL_PG;
REG32(address) = data;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PG bit */
FMC_CTL &= ~FMC_CTL_PG;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief unlock the option bytes operation
it is better to used in pairs with ob_lock
\param[in] none
\param[out] none
\retval none
*/
void ob_unlock(void)
{
if(RESET == (FMC_CTL & FMC_CTL_OBWEN)){
/* write the FMC ob unlock key */
FMC_OBKEY = UNLOCK_KEY0;
FMC_OBKEY = UNLOCK_KEY1;
}
}
/*!
\brief lock the option bytes operation
it is better to used in pairs with ob_unlock after an operation
\param[in] none
\param[out] none
\retval none
*/
void ob_lock(void)
{
/* reset the OBWEN bit */
FMC_CTL &= ~FMC_CTL_OBWEN;
}
/*!
\brief erase the option bytes
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_erase(void)
{
uint32_t temp_spc;
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
/* set the OBPG bit */
FMC_CTL |= FMC_CTL_OBPG;
/* restore the last get option bytes security protection code */
OB_SPC_USER = (temp_spc & LOW_8BITS_MASK) | LOW_8BITS_MASK1;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief enable write protection
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_wp: specify sector to be write protected
only one parameter can be selected which are shown as below:
\arg OB_WP_NONE: disable all write protection
\arg OB_WP_x(x=0..31): write protect specify sector
\arg OB_WP_ALL: write protect all sector
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
ob_wp = (uint32_t)(~ob_wp);
op_byte[2] = (ob_wp & LOW_8BITS_MASK) | ((ob_wp & HIGH_8BITS_MASK) << 8);
op_byte[3] = ((ob_wp & LOW_8BITS_MASK1) >> 16) | ((ob_wp & HIGH_8BITS_MASK1) >> 8);
if(FMC_READY == fmc_state){
/* start erase the option byte */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief configure security protection
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_spc: specify security protection
only one parameter can be selected which is shown as below:
\arg FMC_NSPC: no security protection
\arg FMC_LSPC: low security protection
\arg FMC_HSPC: high security protection
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER & LOW_16BITS_MASK;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
op_byte[0] = ((uint32_t)(ob_spc)) | ((op_byte[0] & HIGH_16BITS_MASK));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief program option bytes USER
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_fwdgt: option bytes free watchdog value
only one parameter can be selected which is shown as below:
\arg OB_FWDGT_SW: software free watchdog
\arg OB_FWDGT_HW: hardware free watchdog
\param[in] ob_deepsleep: option bytes deepsleep reset value
only one parameter can be selected which is shown as below:
\arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
\arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
\param[in] ob_stdby:option bytes standby reset value
only one parameter can be selected which is shown as below:
\arg OB_STDBY_NRST: no reset when entering standby mode
\arg OB_STDBY_RST: generate a reset instead of entering standby mode
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_user_write(uint8_t ob_fwdgt, uint8_t ob_deepsleep, uint8_t ob_stdby)
{
uint32_t temp_spc;
uint8_t temp;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
temp = ((uint8_t)((uint8_t)(((uint8_t)(ob_fwdgt) | ob_deepsleep) | ob_stdby)) | (OB_USER_MASK));
op_byte[0] = ((uint32_t)(temp) << 16U) | ((op_byte[0] & LOW_16BITS_MASK));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief program option bytes DATA
\param[in] data: the byte to be programmed
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_data_program(uint16_t ob_data)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
op_byte[1] = (uint32_t)((ob_data & LOW_8BITS_MASK) | ((ob_data & HIGH_8BITS_MASK) << 8));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief get the value of option bytes USER
\param[in] none
\param[out] none
\retval the option bytes USER value
*/
uint8_t ob_user_get(void)
{
/* return the FMC user option bytes value */
return (uint8_t)(FMC_OBSTAT >> FMC_OBSTAT_USER_OFFSET);
}
/*!
\brief get the value of option bytes DATA
\param[in] none
\param[out] none
\retval the option bytes DATA value
*/
uint16_t ob_data_get(void)
{
return (uint16_t)(FMC_OBSTAT >> FMC_OBSTAT_DATA_OFFSET);
}
/*!
\brief get the value of option bytes write protection
\param[in] none
\param[out] none
\retval the write protection option bytes value
*/
uint32_t ob_write_protection_get(void)
{
/* return the FMC write protection option bytes value */
return FMC_WP;
}
/*!
\brief get the FMC option bytes security protection state
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ob_security_protection_flag_get(void)
{
FlagStatus spc_state = RESET;
if(RESET != (FMC_OBSTAT & FMC_OBSTAT_SPC)){
spc_state = SET;
}else{
spc_state = RESET;
}
return spc_state;
}
/*!
\brief get FMC flag status
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_BUSY: FMC busy flag
\arg FMC_FLAG_PGERR: FMC program error flag
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag
\arg FMC_FLAG_END: FMC end of operation flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(FMC_STAT & flag){
status = SET;
}
/* return the state of corresponding FMC flag */
return status;
}
/*!
\brief clear the FMC flag
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_PGERR: FMC program error flag
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag
\arg FMC_FLAG_END: FMC end of operation flag
\param[out] none
\retval none
*/
void fmc_flag_clear(uint32_t flag)
{
/* clear the flags */
FMC_STAT = flag;
}
/*!
\brief enable FMC interrupt
\param[in] interrupt: the FMC interrupt
only one parameter can be selected which is shown as below:
\arg FMC_INT_END: FMC end of operation interrupt
\arg FMC_INT_ERR: FMC error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_enable(uint32_t interrupt)
{
FMC_CTL |= interrupt;
}
/*!
\brief disable FMC interrupt
\param[in] interrupt: the FMC interrupt
only one parameter can be selected which is shown as below:
\arg FMC_INT_END: FMC end of operation interrupt
\arg FMC_INT_ERR: FMC error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_disable(uint32_t interrupt)
{
FMC_CTL &= ~(uint32_t)interrupt;
}
/*!
\brief get FMC interrupt flag
\param[in] flag: FMC interrupt flag
only one parameter can be selected which is shown as below:
\arg FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
\arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
\arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_interrupt_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(FMC_STAT & flag){
status = SET;
}
/* return the state of corresponding FMC flag */
return status;
}
/*!
\brief clear FMC interrupt flag
\param[in] flag: FMC interrupt flag
one or more parameters can be selected which is shown as below:
\arg FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
\arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
\arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
\param[out] none
\retval none
*/
void fmc_interrupt_flag_clear(uint32_t flag)
{
/* clear the flag */
FMC_STAT = flag;
}
/*!
\brief get the FMC state
\param[in] none
\param[out] none
\retval state of FMC, refer to fmc_state_enum
*/
static fmc_state_enum fmc_state_get(void)
{
fmc_state_enum fmc_state = FMC_READY;
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)){
fmc_state = FMC_BUSY;
}else{
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)){
fmc_state = FMC_WPERR;
}else{
if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGERR))){
fmc_state = FMC_PGERR;
}else{
if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGAERR))){
fmc_state = FMC_PGAERR;
}
}
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief check whether FMC is ready or not
\param[in] timeout: timeout count
\param[out] none
\retval state of FMC, refer to fmc_state_enum
*/
static fmc_state_enum fmc_ready_wait(uint32_t timeout)
{
fmc_state_enum fmc_state = FMC_BUSY;
/* wait for FMC ready */
do{
/* get FMC state */
fmc_state = fmc_state_get();
timeout--;
}while((FMC_BUSY == fmc_state) && (0x00U != timeout));
if(FMC_BUSY == fmc_state){
fmc_state = FMC_TOERR;
}
/* return the FMC state */
return fmc_state;
}
@@ -0,0 +1,875 @@
/*!
\file gd32e50x_fmc.c
\brief FMC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_fmc.h"
/* FMC mask */
#define LOW_8BITS_MASK ((uint32_t)0x000000FFU)
#define HIGH_8BITS_MASK ((uint32_t)0x0000FF00U)
#define LOW_8BITS_MASK1 ((uint32_t)0x00FF0000U)
#define HIGH_8BITS_MASK1 ((uint32_t)0xFF000000U)
#define LOW_16BITS_MASK ((uint32_t)0x0000FFFFU)
#define HIGH_16BITS_MASK ((uint32_t)0xFFFF0000U)
/* USER of option bytes mask */
#define OB_USER_MASK ((uint8_t)0x38U)
/* default offset */
#define FMC_OBSTAT_USER_OFFSET 2U
#define FMC_OBSTAT_DATA_OFFSET 10U
/* return the FMC state */
static fmc_state_enum fmc_state_get(void);
/* check FMC ready or not */
static fmc_state_enum fmc_ready_wait(uint32_t timeout);
/*!
\brief unlock the main FMC operation
it is better to used in pairs with fmc_lock
\param[in] none
\param[out] none
\retval none
*/
void fmc_unlock(void)
{
if(RESET != (FMC_CTL & FMC_CTL_LK)){
/* write the FMC unlock key */
FMC_KEY = UNLOCK_KEY0;
FMC_KEY = UNLOCK_KEY1;
}
}
/*!
\brief lock the main FMC operation
it is better to used in pairs with fmc_unlock after an operation
\param[in] none
\param[out] none
\retval none
*/
void fmc_lock(void)
{
/* set the LK bit */
FMC_CTL |= FMC_CTL_LK;
}
/*!
\brief set the wait state
\param[in] wscnt: wait state
only one parameter can be selected which is shown as below:
\arg FMC_WAIT_STATE_0: 0 wait state added
\arg FMC_WAIT_STATE_1: 1 wait state added
\arg FMC_WAIT_STATE_2: 2 wait state added
\arg FMC_WAIT_STATE_3: 3 wait state added
\arg FMC_WAIT_STATE_4: 4 wait state added
\param[out] none
\retval none
*/
void fmc_wscnt_set(uint32_t wscnt)
{
uint32_t ws;
ws = FMC_WS;
/* set the wait state counter value */
ws &= ~FMC_WS_WSCNT;
FMC_WS = (ws | wscnt);
}
/*!
\brief enable pre-fetch
\param[in] none
\param[out] none
\retval none
*/
void fmc_prefetch_enable(void)
{
FMC_WS |= FMC_WS_PFEN;
}
/*!
\brief disable pre-fetch
\param[in] none
\param[out] none
\retval none
*/
void fmc_prefetch_disable(void)
{
FMC_WS &= ~FMC_WS_PFEN;
}
/*!
\brief enable IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_enable(void)
{
FMC_WS |= FMC_WS_ICEN;
}
/*!
\brief disable IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_disable(void)
{
FMC_WS &= ~FMC_WS_ICEN;
}
/*!
\brief reset IBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_ibus_reset(void)
{
FMC_WS |= FMC_WS_ICRST;
}
/*!
\brief enable DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_enable(void)
{
FMC_WS |= FMC_WS_DCEN;
}
/*!
\brief disable DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_disable(void)
{
FMC_WS &= ~FMC_WS_DCEN;
}
/*!
\brief reset DBUS cache
\param[in] none
\param[out] none
\retval none
*/
void fmc_dbus_reset(void)
{
FMC_WS |= FMC_WS_DCRST;
}
/*!
\brief FMC erase page
\param[in] page_address: target page address
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_page_erase(uint32_t page_address)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* start page erase */
FMC_CTL |= FMC_CTL_PER;
FMC_ADDR = page_address;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PER bit */
FMC_CTL &= ~FMC_CTL_PER;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC erase whole chip
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_mass_erase(void)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* start chip erase */
FMC_CTL |= FMC_CTL_MER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the MER bit */
FMC_CTL &= ~FMC_CTL_MER;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief FMC program a word at the corresponding address
\param[in] address: address to program
\param[in] data: word to program
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
{
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* set the PG bit to start program */
FMC_CTL |= FMC_CTL_PG;
REG32(address) = data;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PG bit */
FMC_CTL &= ~FMC_CTL_PG;
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief unlock the option bytes operation
it is better to used in pairs with ob_lock
\param[in] none
\param[out] none
\retval none
*/
void ob_unlock(void)
{
if(RESET == (FMC_CTL & FMC_CTL_OBWEN)){
/* write the FMC ob unlock key */
FMC_OBKEY = UNLOCK_KEY0;
FMC_OBKEY = UNLOCK_KEY1;
}
}
/*!
\brief lock the option bytes operation
it is better to used in pairs with ob_unlock after an operation
\param[in] none
\param[out] none
\retval none
*/
void ob_lock(void)
{
/* reset the OBWEN bit */
FMC_CTL &= ~FMC_CTL_OBWEN;
}
/*!
\brief erase the option bytes
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] none
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_erase(void)
{
uint32_t temp_spc;
fmc_state_enum fmc_state;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
/* set the OBPG bit */
FMC_CTL |= FMC_CTL_OBPG;
/* restore the last get option bytes security protection code */
OB_SPC_USER = (temp_spc & LOW_8BITS_MASK) | LOW_8BITS_MASK1;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief enable write protection
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_wp: specify sector to be write protected
only one parameter can be selected which are shown as below:
\arg OB_WP_NONE: disable all write protection
\arg OB_WP_x(x=0..31): write protect specify sector
\arg OB_WP_ALL: write protect all sector
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
ob_wp = (uint32_t)(~ob_wp);
op_byte[2] = (ob_wp & LOW_8BITS_MASK) | ((ob_wp & HIGH_8BITS_MASK) << 8);
op_byte[3] = ((ob_wp & LOW_8BITS_MASK1) >> 16) | ((ob_wp & HIGH_8BITS_MASK1) >> 8);
if(FMC_READY == fmc_state){
/* start erase the option byte */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief configure security protection
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_spc: specify security protection
only one parameter can be selected which is shown as below:
\arg FMC_NSPC: no security protection
\arg FMC_LSPC: low security protection
\arg FMC_HSPC: high security protection
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER & LOW_16BITS_MASK;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
op_byte[0] = ((uint32_t)(ob_spc)) | ((op_byte[0] & HIGH_16BITS_MASK));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief program option bytes USER
programmer must ensure FMC & option bytes are both unlocked before calling this function
\param[in] ob_fwdgt: option bytes free watchdog value
only one parameter can be selected which is shown as below:
\arg OB_FWDGT_SW: software free watchdog
\arg OB_FWDGT_HW: hardware free watchdog
\param[in] ob_deepsleep: option bytes deepsleep reset value
only one parameter can be selected which is shown as below:
\arg OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
\arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
\param[in] ob_stdby:option bytes standby reset value
only one parameter can be selected which is shown as below:
\arg OB_STDBY_NRST: no reset when entering standby mode
\arg OB_STDBY_RST: generate a reset instead of entering standby mode
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_user_write(uint8_t ob_fwdgt, uint8_t ob_deepsleep, uint8_t ob_stdby)
{
uint32_t temp_spc;
uint8_t temp;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
temp = ((uint8_t)((uint8_t)(((uint8_t)(ob_fwdgt) | ob_deepsleep) | ob_stdby)) | (OB_USER_MASK));
op_byte[0] = ((uint32_t)(temp) << 16U) | ((op_byte[0] & LOW_16BITS_MASK));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief program option bytes DATA
\param[in] data: the byte to be programmed
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_PGERR: program error
\arg FMC_PGAERR: program alignment error
\arg FMC_WPERR: erase/program protection error
\arg FMC_TOERR: timeout error
\arg FMC_OB_HSPC: high security protection
*/
fmc_state_enum ob_data_program(uint16_t ob_data)
{
uint32_t temp_spc;
uint8_t i;
uint32_t op_byte[4];
fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
temp_spc = OB_SPC_USER;
/* check the option bytes security protection value */
if((RESET != ob_security_protection_flag_get()) && (FMC_HSPC == (temp_spc & LOW_8BITS_MASK))){
fmc_state = FMC_OB_HSPC;
}
for(i = 0U; i < 4U; i++){
op_byte[i] = OP_BYTE(i);
}
op_byte[1] = (uint32_t)((ob_data & LOW_8BITS_MASK) | ((ob_data & HIGH_8BITS_MASK) << 8));
if(FMC_READY == fmc_state){
/* start erase the option bytes */
FMC_CTL |= FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_START;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state){
/* reset the OBER bit and enable the option bytes programming */
FMC_CTL &= ~FMC_CTL_OBER;
FMC_CTL |= FMC_CTL_OBPG;
for(i = 0U; i < 4U; i++){
OP_BYTE(i) = op_byte[i];
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY != fmc_state){
break;
}
}
/* reset the OBPG bit */
FMC_CTL &= ~FMC_CTL_OBPG;
}else{
/* reset the OBER bit */
FMC_CTL &= ~FMC_CTL_OBER;
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief get the value of option bytes USER
\param[in] none
\param[out] none
\retval the option bytes USER value
*/
uint8_t ob_user_get(void)
{
/* return the FMC user option bytes value */
return (uint8_t)(FMC_OBSTAT >> FMC_OBSTAT_USER_OFFSET);
}
/*!
\brief get the value of option bytes DATA
\param[in] none
\param[out] none
\retval the option bytes DATA value
*/
uint16_t ob_data_get(void)
{
return (uint16_t)(FMC_OBSTAT >> FMC_OBSTAT_DATA_OFFSET);
}
/*!
\brief get the value of option bytes write protection
\param[in] none
\param[out] none
\retval the write protection option bytes value
*/
uint32_t ob_write_protection_get(void)
{
/* return the FMC write protection option bytes value */
return FMC_WP;
}
/*!
\brief get the FMC option bytes security protection state
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus ob_security_protection_flag_get(void)
{
FlagStatus spc_state = RESET;
if(RESET != (FMC_OBSTAT & FMC_OBSTAT_SPC)){
spc_state = SET;
}else{
spc_state = RESET;
}
return spc_state;
}
/*!
\brief get FMC flag status
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_BUSY: FMC busy flag
\arg FMC_FLAG_PGERR: FMC program error flag
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag
\arg FMC_FLAG_END: FMC end of operation flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(FMC_STAT & flag){
status = SET;
}
/* return the state of corresponding FMC flag */
return status;
}
/*!
\brief clear the FMC flag
\param[in] flag: FMC flag
only one parameter can be selected which is shown as below:
\arg FMC_FLAG_PGERR: FMC program error flag
\arg FMC_FLAG_PGAERR: FMC program alignment error flag
\arg FMC_FLAG_WPERR: FMC erase/program protection error flag
\arg FMC_FLAG_END: FMC end of operation flag
\param[out] none
\retval none
*/
void fmc_flag_clear(uint32_t flag)
{
/* clear the flags */
FMC_STAT = flag;
}
/*!
\brief enable FMC interrupt
\param[in] interrupt: the FMC interrupt
only one parameter can be selected which is shown as below:
\arg FMC_INT_END: FMC end of operation interrupt
\arg FMC_INT_ERR: FMC error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_enable(uint32_t interrupt)
{
FMC_CTL |= interrupt;
}
/*!
\brief disable FMC interrupt
\param[in] interrupt: the FMC interrupt
only one parameter can be selected which is shown as below:
\arg FMC_INT_END: FMC end of operation interrupt
\arg FMC_INT_ERR: FMC error interrupt
\param[out] none
\retval none
*/
void fmc_interrupt_disable(uint32_t interrupt)
{
FMC_CTL &= ~(uint32_t)interrupt;
}
/*!
\brief get FMC interrupt flag
\param[in] flag: FMC interrupt flag
only one parameter can be selected which is shown as below:
\arg FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
\arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
\arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fmc_interrupt_flag_get(uint32_t flag)
{
FlagStatus status = RESET;
if(FMC_STAT & flag){
status = SET;
}
/* return the state of corresponding FMC flag */
return status;
}
/*!
\brief clear FMC interrupt flag
\param[in] flag: FMC interrupt flag
one or more parameters can be selected which is shown as below:
\arg FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
\arg FMC_INT_FLAG_PGAERR: FMC program alignment error interrupt flag
\arg FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
\arg FMC_INT_FLAG_END: FMC end of operation interrupt flag
\param[out] none
\retval none
*/
void fmc_interrupt_flag_clear(uint32_t flag)
{
/* clear the flag */
FMC_STAT = flag;
}
/*!
\brief get the FMC state
\param[in] none
\param[out] none
\retval state of FMC, refer to fmc_state_enum
*/
static fmc_state_enum fmc_state_get(void)
{
fmc_state_enum fmc_state = FMC_READY;
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)){
fmc_state = FMC_BUSY;
}else{
if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)){
fmc_state = FMC_WPERR;
}else{
if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGERR))){
fmc_state = FMC_PGERR;
}else{
if((uint32_t)0x00U != (FMC_STAT & (FMC_STAT_PGAERR))){
fmc_state = FMC_PGAERR;
}
}
}
}
/* return the FMC state */
return fmc_state;
}
/*!
\brief check whether FMC is ready or not
\param[in] timeout: timeout count
\param[out] none
\retval state of FMC, refer to fmc_state_enum
*/
static fmc_state_enum fmc_ready_wait(uint32_t timeout)
{
fmc_state_enum fmc_state = FMC_BUSY;
/* wait for FMC ready */
do{
/* get FMC state */
fmc_state = fmc_state_get();
timeout--;
}while((FMC_BUSY == fmc_state) && (0x00U != timeout));
if(FMC_BUSY == fmc_state){
fmc_state = FMC_TOERR;
}
/* return the FMC state */
return fmc_state;
}
@@ -0,0 +1,227 @@
/*!
\file gd32e50x_fwdgt.c
\brief FWDGT driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_fwdgt.h"
/*!
\brief enable write access to FWDGT_PSC and FWDGT_RLD
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_write_enable(void)
{
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
}
/*!
\brief disable write access to FWDGT_PSC and FWDGT_RLD
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_write_disable(void)
{
FWDGT_CTL = FWDGT_WRITEACCESS_DISABLE;
}
/*!
\brief start the free watchdog timer counter
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_enable(void)
{
FWDGT_CTL = FWDGT_KEY_ENABLE;
}
/*!
\brief configure the free watchdog timer counter prescaler value
\param[in] prescaler_value: specify prescaler value
only one parameter can be selected which is shown as below:
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_prescaler_value_config(uint16_t prescaler_value)
{
uint32_t timeout = FWDGT_PSC_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* enable write access to FWDGT_PSC */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT */
FWDGT_PSC = (uint32_t)prescaler_value;
/* wait until the PUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
return status;
}
/*!
\brief configure the free watchdog timer counter reload value
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_reload_value_config(uint16_t reload_value)
{
uint32_t timeout = FWDGT_RLD_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* enable write access to FWDGT_RLD */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT_RLD */
FWDGT_RLD = RLD_RLD(reload_value);
/* wait until the RUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
return status;
}
/*!
\brief reload the counter of FWDGT
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_counter_reload(void)
{
FWDGT_CTL = FWDGT_KEY_RELOAD;
}
/*!
\brief configure counter reload value, and prescaler divider value
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
\param[in] prescaler_value: FWDGT prescaler value
only one parameter can be selected which is shown as below:
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_config(uint16_t reload_value, uint8_t prescaler_value)
{
uint32_t timeout = FWDGT_PSC_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* start the free watchdog timer counter */
FWDGT_CTL = FWDGT_KEY_ENABLE;
/* enable write access to FWDGT_PSC,and FWDGT_RLD */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT PSC */
FWDGT_PSC = (uint32_t)prescaler_value;
/* wait until the PUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
if(SUCCESS == status) {
/* configure FWDGT_RLD */
FWDGT_RLD = RLD_RLD(reload_value);
/* wait until the RUD flag to be reset */
timeout = FWDGT_RLD_TIMEOUT;
do {
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
}
if(SUCCESS == status) {
/* reload the counter */
FWDGT_CTL = FWDGT_KEY_RELOAD;
}
return status;
}
/*!
\brief get flag state of FWDGT
\param[in] flag: flag to get
only one parameter can be selected which is shown as below:
\arg FWDGT_FLAG_PUD: a write operation to FWDGT_PSC register is on going
\arg FWDGT_FLAG_RUD: a write operation to FWDGT_RLD register is on going
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fwdgt_flag_get(uint16_t flag)
{
FlagStatus flag_status = RESET;
if(FWDGT_STAT & flag) {
flag_status = SET;
}
return flag_status;
}
@@ -0,0 +1,227 @@
/*!
\file gd32e50x_fwdgt.c
\brief FWDGT driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_fwdgt.h"
/*!
\brief enable write access to FWDGT_PSC and FWDGT_RLD
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_write_enable(void)
{
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
}
/*!
\brief disable write access to FWDGT_PSC and FWDGT_RLD
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_write_disable(void)
{
FWDGT_CTL = FWDGT_WRITEACCESS_DISABLE;
}
/*!
\brief start the free watchdog timer counter
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_enable(void)
{
FWDGT_CTL = FWDGT_KEY_ENABLE;
}
/*!
\brief configure the free watchdog timer counter prescaler value
\param[in] prescaler_value: specify prescaler value
only one parameter can be selected which is shown as below:
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_prescaler_value_config(uint16_t prescaler_value)
{
uint32_t timeout = FWDGT_PSC_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* enable write access to FWDGT_PSC */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT */
FWDGT_PSC = (uint32_t)prescaler_value;
/* wait until the PUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
return status;
}
/*!
\brief configure the free watchdog timer counter reload value
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_reload_value_config(uint16_t reload_value)
{
uint32_t timeout = FWDGT_RLD_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* enable write access to FWDGT_RLD */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT_RLD */
FWDGT_RLD = RLD_RLD(reload_value);
/* wait until the RUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
return status;
}
/*!
\brief reload the counter of FWDGT
\param[in] none
\param[out] none
\retval none
*/
void fwdgt_counter_reload(void)
{
FWDGT_CTL = FWDGT_KEY_RELOAD;
}
/*!
\brief configure counter reload value, and prescaler divider value
\param[in] reload_value: specify reload value(0x0000 - 0x0FFF)
\param[in] prescaler_value: FWDGT prescaler value
only one parameter can be selected which is shown as below:
\arg FWDGT_PSC_DIV4: FWDGT prescaler set to 4
\arg FWDGT_PSC_DIV8: FWDGT prescaler set to 8
\arg FWDGT_PSC_DIV16: FWDGT prescaler set to 16
\arg FWDGT_PSC_DIV32: FWDGT prescaler set to 32
\arg FWDGT_PSC_DIV64: FWDGT prescaler set to 64
\arg FWDGT_PSC_DIV128: FWDGT prescaler set to 128
\arg FWDGT_PSC_DIV256: FWDGT prescaler set to 256
\param[out] none
\retval ErrStatus: ERROR or SUCCESS
*/
ErrStatus fwdgt_config(uint16_t reload_value, uint8_t prescaler_value)
{
uint32_t timeout = FWDGT_PSC_TIMEOUT;
uint32_t flag_status = RESET;
ErrStatus status = SUCCESS;
/* start the free watchdog timer counter */
FWDGT_CTL = FWDGT_KEY_ENABLE;
/* enable write access to FWDGT_PSC,and FWDGT_RLD */
FWDGT_CTL = FWDGT_WRITEACCESS_ENABLE;
/* configure FWDGT PSC */
FWDGT_PSC = (uint32_t)prescaler_value;
/* wait until the PUD flag to be reset */
do {
flag_status = FWDGT_STAT & FWDGT_STAT_PUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
if(SUCCESS == status) {
/* configure FWDGT_RLD */
FWDGT_RLD = RLD_RLD(reload_value);
/* wait until the RUD flag to be reset */
timeout = FWDGT_RLD_TIMEOUT;
do {
flag_status = FWDGT_STAT & FWDGT_STAT_RUD;
} while((--timeout > 0U) && ((uint32_t)RESET != flag_status));
if((uint32_t)RESET != flag_status) {
status = ERROR;
}
}
if(SUCCESS == status) {
/* reload the counter */
FWDGT_CTL = FWDGT_KEY_RELOAD;
}
return status;
}
/*!
\brief get flag state of FWDGT
\param[in] flag: flag to get
only one parameter can be selected which is shown as below:
\arg FWDGT_FLAG_PUD: a write operation to FWDGT_PSC register is on going
\arg FWDGT_FLAG_RUD: a write operation to FWDGT_RLD register is on going
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus fwdgt_flag_get(uint16_t flag)
{
FlagStatus flag_status = RESET;
if(FWDGT_STAT & flag) {
flag_status = SET;
}
return flag_status;
}
@@ -0,0 +1,699 @@
/*!
\file gd32e50x_gpio.c
\brief GPIO driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_gpio.h"
#define AFIO_EXTI_SOURCE_MASK ((uint8_t)0x03U) /*!< AFIO exti source selection mask*/
#define AFIO_EXTI_SOURCE_FIELDS ((uint8_t)0x04U) /*!< select AFIO exti source registers */
#define LSB_16BIT_MASK ((uint16_t)0xFFFFU) /*!< LSB 16-bit mask */
#define PCF_POSITION_MASK ((uint32_t)0x000F0000U) /*!< AFIO_PCF register position mask */
#define PCF_SWJCFG_MASK ((uint32_t)0xF8FFFFFFU) /*!< AFIO_PCF register SWJCFG mask */
#define PCF_LOCATION1_MASK ((uint32_t)0x00200000U) /*!< AFIO_PCF register location1 mask */
#define PCF_LOCATION2_MASK ((uint32_t)0x00100000U) /*!< AFIO_PCF register location2 mask */
#define AFIO_PCF1_FIELDS ((uint32_t)0x80000000U) /*!< select AFIO_PCF1 register */
#define GPIO_OUTPUT_PORT_OFFSET ((uint32_t)4U) /*!< GPIO event output port offset*/
/*!
\brief reset GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval none
*/
void gpio_deinit(uint32_t gpio_periph)
{
switch(gpio_periph){
case GPIOA:
/* reset GPIOA */
rcu_periph_reset_enable(RCU_GPIOARST);
rcu_periph_reset_disable(RCU_GPIOARST);
break;
case GPIOB:
/* reset GPIOB */
rcu_periph_reset_enable(RCU_GPIOBRST);
rcu_periph_reset_disable(RCU_GPIOBRST);
break;
case GPIOC:
/* reset GPIOC */
rcu_periph_reset_enable(RCU_GPIOCRST);
rcu_periph_reset_disable(RCU_GPIOCRST);
break;
case GPIOD:
/* reset GPIOD */
rcu_periph_reset_enable(RCU_GPIODRST);
rcu_periph_reset_disable(RCU_GPIODRST);
break;
case GPIOE:
/* reset GPIOE */
rcu_periph_reset_enable(RCU_GPIOERST);
rcu_periph_reset_disable(RCU_GPIOERST);
break;
case GPIOF:
/* reset GPIOF */
rcu_periph_reset_enable(RCU_GPIOFRST);
rcu_periph_reset_disable(RCU_GPIOFRST);
break;
case GPIOG:
/* reset GPIOG */
rcu_periph_reset_enable(RCU_GPIOGRST);
rcu_periph_reset_disable(RCU_GPIOGRST);
break;
default:
break;
}
}
/*!
\brief reset alternate function I/O(AFIO)
\param[in] none
\param[out] none
\retval none
*/
void gpio_afio_deinit(void)
{
rcu_periph_reset_enable(RCU_AFRST);
rcu_periph_reset_disable(RCU_AFRST);
}
/*!
\brief GPIO parameter initialization
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] mode: gpio pin mode
only one parameter can be selected which is shown as below:
\arg GPIO_MODE_AIN: analog input mode
\arg GPIO_MODE_IN_FLOATING: floating input mode
\arg GPIO_MODE_IPD: pull-down input mode
\arg GPIO_MODE_IPU: pull-up input mode
\arg GPIO_MODE_OUT_OD: GPIO output with open-drain
\arg GPIO_MODE_OUT_PP: GPIO output with push-pull
\arg GPIO_MODE_AF_OD: AFIO output with open-drain
\arg GPIO_MODE_AF_PP: AFIO output with push-pull
\param[in] speed: gpio output max speed value
only one parameter can be selected which is shown as below:
\arg GPIO_OSPEED_10MHZ: output max speed 10MHz
\arg GPIO_OSPEED_2MHZ: output max speed 2MHz
\arg GPIO_OSPEED_50MHZ: output max speed 50MHz
\arg GPIO_OSPEED_MAX: output max speed more than 50MHz
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_init(uint32_t gpio_periph, uint32_t mode, uint32_t speed, uint32_t pin)
{
uint16_t i;
uint32_t temp_mode = 0U;
uint32_t reg = 0U;
/* GPIO mode configuration */
temp_mode = (uint32_t)(mode & ((uint32_t)0x0FU));
/* GPIO speed configuration */
if(((uint32_t)0x00U) != ((uint32_t)mode & ((uint32_t)0x10U))){
/* output mode max speed */
if(GPIO_OSPEED_MAX == (uint32_t)speed){
temp_mode |= (uint32_t)0x03U;
/* set the corresponding SPD bit */
GPIOx_SPD(gpio_periph) |= (uint32_t)pin ;
}else{
/* output mode max speed:10MHz,2MHz,50MHz */
temp_mode |= (uint32_t)speed;
}
}
/* configure the eight low port pins with GPIO_CTL0 */
for(i = 0U;i < 8U;i++){
if((1U << i) & pin){
reg = GPIO_CTL0(gpio_periph);
/* clear the specified pin mode bits */
reg &= ~GPIO_MODE_MASK(i);
/* set the specified pin mode bits */
reg |= GPIO_MODE_SET(i, temp_mode);
/* set IPD or IPU */
if(GPIO_MODE_IPD == mode){
/* reset the corresponding OCTL bit */
GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin);
}else{
/* set the corresponding OCTL bit */
if(GPIO_MODE_IPU == mode){
GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin);
}
}
/* set GPIO_CTL0 register */
GPIO_CTL0(gpio_periph) = reg;
}
}
/* configure the eight high port pins with GPIO_CTL1 */
for(i = 8U;i < 16U;i++){
if((1U << i) & pin){
reg = GPIO_CTL1(gpio_periph);
/* clear the specified pin mode bits */
reg &= ~GPIO_MODE_MASK(i - 8U);
/* set the specified pin mode bits */
reg |= GPIO_MODE_SET(i - 8U, temp_mode);
/* set IPD or IPU */
if(GPIO_MODE_IPD == mode){
/* reset the corresponding OCTL bit */
GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin);
}else{
/* set the corresponding OCTL bit */
if(GPIO_MODE_IPU == mode){
GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin);
}
}
/* set GPIO_CTL1 register */
GPIO_CTL1(gpio_periph) = reg;
}
}
}
/*!
\brief set GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_set(uint32_t gpio_periph,uint32_t pin)
{
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}
/*!
\brief reset GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_reset(uint32_t gpio_periph,uint32_t pin)
{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
/*!
\brief write data to the specified GPIO pin
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[in] bit_value: SET or RESET
\arg RESET: clear the port pin
\arg SET: set the port pin
\param[out] none
\retval none
*/
void gpio_bit_write(uint32_t gpio_periph,uint32_t pin,bit_status bit_value)
{
if(RESET != bit_value){
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}else{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
}
/*!
\brief write data to the specified GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] data: specify the value to be written to the port output data register
\param[out] none
\retval none
*/
void gpio_port_write(uint32_t gpio_periph,uint16_t data)
{
GPIO_OCTL(gpio_periph) = (uint32_t)data;
}
/*!
\brief get GPIO pin input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval input status of gpio pin: SET or RESET
*/
FlagStatus gpio_input_bit_get(uint32_t gpio_periph,uint32_t pin)
{
if((uint32_t)RESET != (GPIO_ISTAT(gpio_periph)&(pin))){
return SET;
}else{
return RESET;
}
}
/*!
\brief get GPIO port input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval input status of gpio all pins
*/
uint16_t gpio_input_port_get(uint32_t gpio_periph)
{
return (uint16_t)(GPIO_ISTAT(gpio_periph));
}
/*!
\brief get GPIO pin output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval output status of gpio pin: SET or RESET
*/
FlagStatus gpio_output_bit_get(uint32_t gpio_periph,uint32_t pin)
{
if((uint32_t)RESET !=(GPIO_OCTL(gpio_periph)&(pin))){
return SET;
}else{
return RESET;
}
}
/*!
\brief get GPIO port output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval output status of gpio all pins
*/
uint16_t gpio_output_port_get(uint32_t gpio_periph)
{
return ((uint16_t)GPIO_OCTL(gpio_periph));
}
/*!
\brief configure GPIO pin remap
\param[in] gpio_remap: select the pin to remap
only one parameter can be selected which are shown as below:
\arg GPIO_SPI0_REMAP: SPI0 remapping
\arg GPIO_I2C0_REMAP: I2C0 remapping
\arg GPIO_USART0_REMAP: USART0 remapping
\arg GPIO_USART1_REMAP: USART1 remapping
\arg GPIO_USART2_PARTIAL_REMAP: USART2 partial remapping
\arg GPIO_USART2_FULL_REMAP: USART2 full remapping
\arg GPIO_TIMER0_PARTIAL_REMAP: TIMER0 partial remapping
\arg GPIO_TIMER0_FULL_REMAP: TIMER0 full remapping
\arg GPIO_TIMER1_PARTIAL_REMAP0: TIMER1 partial remapping
\arg GPIO_TIMER1_PARTIAL_REMAP1: TIMER1 partial remapping
\arg GPIO_TIMER1_FULL_REMAP: TIMER1 full remapping
\arg GPIO_TIMER2_PARTIAL_REMAP: TIMER2 partial remapping
\arg GPIO_TIMER2_FULL_REMAP: TIMER2 full remapping
\arg GPIO_TIMER3_REMAP: TIMER3 remapping
\arg GPIO_CAN0_PARTIAL_REMAP: CAN0 partial remapping(not support on GD32EPRT devices)
\arg GPIO_CAN0_FULL_REMAP: CAN0 full remapping(not support on GD32EPRT devices)
\arg GPIO_PD01_REMAP: PD01 remapping
\arg GPIO_TIMER4CH3_IREMAP: TIMER4 channel3 internal remapping
\arg GPIO_ADC0_ETRGRT_REMAP: ADC0 external trigger routine conversion remapping(only for GD32E50X_HD devices)
\arg GPIO_ADC1_ETRGRT_REMAP: ADC1 external trigger routine conversion remapping(only for GD32E50X_HD devices)
\arg GPIO_ENET_REMAP: ENET remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_CAN1_REMAP: CAN1 remapping(not support on GD32EPRT devices)
\arg GPIO_SWJ_NONJTRST_REMAP: full SWJ(JTAG-DP + SW-DP),but without NJTRST
\arg GPIO_SWJ_SWDPENABLE_REMAP: JTAG-DP disabled and SW-DP enabled
\arg GPIO_SWJ_DISABLE_REMAP: JTAG-DP disabled and SW-DP disabled
\arg GPIO_SPI2_REMAP: SPI2 remapping
\arg GPIO_TIMER1ITR1_REMAP: TIMER1 internal trigger 1 remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_PTP_PPS_REMAP: ethernet PTP PPS remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_TIMER8_REMAP: TIMER8 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER9_REMAP: TIMER9 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER10_REMAP: TIMER10 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER12_REMAP: TIMER12 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER13_REMAP: TIMER13 remapping(not support on GD32EPRT devices)
\arg GPIO_EXMC_NADV_REMAP: EXMC_NADV connect/disconnect
\arg GPIO_CTC_REMAP0: CTC remapping(PD15)
\arg GPIO_CTC_REMAP1: CTC remapping(PF0)
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void gpio_pin_remap_config(uint32_t remap, ControlStatus newvalue)
{
uint32_t remap1 = 0U, remap2 = 0U, temp_reg = 0U, temp_mask = 0U;
if(((uint32_t)0x80000000U) == (remap & 0x80000000U)){
/* get AFIO_PCF1 regiter value */
temp_reg = AFIO_PCF1;
}else{
/* get AFIO_PCF0 regiter value */
temp_reg = AFIO_PCF0;
}
temp_mask = (remap & PCF_POSITION_MASK) >> 0x10U;
remap1 = remap & LSB_16BIT_MASK;
/* judge pin remap type */
if((PCF_LOCATION1_MASK | PCF_LOCATION2_MASK) == (remap & (PCF_LOCATION1_MASK | PCF_LOCATION2_MASK))){
temp_reg &= PCF_SWJCFG_MASK;
AFIO_PCF0 &= PCF_SWJCFG_MASK;
}else if(PCF_LOCATION2_MASK == (remap & PCF_LOCATION2_MASK)){
remap2 = ((uint32_t)0x03U) << temp_mask;
temp_reg &= ~remap2;
temp_reg |= ~PCF_SWJCFG_MASK;
}else{
temp_reg &= ~(remap1 << ((remap >> 0x15U)*0x10U));
temp_reg |= ~PCF_SWJCFG_MASK;
}
/* set pin remap value */
if(DISABLE != newvalue){
temp_reg |= (remap1 << ((remap >> 0x15U)*0x10U));
}
if(AFIO_PCF1_FIELDS == (remap & AFIO_PCF1_FIELDS)){
/* set AFIO_PCF1 regiter value */
AFIO_PCF1 = temp_reg;
}else{
/* set AFIO_PCF0 regiter value */
AFIO_PCF0 = temp_reg;
}
}
/*!
\brief configure AFIO port alternate function
\param[in] afio_function: select the port AFIO function(SHRTIMER not support on GD32EPRT devices)
only one parameter can be selected which are shown as below:
\arg AFIO_PA2_CMP1_CFG: configure PA2 alternate function to CMP1
\arg AFIO_PA3_USBHS_CFG: configure PA3 alternate function to USBHS
\arg AFIO_PA5_USBHS_CFG: configure PA5 alternate function to USBHS
\arg AFIO_PA8_I2C2_CFG: configure PA8 alternate function to I2C2
\arg AFIO_PA8_SHRTIMER_CFG: configure PA8 alternate function to SHRTIMER
\arg AFIO_PA9_CAN2_CFG: configure PA9 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PA9_I2C2_CFG: configure PA9 alternate function to I2C2
\arg AFIO_PA9_SHRTIMER_CFG: configure PA9 alternate function to SHRTIMER
\arg AFIO_PA10_CAN2_CFG: configure PA10 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PA10_CMP5_CFG: configure PA10 alternate function to CMP5
\arg AFIO_PA10_SHRTIMER_CFG: configure PA10 alternate function to SHRTIMER
\arg AFIO_PA11_USART5_CFG: configure PA11 alternate function to USART5
\arg AFIO_PA11_SHRTIMER_CFG: configure PA11 alternate function to SHRTIMER
\arg AFIO_PA12_CMP1_CFG: configure PA12 alternate function to CMP1
\arg AFIO_PA12_USART5_CFG: configure PA12 alternate function to USART5
\arg AFIO_PA12_SHRTIMER_CFG: configure PA12 alternate function to SHRTIMER
\arg AFIO_PA15_SHRTIMER_CFG: configure PA15 alternate function to SHRTIMER
\arg AFIO_PB0_USBHS_CFG: configure PB0 alternate function to USBHS
\arg AFIO_PB1_CMP3_CFG: configure PB1 alternate function to CMP3
\arg AFIO_PB1_USBHS_CFG: configure PB1 alternate function to USBHS
\arg AFIO_PB1_SHRTIMER_CFG: configure PB1 alternate function to SHRTIMER
\arg AFIO_PB2_USBHS_CFG: configure PB2 alternate function to USBHS
\arg AFIO_PB2_SHRTIMER_CFG: configure PB2 alternate function to SHRTIMER
\arg AFIO_PB3_SHRTIMER_CFG: configure PB3 alternate function to SHRTIMER
\arg AFIO_PB4_I2S2_CFG: configure PB4 alternate function to I2S2
\arg AFIO_PB4_I2C2_CFG: configure PB4 alternate function to I2C2
\arg AFIO_PB4_SHRTIMER_CFG: configure PB4 alternate function to SHRTIMER
\arg AFIO_PB5_I2C2_CFG: configure PB5 alternate function to I2C2
\arg AFIO_PB5_USBHS_CFG: configure PB5 alternate function to USBHS
\arg AFIO_PB5_SHRTIMER_CFG: configure PB5 alternate function to SHRTIMER
\arg AFIO_PB6_SHRTIMER_CFG: configure PB6 alternate function to SHRTIMER
\arg AFIO_PB7_SHRTIMER_CFG: configure PB7 alternate function to SHRTIMER
\arg AFIO_PB8_I2C2_CFG: configure PB8 alternate function to I2C2
\arg AFIO_PB8_SHRTIMER_CFG: configure PB8 alternate function to SHRTIMER
\arg AFIO_PB9_CMP1_CFG: configure PB9 alternate function to CMP1
\arg AFIO_PB9_SHRTIMER_CFG: configure PB9 alternate function to SHRTIMER
\arg AFIO_PB10_CAN2_CFG: configure PB10 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PB10_USBHS_CFG: configure PB10 alternate function to USBHS
\arg AFIO_PB10_SHRTIMER_CFG: configure PB10 alternate function to SHRTIMER
\arg AFIO_PB11_CAN2_CFG: configure PB11 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PB11_USBHS_CFG: configure PB11 alternate function to USBHS
\arg AFIO_PB11_SHRTIMER_CFG: configure PB11 alternate function to SHRTIMER
\arg AFIO_PB12_USBHS_CFG: configure PB12 alternate function to USBHS
\arg AFIO_PB12_SHRTIMER_CFG: configure PB12 alternate function to SHRTIMER
\arg AFIO_PB13_USBHS_CFG: configure PB13 alternate function to USBHS
\arg AFIO_PB13_SHRTIMER_CFG: configure PB13 alternate function to SHRTIMER
\arg AFIO_PB14_I2S1_CFG: configure PB14 alternate function to I2S1
\arg AFIO_PB14_SHRTIMER_CFG: configure PB14 alternate function to SHRTIMER
\arg AFIO_PB15_SHRTIMER_CFG: configure PB15 alternate function to SHRTIMER
\arg AFIO_PC0_USBHS_CFG: configure PC0 alternate function to USBHS
\arg AFIO_PC2_I2S1_CFG: configure PC2 alternate function to I2S1
\arg AFIO_PC2_USBHS_CFG: configure PC2 alternate function to USBHS
\arg AFIO_PC3_USBHS_CFG: configure PC3 alternate function to USBHS
\arg AFIO_PC6_CMP5_CFG: configure PC6 alternate function to CMP5
\arg AFIO_PC6_USART5_CFG: configure PC6 alternate function to USART5
\arg AFIO_PC6_SHRTIMER_CFG: configure PC6 alternate function to SHRTIMER
\arg AFIO_PC7_USART5_CFG: configure PC7 alternate function to USART5
\arg AFIO_PC7_SHRTIMER_CFG: configure PC7 alternate function to SHRTIMER
\arg AFIO_PC8_USART5_CFG: configure PC8 alternate function to USART5
\arg AFIO_PC8_SHRTIMER_CFG: configure PC8 alternate function to SHRTIMER
\arg AFIO_PC9_I2C2_CFG: configure PC9 alternate function to I2C2
\arg AFIO_PC9_SHRTIMER_CFG: configure PC9 alternate function to SHRTIMER
\arg AFIO_PC10_I2C2_CFG: configure PC10 alternate function to I2C2
\arg AFIO_PC11_I2S2_CFG: configure PC11 alternate function to I2S2
\arg AFIO_PC11_SHRTIMER_CFG: configure PC11 alternate function to SHRTIMER
\arg AFIO_PC12_SHRTIMER_CFG: configure PC12 alternate function to SHRTIMER
\arg AFIO_PD4_SHRTIMER_CFG: configure PD4 alternate function to SHRTIMER
\arg AFIO_PD5_SHRTIMER_CFG: configure PD5 alternate function to SHRTIMER
\arg AFIO_PE0_CAN2_CFG: configure PE0 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PE0_SHRTIMER_CFG: configure PE0 alternate function to SHRTIMER
\arg AFIO_PE1_CAN2_CFG: configure PE1 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PE1_SHRTIMER_CFG: configure PE1 alternate function to SHRTIMER
\arg AFIO_PE8_CMP1_CFG: configure PE8 alternate function to CMP1
\arg AFIO_PE9_CMP3_CFG: configure PE9 alternate function to CMP3
\arg AFIO_PE10_CMP5_CFG: configure PE10 alternate function to CMP5
\arg AFIO_PE11_CMP5_CFG: configure PE11 alternate function to CMP5
\arg AFIO_PE12_CMP3_CFG: configure PE12 alternate function to CMP3
\arg AFIO_PE13_CMP1_CFG: configure PE13 alternate function to CMP1
\arg AFIO_PG6_SHRTIMER_CFG: configure PG6 alternate function to SHRTIMER
\arg AFIO_PG7_USART5_CFG: configure PG7 alternate function to USART5
\arg AFIO_PG7_SHRTIMER_CFG: configure PG7 alternate function to SHRTIMER
\arg AFIO_PG9_USART5_CFG: configure PG9 alternate function to USART5
\arg AFIO_PG10_SHRTIMER_CFG: configure PG10 alternate function to SHRTIMER
\arg AFIO_PG11_SHRTIMER_CFG: configure PG11 alternate function to SHRTIMER
\arg AFIO_PG12_SHRTIMER_CFG: configure PG12 alternate function to SHRTIMER
\arg AFIO_PG13_SHRTIMER_CFG: configure PG13 alternate function to SHRTIMER
\arg AFIO_PG14_USART5_CFG: configure PG14 alternate function to USART5
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void gpio_afio_port_config(uint32_t afio_function, ControlStatus newvalue)
{
uint32_t remap1 = 0U, remap2 = 0U, temp_reg = 0U, temp_mask = 0U;
/* get AFIO_PCFx(x=A,B,C,D,E,G) regiter value */
temp_reg = REG32(AFIO+0x0000003CU+((afio_function>>24)<<2));
temp_mask = (afio_function & PCF_POSITION_MASK) >> 0x10U;
remap1 = afio_function & LSB_16BIT_MASK;
/* judge port function select type */
if(afio_function & PCF_LOCATION2_MASK){
remap2 = ((uint32_t)0x03U) << temp_mask;
remap2 = (remap2 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
temp_reg &= ~remap2;
}else{
temp_reg &= ~(remap1 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
}
/* set pin remap value */
if(DISABLE != newvalue){
temp_reg |= (remap1 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
}
/* set AFIO_PCFx(x=A,B,C,D,E,G) regiter value */
REG32(AFIO+0x0000003CU+((afio_function>>24)<<2)) = temp_reg;
}
#if (defined(GD32E50X_CL) || defined(GD32E508) || defined(GD32EPRT))
/*!
\brief select ethernet MII or RMII PHY
\param[in] enet_sel: ethernet MII or RMII PHY selection
\arg GPIO_ENET_PHY_MII: configure ethernet MAC for connection with an MII PHY
\arg GPIO_ENET_PHY_RMII: configure ethernet MAC for connection with an RMII PHY
\param[out] none
\retval none
*/
void gpio_ethernet_phy_select(uint32_t enet_sel)
{
/* clear AFIO_PCF0_ENET_PHY_SEL bit */
AFIO_PCF0 &= (uint32_t)(~AFIO_PCF0_ENET_PHY_SEL);
/* select MII or RMII PHY */
AFIO_PCF0 |= (uint32_t)enet_sel;
}
#endif /* GD32E50X_CL||GD32E508||GD32EPRT */
/*!
\brief select GPIO pin exti sources
\param[in] output_port: gpio event output port
only one parameter can be selected which are shown as below:
\arg GPIO_PORT_SOURCE_GPIOA: output port source A
\arg GPIO_PORT_SOURCE_GPIOB: output port source B
\arg GPIO_PORT_SOURCE_GPIOC: output port source C
\arg GPIO_PORT_SOURCE_GPIOD: output port source D
\arg GPIO_PORT_SOURCE_GPIOE: output port source E
\arg GPIO_PORT_SOURCE_GPIOF: output port source F
\arg GPIO_PORT_SOURCE_GPIOG: output port source G
\param[in] output_pin: GPIO output pin source
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_SOURCE_x(x=0..15)
\param[out] none
\retval none
*/
void gpio_exti_source_select(uint8_t output_port, uint8_t output_pin)
{
uint32_t source = 0U;
source = ((uint32_t)0x0FU) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK));
/* select EXTI sources */
if(GPIO_PIN_SOURCE_4 > output_pin){
/* select EXTI0/EXTI1/EXTI2/EXTI3 */
AFIO_EXTISS0 &= ~source;
AFIO_EXTISS0 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else if(GPIO_PIN_SOURCE_8 > output_pin){
/* select EXTI4/EXTI5/EXTI6/EXTI7 */
AFIO_EXTISS1 &= ~source;
AFIO_EXTISS1 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else if(GPIO_PIN_SOURCE_12 > output_pin){
/* select EXTI8/EXTI9/EXTI10/EXTI11 */
AFIO_EXTISS2 &= ~source;
AFIO_EXTISS2 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else{
/* select EXTI12/EXTI13/EXTI14/EXTI15 */
AFIO_EXTISS3 &= ~source;
AFIO_EXTISS3 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}
}
/*!
\brief configure GPIO pin event output
\param[in] output_port: gpio event output port
only one parameter can be selected which are shown as below:
\arg GPIO_EVENT_PORT_GPIOA: event output port A
\arg GPIO_EVENT_PORT_GPIOB: event output port B
\arg GPIO_EVENT_PORT_GPIOC: event output port C
\arg GPIO_EVENT_PORT_GPIOD: event output port D
\arg GPIO_EVENT_PORT_GPIOE: event output port E
\param[in] output_pin: GPIO event output pin
only one parameter can be selected which are shown as below:
\arg GPIO_EVENT_PIN_x(x=0..15)
\param[out] none
\retval none
*/
void gpio_event_output_config(uint8_t output_port, uint8_t output_pin)
{
uint32_t reg = 0U;
reg = AFIO_EC;
/* clear AFIO_EC_PORT and AFIO_EC_PIN bits */
reg &= (uint32_t)(~(AFIO_EC_PORT|AFIO_EC_PIN));
reg |= (uint32_t)((uint32_t)output_port << GPIO_OUTPUT_PORT_OFFSET);
reg |= (uint32_t)output_pin;
AFIO_EC = reg;
}
/*!
\brief enable GPIO pin event output
\param[in] none
\param[out] none
\retval none
*/
void gpio_event_output_enable(void)
{
AFIO_EC |= AFIO_EC_EOE;
}
/*!
\brief disable GPIO pin event output
\param[in] none
\param[out] none
\retval none
*/
void gpio_event_output_disable(void)
{
AFIO_EC &= (uint32_t)(~AFIO_EC_EOE);
}
/*!
\brief lock GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_pin_lock(uint32_t gpio_periph,uint32_t pin)
{
uint32_t lock = 0x00010000U;
lock |= pin;
/* lock key writing sequence: write 1 -> write 0 -> write 1 -> read 0 -> read 1 */
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
GPIO_LOCK(gpio_periph) = (uint32_t)pin;
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
lock = GPIO_LOCK(gpio_periph);
lock = GPIO_LOCK(gpio_periph);
}
/*!
\brief configure the I/O compensation cell
\param[in] compensation: specifies the I/O compensation cell mode
only one parameter can be selected which are shown as below:
\arg GPIO_COMPENSATION_ENABLE: I/O compensation cell is enabled
\arg GPIO_COMPENSATION_DISABLE: I/O compensation cell is disabled
\param[out] none
\retval none
*/
void gpio_compensation_config(uint32_t compensation)
{
uint32_t reg;
reg = AFIO_CPSCTL;
/* reset the AFIO_CPSCTL_CPS_EN bit and set according to gpio_compensation */
reg &= ~AFIO_CPSCTL_CPS_EN;
AFIO_CPSCTL = (reg | compensation);
}
/*!
\brief check the I/O compensation cell is ready or not
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus gpio_compensation_flag_get(void)
{
if(((uint32_t)RESET) != (AFIO_CPSCTL & AFIO_CPSCTL_CPS_RDY)){
return SET;
}else{
return RESET;
}
}
@@ -0,0 +1,699 @@
/*!
\file gd32e50x_gpio.c
\brief GPIO driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_gpio.h"
#define AFIO_EXTI_SOURCE_MASK ((uint8_t)0x03U) /*!< AFIO exti source selection mask*/
#define AFIO_EXTI_SOURCE_FIELDS ((uint8_t)0x04U) /*!< select AFIO exti source registers */
#define LSB_16BIT_MASK ((uint16_t)0xFFFFU) /*!< LSB 16-bit mask */
#define PCF_POSITION_MASK ((uint32_t)0x000F0000U) /*!< AFIO_PCF register position mask */
#define PCF_SWJCFG_MASK ((uint32_t)0xF8FFFFFFU) /*!< AFIO_PCF register SWJCFG mask */
#define PCF_LOCATION1_MASK ((uint32_t)0x00200000U) /*!< AFIO_PCF register location1 mask */
#define PCF_LOCATION2_MASK ((uint32_t)0x00100000U) /*!< AFIO_PCF register location2 mask */
#define AFIO_PCF1_FIELDS ((uint32_t)0x80000000U) /*!< select AFIO_PCF1 register */
#define GPIO_OUTPUT_PORT_OFFSET ((uint32_t)4U) /*!< GPIO event output port offset*/
/*!
\brief reset GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval none
*/
void gpio_deinit(uint32_t gpio_periph)
{
switch(gpio_periph){
case GPIOA:
/* reset GPIOA */
rcu_periph_reset_enable(RCU_GPIOARST);
rcu_periph_reset_disable(RCU_GPIOARST);
break;
case GPIOB:
/* reset GPIOB */
rcu_periph_reset_enable(RCU_GPIOBRST);
rcu_periph_reset_disable(RCU_GPIOBRST);
break;
case GPIOC:
/* reset GPIOC */
rcu_periph_reset_enable(RCU_GPIOCRST);
rcu_periph_reset_disable(RCU_GPIOCRST);
break;
case GPIOD:
/* reset GPIOD */
rcu_periph_reset_enable(RCU_GPIODRST);
rcu_periph_reset_disable(RCU_GPIODRST);
break;
case GPIOE:
/* reset GPIOE */
rcu_periph_reset_enable(RCU_GPIOERST);
rcu_periph_reset_disable(RCU_GPIOERST);
break;
case GPIOF:
/* reset GPIOF */
rcu_periph_reset_enable(RCU_GPIOFRST);
rcu_periph_reset_disable(RCU_GPIOFRST);
break;
case GPIOG:
/* reset GPIOG */
rcu_periph_reset_enable(RCU_GPIOGRST);
rcu_periph_reset_disable(RCU_GPIOGRST);
break;
default:
break;
}
}
/*!
\brief reset alternate function I/O(AFIO)
\param[in] none
\param[out] none
\retval none
*/
void gpio_afio_deinit(void)
{
rcu_periph_reset_enable(RCU_AFRST);
rcu_periph_reset_disable(RCU_AFRST);
}
/*!
\brief GPIO parameter initialization
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] mode: gpio pin mode
only one parameter can be selected which is shown as below:
\arg GPIO_MODE_AIN: analog input mode
\arg GPIO_MODE_IN_FLOATING: floating input mode
\arg GPIO_MODE_IPD: pull-down input mode
\arg GPIO_MODE_IPU: pull-up input mode
\arg GPIO_MODE_OUT_OD: GPIO output with open-drain
\arg GPIO_MODE_OUT_PP: GPIO output with push-pull
\arg GPIO_MODE_AF_OD: AFIO output with open-drain
\arg GPIO_MODE_AF_PP: AFIO output with push-pull
\param[in] speed: gpio output max speed value
only one parameter can be selected which is shown as below:
\arg GPIO_OSPEED_10MHZ: output max speed 10MHz
\arg GPIO_OSPEED_2MHZ: output max speed 2MHz
\arg GPIO_OSPEED_50MHZ: output max speed 50MHz
\arg GPIO_OSPEED_MAX: output max speed more than 50MHz
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_init(uint32_t gpio_periph, uint32_t mode, uint32_t speed, uint32_t pin)
{
uint16_t i;
uint32_t temp_mode = 0U;
uint32_t reg = 0U;
/* GPIO mode configuration */
temp_mode = (uint32_t)(mode & ((uint32_t)0x0FU));
/* GPIO speed configuration */
if(((uint32_t)0x00U) != ((uint32_t)mode & ((uint32_t)0x10U))){
/* output mode max speed */
if(GPIO_OSPEED_MAX == (uint32_t)speed){
temp_mode |= (uint32_t)0x03U;
/* set the corresponding SPD bit */
GPIOx_SPD(gpio_periph) |= (uint32_t)pin ;
}else{
/* output mode max speed:10MHz,2MHz,50MHz */
temp_mode |= (uint32_t)speed;
}
}
/* configure the eight low port pins with GPIO_CTL0 */
for(i = 0U;i < 8U;i++){
if((1U << i) & pin){
reg = GPIO_CTL0(gpio_periph);
/* clear the specified pin mode bits */
reg &= ~GPIO_MODE_MASK(i);
/* set the specified pin mode bits */
reg |= GPIO_MODE_SET(i, temp_mode);
/* set IPD or IPU */
if(GPIO_MODE_IPD == mode){
/* reset the corresponding OCTL bit */
GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin);
}else{
/* set the corresponding OCTL bit */
if(GPIO_MODE_IPU == mode){
GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin);
}
}
/* set GPIO_CTL0 register */
GPIO_CTL0(gpio_periph) = reg;
}
}
/* configure the eight high port pins with GPIO_CTL1 */
for(i = 8U;i < 16U;i++){
if((1U << i) & pin){
reg = GPIO_CTL1(gpio_periph);
/* clear the specified pin mode bits */
reg &= ~GPIO_MODE_MASK(i - 8U);
/* set the specified pin mode bits */
reg |= GPIO_MODE_SET(i - 8U, temp_mode);
/* set IPD or IPU */
if(GPIO_MODE_IPD == mode){
/* reset the corresponding OCTL bit */
GPIO_BC(gpio_periph) = (uint32_t)((1U << i) & pin);
}else{
/* set the corresponding OCTL bit */
if(GPIO_MODE_IPU == mode){
GPIO_BOP(gpio_periph) = (uint32_t)((1U << i) & pin);
}
}
/* set GPIO_CTL1 register */
GPIO_CTL1(gpio_periph) = reg;
}
}
}
/*!
\brief set GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_set(uint32_t gpio_periph,uint32_t pin)
{
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}
/*!
\brief reset GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_bit_reset(uint32_t gpio_periph,uint32_t pin)
{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
/*!
\brief write data to the specified GPIO pin
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[in] bit_value: SET or RESET
\arg RESET: clear the port pin
\arg SET: set the port pin
\param[out] none
\retval none
*/
void gpio_bit_write(uint32_t gpio_periph,uint32_t pin,bit_status bit_value)
{
if(RESET != bit_value){
GPIO_BOP(gpio_periph) = (uint32_t)pin;
}else{
GPIO_BC(gpio_periph) = (uint32_t)pin;
}
}
/*!
\brief write data to the specified GPIO port
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] data: specify the value to be written to the port output data register
\param[out] none
\retval none
*/
void gpio_port_write(uint32_t gpio_periph,uint16_t data)
{
GPIO_OCTL(gpio_periph) = (uint32_t)data;
}
/*!
\brief get GPIO pin input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval input status of gpio pin: SET or RESET
*/
FlagStatus gpio_input_bit_get(uint32_t gpio_periph,uint32_t pin)
{
if((uint32_t)RESET != (GPIO_ISTAT(gpio_periph)&(pin))){
return SET;
}else{
return RESET;
}
}
/*!
\brief get GPIO port input status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval input status of gpio all pins
*/
uint16_t gpio_input_port_get(uint32_t gpio_periph)
{
return (uint16_t)(GPIO_ISTAT(gpio_periph));
}
/*!
\brief get GPIO pin output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval output status of gpio pin: SET or RESET
*/
FlagStatus gpio_output_bit_get(uint32_t gpio_periph,uint32_t pin)
{
if((uint32_t)RESET !=(GPIO_OCTL(gpio_periph)&(pin))){
return SET;
}else{
return RESET;
}
}
/*!
\brief get GPIO port output status
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[out] none
\retval output status of gpio all pins
*/
uint16_t gpio_output_port_get(uint32_t gpio_periph)
{
return ((uint16_t)GPIO_OCTL(gpio_periph));
}
/*!
\brief configure GPIO pin remap
\param[in] gpio_remap: select the pin to remap
only one parameter can be selected which are shown as below:
\arg GPIO_SPI0_REMAP: SPI0 remapping
\arg GPIO_I2C0_REMAP: I2C0 remapping
\arg GPIO_USART0_REMAP: USART0 remapping
\arg GPIO_USART1_REMAP: USART1 remapping
\arg GPIO_USART2_PARTIAL_REMAP: USART2 partial remapping
\arg GPIO_USART2_FULL_REMAP: USART2 full remapping
\arg GPIO_TIMER0_PARTIAL_REMAP: TIMER0 partial remapping
\arg GPIO_TIMER0_FULL_REMAP: TIMER0 full remapping
\arg GPIO_TIMER1_PARTIAL_REMAP0: TIMER1 partial remapping
\arg GPIO_TIMER1_PARTIAL_REMAP1: TIMER1 partial remapping
\arg GPIO_TIMER1_FULL_REMAP: TIMER1 full remapping
\arg GPIO_TIMER2_PARTIAL_REMAP: TIMER2 partial remapping
\arg GPIO_TIMER2_FULL_REMAP: TIMER2 full remapping
\arg GPIO_TIMER3_REMAP: TIMER3 remapping
\arg GPIO_CAN0_PARTIAL_REMAP: CAN0 partial remapping(not support on GD32EPRT devices)
\arg GPIO_CAN0_FULL_REMAP: CAN0 full remapping(not support on GD32EPRT devices)
\arg GPIO_PD01_REMAP: PD01 remapping
\arg GPIO_TIMER4CH3_IREMAP: TIMER4 channel3 internal remapping
\arg GPIO_ADC0_ETRGRT_REMAP: ADC0 external trigger routine conversion remapping(only for GD32E50X_HD devices)
\arg GPIO_ADC1_ETRGRT_REMAP: ADC1 external trigger routine conversion remapping(only for GD32E50X_HD devices)
\arg GPIO_ENET_REMAP: ENET remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_CAN1_REMAP: CAN1 remapping(not support on GD32EPRT devices)
\arg GPIO_SWJ_NONJTRST_REMAP: full SWJ(JTAG-DP + SW-DP),but without NJTRST
\arg GPIO_SWJ_SWDPENABLE_REMAP: JTAG-DP disabled and SW-DP enabled
\arg GPIO_SWJ_DISABLE_REMAP: JTAG-DP disabled and SW-DP disabled
\arg GPIO_SPI2_REMAP: SPI2 remapping
\arg GPIO_TIMER1ITR1_REMAP: TIMER1 internal trigger 1 remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_PTP_PPS_REMAP: ethernet PTP PPS remapping(only for GD32E50X_CL and GD32E508 devices)
\arg GPIO_TIMER8_REMAP: TIMER8 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER9_REMAP: TIMER9 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER10_REMAP: TIMER10 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER12_REMAP: TIMER12 remapping(not support on GD32EPRT devices)
\arg GPIO_TIMER13_REMAP: TIMER13 remapping(not support on GD32EPRT devices)
\arg GPIO_EXMC_NADV_REMAP: EXMC_NADV connect/disconnect
\arg GPIO_CTC_REMAP0: CTC remapping(PD15)
\arg GPIO_CTC_REMAP1: CTC remapping(PF0)
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void gpio_pin_remap_config(uint32_t remap, ControlStatus newvalue)
{
uint32_t remap1 = 0U, remap2 = 0U, temp_reg = 0U, temp_mask = 0U;
if(((uint32_t)0x80000000U) == (remap & 0x80000000U)){
/* get AFIO_PCF1 regiter value */
temp_reg = AFIO_PCF1;
}else{
/* get AFIO_PCF0 regiter value */
temp_reg = AFIO_PCF0;
}
temp_mask = (remap & PCF_POSITION_MASK) >> 0x10U;
remap1 = remap & LSB_16BIT_MASK;
/* judge pin remap type */
if((PCF_LOCATION1_MASK | PCF_LOCATION2_MASK) == (remap & (PCF_LOCATION1_MASK | PCF_LOCATION2_MASK))){
temp_reg &= PCF_SWJCFG_MASK;
AFIO_PCF0 &= PCF_SWJCFG_MASK;
}else if(PCF_LOCATION2_MASK == (remap & PCF_LOCATION2_MASK)){
remap2 = ((uint32_t)0x03U) << temp_mask;
temp_reg &= ~remap2;
temp_reg |= ~PCF_SWJCFG_MASK;
}else{
temp_reg &= ~(remap1 << ((remap >> 0x15U)*0x10U));
temp_reg |= ~PCF_SWJCFG_MASK;
}
/* set pin remap value */
if(DISABLE != newvalue){
temp_reg |= (remap1 << ((remap >> 0x15U)*0x10U));
}
if(AFIO_PCF1_FIELDS == (remap & AFIO_PCF1_FIELDS)){
/* set AFIO_PCF1 regiter value */
AFIO_PCF1 = temp_reg;
}else{
/* set AFIO_PCF0 regiter value */
AFIO_PCF0 = temp_reg;
}
}
/*!
\brief configure AFIO port alternate function
\param[in] afio_function: select the port AFIO function(SHRTIMER not support on GD32EPRT devices)
only one parameter can be selected which are shown as below:
\arg AFIO_PA2_CMP1_CFG: configure PA2 alternate function to CMP1
\arg AFIO_PA3_USBHS_CFG: configure PA3 alternate function to USBHS
\arg AFIO_PA5_USBHS_CFG: configure PA5 alternate function to USBHS
\arg AFIO_PA8_I2C2_CFG: configure PA8 alternate function to I2C2
\arg AFIO_PA8_SHRTIMER_CFG: configure PA8 alternate function to SHRTIMER
\arg AFIO_PA9_CAN2_CFG: configure PA9 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PA9_I2C2_CFG: configure PA9 alternate function to I2C2
\arg AFIO_PA9_SHRTIMER_CFG: configure PA9 alternate function to SHRTIMER
\arg AFIO_PA10_CAN2_CFG: configure PA10 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PA10_CMP5_CFG: configure PA10 alternate function to CMP5
\arg AFIO_PA10_SHRTIMER_CFG: configure PA10 alternate function to SHRTIMER
\arg AFIO_PA11_USART5_CFG: configure PA11 alternate function to USART5
\arg AFIO_PA11_SHRTIMER_CFG: configure PA11 alternate function to SHRTIMER
\arg AFIO_PA12_CMP1_CFG: configure PA12 alternate function to CMP1
\arg AFIO_PA12_USART5_CFG: configure PA12 alternate function to USART5
\arg AFIO_PA12_SHRTIMER_CFG: configure PA12 alternate function to SHRTIMER
\arg AFIO_PA15_SHRTIMER_CFG: configure PA15 alternate function to SHRTIMER
\arg AFIO_PB0_USBHS_CFG: configure PB0 alternate function to USBHS
\arg AFIO_PB1_CMP3_CFG: configure PB1 alternate function to CMP3
\arg AFIO_PB1_USBHS_CFG: configure PB1 alternate function to USBHS
\arg AFIO_PB1_SHRTIMER_CFG: configure PB1 alternate function to SHRTIMER
\arg AFIO_PB2_USBHS_CFG: configure PB2 alternate function to USBHS
\arg AFIO_PB2_SHRTIMER_CFG: configure PB2 alternate function to SHRTIMER
\arg AFIO_PB3_SHRTIMER_CFG: configure PB3 alternate function to SHRTIMER
\arg AFIO_PB4_I2S2_CFG: configure PB4 alternate function to I2S2
\arg AFIO_PB4_I2C2_CFG: configure PB4 alternate function to I2C2
\arg AFIO_PB4_SHRTIMER_CFG: configure PB4 alternate function to SHRTIMER
\arg AFIO_PB5_I2C2_CFG: configure PB5 alternate function to I2C2
\arg AFIO_PB5_USBHS_CFG: configure PB5 alternate function to USBHS
\arg AFIO_PB5_SHRTIMER_CFG: configure PB5 alternate function to SHRTIMER
\arg AFIO_PB6_SHRTIMER_CFG: configure PB6 alternate function to SHRTIMER
\arg AFIO_PB7_SHRTIMER_CFG: configure PB7 alternate function to SHRTIMER
\arg AFIO_PB8_I2C2_CFG: configure PB8 alternate function to I2C2
\arg AFIO_PB8_SHRTIMER_CFG: configure PB8 alternate function to SHRTIMER
\arg AFIO_PB9_CMP1_CFG: configure PB9 alternate function to CMP1
\arg AFIO_PB9_SHRTIMER_CFG: configure PB9 alternate function to SHRTIMER
\arg AFIO_PB10_CAN2_CFG: configure PB10 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PB10_USBHS_CFG: configure PB10 alternate function to USBHS
\arg AFIO_PB10_SHRTIMER_CFG: configure PB10 alternate function to SHRTIMER
\arg AFIO_PB11_CAN2_CFG: configure PB11 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PB11_USBHS_CFG: configure PB11 alternate function to USBHS
\arg AFIO_PB11_SHRTIMER_CFG: configure PB11 alternate function to SHRTIMER
\arg AFIO_PB12_USBHS_CFG: configure PB12 alternate function to USBHS
\arg AFIO_PB12_SHRTIMER_CFG: configure PB12 alternate function to SHRTIMER
\arg AFIO_PB13_USBHS_CFG: configure PB13 alternate function to USBHS
\arg AFIO_PB13_SHRTIMER_CFG: configure PB13 alternate function to SHRTIMER
\arg AFIO_PB14_I2S1_CFG: configure PB14 alternate function to I2S1
\arg AFIO_PB14_SHRTIMER_CFG: configure PB14 alternate function to SHRTIMER
\arg AFIO_PB15_SHRTIMER_CFG: configure PB15 alternate function to SHRTIMER
\arg AFIO_PC0_USBHS_CFG: configure PC0 alternate function to USBHS
\arg AFIO_PC2_I2S1_CFG: configure PC2 alternate function to I2S1
\arg AFIO_PC2_USBHS_CFG: configure PC2 alternate function to USBHS
\arg AFIO_PC3_USBHS_CFG: configure PC3 alternate function to USBHS
\arg AFIO_PC6_CMP5_CFG: configure PC6 alternate function to CMP5
\arg AFIO_PC6_USART5_CFG: configure PC6 alternate function to USART5
\arg AFIO_PC6_SHRTIMER_CFG: configure PC6 alternate function to SHRTIMER
\arg AFIO_PC7_USART5_CFG: configure PC7 alternate function to USART5
\arg AFIO_PC7_SHRTIMER_CFG: configure PC7 alternate function to SHRTIMER
\arg AFIO_PC8_USART5_CFG: configure PC8 alternate function to USART5
\arg AFIO_PC8_SHRTIMER_CFG: configure PC8 alternate function to SHRTIMER
\arg AFIO_PC9_I2C2_CFG: configure PC9 alternate function to I2C2
\arg AFIO_PC9_SHRTIMER_CFG: configure PC9 alternate function to SHRTIMER
\arg AFIO_PC10_I2C2_CFG: configure PC10 alternate function to I2C2
\arg AFIO_PC11_I2S2_CFG: configure PC11 alternate function to I2S2
\arg AFIO_PC11_SHRTIMER_CFG: configure PC11 alternate function to SHRTIMER
\arg AFIO_PC12_SHRTIMER_CFG: configure PC12 alternate function to SHRTIMER
\arg AFIO_PD4_SHRTIMER_CFG: configure PD4 alternate function to SHRTIMER
\arg AFIO_PD5_SHRTIMER_CFG: configure PD5 alternate function to SHRTIMER
\arg AFIO_PE0_CAN2_CFG: configure PE0 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PE0_SHRTIMER_CFG: configure PE0 alternate function to SHRTIMER
\arg AFIO_PE1_CAN2_CFG: configure PE1 alternate function to CAN2(not support on GD32EPRT devices)
\arg AFIO_PE1_SHRTIMER_CFG: configure PE1 alternate function to SHRTIMER
\arg AFIO_PE8_CMP1_CFG: configure PE8 alternate function to CMP1
\arg AFIO_PE9_CMP3_CFG: configure PE9 alternate function to CMP3
\arg AFIO_PE10_CMP5_CFG: configure PE10 alternate function to CMP5
\arg AFIO_PE11_CMP5_CFG: configure PE11 alternate function to CMP5
\arg AFIO_PE12_CMP3_CFG: configure PE12 alternate function to CMP3
\arg AFIO_PE13_CMP1_CFG: configure PE13 alternate function to CMP1
\arg AFIO_PG6_SHRTIMER_CFG: configure PG6 alternate function to SHRTIMER
\arg AFIO_PG7_USART5_CFG: configure PG7 alternate function to USART5
\arg AFIO_PG7_SHRTIMER_CFG: configure PG7 alternate function to SHRTIMER
\arg AFIO_PG9_USART5_CFG: configure PG9 alternate function to USART5
\arg AFIO_PG10_SHRTIMER_CFG: configure PG10 alternate function to SHRTIMER
\arg AFIO_PG11_SHRTIMER_CFG: configure PG11 alternate function to SHRTIMER
\arg AFIO_PG12_SHRTIMER_CFG: configure PG12 alternate function to SHRTIMER
\arg AFIO_PG13_SHRTIMER_CFG: configure PG13 alternate function to SHRTIMER
\arg AFIO_PG14_USART5_CFG: configure PG14 alternate function to USART5
\param[in] newvalue: ENABLE or DISABLE
\param[out] none
\retval none
*/
void gpio_afio_port_config(uint32_t afio_function, ControlStatus newvalue)
{
uint32_t remap1 = 0U, remap2 = 0U, temp_reg = 0U, temp_mask = 0U;
/* get AFIO_PCFx(x=A,B,C,D,E,G) regiter value */
temp_reg = REG32(AFIO+0x0000003CU+((afio_function>>24)<<2));
temp_mask = (afio_function & PCF_POSITION_MASK) >> 0x10U;
remap1 = afio_function & LSB_16BIT_MASK;
/* judge port function select type */
if(afio_function & PCF_LOCATION2_MASK){
remap2 = ((uint32_t)0x03U) << temp_mask;
remap2 = (remap2 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
temp_reg &= ~remap2;
}else{
temp_reg &= ~(remap1 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
}
/* set pin remap value */
if(DISABLE != newvalue){
temp_reg |= (remap1 << (((afio_function & PCF_LOCATION1_MASK) >> 0x15U)*0x10U));
}
/* set AFIO_PCFx(x=A,B,C,D,E,G) regiter value */
REG32(AFIO+0x0000003CU+((afio_function>>24)<<2)) = temp_reg;
}
#if (defined(GD32E50X_CL) || defined(GD32E508) || defined(GD32EPRT))
/*!
\brief select ethernet MII or RMII PHY
\param[in] enet_sel: ethernet MII or RMII PHY selection
\arg GPIO_ENET_PHY_MII: configure ethernet MAC for connection with an MII PHY
\arg GPIO_ENET_PHY_RMII: configure ethernet MAC for connection with an RMII PHY
\param[out] none
\retval none
*/
void gpio_ethernet_phy_select(uint32_t enet_sel)
{
/* clear AFIO_PCF0_ENET_PHY_SEL bit */
AFIO_PCF0 &= (uint32_t)(~AFIO_PCF0_ENET_PHY_SEL);
/* select MII or RMII PHY */
AFIO_PCF0 |= (uint32_t)enet_sel;
}
#endif /* GD32E50X_CL||GD32E508||GD32EPRT */
/*!
\brief select GPIO pin exti sources
\param[in] output_port: gpio event output port
only one parameter can be selected which are shown as below:
\arg GPIO_PORT_SOURCE_GPIOA: output port source A
\arg GPIO_PORT_SOURCE_GPIOB: output port source B
\arg GPIO_PORT_SOURCE_GPIOC: output port source C
\arg GPIO_PORT_SOURCE_GPIOD: output port source D
\arg GPIO_PORT_SOURCE_GPIOE: output port source E
\arg GPIO_PORT_SOURCE_GPIOF: output port source F
\arg GPIO_PORT_SOURCE_GPIOG: output port source G
\param[in] output_pin: GPIO output pin source
only one parameter can be selected which are shown as below:
\arg GPIO_PIN_SOURCE_x(x=0..15)
\param[out] none
\retval none
*/
void gpio_exti_source_select(uint8_t output_port, uint8_t output_pin)
{
uint32_t source = 0U;
source = ((uint32_t)0x0FU) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK));
/* select EXTI sources */
if(GPIO_PIN_SOURCE_4 > output_pin){
/* select EXTI0/EXTI1/EXTI2/EXTI3 */
AFIO_EXTISS0 &= ~source;
AFIO_EXTISS0 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else if(GPIO_PIN_SOURCE_8 > output_pin){
/* select EXTI4/EXTI5/EXTI6/EXTI7 */
AFIO_EXTISS1 &= ~source;
AFIO_EXTISS1 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else if(GPIO_PIN_SOURCE_12 > output_pin){
/* select EXTI8/EXTI9/EXTI10/EXTI11 */
AFIO_EXTISS2 &= ~source;
AFIO_EXTISS2 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}else{
/* select EXTI12/EXTI13/EXTI14/EXTI15 */
AFIO_EXTISS3 &= ~source;
AFIO_EXTISS3 |= (((uint32_t)output_port) << (AFIO_EXTI_SOURCE_FIELDS * (output_pin & AFIO_EXTI_SOURCE_MASK)));
}
}
/*!
\brief configure GPIO pin event output
\param[in] output_port: gpio event output port
only one parameter can be selected which are shown as below:
\arg GPIO_EVENT_PORT_GPIOA: event output port A
\arg GPIO_EVENT_PORT_GPIOB: event output port B
\arg GPIO_EVENT_PORT_GPIOC: event output port C
\arg GPIO_EVENT_PORT_GPIOD: event output port D
\arg GPIO_EVENT_PORT_GPIOE: event output port E
\param[in] output_pin: GPIO event output pin
only one parameter can be selected which are shown as below:
\arg GPIO_EVENT_PIN_x(x=0..15)
\param[out] none
\retval none
*/
void gpio_event_output_config(uint8_t output_port, uint8_t output_pin)
{
uint32_t reg = 0U;
reg = AFIO_EC;
/* clear AFIO_EC_PORT and AFIO_EC_PIN bits */
reg &= (uint32_t)(~(AFIO_EC_PORT|AFIO_EC_PIN));
reg |= (uint32_t)((uint32_t)output_port << GPIO_OUTPUT_PORT_OFFSET);
reg |= (uint32_t)output_pin;
AFIO_EC = reg;
}
/*!
\brief enable GPIO pin event output
\param[in] none
\param[out] none
\retval none
*/
void gpio_event_output_enable(void)
{
AFIO_EC |= AFIO_EC_EOE;
}
/*!
\brief disable GPIO pin event output
\param[in] none
\param[out] none
\retval none
*/
void gpio_event_output_disable(void)
{
AFIO_EC &= (uint32_t)(~AFIO_EC_EOE);
}
/*!
\brief lock GPIO pin bit
\param[in] gpio_periph: GPIOx(x = A,B,C,D,E,F,G)
\param[in] pin: GPIO pin
one or more parameters can be selected which are shown as below:
\arg GPIO_PIN_x(x=0..15), GPIO_PIN_ALL
\param[out] none
\retval none
*/
void gpio_pin_lock(uint32_t gpio_periph,uint32_t pin)
{
uint32_t lock = 0x00010000U;
lock |= pin;
/* lock key writing sequence: write 1 -> write 0 -> write 1 -> read 0 -> read 1 */
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
GPIO_LOCK(gpio_periph) = (uint32_t)pin;
GPIO_LOCK(gpio_periph) = (uint32_t)lock;
lock = GPIO_LOCK(gpio_periph);
lock = GPIO_LOCK(gpio_periph);
}
/*!
\brief configure the I/O compensation cell
\param[in] compensation: specifies the I/O compensation cell mode
only one parameter can be selected which are shown as below:
\arg GPIO_COMPENSATION_ENABLE: I/O compensation cell is enabled
\arg GPIO_COMPENSATION_DISABLE: I/O compensation cell is disabled
\param[out] none
\retval none
*/
void gpio_compensation_config(uint32_t compensation)
{
uint32_t reg;
reg = AFIO_CPSCTL;
/* reset the AFIO_CPSCTL_CPS_EN bit and set according to gpio_compensation */
reg &= ~AFIO_CPSCTL_CPS_EN;
AFIO_CPSCTL = (reg | compensation);
}
/*!
\brief check the I/O compensation cell is ready or not
\param[in] none
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus gpio_compensation_flag_get(void)
{
if(((uint32_t)RESET) != (AFIO_CPSCTL & AFIO_CPSCTL_CPS_RDY)){
return SET;
}else{
return RESET;
}
}
@@ -0,0 +1,180 @@
/*!
\file gd32e50x_misc.c
\brief MISC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_misc.h"
/*!
\brief set the priority group
\param[in] nvic_prigroup: the NVIC priority group
\arg NVIC_PRIGROUP_PRE0_SUB4:0 bits for pre-emption priority 4 bits for subpriority
\arg NVIC_PRIGROUP_PRE1_SUB3:1 bits for pre-emption priority 3 bits for subpriority
\arg NVIC_PRIGROUP_PRE2_SUB2:2 bits for pre-emption priority 2 bits for subpriority
\arg NVIC_PRIGROUP_PRE3_SUB1:3 bits for pre-emption priority 1 bits for subpriority
\arg NVIC_PRIGROUP_PRE4_SUB0:4 bits for pre-emption priority 0 bits for subpriority
\param[out] none
\retval none
*/
void nvic_priority_group_set(uint32_t nvic_prigroup)
{
/* set the priority group value */
SCB->AIRCR = NVIC_AIRCR_VECTKEY_MASK | nvic_prigroup;
}
/*!
\brief enable NVIC request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[in] nvic_irq_pre_priority: the pre-emption priority needed to set
\param[in] nvic_irq_sub_priority: the subpriority needed to set
\param[out] none
\retval none
*/
void nvic_irq_enable(IRQn_Type nvic_irq, uint8_t nvic_irq_pre_priority,
uint8_t nvic_irq_sub_priority)
{
uint32_t nvic_prigroup, nvic_priority;
/* check current priority group */
switch(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) {
case NVIC_PRIGROUP_PRE0_SUB4:
case NVIC_PRIGROUP_PRE1_SUB3:
case NVIC_PRIGROUP_PRE2_SUB2:
case NVIC_PRIGROUP_PRE3_SUB1:
case NVIC_PRIGROUP_PRE4_SUB0:
break;
default:
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
break;
}
/* get the priority group value */
nvic_prigroup = NVIC_GetPriorityGrouping();
/* encoding the pre-emption, subpriority priority */
nvic_priority = NVIC_EncodePriority(nvic_prigroup, (uint32_t)nvic_irq_pre_priority, (uint32_t)nvic_irq_sub_priority);
/* set priority */
NVIC_SetPriority(nvic_irq, nvic_priority);
/* enable the selected IRQ */
NVIC_EnableIRQ(nvic_irq);
}
/*!
\brief disable NVIC request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[out] none
\retval none
*/
void nvic_irq_disable(IRQn_Type nvic_irq)
{
/* disable the selected IRQ.*/
NVIC_DisableIRQ((IRQn_Type)nvic_irq);
}
/*!
\brief initiates a system reset request to reset the MCU
\param[in] none
\param[out] none
\retval none
*/
void nvic_system_reset(void)
{
NVIC_SystemReset();
}
/*!
\brief set the NVIC vector table base address
\param[in] nvic_vict_tab: the RAM or FLASH base address
\arg NVIC_VECTTAB_RAM: RAM base address
\are NVIC_VECTTAB_FLASH: Flash base address
\param[in] offset: Vector Table offset
\param[out] none
\retval none
*/
void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
{
SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
__DSB();
}
/*!
\brief set the state of the low power mode
\param[in] lowpower_mode: the low power mode state
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system always enter low power
mode by exiting from ISR
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the DEEPSLEEP mode
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode can be woke up
by all the enable and disable interrupts
\param[out] none
\retval none
*/
void system_lowpower_set(uint8_t lowpower_mode)
{
SCB->SCR |= (uint32_t)lowpower_mode;
}
/*!
\brief reset the state of the low power mode
\param[in] lowpower_mode: the low power mode state
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system will exit low power
mode by exiting from ISR
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the SLEEP mode
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode only can be
woke up by the enable interrupts
\param[out] none
\retval none
*/
void system_lowpower_reset(uint8_t lowpower_mode)
{
SCB->SCR &= (~(uint32_t)lowpower_mode);
}
/*!
\brief set the systick clock source
\param[in] systick_clksource: the systick clock source needed to choose
\arg SYSTICK_CLKSOURCE_HCLK: systick clock source is from HCLK
\arg SYSTICK_CLKSOURCE_HCLK_DIV8: systick clock source is from HCLK/8
\param[out] none
\retval none
*/
void systick_clksource_set(uint32_t systick_clksource)
{
if(SYSTICK_CLKSOURCE_HCLK == systick_clksource ){
/* set the systick clock source from HCLK */
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
}else{
/* set the systick clock source from HCLK/8 */
SysTick->CTRL &= SYSTICK_CLKSOURCE_HCLK_DIV8;
}
}
@@ -0,0 +1,180 @@
/*!
\file gd32e50x_misc.c
\brief MISC driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_misc.h"
/*!
\brief set the priority group
\param[in] nvic_prigroup: the NVIC priority group
\arg NVIC_PRIGROUP_PRE0_SUB4:0 bits for pre-emption priority 4 bits for subpriority
\arg NVIC_PRIGROUP_PRE1_SUB3:1 bits for pre-emption priority 3 bits for subpriority
\arg NVIC_PRIGROUP_PRE2_SUB2:2 bits for pre-emption priority 2 bits for subpriority
\arg NVIC_PRIGROUP_PRE3_SUB1:3 bits for pre-emption priority 1 bits for subpriority
\arg NVIC_PRIGROUP_PRE4_SUB0:4 bits for pre-emption priority 0 bits for subpriority
\param[out] none
\retval none
*/
void nvic_priority_group_set(uint32_t nvic_prigroup)
{
/* set the priority group value */
SCB->AIRCR = NVIC_AIRCR_VECTKEY_MASK | nvic_prigroup;
}
/*!
\brief enable NVIC request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[in] nvic_irq_pre_priority: the pre-emption priority needed to set
\param[in] nvic_irq_sub_priority: the subpriority needed to set
\param[out] none
\retval none
*/
void nvic_irq_enable(IRQn_Type nvic_irq, uint8_t nvic_irq_pre_priority,
uint8_t nvic_irq_sub_priority)
{
uint32_t nvic_prigroup, nvic_priority;
/* check current priority group */
switch(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) {
case NVIC_PRIGROUP_PRE0_SUB4:
case NVIC_PRIGROUP_PRE1_SUB3:
case NVIC_PRIGROUP_PRE2_SUB2:
case NVIC_PRIGROUP_PRE3_SUB1:
case NVIC_PRIGROUP_PRE4_SUB0:
break;
default:
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
break;
}
/* get the priority group value */
nvic_prigroup = NVIC_GetPriorityGrouping();
/* encoding the pre-emption, subpriority priority */
nvic_priority = NVIC_EncodePriority(nvic_prigroup, (uint32_t)nvic_irq_pre_priority, (uint32_t)nvic_irq_sub_priority);
/* set priority */
NVIC_SetPriority(nvic_irq, nvic_priority);
/* enable the selected IRQ */
NVIC_EnableIRQ(nvic_irq);
}
/*!
\brief disable NVIC request
\param[in] nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
\param[out] none
\retval none
*/
void nvic_irq_disable(IRQn_Type nvic_irq)
{
/* disable the selected IRQ.*/
NVIC_DisableIRQ((IRQn_Type)nvic_irq);
}
/*!
\brief initiates a system reset request to reset the MCU
\param[in] none
\param[out] none
\retval none
*/
void nvic_system_reset(void)
{
NVIC_SystemReset();
}
/*!
\brief set the NVIC vector table base address
\param[in] nvic_vict_tab: the RAM or FLASH base address
\arg NVIC_VECTTAB_RAM: RAM base address
\are NVIC_VECTTAB_FLASH: Flash base address
\param[in] offset: Vector Table offset
\param[out] none
\retval none
*/
void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
{
SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
__DSB();
}
/*!
\brief set the state of the low power mode
\param[in] lowpower_mode: the low power mode state
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system always enter low power
mode by exiting from ISR
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the DEEPSLEEP mode
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode can be woke up
by all the enable and disable interrupts
\param[out] none
\retval none
*/
void system_lowpower_set(uint8_t lowpower_mode)
{
SCB->SCR |= (uint32_t)lowpower_mode;
}
/*!
\brief reset the state of the low power mode
\param[in] lowpower_mode: the low power mode state
\arg SCB_LPM_SLEEP_EXIT_ISR: if chose this para, the system will exit low power
mode by exiting from ISR
\arg SCB_LPM_DEEPSLEEP: if chose this para, the system will enter the SLEEP mode
\arg SCB_LPM_WAKE_BY_ALL_INT: if chose this para, the lowpower mode only can be
woke up by the enable interrupts
\param[out] none
\retval none
*/
void system_lowpower_reset(uint8_t lowpower_mode)
{
SCB->SCR &= (~(uint32_t)lowpower_mode);
}
/*!
\brief set the systick clock source
\param[in] systick_clksource: the systick clock source needed to choose
\arg SYSTICK_CLKSOURCE_HCLK: systick clock source is from HCLK
\arg SYSTICK_CLKSOURCE_HCLK_DIV8: systick clock source is from HCLK/8
\param[out] none
\retval none
*/
void systick_clksource_set(uint32_t systick_clksource)
{
if(SYSTICK_CLKSOURCE_HCLK == systick_clksource ){
/* set the systick clock source from HCLK */
SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
}else{
/* set the systick clock source from HCLK/8 */
SysTick->CTRL &= SYSTICK_CLKSOURCE_HCLK_DIV8;
}
}
@@ -0,0 +1,522 @@
/*!
\file gd32e50x_pmu.c
\brief PMU driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_pmu.h"
/*!
\brief reset PMU registers
\param[in] none
\param[out] none
\retval none
*/
void pmu_deinit(void)
{
/* reset PMU */
rcu_periph_reset_enable(RCU_PMURST);
rcu_periph_reset_disable(RCU_PMURST);
}
/*!
\brief select low voltage detector threshold
\param[in] lvdt_n:
only one parameter can be selected which is shown as below:
\arg PMU_LVDT_0: voltage threshold is 2.1V
\arg PMU_LVDT_1: voltage threshold is 2.3V
\arg PMU_LVDT_2: voltage threshold is 2.4V
\arg PMU_LVDT_3: voltage threshold is 2.6V
\arg PMU_LVDT_4: voltage threshold is 2.7V
\arg PMU_LVDT_5: voltage threshold is 2.9V
\arg PMU_LVDT_6: voltage threshold is 3.0V
\arg PMU_LVDT_7: voltage threshold is 3.1V
\param[out] none
\retval none
*/
void pmu_lvd_select(uint32_t lvdt_n)
{
/* disable LVD */
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
/* clear LVDT bits */
PMU_CTL0 &= ~PMU_CTL0_LVDT;
/* set LVDT bits according to lvdt_n */
PMU_CTL0 |= lvdt_n;
/* enable LVD */
PMU_CTL0 |= PMU_CTL0_LVDEN;
}
/*!
\brief disable PMU LVD
\param[in] none
\param[out] none
\retval none
*/
void pmu_lvd_disable(void)
{
/* disable LVD */
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
}
/*!
\brief enable high-driver mode
this bit set by software only when IRC8M or HXTAL used as system clock
\param[in] none
\param[out] none
\retval none
*/
void pmu_highdriver_mode_enable(void)
{
PMU_CTL0 |= PMU_CTL0_HDEN;
}
/*!
\brief disable high-driver mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_highdriver_mode_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_HDEN;
}
/*!
\brief switch high-driver mode
this bit set by software only when IRC8M or HXTAL used as system clock
\param[in] highdr_switch:
only one parameter can be selected which is shown as below:
\arg PMU_HIGHDR_SWITCH_NONE: disable high-driver mode switch
\arg PMU_HIGHDR_SWITCH_EN: enable high-driver mode switch
\param[out] none
\retval none
*/
void pmu_highdriver_switch_select(uint32_t highdr_switch)
{
/* wait for HDRF flag set */
while(SET != pmu_flag_get(PMU_FLAG_HDRF)){
}
PMU_CTL0 &= ~PMU_CTL0_HDS;
PMU_CTL0 |= highdr_switch;
}
/*!
\brief enable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_lowdriver_mode_enable(void)
{
PMU_CTL0 |= PMU_CTL0_LDEN;
}
/*!
\brief disable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_lowdriver_mode_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_LDEN;
}
/*!
\brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use low power LDO
\param[in] mode:
only one parameter can be selected which is shown as below:
\arg PMU_NORMALDR_LOWPWR: normal driver when use low power LDO
\arg PMU_LOWDR_LOWPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
\param[out] none
\retval none
*/
void pmu_lowpower_driver_config(uint32_t mode)
{
PMU_CTL0 &= ~PMU_CTL0_LDLP;
PMU_CTL0 |= mode;
}
/*!
\brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use normal power LDO
\param[in] mode:
only one parameter can be selected which is shown as below:
\arg PMU_NORMALDR_NORMALPWR: normal driver when use normal power LDO
\arg PMU_LOWDR_NORMALPWR: low-driver mode enabled when LDEN is 11 and use normal power LDO
\param[out] none
\retval none
*/
void pmu_normalpower_driver_config(uint32_t mode)
{
PMU_CTL0 &= ~PMU_CTL0_LDNP;
PMU_CTL0 |= mode;
}
/*!
\brief PMU work at sleep mode
\param[in] sleepmodecmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_sleepmode(uint8_t sleepmodecmd)
{
/* clear sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
/* select WFI or WFE command to enter sleep mode */
if(WFI_CMD == sleepmodecmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
}
/*!
\brief PMU work at deepsleep mode
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep mode
\param[in] deepsleepmodecmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmodecmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 1/2 mode enable bits */
PMU_CTL1 &= ~(PMU_CTL1_DPMOD1 | PMU_CTL1_DPMOD2);
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode */
if(WFI_CMD == deepsleepmodecmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
/*!
\brief PMU work at deepsleep mode 1
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 1
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 1
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 1 mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 1 mode
\param[in] deepsleepmode1cmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode_1(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode1cmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 2 mode enable bit */
PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
/* enable deep-sleep 1 mode */
PMU_CTL1 |= PMU_CTL1_DPMOD1;
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep 1 mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode 1 */
if(WFI_CMD == deepsleepmode1cmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
}
/*!
\brief PMU work at deepsleep mode 2
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 2
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 2
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 2 mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 2 mode
\param[in] deepsleepmode2cmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode_2(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode2cmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 1 mode enable bit */
PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
/* enable deep-sleep 2 mode */
PMU_CTL1 |= PMU_CTL1_DPMOD2;
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep 2 mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode 2 */
if(WFI_CMD == deepsleepmode2cmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
}
/*!
\brief pmu work at standby mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_to_standbymode(void)
{
/* set stbmod bit */
PMU_CTL0 |= PMU_CTL0_STBMOD;
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
REG32( 0xE000E010U ) &= 0x00010004U;
REG32( 0xE000E180U ) = 0XFFFFFFF7U;
REG32( 0xE000E184U ) = 0XFFFFFDFFU;
REG32( 0xE000E188U ) = 0xFFFFFFFFU;
/* select WFI command to enter standby mode */
__WFI();
}
/*!
\brief enable PMU wakeup pin
\param[in] wakeup_pin:
one or more parameters can be selected which are shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
\arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
\arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
\arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
\arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
\param[out] none
\retval none
*/
void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
{
PMU_CS0 |= wakeup_pin;
}
/*!
\brief disable PMU wakeup pin
\param[in] wakeup_pin:
one or more parameters can be selected which are shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
\arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
\arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
\arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
\arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
\param[out] none
\retval none
*/
void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
{
PMU_CS0 &= ~(wakeup_pin);
}
/*!
\brief enable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_enable(void)
{
PMU_CTL0 |= PMU_CTL0_BKPWEN;
}
/*!
\brief disable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_BKPWEN;
}
/*!
\brief get flag state
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg PMU_FLAG_WAKEUP: wakeup flag
\arg PMU_FLAG_STANDBY: standby flag
\arg PMU_FLAG_LVD: lvd flag
\arg PMU_FLAG_HDRF: high-driver ready flag
\arg PMU_FLAG_HDSRF: high-driver switch ready flag
\arg PMU_FLAG_LDRF: low-driver mode ready flag
\arg PMU_FLAG_DEEPSLEEP_1: deep-sleep 1 mode status flag
\arg PMU_FLAG_DEEPSLEEP_2: deep-sleep 2 mode status flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus pmu_flag_get(uint32_t flag)
{
FlagStatus ret = RESET;
if(RESET != (flag & BIT(31))){
flag &= ~BIT(31);
if(PMU_CS1 & flag){
ret = SET;
}
}else{
if(PMU_CS0 & flag){
ret = SET;
}
}
return ret;
}
/*!
\brief clear flag bit
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg PMU_FLAG_RESET_WAKEUP: reset wakeup flag
\arg PMU_FLAG_RESET_STANDBY: reset standby flag
\arg PMU_FLAG_RESET_DEEPSLEEP_1: reset deep-sleep 1 mode status flag
\arg PMU_FLAG_RESET_DEEPSLEEP_2: reset deep-sleep 2 mode status flag
\param[out] none
\retval none
*/
void pmu_flag_clear(uint32_t flag)
{
switch(flag){
case PMU_FLAG_RESET_WAKEUP:
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
break;
case PMU_FLAG_RESET_STANDBY:
/* reset standby flag */
PMU_CTL0 |= PMU_CTL0_STBRST;
break;
case PMU_FLAG_RESET_DEEPSLEEP_1:
/* reset deep-sleep 1 mode status flag */
PMU_CS1 &= ~PMU_CS1_DPF1;
break;
case PMU_FLAG_RESET_DEEPSLEEP_2:
/* reset deep-sleep 2 mode status flag */
PMU_CS1 &= ~PMU_CS1_DPF2;
break;
default :
break;
}
}
@@ -0,0 +1,522 @@
/*!
\file gd32e50x_pmu.c
\brief PMU driver
\version 2026-02-09, V1.7.0, firmware for GD32E50x
*/
/*
Copyright (c) 2025, 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.
*/
#include "gd32e50x_pmu.h"
/*!
\brief reset PMU registers
\param[in] none
\param[out] none
\retval none
*/
void pmu_deinit(void)
{
/* reset PMU */
rcu_periph_reset_enable(RCU_PMURST);
rcu_periph_reset_disable(RCU_PMURST);
}
/*!
\brief select low voltage detector threshold
\param[in] lvdt_n:
only one parameter can be selected which is shown as below:
\arg PMU_LVDT_0: voltage threshold is 2.1V
\arg PMU_LVDT_1: voltage threshold is 2.3V
\arg PMU_LVDT_2: voltage threshold is 2.4V
\arg PMU_LVDT_3: voltage threshold is 2.6V
\arg PMU_LVDT_4: voltage threshold is 2.7V
\arg PMU_LVDT_5: voltage threshold is 2.9V
\arg PMU_LVDT_6: voltage threshold is 3.0V
\arg PMU_LVDT_7: voltage threshold is 3.1V
\param[out] none
\retval none
*/
void pmu_lvd_select(uint32_t lvdt_n)
{
/* disable LVD */
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
/* clear LVDT bits */
PMU_CTL0 &= ~PMU_CTL0_LVDT;
/* set LVDT bits according to lvdt_n */
PMU_CTL0 |= lvdt_n;
/* enable LVD */
PMU_CTL0 |= PMU_CTL0_LVDEN;
}
/*!
\brief disable PMU LVD
\param[in] none
\param[out] none
\retval none
*/
void pmu_lvd_disable(void)
{
/* disable LVD */
PMU_CTL0 &= ~PMU_CTL0_LVDEN;
}
/*!
\brief enable high-driver mode
this bit set by software only when IRC8M or HXTAL used as system clock
\param[in] none
\param[out] none
\retval none
*/
void pmu_highdriver_mode_enable(void)
{
PMU_CTL0 |= PMU_CTL0_HDEN;
}
/*!
\brief disable high-driver mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_highdriver_mode_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_HDEN;
}
/*!
\brief switch high-driver mode
this bit set by software only when IRC8M or HXTAL used as system clock
\param[in] highdr_switch:
only one parameter can be selected which is shown as below:
\arg PMU_HIGHDR_SWITCH_NONE: disable high-driver mode switch
\arg PMU_HIGHDR_SWITCH_EN: enable high-driver mode switch
\param[out] none
\retval none
*/
void pmu_highdriver_switch_select(uint32_t highdr_switch)
{
/* wait for HDRF flag set */
while(SET != pmu_flag_get(PMU_FLAG_HDRF)){
}
PMU_CTL0 &= ~PMU_CTL0_HDS;
PMU_CTL0 |= highdr_switch;
}
/*!
\brief enable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_lowdriver_mode_enable(void)
{
PMU_CTL0 |= PMU_CTL0_LDEN;
}
/*!
\brief disable low-driver mode in deep-sleep/deep-sleep 1/deep-sleep 2 mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_lowdriver_mode_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_LDEN;
}
/*!
\brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use low power LDO
\param[in] mode:
only one parameter can be selected which is shown as below:
\arg PMU_NORMALDR_LOWPWR: normal driver when use low power LDO
\arg PMU_LOWDR_LOWPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
\param[out] none
\retval none
*/
void pmu_lowpower_driver_config(uint32_t mode)
{
PMU_CTL0 &= ~PMU_CTL0_LDLP;
PMU_CTL0 |= mode;
}
/*!
\brief in deep-sleep/deep-sleep 1/deep-sleep 2 mode, driver mode when use normal power LDO
\param[in] mode:
only one parameter can be selected which is shown as below:
\arg PMU_NORMALDR_NORMALPWR: normal driver when use normal power LDO
\arg PMU_LOWDR_NORMALPWR: low-driver mode enabled when LDEN is 11 and use normal power LDO
\param[out] none
\retval none
*/
void pmu_normalpower_driver_config(uint32_t mode)
{
PMU_CTL0 &= ~PMU_CTL0_LDNP;
PMU_CTL0 |= mode;
}
/*!
\brief PMU work at sleep mode
\param[in] sleepmodecmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_sleepmode(uint8_t sleepmodecmd)
{
/* clear sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
/* select WFI or WFE command to enter sleep mode */
if(WFI_CMD == sleepmodecmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
}
/*!
\brief PMU work at deepsleep mode
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep mode
\param[in] deepsleepmodecmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmodecmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 1/2 mode enable bits */
PMU_CTL1 &= ~(PMU_CTL1_DPMOD1 | PMU_CTL1_DPMOD2);
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode */
if(WFI_CMD == deepsleepmodecmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
}
/*!
\brief PMU work at deepsleep mode 1
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 1
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 1
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 1 mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 1 mode
\param[in] deepsleepmode1cmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode_1(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode1cmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 2 mode enable bit */
PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
/* enable deep-sleep 1 mode */
PMU_CTL1 |= PMU_CTL1_DPMOD1;
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep 1 mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode 1 */
if(WFI_CMD == deepsleepmode1cmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
}
/*!
\brief PMU work at deepsleep mode 2
\param[in] ldo:
only one parameter can be selected which is shown as below:
\arg PMU_LDO_NORMAL: LDO normal work when pmu enter deepsleep mode 2
\arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode 2
\param[in] lowdrive:
only one parameter can be selected which is shown as below:
\arg PMU_LOWDRIVER_ENABLE: low-driver mode enable in deep-sleep 2 mode
\arg PMU_LOWDRIVER_DISABLE: low-driver mode disable in deep-sleep 2 mode
\param[in] deepsleepmode2cmd:
only one parameter can be selected which is shown as below:
\arg WFI_CMD: use WFI command
\arg WFE_CMD: use WFE command
\param[out] none
\retval none
*/
void pmu_to_deepsleepmode_2(uint32_t ldo, uint32_t lowdrive, uint8_t deepsleepmode2cmd)
{
/* clear stbmod and ldolp bits and low drive bits */
PMU_CTL0 &= ~((uint32_t)(PMU_CTL0_STBMOD | PMU_CTL0_LDOLP | PMU_CTL0_LDEN | PMU_CTL0_LDNP | PMU_CTL0_LDLP));
/* clear deep-sleep 1 mode enable bit */
PMU_CTL1 &= ~PMU_CTL1_DPMOD1;
/* enable deep-sleep 2 mode */
PMU_CTL1 |= PMU_CTL1_DPMOD2;
/* set ldolp bit according to pmu_ldo */
PMU_CTL0 |= ldo;
/* low drive mode config in deep-sleep 2 mode */
if(PMU_LOWDRIVER_ENABLE == lowdrive){
if(PMU_LDO_NORMAL == ldo){
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDNP);
}else{
PMU_CTL0 |= (uint32_t)(PMU_CTL0_LDEN | PMU_CTL0_LDLP);
}
}
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
/* select WFI or WFE command to enter deepsleep mode 2 */
if(WFI_CMD == deepsleepmode2cmd){
__WFI();
}else{
__SEV();
__WFE();
__WFE();
}
/* reset sleepdeep bit of Cortex-M33 system control register */
SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
PMU_CTL1 &= ~PMU_CTL1_DPMOD2;
}
/*!
\brief pmu work at standby mode
\param[in] none
\param[out] none
\retval none
*/
void pmu_to_standbymode(void)
{
/* set stbmod bit */
PMU_CTL0 |= PMU_CTL0_STBMOD;
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
/* set sleepdeep bit of Cortex-M33 system control register */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
REG32( 0xE000E010U ) &= 0x00010004U;
REG32( 0xE000E180U ) = 0XFFFFFFF7U;
REG32( 0xE000E184U ) = 0XFFFFFDFFU;
REG32( 0xE000E188U ) = 0xFFFFFFFFU;
/* select WFI command to enter standby mode */
__WFI();
}
/*!
\brief enable PMU wakeup pin
\param[in] wakeup_pin:
one or more parameters can be selected which are shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
\arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
\arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
\arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
\arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
\param[out] none
\retval none
*/
void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
{
PMU_CS0 |= wakeup_pin;
}
/*!
\brief disable PMU wakeup pin
\param[in] wakeup_pin:
one or more parameters can be selected which are shown as below:
\arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
\arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
\arg PMU_WAKEUP_PIN2: WKUP Pin 2 (PE6)
\arg PMU_WAKEUP_PIN3: WKUP Pin 3 (PA2)
\arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
\arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
\arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
\arg PMU_WAKEUP_PIN7: WKUP Pin 7 (PF8)
\param[out] none
\retval none
*/
void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
{
PMU_CS0 &= ~(wakeup_pin);
}
/*!
\brief enable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_enable(void)
{
PMU_CTL0 |= PMU_CTL0_BKPWEN;
}
/*!
\brief disable backup domain write
\param[in] none
\param[out] none
\retval none
*/
void pmu_backup_write_disable(void)
{
PMU_CTL0 &= ~PMU_CTL0_BKPWEN;
}
/*!
\brief get flag state
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg PMU_FLAG_WAKEUP: wakeup flag
\arg PMU_FLAG_STANDBY: standby flag
\arg PMU_FLAG_LVD: lvd flag
\arg PMU_FLAG_HDRF: high-driver ready flag
\arg PMU_FLAG_HDSRF: high-driver switch ready flag
\arg PMU_FLAG_LDRF: low-driver mode ready flag
\arg PMU_FLAG_DEEPSLEEP_1: deep-sleep 1 mode status flag
\arg PMU_FLAG_DEEPSLEEP_2: deep-sleep 2 mode status flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus pmu_flag_get(uint32_t flag)
{
FlagStatus ret = RESET;
if(RESET != (flag & BIT(31))){
flag &= ~BIT(31);
if(PMU_CS1 & flag){
ret = SET;
}
}else{
if(PMU_CS0 & flag){
ret = SET;
}
}
return ret;
}
/*!
\brief clear flag bit
\param[in] flag:
only one parameter can be selected which is shown as below:
\arg PMU_FLAG_RESET_WAKEUP: reset wakeup flag
\arg PMU_FLAG_RESET_STANDBY: reset standby flag
\arg PMU_FLAG_RESET_DEEPSLEEP_1: reset deep-sleep 1 mode status flag
\arg PMU_FLAG_RESET_DEEPSLEEP_2: reset deep-sleep 2 mode status flag
\param[out] none
\retval none
*/
void pmu_flag_clear(uint32_t flag)
{
switch(flag){
case PMU_FLAG_RESET_WAKEUP:
/* reset wakeup flag */
PMU_CTL0 |= PMU_CTL0_WURST;
break;
case PMU_FLAG_RESET_STANDBY:
/* reset standby flag */
PMU_CTL0 |= PMU_CTL0_STBRST;
break;
case PMU_FLAG_RESET_DEEPSLEEP_1:
/* reset deep-sleep 1 mode status flag */
PMU_CS1 &= ~PMU_CS1_DPF1;
break;
case PMU_FLAG_RESET_DEEPSLEEP_2:
/* reset deep-sleep 2 mode status flag */
PMU_CS1 &= ~PMU_CS1_DPF2;
break;
default :
break;
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,101 @@
#ifndef REGIONS_GD32E508VE_H
#define REGIONS_GD32E508VE_H
//-------- <<< Use Configuration Wizard in Context Menu >>> --------------------
//------ With VS Code: Open Preview for Configuration Wizard -------------------
// <n> Auto-generated using information from packs
// <i> Device Family Pack (DFP): GigaDevice::GD32E50x_DFP@1.9.0
// <h> ROM Configuration
// =======================
// <h> __ROM0 (is rx memory: IROM1 from DFP)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region. Default: 0x08000000
// <i> Contains Startup and Vector Table
#define __ROM0_BASE 0x08000000
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region. Default: 0x00080000
#define __ROM0_SIZE 0x00080000
// </h>
// <h> __ROM1 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __ROM1_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __ROM1_SIZE 0x0
// </h>
// <h> __ROM2 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __ROM2_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __ROM2_SIZE 0x0
// </h>
// <h> __ROM3 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __ROM3_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __ROM3_SIZE 0x0
// </h>
// </h>
// <h> RAM Configuration
// =======================
// <h> __RAM0 (is rwx memory: IRAM1 from DFP)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region. Default: 0x20000000
// <i> Contains uninitialized RAM, Stack, and Heap
#define __RAM0_BASE 0x20000000
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region. Default: 0x00020000
#define __RAM0_SIZE 0x00020000
// </h>
// <h> __RAM1 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __RAM1_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __RAM1_SIZE 0x0
// </h>
// <h> __RAM2 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __RAM2_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __RAM2_SIZE 0x0
// </h>
// <h> __RAM3 (unused)
// <o> Base address <0x0-0xFFFFFFFF:8>
// <i> Defines base address of memory region.
#define __RAM3_BASE 0x0
// <o> Region size [bytes] <0x0-0xFFFFFFFF:8>
// <i> Defines size of memory region.
#define __RAM3_SIZE 0x0
// </h>
// </h>
// <h> Stack / Heap Configuration
// <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
// <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
#define __STACK_SIZE 0x00000200
#define __HEAP_SIZE 0x00000C00
// </h>
#endif /* REGIONS_GD32E508VE_H */
@@ -0,0 +1,434 @@
;/*!
; \file startup_gd32e50x_cl.s
; \brief start up file
;
; \version 2025-07-09, V1.6.1, firmware for GD32E50x
;*/
;
;/*
; * Copyright (c) 2009-2018 Arm Limited. All rights reserved.
; * Copyright (c) 2023, GigaDevice Semiconductor Inc.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Licensed under the Apache License, Version 2.0 (the License); you may
; * not use this file except in compliance with the License.
; * You may obtain a copy of the License at
; *
; * www.apache.org/licenses/LICENSE-2.0
; *
; * Unless required by applicable law or agreed to in writing, software
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; * See the License for the specific language governing permissions and
; * limitations under the License.
; */
;/* This file refers the CMSIS standard, some adjustments are made according to GigaDevice chips */
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x00000800
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000400
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
; /* reset Vector Mapped to at Address 0 */
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; /* external interrupts handler */
DCD WWDGT_IRQHandler ; 16:Window Watchdog Timer
DCD LVD_IRQHandler ; 17:LVD through EXTI Line detect
DCD TAMPER_IRQHandler ; 18:Tamper through EXTI Line detect
DCD RTC_IRQHandler ; 19:RTC through EXTI Line
DCD FMC_IRQHandler ; 20:FMC
DCD RCU_CTC_IRQHandler ; 21:RCU and CTC
DCD EXTI0_IRQHandler ; 22:EXTI Line 0
DCD EXTI1_IRQHandler ; 23:EXTI Line 1
DCD EXTI2_IRQHandler ; 24:EXTI Line 2
DCD EXTI3_IRQHandler ; 25:EXTI Line 3
DCD EXTI4_IRQHandler ; 26:EXTI Line 4
DCD DMA0_Channel0_IRQHandler ; 27:DMA0 Channel0
DCD DMA0_Channel1_IRQHandler ; 28:DMA0 Channel1
DCD DMA0_Channel2_IRQHandler ; 29:DMA0 Channel2
DCD DMA0_Channel3_IRQHandler ; 30:DMA0 Channel3
DCD DMA0_Channel4_IRQHandler ; 31:DMA0 Channel4
DCD DMA0_Channel5_IRQHandler ; 32:DMA0 Channel5
DCD DMA0_Channel6_IRQHandler ; 33:DMA0 Channel6
DCD ADC0_1_IRQHandler ; 34:ADC0 and ADC1
DCD CAN0_TX_IRQHandler ; 35:CAN0 TX
DCD CAN0_RX0_IRQHandler ; 36:CAN0 RX0
DCD CAN0_RX1_IRQHandler ; 37:CAN0 RX1
DCD CAN0_EWMC_IRQHandler ; 38:CAN0 EWMC
DCD EXTI5_9_IRQHandler ; 39:EXTI5 to EXTI9
DCD TIMER0_BRK_TIMER8_IRQHandler ; 40:TIMER0 Break and TIMER8
DCD TIMER0_UP_TIMER9_IRQHandler ; 41:TIMER0 Update and TIMER9
DCD TIMER0_TRG_CMT_TIMER10_IRQHandler ; 42:TIMER0 Trigger and Commutation and TIMER10
DCD TIMER0_Channel_IRQHandler ; 43:TIMER0 Channel Capture Compare
DCD TIMER1_IRQHandler ; 44:TIMER1
DCD TIMER2_IRQHandler ; 45:TIMER2
DCD TIMER3_IRQHandler ; 46:TIMER3
DCD I2C0_EV_IRQHandler ; 47:I2C0 Event
DCD I2C0_ER_IRQHandler ; 48:I2C0 Error
DCD I2C1_EV_IRQHandler ; 49:I2C1 Event
DCD I2C1_ER_IRQHandler ; 50:I2C1 Error
DCD SPI0_IRQHandler ; 51:SPI0
DCD SPI1_I2S1ADD_IRQHandler ; 52:SPI1 or I2S1ADD
DCD USART0_IRQHandler ; 53:USART0
DCD USART1_IRQHandler ; 54:USART1
DCD USART2_IRQHandler ; 55:USART2
DCD EXTI10_15_IRQHandler ; 56:EXTI10 to EXTI15
DCD RTC_Alarm_IRQHandler ; 57:RTC Alarm
DCD USBHS_WKUP_IRQHandler ; 58:USBHS Wakeup
DCD TIMER7_BRK_TIMER11_IRQHandler ; 59:TIMER7 Break and TIMER11
DCD TIMER7_UP_TIMER12_IRQHandler ; 60:TIMER7 Update and TIMER12
DCD TIMER7_TRG_CMT_TIMER13_IRQHandler ; 61:TIMER7 Trigger and Commutation and TIMER13
DCD TIMER7_Channel_IRQHandler ; 62:TIMER7 Channel Capture Compare
DCD 0 ; Reserved
DCD EXMC_IRQHandler ; 64:EXMC
DCD 0 ; Reserved
DCD TIMER4_IRQHandler ; 66:TIMER4
DCD SPI2_I2S2ADD_IRQHandler ; 67:SPI2 or I2S2ADD
DCD UART3_IRQHandler ; 68:UART3
DCD UART4_IRQHandler ; 69:UART4
DCD TIMER5_DAC_IRQHandler ; 70:TIMER5 or DAC
DCD TIMER6_IRQHandler ; 71:TIMER6
DCD DMA1_Channel0_IRQHandler ; 72:DMA1 Channel0
DCD DMA1_Channel1_IRQHandler ; 73:DMA1 Channel1
DCD DMA1_Channel2_IRQHandler ; 74:DMA1 Channel2
DCD DMA1_Channel3_IRQHandler ; 75:DMA1 Channel3
DCD DMA1_Channel4_IRQHandler ; 76:DMA1 Channel4
DCD ENET_IRQHandler ; 77:Ethernet
DCD ENET_WKUP_IRQHandler ; 78:Ethernet Wakeup through EXTI Line
DCD CAN1_TX_IRQHandler ; 79:CAN1 TX
DCD CAN1_RX0_IRQHandler ; 80:CAN1 RX0
DCD CAN1_RX1_IRQHandler ; 81:CAN1 RX1
DCD CAN1_EWMC_IRQHandler ; 82:CAN1 EWMC
DCD USBHS_IRQHandler ; 83:USBHS
DCD 0 ; Reserved
DCD SHRTIMER_IRQ2_IRQHandler ; 85:SHRTIMER IRQ2
DCD SHRTIMER_IRQ3_IRQHandler ; 86:SHRTIMER IRQ3
DCD SHRTIMER_IRQ4_IRQHandler ; 87:SHRTIMER IRQ4
DCD SHRTIMER_IRQ5_IRQHandler ; 88:SHRTIMER IRQ5
DCD SHRTIMER_IRQ6_IRQHandler ; 89:SHRTIMER IRQ6
DCD USBHS_EP1_OUT_IRQHandler ; 90:USBHS end point 1 out
DCD USBHS_EP1_IN_IRQHandler ; 91:USBHS end point 1 in
DCD SHRTIMER_IRQ0_IRQHandler ; 92:SHRTIMER IRQ0
DCD SHRTIMER_IRQ1_IRQHandler ; 93:SHRTIMER IRQ1
DCD CAN2_TX_IRQHandler ; 94:CAN2 TX
DCD CAN2_RX0_IRQHandler ; 95:CAN2 RX0
DCD CAN2_RX1_IRQHandler ; 96:CAN2 RX1
DCD CAN2_EWMC_IRQHandler ; 97:CAN2 EWMC
DCD I2C2_EV_IRQHandler ; 98:I2C2 Event
DCD I2C2_ER_IRQHandler ; 99:I2C2 Error
DCD USART5_IRQHandler ; 100:USART5
DCD I2C2_WKUP_IRQHandler ; 101:I2C2 Wakeup
DCD USART5_WKUP_IRQHandler ; 102:USART5 Wakeup
DCD TMU_IRQHandler ; 103:TMU
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
;/* reset Handler */
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
;/* dummy Exception Handlers */
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemManage_Handler\
PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler\
PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler\
PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler\
PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
; /* external interrupts handler */
EXPORT WWDGT_IRQHandler [WEAK]
EXPORT LVD_IRQHandler [WEAK]
EXPORT TAMPER_IRQHandler [WEAK]
EXPORT RTC_IRQHandler [WEAK]
EXPORT FMC_IRQHandler [WEAK]
EXPORT RCU_CTC_IRQHandler [WEAK]
EXPORT EXTI0_IRQHandler [WEAK]
EXPORT EXTI1_IRQHandler [WEAK]
EXPORT EXTI2_IRQHandler [WEAK]
EXPORT EXTI3_IRQHandler [WEAK]
EXPORT EXTI4_IRQHandler [WEAK]
EXPORT DMA0_Channel0_IRQHandler [WEAK]
EXPORT DMA0_Channel1_IRQHandler [WEAK]
EXPORT DMA0_Channel2_IRQHandler [WEAK]
EXPORT DMA0_Channel3_IRQHandler [WEAK]
EXPORT DMA0_Channel4_IRQHandler [WEAK]
EXPORT DMA0_Channel5_IRQHandler [WEAK]
EXPORT DMA0_Channel6_IRQHandler [WEAK]
EXPORT ADC0_1_IRQHandler [WEAK]
EXPORT CAN0_TX_IRQHandler [WEAK]
EXPORT CAN0_RX0_IRQHandler [WEAK]
EXPORT CAN0_RX1_IRQHandler [WEAK]
EXPORT CAN0_EWMC_IRQHandler [WEAK]
EXPORT EXTI5_9_IRQHandler [WEAK]
EXPORT TIMER0_BRK_TIMER8_IRQHandler [WEAK]
EXPORT TIMER0_UP_TIMER9_IRQHandler [WEAK]
EXPORT TIMER0_TRG_CMT_TIMER10_IRQHandler [WEAK]
EXPORT TIMER0_Channel_IRQHandler [WEAK]
EXPORT TIMER1_IRQHandler [WEAK]
EXPORT TIMER2_IRQHandler [WEAK]
EXPORT TIMER3_IRQHandler [WEAK]
EXPORT I2C0_EV_IRQHandler [WEAK]
EXPORT I2C0_ER_IRQHandler [WEAK]
EXPORT I2C1_EV_IRQHandler [WEAK]
EXPORT I2C1_ER_IRQHandler [WEAK]
EXPORT SPI0_IRQHandler [WEAK]
EXPORT SPI1_I2S1ADD_IRQHandler [WEAK]
EXPORT USART0_IRQHandler [WEAK]
EXPORT USART1_IRQHandler [WEAK]
EXPORT USART2_IRQHandler [WEAK]
EXPORT EXTI10_15_IRQHandler [WEAK]
EXPORT RTC_Alarm_IRQHandler [WEAK]
EXPORT USBHS_WKUP_IRQHandler [WEAK]
EXPORT TIMER7_BRK_TIMER11_IRQHandler [WEAK]
EXPORT TIMER7_UP_TIMER12_IRQHandler [WEAK]
EXPORT TIMER7_TRG_CMT_TIMER13_IRQHandler [WEAK]
EXPORT TIMER7_Channel_IRQHandler [WEAK]
EXPORT EXMC_IRQHandler [WEAK]
EXPORT TIMER4_IRQHandler [WEAK]
EXPORT SPI2_I2S2ADD_IRQHandler [WEAK]
EXPORT UART3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT TIMER5_DAC_IRQHandler [WEAK]
EXPORT TIMER6_IRQHandler [WEAK]
EXPORT DMA1_Channel0_IRQHandler [WEAK]
EXPORT DMA1_Channel1_IRQHandler [WEAK]
EXPORT DMA1_Channel2_IRQHandler [WEAK]
EXPORT DMA1_Channel3_IRQHandler [WEAK]
EXPORT DMA1_Channel4_IRQHandler [WEAK]
EXPORT ENET_IRQHandler [WEAK]
EXPORT ENET_WKUP_IRQHandler [WEAK]
EXPORT CAN1_TX_IRQHandler [WEAK]
EXPORT CAN1_RX0_IRQHandler [WEAK]
EXPORT CAN1_RX1_IRQHandler [WEAK]
EXPORT CAN1_EWMC_IRQHandler [WEAK]
EXPORT USBHS_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ2_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ3_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ4_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ5_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ6_IRQHandler [WEAK]
EXPORT USBHS_EP1_OUT_IRQHandler [WEAK]
EXPORT USBHS_EP1_IN_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ0_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ1_IRQHandler [WEAK]
EXPORT CAN2_TX_IRQHandler [WEAK]
EXPORT CAN2_RX0_IRQHandler [WEAK]
EXPORT CAN2_RX1_IRQHandler [WEAK]
EXPORT CAN2_EWMC_IRQHandler [WEAK]
EXPORT I2C2_EV_IRQHandler [WEAK]
EXPORT I2C2_ER_IRQHandler [WEAK]
EXPORT USART5_IRQHandler [WEAK]
EXPORT I2C2_WKUP_IRQHandler [WEAK]
EXPORT USART5_WKUP_IRQHandler [WEAK]
EXPORT TMU_IRQHandler [WEAK]
;/* external interrupts handler */
WWDGT_IRQHandler
LVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FMC_IRQHandler
RCU_CTC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA0_Channel0_IRQHandler
DMA0_Channel1_IRQHandler
DMA0_Channel2_IRQHandler
DMA0_Channel3_IRQHandler
DMA0_Channel4_IRQHandler
DMA0_Channel5_IRQHandler
DMA0_Channel6_IRQHandler
ADC0_1_IRQHandler
CAN0_TX_IRQHandler
CAN0_RX0_IRQHandler
CAN0_RX1_IRQHandler
CAN0_EWMC_IRQHandler
EXTI5_9_IRQHandler
TIMER0_BRK_TIMER8_IRQHandler
TIMER0_UP_TIMER9_IRQHandler
TIMER0_TRG_CMT_TIMER10_IRQHandler
TIMER0_Channel_IRQHandler
TIMER1_IRQHandler
TIMER2_IRQHandler
TIMER3_IRQHandler
I2C0_EV_IRQHandler
I2C0_ER_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
SPI0_IRQHandler
SPI1_I2S1ADD_IRQHandler
USART0_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
EXTI10_15_IRQHandler
RTC_Alarm_IRQHandler
USBHS_WKUP_IRQHandler
TIMER7_BRK_TIMER11_IRQHandler
TIMER7_UP_TIMER12_IRQHandler
TIMER7_TRG_CMT_TIMER13_IRQHandler
TIMER7_Channel_IRQHandler
EXMC_IRQHandler
TIMER4_IRQHandler
SPI2_I2S2ADD_IRQHandler
UART3_IRQHandler
UART4_IRQHandler
TIMER5_DAC_IRQHandler
TIMER6_IRQHandler
DMA1_Channel0_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
ENET_IRQHandler
ENET_WKUP_IRQHandler
CAN1_TX_IRQHandler
CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_EWMC_IRQHandler
USBHS_IRQHandler
SHRTIMER_IRQ2_IRQHandler
SHRTIMER_IRQ3_IRQHandler
SHRTIMER_IRQ4_IRQHandler
SHRTIMER_IRQ5_IRQHandler
SHRTIMER_IRQ6_IRQHandler
USBHS_EP1_OUT_IRQHandler
USBHS_EP1_IN_IRQHandler
SHRTIMER_IRQ0_IRQHandler
SHRTIMER_IRQ1_IRQHandler
CAN2_TX_IRQHandler
CAN2_RX0_IRQHandler
CAN2_RX1_IRQHandler
CAN2_EWMC_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
USART5_IRQHandler
I2C2_WKUP_IRQHandler
USART5_WKUP_IRQHandler
TMU_IRQHandler
B .
ENDP
ALIGN
; user Initial Stack & Heap
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap PROC
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDP
ALIGN
ENDIF
END
@@ -0,0 +1,434 @@
;/*!
; \file startup_gd32e50x_cl.s
; \brief start up file
;
; \version 2025-07-09, V1.6.1, firmware for GD32E50x
;*/
;
;/*
; * Copyright (c) 2009-2018 Arm Limited. All rights reserved.
; * Copyright (c) 2023, GigaDevice Semiconductor Inc.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Licensed under the Apache License, Version 2.0 (the License); you may
; * not use this file except in compliance with the License.
; * You may obtain a copy of the License at
; *
; * www.apache.org/licenses/LICENSE-2.0
; *
; * Unless required by applicable law or agreed to in writing, software
; * distributed under the License is distributed on an AS IS BASIS, WITHOUT
; * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; * See the License for the specific language governing permissions and
; * limitations under the License.
; */
;/* This file refers the CMSIS standard, some adjustments are made according to GigaDevice chips */
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x00000800
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x00000400
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
; /* reset Vector Mapped to at Address 0 */
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; /* external interrupts handler */
DCD WWDGT_IRQHandler ; 16:Window Watchdog Timer
DCD LVD_IRQHandler ; 17:LVD through EXTI Line detect
DCD TAMPER_IRQHandler ; 18:Tamper through EXTI Line detect
DCD RTC_IRQHandler ; 19:RTC through EXTI Line
DCD FMC_IRQHandler ; 20:FMC
DCD RCU_CTC_IRQHandler ; 21:RCU and CTC
DCD EXTI0_IRQHandler ; 22:EXTI Line 0
DCD EXTI1_IRQHandler ; 23:EXTI Line 1
DCD EXTI2_IRQHandler ; 24:EXTI Line 2
DCD EXTI3_IRQHandler ; 25:EXTI Line 3
DCD EXTI4_IRQHandler ; 26:EXTI Line 4
DCD DMA0_Channel0_IRQHandler ; 27:DMA0 Channel0
DCD DMA0_Channel1_IRQHandler ; 28:DMA0 Channel1
DCD DMA0_Channel2_IRQHandler ; 29:DMA0 Channel2
DCD DMA0_Channel3_IRQHandler ; 30:DMA0 Channel3
DCD DMA0_Channel4_IRQHandler ; 31:DMA0 Channel4
DCD DMA0_Channel5_IRQHandler ; 32:DMA0 Channel5
DCD DMA0_Channel6_IRQHandler ; 33:DMA0 Channel6
DCD ADC0_1_IRQHandler ; 34:ADC0 and ADC1
DCD CAN0_TX_IRQHandler ; 35:CAN0 TX
DCD CAN0_RX0_IRQHandler ; 36:CAN0 RX0
DCD CAN0_RX1_IRQHandler ; 37:CAN0 RX1
DCD CAN0_EWMC_IRQHandler ; 38:CAN0 EWMC
DCD EXTI5_9_IRQHandler ; 39:EXTI5 to EXTI9
DCD TIMER0_BRK_TIMER8_IRQHandler ; 40:TIMER0 Break and TIMER8
DCD TIMER0_UP_TIMER9_IRQHandler ; 41:TIMER0 Update and TIMER9
DCD TIMER0_TRG_CMT_TIMER10_IRQHandler ; 42:TIMER0 Trigger and Commutation and TIMER10
DCD TIMER0_Channel_IRQHandler ; 43:TIMER0 Channel Capture Compare
DCD TIMER1_IRQHandler ; 44:TIMER1
DCD TIMER2_IRQHandler ; 45:TIMER2
DCD TIMER3_IRQHandler ; 46:TIMER3
DCD I2C0_EV_IRQHandler ; 47:I2C0 Event
DCD I2C0_ER_IRQHandler ; 48:I2C0 Error
DCD I2C1_EV_IRQHandler ; 49:I2C1 Event
DCD I2C1_ER_IRQHandler ; 50:I2C1 Error
DCD SPI0_IRQHandler ; 51:SPI0
DCD SPI1_I2S1ADD_IRQHandler ; 52:SPI1 or I2S1ADD
DCD USART0_IRQHandler ; 53:USART0
DCD USART1_IRQHandler ; 54:USART1
DCD USART2_IRQHandler ; 55:USART2
DCD EXTI10_15_IRQHandler ; 56:EXTI10 to EXTI15
DCD RTC_Alarm_IRQHandler ; 57:RTC Alarm
DCD USBHS_WKUP_IRQHandler ; 58:USBHS Wakeup
DCD TIMER7_BRK_TIMER11_IRQHandler ; 59:TIMER7 Break and TIMER11
DCD TIMER7_UP_TIMER12_IRQHandler ; 60:TIMER7 Update and TIMER12
DCD TIMER7_TRG_CMT_TIMER13_IRQHandler ; 61:TIMER7 Trigger and Commutation and TIMER13
DCD TIMER7_Channel_IRQHandler ; 62:TIMER7 Channel Capture Compare
DCD 0 ; Reserved
DCD EXMC_IRQHandler ; 64:EXMC
DCD 0 ; Reserved
DCD TIMER4_IRQHandler ; 66:TIMER4
DCD SPI2_I2S2ADD_IRQHandler ; 67:SPI2 or I2S2ADD
DCD UART3_IRQHandler ; 68:UART3
DCD UART4_IRQHandler ; 69:UART4
DCD TIMER5_DAC_IRQHandler ; 70:TIMER5 or DAC
DCD TIMER6_IRQHandler ; 71:TIMER6
DCD DMA1_Channel0_IRQHandler ; 72:DMA1 Channel0
DCD DMA1_Channel1_IRQHandler ; 73:DMA1 Channel1
DCD DMA1_Channel2_IRQHandler ; 74:DMA1 Channel2
DCD DMA1_Channel3_IRQHandler ; 75:DMA1 Channel3
DCD DMA1_Channel4_IRQHandler ; 76:DMA1 Channel4
DCD ENET_IRQHandler ; 77:Ethernet
DCD ENET_WKUP_IRQHandler ; 78:Ethernet Wakeup through EXTI Line
DCD CAN1_TX_IRQHandler ; 79:CAN1 TX
DCD CAN1_RX0_IRQHandler ; 80:CAN1 RX0
DCD CAN1_RX1_IRQHandler ; 81:CAN1 RX1
DCD CAN1_EWMC_IRQHandler ; 82:CAN1 EWMC
DCD USBHS_IRQHandler ; 83:USBHS
DCD 0 ; Reserved
DCD SHRTIMER_IRQ2_IRQHandler ; 85:SHRTIMER IRQ2
DCD SHRTIMER_IRQ3_IRQHandler ; 86:SHRTIMER IRQ3
DCD SHRTIMER_IRQ4_IRQHandler ; 87:SHRTIMER IRQ4
DCD SHRTIMER_IRQ5_IRQHandler ; 88:SHRTIMER IRQ5
DCD SHRTIMER_IRQ6_IRQHandler ; 89:SHRTIMER IRQ6
DCD USBHS_EP1_OUT_IRQHandler ; 90:USBHS end point 1 out
DCD USBHS_EP1_IN_IRQHandler ; 91:USBHS end point 1 in
DCD SHRTIMER_IRQ0_IRQHandler ; 92:SHRTIMER IRQ0
DCD SHRTIMER_IRQ1_IRQHandler ; 93:SHRTIMER IRQ1
DCD CAN2_TX_IRQHandler ; 94:CAN2 TX
DCD CAN2_RX0_IRQHandler ; 95:CAN2 RX0
DCD CAN2_RX1_IRQHandler ; 96:CAN2 RX1
DCD CAN2_EWMC_IRQHandler ; 97:CAN2 EWMC
DCD I2C2_EV_IRQHandler ; 98:I2C2 Event
DCD I2C2_ER_IRQHandler ; 99:I2C2 Error
DCD USART5_IRQHandler ; 100:USART5
DCD I2C2_WKUP_IRQHandler ; 101:I2C2 Wakeup
DCD USART5_WKUP_IRQHandler ; 102:USART5 Wakeup
DCD TMU_IRQHandler ; 103:TMU
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
;/* reset Handler */
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
;/* dummy Exception Handlers */
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemManage_Handler\
PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler\
PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler\
PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler\
PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
; /* external interrupts handler */
EXPORT WWDGT_IRQHandler [WEAK]
EXPORT LVD_IRQHandler [WEAK]
EXPORT TAMPER_IRQHandler [WEAK]
EXPORT RTC_IRQHandler [WEAK]
EXPORT FMC_IRQHandler [WEAK]
EXPORT RCU_CTC_IRQHandler [WEAK]
EXPORT EXTI0_IRQHandler [WEAK]
EXPORT EXTI1_IRQHandler [WEAK]
EXPORT EXTI2_IRQHandler [WEAK]
EXPORT EXTI3_IRQHandler [WEAK]
EXPORT EXTI4_IRQHandler [WEAK]
EXPORT DMA0_Channel0_IRQHandler [WEAK]
EXPORT DMA0_Channel1_IRQHandler [WEAK]
EXPORT DMA0_Channel2_IRQHandler [WEAK]
EXPORT DMA0_Channel3_IRQHandler [WEAK]
EXPORT DMA0_Channel4_IRQHandler [WEAK]
EXPORT DMA0_Channel5_IRQHandler [WEAK]
EXPORT DMA0_Channel6_IRQHandler [WEAK]
EXPORT ADC0_1_IRQHandler [WEAK]
EXPORT CAN0_TX_IRQHandler [WEAK]
EXPORT CAN0_RX0_IRQHandler [WEAK]
EXPORT CAN0_RX1_IRQHandler [WEAK]
EXPORT CAN0_EWMC_IRQHandler [WEAK]
EXPORT EXTI5_9_IRQHandler [WEAK]
EXPORT TIMER0_BRK_TIMER8_IRQHandler [WEAK]
EXPORT TIMER0_UP_TIMER9_IRQHandler [WEAK]
EXPORT TIMER0_TRG_CMT_TIMER10_IRQHandler [WEAK]
EXPORT TIMER0_Channel_IRQHandler [WEAK]
EXPORT TIMER1_IRQHandler [WEAK]
EXPORT TIMER2_IRQHandler [WEAK]
EXPORT TIMER3_IRQHandler [WEAK]
EXPORT I2C0_EV_IRQHandler [WEAK]
EXPORT I2C0_ER_IRQHandler [WEAK]
EXPORT I2C1_EV_IRQHandler [WEAK]
EXPORT I2C1_ER_IRQHandler [WEAK]
EXPORT SPI0_IRQHandler [WEAK]
EXPORT SPI1_I2S1ADD_IRQHandler [WEAK]
EXPORT USART0_IRQHandler [WEAK]
EXPORT USART1_IRQHandler [WEAK]
EXPORT USART2_IRQHandler [WEAK]
EXPORT EXTI10_15_IRQHandler [WEAK]
EXPORT RTC_Alarm_IRQHandler [WEAK]
EXPORT USBHS_WKUP_IRQHandler [WEAK]
EXPORT TIMER7_BRK_TIMER11_IRQHandler [WEAK]
EXPORT TIMER7_UP_TIMER12_IRQHandler [WEAK]
EXPORT TIMER7_TRG_CMT_TIMER13_IRQHandler [WEAK]
EXPORT TIMER7_Channel_IRQHandler [WEAK]
EXPORT EXMC_IRQHandler [WEAK]
EXPORT TIMER4_IRQHandler [WEAK]
EXPORT SPI2_I2S2ADD_IRQHandler [WEAK]
EXPORT UART3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT TIMER5_DAC_IRQHandler [WEAK]
EXPORT TIMER6_IRQHandler [WEAK]
EXPORT DMA1_Channel0_IRQHandler [WEAK]
EXPORT DMA1_Channel1_IRQHandler [WEAK]
EXPORT DMA1_Channel2_IRQHandler [WEAK]
EXPORT DMA1_Channel3_IRQHandler [WEAK]
EXPORT DMA1_Channel4_IRQHandler [WEAK]
EXPORT ENET_IRQHandler [WEAK]
EXPORT ENET_WKUP_IRQHandler [WEAK]
EXPORT CAN1_TX_IRQHandler [WEAK]
EXPORT CAN1_RX0_IRQHandler [WEAK]
EXPORT CAN1_RX1_IRQHandler [WEAK]
EXPORT CAN1_EWMC_IRQHandler [WEAK]
EXPORT USBHS_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ2_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ3_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ4_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ5_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ6_IRQHandler [WEAK]
EXPORT USBHS_EP1_OUT_IRQHandler [WEAK]
EXPORT USBHS_EP1_IN_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ0_IRQHandler [WEAK]
EXPORT SHRTIMER_IRQ1_IRQHandler [WEAK]
EXPORT CAN2_TX_IRQHandler [WEAK]
EXPORT CAN2_RX0_IRQHandler [WEAK]
EXPORT CAN2_RX1_IRQHandler [WEAK]
EXPORT CAN2_EWMC_IRQHandler [WEAK]
EXPORT I2C2_EV_IRQHandler [WEAK]
EXPORT I2C2_ER_IRQHandler [WEAK]
EXPORT USART5_IRQHandler [WEAK]
EXPORT I2C2_WKUP_IRQHandler [WEAK]
EXPORT USART5_WKUP_IRQHandler [WEAK]
EXPORT TMU_IRQHandler [WEAK]
;/* external interrupts handler */
WWDGT_IRQHandler
LVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FMC_IRQHandler
RCU_CTC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA0_Channel0_IRQHandler
DMA0_Channel1_IRQHandler
DMA0_Channel2_IRQHandler
DMA0_Channel3_IRQHandler
DMA0_Channel4_IRQHandler
DMA0_Channel5_IRQHandler
DMA0_Channel6_IRQHandler
ADC0_1_IRQHandler
CAN0_TX_IRQHandler
CAN0_RX0_IRQHandler
CAN0_RX1_IRQHandler
CAN0_EWMC_IRQHandler
EXTI5_9_IRQHandler
TIMER0_BRK_TIMER8_IRQHandler
TIMER0_UP_TIMER9_IRQHandler
TIMER0_TRG_CMT_TIMER10_IRQHandler
TIMER0_Channel_IRQHandler
TIMER1_IRQHandler
TIMER2_IRQHandler
TIMER3_IRQHandler
I2C0_EV_IRQHandler
I2C0_ER_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
SPI0_IRQHandler
SPI1_I2S1ADD_IRQHandler
USART0_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
EXTI10_15_IRQHandler
RTC_Alarm_IRQHandler
USBHS_WKUP_IRQHandler
TIMER7_BRK_TIMER11_IRQHandler
TIMER7_UP_TIMER12_IRQHandler
TIMER7_TRG_CMT_TIMER13_IRQHandler
TIMER7_Channel_IRQHandler
EXMC_IRQHandler
TIMER4_IRQHandler
SPI2_I2S2ADD_IRQHandler
UART3_IRQHandler
UART4_IRQHandler
TIMER5_DAC_IRQHandler
TIMER6_IRQHandler
DMA1_Channel0_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
ENET_IRQHandler
ENET_WKUP_IRQHandler
CAN1_TX_IRQHandler
CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_EWMC_IRQHandler
USBHS_IRQHandler
SHRTIMER_IRQ2_IRQHandler
SHRTIMER_IRQ3_IRQHandler
SHRTIMER_IRQ4_IRQHandler
SHRTIMER_IRQ5_IRQHandler
SHRTIMER_IRQ6_IRQHandler
USBHS_EP1_OUT_IRQHandler
USBHS_EP1_IN_IRQHandler
SHRTIMER_IRQ0_IRQHandler
SHRTIMER_IRQ1_IRQHandler
CAN2_TX_IRQHandler
CAN2_RX0_IRQHandler
CAN2_RX1_IRQHandler
CAN2_EWMC_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
USART5_IRQHandler
I2C2_WKUP_IRQHandler
USART5_WKUP_IRQHandler
TMU_IRQHandler
B .
ENDP
ALIGN
; user Initial Stack & Heap
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap PROC
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDP
ALIGN
ENDIF
END
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,48 @@
/*
* CSOLUTION generated file: DO NOT EDIT!
* Generated by: csolution version 2.13.0+p3-g40b6564e
*
* Project: 'GD32E50X_BOOT.Debug+GD32E508VE'
* Target: 'Debug+GD32E508VE'
*/
#ifndef RTE_COMPONENTS_H
#define RTE_COMPONENTS_H
/*
* Define the Device Header File:
*/
#define CMSIS_device_header "gd32e50x.h"
/* GigaDevice::Device:GD32E50x_StdPeripherals:ADC@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_ADC
/* GigaDevice::Device:GD32E50x_StdPeripherals:CAN@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_CAN
/* GigaDevice::Device:GD32E50x_StdPeripherals:CRC@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_CRC
/* GigaDevice::Device:GD32E50x_StdPeripherals:DBG@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_DBG
/* GigaDevice::Device:GD32E50x_StdPeripherals:DMA@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_DMA
/* GigaDevice::Device:GD32E50x_StdPeripherals:EXTI@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_EXTI
/* GigaDevice::Device:GD32E50x_StdPeripherals:FMC@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_FMC
/* GigaDevice::Device:GD32E50x_StdPeripherals:FWDGT@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_FWDGT
/* GigaDevice::Device:GD32E50x_StdPeripherals:GPIO@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_GPIO
/* GigaDevice::Device:GD32E50x_StdPeripherals:MISC@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_MISC
/* GigaDevice::Device:GD32E50x_StdPeripherals:PMU@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_PMU
/* GigaDevice::Device:GD32E50x_StdPeripherals:RCU@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_RCU
/* GigaDevice::Device:GD32E50x_StdPeripherals:TIMER@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_TIMER
/* GigaDevice::Device:GD32E50x_StdPeripherals:USART@1.6.0 */
#define RTE_DEVICE_STDPERIPHERALS_USART
#endif /* RTE_COMPONENTS_H */
@@ -0,0 +1,7 @@
#include "RTE_Components.h"
#include CMSIS_device_header
int main() {
for (;;) {
}
}
+16
View File
@@ -0,0 +1,16 @@
{
"registries": [
{
"name": "arm",
"kind": "artifact",
"location": "https://artifacts.tools.arm.com/vcpkg-registry"
}
],
"requires": {
"arm:tools/open-cmsis-pack/cmsis-toolbox": "2.13.0",
"arm:tools/kitware/cmake": "3.31.5",
"arm:tools/ninja-build/ninja": "1.13.2",
"arm:tools/arm/mdk-toolbox": "1.1.0",
"arm:compilers/arm/armclang": "6.24.0"
}
}