gd32f427zg系列一:环境搭建与点亮led灯

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

以上软件看着很多,其实一点儿也不少,不要觉得仅仅是开发个单片机,至于这么折腾吗?其实有这几点考虑:

  1. 工作中仅使用Keil就能完全开发的场景较少,
    • 就作者目前工作而言更多是使用命令行+脚本的形式完成开发.
    • 公司达到一定规模后,必然会追求自动化:自动化集成构建,甚至自动化测试;使用脚本可以方便的完成以上工作
  2. 多学一点技能,拓展视野:工作中最常用到的脚本: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相关支持包

  1. 直接在gd32的官网下载对应的固件库即可:兆易创新GigaDevice-资料下载兆易创新GD32 MCU

  2. 由于是使用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。

八、参考

  1. 【GD32F427开发板试用】Windows系统VSCode+pyOCD开发环境搭建 - 极术社区 - 连接开发者与智能计算生态 (aijishu.com)

  2. 【GD32F427开发板试用】macOS/Linux系统开发环境搭建(开发、编译、烧录、调试) - 极术社区 - 连接开发者与智能计算生态 (aijishu.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值