你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验之谈】基于STM32在vscode下用stm32+makefile+gcc实现一键编译仿真下载的经验分享

[复制链接]
STMCU小助手 发布时间:2022-12-11 15:29

生命在于运动,技术在于折腾,你是否厌倦了在keil、iar下孜孜不倦的写代码、debug,是否玩累了在外部编辑器下写代码,然后在转到ide下进行仿真、下载等操作呢?
6 Z6 `5 C+ |" C6 k$ Z; \
1 f3 R; G9 V- O9 B. r, f. b这个教程将介绍下如何在vscode下实现这些操作,真正实现一个vscode可以吃天下、实现一键编译仿真下载,而你只需要在vscode下的终端敲几个命令而已。。。


% M1 w; q# O7 N$ v0 a/ q& ~本教程以阿波罗开发板stm32f429igt6为例,先瞅瞅最终界面* D! d1 O2 T! x# u* @- ]
1 A3 h0 Z6 I' A) q6 P( y$ z/ d
最终可以用的功能如下:$ \" c# B' `3 [. R$ h' ?
1,vscode终端下执行make指令,即可在build文件下编译出.hex .bin .elf文件,中间文件放在build/Obj/文件夹下: ?- Q% F& ~/ U$ G, x
2,执行make clean,可清除build文件夹
4 Q" u8 z7 K* t# @: ^  f3 d2 G3,执行make download,可一键下载hex到目标板子并让板子复位运行,相当于keil的一键下载按钮
: g) v0 W5 u: M; R! D; q4,执行make reset,可以让板子复位运行一下: w9 ]; m7 \7 V* n: C
5,执行make commit,可一键推送到你的github或者giteee远程服务器上去,但前提是你自己创建了这个工程的git
2 x$ {8 O- Z9 @& b0 H% N4 d教程如下:
) w/ s9 b: p, ^) y$ Y( c+ W环境:  }0 G( a$ h( p+ L/ `: J2 s
1,下载vscode及必要插件,令需要一个插件Cortex_debug
! y5 `, P+ ]4 a. V2,Windows下安装arm-none-eabi-gcc工具链,推荐q4版本
. f/ X) |! k5 W3,Windows下安装Jlink最新版驱动(V6.88a)
# M2 s& t7 E3 W  S3 A% W3 }5 G安装、下载的教程也在上面的链接。
; o8 m/ m/ e# ~5 ~+ R* |$ e4,GNU make! R4 [: Z' j- J" q: n8 @
百度网盘链接和安装教程、添加环境变量教程也在上边的链接。。。
' g2 Z: C* E. E) A( {5,git bash3 |& N# ^1 ]. k$ q: q8 t9 r+ {
这个不用说,大家都会有的吧,然后需要把vscode的终端换成git bash。百度一下,太容易了。
. c9 B; M. H$ t( M好了,环境就搭好了,不要嫌麻烦,现在越麻烦,你用起来越方便!
  Y. q% n  I4 b. z1 T! l" V$ H+ B编译:, H* N7 w+ L+ L$ h
编译只需在vscode终端中执行make指令就行,如下图:


7 U& }7 M/ n, d- {" f; I; |! d* P. ^: j4 ?4 [. X

1 @+ `% w, n7 q! q" @( u# `

仿真:
' @& _7 j* E+ K+ `9 D仿真的话需要vscode下的插件cortex debug,这个教程我粘贴上我之前写的国产芯片fm33lc02x的教程,大家只要把芯片名字换成STM32F429就行
' v! h8 ^6 z6 D0 |, F( s4 K(1) vscode下载插件cortex debug插件

(2) 创建launch.json文件

如下图所示:

6 M( Q) e3 ?$ i. R" `0 Z" j% k* x% F

: O* k6 B3 I( |. X- ]5 a

然后选择Cotrex Debug即可创建好launch.json文件

. M; n( |4 s9 A/ d

(3) 配置launch.json文件

稍微按照自己的芯片修改下就好,以FM33LC026为例:

. H1 e- Q8 p/ a8 k* k3 [

. E$ ~8 z9 P+ f

然后将厂商提供的.svd文件放到你的工程根目录即可开始仿真,可以看变量、看外设寄存器、内核寄存器等等,还可以保存你的断点等。

然后实现这一切的核心就是makefile文件,不用管,我已经帮你写好了,而且全部中文注释,各种参数也是取自stm32cube的makefile参数,放心的用,放心的学!

然后我将在附件提供一个基于阿波罗开发板stm32f429igt6的点灯例程。如果的芯片不是stm32f429,但只要你的核是arm核,本例程本makefile,通通能用!

& y( c' h! G  T* Q5 Q$ x

换芯片后你需要改以下内容:

1,找到你的芯片的基于gcc的启动文件和链接脚本,一般问厂商要肯定有的,不用自己写,然后替换到根目录下的2个对应文件


. ]' j! B+ w9 r8 [4 D1 O+ b3 h& {2 m+ l

% T9 S0 o! ?. C1 W" `5 Q) h! [: \2,改以下内容,是不是看起来特简单。) b0 A% b! ^- w: C
, N6 z3 d. S) ~. ]) u. y
然后,就搞定了,具体的参数可以去stm32cube上生成一个对应内核的makefile,然后参考下就行了,其实其他核是更简单的。教程可能有点乱,后期我会在整理下。# f! [1 S& g6 n* l1 }% S
& `" f( X' X2 `4 C
最后附上我的整个makefile

#*************************************************************************

#  **

#  ** File         : Makefile

#  ** Abstract     : This is the introduction to the document

#  ** Author       : wr

#  ** mail         : 791314247@q.com

#  ** Created Time : 2020年11月22日星期日 11时58分06秒

#  ** copyright    : COPYRIGHT(c) 2020

#  **

#  ************************************************************************/

: @& O$ B9 O3 o

ifneq ($(V),1)

Q := @

else

Q :=

endif

" h5 h  d9 f: _* g3 k1 k8 @

################################以下项目需用户根据需要更改##########################

# 输出文件的名称,默认为main(main.elf main.bin main.hex)

TARGET := main

) F; I7 d1 S$ ^$ }6 s

#链接文件名称和所在路径

LDSCRIPT := ./STM32F429IGTx_FLASH.ld


  `2 V% i7 k  }, {0 F2 F( q

#启动文件名称和所在路径

START_FILE_SOURCES := ./startup_stm32f429xx.s


. _9 E/ r, W% Z8 u& c; ~# C1 `1 ^

#内核选择,FPU, FLOAT-ABI可为空

CPU       := -mcpu=cortex-m4

FPU       := -mfpu=fpv4-sp-d16

FLOAT-ABI := -mfloat-abi=hard


: G9 K# O; d: i0 T( @  i8 t& Z7 x1 `3 P  y

#系统宏定义

C_DEFS    := \

-DUSE_HAL_DRIVER \

-DSTM32F429xx

. J7 k# Y5 K# i( L3 z2 a' N( n2 c

# 芯片型号,用于Jlink仿真调试、下载

CHIP      := STM32F429IG

! f) `% l) t$ X6 s

# 选择优化等级:

# 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 命令来查询。

OPT       := -Og

5 I9 H+ W. c2 o' \

# 是否将debug信息编译进.elf文件,默认打开

DEBUG     := 1

9 L& \- V, ?" @

# 输出文件夹,.hex .bin .elf放在此文件夹下,.o .d文件放在此文件的子目录Obj下(自动创建)

BUILD     := ./build

  ]8 x" [5 L% r6 Z& L! b

# 支持双系统编译,故需选当前系统,0为linux,1为windows

SYS    := 1

# 若指定了windows系统,则需确认编译器的路径,若安装时以默认路径安装,则正确

ifeq ($(SYS), 1)

GCC_PATH = "/c/Program Files (x86)/GNU Tools Arm Embedded/9 2019-q4-major/bin"

JLINK_PATH = "/c/Program Files (x86)/SEGGER/JLink"

endif

###################################用户修改结束###################################


' x4 b  T9 q3 q  K) C/ g1 ~

# 编译器定义

PREFIX = arm-none-eabi-

ifdef GCC_PATH

SUFFIX = .exe

CC      := $(GCC_PATH)/$(PREFIX)gcc$(SUFFIX)

SZ      := $(GCC_PATH)/$(PREFIX)size$(SUFFIX)

OBJCOPY := $(GCC_PATH)/$(PREFIX)objcopy$(SUFFIX)

GDB     := $(GCC_PATH)/$(PREFIX)gdb$(SUFFIX)

BIN     := $(OBJCOPY) -O binary -S

HEX     := $(OBJCOPY) -O ihex

else

CC      := $(PREFIX)gcc

SZ      := $(PREFIX)size

OBJCOPY := $(PREFIX)objcopy

GDB     := $(PREFIX)gdb

BIN     := $(OBJCOPY) -O binary -S

HEX     := $(OBJCOPY) -O ihex

endif


3 q! Q' I3 Q3 I; Q4 ^4 b4 e

# Jlink定义,用于支持一键下载和gdb仿真

ifdef JLINK_PATH

SUFFIX = .exe

JLINKEXE       := $(JLINK_PATH)/JLink$(SUFFIX)

JLINKGDBSERVER := $(JLINK_PATH)/JLinkGDBServer$(SUFFIX)

else

JLINKEXE       := JLinkExe

JLINKGDBSERVER := JLinkGDBServer

endif

) K4 `/ E# P, y5 q, ?

* g9 {3 g- D  `7 }6 r% J% l* T' u9 b

#################### CFLAGS Config Start ##########################

MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)

* V- T5 ]  W+ I  x$ F

#搜索所有的h文件,并输出携带-I的.h文件路径

C_INCLUDES := $(addprefix -I,$(subst ./,,$(sort $(dir $(shell find ./ -type f -iname "*.h")))))

# q' a9 F: @; y9 v8 _

#编译参数

CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -fdata-sections -ffunction-sections

#开关警告

CFLAGS += -Wall -W -Wno-unused-parameter

#标准

CFLAGS += -std=c99

9 z- T5 k. d5 [2 m7 Z: Q5 V: f! ^# F

#当开启DEBUG功能时携带DEBUG参数

ifeq ($(DEBUG), 1)

CFLAGS += -g -gdwarf-2

endif


' T9 Z( `; j0 C2 p

#自动生成依赖文件

CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

#################### CFLAGS Config End ##########################

% M1 O& Q9 X; {+ ~% w, P

# 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 += -Wl,--gc-sections

$ i! x! r; m! D

#制作启动文件依赖Obj,输出去掉路径的.o文件,可兼容.s和.S

START_FILE_OBJ     = $(addsuffix .o, $(basename $(notdir $(START_FILE_SOURCES))))

OBJECTS            = $(addprefix $(BUILD)/Obj/, $(START_FILE_OBJ))

( a4 R( ^% u# q4 Q7 b

#搜索所有的c文件,制作所有的.c文件依赖Obj

C_SOURCES          = $(subst ./,,$(shell find ./ -type f -iname "*.c"))

OBJECTS           += $(addprefix $(BUILD)/Obj/, $(notdir $(C_SOURCES:%.c=%.o)))

#PS:去掉终极目标的原始路径前缀并添加输出文件夹路径前缀(改变了依赖文件的路径前缀,需要重新指定搜索路径)

+ r* A) S# _8 j2 f& t. ^* M

#指定makefile搜索文件的路径(假如终极目标的依赖文件不携带.c文件所在的路径,

#且不指定搜索路径,makefile会报错没有规则制定目标)

vpath %.c $(sort $(dir $(C_SOURCES)))  #取出路径并去重和排序(以首字母为单位)

vpath %.s $(dir $(START_FILE_SOURCES))

vpath %.S $(dir $(START_FILE_SOURCES))

& `- S. v4 Q7 f7 P2 _4 V. p
3 @! X  u! ~2 }7 e

#指定为伪目标跳过隐含规则搜索,提升makefile的性能,并防止make时携带的参数与实际文件重名的问题

.PHONY:all clean printf JLinkGDBServer debug download reset commit


8 G/ b& t2 \7 w5 {" [0 S: e( @

all : $(BUILD)/$(TARGET).elf $(BUILD)/$(TARGET).bin $(BUILD)/$(TARGET).hex


3 |; `- P- _/ }) k0 X. w5 ^* f( f, E$ P; s

#链接所有的.o生成.elf文件

$(BUILD)/$(TARGET).elf : $(OBJECTS) | $(LDSCRIPT)

        $(Q)$(CC) $(LDFLAGS) -o $@ $(OBJECTS)

        $(Q)echo "make $@:"

        $(Q)$(SZ) $@

  ?5 u& t& z( J) ?' _

7 B3 x% }, O8 n8 L6 g2 i

#编译启动文件备用参数:#-x assembler-with-cpp

$(BUILD)/Obj/$(START_FILE_OBJ) : $(START_FILE_SOURCES) Makefile | $(BUILD)/Obj

        $(Q)echo "buid $(subst ./,,[        DISCUZ_CODE_34        ]lt;)"

        $(Q) $(CC) -c $(CFLAGS) -o $@ [        DISCUZ_CODE_34        ]lt;


6 y6 Z; ?) m/ ^# v, j- r: u

#编译工程

$(BUILD)/Obj/%.o : %.c Makefile | $(BUILD)/Obj

        $(Q)echo "buid $(subst ./,,[        DISCUZ_CODE_34        ]lt;)"

        $(Q) $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(@:%.o=%.lst) -o $@ [        DISCUZ_CODE_34        ]lt;

* p2 g8 ^: R0 P: y5 D

$(BUILD)/Obj :

        $(Q)mkdir -p $@

        $(Q)echo "mkdir $@"


( M& x& o; c; N9 x

%.bin : $(BUILD)/$(TARGET).elf

        $(Q) $(BIN) [        DISCUZ_CODE_34        ]lt; $@

        $(Q)du -h $(BUILD)/$(TARGET).bin

, f, T& L, H+ S

%.hex : $(BUILD)/$(TARGET).elf

        $(Q) $(HEX) [        DISCUZ_CODE_34        ]lt; $@

$ m2 J  ^& Q; D

#用于检查链接脚本和启动文件是否存在,不存在则报错误

$(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 2

  k9 {3 e' k: [' ]! ^

clean:

        $(RM) -rf $(BUILD)

6 u. ~- z8 z/ w: [% f  b7 b

printf:

        $(Q)echo $(info $(LDFLAGS))


) C1 N/ ^4 Q2 ^1 q5 V
6 }/ @5 I( Y! U- m# J9 h

JLinkGDBServer:

        $(Q)JLinkGDBServer -select USB -device $(CHIP) \

        -endian little -if SWD -speed 4000 -noir -LocalhostOnly

* u. u1 E2 G6 Z8 D1 @- |

debug:

        $(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.gdb

: a: H) B' Z$ ~* y8 G

download:

        $(Q)make

        $(Q)echo "h" > jlink.jlink

        $(Q)echo "loadfile" $(BUILD)/$(TARGET).hex >> 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.jlink

' \; u- V# O& v! k0 F% |( F

reset:

        $(Q)echo "r" >> jlink.jlink

        $(Q)echo "qc" >> jlink.jlink

        $(Q)$(JLINKEXE) -device $(CHIP) -Speed 4000 -IF SWD -CommanderScript jlink.jlink

        $(Q)$(RM) jlink.jlink

) m' j7 a6 }  j6 v5 x) G! H+ W

commit:

        $(Q)git add .

        $(Q)status='$(shell git status | grep "git pull")';\

        if test -n "$status";then echo "Need to do git pull !";exit 10;fi

        $(Q)explain='$(shell read -p "Please input git commit explain:" explain;echo "$explain")';\

        if test -z "$explain";then git commit -m "Daily development submission"; \

        else git commit -m "$explain";fi

        $(Q)git push

        $(Q)git status


% n  ?# n/ x6 N

-include $(wildcard $(BUILD)/Obj/*.d)! T$ N& |# d% Q$ f
---------------------5 Q! u9 M9 S$ R8 N; J$ A/ F* u$ Z
作者:791314247

+ z2 t4 q6 Y, ]8 i" W2 f9 O: d) r
赞 收藏 评论0 发布时间:2022-12-11 15:29

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版