Betaflight 的Makefile 体系与移植
二木山人
2022年10月17日 22:47
收录于文集
共14篇

betaflight 的 makefile体系是整体构建固件的基础, 因为支持基本整个全系列STM 芯片,从F103 一直到 H7 (目前官方已经移除F1、F3 的支持,仅支持F4、F7、H7系列),芯片的架构、配置、存储布局、内存布局等各不相同,另外还要考虑一部分特定目标需要配置特定的信息,所以betaflight 实现了一个十分复杂的makefile体系。 所以构建betaflight 最好的方式是按照官方文档,使用 make +arm-gcc + binutils 工具链进行构建。 调试最好使用 gdb+openocd +Jlink/STlink/Daplink 进行仿真调试。

所需背景知识:

1、makefile 语法

2、linux 下 make、gcc、gdb、binutils 等编译工具链基础知识

3、git 、python 等基本工具知识

如果以上背景知识不够扎实,可以边看边搜边补充。

先介绍 betaflight 的makefile体系:

整体betaflight的makefile 包括3部分:

betaflight/make 目录,

betflight/Makefile

betaflight/src/main/targets/target.mk

第一部分:betaflight/make 文件夹相关目录结构与用途如下:

make

----mcu                                     具体MCU 的定义,如果新增MCU 需要在这里配置

--------AT32F43x.mk                 本次移植新增的at32f435/7 系列mcu构建脚本,新建 --------SITL.mk                           软件仿真构建目标 --------STM32F1.mk                  stm32f103 mcu 构建脚本 --------STM32F3.mk --------STM32F4.mk --------STM32F7.mk --------STM32G4.mk --------STM32H7.mk

---source.mk                          betaflight 公用源文件清单、usb以及其他库文件清单,速度、大小优化裁剪文件清单等          需要微调,增加at系列source file

---targets.mk                         所有的目标信息配置,需要配置 at新增的target

---targets_list.mk                   所有目标清单,包括支持的、淘汰的等,不需要动

---tools.mk                            自动安装构建相关工具的清单,不需要动

---checks.mk                         相关校验清单,不需要动

---openocd.mk                      openocd 仿真配置清单,包括jlink、stlink等,本次移植没有用

---system-id.mk                      其他配置相关清单,判断当前系统是什么系统 ,不需要动

---macosx.mk                         mac os下 的编译环境配置,不需要动

---windows.mk                        windows 下的编译环境配置,不需要动

--- linux.mk                             linux 下的编译环境配置 ,不需要动

--- build_verbosity.mk             交互式构建的设置,不需要动

第二部分:主Makefile

betaflight/ Makefile                   makefile 是bf的 主makefile文件,通过include make文件夹和target文件夹下的makefile来实现根据命令自动构建具体的目标固件的构建规则。 主makefile 不需要做修改。

第三部分: betaflight/src/main/target/AT32F437DEV

具体的target 配置文件夹,主要包括 targe.h  target.c  target.mk 三个文件,为了移植到at32 的starter 开发板上,新增 AT32F437DEV 目标

target.h  :新增目标头文件配置,主要是配置spi、i2c、uart、beeper、timer、led 等针脚配置以及启用的timer 、gpio端口等,这部分信息会被编译后的 转换为  PG 配置信息,对应到 bf 地面站 CLI 命令行里的Resource 信息 ,另外还包括具体使用什么 ACC 和GYRO、 具体传感器信息等,通过 #define  USE_xxxx  等宏定义打开编译时包含的传感器驱动代码等。 一般考虑到mcu 的flash 大小以及构建的目标硬件配置来设定

代码块
C++
自动换行
复制代码
#pragma once

#define TARGET_BOARD_IDENTIFIER "AT32F437"
#define USBD_PRODUCT_STRING     "EMSRAT32F4"

//buttons
#define USE_BUTTONS
#define BUTTON_A_PIN            PD2
#define BUTTON_A_PIN_INVERTED // Active high
#define BUTTON_B_PIN            PC13 //PC14 FOR lqfp64
#define BUTTON_B_PIN_INVERTED // Active high

// LED0_PIN PH0 FOR lqfp64
// LED1_PIN PH1 FOR lqfp64
// LED2_PIN PH2 FOR lqfp64

#define LED0_PIN                PD13 //confirm on LQFP64
#define LED1_PIN                PD14 //confirm on LQFP64
#define LED2_PIN                PD15 //confirm on LQFP64
#define LED0_INVERTED
#define LED1_INVERTED
#define LED2_INVERTED


#define USE_BEEPER
#define BEEPER_PIN              PB11
#define BEEPER_INVERTED		 //低电平触发
#define BEEPER_PWM_HZ	2500 //0  有源bb响 | 2500Hz 无源bb响,PWM驱动

#define ENABLE_DSHOT_DMAR       DSHOT_DMAR_AUTO
#define DSHOT_BITBANG_DEFAULT   DSHOT_BITBANG_AUTO

// *************** SPI **********************
#define USE_SPI
#define USE_SPI_DEVICE_1

#define SPI1_SCK_PIN            PA5
#define SPI1_MISO_PIN           PA6
#define SPI1_MOSI_PIN           PA7
#define SPI1_NSS_PIN            PA4

//NOT USE ON AT-START BOARD ! -->OTG2
#define USE_SPI_DEVICE_2
#define SPI2_SCK_PIN            PD1//PB13 on LQFP64
#define SPI2_MISO_PIN           PD3//PB14 on LQFP64
#define SPI2_MOSI_PIN           PD4//PB15 on LQFP64
#define SPI2_NSS_PIN            PD5 //confirm on lqfp64



#define USE_SPI_DEVICE_3
#define SPI3_SCK_PIN            PC10
#define SPI3_MISO_PIN           PC11
#define SPI3_MOSI_PIN           PC12
#define SPI3_NSS_PIN 			PD6 //confirm on lqfp64

// *************** Gyro & ACC **********************

#define USE_EXTI
#define USE_GYRO_EXTI
#define GYRO_1_EXTI_PIN        PA15
#define USE_MPU_DATA_READY_SIGNAL
#define ENSURE_MPU_DATA_READY_IS_LOW

#define GYRO_1_CS_PIN          SPI1_NSS_PIN
#define GYRO_1_SPI_INSTANCE    SPI1
#define GYRO_1_ALIGN           CW90_DEG


#define USE_GYRO
#define USE_GYRO_SPI_MPU6500
#define USE_GYRO_SPI_ICM42688P
#define USE_ACCGYRO_LSM6DSO

#define USE_ACC
#define USE_ACC_SPI_MPU6500
#define USE_ACC_SPI_ICM42688P


//#define GYRO_CONFIG_USE_GYRO_DEFAULT GYRO_CONFIG_USE_GYRO_1

// *************** OSD *****************************
//USE SPI3 ON AT-START BOARD ,USE SPI2 ON LQFP64
#define USE_MAX7456
#define MAX7456_SPI_INSTANCE    SPI2
#define MAX7456_SPI_CS_PIN      SPI2_NSS_PIN

/********************BLACKBOX***********************/
#define ENABLE_BLACKBOX_LOGGING_ON_SPIFLASH_BY_DEFAULT
#define USE_FLASHFS
#define USE_FLASH_M25P16
#define FLASH_SPI_INSTANCE      SPI3
#define FLASH_CS_PIN            SPI3_NSS_PIN


// ***************ELRS **************************


//#define USE_RX_SPI
//#define RX_SPI_INSTANCE        SPI3
//#define RX_SPI_LED_INVERTED
//
//#define RX_SPI_DEFAULT_PROTOCOL RX_SPI_EXPRESSLRS
//
//#define USE_RX_EXPRESSLRS
//#define USE_RX_EXPRESSLRS_TELEMETRY
//#define USE_RX_SX1280
//#define RX_CHANNELS_AETR
//#define RX_SPI_BIND_PIN        PC3
//#define RX_NSS_PIN             PA15
//#define RX_SPI_LED_PIN         PC12
//#define RX_SPI_EXTI_PIN        PC13
//#define RX_EXPRESSLRS_SPI_RESET_PIN      PC5
//#define RX_EXPRESSLRS_SPI_BUSY_PIN       PA13
//#define RX_EXPRESSLRS_TIMER_INSTANCE     TMR5


// *************** Baro **************************
#define USE_I2C
#define USE_I2C_DEVICE_3
#define I2C_DEVICE              (I2CDEV_3)
#define I2C3_SCL                PC0        // SCL pad
#define I2C3_SDA                PC1        // SDA pad
#define USE_I2C_PULLUP

#define USE_BARO
#define USE_BARO_BMP280
#define BARO_I2C_INSTANCE       (I2CDEV_3)

#define USE_MAG
#define USE_MAG_HMC5883
#define USE_MAG_QMC5883
#define MAG_I2C_INSTANCE        (I2CDEV_3)

//#define USE_BARO_MS5611

// *************** UART *****************************
#define USE_VCP
#define USB_DETECT_PIN          PC15
#define USE_USB_DETECT

#define USE_UART1
#define UART1_RX_PIN            PA10
#define UART1_TX_PIN            PA9

#define USE_UART2
#define UART2_RX_PIN            PA3
#define UART2_TX_PIN            PA2

#define USE_UART3
#define UART3_RX_PIN            PC5
#define UART3_TX_PIN            PC4

#define USE_UART4
#define UART4_RX_PIN            PA1
#define UART4_TX_PIN            PA0

#define USE_UART8
#define UART8_RX_PIN            PC3
#define UART8_TX_PIN            PC2

//#define USE_SOFTSERIAL1
//#define USE_SOFTSERIAL2

#define SERIAL_PORT_COUNT       6 // VCP  UART1 UART2 UART3 UART4 UART5

#define DEFAULT_RX_FEATURE      FEATURE_RX_SERIAL
#define SERIALRX_PROVIDER       SERIALRX_CRSF
#define SERIALRX_UART           SERIAL_PORT_USART2



// *************** ADC *****************************
#define USE_ADC
#define ADC_INSTANCE         ADC1  // Default added
#define ADC1_DMA_OPT            11  //DMA 2 CH 5

#define VBAT_ADC_PIN            PB0
#define CURRENT_METER_ADC_PIN   PB1
//#define RSSI_ADC_PIN            0

#define USE_ESCSERIAL

#define DEFAULT_FEATURES                (FEATURE_OSD | FEATURE_TELEMETRY | FEATURE_SOFTSERIAL |FEATURE_LED_STRIP )
#define DEFAULT_VOLTAGE_METER_SOURCE    VOLTAGE_METER_ADC
#define DEFAULT_CURRENT_METER_SOURCE    CURRENT_METER_ADC

#define TARGET_IO_PORTA         0xffff
#define TARGET_IO_PORTB         0xffff
#define TARGET_IO_PORTC         0xffff
#define TARGET_IO_PORTD         0xffff
#define TARGET_IO_PORTE         BIT(2)

#define USABLE_TIMER_CHANNEL_COUNT 28
#define USED_TIMERS             ( TIM_N(1) | TIM_N(2) | TIM_N(3) | TIM_N(4) | TIM_N(5) | TIM_N(8) | TIM_N(20) )
复制成功

target.c  与target.h 配套使用,但是主要配置的是

timerHardware[USABLE_TIMER_CHANNEL_COUNT]

通过 DEF_TIM 宏来给需要通过timer  输出PWM 的针脚定义配置信息, 主要包括:CameraControl、LedStrip、Motor、Servo 等需要pwm 驱动的外设针脚定义以及使用的DMA 通道。

代码块
C++
自动换行
复制代码

#include <stdint.h>

#include "platform.h"
#include "drivers/io.h"

 #include "drivers/dma.h"
 #include "drivers/timer.h"
 #include "drivers/timer_def.h"

 const timerHardware_t timerHardware[USABLE_TIMER_CHANNEL_COUNT] = {
 	DEF_TIM(TMR2, CH3, PB10, TIM_USE_ANY |TIM_USE_LED, 0,13,0), // PWM1 - OUT1 MCO1 DMA1 CH2
	DEF_TIM(TMR2, CH4, PB11,  TIM_USE_ANY |TIM_USE_BEEPER, 0,12,0), // PWM2 - OUT1 DMA1 CH6
	DEF_TIM(TMR3, CH1, PC6,  TIM_USE_ANY |TIM_USE_SERVO, 0,11,10), // PWM3 - OUT3  DMA1 CH7
	DEF_TIM(TMR3, CH2, PC7,  TIM_USE_ANY |TIM_USE_SERVO, 0,10,10), // PWM4 - OUT4  DMA2 CH1
	DEF_TIM(TMR3, CH3, PC8,  TIM_USE_ANY |TIM_USE_SERVO, 0,9,10), // PWM5 - OUT5  DMA2 CH2
	DEF_TIM(TMR3, CH4, PC9,  TIM_USE_ANY |TIM_USE_SERVO, 0,8,10), // PWM6 - OUT6  DMA2 CH3

 	DEF_TIM(TMR4, CH1, PB6,  TIM_USE_MOTOR, 0,0,1),  // motor1 DMA2 CH7
 	DEF_TIM(TMR4, CH2, PB7,  TIM_USE_MOTOR, 0,2,1),  // motor2 DMA2 CH6
 	DEF_TIM(TMR4, CH3, PB8,  TIM_USE_MOTOR,  0,1,0), // motor3 DMA2 CH5
 	DEF_TIM(TMR4, CH4, PB9,  TIM_USE_MOTOR,  0,3,0), // motor4 DMA2 CH4

 };
复制成功

以上target.h和target.c 的相关针脚映射不可以随便定义,需要查具体芯片的用户手册与数据手册GPIO 复用表格,来设定具体目标板的针脚IO分配。 配置错误可能会导致硬件无法使用。所以移植过程中需要反复的核对配置信息。

target.mk   这个文件是 target 的关键, 通过targets.mk 通过扫描 target 目录下的具体子目录名称作为 BASE_TARGET  参数,而 target.mk 文件里

代码块
JavaScript
自动换行
复制代码
AT32F43xxMT7_TARGETS += $(TARGET)   #规定当前target 归属的target 类,

CUSTOM_DEFAULTS_EXTENDED = yes    #是否使用自定义扩展配置信息(在flash 的最后16kb)
FEATURES       +=  VCP ONBOARDFLASH  #启用的特性,VCP 是usb 串口,onboardflash 是内置黑匣子芯片

TARGET_SRC = \                    #本target 关联的传感器需要包含的源代码
			drivers/accgyro/accgyro_mpu6500.c \
            drivers/accgyro/accgyro_spi_icm426xx.c\
            drivers/barometer/barometer_bmp280.c \
            drivers/compass/compass_hmc5883l.c\
            drivers/compass/compass_qmc5883l.c\
            drivers/accgyro/accgyro_spi_mpu6000.c \
            drivers/accgyro/accgyro_spi_mpu6500.c\
            drivers/accgyro/accgyro_spi_lsm6dso_init.c \
            drivers/accgyro/accgyro_spi_lsm6dso.c \
            drivers/max7456.c \
            drivers/vtx_rtc6705.c \
            drivers/vtx_rtc6705_soft_spi.c \
            drivers/rx/expresslrs_driver_atbsp.c \
            drivers/rx/rx_sx127x.c \
            drivers/rx/rx_sx1280.c \
            rx/expresslrs_telemetry.c \
            rx/expresslrs_common.c \
            rx/expresslrs.c
复制成功

为了移植AT32F43x 系列MCU ,需要做以下工作:

1、搭建编译环境,可以在linux 或者安装了cygwin 的windows bash 中,在betaflight 目录下执行 :make arm_sdk_install  命令,会自动安装 arm 相关工具链到 betaflight/tools/文件夹下,后面的固件构建也会自动引用这个文件夹下的工具 。

2、新建target 配置,如上文分析

3、增加 targets.mk 配置

代码块
JavaScript
自动换行
复制代码
#略
AT32F43x_TARGETS := $(AT32F43xxMT7_TARGETS) $(AT32F43xxGT7_TARGETS) $(AT32F43xxCT7_TARGETS)
# xM系列(4m flash) xG系列(1M flash)xC 系列(256K flash)

#略
else ifeq ($(TARGET),$(filter $(TARGET), $(AT32F43x_TARGETS)))

TARGET_MCU := AT32F43x
#略
复制成功

4、新增 mcu/AT32F43X.mk 配置

代码块
clike
自动换行
复制代码
#
# AT32F4 Make file include
# 配置不同型号MCU 的flash 大小
ifeq ($(TARGET),$(filter $(TARGET), $(AT32F43xxMT7_TARGETS)))
MCU_FLASH_SIZE  := 4032
DEVICE_FLAGS    = -DAT32F437VMT7
else ifeq ($(TARGET),$(filter $(TARGET), $(AT32F43xxGT7_TARGETS)))
MCU_FLASH_SIZE  := 1024
DEVICE_FLAGS    = -DAT32F435RGT7
else ifeq ($(TARGET),$(filter $(TARGET), $(AT32F43xxCT7_TARGETS)))
MCU_FLASH_SIZE  := 256
else
MCU_FLASH_SIZE  := 256
endif

# for the bsp dir & src 
STDPERIPH_DIR   = $(ROOT)/lib/main/AT32F43x/drivers/
STDPERIPH_SRC   = $(notdir $(wildcard $(STDPERIPH_DIR)/src/*.c))
EXCLUDES        = \
				  at32f435_437_dvp.c\
				  at32f435_437_can.c\
				  at32f435_437_xmc.c\
				  at32f435_437_emac
				  
				  
				  
STARTUP_SRC     = startup_at32f435_437.S
STDPERIPH_SRC   := $(filter-out ${EXCLUDES}, $(STDPERIPH_SRC))

#I2C_APPLICATION_DIR=$(ROOT)/lib/main/AT32F43x/i2c_application_library
#I2C_APPLICATION_SRC=$(notdir $(wildcard $(I2C_APPLICATION_DIR)/*.c))

# Search path and source files for the bsp cmsis sources
VPATH           := $(VPATH):$(ROOT)/lib/main/AT32F43x/cmsis/cm4/core_support/

INCLUDE_DIRS    := $(INCLUDE_DIRS) \
                   $(STDPERIPH_DIR)/inc \
                   $(ROOT)/lib/main/AT32F43x/cmsis/cm4/core_support \
                   $(ROOT)/lib/main/AT32F43x/cmsis/cm4/ \
                   #$(I2C_APPLICATION_DIR)\
                   

DEVICE_STDPERIPH_SRC = $(STDPERIPH_SRC)\
					# $(I2C_APPLICATION_SRC)

#fixme: vcp & support later 
ifneq ($(filter VCP, $(FEATURES)),)
INCLUDE_DIRS    := $(INCLUDE_DIRS) \
                   $(USBFS_DIR)/inc\
                   $(ROOT)/lib/main/AT32F43x/usbd_class/cdc \
                   $(ROOT)/lib/main/AT32F43x/usbd_class/msc \

VPATH           := $(VPATH):$(USBFS_DIR)/src\

DEVICE_STDPERIPH_SRC := $(DEVICE_STDPERIPH_SRC) \
                        $(USBFS_DIR)/src/usb_core.c\
                        $(USBFS_DIR)/src/usbd_core.c\
                        $(USBFS_DIR)/src/usbd_int.c\
                        $(USBFS_DIR)/src/usbd_sdr.c\

endif
# 不同型号 MCU 使用不同的 gcc ld 文件来制定链接内存布局结构
ifeq ($(LD_SCRIPT),)
ifeq ($(MCU_FLASH_SIZE),4032)
	LD_SCRIPT       = $(LINKER_DIR)/at32_flash_f43xM.ld
endif
ifeq ($(MCU_FLASH_SIZE),1024)
	LD_SCRIPT       = $(LINKER_DIR)/at32_flash_f43xG.ld
endif
endif

ARCH_FLAGS      = -std=c99  -mthumb -mcpu=cortex-m4 -march=armv7e-m -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -Wdouble-promotion



DEVICE_FLAGS   += -DUSE_ATBSP_DRIVER -DAT32F43x -DHSE_VALUE=$(HSE_VALUE)


VCP_SRC = 	$(ROOT)/lib/main/AT32F43x/usbd_class/cdc/cdc_class.c\
			$(ROOT)/lib/main/AT32F43x/usbd_class/cdc/cdc_desc.c\
            drivers/serial_usb_vcp_at32f43x.c \
            drivers/usb_io.c
            

MCU_COMMON_SRC = \
            startup/system_at32f435_437.c\
            startup/at32f435_437_clock.c\
            drivers/system_at32f43x.c\
            drivers/light_ws2811strip_at32f43x.c \
            drivers/timer_atbsp.c\
            drivers/timer_at32f43x.c\
            drivers/dma_at32f43x.c\
            drivers/i2c_application.c\
            drivers/bus_i2c_atbsp_init.c \
            drivers/bus_i2c_atbsp.c\
			drivers/bus_spi_at32bsp.c\
            drivers/inverter.c \
            drivers/serial_uart_at32bsp.c\
            drivers/serial_uart_at32f43x.c\
            drivers/pwm_output_dshot_shared.c \
			drivers/pwm_output_dshot.c \
			drivers/dshot_bitbang.c \
            drivers/dshot_bitbang_decode.c \
            drivers/dshot_bitbang_at32bsp.c \
            drivers/accgyro/accgyro_mpu.c \
            drivers/persistent.c\
            drivers/camera_control_atbsp.c\
            drivers/adc_at32f43x.c \

            
MSC_SRC = \
			$(ROOT)/lib/main/AT32F43x/usbd_class/msc/msc_desc.c\
			$(ROOT)/lib/main/AT32F43x/usbd_class/msc/msc_class.c\
			$(ROOT)/lib/main/AT32F43x/usbd_class/msc/msc_bot_scsi.c\
            drivers/usb_msc_common.c \
            drivers/usb_msc_at32f43x.c \
            
EXCLUDES +=\
			drivers/msc/usbd_storage.c\
			drivers/msc/usbd_storage_sdio.c\
			drivers/msc/usbd_msc_desc.c\
			dirvers/msc/usbd_storage_sd_spi.c\
			



ifneq ($(filter ONBOARDFLASH,$(FEATURES)),)
MSC_SRC += \
            msc/at32_msc_diskio.c \
            msc/emfat.c \
            msc/emfat_file.c
endif 

DSP_LIB :=

ifneq ($(DEBUG),GDB)
OPTIMISE_DEFAULT    := -Os
OPTIMISE_SPEED      :=
OPTIMISE_SIZE       :=

LTO_FLAGS           := $(OPTIMISATION_BASE) $(OPTIMISE_DEFAULT)
endif

DEVICE_FLAGS +=  -DARM_MATH_MATRIX_CHECK -DARM_MATH_ROUNDING  -DUNALIGNED_SUPPORT_DISABLE -DARM_MATH_CM4 

复制成功

通过以上几步基本构建了新移植的at32f435/7 系列mcu 的makefile体系,后面的移植过程中通过make命令进行目标固件的构建工作。