gd32f427zg系列一:环境搭建与点亮led灯
文章目录
零、前言
作者工作以后,在实际的开发过程中从c51、riscv、mips、arm架构的单片机、处理器均有不同程度的接触,甚至还使用过Andes32这种以后从未听过的架构的单片机。
由于工作缘故,通用MCU其实已经有很久一段时间没摸过了,另外手上也有一部分的开发板是非stm32系列芯片,所以就想摸一摸这些吃灰的板子,不再当“一灯大师”。
一、硬件环境
本系列文章的开发板选用:慧勤智远 GD32F427 核心板,该核心板采用兆易创新的GD32F427ZGT6 作为主控芯片,LQFP144 pin 封装,基于 Cortex-M4 RISC 内核,主频 200MHZ,Flash 访问零等待状态。
由于使用的是Cortex-M核的单片机,并且开发板通常会把调试接口引出,所以此系列文章也会使用调试器(作者工作中很难使用到调试器,全是靠printf)。调试器使用的是沁恒WCH-Link,该模块可用于沁恒RISC-V架构MCU在线调试和下载, 也可用于带有SWD/JTAG接口的ARM内核MCU在线调试和下载。同时带有一路串口, 方便调试输出。
1.1 简单介绍一下GD32F427ZGT6
与stm32f407zgt6可以做一下竞品分析,主要差距在主频和SRAM上。不要小看SRAM的提升,根据作者的开发经验,64K的内存提升可以增加不少需求。256K在实际开发过程中可以上RTOS+LWIP,甚至还可以加上文件系统(FatFs、LittleFs)。
核心板提供的接口如下图所示:
1.2 介绍一下慧勤智远GD32F427核心板
核心板的接口如下图所示,可以看到板子接口还是相当丰富的,后续可以接各种传感器、外设来做各种实验,特别是还有屏幕接口(SPI、8080),可以移植LVGL或者其他GUI做界面开发,而且还带上了外挂的16M Flash、8M SRAM,可以疯狂堆功能、堆代码;唯一的缺点可能是没有把Ethernet接口接出来,后续想要上云,就需要借助无线模块、以太网模块了。
1.3 WCH-LinkE介绍
这小东西还好用,支持riscv、arm,建议使用时搞一根USB延长线,仅有杜邦线插到电脑上偏短。
二、软件环境
软件环境这里作者避免使用Keil,主要有这几个原因:1、Keil的编辑功能较差;2、自己想折腾;3、相结合使用AIGC、GPT等AI助手。
软件环境如下:
- 编辑器:VS Code
- 用到的插件:
- clangd
- xmake插件
- AI助手:GeekX 或者其他的AI助手
- 用到的插件:
- 工具链:gcc-arm-none-eabi-10.3
- 构建系统:xmake
- 调试上位机:pyocd(依赖Python)
- 串口终端:Mobaxterm20.3
以上软件看着很多,其实一点儿也不少,不要觉得仅仅是开发个单片机,至于这么折腾吗?其实有这几点考虑:
- 工作中仅使用Keil就能完全开发的场景较少,
- 就作者目前工作而言更多是使用命令行+脚本的形式完成开发.
- 公司达到一定规模后,必然会追求自动化:自动化集成构建,甚至自动化测试;使用脚本可以方便的完成以上工作
- 多学一点技能,拓展视野:工作中最常用到的脚本:Makefile、Python、Shell、Bat。
2.1 VS Code及其插件安装
VS Code没啥好说的,直接下载安装即可:Download Visual Studio Code - Mac, Linux, Windows
其中的插件安装,以Clangd为例其他插件类似步骤即可
2.2 工具链:gcc-arm-none-eabi-10.3安装
版本不强制要求10.3,其他版本均可,如果遇到构建问题可以直接GPT、通义千问、文心一言等AI查询一下即可。
链接:Downloads | 10.3-2021.10 – Arm Developer
以下是10.3版本的zip包下载链接,解压后直接用:
https://developer.arm.com/-/media/Files/downloads/gnu-rm/10.3-2021.10/gcc-arm-none-eabi-10.3-2021.10-win32.zip?rev=8f4a92e2ec2040f89912f372a55d8cf3&hash=5569B4C322E49BB400BFB63567A4B33B
安装完成后是否加入环境变量就看个人喜好,作者是没有加入环境变量的
PS:如果下载速度慢的话尝试寻找云盘、梯子等工具
2.3 xmake的安装
xmake是一个基于Lua的轻量级跨平台自动构建工具。语法对比Makefile、Cmake友好一点。最主要是文档十分完善、还是中文文档非常容易理解。
xmake安装:xmake
2.4 pyocd安装
为什么选择pyocd?查了下openocd支持的GD32的片子有点少,也正好没有GD32F4系列的,检索了一下发现pyocd有就选择pyocd。
pyocd的安装、使用可以参考:【GD32F427开发板试用】macOS/Linux系统开发环境搭建(开发、编译、烧录、调试) - 极术社区 - 连接开发者与智能计算生态 (aijishu.com)
2.5 Mobaxterm20.3安装
直接下载压缩包解压即可:MobaXterm free Xserver and tabbed SSH client for Windows (mobatek.net)
2.6 获取gd32f427相关支持包
-
直接在gd32的官网下载对应的固件库即可:兆易创新GigaDevice-资料下载兆易创新GD32 MCU
-
由于是使用gcc的Toolchain,并且gd32官方并未提供gd32f4xx基于gcc版本的启动文件和连接脚本,而靠我们自己修改又容易出错,所以这里使用了RT-Thread的启动文件和脚本,具体可以参考RT-Thread的源码:bsp/gd32/arm/libraries/GD32F4xx_Firmware_Library · RT-Thread/rt-thread - 码云 - 开源中国 (gitee.com)
- 启动文件如下所示,固件库路径,GCC\startup_gd32f4xx.s部分没有创建一个目录与文件即可,填入下方代码保存:GD32F4xx_Firmware_Library_V3.0.4\CMSIS\GD\GD32F4xx\Source\GCC\startup_gd32f4xx.s
;/* ; * Copyright (c) 2006-2021, RT-Thread Development Team ; * ; * SPDX-License-Identifier: Apache-2.0 ; * ; * Change Logs: ; * Date Author Notes ; * 2018-05-22 tanek first implementation ; */ .syntax unified .cpu cortex-m4 .fpu softvfp .thumb .global g_pfnVectors .global Default_Handler .section .isr_vector,"a",%progbits .type g_pfnVectors, %object g_pfnVectors: .word _estack // Top of Stack .word Reset_Handler // Reset Handler .word NMI_Handler // NMI Handler .word HardFault_Handler // Hard Fault Handler .word MemManage_Handler // MPU Fault Handler .word BusFault_Handler // Bus Fault Handler .word UsageFault_Handler // Usage Fault Handler .word 0 // Reserved .word 0 // Reserved .word 0 // Reserved .word 0 // Reserved .word SVC_Handler // SVCall Handler .word DebugMon_Handler // Debug Monitor Handler .word 0 // Reserved .word PendSV_Handler // PendSV Handler .word SysTick_Handler // SysTick Handler // external interrupts handler .word WWDGT_IRQHandler // 16:Window Watchdog Timer .word LVD_IRQHandler // 17:LVD through EXTI Line detect .word TAMPER_STAMP_IRQHandler // 18:Tamper and TimeStamp through EXTI Line detect .word RTC_WKUP_IRQHandler // 19:RTC Wakeup through EXTI Line .word FMC_IRQHandler // 20:FMC .word RCU_CTC_IRQHandler // 21:RCU and CTC .word EXTI0_IRQHandler // 22:EXTI Line 0 .word EXTI1_IRQHandler // 23:EXTI Line 1 .word EXTI2_IRQHandler // 24:EXTI Line 2 .word EXTI3_IRQHandler // 25:EXTI Line 3 .word EXTI4_IRQHandler // 26:EXTI Line 4 .word DMA0_Channel0_IRQHandler // 27:DMA0 Channel0 .word DMA0_Channel1_IRQHandler // 28:DMA0 Channel1 .word DMA0_Channel2_IRQHandler // 29:DMA0 Channel2 .word DMA0_Channel3_IRQHandler // 30:DMA0 Channel3 .word DMA0_Channel4_IRQHandler // 31:DMA0 Channel4 .word DMA0_Channel5_IRQHandler // 32:DMA0 Channel5 .word DMA0_Channel6_IRQHandler // 33:DMA0 Channel6 .word ADC_IRQHandler // 34:ADC .word CAN0_TX_IRQHandler // 35:CAN0 TX .word CAN0_RX0_IRQHandler // 36:CAN0 RX0 .word CAN0_RX1_IRQHandler // 37:CAN0 RX1 .word CAN0_EWMC_IRQHandler // 38:CAN0 EWMC .word EXTI5_9_IRQHandler // 39:EXTI5 to EXTI9 .word TIMER0_BRK_TIMER8_IRQHandler // 40:TIMER0 Break and TIMER8 .word TIMER0_UP_TIMER9_IRQHandler // 41:TIMER0 Update and TIMER9 .word TIMER0_TRG_CMT_TIMER10_IRQHandler // 42:TIMER0 Trigger and Commutation and TIMER10 .word TIMER0_CC_IRQHandler // 43:TIMER0 Capture Compare .word TIMER1_IRQHandler // 44:TIMER1 .word TIMER2_IRQHandler // 45:TIMER2 .word TIMER3_IRQHandler // 46:TIMER3 .word I2C0_EV_IRQHandler // 47:I2C0 Event .word I2C0_ER_IRQHandler // 48:I2C0 Error .word I2C1_EV_IRQHandler // 49:I2C1 Event .word I2C1_ER_IRQHandler // 50:I2C1 Error .word SPI0_IRQHandler // 51:SPI0 .word SPI1_IRQHandler // 52:SPI1 .word USART0_IRQHandler // 53:USART0 .word USART1_IRQHandler // 54:USART1 .word USART2_IRQHandler // 55:USART2 .word EXTI10_15_IRQHandler // 56:EXTI10 to EXTI15 .word RTC_Alarm_IRQHandler // 57:RTC Alarm .word USBFS_WKUP_IRQHandler // 58:USBFS Wakeup .word TIMER7_BRK_TIMER11_IRQHandler // 59:TIMER7 Break and TIMER11 .word TIMER7_UP_TIMER12_IRQHandler // 60:TIMER7 Update and TIMER12 .word TIMER7_TRG_CMT_TIMER13_IRQHandler // 61:TIMER7 Trigger and Commutation and TIMER13 .word TIMER7_CC_IRQHandler // 62:TIMER7 Capture Compare .word DMA0_Channel7_IRQHandler // 63:DMA0 Channel7 .word EXMC_IRQHandler // 64:EXMC .word SDIO_IRQHandler // 65:SDIO .word TIMER4_IRQHandler // 66:TIMER4 .word SPI2_IRQHandler // 67:SPI2 .word UART3_IRQHandler // 68:UART3 .word UART4_IRQHandler // 69:UART4 .word TIMER5_DAC_IRQHandler // 70:TIMER5 and DAC0 DAC1 Underrun error .word TIMER6_IRQHandler // 71:TIMER6 .word DMA1_Channel0_IRQHandler // 72:DMA1 Channel0 .word DMA1_Channel1_IRQHandler // 73:DMA1 Channel1 .word DMA1_Channel2_IRQHandler // 74:DMA1 Channel2 .word DMA1_Channel3_IRQHandler // 75:DMA1 Channel3 .word DMA1_Channel4_IRQHandler // 76:DMA1 Channel4 .word ENET_IRQHandler // 77:Ethernet .word ENET_WKUP_IRQHandler // 78:Ethernet Wakeup through EXTI Line .word CAN1_TX_IRQHandler // 79:CAN1 TX .word CAN1_RX0_IRQHandler // 80:CAN1 RX0 .word CAN1_RX1_IRQHandler // 81:CAN1 RX1 .word CAN1_EWMC_IRQHandler // 82:CAN1 EWMC .word USBFS_IRQHandler // 83:USBFS .word DMA1_Channel5_IRQHandler // 84:DMA1 Channel5 .word DMA1_Channel6_IRQHandler // 85:DMA1 Channel6 .word DMA1_Channel7_IRQHandler // 86:DMA1 Channel7 .word USART5_IRQHandler // 87:USART5 .word I2C2_EV_IRQHandler // 88:I2C2 Event .word I2C2_ER_IRQHandler // 89:I2C2 Error .word USBHS_EP1_Out_IRQHandler // 90:USBHS Endpoint 1 Out .word USBHS_EP1_In_IRQHandler // 91:USBHS Endpoint 1 in .word USBHS_WKUP_IRQHandler // 92:USBHS Wakeup through EXTI Line .word USBHS_IRQHandler // 93:USBHS .word DCI_IRQHandler // 94:DCI .word 0 // 95:Reserved .word TRNG_IRQHandler // 96:TRNG .word FPU_IRQHandler // 97:FPU .word UART6_IRQHandler // 98:UART6 .word UART7_IRQHandler // 99:UART7 .word SPI3_IRQHandler // 100:SPI3 .word SPI4_IRQHandler // 101:SPI4 .word SPI5_IRQHandler // 102:SPI5 .word 0 // 103:Reserved .word TLI_IRQHandler // 104:TLI .word TLI_ER_IRQHandler // 105:TLI Error .word IPA_IRQHandler // 106:IPA .size g_pfnVectors, .-g_pfnVectors .section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function Reset_Handler: ldr r1, =_sidata ldr r2, =_sdata ldr r3, =_edata subs r3, r2 ble fill_bss_start loop_copy_data: subs r3, #4 ldr r0, [r1,r3] str r0, [r2,r3] bgt loop_copy_data fill_bss_start: ldr r1, =__bss_start ldr r2, =__bss_end movs r0, 0 subs r2, r1 ble startup_enter loop_fill_bss: subs r2, #4 str r0, [r1, r2] bgt loop_fill_bss startup_enter: bl SystemInit bl main /* Exception Handlers */ .weak NMI_Handler .type NMI_Handler, %function NMI_Handler: b . .size NMI_Handler, . - NMI_Handler .weak MemManage_Handler .type MemManage_Handler, %function MemManage_Handler: b . .size MemManage_Handler, . - MemManage_Handler .weak BusFault_Handler .type BusFault_Handler, %function BusFault_Handler: b . .size BusFault_Handler, . - BusFault_Handler .weak UsageFault_Handler .type UsageFault_Handler, %function UsageFault_Handler: b . .size UsageFault_Handler, . - UsageFault_Handler .weak SVC_Handler .type SVC_Handler, %function SVC_Handler: b . .size SVC_Handler, . - SVC_Handler .weak DebugMon_Handler .type DebugMon_Handler, %function DebugMon_Handler: b . .size DebugMon_Handler, . - DebugMon_Handler .weak PendSV_Handler .type PendSV_Handler, %function PendSV_Handler: b . .size PendSV_Handler, . - PendSV_Handler .weak SysTick_Handler .type SysTick_Handler, %function SysTick_Handler: b . .size SysTick_Handler, . - SysTick_Handler /* IQR Handler */ .section .text.Default_Handler,"ax",%progbits .type Default_Handler, %function Default_Handler: b . .size Default_Handler, . - Default_Handler .macro IRQ handler .weak \handler .set \handler, Default_Handler .endm IRQ WWDGT_IRQHandler IRQ LVD_IRQHandler IRQ TAMPER_STAMP_IRQHandler IRQ RTC_WKUP_IRQHandler IRQ FMC_IRQHandler IRQ RCU_CTC_IRQHandler IRQ EXTI0_IRQHandler IRQ EXTI1_IRQHandler IRQ EXTI2_IRQHandler IRQ EXTI3_IRQHandler IRQ EXTI4_IRQHandler IRQ DMA0_Channel0_IRQHandler IRQ DMA0_Channel1_IRQHandler IRQ DMA0_Channel2_IRQHandler IRQ DMA0_Channel3_IRQHandler IRQ DMA0_Channel4_IRQHandler IRQ DMA0_Channel5_IRQHandler IRQ DMA0_Channel6_IRQHandler IRQ ADC_IRQHandler IRQ CAN0_TX_IRQHandler IRQ CAN0_RX0_IRQHandler IRQ CAN0_RX1_IRQHandler IRQ CAN0_EWMC_IRQHandler IRQ EXTI5_9_IRQHandler IRQ TIMER0_BRK_TIMER8_IRQHandler IRQ TIMER0_UP_TIMER9_IRQHandler IRQ TIMER0_TRG_CMT_TIMER10_IRQHandler IRQ TIMER0_CC_IRQHandler IRQ TIMER1_IRQHandler IRQ TIMER2_IRQHandler IRQ TIMER3_IRQHandler IRQ I2C0_EV_IRQHandler IRQ I2C0_ER_IRQHandler IRQ I2C1_EV_IRQHandler IRQ I2C1_ER_IRQHandler IRQ SPI0_IRQHandler IRQ SPI1_IRQHandler IRQ USART0_IRQHandler IRQ USART1_IRQHandler IRQ USART2_IRQHandler IRQ EXTI10_15_IRQHandler IRQ RTC_Alarm_IRQHandler IRQ USBFS_WKUP_IRQHandler IRQ TIMER7_BRK_TIMER11_IRQHandler IRQ TIMER7_UP_TIMER12_IRQHandler IRQ TIMER7_TRG_CMT_TIMER13_IRQHandler IRQ TIMER7_CC_IRQHandler IRQ DMA0_Channel7_IRQHandler IRQ EXMC_IRQHandler IRQ SDIO_IRQHandler IRQ TIMER4_IRQHandler IRQ SPI2_IRQHandler IRQ UART3_IRQHandler IRQ UART4_IRQHandler IRQ TIMER5_DAC_IRQHandler IRQ TIMER6_IRQHandler IRQ DMA1_Channel0_IRQHandler IRQ DMA1_Channel1_IRQHandler IRQ DMA1_Channel2_IRQHandler IRQ DMA1_Channel3_IRQHandler IRQ DMA1_Channel4_IRQHandler IRQ ENET_IRQHandler IRQ ENET_WKUP_IRQHandler IRQ CAN1_TX_IRQHandler IRQ CAN1_RX0_IRQHandler IRQ CAN1_RX1_IRQHandler IRQ CAN1_EWMC_IRQHandler IRQ USBFS_IRQHandler IRQ DMA1_Channel5_IRQHandler IRQ DMA1_Channel6_IRQHandler IRQ DMA1_Channel7_IRQHandler IRQ USART5_IRQHandler IRQ I2C2_EV_IRQHandler IRQ I2C2_ER_IRQHandler IRQ USBHS_EP1_Out_IRQHandler IRQ USBHS_EP1_In_IRQHandler IRQ USBHS_WKUP_IRQHandler IRQ USBHS_IRQHandler IRQ DCI_IRQHandler IRQ TRNG_IRQHandler IRQ FPU_IRQHandler IRQ UART6_IRQHandler IRQ UART7_IRQHandler IRQ SPI3_IRQHandler IRQ SPI4_IRQHandler IRQ SPI5_IRQHandler IRQ TLI_IRQHandler IRQ TLI_ER_IRQHandler IRQ IPA_IRQHandler
- ld链接脚本文件如下,链接脚本的地址无所谓,后续在xmake的lua脚本中指定一下路径就好了。
/* * linker script for GD32F4xx with GNU ld * BruceOu 2021-12-14 */ /* Program Entry, set to mark it as "used" and avoid gc */ MEMORY { CODE (rx) : ORIGIN = 0x08000000, LENGTH = 1024k /* 3072KB flash */ DATA (rw) : ORIGIN = 0x20000000, LENGTH = 256k /* 256KB sram */ } ENTRY(Reset_Handler) _system_stack_size = 0x200; SECTIONS { .text : { . = ALIGN(4); _stext = .; KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); *(.text) /* remaining code */ *(.text.*) /* remaining code */ *(.rodata) /* read-only data (constants) */ *(.rodata*) *(.glue_7) *(.glue_7t) *(.gnu.linkonce.t*) /* section information for finsh shell */ . = ALIGN(4); __fsymtab_start = .; KEEP(*(FSymTab)) __fsymtab_end = .; . = ALIGN(4); __vsymtab_start = .; KEEP(*(VSymTab)) __vsymtab_end = .; . = ALIGN(4); /* section information for initial. */ . = ALIGN(4); __rt_init_start = .; KEEP(*(SORT(.rti_fn*))) __rt_init_end = .; . = ALIGN(4); . = ALIGN(4); _etext = .; } > CODE = 0 /* .ARM.exidx is sorted, so has to go in its own output section. */ __exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) /* This is used by the startup in order to initialize the .data secion */ _sidata = .; } > CODE __exidx_end = .; /* .data section which is used for initialized data */ .data : AT (_sidata) { . = ALIGN(4); /* This is used by the startup in order to initialize the .data secion */ _sdata = . ; *(.data) *(.data.*) *(.gnu.linkonce.d*) . = ALIGN(4); /* This is used by the startup in order to initialize the .data secion */ _edata = . ; } >DATA .stack : { . = . + _system_stack_size; . = ALIGN(4); _estack = .; } >DATA __bss_start = .; .bss : { . = ALIGN(4); /* This is used by the startup in order to initialize the .bss secion */ _sbss = .; *(.bss) *(.bss.*) *(COMMON) . = ALIGN(4); /* This is used by the startup in order to initialize the .bss secion */ _ebss = . ; *(.bss.init) } > DATA __bss_end = .; _end = .; /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. * Symbols in the DWARF debugging sections are relative to the beginning * of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } }
三、搭建模板工程
可以直接去github下载我使用的模板工程:ethereal14/GD32F427_TemplateProject: The template project for the GD32F427 using the xmake build system, with development done using Vscode, GCC, and PyOCD. (github.com)
3.1 目录结构
具体的目录结构如下,大体是根据野火STM32教程的工程目录结构来的,读者如果有自己使用习惯的工程目录结构自行搭建即可,相应的后续的xmake.lua文件就需要根据目录结构来修改了:
3.2 xmake.lua脚本编写
使用过Makefile、CMake的同志们应该知道,构建系统的脚本协助我们的工作就是:收集所有源文件、头文件进行编译,在编译时会加入在脚本中指定好的编译参数,随后将所有目标文件通过链接命令链接成目标文件。
除此以外,构建脚本还可以更进一步,在编译前、在编译后还可以设置一些自定义脚本来做我们想要的操作。这里举一个使用场景:在一些专用SoC中,片上没有集成Flash或其他存储器件,都是使用的外挂nor flash,为方便产线生产,在开发时都会使用构建脚本生成一个烧片bin文件,通常就是先烧片再贴片到单板。
对应的Keil/MDK中,当然也有自定义脚本可以实现在编译前后进行用户自定义操作。
- 图片待补充
下面是xmake.lua文件,这里集成了build、install的操作。rebuild、clean功能xmake已经内置。具体语法可以参考xmake的文档(非常完善)
-
编译命令:
xmake build、xmake rebuild
或者xmake -b、xmake -r
-
清理命令:
xmake clean
-
下载命令:
xmake install
ProjectName = "GD32F427xx"
set_config("downloadfile", ProjectName)
-- print(get_config("downloadfile"))
-- 设置工具链
toolchain("arm-none-eabi")
set_kind("standalone")
set_sdkdir("D:/gcc-arm-none-eabi-10.3")
toolchain_end()
add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
-- 设置编译目标
target(ProjectName)
-- 设置生成的文件名称
set_filename(ProjectName ..".elf")
-- 设置编译链
set_toolchains("arm-none-eabi")
-- 生成二进制文件
set_kind("binary")
-- 启用所有警告
set_warnings("all")
-- 禁用优化
set_optimize("none")
-- 设置编译文件的目录
set_targetdir("build")
-- 设置源文件位置
add_files(
"./User/*.c",
"./Libraries/CMSIS/GD/GD32F4xx/Source/GCC/startup_gd32f4xx.s",
"./Libraries/CMSIS/GD/GD32F4xx/Source/*.c",
"./Libraries/GD32F4xx_standard_peripheral/Source/*.c"
)
-- -- 移除模板文件
-- remove_files(
-- "./Drivers/STM32F4xx_HAL_Driver/Src/*_template.c"
-- )
-- 设置头文件搜索路径
add_includedirs(
"./User",
"./Libraries/GD32F4xx_standard_peripheral/Include",
"./Libraries/CMSIS/GD/GD32F4xx/Include",
"./Libraries/CMSIS/GD/GD32F4xx",
"./Libraries/CMSIS"
)
-- 添加宏定义
add_defines(
"USE_STDPERIPH_DRIVER",
"GD32F427",
"GD32F4xx"
)
-- 设置C编译参数
add_cflags(
"-mcpu=cortex-m4",
"-mthumb",
"-mfloat-abi=hard -mfpu=fpv4-sp-d16",
"-fdata-sections -ffunction-sections",
"-g -gdwarf-2",
"--specs=nano.specs --specs=nosys.specs",
{ force = true }
)
-- 设置汇编编译参数
add_asflags(
"-mcpu=cortex-m4",
"-mthumb",
"-mfloat-abi=hard -mfpu=fpv4-sp-d16",
"-fdata-sections -ffunction-sections",
{ force = true }
)
-- 设置链接参数
local MapCMD = "-Wl,-Map=" .. ProjectName .. ".map,--cref"
add_ldflags(
"-mcpu=cortex-m4",
"-mthumb",
"-mfloat-abi=hard -mfpu=fpv4-sp-d16",
"-specs=nano.specs",
"-Tlink.ld",
"-Wl,--gc-sections",
"-u _printf_float",
"-lc -lm -lnosys",
MapCMD,
{ force = true }
)
target_end()
after_build(function(target)
os.exec("arm-none-eabi-objcopy -O ihex ./build/%s.elf ./build/%s.hex", target:name(), target:name())
os.exec("arm-none-eabi-objcopy -O binary ./build/%s.elf ./build/%s.bin", target:name(), target:name())
print("生成已完成!")
print("********************储存空间占用情况*****************************")
os.exec("arm-none-eabi-size -Bd ./build/%s.elf", target:name())
print("****************************************************************")
end)
after_install(function (target)
os.exec("pyocd flash --erase chip --target gd32f427zg %s", target:targetfile())
end)
on_clean(function()
os.rm("build")
end)
3.3 编译体验
四、clangd配置
clangd所需要的compile_command.json在xmake中其实已经生成了:
add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
不过由于是交叉编译的,所以clangd还是找不到编译器提供的头文件在哪里,这时候需要手动去配置一点配置项,全部代码可以参考:GD32F427_TemplateProject/gd32f427_xmake_template.code-workspace at master · ethereal14/GD32F427_TemplateProject (github.com)
"clangd.arguments": [
"--query-driver=D:/gcc-arm-none-eabi-10.3/bin/arm-none-eabi-gcc.exe",
"--compile-commands-dir=.vscode/",
]
五、调试配置
- 暂时没折腾(printf大法好)
六、点灯
- 2024.09.07更新
七、遗留工作项(Q&A)
-
点灯代码实现
-
QA :读者若是有疑问,随时在评论区留言或者github提issue。后续会更新一波QA。