betaflight 代码结构参考:
betaflight 代码结构 - 哔哩哔哩 (bilibili.com)
Betaflight 的Makefile 体系与移植参考:
Betaflight 的Makefile 体系与移植 - 哔哩哔哩 (bilibili.com)
一、平台简介
AT32国产飞控最近比较火,佬儿出了一些关于BF飞控移植的文章,但不太详细。这里记录了本人学习BF飞控时关于Makefile部分的总结,留待参照。
AT32飞控实物:
**1.1 **AT32飞控参数
CPU: AT32VMT7
主频: 288MHz
引脚: 100 Pin(“V”)
Flash: 4032 KB(“M”)
RAM: 384 KB
内核:32位ARM® Cortex®-M4内核
*1.2 BF飞控运行*参考参数:
1、系统计算能力,主频在140mhz 以上(对比stm32f405)
2、系统内存在 128kb 以上,flash在 512kb 及以上,如果是spi集成外部flash,执行效率会下降2-3倍
**1.3 **电路接口:
- SBUS接收机 uart1_rx
二、开发工具
Betaflight源码地址:
https://github.com/flightng/atbetaflight
也可以使用百度网盘:
链接:https://pan.baidu.com/s/1JVMqFuiKKQpDiMzGRpQegg
提取码:6q86
开发工具为Ubuntu 18.04.6 + Vscode + arm-none-eabi-gcc 10.3.1
其中arm-none-eabi-gcc 安装可以参考:
STM32高级开发(5)-gcc-arm-none-eabi-CSDN博客
文章中arm-none-eabi-gcc的版本较低,可在arm官网下载该软件:
Downloads | GNU Arm Embedded Toolchain Downloads – Arm Developer
三、源码编译
使用vscode打开BF源码后,在第一次在终端输入make会出在报错且没有编译出obj文件夹,报错内容有git字样。
错误原因:
源码文件没有建立为git仓库。git使用可以网上搜索教程或者参考这个文档:
链接:https://pan.baidu.com/s/1RzRXGwTwV9UBXsOP8yaTkw
提取码:z624
问题解决:
(1)使用命令
git init
创建仓库
(2)使用
git add . (注意后面有个“.”)
将所有未跟踪文件加入暂存区
(3)使用
git commit -a
提交文件作为一个新版本,此后会出现版本名编辑窗口。
(4)输入版本名,如 1_read
ctrl + O 写入内容
回车,确定写入
ctrl + X 离开
(5)使用git status 可以查看当前仓库内容改变状态,
使用git log 可以查看所有历史版本:
(6)此时输入make命令,即可正常编译。编译完成会在obj文件夹下生成.hex文件:
三、Makefile详解
打开源码的主Makefile,从头开始,主Makefile文件的大致内容为(行数以实际为准):
(1)前置变量(~55)
默认构建目标
19: TARGET ?= AT32F437DEV
源目录
68: SRC_DIR := $(ROOT)/src/main
(2)对下级make文件的调用与前期设置(56~225)
主要调用./make ./src/main/target(/AT32F437DEV) 下的.mk文件
在源代码更改时需要维护的内容
(3)对编译工具的设置(226~311)
(4)编译目标设置(322 ~ 351)
(5)具体编译部分(352 ~ )
3.1 子makefile文件的引用与前置变量设置:
**3.1.1 **前置变量(~55)
默认构建目标
19: TARGET ?= AT32F437DEV
源目录
68: SRC_DIR := $(ROOT)/src/main
3.1.2 **** ./make/build_verbosity.mk
include $(ROOT)/make/build_verbosity.mk (80)
(1)功能设置冗余度
(2)变量:
V(命令行变量):
V : Set verbosity level based on the V= parameter
V=0 Low
V=1 High
AT := @ (makefile命令前加“@”不输出, 通过export递归传递到其他makefile中)
当命令行V=0,即输出短命令时,有变量:
export V0 := $(AT)
export V1 := $(AT)
export STDOUT:= "> /dev/null"
3.1.3 **** ./make/system-id.mk
include $(ROOT)/make/system-id.mk (84)
设置系统类型与电脑CPU架构
(1)引用变量:
UNAME: 操作系统名
ARCH: 电脑CPU架构
OSFAMILY: 操作系统名(小写)
3.1.4 **** ./make/checks.mk
include $(ROOT)/make/checks.mk (90)
代码检查
(1)目标:
checks
(2)变量:
VALID_TARGETS ?
**3.1.5 ****./make/linux.mk**
include $(ROOT)/make/$(OSFAMILY).mk (99)
配置系统环境
(1)如果有python3
PYTHON:=python3
(2)否则:
PYTHON_VERSION_ python版本号
PYTHON_MAJOR_VERSION_ python主版本号
PYTHON =python
(3)export PYTHON
**3.1.6 ****./make/tools.mk (?)**
(102)
安装编译工具?gcc-arm-none-eabi-10.3-2021.10
(1)变量:
命令行变量:
- TOOLS_DIR
编译工具所在位置
- ARM_SDK_PREFIX
SDK(软件开发工具)前缀
创建变量:
ARM_SDK_DIR
GCC_REQUIRED_VERSION
版本号
3.1.7 **** ./make/targets.mk
include $(ROOT)/make/targets.mk(122)
- 命令行变量
TARGET 对应的芯片(此处使用TARGET=AT32F437DEV)
**3.1.**8 ./src/main/target/AT32F437DEV/AT32F437DEV.mk
-include $(ROOT)/src/main/target/$(BASE_TARGET)/$(TARGET).mk (./make/targets.mk 12)
**3.1.**9 ./make/mcu/AT32F43x.mk
include $(ROOT)/make/mcu/$(TARGET_MCU).mk (173)
**3.1.**10 ./make/source.mk
include $(ROOT)/make/source.mk (224)
3.2 设置默认目标:
.DEFAULT_GOAL := hex (201)
注:
.DEFAULT_GOAL内置变量用来设置Makefile中的默认目标。 在所有的目标中,Makefile会首先执行“终极目标”,而若make命令中没有指定目标的话,.DEFAULT_GOAL指定的默认目标就是终极目标
3.3 执行hex默认目标(577)
hex:
@echo "make .hex have run"
$(V0) $(MAKE) -j $(TARGET_HEX)
3.4 make[1]: 进入目录“/home/embedfire/5_Projects/1_betaflight/4_read”
为执行$(V0) $(MAKE) -j $(TARGET_HEX)时寻找$(TARGET_HEX)目标所在Makefile的目录。
其后会依次对目标
$(TARGET_HEX) 353行 -》
$(TARGET_ELF) 411行 -》
$(TARGET_OBJS)
进行递归检测与更新, 其中 $(TARGET_OBJS)较为特殊
3.5 $(TARGET_OBJS)目标
对$(TARGET_OBJS)目标的更新的规则包括三部分。
(1)其一位于主Makefile 末尾705行,如下
$(TARGET_OBJS): Makefile $(TARGET_DIR)/target.mk $(wildcard make/*)
该规则表示是当Makefile(就是批主Makefile)、$(TARGET_DIR)/target.mk、$(wildcard make/*) 三部分文件更新时更新$(TARGET_OBJS)。(虽然这里没有关于$(TARGET_OBJS)目标更新的命令,但由于下面这一部分$(TARGET_OBJS)目标规则的存在,此处的规则并非没有意义。)
(2)其二位于主Makefile 433行,如下(在判断语句中$(DEBUG)为空)
$(OBJECT_DIR)/$(TARGET)/%.o: %.c
$(V1) mkdir -p $(dir $@)
……
(3)其三位于主Makefile 451、456行
$(OBJECT_DIR)/$(TARGET)/%.o: %.s
$(V1) mkdir -p $(dir $@)
@echo "%% $(notdir $<)" "$(STDOUT)"
$(V1) $(CROSS_CC) -c -o $@ $(ASFLAGS) $<
$(OBJECT_DIR)/$(TARGET)/%.o: %.S
$(V1) mkdir -p $(dir $@)
@echo "%% $(notdir $<)" "$(STDOUT)"
$(V1) $(CROSS_CC) -c -o $@ $(ASFLAGS) $<
为对.s、.S以汇编文件作为依赖的更新
这里$(OBJECT_DIR)/$(TARGET)/%.o与$(TARGET_OBJS)其实相同,都为./obj/main/AT32F437DEV及其递归目录下所有的.o文件,只是为了依次更新.o文件才如此写。(%表示文件名匹配,实测可以为/drivers/dma_at32f43x等递归目录下文件名)
综上所述,除(2)中%.c文件的更新会引起(2)中$(OBJECT_DIR)/$(TARGET)/%.o目标的更新命令外,(1)中Makefile的变更也会引起相同的更新命令(即(2)规则中的更新命令)。
3.6 将.S汇编文件编译为.o文件
该命令为$(TARGET_OBJS)目标命令的第三部分
位于主Makefile 451~456行,将.S文件编译为.o文件并放在.obj相关目录下(源码无.s文件),具体目录在$(TARGET_OBJS)变量中已经指定。
$(OBJECT_DIR)/$(TARGET)/%.o: %.s
$(V1) mkdir -p $(dir $@)
@echo "%% $(notdir $<)" "$(STDOUT)"
$(V1) $(CROSS_CC) -c -o $@ $(ASFLAGS) $<
$(OBJECT_DIR)/$(TARGET)/%.o: %.S
$(V1) mkdir -p $(dir $@)
@echo "%% $(notdir $<)" "$(STDOUT)"
$(V1) $(CROSS_CC) -c -o $@ $(ASFLAGS) $<
其中,$(ASFLAGS)为.s、.S文件的搜索目录,具体值参考《Makefile中各变量值》文件
3.7 将所有.c文件编译为.o文件
该命令为$(TARGET_OBJS)目标命令的第二部分
433~447行会将所有源文件中的.c文件编译为.o文件,并放在.obj的相关目录下,具体目录在$(TARGET_OBJS)变量中已经指定。
$(OBJECT_DIR)/$(TARGET)/%.o: %.c
$(V1) mkdir -p $(dir $@)
$(V1) $(if $(findstring $<,$(NOT_OPTIMISED_SRC)), \
$(call compile_file,not optimised,$(CC_NO_OPTIMISATION)) \
, \
$(if $(findstring $(subst ./src/main/,,$<),$(SPEED_OPTIMISED_SRC)), \
$(call compile_file,speed optimised,$(CC_SPEED_OPTIMISATION)) \
, \
$(if $(findstring $(subst ./src/main/,,$<),$(SIZE_OPTIMISED_SRC)), \
$(call compile_file,size optimised,$(CC_SIZE_OPTIMISATION)) \
, \
$(call compile_file,optimised,$(CC_DEFAULT_OPTIMISATION)) \
) \
) \
)
该段Makefile中每个选择语句最后都调用了call函数,并对compile_file函数传入两个参数($(1) $(2) ?):
$(call compile_file, 参数1, 参数2)
compile_file函数位于418~422行:
define compile_file
echo "%% ($(1)) $<" "$(STDOUT)" && \
$(CROSS_CC) -c -o $@ $(CFLAGS) $(2) $<
endef
其中, $(CFLAGS)为.c文件的搜索目录,具体值参考《Makefile中各变量值》文件
3.8 $(TARGET_ELF) 目标链接文件
411行, $(TARGET_ELF) 目标的命令会将所有已经编译的.o文件链接为obj/main/betaflight_AT32F437DEV.elf 文件。
$(TARGET_ELF): $(TARGET_OBJS) $(LD_SCRIPT) $(LD_SCRIPTS)
@echo "Linking $(TARGET)" "$(STDOUT)"
$(V1) $(CROSS_CC) -o $@ $(filter-out %.ld,$^) $(LD_FLAGS)
$(V1) $(SIZE) $(TARGET_ELF)
其中$(LD_FLAGS)为链接参数(具体值参考《Makefile中各变量值》文件), 参数中 -T./src/link/at32_flash_f43xM.ld 表明使用./src/link/at32_flash_f43xM.ld作为链接过程的链接脚本
3.9 $(TARGET_HEX) 目标命令生成.hex文件
由于变量$(EXST)的值为no,ifeq ($(EXST),no)判断为真,$(TARGET_HEX) 目标执行353行所在的命令,即:
$(TARGET_HEX): $(TARGET_ELF)
@echo "Creating HEX $(TARGET_HEX)" "$(STDOUT)"
$(V1) $(OBJCOPY) -O ihex --set-start 0x8000000 $< $@
该命令使用objcopy格式转换工具将.elf转化为.hex格式文件。
ihex 表式生成.hex文件
--set-start 0x8000000 设置链接文件首地址为0x8000000
至此.hex编译完成
本文参考:
Betaflight 的Makefile 体系与移植 - 哔哩哔哩
arm 交叉编译器各种gcc_arm-linux-gnueabihf-gcc_HKTK-CWW的博客-CSDN博客
STM32高级开发(5)-gcc-arm-none-eabi-CSDN博客
版权归原作者 清月阁 所有, 如有侵权,请联系我们删除。