GD32E230程序烧录和开发环境使用介绍
从GD32提供的资料来看,支持IAR、Keil、EmbeddedBuilder;目前该软件还是比较粗糙,个人上手体验不佳,面板菜单按键烧操作一下,动不动就卡死,仅支持gdlink调试器。
- EmbeddedBuilder开发环境体验较差,我不太喜欢,虽然Keil开发环境槽点也是有,用起来还是比前者好用,起码动不动就卡死要好。Keil工程配合VSCode插件Keil Assistant使用起来体验不错。Embedded IDE目前没有安装该插件测试。基于
GNU Tools ARM Embedded
工具链,开发平台和环境选择还是很多样化的。 EmbeddedBuilde
创建并生成的代码工程,不能直接转到Keil开发环境下使用,没有这个功能。生成的代码有点奇葩的是驱动库竟然包含标准库和hal库,但是使能的外设仅做了对hal库函数的初始化,后面会介绍说明。- ✨需要注意一点的是,在使用
EmbeddedBuilde
,自动自动生成初始化代码后,所有外设和中断都是仅仅做了初始化,并没有使能。在使用前必须先调用使能外设和使能对应外设中断才行。
- 🔖 例如开启串口功能,在初次调用串口打印函数前,需要调用一次串口使能函数:
usart_enable(USART0);
造成这样的原因可能是由于
EmbeddedBuilde
配置功能,仅仅调用了HAL库中相关的代码进行初始化操作。而 HAL 库代码仅包括这三大类函数,分别为:1.初始化类函数。2.配置类函数。3.功能类函数。原子/位操作需要从标准库中调用。EmbeddedBuilde
配置的外设和中断功能,需要单独做使能操作。
📘SWD串行调试接口说明
GD32E23x系列内核只支持SWD调试接口,不支持JTAG接口。
- GD32E230串行调试(SWD)提供两个引脚的接口:数据输入输出引脚(SWDIO)和时钟引脚(SWCLK)。
调试引脚分配:
PA14 : SWCLK
PA13 : SWDIO
注意:复位后,调试相关端口为输入PU/PD模式,其中:
PA13:SWDIO为上拉模式;
PA14:SWCLK为下拉模式。
- 🔨调试器:GD-LINK、CMSIS-DAP、J-LINK
✨通过SWD接口连接目标时,芯片不要处于Boot0=1,模式下,否则连接不到目标。在Boot0=1模式下,可以通过
GD32AllInOneProgrammer
工具,使用串口连接目标。
🧬Boot0=1模式下串口下载程序
In default condition, boot from main Flash memory is selected. The boot loader is located in
the internal boot ROM memory (system memory). It is used to reprogram the Flash memory
by using USART0 (PA9 and PA10) or USART1 (PA14 and PA15 or PA2 and PA3)
- 🌿USART0 :PA9 and PA10
- 🌿USART1 :(PA14 and PA15 or PA2 and PA3)
- 🔧串口烧录程序,GUI上位机软件:
GD32AllInOneProgrammer
- 🔖串口连接后,可以编辑OB选项字节参数:
- 🌿IAR和Keil环境不多做介绍,如果使用
EmbeddedBuilder
,如果手上有gdlink那可以配合一起调试使用,如果有J-LINK/CMSISI-DAP可以配合MCUProg
软件烧录程序使用。
📗资源外设库说明
- 🧨如果使用
EmbeddedBuilder
,那么所生成的工程中既包含有标准库文件也有hal库文件,std库是方便被hal库调用的。
- 🌿hal库:
GD32E23x_hal_peripheral
- 🌿std库:
GD32E23x_standard_peripheral
- 🌿GD32E23x标准固件库:
GD32E23x Firmware Library
:https://www.gd32mcu.com/cn/download/7?kw=GD32E2
🧲EmbeddedBuilder工程移植到Keil环境说明
- 🔰移植对比图:
- 🌿EmbeddedBuilder工程移植到Keil环境,
.s
底层驱动文件不同。在Keil环境工程中可以直接拷贝标准库工程中的.s底层文件来用。("路径\GD32E23x_Firmware_Library_V2.1.0\Firmware\CMSIS\GD\GD32E23x\Source\ARM\startup_gd32e23x.s"
)
- 🌿添加宏
GD32E230
和设置头文件路径:
- 🌿如果是新建工程,需要配置程序起始地址和大小:
- 🌿连接器配置选项:(与下载有关,没有勾选或上面的地址配置错误,烧录时会报错:
No Algorithm found for: 00008000H - 00009EABH
)
📚EmbeddedBuilder`移植到Keil工程模板
- 🎉为了方便在Keil环境下,使用
EmbeddedBuilder
自动配置初始化代码的便利。可以直接将EmbeddedBuilder
自动配置的初始化代码拷贝到Keil工程中使用。- 🔖如果只在
EmbeddedBuilder
中使用,那么此模板没有用处。
通过网盘分享的文件:HAL_Template.rar
链接: https://pan.baidu.com/s/19-5Kc3Xyv5wW9JJns2O6cQ?pwd=ijah 提取码: ijah
📘串口标准输出代码实现
- 🌿支持printf函数,需要选择
Use MicroLIB
.
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART0, (uint8_t)ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
return ch;
}
- 🌿支持printf函数,而不需要选择
Use MicroLIB
。
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#if (__ARMCC_VERSION >= 6010050)
__asm(".global __use_no_semihosting\n\t");
__asm(".global __ARM_use_no_argv \n\t");
#else
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
};
#endif
int _ttywrch(int ch)
{
ch = ch;
return ch;
}
void _sys_exit(int x)
{
x = x;
}
char *_sys_command_string(char *cmd, int len)
{
return NULL;
}
FILE __stdout;
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART0, (uint8_t)ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
return ch;
}
#endif
📗24位滴答定时器做延时使用实现
- 🌿做延时使用,不影响滴答定时器中断功能
volatile static uint32_t delay;
/*!
\brief configure systick
\param[in] none
\param[out] none
\retval none
*/
void systick_config(void)
{
/* setup systick timer for 1000,000 Hz interrupts */
if (SysTick_Config(SystemCoreClock / 1000U)){
/* capture error */
while (1){
}
}
/* configure the systick handler priority */
NVIC_SetPriority(SysTick_IRQn, 0x00U);
}
/*!
\brief delay decrement
\param[in] none
\param[out] none
\retval none
*/
void delay_decrement(void)
{
if (0U != delay){
delay--;
}
}
/*!
\brief delay a time in milliseconds
\param[in] count: count in milliseconds
\param[out] none
\retval none
*/
void delay_1ms(uint32_t count)
{
delay = count;
while(0U != delay){
}
}
/*!
\brief delay a time in seconds
\param[in] count: count in seconds
\param[out] none
\retval none
*/
void delay_1s(uint32_t count)
{
uint32_t i;
for(i = 0U; i < count; i++){
delay_1ms(1000U);
}
}
void SysTick_Handler(void)
{
/* user code [SysTick_IRQn local 0] begin */
/* user code [SysTick_IRQn local 0] end */
// hal_basetick_irq();
delay_decrement();
/* user code [SysTick_IRQn local 1] begin */
/* user code [SysTick_IRQn local 1] end */
}
- 🌿滴答定时器仅做延时使用,中断不能使用。
olatile static float count_1us = 0;
volatile static float count_1ms = 0;
/*!
\brief configure systick
\param[in] none
\param[out] none
\retval none
*/
void systick_config(void)
{
/* systick clock source is from HCLK/8 */
systick_clksource_set(SYSTICK_CLKSOURCE_HCLK_DIV8);
count_1us = (float)SystemCoreClock/8000000;
count_1ms = (float)count_1us * 1000;
}
/*!
\brief delay a time in microseconds in polling mode
\param[in] count: count in microseconds
\param[out] none
\retval none
*/
void delay_1us(uint32_t count)
{
uint32_t ctl;
/* reload the count value */
SysTick->LOAD = (uint32_t)(count * count_1us);
/* clear the current count value */
SysTick->VAL = 0x0000U;
/* enable the systick timer */
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
/* wait for the COUNTFLAG flag set */
do{
ctl = SysTick->CTRL;
}while((ctl&SysTick_CTRL_ENABLE_Msk)&&!(ctl & SysTick_CTRL_COUNTFLAG_Msk));
/* disable the systick timer */
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
/* clear the current count value */
SysTick->VAL = 0x0000U;
}
/*!
\brief delay a time in milliseconds in polling mode
\param[in] count: count in milliseconds
\param[out] none
\retval none
*/
void delay_1ms(uint32_t count)
{
uint32_t ctl;
/* reload the count value */
SysTick->LOAD = (uint32_t)(count * count_1ms);
/* clear the current count value */
SysTick->VAL = 0x0000U;
/* enable the systick timer */
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk;
/* wait for the COUNTFLAG flag set */
do{
ctl = SysTick->CTRL;
}while((ctl&SysTick_CTRL_ENABLE_Msk)&&!(ctl & SysTick_CTRL_COUNTFLAG_Msk));
/* disable the systick timer */
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
/* clear the current count value */
SysTick->VAL = 0x0000U;
}
- 🌿使用Hal库调用延时函数
使用hal库时,滴答定时器默认是启用的,在系统初始化函数中一起被初始化。
void msd_system_init(void)
{
/* user code [system_init local 0] begin */
/* user code [system_init local 0] end */
hal_fmc_prefetch_enable();
hal_rcu_periph_clk_enable(RCU_CFGCMP);
hal_nvic_periph_irq_enable(NonMaskableInt_IRQn, 0);
hal_nvic_periph_irq_enable(HardFault_IRQn, 0);
hal_nvic_periph_irq_enable(SVCall_IRQn, 0);
hal_nvic_periph_irq_enable(PendSV_IRQn, 0);
hal_nvic_periph_irq_enable(SysTick_IRQn, 0);
hal_basetick_init(HAL_BASETICK_SOURCE_SYSTICK);//滴答定时器初始化
/* user code [system_init local 1] begin */
/* user code [system_init local 1] end */
}
void SysTick_Handler(void)
{
/* user code [SysTick_IRQn local 0] begin */
/* user code [SysTick_IRQn local 0] end */
hal_basetick_irq();
/* user code [SysTick_IRQn local 1] begin */
/* user code [SysTick_IRQn local 1] end */
}
- 🌿毫秒延时函数:
hal_sys_basetick_delay_ms(1000);