STM32裸机编程指南-4
系列目录
- STM32裸机编程指南-1,存储和寄存器相关知识
- STM32裸机编程指南-2,更易读的外设寄存器编程
- STM32裸机编程指南-3,启动代码和向量表
- STM32裸机编程指南-4,Makefile构建自动化
- STM32裸机编程指南-5,闪烁LED
- STM32裸机编程指南-6,用SysTick中断实现闪烁
- STM32裸机编程指南-7,添加串口调试输出
- STM32裸机编程指南-8,重定向
printf()
到串口 - STM32裸机编程指南-9,用Segger Ozone进行调试
- STM32裸机编程指南-10,供应商CMSIS头文件
- STM32裸机编程指南-11,配置时钟
- STM32裸机编程指南-12,带设备仪表盘的网络服务器
Makefile:构建自动化
我们可以用 make
命令行工具替代手动敲入“编译”、“链接”、“烧写”这些命令,自动完成整个过程。make
工具使用一个名为 Makefile
的配置文件,从中读取执行动作的指令。这种自动化方式非常棒,因为这样可以把构建固件的过程、使用了哪些编译标记等也文档化。
在 https://makefiletutorial.com 上有一个非常好的给初学者的Makefile教程,强烈建议看一下。下面我将列出一些非常必要的概念以理解我们所使用的Makefile。对于已经很熟悉 make
的朋友,可以跳过这一部分。
其实 Makefile
的格式并不复杂:
1 | action1: |
现在我们可以跟动作名(也被称作目标)一起调用 make
来执行相应的动作:
1 | $ make action1 |
当然,也可以在命令中定义和使用变量,动作也可以是需要创建的文件名:
1 | firmware.elf: |
任何动作都可以有一个依赖列表。例如,firmware.elf
依赖源文件 main.c
,当 main.c
改变时,make build
就会重新构建 firmware.elf
:
1 | build: firmware.elf |
我们已经准备好为固件编写 Makefile
,定义一个 build
动作/目标:
1 | CFLAGS ?= -W -Wall -Wextra -Werror -Wundef -Wshadow -Wdouble-promotion \ |
在这里我们定义了一些编译标记。?=
表示这是默认值,我们可以在命令行中覆盖它们,像这样:
1 | $ make build CFLAGS="-O2 ...." |
上面的 Makefile
文件中定义了 CFLAGS
、LDFLAGS
、SOURCES
变量,然后我们告诉 make
,当要 build
时创建 firmware.elf
文件,它依赖 main.c
文件,使用 arm-none-eabi-gcc
编译器和给定的编译标记生成它。$@
特殊变量会被展开成动作/目标名,在这个例子中是 firmware.elf
。
现在调用 make
试一下:
1 | $ make build |
如果我们再次运行:
1 | $ make build |
make
会检查 firmware.elf
和依赖项 main.c
的修改时间,如果是它们是最新的,则什么都不做。如果我们修改下 main.c
,则会重新构建:
1 | $ touch main.c # Simulate changes in main.c |
现在,还剩下“烧写”这个动作/目标:
1 | firmware.bin: firmware.elf |
OK,现在从终端中执行命令 make flash
就会创建 firmware.bin
文件,然后通过 st-link
烧入板子。当 main.c
改变时,这个命令也会重新构建,因为 firmware.bin
依赖 firmware.elf
,firmware.elf
又依赖 main.c
。所以我们的开发循环就是这样的两步:
1 | # Develop code in main.c |
还有一个良好实践就是在 Makefile
中添加 clean
动作,以删除构建生成的文件:
1 | clean: |
完整工程源码可以在 step-0-minimal 文件夹找到。