GD32VW553-IOT 测评和vscode开发环境搭建

GD32VW553-IOT 测评和vscode开发环境搭建

1. 背景介绍

iCEasy商城的产品, Firefly Workshop 萤火工厂的样片, 是一款基于GD32VW553 MCU的开源硬件, 这款MCU内置了32bit的RISC-V内核, 支持双模无线WIFI-6和BLE-5.2, 最高主频可达160Mhz.

本人曾在公司参与开发了一款基于RISC-V内核的触控芯片, 所以之前接触过兆易更早的一款RISC-V的MCU, 即GD32VF103, 同时也使用过GD32W5系列的IOT MCU, 这次正好看到了结合GD的V和W联手的产品, 于是就申请了一块板子回来研究研究。

同样想要玩玩这款芯片的小伙伴, 可以去申请样品, 链接如下:https://www.iceasy.com/

2. 准备工作

样品拿到手之后, 先去GD官网把手册和开发软件下载一下, 同时也可以去iCEasy商城网站上下载对应资料。https://www.gd32mcu.com/cn/download/0?kw=GD32VW5

  • 用户手册、数据手册
  • 固件库、原理图
  • GD32AllInOneProgrammer_win
  • GD32EmbeddedBuilder

3. 展示一下

4. 创建工程

基于GD32EmbeddedBuilder可以很方便快速的把demo程序跑起来, 下面是创建工程的步骤, 软件提供了MCU的ARM C project和RISC-V Cproject, 本次测试的芯片是基于RISC-V的, 因此选择对应的选项.




5. 工程结构

Firmware目录中是GD的外设库和RISC-V的驱动库, inc和src是具体实现的功能, 可以参考官方提供的demo来移植想要的功能, idscripts提供的链接文件, 指定了芯片的内存大小和布局, openocd提供了基于gd_link的openocd下载脚本。

比较需要注意的是Firmware/RISC-V/env_Eclipse和stubs文件夹, 其中stubs文件夹提供的是一些系统调用的桩函数, env_Eclipse文件夹下提供的entry.S和start.S实现了芯片启动部分和中断向量表设置。


编译选项如图所示:
riscv-nuclei-elf-gcc -march=rv32imac -mabi=ilp32 -mcmodel=medlow -msmall-data-limit=8 -mdiv -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -g3 -std=gnu11 -DGD_ECLIPSE_GCC -DUSE_STDPERIPH_DRIVER ........

riscv-nuclei-elf-gcc -march=rv32imac -mabi=ilp32 -mcmodel=medlow -msmall-data-limit=8 -mdiv -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -g3 -Wa,-adhlns=Firmware/RISCV/env_Eclipse/entry.o.lst -x assembler-with-cpp -I"../Firmware/RISCV/drivers" -c -o "Firmware/RISCV/env_Eclipse/entry.o" "../Firmware/RISCV/env_Eclipse/entry.S"

riscv-nuclei-elf-gcc -march=rv32imac -mabi=ilp32 -mcmodel=medlow -msmall-data-limit=8 -mdiv -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -g3 -Wl,-Map,"gd32vw553_test.map" -T GD32VW55X.lds -nostartfiles -Xlinker --gc-sections -L"../ldscripts/" --specs=nano.specs --specs=nosys.specs -o "gd32vw553_test.elf" ......

6. 代码下载

  1. 启动模式修改, 从表中可以看出, 将BOOT0接高之后, 会从Bootloader启动, 就能用串口ISP更新固件, 根据原理图可以看出, 首先需要将R4和R5两个电阻焊接上

7. 串口LOG打印和LED闪烁

  1. 使用的是串口0和PA15作为LED口

    c 复制代码
      int main(void)
      {
          /* configure systick */
          systick_config();
          eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL3_PRIO1);
    
          /* enable the led clock */
          rcu_periph_clock_enable(RCU_GPIOA);
          /* configure led GPIO port */
          gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
          gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_15);
    
          GPIO_BC(GPIOA) = GPIO_PIN_15;
    
          /* initilize the LEDs, USART and key */
          gd_eval_com_init(EVAL_COM0);
    
          /* print out the clock frequency of system, AHB, APB1 and APB2 */
          printf("CK_SYS is %d\r\n", rcu_clock_freq_get(CK_SYS));
          printf("CK_AHB is %d\r\n", rcu_clock_freq_get(CK_AHB));
          printf("CK_APB1 is %d\r\n", rcu_clock_freq_get(CK_APB1));
          printf("CK_APB2 is %d\r\n", rcu_clock_freq_get(CK_APB2));
    
          while(1) {
              delay_1ms(500);
              GPIO_TG(GPIOA) = GPIO_PIN_15;
          }
      }
  2. 在桩函数中修改串口打印的功能

    c 复制代码
     int _put_char(int ch)
     {
       usart_data_transmit(EVAL_COM0, (uint8_t) ch );
       while (usart_flag_get(EVAL_COM0, USART_FLAG_TBE)== RESET){
       }
    
       return ch;
     }
  3. 将代码下载进板子, 打开串口助手, 可以看到log打印

8. vscode开发环境搭建

  1. 目录修改

  2. CmakeList.txt编写

    cmake_minimum_required(VERSION 3.22)

    Setup compiler settings

    set(CMAKE_C_STANDARD 11)
    set(CMAKE_C_STANDARD_REQUIRED ON)
    set(CMAKE_C_EXTENSIONS ON)

    ###########################################################

    Set the project name

    set(CMAKE_PROJECT_NAME gd32vw553_test)

    set(APP_ADDR "0x08000000") # 从0x08000000启动
    add_definitions(-DDOWNLOAD_MODE=DOWNLOAD_MODE_FLASHXIP -DDOWNLOAD_MODE_STRING="FLASHXIP" -D__IDE_RV_DE_RV_CORE=n303 -DSYSTEM_CLOCK=160000000 -DSYSCLK_USING_HXTAL)

    Define the build type

    if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE "Debug")
    endif()

    find_program(CCACHE_FOUND ccache)
    if(CCACHE_FOUND)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache)
    set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache)
    endif(CCACHE_FOUND)

    ###########################################################

    Include toolchain file

    set(CMAKE_SYSTEM_NAME Generic)
    set(CMAKE_SYSTEM_PROCESSOR riscv)

    set(CMAKE_C_COMPILER_FORCED TRUE)
    set(CMAKE_CXX_COMPILER_FORCED TRUE)
    set(CMAKE_C_COMPILER_ID GNU)
    set(CMAKE_CXX_COMPILER_ID GNU)

    Some default GCC settings

    riscv64-unknown-elf- must be part of path environment

    set(TOOLCHAIN_PREFIX riscv64-unknown-elf-)

    set(CMAKE_C_COMPILER {TOOLCHAIN_PREFIX}gcc) set(CMAKE_ASM_COMPILER {CMAKE_C_COMPILER})
    set(CMAKE_CXX_COMPILER {TOOLCHAIN_PREFIX}g++) set(CMAKE_LINKER {TOOLCHAIN_PREFIX}g++)
    set(CMAKE_OBJCOPY {TOOLCHAIN_PREFIX}objcopy) set(CMAKE_SIZE {TOOLCHAIN_PREFIX}size)
    set(CMAKE_OpenOCD "E:/Program Files/NucleiStudio/toolchain/openocd/bin/openocd.exe")

    set(CMAKE_EXECUTABLE_SUFFIX_ASM ".elf")
    set(CMAKE_EXECUTABLE_SUFFIX_C ".elf")
    set(CMAKE_EXECUTABLE_SUFFIX_CXX ".elf")

    set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

    MCU specific flags

    set(TARGET_FLAGS "-march=rv32imac -mabi=ilp32 -mtune=nuclei-200-series -mcmodel=medlow -mno-save-restore")

    set(CMAKE_C_FLAGS "{CMAKE_C_FLAGS} {TARGET_FLAGS}")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections -fno-common")

    if(CMAKE_BUILD_TYPE MATCHES Debug)
    set(CMAKE_C_FLAGS "{CMAKE_C_FLAGS} -Og -g -gdwarf-2") endif() if(CMAKE_BUILD_TYPE MATCHES Release) set(CMAKE_C_FLAGS "{CMAKE_C_FLAGS} -O3")
    endif()
    if(CMAKE_BUILD_TYPE MATCHES RelWithDebInfo)
    set(CMAKE_C_FLAGS "{CMAKE_C_FLAGS} -O2 -g") endif() if(CMAKE_BUILD_TYPE MATCHES MinSizeRel) set(CMAKE_C_FLAGS "{CMAKE_C_FLAGS} -Os")
    endif()

    set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -MMD -MP")

    set(CMAKE_C_LINK_FLAGS "{CMAKE_C_FLAGS}") set(CMAKE_C_LINK_FLAGS "{CMAKE_C_LINK_FLAGS} -T "{CMAKE_SOURCE_DIR}/ldscripts/GD32VW55X.lds\"") set(CMAKE_C_LINK_FLAGS "{CMAKE_C_LINK_FLAGS} -nostartfiles")
    set(CMAKE_C_LINK_FLAGS "{CMAKE_C_LINK_FLAGS} -Wl,-Map={CMAKE_PROJECT_NAME}.map -Wl,--check-sections -Wl,--no-warn-rwx-segments")
    set(CMAKE_C_LINK_FLAGS "{CMAKE_C_LINK_FLAGS} -Wl,--start-group -lc -lm -Wl,--end-group") set(CMAKE_C_LINK_FLAGS "{CMAKE_C_LINK_FLAGS} -Wl,--print-memory-usage")

    set(CMAKE_CXX_FLAGS "{CMAKE_C_FLAGS} -fno-rtti -fno-exceptions -fno-threadsafe-statics") set(CMAKE_CXX_LINK_FLAGS "{CMAKE_C_LINK_FLAGS} -Wl,--start-group,-lstdc++,-lc_nano,-lgcc,--end-group")
    ##########################################################

    Enable compile command to ease indexing with e.g. clangd

    set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)

    must need

    enable_language(C ASM)

    Core project settings

    project({CMAKE_PROJECT_NAME}) message("Build type: " {CMAKE_BUILD_TYPE})

    Create an executable object type

    add_executable(${CMAKE_PROJECT_NAME})

    汇编的宏定义

    Add project symbols (macros)

    target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE
    # Add user defined symbols
    )

    Add linked libraries

    target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
    stm32cubemx
    # Add user defined libraries
    )

    ##########################################################
    add_library(stm32cubemx INTERFACE)

    target_compile_definitions(stm32cubemx INTERFACE
    # TX_INCLUDE_USER_DEFINE_FILE
    )

    target_include_directories(stm32cubemx INTERFACE
    Application/Include/
    Hardware/Include/

    复制代码
     Firmware/GD32VW55x_standard_peripheral/
     Firmware/GD32VW55x_standard_peripheral/Include/
    
     Firmware/RISCV/drivers/
    
     # Firmware/OS/FreeRTOS/Source/include
     # Firmware/OS/FreeRTOS/Source/portable
    
     # Firmware/OS/ThreadX/common/inc
     # Firmware/OS/ThreadX/ports/nuclei/

    )

    file(GLOB SRC_LIB_0 Firmware/GD32VW55x_standard_peripheral/.c)
    file(GLOB SRC_LIB_1 Firmware/GD32VW55x_standard_peripheral/Source/
    .c)
    file(GLOB SRC_LIB_2 Firmware/RISCV/env_Eclipse/.c)
    file(GLOB SRC_LIB_3 Firmware/RISCV/stubs/
    .c)

    file(GLOB SRC_LIB_4 Firmware/OS/FreeRTOS/Source/*.c)

    file(GLOB SRC_LIB_5 Firmware/OS/FreeRTOS/Source/portable/*.c)

    file(GLOB SRC_LIB_6 Firmware/OS/FreeRTOS/Source/portable/MemMang/*.c)

    file(GLOB SRC_LIB_7 Firmware/OS/FreeRTOS/Source/portable/GCC/portasm.S)

    file(GLOB SRC_LIB_4 Firmware/OS/ThreadX/common/src/*.c)

    file(GLOB SRC_LIB_5 Firmware/OS/ThreadX/ports/nuclei/*.c)

    file(GLOB SRC_LIB_6 Firmware/OS/ThreadX/ports/nuclei/gcc/context.S)

    file(GLOB SRC_LIB_7 Firmware/OS/ThreadX/ports/nuclei/gcc/interrupt.S)

    file(GLOB SRC_APP_0 Application/Source/.c)
    file(GLOB SRC_APP_1 Hardware/Source/
    .c)

    target_sources(stm32cubemx INTERFACE
    {SRC_APP_0} {SRC_APP_1}

    复制代码
     ${SRC_LIB_0}
     ${SRC_LIB_1}
     ${SRC_LIB_2}
     ${SRC_LIB_3}
     ${SRC_LIB_4}
     ${SRC_LIB_5}
     ${SRC_LIB_6}
     ${SRC_LIB_7}
    
     # GLOB *.S doesn't work
     Firmware/RISCV/env_Eclipse/entry.S
     Firmware/RISCV/env_Eclipse/start.S

    )
    ##########################################################

    For Download & Debug

    set(ELF_FILE {PROJECT_NAME}.elf) set(HEX_FILE {PROJECT_NAME}.hex)
    set(BIN_FILE {PROJECT_NAME}.bin) set(DFU_FILE {PROJECT_NAME}.dfu)

    PRE_BUILD(预构建)、PRE_LINK(链接前)和POST_BUILD(构建后)用于指定自定义命令在构建过程中的执行时机。

    add_custom_command(TARGET {CMAKE_PROJECT_NAME} POST_BUILD COMMAND {CMAKE_OBJCOPY} -Obinary -S {ELF_FILE} {BIN_FILE}
    COMMAND {CMAKE_OBJCOPY} -Oihex {ELF_FILE} {HEX_FILE} COMMENT "Building {PROJECT_NAME}.bin and ${PROJECT_NAME}.hex"
    )

    print size

    add_custom_command(TARGET {CMAKE_PROJECT_NAME} POST_BUILD COMMAND {CMAKE_SIZE} --format=berkeley ${PROJECT_NAME}.elf
    COMMENT "Invoking: Cross ARM GNU Print Size"
    )

    make openocd_flash

    add_custom_target(openocd_flash
    COMMAND {CMAKE_OpenOCD} -f "{CMAKE_SOURCE_DIR}/nuclei_sdk/SoC/gd32vf103/Board/gd32vf103v_rvstar/openocd_gd32vf103.cfg" -c "program gd32vf103.elf verify reset exit"
    COMMENT "USE OpenOCD to make flash at ${APP_ADDR}"
    )

  3. 编译工具链配置(这里windows平台工具链下载就不多说了,下载对应工具,然后添加环境变量可以找找其他教程)

  • gcc
  • riscv-none-embed-gcc
  • ninja
  • cmake
  • cacache

9. Timer Breath LED

  1. 移植DEMO中的Timer Breath LED功能

10. 移植MBL和MSDK

SDK 最终生成的执行程序主要有两个:一个是 MBL(Main Bootloader),一个是 MSDK

( Main SDK ) 。它们最终都将被烧写到 FLASH 运行。 上电之后, 程序将从 MBL 的

Reset_Handler 启动,然后跳转到 MSDK 主程序运行

  1. 三个配置文件
  • GD32VW55x_RELEASE/config/platform_def.h 用于配置WIFI 和 BLE
  • GD32VW55x_RELEASE/config/config_gdm32.h 用于设置Flahs和SRAM内存布局
  • GD32VW55x_RELEASE/MSDK/app/app_cfg.h 用于配置一些无线相关的应用, 例如: ATCMD,阿里云, MQTT, COAP

注:通过修改 app_cfg.h 内的宏CONFIG_BLE_LIB 可切换BLE library。将 CONFIG_BLE_LIB 配

置为 BLE_LIB_MIN,工程编译时会选择libble.a,同时头文件会include ble_config_min.h;将CONFIG_BLE_LIB 配置为BLE_LIB_MAX, 工程编译时会选择 libble_max.a,同时头文件会include ble_config_max.h。

  1. 工程配置

  2. 编译工程

  • Embedded Builder IDE 下编译和调试 SDK。首先下载GD32VW55x_RELEASE, 目前官网最新版本是1.0.3a.
  • 将workspaces 指向 GD32VW55x_RELEASE 目录
  • 然后选择 MSDK 或 MBL 工程进行导入, 路径为GD32VW55x_RELEASE/MBL/project/eclipse和GD32VW55x_RELEASE/MSDK/projects/eclipse/msdk
  • 分别编译 MBL 和 MSDK 工程
  • MSDK 编译完成之后, 会调用 MSDK/projects/image_afterbuild.bat 生成 image-ota.bin 和image-all.bin。并将生成的 bin 文件拷贝至/scripts/images 内, image-ota.bin是MSDK工程生成的bin文件,可用于OTA 升级, image-all.bin是MBL(mbl.bin)和 MSDK(image-ota.bin)的组合,该固件可用于生产,烧录到 FLASH 中运行
  1. 编译报错
    编译MSDK时候,出现了以下错误信息, 而且image没有成功生成

导致的原因是bat命令没有识别出我路径中的空格, 这里我的路径是program file, 导致脚本将空格之后和空格之前设别成了两条指令,解决办法就是将整个路径用双引号括起来


11. 初始化成功

视频链接和项目地址

  1. https://github.com/1508912767/gd32vw553_test
  2. https://www.bilibili.com/video/BV1MEeJzrE9u/