为了构建Cortex M系列单片机免费开源的开发环境,网络上了解来看VSCODE+GCC+JLINK是一套比较高效的组合方式,下面记录环境搭建的流程。
我这边的PC环境为 WIN10专业版64bit。
工具准备
1. arm-none-eabi-gcc下载及安装
官网下载链接:
Downloads | GNU Arm Embedded Toolchain Downloads – Arm DeveloperDownload the GNU Embedded Toolchain for ARM, an open-source suite of tools for C, C++, and Assembly programming for 32-bit ARM Cortex-A, ARM Cortex-M and Cortex-R familieshttps://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads下载最新版本。
下载完成后点击.exe直接一直点下一步就好,千万要记得在最后一步的时候将add path打上勾,默认是不打勾的。
2. Gnu make工具 --- MinGW下载及安装
官网下载很慢,推荐到下面镜像站点下载最新版本即可
/明威指数 (1f0.de)http://files.1f0.de/mingw/下载好之后解压到D盘根目录,然后将bin文件路径加到环境变量。
设置 -> 系统 -> 关于 -> 高级系统设置
将MinGW路径加入到Path中。
重启后即可生效。
打开cmd,输入gcc -v验证是否成功即可。
3. GIT Bash安装(推荐)
这里使用git bash终端(unix)替换dos 终端,自行百度安装GIT即可。
将vscode的终端使用git bash代替cmd,验证gcc -v成功的结果如下:
4. JLINK安装
官网下载安装JLINK最新版本即可。
GD32F307 JLINK已经默认支持,如果是其他一些国内的mcu,需要去mcu官网下载对应的JLINK支持文件。
这部分可自行百度解决。
5. vscode下载安装
官网下载安装。
vscode需要使用到的插件如下:
1. 中文插件。
可能有人看着英文界面比较难受,下面介绍如何设置中文环境。现在中文环境也是通过安装扩展来实现,如下图,先点击侧边栏的扩展,然后在搜索框中输入language,选择“中文(简体)”进行安装,完成后重启VSCode即可。
2. C/C++环境插件
3. Cortex debug插件
4. Code runner仿真插件
插件可以在搜索栏输入关键字搜索安装。
至此,环境工具安装完毕。
6. MDK5官方版本(不要使用破解版)
官网下载并安装MDK5,这里是为了生成芯片用于仿真的SVD文件,如芯片官网有SVD文件下载,则不需要这一步。
编译准备
1. 代码准备
这里以GD32F307 demo板的LED闪烁例程来做演示,参考官方下载的GD32F30x_Firmware_Library_V2.1.4.rar目录tree,初步扩展如下:
因官网下载的代码printf为MDK环境使用,使用GNU gcc编译会出错,libs中重写了gcc所需的printf部分函数
2. makefile
makefile参考下面范本修改芯片名称即可。
#当由用户传入的参数V等于1时,条件为真,输出编译信息,当V不等于1时禁止信息
ifneq ($(V),1)
Q := @
else
Q :=
endif################################以下项目需用户根据需要更改##########################
# 输出文件的名称,默认为main(main.elf main.bin main.hex)
TARGET := main#链接文件名称和所在路径
LDSCRIPT := \
./StartUp/gd32f307vctb_flash.ld#启动文件名称和所在路径
START_FILE_SOURCES := \
./StartUp/startup_gd32f307vctb.s#内核选择,FPU, FLOAT-ABI可为空
CPU := -mcpu=cortex-m4
FPU :=
FLOAT-ABI :=#系统宏定义
C_DEFS := \
-DGD32F30X_HD \
-DUSE_FULL_ASSERT \
-D_DLIB_FILE_DESCRIPTOR# 芯片型号,用于Jlink仿真调试、下载
CHIP := GD32F307VC# 选择优化等级:
# 1. gcc中指定优化级别的参数有:-O0、-O1、-O2、-O3、-Og、-Os、-Ofast。
# 2. 在编译时,如果没有指定上面的任何优化参数,则默认为 -O0,即没有优化。
# 3. 参数 -O1、-O2、-O3 中,随着数字变大,代码的优化程度也越高,不过这在某种意义上来说,也是以牺牲程序的可调试性为代价的。
# 4. 参数 -Og 是在 -O1 的基础上,去掉了那些影响调试的优化,所以如果最终是为了调试程序,可以使用这个参数。不过光有这个参数也是不行的,这个参数只是告诉编译器,编译后的代码不要影响调试,但调试信息的生成还是靠 -g 参数的。
# 5. 参数 -Os 是在 -O2 的基础上,去掉了那些会导致最终可执行程序增大的优化,如果想要更小的可执行程序,可选择这个参数。
# 6. 参数 -Ofast 是在 -O3 的基础上,添加了一些非常规优化,这些优化是通过打破一些国际标准(比如一些数学函数的实现标准)来实现的,所以一般不推荐使用该参数。
# 7. 如果想知道上面的优化参数具体做了哪些优化,可以使用 gcc -Q --help=optimizers 命令来查询,比如下面是查询 -O3 参数开启了哪些优化:
OPT := -Og# 是否将debug信息编译进.elf文件,默认打开
DEBUG := 1# 输出文件夹,.hex .bin .elf放在此文件夹下,.o .d文件放在此文件的子目录Obj下(自动创建)
BUILD := ./build
###################################用户修改结束#################################### 以下与系统相关,用于支持JLink下载和仿真
# linux 执行make download的时候不用带参数,windows下需要带SYS=1,用以支持Jlink
ifneq ($(SYS), 1)
JLINKEXE := JLinkExe
JLINKGDBSERVER := JLinkGDBServer
else
JLINKEXE := JLink.exe
JLINKGDBSERVER := JLinkGDBServer.exe
endif# 编译器定义
CC := arm-none-eabi-gcc
SZ := arm-none-eabi-size
OBJCOPY := arm-none-eabi-objcopy
GDB := arm-none-eabi-gdb
BIN := $(OBJCOPY) -O binary -S
HEX := $(OBJCOPY) -O ihex#################### CFLAGS Config Start ##########################
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)#搜索所有的h文件,并输出携带-I的.h文件路径
C_INCLUDES := $(addprefix -I,$(sort $(dir $(shell find ./ -type f -iname "*.h"))))#编译参数
CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -fdata-sections -ffunction-sections
#开关警告
CFLAGS += -Wall #-W
#标准
CFLAGS += -std=c99#当开启DEBUG功能时携带DEBUG参数
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif#自动生成依赖文件
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
#################### CFLAGS Config End ########################### libraries
LIBS = -lc -lm -lnosys
LIBDIR =
#链接指令集-specs=nosys.specs
LDFLAGS = $(MCU) -T$(LDSCRIPT) -specs=nano.specs $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD)/Obj/$(TARGET).map,--cref
#LDFLAGS = $(MCU) -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD)/Obj/$(TARGET).map,--cref
#是否开启优化掉未使用的函数和符号
LDFLAGS += -Wl,--gc-sections#制作启动文件依赖Obj,输出去掉路径的.o文件,可兼容.s和.S
START_FILE_OBJ = $(addsuffix .o, $(basename $(notdir $(START_FILE_SOURCES))))
OBJECTS = $(addprefix $(BUILD)/Obj/, $(START_FILE_OBJ))#搜索所有的c文件,制作所有的.c文件依赖Obj
C_SOURCES = $(shell find ./ -type f -iname "*.c")
OBJECTS += $(addprefix $(BUILD)/Obj/,$(notdir $(C_SOURCES:%.c=%.o)))
#PS:去掉终极目标的原始路径前缀并添加输出文件夹路径前缀(改变了依赖文件的路径前缀,需要重新指定搜索路径)#指定makefile搜索文件的路径(假如终极目标的依赖文件不携带.c文件所在的路径,
#且不指定搜索路径,makefile会报错没有规则制定目标)
vpath %.c $(sort $(dir $(C_SOURCES))) #取出路径并去重和排序(以首字母为单位)
vpath %.s $(dir $(START_FILE_SOURCES))
vpath %.S $(dir $(START_FILE_SOURCES))#指定为伪目标跳过隐含规则搜索,提升makefile的性能,并防止make时携带的参数与实际文件重名的问题
.PHONY:all cleanAll clean printf JLinkGDBServer debug download commitall : $(BUILD)/Obj $(BUILD)/$(TARGET).elf $(BUILD)/$(TARGET).bin $(BUILD)/$(TARGET).hex#链接所有的.o生成.elf文件
$(BUILD)/$(TARGET).elf : $(OBJECTS) | $(LDSCRIPT)$(Q)$(CC) $(LDFLAGS) -o $@ $(OBJECTS)$(Q)echo "make $@:"$(Q)$(SZ) $@#编译启动文件 备用参数:#-x assembler-with-cpp
$(BUILD)/Obj/$(START_FILE_OBJ) : $(START_FILE_SOURCES) Makefile$(Q) $(CC) -c $(CFLAGS) -x assembler-with-cpp -o $@ $<$(Q)echo "buid $(notdir $<)"#编译工程 备用参数:#-Wa,-a,-ad,-alms=$(BUILD_DIR)/Obj/$(notdir $(<:.c=.lst))
$(BUILD)/Obj/%.o : %.c Makefile$(Q) $(CC) -c $(CFLAGS) -o $@ $< $(Q)echo "buid $(notdir $<)"$(BUILD)/Obj :$(Q)mkdir -p $(BUILD)/Obj$(Q)echo "mkdir $(BUILD)/Obj"%.bin : $(BUILD)/$(TARGET).elf$(Q) $(BIN) $< $@%.hex : $(BUILD)/$(TARGET).elf$(Q) $(HEX) $< $@#用于检查链接脚本和启动文件是否存在,不存在则报错误
$(START_FILE_SOURCES):$(Q)echo ERROR: The startup file does not exist or has the wrong path !;\exit 1
$(LDSCRIPT):$(Q)echo ERROR: The link file does not exist or has the wrong path !;\exit 2cleanAll: clean$(Q)$(RM) -r build$(Q)echo "clean all *.elf *.hex *.bin";clean:$(Q)$(RM) $(shell find ./ -type f -iname "*.o")$(Q)$(RM) $(shell find ./ -type f -iname "*.d")$(Q)$(RM) $(shell find ./ -type f -iname "*.d.*")$(Q)$(RM) $(shell find ./ -type f -iname "*.map")$(Q)$(RM) $(shell find ./ -type f -iname "*.gdb")$(Q)echo "clean all *.o *.d *.map";printf:$(Q)echo $(info $(LDFLAGS))JLinkGDBServer:$(Q)JLinkGDBServer -select USB -device $(CHIP) \-endian little -if SWD -speed 4000 -noir -LocalhostOnlydebug:$(Q)make$(Q)echo target remote localhost\:2331 > gdb.gdb$(Q)echo monitor reset >> gdb.gdb$(Q)echo monitor halt >> gdb.gdb$(Q)echo load >> gdb.gdb$(Q)echo b main >> gdb.gdb$(Q)echo - >> gdb.gdb$(Q)echo c >> gdb.gdb$(Q)-$(GDB) $(BUILD)/$(TARGET).elf --command=gdb.gdb $(Q)$(RM) gdb.gdbdownload:$(Q)make$(Q)echo "h" > jlink.jlink$(Q)echo "loadfile" $(BUILD)/$(TARGET).bin >> jlink.jlink$(Q)echo "r" >> jlink.jlink$(Q)echo "qc" >> jlink.jlink$(Q)$(JLINKEXE) -device $(CHIP) -Speed 4000 -IF SWD -CommanderScript jlink.jlink$(Q)$(RM) jlink.jlinkcommit:$(Q)git add .$(Q)echo read -p \"Please input git commit explain:\" explain > git.so$(Q)echo if test -z \"\$$explain\"\; then explain=\"Daily development submission\"\; fi >> git.so$(Q)echo echo \$$explain >> git.so$(Q)echo git commit -m \"'$$'explain\" >> git.so$(Q)bash ./git.so$(Q)$(RM) git.so$(Q)git pushinclude $(wildcard $(BUILD)/Obj/*.d)
使用方法:
1,根目录下执行make指令,即可编译出.hex .bin .elf文件
2,执行make clean,可清除.o .d文件
3,执行make cleanAll,可清除.o .d .hex .bin .elf文件
4,执行make download,可一键下载hex到目标板子并让板子复位运行,相当于keil的一键下载按钮(推荐使用JFLASH烧写)
5,执行make commit,可一键推送到你的github或者giteee远程服务器上去,但前提是你自己创建了这个工程的git
至此,在vscode的终端中输入下面指令即可编译:
vscode调试仿真
1. 准备VSD文件
安装好MDK5后,双击从gd官网下载的pack包,可以从下面路径得到解开的VSD文件。
2. vscode已经安装cortex debug插件
3. 创建launch.json文件
如下图所示:
如下图所示:
配置launch.json文件,修改下面红色粗体部分。
"version": "0.2.0",
"configurations": [
{
"name": "Cortex Debug",
"cwd": "${workspaceFolder}",
"executable": "${workspaceFolder}/build/main.elf",
"request": "launch",
"type": "cortex-debug",
"runToEntryPoint": "main",
"servertype": "jlink",
"device": "GD32F307VC",
"svdFile": "${workspaceFolder}/GD32F30x_HD.svd"
}
]
保存重启vscode。
至此即可在vscode中使用JLINK进行调试仿真了。