ARM学习(15)Makefile编译以及CortexM4命令行STLINK 烧录
笔者来聊聊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之后,继续+= 不存在的变量,结果就无法添加,说明其属性延续上面的:=
```shell
#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</code></pre>
<p>对比上面,Compiler=赋值,所以其+=之后,可以加上cc的变量的值</p>
<pre><code class="language-shell">#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</code></pre>
<p>关注DIR变量,如果其为定义,则按=处理,可以+上后面的定义的变量</p>
<pre><code class="language-shell">#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</code></pre>
<ul>
<li>变量的高级用法,多个变量后缀统一替换</li>
</ul>
<pre><code class="language-shell">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</code></pre>
<ul>
<li>变量的嵌套
<pre><code class="language-shell">A = $(B)
B = C
C = hello
D = $($(A))
all:
@echo $(D)
$ make -f makfile_test.mak
hello</code></pre></li>
<li>环境变量
<pre><code class="language-shell">
```
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=<id>/SN=<sn>] [JTAG/SWD] [FREQ=<frequency>] [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。
版权声明:
作者:ZhangYixi
链接:http://zyixi.xyz/arm%e5%ad%a6%e4%b9%a0%ef%bc%8815%ef%bc%89makefile%e7%bc%96%e8%af%91%e4%bb%a5%e5%8f%8acortexm4%e5%91%bd%e4%bb%a4%e8%a1%8cstlink-%e7%83%a7%e5%bd%95/
来源:一西站点
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论