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 大小以及构建的目标硬件配置来设定
#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 通道。
#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 文件里
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 配置
#略
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 配置
#
# 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命令进行目标固件的构建工作。