betaflight 代码结构参考:

    betaflight 代码结构 - 哔哩哔哩 (bilibili.com)

Betaflight 的Makefile 体系与移植参考:

    Betaflight 的Makefile 体系与移植 - 哔哩哔哩 (bilibili.com)

一、平台简介

AT32国产飞控最近比较火,佬儿出了一些关于BF飞控移植的文章,但不太详细。这里记录了本人学习BF飞控时关于Makefile部分的总结,留待参照。

AT32飞控实物:

https://item.taobao.com/item.htm?spm=a21n57.1.0.0.4a67523cLjtnSO&id=703550743029&ns=1&abbucket=19#detail

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 电路接口:

1. 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)变量:

命令行变量:

1. TOOLS_DIR

编译工具所在位置

2. ARM_SDK_PREFIX

SDK(软件开发工具)前缀

创建变量:

1. ARM_SDK_DIR

2. GCC_REQUIRED_VERSION

版本号

3.1.7  ./make/targets.mk

include $(ROOT)/make/targets.mk(122)

1. 命令行变量

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博客

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐