ARM学习(15)Makefile编译以及CortexM4命令行STLINK 烧录

32 篇文章 32 订阅

笔者来聊聊Makefile编译以及CortexM4命令行STLINK 烧录

1、简单Makefile编译STM32工程

先放一个笔者的makefile工程,笔者之前介绍过一个makefile语法,不过比较简单。

# ###########################################################
# File  : makfile for project compiler
# Author: guoqing.zhang
# date  : 2022/11/20
###########################################################

# Target
TARGET = AdvancedClock
DEBUG = -O2

# directoty for compiler object file
BUILD_OBJ_DIR  :=obj
BUILD_DEP_DIR  :=dep
OUT_DIR    :=out

# directoty for compiler source file
CORE       := ../Core
DRIVER     := ../Driver
SOURCECODE := ../SourceCode

# source file path
C_SOURCE = \
$(wildcard $(CORE)/*.c)  				\
$(wildcard $(DRIVER)/src/misc.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_adc.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_dac.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_dma.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_dma2d.c)  		\
$(wildcard $(DRIVER)/src/stm32f4xx_exti.c)  		\
$(wildcard $(DRIVER)/src/stm32f4xx_flash.c)  		\
$(wildcard $(DRIVER)/src/stm32f4xx_gpio.c)  		\
$(wildcard $(DRIVER)/src/stm32f4xx_iwdg.c)  		\
$(wildcard $(DRIVER)/src/stm32f4xx_pwr.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_rcc.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_rtc.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_spi.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_syscfg.c)  		\
$(wildcard $(DRIVER)/src/stm32f4xx_tim.c)  			\
$(wildcard $(DRIVER)/src/stm32f4xx_usart.c)  		\
$(wildcard $(DRIVER)/src/stm32f4xx_wwdg.c)  		\
$(wildcard $(SOURCECODE)/*.c)  			\
$(wildcard $(SOURCECODE)/bluetooth/*.c) \
$(wildcard $(SOURCECODE)/cJson/*.c)  	\
$(wildcard $(SOURCECODE)/common/*.c)  	\
$(wildcard $(SOURCECODE)/ht_sensor/*.c)  \
$(wildcard $(SOURCECODE)/key/*.c)  		\
$(wildcard $(SOURCECODE)/led/*.c)  		\
$(wildcard $(SOURCECODE)/msg_deal/*.c)  \
$(wildcard $(SOURCECODE)/nrf24l01/*.c)  \
$(wildcard $(SOURCECODE)/oled/*.c)  	\
$(wildcard $(SOURCECODE)/queue/*.c)  	\
$(wildcard $(SOURCECODE)/rtc/*.c)  		\
$(wildcard $(SOURCECODE)/timer/*.c)  	\
$(wildcard $(SOURCECODE)/uart/*.c)  	\
$(wildcard $(SOURCECODE)/wdg/*.c)  		\
$(wildcard $(SOURCECODE)/wifi/*.c)  	\
$(wildcard $(SOURCECODE)/show/*.c)  	

# asm source file path
ASM_SOURCE = \
$(wildcard $(CORE)/startup_stm32f40_41xxx.s)  

# inlcude file path
C_INCLUDE  =							\
-I$(CORE)/     							\
-I$(DRIVER)/inc/     					\
-I$(SOURCECODE)/     					\
-I$(SOURCECODE)/bluetooth/    			\
-I$(SOURCECODE)/cJson/    				\
-I$(SOURCECODE)/common/    				\
-I$(SOURCECODE)/key/    				\
-I$(SOURCECODE)/ht_sensor/    			\
-I$(SOURCECODE)/led/    				\
-I$(SOURCECODE)/msg_deal/    			\
-I$(SOURCECODE)/nrf24l01/    			\
-I$(SOURCECODE)/oled/    				\
-I$(SOURCECODE)/queue/    				\
-I$(SOURCECODE)/radio/    				\
-I$(SOURCECODE)/rtc/    				\
-I$(SOURCECODE)/timer/    				\
-I$(SOURCECODE)/uart/    				\
-I$(SOURCECODE)/wdg/    				\
-I$(SOURCECODE)/wifi/    				\
-I$(SOURCECODE)/show/    				\

# compiler exe 
CC_EXEC := armcc.exe 
AR_EXEC := armar.exe
ASM_EXEC := armasm.exe
LINK_EXEC := armlink.exe
FROMELF_EXEC := fromelf.exe
DOWNLOAD_EXEC := ST-LINK_CLI.exe

RM   := rm -rf 
ECHO := echo


CMN_CFLAGS = --C99 -c --cpu Cortex-M4.fp.sp -g --apcs=interwork --split_sections \
$(DEBUG) $(C_INCLUDE)  \
--diag_suppress=1295,111,1293,167,513,177 \
-ID:/Software/Keil/pack/Keil/STM32F4xx_DFP/2.13.0/Drivers/CMSIS/Device/ST/STM32F4xx/Include \
-D__UVISION_VERSION="537"    \
-DSTM32F405xx \
-DSTM32F40_41xxx \
-DUSE_STDPERIPH_DRIVER \

CMN_AFLAGS = --cpu Cortex-M4.fp.sp -g --apcs=interwork \
-I D:\Software\Keil\pack\Keil\STM32F4xx_DFP\2.13.0\Drivers\CMSIS\Device\ST\STM32F4xx\Include \
--pd "__UVISION_VERSION SETA 537" --pd "STM32F405xx SETA 1" \

LINK_SCRIPT := AdvanceClock.sct
CMN_LFLAGS = --cpu Cortex-M4.fp.sp \
--strict --scatter $(LINK_SCRIPT)


# compiler objects
OBJECTS  = $(addprefix $(BUILD_OBJ_DIR)/,$(notdir $(C_SOURCE:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCE)))

OBJECTS  += $(addprefix $(BUILD_OBJ_DIR)/,$(notdir $(ASM_SOURCE:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCE)))



$(OUT_DIR)/$(TARGET).axf: $(OBJECTS) 
	@$(ECHO) Link $@ ...
	@$(LINK_EXEC) $(OBJECTS) $(CMN_LFLAGS) -o $@ --map --info totals --list_mapping_symbols --list=$(OUT_DIR)/$(TARGET).map 
	@$(FROMELF_EXEC) --bin --output $(OUT_DIR)/$(TARGET).bin $@

$(BUILD_OBJ_DIR)/%.o : %.s Makefile | $(BUILD_OBJ_DIR)
	@$(ECHO) 'Compiling' $<
	@$(ASM_EXEC)  $(CMN_AFLAGS) $< -o $@ 

# compiler process
$(BUILD_OBJ_DIR)/%.o : %.d Makefile | $(BUILD_DEP_DIR)
$(BUILD_OBJ_DIR)/%.o : %.c Makefile | $(BUILD_OBJ_DIR)
	@$(ECHO)  'Compiling' $<
	@$(CC_EXEC) -c  $(CMN_CFLAGS) $< -o $@ 

$(BUILD_DEP_DIR)/%.d : OBJ_BNAME=$(basename $(notdir $@)) 
$(BUILD_DEP_DIR)/%.d : %.c Makefile | $(BUILD_DEP_DIR)
	$(CC_EXEC) -M   $(CMN_CFLAGS) $< -o $(BUILD_OBJ_DIR)/$(OBJ_BNAME).o > $@
	$(CC_EXEC) -c   $(CMN_CFLAGS) $< -o $(BUILD_OBJ_DIR)/$(OBJ_BNAME).o


$(OUT_DIR):
	mkdir $@

$(BUILD_OBJ_DIR):
	mkdir $@

$(BUILD_DEP_DIR):
	mkdir $@

# dwonload 
flash:
	$(DOWNLOAD_EXEC) -c -SE 0 4  -V "while_programming" -P $(OUT_DIR)/$(TARGET).bin 0x08000000
	$(DOWNLOAD_EXEC) -Rst

# clean 
clean:
	$(RM) obj/*
	$(RM) out/*

1.1 makefile 变量

简单接着上面的makefile,看一下变量的定义,变量的引用需要加$符号,建议加()或者{}

  • = 为常见的变量赋值,左侧是变量,右边是变量的值,值得说的是:右侧变量的值可以是后面定义的值
# makfile_test.mak 
Target = $(Target_def)
Target_def  = AdvancedClock

all:
	@echo $(Target)

13952@DESKTOP-91JBMMS MINGW64 /d/Workspace/DesignProject/AdvancedClock/Advanced-Clock/Advanced Clock Project/Advanced Clock1027/Advanced Clock Project/build (feature/code-clear)
$ make -f makfile_test.mak 
AdvancedClock

但是其也有一个不好的地方,假如两个变量互相赋值,则会造成make编译比较慢,但幸好的是make可以检测这样的错误

# makfile_test.mak 
Target = $(Target_def)
Target_def  = AdvancedClock


Dependency = $(Module) 
Module = $(Dependency)

all:
	@echo $(Target)
	@echo $(Module)

$ make -f makfile_test.mak 
makfile_test.mak:8: *** Recursive variable `Module' references itself (eventually).  Stop.

上面那种错误就可以:= 解决。

  • :=,其赋值只是是前面定义好的值,如果没有定义,那么该值就是空,相当于没有赋值。
Target = $(Target_def)
Target_def  = AdvancedClock


Dependency := $(Module) 
Module := $(Dependency)

all:
	@echo $(Target)
	@echo $(Module)

$ make -f makfile_test.mak 
AdvancedClock

  • ?= 如果该变量没有赋值,就赋值成右值,否则,就不赋值
Target = $(Target_def)
Target_def  = AdvancedClock


Dependency := $(Module) 
Module := $(Dependency)

Target ?= 123456

all:
	@echo $(Target)
	@echo $(Module)
	
$ make -f makfile_test.mak 
AdvancedClock

如果变量没有定义,那么就赋值,采用=赋值,所以只要定义过,就可以被赋值

#Target = $(Target_def)
Target_def  = AdvancedClock


Dependency := $(Module) 
Module := $(Dependency)

Target ?= $(Compiler)


Compiler := armcc
all:
	@echo $(Target)
	@echo $(Module)

$ make -f makfile_test.mak 
armcc

  • += 如果之前没有被定义,就采用=赋值,如果之前是:=赋值,那么就是:+=,就是采用:=的赋值,如果之前是+=,那么之后就采用+=赋值。
    Compiler 为:=赋值,+= armclang之后,继续+= 不存在的变量,结果就无法添加,说明其属性延续上面的:=
#Target = $(Target_def)
Target_def  = AdvancedClock


#$(info HOMEPATH=$(HOMEPATH))
#$(info HOMEDRIVE=$(HOMEDRIVE))

Dependency := $(Module) 
Module := $(Dependency)

Target ?= $(Compiler)


Compiler := armcc

Compiler += armclang

Compiler += $(cc)

cc = gcc
all:
	@echo $(Target)
	@echo $(Module)
	@echo $(Compiler)
	
$ make -f makfile_test.mak 
armcc armclang

armcc armclang

对比上面,Compiler=赋值,所以其+=之后,可以加上cc的变量的值



#Target = $(Target_def)
Target_def  = AdvancedClock


#$(info HOMEPATH=$(HOMEPATH))
#$(info HOMEDRIVE=$(HOMEDRIVE))

Dependency := $(Module) 
Module := $(Dependency)

Target ?= $(Compiler)


Compiler = armcc

Compiler += armclang

Compiler += $(cc)

cc = gcc
all:
	@echo $(Target)
	@echo $(Module)
	@echo $(Compiler)
	
$ make -f makfile_test.mak 
armcc armclang gcc

armcc armclang gcc

关注DIR变量,如果其为定义,则按=处理,可以+上后面的定义的变量

#Target = $(Target_def)
Target_def  = AdvancedClock


#$(info HOMEPATH=$(HOMEPATH))
#$(info HOMEDRIVE=$(HOMEDRIVE))

Dependency := $(Module) 
Module := $(Dependency)

Target ?= $(Compiler)


Compiler = armcc

Compiler += armclang

Compiler += $(cc)

cc = gcc

DIR += $(C_DIR)

C_DIR = /123
all:
	@echo $(Target)
	@echo $(Module)
	@echo $(Compiler)
	@echo $(DIR)

$ make -f makfile_test.mak 
armcc armclang gcc

armcc armclang gcc
D:/Software/MinGW/msys/1.0/123
  • 变量的高级用法,多个变量后缀统一替换
src_file = 1.c 2.c 3.c

object = $(src_file:%.c=%.o)

all:
	@echo $(object)

$ make -f makfile_test.mak 
1.o 2.o 3.o
  • 变量的嵌套
A = $(B)
B = C
C = hello 
D = $($(A))

all:
	@echo $(D)
$ make -f makfile_test.mak 
hello
  • 环境变量

1.2 makefile 关键字

1.3 makefile 自动推导

2、ST-Link命令行烧录

对于ST的芯片来说,其支持ST-Link烧录(走SWD协议)同时也支持JLink,其他厂商的芯片通常都是用JLink(支持Jtag协议来烧录)。

使用命令行来进行烧录,完全就是为了自动化进行,图形界面毕竟需要自己去点,

2.1 常见的界面烧录方式

常见的烧录方式比如

  • keil IDE 烧录

在这里插入图片描述

  • IAR IDE 烧录

  • STLINK-Unity 图形界面烧录
    在这里插入图片描述

  • Ozone 调试软件烧录
    在这里插入图片描述
    在这里插入图片描述

  • JFlash 去烧录
    在这里插入图片描述

2.1 STLink CLI 命令行烧录方式

废话不多说,直接上命令行的烧录方式。

ST-LINK_CLI.exe -c -SE 0 4  -V "after_programming" -P out/AdvancedClock.bin 0x08000000
  • -c:连接指令,命令格式:-c [ID=/SN=] [JTAG/SWD] [FREQ=] [UR/HOTPLUG] [LPM]
    • JTAG/SWD: JTAG还是SWD协议连接
    • UR/HOTPLUG: 连接后复位,还是连接后程序还是正常运行(热连接)
    • FREQ:通信频率
    • LPM:低功耗模式
ST-LINK_CLI.exe -c HOTPLUG

ST-LINK SN: 213E03002C135737334D4E00
ST-LINK Firmware version: V2J38S7
Connected via SWD.
SWD Frequency = 4000K.
Target voltage = 3.2 V
Connection mode: **HotPlug**
Reset mode: Software reset
Device ID: 0x413 
Device flash Size: **1024 Kbytes**
Device family: **STM32F405xx/F407xx/F415xx/F417xx**

连接后可以看到:连接后的MCU的 Flash Size、MCU的类型,以及MCU的ID等。

  • -SE:命令格式:-SE <开始sector> <结束sector>。擦除sector,每个sector 16K,地址从0x0800 0000开始,所以0表示第0个sector,0 4表示擦除从sector 0到sector 4。所以总的擦除大小就是16K*5=80K,具体的大小可根据bin的大小来定。
Memory Sector @0x08000000 erased
Memory Sector @0x08004000 erased
Memory Sector @0x08008000 erased
Memory Sector @0x0800C000 erased
Memory Sector @0x08010000 erased

笔者系列的STM32系列为405,Flash空间为1MB。
  • -V:该参数表示编程成功后进行校验是否正确写入,可跟参数:
    • “after_programming”:表示编程后,再读取出来进行校验。
    • “while_programming”:表示编程中进行校验。
  • -P:命令格式:-P <bin文件路径> <写入地址>

还有其他的命令,

  • -CoreReg:读取MCU寄存器,
$ ST-LINK_CLI.exe -c HOTPLUG -Halt -CoreReg

STM32 ST-LINK CLI v3.6.0.0
STM32 ST-LINK Command Line Interface

ST-LINK SN: 213E03002C135737334D4E00
ST-LINK Firmware version: V2J38S7
Connected via SWD.
SWD Frequency = 4000K.
Target voltage = 3.2 V
Connection mode: HotPlug
Reset mode: Software reset
Device ID: 0x413 
Device flash Size: 1024 Kbytes
Device family: STM32F405xx/F407xx/F415xx/F417xx

R0   = 0x00000000
R1   = 0x00000001
R2   = 0x00000082
R3   = 0x20000094
R4   = 0x40013000
R5   = 0x00000007
R6   = 0x00000000
R7   = 0x00000000
R8   = 0x00000000
R9   = 0x00000000
R10  = 0x08009C60
R11  = 0x00000000
R12  = 0x00000000
R13  = 0x2001A510
R14  = 0x08003C1F
APSR = 0x60000000
IPSR = 0x00000000
EPSR = 0x01000000
MSP  = 0x2001A510
PSP  = 0x00000000
XPSR = 0x61000000
PC   = 0x08003C16
  • -Halt:停住CPU,但是笔者多次尝试,显示有日志,但是程序继续运行
$ ST-LINK_CLI.exe -c HOTPLUG -Halt 

STM32 ST-LINK CLI v3.6.0.0
STM32 ST-LINK Command Line Interface

ST-LINK SN: 213E03002C135737334D4E00
ST-LINK Firmware version: V2J38S7
Connected via SWD.
SWD Frequency = 4000K.
Target voltage = 3.2 V
Connection mode: HotPlug
Reset mode: Software reset
Device ID: 0x413 
Device flash Size: 1024 Kbytes
Device family: STM32F405xx/F407xx/F415xx/F417xx
  • -r8:命令格式:-r8 <地址> <长度>
$ ST-LINK_CLI.exe -c HOTPLUG -r8 0x08000000  0x32


STM32 ST-LINK CLI v3.6.0.0
STM32 ST-LINK Command Line Interface

ST-LINK SN: 213E03002C135737334D4E00
ST-LINK Firmware version: V2J38S7
Connected via SWD.
SWD Frequency = 4000K.
Target voltage = 3.2 V
Connection mode: HotPlug
Reset mode: Software reset
Device ID: 0x413 
Device flash Size: 1024 Kbytes
Device family: STM32F405xx/F407xx/F415xx/F417xx


0x08000000 : 68  A5  01  20  1D  03  00  08  F9  2B  00  08  11  27  00  08
0x08000010 : 41  2B  00  08  B9  21  00  08  19  4D  00  08  00  00  00  00
0x08000020 : 00  00  00  00  00  00  00  00  00  00  00  00  AF  3C  00  08 
0x08000030 : B5  23
  • -ME:全部擦除Flash。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张一西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值