feat: 添加GD32E508 DCU应用工程的初始结构

- 新增完整的CMSIS解决方案配置,包含AC6/GCC/IAR/CLANG编译器支持
- 添加项目配置文件,定义了设备层、系统层、应用层的模块结构
- 配置ARM::CMSIS和GigaDevice::GD32E50x_DFP软件包依赖
- 创建多层代码架构:应用入口(main)、系统层(sys)、设备层(device)
- 实现任务管理系统,包含任务调度器和任务执行器分离设计
- 集成ADC、CANFD、定时器、串口、温度采样等核心功能模块
- 添加详细的README文档说明项目结构和代码组织方式
- 配置AC6链接脚本和运行时环境文件
- 设置Git忽略规则以排除编译产物和临时文件
This commit is contained in:
cbb
2026-05-10 17:28:14 +08:00
commit 4b8b47bc9b
116 changed files with 36659 additions and 0 deletions
@@ -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
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,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,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
@@ -0,0 +1,895 @@
/*!
\file gd32e50x_spi.c
\brief SPI 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_spi.h"
/* SPI/I2S parameter initialization mask */
#define SPI_INIT_MASK ((uint32_t)0x00003040U) /*!< SPI parameter initialization mask */
#define I2S_INIT_MASK ((uint32_t)0x0000F047U) /*!< I2S parameter initialization mask */
#define I2S_FULL_DUPLEX_MASK ((uint32_t)0x00000480U) /*!< I2S full duples mode configure parameter initialization mask */
/* default value */
#define SPI_I2SPSC_DEFAULT_VALUE ((uint32_t)0x00000002U) /*!< default value of SPI_I2SPSC register */
/* I2S clock source selection, multiplication and division mask */
#define I2S1_CLOCK_SEL ((uint32_t)0x00020000U) /*!< I2S1 clock source selection */
#define I2S2_CLOCK_SEL ((uint32_t)0x00040000U) /*!< I2S2 clock source selection */
#define I2S_CLOCK_MUL_MASK ((uint32_t)0x0000F000U) /*!< I2S clock multiplication mask */
#define I2S_CLOCK_DIV_MASK ((uint32_t)0x000000F0U) /*!< I2S clock division mask */
/*!
\brief reset SPI and I2S
\param[in] spi_periph: SPIx(x=0,1,2),include I2S1_ADD and I2S2_ADD
\param[out] none
\retval none
*/
void spi_i2s_deinit(uint32_t spi_periph)
{
switch(spi_periph){
case SPI0:
/* reset SPI0 */
rcu_periph_reset_enable(RCU_SPI0RST);
rcu_periph_reset_disable(RCU_SPI0RST);
break;
case SPI1:
/* reset SPI1 , I2S1 and I2S1_ADD */
rcu_periph_reset_enable(RCU_SPI1RST);
rcu_periph_reset_disable(RCU_SPI1RST);
break;
case SPI2:
/* reset SPI2 , I2S2 and I2S2_ADD */
rcu_periph_reset_enable(RCU_SPI2RST);
rcu_periph_reset_disable(RCU_SPI2RST);
break;
default :
break;
}
}
/*!
\brief initialize the parameters of SPI struct with default values
\param[in] none
\param[out] spi_parameter_struct: the initialized struct spi_parameter_struct pointer
\retval none
*/
void spi_struct_para_init(spi_parameter_struct *spi_struct)
{
/* configure the structure with default value */
spi_struct->device_mode = SPI_SLAVE;
spi_struct->trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_struct->frame_size = SPI_FRAMESIZE_8BIT;
spi_struct->nss = SPI_NSS_HARD;
spi_struct->clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_struct->prescale = SPI_PSC_2;
spi_struct->endian = SPI_ENDIAN_MSB;
}
/*!
\brief initialize SPI parameter
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] spi_struct: SPI parameter initialization stuct members of the structure
and the member values are shown as below:
device_mode: SPI_MASTER, SPI_SLAVE
trans_mode: SPI_TRANSMODE_FULLDUPLEX, SPI_TRANSMODE_RECEIVEONLY,
SPI_TRANSMODE_BDRECEIVE, SPI_TRANSMODE_BDTRANSMIT
frame_size: SPI_FRAMESIZE_16BIT, SPI_FRAMESIZE_8BIT
nss: SPI_NSS_SOFT, SPI_NSS_HARD
endian: SPI_ENDIAN_MSB, SPI_ENDIAN_LSB
clock_polarity_phase: SPI_CK_PL_LOW_PH_1EDGE, SPI_CK_PL_HIGH_PH_1EDGE
SPI_CK_PL_LOW_PH_2EDGE, SPI_CK_PL_HIGH_PH_2EDGE
prescale: SPI_PSC_n (n=2,4,8,16,32,64,128,256)
\param[out] none
\retval none
*/
void spi_init(uint32_t spi_periph, spi_parameter_struct* spi_struct)
{
uint32_t reg = 0U;
reg = SPI_CTL0(spi_periph);
reg &= SPI_INIT_MASK;
/* select SPI as master or slave */
reg |= spi_struct->device_mode;
/* select SPI transfer mode */
reg |= spi_struct->trans_mode;
/* select SPI frame size */
reg |= spi_struct->frame_size;
/* select SPI NSS use hardware or software */
reg |= spi_struct->nss;
/* select SPI LSB or MSB */
reg |= spi_struct->endian;
/* select SPI polarity and phase */
reg |= spi_struct->clock_polarity_phase;
/* select SPI prescale to adjust transmit speed */
reg |= spi_struct->prescale;
/* write to SPI_CTL0 register */
SPI_CTL0(spi_periph) = (uint32_t)reg;
SPI_I2SCTL(spi_periph) &= (uint32_t)(~SPI_I2SCTL_I2SSEL);
}
/*!
\brief enable SPI
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_enable(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_SPIEN;
}
/*!
\brief disable SPI
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_disable(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_SPIEN);
}
/*!
\brief initialize I2S parameter
\param[in] spi_periph: SPIx(x=1,2)
\param[in] i2s_mode: I2S operation mode
only one parameter can be selected which is shown as below:
\arg I2S_MODE_SLAVETX: I2S slave transmit mode
\arg I2S_MODE_SLAVERX: I2S slave receive mode
\arg I2S_MODE_MASTERTX: I2S master transmit mode
\arg I2S_MODE_MASTERRX: I2S master receive mode
\param[in] i2s_standard: I2S standard
only one parameter can be selected which is shown as below:
\arg I2S_STD_PHILIPS: I2S philips standard
\arg I2S_STD_MSB: I2S MSB standard
\arg I2S_STD_LSB: I2S LSB standard
\arg I2S_STD_PCMSHORT: I2S PCM short standard
\arg I2S_STD_PCMLONG: I2S PCM long standard
\param[in] i2s_ckpl: I2S idle state clock polarity
only one parameter can be selected which is shown as below:
\arg I2S_CKPL_LOW: I2S clock polarity low level
\arg I2S_CKPL_HIGH: I2S clock polarity high level
\param[out] none
\retval none
*/
void i2s_init(uint32_t spi_periph, uint32_t i2s_mode, uint32_t i2s_standard, uint32_t i2s_ckpl)
{
uint32_t reg= 0U;
reg = SPI_I2SCTL(spi_periph);
reg &= I2S_INIT_MASK;
/* enable I2S mode */
reg |= (uint32_t)SPI_I2SCTL_I2SSEL;
/* select I2S mode */
reg |= (uint32_t)i2s_mode;
/* select I2S standard */
reg |= (uint32_t)i2s_standard;
/* select I2S polarity */
reg |= (uint32_t)i2s_ckpl;
/* write to SPI_I2SCTL register */
SPI_I2SCTL(spi_periph) = (uint32_t)reg;
}
/*!
\brief configure I2S prescaler
\param[in] spi_periph: SPIx(x=1,2)
\param[in] i2s_audiosample: I2S audio sample rate
only one parameter can be selected which is shown as below:
\arg I2S_AUDIOSAMPLE_8K: audio sample rate is 8KHz
\arg I2S_AUDIOSAMPLE_11K: audio sample rate is 11KHz
\arg I2S_AUDIOSAMPLE_16K: audio sample rate is 16KHz
\arg I2S_AUDIOSAMPLE_22K: audio sample rate is 22KHz
\arg I2S_AUDIOSAMPLE_32K: audio sample rate is 32KHz
\arg I2S_AUDIOSAMPLE_44K: audio sample rate is 44KHz
\arg I2S_AUDIOSAMPLE_48K: audio sample rate is 48KHz
\arg I2S_AUDIOSAMPLE_96K: audio sample rate is 96KHz
\arg I2S_AUDIOSAMPLE_192K: audio sample rate is 192KHz
\param[in] i2s_frameformat: I2S data length and channel length
only one parameter can be selected which is shown as below:
\arg I2S_FRAMEFORMAT_DT16B_CH16B: I2S data length is 16 bit and channel length is 16 bit
\arg I2S_FRAMEFORMAT_DT16B_CH32B: I2S data length is 16 bit and channel length is 32 bit
\arg I2S_FRAMEFORMAT_DT24B_CH32B: I2S data length is 24 bit and channel length is 32 bit
\arg I2S_FRAMEFORMAT_DT32B_CH32B: I2S data length is 32 bit and channel length is 32 bit
\param[in] i2s_mckout: I2S master clock output
only one parameter can be selected which is shown as below:
\arg I2S_MCKOUT_ENABLE: I2S master clock output enable
\arg I2S_MCKOUT_DISABLE: I2S master clock output disable
\param[out] none
\retval none
*/
void i2s_psc_config(uint32_t spi_periph, uint32_t i2s_audiosample, uint32_t i2s_frameformat, uint32_t i2s_mckout)
{
uint32_t i2sdiv = 2U, i2sof = 0U;
uint32_t clks = 0U;
uint32_t i2sclock = 0U;
#ifdef GD32E50X_CL
uint32_t pll2mf_4 = 0U;
#endif /* GD32E50X_CL */
/* deinit SPI_I2SPSC register */
SPI_I2SPSC(spi_periph) = SPI_I2SPSC_DEFAULT_VALUE;
#ifdef GD32E50X_CL
/* get the I2S clock source */
if(((uint32_t)spi_periph) == SPI1){
/* I2S1 clock source selection */
clks = I2S1_CLOCK_SEL;
}else{
/* I2S2 clock source selection */
clks = I2S2_CLOCK_SEL;
}
if(0U != (RCU_CFG1 & clks)){
/* get RCU PLL2 clock multiplication factor */
clks = (uint32_t)((RCU_CFG1 & I2S_CLOCK_MUL_MASK) >> 12U);
pll2mf_4 = RCU_CFG1 & RCU_CFG1_PLL2MF_4;
if( 0U == pll2mf_4){
if((clks > 5U) && (clks < 15U)){
/* multiplier is between 8 and 16 */
clks += 2U;
}else{
if(15U == clks){
/* multiplier is 20 */
clks = 20U;
}
}
}else{
if(clks < 15U){
/* multiplier is between 18 and 32 */
clks += 18U;
}else{
if(15U == clks){
/* multiplier is 40 */
clks = 40U;
}
}
}
/* get the PREDV1 value */
i2sclock = (uint32_t)(((RCU_CFG1 & I2S_CLOCK_DIV_MASK) >> 4U) + 1U);
/* calculate i2sclock based on PLL2 and PREDV1 */
i2sclock = (uint32_t)((HXTAL_VALUE / i2sclock) * clks * 2U);
}else{
/* get system clock */
i2sclock = rcu_clock_freq_get(CK_SYS);
}
#else
/* get system clock */
i2sclock = rcu_clock_freq_get(CK_SYS);
#endif /* GD32E50X_CL */
/* config the prescaler depending on the mclk output state, the frame format and audio sample rate */
if(I2S_MCKOUT_ENABLE == i2s_mckout){
clks = (uint32_t)(((i2sclock / 256U) * 10U) / i2s_audiosample);
}else{
if(I2S_FRAMEFORMAT_DT16B_CH16B == i2s_frameformat){
clks = (uint32_t)(((i2sclock / 32U) *10U ) / i2s_audiosample);
}else{
clks = (uint32_t)(((i2sclock / 64U) *10U ) / i2s_audiosample);
}
}
/* remove the floating point */
clks = (clks + 5U) / 10U;
i2sof = (clks & 0x00000001U);
i2sdiv = ((clks - i2sof) / 2U);
i2sof = (i2sof << 8U);
/* set the default values */
if((i2sdiv < 2U) || (i2sdiv > 255U)){
i2sdiv = 2U;
i2sof = 0U;
}
/* configure SPI_I2SPSC */
SPI_I2SPSC(spi_periph) = (uint32_t)(i2sdiv | i2sof | i2s_mckout);
/* clear SPI_I2SCTL_DTLEN and SPI_I2SCTL_CHLEN bits */
SPI_I2SCTL(spi_periph) &= (uint32_t)(~(SPI_I2SCTL_DTLEN | SPI_I2SCTL_CHLEN));
/* configure data frame format */
SPI_I2SCTL(spi_periph) |= (uint32_t)i2s_frameformat;
}
/*!
\brief enable I2S
\param[in] spi_periph: SPIx(x=1,2)
\param[out] none
\retval none
*/
void i2s_enable(uint32_t spi_periph)
{
SPI_I2SCTL(spi_periph) |= (uint32_t)SPI_I2SCTL_I2SEN;
}
/*!
\brief disable I2S
\param[in] spi_periph: SPIx(x=1,2)
\param[out] none
\retval none
*/
void i2s_disable(uint32_t spi_periph)
{
SPI_I2SCTL(spi_periph) &= (uint32_t)(~SPI_I2SCTL_I2SEN);
}
/*!
\brief enable SPI NSS output
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nss_output_enable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_NSSDRV;
}
/*!
\brief disable SPI NSS output
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nss_output_disable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_NSSDRV);
}
/*!
\brief SPI NSS pin high level in software mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nss_internal_high(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_SWNSS;
}
/*!
\brief SPI NSS pin low level in software mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nss_internal_low(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_SWNSS);
}
/*!
\brief enable SPI DMA send or receive
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] dma: SPI DMA mode
only one parameter can be selected which is shown as below:
\arg SPI_DMA_TRANSMIT: SPI transmit data use DMA
\arg SPI_DMA_RECEIVE: SPI receive data use DMA
\param[out] none
\retval none
*/
void spi_dma_enable(uint32_t spi_periph, uint8_t dma)
{
if(SPI_DMA_TRANSMIT == dma){
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_DMATEN;
}else{
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_DMAREN;
}
}
/*!
\brief disable SPI DMA send or receive
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] dma: SPI DMA mode
only one parameter can be selected which is shown as below:
\arg SPI_DMA_TRANSMIT: SPI transmit data use DMA
\arg SPI_DMA_RECEIVE: SPI receive data use DMA
\param[out] none
\retval none
*/
void spi_dma_disable(uint32_t spi_periph, uint8_t dma)
{
if(SPI_DMA_TRANSMIT == dma){
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_DMATEN);
}else{
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_DMAREN);
}
}
/*!
\brief configure SPI/I2S data frame format
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] frame_format: SPI frame size
only one parameter can be selected which is shown as below:
\arg SPI_FRAMESIZE_16BIT: SPI frame size is 16 bits
\arg SPI_FRAMESIZE_8BIT: SPI frame size is 8 bits
\param[out] none
\retval none
*/
void spi_i2s_data_frame_format_config(uint32_t spi_periph, uint16_t frame_format)
{
/* clear SPI_CTL0_FF16 bit */
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_FF16);
/* confige SPI_CTL0_FF16 bit */
SPI_CTL0(spi_periph) |= (uint32_t)frame_format;
}
/*!
\brief SPI transmit data
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] data: 16-bit data
\param[out] none
\retval none
*/
void spi_i2s_data_transmit(uint32_t spi_periph, uint16_t data)
{
SPI_DATA(spi_periph) = (uint32_t)data;
}
/*!
\brief SPI receive data
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval 16-bit data
*/
uint16_t spi_i2s_data_receive(uint32_t spi_periph)
{
return ((uint16_t)SPI_DATA(spi_periph));
}
/*!
\brief configure SPI bidirectional transfer direction
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] transfer_direction: SPI transfer direction
only one parameter can be selected which is shown as below:
\arg SPI_BIDIRECTIONAL_TRANSMIT: SPI work in transmit-only mode
\arg SPI_BIDIRECTIONAL_RECEIVE: SPI work in receive-only mode
\retval none
*/
void spi_bidirectional_transfer_config(uint32_t spi_periph, uint32_t transfer_direction)
{
if(SPI_BIDIRECTIONAL_TRANSMIT == transfer_direction){
/* set the transmit only mode */
SPI_CTL0(spi_periph) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
}else{
/* set the receive only mode */
SPI_CTL0(spi_periph) &= SPI_BIDIRECTIONAL_RECEIVE;
}
}
/*!
\brief clear SPI/I2S format error flag status
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] flag: SPI/I2S frame format error flag
\arg SPI_FLAG_FERR: only for SPI work in TI mode
\arg I2S_FLAG_FERR: for I2S
\param[out] none
\retval none
*/
void spi_i2s_format_error_clear(uint32_t spi_periph, uint32_t flag)
{
SPI_STAT(spi_periph) = (uint32_t)(~flag);
}
/*!
\brief set SPI CRC polynomial
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] crc_poly: CRC polynomial value
\param[out] none
\retval none
*/
void spi_crc_polynomial_set(uint32_t spi_periph,uint16_t crc_poly)
{
/* enable SPI CRC */
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCEN;
/* set SPI CRC polynomial */
SPI_CRCPOLY(spi_periph) = (uint32_t)crc_poly;
}
/*!
\brief get SPI CRC polynomial
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval 16-bit CRC polynomial
*/
uint16_t spi_crc_polynomial_get(uint32_t spi_periph)
{
return ((uint16_t)SPI_CRCPOLY(spi_periph));
}
/*!
\brief turn on CRC function
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_crc_on(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCEN;
}
/*!
\brief turn off CRC function
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_crc_off(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_CRCEN);
}
/*!
\brief SPI next data is CRC value
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_crc_next(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCNT;
}
/*!
\brief get SPI CRC send value or receive value
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] crc: SPI crc value
only one parameter can be selected which is shown as below:
\arg SPI_CRC_TX: get transmit crc value
\arg SPI_CRC_RX: get receive crc value
\param[out] none
\retval 16-bit CRC value
*/
uint16_t spi_crc_get(uint32_t spi_periph,uint8_t crc)
{
if(SPI_CRC_TX == crc){
return ((uint16_t)(SPI_TCRC(spi_periph)));
}else{
return ((uint16_t)(SPI_RCRC(spi_periph)));
}
}
/*!
\brief clear SPI CRC error flag status
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_crc_error_clear(uint32_t spi_periph)
{
SPI_STAT(spi_periph) &= (uint32_t)(~SPI_FLAG_CRCERR);
}
/*!
\brief enable SPI TI mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_ti_mode_enable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_TMOD;
}
/*!
\brief disable SPI TI mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_ti_mode_disable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_TMOD);
}
/*!
\brief enable SPI NSS pulse mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nssp_mode_enable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_NSSP;
}
/*!
\brief disable SPI NSS pulse mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nssp_mode_disable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_NSSP);
}
/*!
\brief configure i2s full duplex mode
\param[in] i2s_add_periph: I2Sx_ADD(x=1,2)
\param[in] i2s_mode:
\arg I2S_MODE_SLAVETX : I2S slave transmit mode
\arg I2S_MODE_SLAVERX : I2S slave receive mode
\arg I2S_MODE_MASTERTX : I2S master transmit mode
\arg I2S_MODE_MASTERRX : I2S master receive mode
\param[in] i2s_standard:
\arg I2S_STD_PHILIPS : I2S philips standard
\arg I2S_STD_MSB : I2S MSB standard
\arg I2S_STD_LSB : I2S LSB standard
\arg I2S_STD_PCMSHORT : I2S PCM short standard
\arg I2S_STD_PCMLONG : I2S PCM long standard
\param[in] i2s_ckpl:
\arg I2S_CKPL_LOW : I2S clock polarity low level
\arg I2S_CKPL_HIGH : I2S clock polarity high level
\param[in] i2s_frameformat:
\arg I2S_FRAMEFORMAT_DT16B_CH16B: I2S data length is 16 bit and channel length is 16 bit
\arg I2S_FRAMEFORMAT_DT16B_CH32B: I2S data length is 16 bit and channel length is 32 bit
\arg I2S_FRAMEFORMAT_DT24B_CH32B: I2S data length is 24 bit and channel length is 32 bit
\arg I2S_FRAMEFORMAT_DT32B_CH32B: I2S data length is 32 bit and channel length is 32 bit
\param[out] none
\retval none
*/
void i2s_full_duplex_mode_config(uint32_t i2s_add_periph, uint32_t i2s_mode, uint32_t i2s_standard,
uint32_t i2s_ckpl, uint32_t i2s_frameformat)
{
uint32_t reg = 0U, tmp = 0U;
reg = I2S_ADD_I2SCTL(i2s_add_periph);
reg &= I2S_FULL_DUPLEX_MASK;
/* get the mode of the extra I2S module I2Sx_ADD */
if((I2S_MODE_MASTERTX == i2s_mode) || (I2S_MODE_SLAVETX == i2s_mode)){
tmp = I2S_MODE_SLAVERX;
}else{
tmp = I2S_MODE_SLAVETX;
}
/* enable I2S mode */
reg |= (uint32_t)SPI_I2SCTL_I2SSEL;
/* select I2S mode */
reg |= (uint32_t)tmp;
/* select I2S standard */
reg |= (uint32_t)i2s_standard;
/* select I2S polarity */
reg |= (uint32_t)i2s_ckpl;
/* configure data frame format */
reg |= (uint32_t)i2s_frameformat;
/* write to SPI_I2SCTL register */
I2S_ADD_I2SCTL(i2s_add_periph) = (uint32_t)reg;
}
/*!
\brief enable SPI quad wire mode
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_enable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_QMOD;
}
/*!
\brief disable SPI quad wire mode
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_disable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_QMOD);
}
/*!
\brief enable SPI quad wire mode write
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_write_enable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_QRD);
}
/*!
\brief enable SPI quad wire mode read
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_read_enable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_QRD;
}
/*!
\brief enable SPI quad wire mode SPI_IO2 and SPI_IO3 pin output
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_io23_output_enable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_IO23_DRV;
}
/*!
\brief disable SPI quad wire mode SPI_IO2 and SPI_IO3 pin output
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_io23_output_disable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_IO23_DRV);
}
/*!
\brief enable SPI and I2S interrupt
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] interrupt: SPI/I2S interrupt
only one parameter can be selected which is shown as below:
\arg SPI_I2S_INT_TBE: transmit buffer empty interrupt
\arg SPI_I2S_INT_RBNE: receive buffer not empty interrupt
\arg SPI_I2S_INT_ERR: CRC error,configuration error,reception overrun error,
transmission underrun error and format error interrupt
\param[out] none
\retval none
*/
void spi_i2s_interrupt_enable(uint32_t spi_periph, uint8_t interrupt)
{
SPI_CTL1(spi_periph) |= (uint32_t)interrupt;
}
/*!
\brief disable SPI and I2S interrupt
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] interrupt: SPI/I2S interrupt
only one parameter can be selected which is shown as below:
\arg SPI_I2S_INT_TBE: transmit buffer empty interrupt
\arg SPI_I2S_INT_RBNE: receive buffer not empty interrupt
\arg SPI_I2S_INT_ERR: CRC error,configuration error,reception overrun error,
transmission underrun error and format error interrupt
\param[out] none
\retval none
*/
void spi_i2s_interrupt_disable(uint32_t spi_periph, uint8_t interrupt)
{
SPI_CTL1(spi_periph) &= ~(uint32_t)interrupt;
}
/*!
\brief get SPI and I2S interrupt flag status
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] interrupt: SPI/I2S interrupt flag status
only one parameter can be selected which is shown as below:
\arg SPI_I2S_INT_FLAG_TBE: transmit buffer empty interrupt flag
\arg SPI_I2S_INT_FLAG_RBNE: receive buffer not empty interrupt flag
\arg SPI_I2S_INT_FLAG_RXORERR: overrun interrupt flag
\arg SPI_INT_FLAG_CONFERR: config error interrupt flag
\arg SPI_INT_FLAG_CRCERR: CRC error interrupt flag
\arg I2S_INT_FLAG_TXURERR: underrun error interrupt flag
\arg SPI_I2S_INT_FLAG_FERR: format error interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus spi_i2s_interrupt_flag_get(uint32_t spi_periph, uint8_t interrupt)
{
uint32_t reg1 = SPI_STAT(spi_periph);
uint32_t reg2 = SPI_CTL1(spi_periph);
switch(interrupt){
/* SPI/I2S transmit buffer empty interrupt */
case SPI_I2S_INT_FLAG_TBE:
reg1 = reg1 & SPI_STAT_TBE;
reg2 = reg2 & SPI_CTL1_TBEIE;
break;
/* SPI/I2S receive buffer not empty interrupt */
case SPI_I2S_INT_FLAG_RBNE:
reg1 = reg1 & SPI_STAT_RBNE;
reg2 = reg2 & SPI_CTL1_RBNEIE;
break;
/* SPI/I2S overrun interrupt */
case SPI_I2S_INT_FLAG_RXORERR:
reg1 = reg1 & SPI_STAT_RXORERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
/* SPI config error interrupt */
case SPI_INT_FLAG_CONFERR:
reg1 = reg1 & SPI_STAT_CONFERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
/* SPI CRC error interrupt */
case SPI_INT_FLAG_CRCERR:
reg1 = reg1 & SPI_STAT_CRCERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
/* I2S underrun error interrupt */
case I2S_INT_FLAG_TXURERR:
reg1 = reg1 & SPI_STAT_TXURERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
/* SPI/I2S format error interrupt */
case SPI_I2S_INT_FLAG_FERR:
reg1 = reg1 & SPI_STAT_FERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
default :
break;
}
/*get SPI/I2S interrupt flag status */
if(reg1 && reg2){
return SET;
}else{
return RESET;
}
}
/*!
\brief get SPI and I2S flag status
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] flag: SPI/I2S flag status
only one parameter can be selected which is shown as below:
\arg SPI_FLAG_TBE: transmit buffer empty flag
\arg SPI_FLAG_RBNE: receive buffer not empty flag
\arg SPI_FLAG_TRANS: transmit on-going flag
\arg SPI_FLAG_RXORERR: receive overrun error flag
\arg SPI_FLAG_CONFERR: mode config error flag
\arg SPI_FLAG_CRCERR: CRC error flag
\arg SPI_FLAG_FERR: format error flag
\arg I2S_FLAG_TBE: transmit buffer empty flag
\arg I2S_FLAG_RBNE: receive buffer not empty flag
\arg I2S_FLAG_TRANS: transmit on-going flag
\arg I2S_FLAG_RXORERR: overrun error flag
\arg I2S_FLAG_TXURERR: underrun error flag
\arg I2S_FLAG_CH: channel side flag
\arg I2S_FLAG_FERR: format error flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus spi_i2s_flag_get(uint32_t spi_periph, uint32_t flag)
{
if(SPI_STAT(spi_periph) & flag){
return SET;
}else{
return RESET;
}
}
@@ -0,0 +1,895 @@
/*!
\file gd32e50x_spi.c
\brief SPI 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_spi.h"
/* SPI/I2S parameter initialization mask */
#define SPI_INIT_MASK ((uint32_t)0x00003040U) /*!< SPI parameter initialization mask */
#define I2S_INIT_MASK ((uint32_t)0x0000F047U) /*!< I2S parameter initialization mask */
#define I2S_FULL_DUPLEX_MASK ((uint32_t)0x00000480U) /*!< I2S full duples mode configure parameter initialization mask */
/* default value */
#define SPI_I2SPSC_DEFAULT_VALUE ((uint32_t)0x00000002U) /*!< default value of SPI_I2SPSC register */
/* I2S clock source selection, multiplication and division mask */
#define I2S1_CLOCK_SEL ((uint32_t)0x00020000U) /*!< I2S1 clock source selection */
#define I2S2_CLOCK_SEL ((uint32_t)0x00040000U) /*!< I2S2 clock source selection */
#define I2S_CLOCK_MUL_MASK ((uint32_t)0x0000F000U) /*!< I2S clock multiplication mask */
#define I2S_CLOCK_DIV_MASK ((uint32_t)0x000000F0U) /*!< I2S clock division mask */
/*!
\brief reset SPI and I2S
\param[in] spi_periph: SPIx(x=0,1,2),include I2S1_ADD and I2S2_ADD
\param[out] none
\retval none
*/
void spi_i2s_deinit(uint32_t spi_periph)
{
switch(spi_periph){
case SPI0:
/* reset SPI0 */
rcu_periph_reset_enable(RCU_SPI0RST);
rcu_periph_reset_disable(RCU_SPI0RST);
break;
case SPI1:
/* reset SPI1 , I2S1 and I2S1_ADD */
rcu_periph_reset_enable(RCU_SPI1RST);
rcu_periph_reset_disable(RCU_SPI1RST);
break;
case SPI2:
/* reset SPI2 , I2S2 and I2S2_ADD */
rcu_periph_reset_enable(RCU_SPI2RST);
rcu_periph_reset_disable(RCU_SPI2RST);
break;
default :
break;
}
}
/*!
\brief initialize the parameters of SPI struct with default values
\param[in] none
\param[out] spi_parameter_struct: the initialized struct spi_parameter_struct pointer
\retval none
*/
void spi_struct_para_init(spi_parameter_struct *spi_struct)
{
/* configure the structure with default value */
spi_struct->device_mode = SPI_SLAVE;
spi_struct->trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_struct->frame_size = SPI_FRAMESIZE_8BIT;
spi_struct->nss = SPI_NSS_HARD;
spi_struct->clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_struct->prescale = SPI_PSC_2;
spi_struct->endian = SPI_ENDIAN_MSB;
}
/*!
\brief initialize SPI parameter
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] spi_struct: SPI parameter initialization stuct members of the structure
and the member values are shown as below:
device_mode: SPI_MASTER, SPI_SLAVE
trans_mode: SPI_TRANSMODE_FULLDUPLEX, SPI_TRANSMODE_RECEIVEONLY,
SPI_TRANSMODE_BDRECEIVE, SPI_TRANSMODE_BDTRANSMIT
frame_size: SPI_FRAMESIZE_16BIT, SPI_FRAMESIZE_8BIT
nss: SPI_NSS_SOFT, SPI_NSS_HARD
endian: SPI_ENDIAN_MSB, SPI_ENDIAN_LSB
clock_polarity_phase: SPI_CK_PL_LOW_PH_1EDGE, SPI_CK_PL_HIGH_PH_1EDGE
SPI_CK_PL_LOW_PH_2EDGE, SPI_CK_PL_HIGH_PH_2EDGE
prescale: SPI_PSC_n (n=2,4,8,16,32,64,128,256)
\param[out] none
\retval none
*/
void spi_init(uint32_t spi_periph, spi_parameter_struct* spi_struct)
{
uint32_t reg = 0U;
reg = SPI_CTL0(spi_periph);
reg &= SPI_INIT_MASK;
/* select SPI as master or slave */
reg |= spi_struct->device_mode;
/* select SPI transfer mode */
reg |= spi_struct->trans_mode;
/* select SPI frame size */
reg |= spi_struct->frame_size;
/* select SPI NSS use hardware or software */
reg |= spi_struct->nss;
/* select SPI LSB or MSB */
reg |= spi_struct->endian;
/* select SPI polarity and phase */
reg |= spi_struct->clock_polarity_phase;
/* select SPI prescale to adjust transmit speed */
reg |= spi_struct->prescale;
/* write to SPI_CTL0 register */
SPI_CTL0(spi_periph) = (uint32_t)reg;
SPI_I2SCTL(spi_periph) &= (uint32_t)(~SPI_I2SCTL_I2SSEL);
}
/*!
\brief enable SPI
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_enable(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_SPIEN;
}
/*!
\brief disable SPI
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_disable(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_SPIEN);
}
/*!
\brief initialize I2S parameter
\param[in] spi_periph: SPIx(x=1,2)
\param[in] i2s_mode: I2S operation mode
only one parameter can be selected which is shown as below:
\arg I2S_MODE_SLAVETX: I2S slave transmit mode
\arg I2S_MODE_SLAVERX: I2S slave receive mode
\arg I2S_MODE_MASTERTX: I2S master transmit mode
\arg I2S_MODE_MASTERRX: I2S master receive mode
\param[in] i2s_standard: I2S standard
only one parameter can be selected which is shown as below:
\arg I2S_STD_PHILIPS: I2S philips standard
\arg I2S_STD_MSB: I2S MSB standard
\arg I2S_STD_LSB: I2S LSB standard
\arg I2S_STD_PCMSHORT: I2S PCM short standard
\arg I2S_STD_PCMLONG: I2S PCM long standard
\param[in] i2s_ckpl: I2S idle state clock polarity
only one parameter can be selected which is shown as below:
\arg I2S_CKPL_LOW: I2S clock polarity low level
\arg I2S_CKPL_HIGH: I2S clock polarity high level
\param[out] none
\retval none
*/
void i2s_init(uint32_t spi_periph, uint32_t i2s_mode, uint32_t i2s_standard, uint32_t i2s_ckpl)
{
uint32_t reg= 0U;
reg = SPI_I2SCTL(spi_periph);
reg &= I2S_INIT_MASK;
/* enable I2S mode */
reg |= (uint32_t)SPI_I2SCTL_I2SSEL;
/* select I2S mode */
reg |= (uint32_t)i2s_mode;
/* select I2S standard */
reg |= (uint32_t)i2s_standard;
/* select I2S polarity */
reg |= (uint32_t)i2s_ckpl;
/* write to SPI_I2SCTL register */
SPI_I2SCTL(spi_periph) = (uint32_t)reg;
}
/*!
\brief configure I2S prescaler
\param[in] spi_periph: SPIx(x=1,2)
\param[in] i2s_audiosample: I2S audio sample rate
only one parameter can be selected which is shown as below:
\arg I2S_AUDIOSAMPLE_8K: audio sample rate is 8KHz
\arg I2S_AUDIOSAMPLE_11K: audio sample rate is 11KHz
\arg I2S_AUDIOSAMPLE_16K: audio sample rate is 16KHz
\arg I2S_AUDIOSAMPLE_22K: audio sample rate is 22KHz
\arg I2S_AUDIOSAMPLE_32K: audio sample rate is 32KHz
\arg I2S_AUDIOSAMPLE_44K: audio sample rate is 44KHz
\arg I2S_AUDIOSAMPLE_48K: audio sample rate is 48KHz
\arg I2S_AUDIOSAMPLE_96K: audio sample rate is 96KHz
\arg I2S_AUDIOSAMPLE_192K: audio sample rate is 192KHz
\param[in] i2s_frameformat: I2S data length and channel length
only one parameter can be selected which is shown as below:
\arg I2S_FRAMEFORMAT_DT16B_CH16B: I2S data length is 16 bit and channel length is 16 bit
\arg I2S_FRAMEFORMAT_DT16B_CH32B: I2S data length is 16 bit and channel length is 32 bit
\arg I2S_FRAMEFORMAT_DT24B_CH32B: I2S data length is 24 bit and channel length is 32 bit
\arg I2S_FRAMEFORMAT_DT32B_CH32B: I2S data length is 32 bit and channel length is 32 bit
\param[in] i2s_mckout: I2S master clock output
only one parameter can be selected which is shown as below:
\arg I2S_MCKOUT_ENABLE: I2S master clock output enable
\arg I2S_MCKOUT_DISABLE: I2S master clock output disable
\param[out] none
\retval none
*/
void i2s_psc_config(uint32_t spi_periph, uint32_t i2s_audiosample, uint32_t i2s_frameformat, uint32_t i2s_mckout)
{
uint32_t i2sdiv = 2U, i2sof = 0U;
uint32_t clks = 0U;
uint32_t i2sclock = 0U;
#ifdef GD32E50X_CL
uint32_t pll2mf_4 = 0U;
#endif /* GD32E50X_CL */
/* deinit SPI_I2SPSC register */
SPI_I2SPSC(spi_periph) = SPI_I2SPSC_DEFAULT_VALUE;
#ifdef GD32E50X_CL
/* get the I2S clock source */
if(((uint32_t)spi_periph) == SPI1){
/* I2S1 clock source selection */
clks = I2S1_CLOCK_SEL;
}else{
/* I2S2 clock source selection */
clks = I2S2_CLOCK_SEL;
}
if(0U != (RCU_CFG1 & clks)){
/* get RCU PLL2 clock multiplication factor */
clks = (uint32_t)((RCU_CFG1 & I2S_CLOCK_MUL_MASK) >> 12U);
pll2mf_4 = RCU_CFG1 & RCU_CFG1_PLL2MF_4;
if( 0U == pll2mf_4){
if((clks > 5U) && (clks < 15U)){
/* multiplier is between 8 and 16 */
clks += 2U;
}else{
if(15U == clks){
/* multiplier is 20 */
clks = 20U;
}
}
}else{
if(clks < 15U){
/* multiplier is between 18 and 32 */
clks += 18U;
}else{
if(15U == clks){
/* multiplier is 40 */
clks = 40U;
}
}
}
/* get the PREDV1 value */
i2sclock = (uint32_t)(((RCU_CFG1 & I2S_CLOCK_DIV_MASK) >> 4U) + 1U);
/* calculate i2sclock based on PLL2 and PREDV1 */
i2sclock = (uint32_t)((HXTAL_VALUE / i2sclock) * clks * 2U);
}else{
/* get system clock */
i2sclock = rcu_clock_freq_get(CK_SYS);
}
#else
/* get system clock */
i2sclock = rcu_clock_freq_get(CK_SYS);
#endif /* GD32E50X_CL */
/* config the prescaler depending on the mclk output state, the frame format and audio sample rate */
if(I2S_MCKOUT_ENABLE == i2s_mckout){
clks = (uint32_t)(((i2sclock / 256U) * 10U) / i2s_audiosample);
}else{
if(I2S_FRAMEFORMAT_DT16B_CH16B == i2s_frameformat){
clks = (uint32_t)(((i2sclock / 32U) *10U ) / i2s_audiosample);
}else{
clks = (uint32_t)(((i2sclock / 64U) *10U ) / i2s_audiosample);
}
}
/* remove the floating point */
clks = (clks + 5U) / 10U;
i2sof = (clks & 0x00000001U);
i2sdiv = ((clks - i2sof) / 2U);
i2sof = (i2sof << 8U);
/* set the default values */
if((i2sdiv < 2U) || (i2sdiv > 255U)){
i2sdiv = 2U;
i2sof = 0U;
}
/* configure SPI_I2SPSC */
SPI_I2SPSC(spi_periph) = (uint32_t)(i2sdiv | i2sof | i2s_mckout);
/* clear SPI_I2SCTL_DTLEN and SPI_I2SCTL_CHLEN bits */
SPI_I2SCTL(spi_periph) &= (uint32_t)(~(SPI_I2SCTL_DTLEN | SPI_I2SCTL_CHLEN));
/* configure data frame format */
SPI_I2SCTL(spi_periph) |= (uint32_t)i2s_frameformat;
}
/*!
\brief enable I2S
\param[in] spi_periph: SPIx(x=1,2)
\param[out] none
\retval none
*/
void i2s_enable(uint32_t spi_periph)
{
SPI_I2SCTL(spi_periph) |= (uint32_t)SPI_I2SCTL_I2SEN;
}
/*!
\brief disable I2S
\param[in] spi_periph: SPIx(x=1,2)
\param[out] none
\retval none
*/
void i2s_disable(uint32_t spi_periph)
{
SPI_I2SCTL(spi_periph) &= (uint32_t)(~SPI_I2SCTL_I2SEN);
}
/*!
\brief enable SPI NSS output
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nss_output_enable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_NSSDRV;
}
/*!
\brief disable SPI NSS output
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nss_output_disable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_NSSDRV);
}
/*!
\brief SPI NSS pin high level in software mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nss_internal_high(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_SWNSS;
}
/*!
\brief SPI NSS pin low level in software mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nss_internal_low(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_SWNSS);
}
/*!
\brief enable SPI DMA send or receive
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] dma: SPI DMA mode
only one parameter can be selected which is shown as below:
\arg SPI_DMA_TRANSMIT: SPI transmit data use DMA
\arg SPI_DMA_RECEIVE: SPI receive data use DMA
\param[out] none
\retval none
*/
void spi_dma_enable(uint32_t spi_periph, uint8_t dma)
{
if(SPI_DMA_TRANSMIT == dma){
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_DMATEN;
}else{
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_DMAREN;
}
}
/*!
\brief disable SPI DMA send or receive
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] dma: SPI DMA mode
only one parameter can be selected which is shown as below:
\arg SPI_DMA_TRANSMIT: SPI transmit data use DMA
\arg SPI_DMA_RECEIVE: SPI receive data use DMA
\param[out] none
\retval none
*/
void spi_dma_disable(uint32_t spi_periph, uint8_t dma)
{
if(SPI_DMA_TRANSMIT == dma){
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_DMATEN);
}else{
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_DMAREN);
}
}
/*!
\brief configure SPI/I2S data frame format
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] frame_format: SPI frame size
only one parameter can be selected which is shown as below:
\arg SPI_FRAMESIZE_16BIT: SPI frame size is 16 bits
\arg SPI_FRAMESIZE_8BIT: SPI frame size is 8 bits
\param[out] none
\retval none
*/
void spi_i2s_data_frame_format_config(uint32_t spi_periph, uint16_t frame_format)
{
/* clear SPI_CTL0_FF16 bit */
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_FF16);
/* confige SPI_CTL0_FF16 bit */
SPI_CTL0(spi_periph) |= (uint32_t)frame_format;
}
/*!
\brief SPI transmit data
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] data: 16-bit data
\param[out] none
\retval none
*/
void spi_i2s_data_transmit(uint32_t spi_periph, uint16_t data)
{
SPI_DATA(spi_periph) = (uint32_t)data;
}
/*!
\brief SPI receive data
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval 16-bit data
*/
uint16_t spi_i2s_data_receive(uint32_t spi_periph)
{
return ((uint16_t)SPI_DATA(spi_periph));
}
/*!
\brief configure SPI bidirectional transfer direction
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] transfer_direction: SPI transfer direction
only one parameter can be selected which is shown as below:
\arg SPI_BIDIRECTIONAL_TRANSMIT: SPI work in transmit-only mode
\arg SPI_BIDIRECTIONAL_RECEIVE: SPI work in receive-only mode
\retval none
*/
void spi_bidirectional_transfer_config(uint32_t spi_periph, uint32_t transfer_direction)
{
if(SPI_BIDIRECTIONAL_TRANSMIT == transfer_direction){
/* set the transmit only mode */
SPI_CTL0(spi_periph) |= (uint32_t)SPI_BIDIRECTIONAL_TRANSMIT;
}else{
/* set the receive only mode */
SPI_CTL0(spi_periph) &= SPI_BIDIRECTIONAL_RECEIVE;
}
}
/*!
\brief clear SPI/I2S format error flag status
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] flag: SPI/I2S frame format error flag
\arg SPI_FLAG_FERR: only for SPI work in TI mode
\arg I2S_FLAG_FERR: for I2S
\param[out] none
\retval none
*/
void spi_i2s_format_error_clear(uint32_t spi_periph, uint32_t flag)
{
SPI_STAT(spi_periph) = (uint32_t)(~flag);
}
/*!
\brief set SPI CRC polynomial
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] crc_poly: CRC polynomial value
\param[out] none
\retval none
*/
void spi_crc_polynomial_set(uint32_t spi_periph,uint16_t crc_poly)
{
/* enable SPI CRC */
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCEN;
/* set SPI CRC polynomial */
SPI_CRCPOLY(spi_periph) = (uint32_t)crc_poly;
}
/*!
\brief get SPI CRC polynomial
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval 16-bit CRC polynomial
*/
uint16_t spi_crc_polynomial_get(uint32_t spi_periph)
{
return ((uint16_t)SPI_CRCPOLY(spi_periph));
}
/*!
\brief turn on CRC function
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_crc_on(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCEN;
}
/*!
\brief turn off CRC function
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_crc_off(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) &= (uint32_t)(~SPI_CTL0_CRCEN);
}
/*!
\brief SPI next data is CRC value
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_crc_next(uint32_t spi_periph)
{
SPI_CTL0(spi_periph) |= (uint32_t)SPI_CTL0_CRCNT;
}
/*!
\brief get SPI CRC send value or receive value
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] crc: SPI crc value
only one parameter can be selected which is shown as below:
\arg SPI_CRC_TX: get transmit crc value
\arg SPI_CRC_RX: get receive crc value
\param[out] none
\retval 16-bit CRC value
*/
uint16_t spi_crc_get(uint32_t spi_periph,uint8_t crc)
{
if(SPI_CRC_TX == crc){
return ((uint16_t)(SPI_TCRC(spi_periph)));
}else{
return ((uint16_t)(SPI_RCRC(spi_periph)));
}
}
/*!
\brief clear SPI CRC error flag status
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_crc_error_clear(uint32_t spi_periph)
{
SPI_STAT(spi_periph) &= (uint32_t)(~SPI_FLAG_CRCERR);
}
/*!
\brief enable SPI TI mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_ti_mode_enable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_TMOD;
}
/*!
\brief disable SPI TI mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_ti_mode_disable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_TMOD);
}
/*!
\brief enable SPI NSS pulse mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nssp_mode_enable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) |= (uint32_t)SPI_CTL1_NSSP;
}
/*!
\brief disable SPI NSS pulse mode
\param[in] spi_periph: SPIx(x=0,1,2)
\param[out] none
\retval none
*/
void spi_nssp_mode_disable(uint32_t spi_periph)
{
SPI_CTL1(spi_periph) &= (uint32_t)(~SPI_CTL1_NSSP);
}
/*!
\brief configure i2s full duplex mode
\param[in] i2s_add_periph: I2Sx_ADD(x=1,2)
\param[in] i2s_mode:
\arg I2S_MODE_SLAVETX : I2S slave transmit mode
\arg I2S_MODE_SLAVERX : I2S slave receive mode
\arg I2S_MODE_MASTERTX : I2S master transmit mode
\arg I2S_MODE_MASTERRX : I2S master receive mode
\param[in] i2s_standard:
\arg I2S_STD_PHILIPS : I2S philips standard
\arg I2S_STD_MSB : I2S MSB standard
\arg I2S_STD_LSB : I2S LSB standard
\arg I2S_STD_PCMSHORT : I2S PCM short standard
\arg I2S_STD_PCMLONG : I2S PCM long standard
\param[in] i2s_ckpl:
\arg I2S_CKPL_LOW : I2S clock polarity low level
\arg I2S_CKPL_HIGH : I2S clock polarity high level
\param[in] i2s_frameformat:
\arg I2S_FRAMEFORMAT_DT16B_CH16B: I2S data length is 16 bit and channel length is 16 bit
\arg I2S_FRAMEFORMAT_DT16B_CH32B: I2S data length is 16 bit and channel length is 32 bit
\arg I2S_FRAMEFORMAT_DT24B_CH32B: I2S data length is 24 bit and channel length is 32 bit
\arg I2S_FRAMEFORMAT_DT32B_CH32B: I2S data length is 32 bit and channel length is 32 bit
\param[out] none
\retval none
*/
void i2s_full_duplex_mode_config(uint32_t i2s_add_periph, uint32_t i2s_mode, uint32_t i2s_standard,
uint32_t i2s_ckpl, uint32_t i2s_frameformat)
{
uint32_t reg = 0U, tmp = 0U;
reg = I2S_ADD_I2SCTL(i2s_add_periph);
reg &= I2S_FULL_DUPLEX_MASK;
/* get the mode of the extra I2S module I2Sx_ADD */
if((I2S_MODE_MASTERTX == i2s_mode) || (I2S_MODE_SLAVETX == i2s_mode)){
tmp = I2S_MODE_SLAVERX;
}else{
tmp = I2S_MODE_SLAVETX;
}
/* enable I2S mode */
reg |= (uint32_t)SPI_I2SCTL_I2SSEL;
/* select I2S mode */
reg |= (uint32_t)tmp;
/* select I2S standard */
reg |= (uint32_t)i2s_standard;
/* select I2S polarity */
reg |= (uint32_t)i2s_ckpl;
/* configure data frame format */
reg |= (uint32_t)i2s_frameformat;
/* write to SPI_I2SCTL register */
I2S_ADD_I2SCTL(i2s_add_periph) = (uint32_t)reg;
}
/*!
\brief enable SPI quad wire mode
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_enable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_QMOD;
}
/*!
\brief disable SPI quad wire mode
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_disable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_QMOD);
}
/*!
\brief enable SPI quad wire mode write
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_write_enable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_QRD);
}
/*!
\brief enable SPI quad wire mode read
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_read_enable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_QRD;
}
/*!
\brief enable SPI quad wire mode SPI_IO2 and SPI_IO3 pin output
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_io23_output_enable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) |= (uint32_t)SPI_QCTL_IO23_DRV;
}
/*!
\brief disable SPI quad wire mode SPI_IO2 and SPI_IO3 pin output
\param[in] spi_periph: SPIx(only x=0)
\param[out] none
\retval none
*/
void spi_quad_io23_output_disable(uint32_t spi_periph)
{
SPI_QCTL(spi_periph) &= (uint32_t)(~SPI_QCTL_IO23_DRV);
}
/*!
\brief enable SPI and I2S interrupt
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] interrupt: SPI/I2S interrupt
only one parameter can be selected which is shown as below:
\arg SPI_I2S_INT_TBE: transmit buffer empty interrupt
\arg SPI_I2S_INT_RBNE: receive buffer not empty interrupt
\arg SPI_I2S_INT_ERR: CRC error,configuration error,reception overrun error,
transmission underrun error and format error interrupt
\param[out] none
\retval none
*/
void spi_i2s_interrupt_enable(uint32_t spi_periph, uint8_t interrupt)
{
SPI_CTL1(spi_periph) |= (uint32_t)interrupt;
}
/*!
\brief disable SPI and I2S interrupt
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] interrupt: SPI/I2S interrupt
only one parameter can be selected which is shown as below:
\arg SPI_I2S_INT_TBE: transmit buffer empty interrupt
\arg SPI_I2S_INT_RBNE: receive buffer not empty interrupt
\arg SPI_I2S_INT_ERR: CRC error,configuration error,reception overrun error,
transmission underrun error and format error interrupt
\param[out] none
\retval none
*/
void spi_i2s_interrupt_disable(uint32_t spi_periph, uint8_t interrupt)
{
SPI_CTL1(spi_periph) &= ~(uint32_t)interrupt;
}
/*!
\brief get SPI and I2S interrupt flag status
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] interrupt: SPI/I2S interrupt flag status
only one parameter can be selected which is shown as below:
\arg SPI_I2S_INT_FLAG_TBE: transmit buffer empty interrupt flag
\arg SPI_I2S_INT_FLAG_RBNE: receive buffer not empty interrupt flag
\arg SPI_I2S_INT_FLAG_RXORERR: overrun interrupt flag
\arg SPI_INT_FLAG_CONFERR: config error interrupt flag
\arg SPI_INT_FLAG_CRCERR: CRC error interrupt flag
\arg I2S_INT_FLAG_TXURERR: underrun error interrupt flag
\arg SPI_I2S_INT_FLAG_FERR: format error interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus spi_i2s_interrupt_flag_get(uint32_t spi_periph, uint8_t interrupt)
{
uint32_t reg1 = SPI_STAT(spi_periph);
uint32_t reg2 = SPI_CTL1(spi_periph);
switch(interrupt){
/* SPI/I2S transmit buffer empty interrupt */
case SPI_I2S_INT_FLAG_TBE:
reg1 = reg1 & SPI_STAT_TBE;
reg2 = reg2 & SPI_CTL1_TBEIE;
break;
/* SPI/I2S receive buffer not empty interrupt */
case SPI_I2S_INT_FLAG_RBNE:
reg1 = reg1 & SPI_STAT_RBNE;
reg2 = reg2 & SPI_CTL1_RBNEIE;
break;
/* SPI/I2S overrun interrupt */
case SPI_I2S_INT_FLAG_RXORERR:
reg1 = reg1 & SPI_STAT_RXORERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
/* SPI config error interrupt */
case SPI_INT_FLAG_CONFERR:
reg1 = reg1 & SPI_STAT_CONFERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
/* SPI CRC error interrupt */
case SPI_INT_FLAG_CRCERR:
reg1 = reg1 & SPI_STAT_CRCERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
/* I2S underrun error interrupt */
case I2S_INT_FLAG_TXURERR:
reg1 = reg1 & SPI_STAT_TXURERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
/* SPI/I2S format error interrupt */
case SPI_I2S_INT_FLAG_FERR:
reg1 = reg1 & SPI_STAT_FERR;
reg2 = reg2 & SPI_CTL1_ERRIE;
break;
default :
break;
}
/*get SPI/I2S interrupt flag status */
if(reg1 && reg2){
return SET;
}else{
return RESET;
}
}
/*!
\brief get SPI and I2S flag status
\param[in] spi_periph: SPIx(x=0,1,2)
\param[in] flag: SPI/I2S flag status
only one parameter can be selected which is shown as below:
\arg SPI_FLAG_TBE: transmit buffer empty flag
\arg SPI_FLAG_RBNE: receive buffer not empty flag
\arg SPI_FLAG_TRANS: transmit on-going flag
\arg SPI_FLAG_RXORERR: receive overrun error flag
\arg SPI_FLAG_CONFERR: mode config error flag
\arg SPI_FLAG_CRCERR: CRC error flag
\arg SPI_FLAG_FERR: format error flag
\arg I2S_FLAG_TBE: transmit buffer empty flag
\arg I2S_FLAG_RBNE: receive buffer not empty flag
\arg I2S_FLAG_TRANS: transmit on-going flag
\arg I2S_FLAG_RXORERR: overrun error flag
\arg I2S_FLAG_TXURERR: underrun error flag
\arg I2S_FLAG_CH: channel side flag
\arg I2S_FLAG_FERR: format error flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus spi_i2s_flag_get(uint32_t spi_periph, uint32_t flag)
{
if(SPI_STAT(spi_periph) & flag){
return SET;
}else{
return RESET;
}
}
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