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/
来源:一西站点
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
< <上一篇
下一篇>>
文章目录
关闭
目 录