穿越机源码剖析 [1]源码编译 [转载lofter乐山]

穿越机源码剖析 [1]源码编译

                                穿越机源码剖析 [1]源码编译

                                 --------- 转载请注明出处 

                                 -------- 更多笔记请访问:merafour.blog.163.com 

                                 -------- 2016-9-6.冷月追风

                                 -------- email:merafour@163.com 

                                 -------- 骑行也是一种修行

关键字:开源飞控、多轴飞行器、四轴、穿越机、CC3D、F3飞控

1. 源码编译

1.1 Makefile

1.2 startup

1.3 stm32_*.ld

1.4 target.h

    在未特别说明的情况下,这里所说的穿越机均指运行Cleanflight软件的多轴飞行器。如 CC3D、NAZE32、F3等。编译环境为 ubuntu系统,或其衍生系统如xubuntu

 1. 源码编译 

拿到源码我们要做的第一件事就是编译代码了。编译过程根据你所使用的操作系统各有不同。我个人习惯于在linux环境下执行make进行编译。

通过命令 “git clone https://github.com/cleanflight/cleanflight.git”可以在linux环境将源码从网络下载到本地。下载完成之后源码放在cleanflight目录中。其源码目录中包含如下内容:

build_docs.sh  CONTRIBUTING.md  docs  fake_travis_build.sh  JLinkSettings.ini  lib  LICENSE  Makefile  media  Notes.md  obj  README.md  src  support  Vagrantfile

我的源码是编译过的,所以包含 obj目录。下面我们就来分析它的第一个Makefile  文件。

 1.1 Makefile

  17 # The target to build, see VALID_TARGETS below

  18 TARGET      ?= NAZE

  19

  20 # Compile-time options

  21 OPTIONS     ?=

  22 export OPTIONS

  23

  24 # Debugger optons, must be empty or GDB

  25 DEBUG ?=

  26

  27 # Serial port/Device for flashing

  28 SERIAL_DEVICE   ?= $(firstword $(wildcard /dev/ttyUSB*) no-port-found)

  29

  30 # Flash size (KB).  Some low-end chips actually have more flash than advertised, use this to override.

  31 FLASH_SIZE ?=

  32

  33 ###############################################################################

  34 # Things that need to be maintained as the source changes

  35 #

  36

  37 FORKNAME             = cleanflight

  38

  39 64K_TARGETS  = CJMCU

  40 128K_TARGETS = ALIENFLIGHTF1 CC3D NAZE OLIMEXINO RMDO SPRACINGF1OSD

  41 256K_TARGETS = ALIENFLIGHTF3 CHEBUZZF3 COLIBRI_RACE EUSTM32F103RC IRCFUSIONF3 LUX_RACE MOTOLAB PORT103R RCEXPLORERF3 SPARKY SPRACINGF3 SPRACINGF3EVO SPRACINGF3MINI      STM32F3DISCOVERY SPRACINGF3OSD

  42

  43 F3_TARGETS = ALIENFLIGHTF3 CHEBUZZF3 COLIBRI_RACE IRCFUSIONF3 LUX_RACE MOTOLAB RCEXPLORERF3 RMDO SPARKY SPRACINGF3 SPRACINGF3EVO SPRACINGF3MINI STM32F3DISCOVERY SP     RACINGF3OSD

  44

  45 VALID_TARGETS = $(64K_TARGETS) $(128K_TARGETS) $(256K_TARGETS)

  46

  47 VCP_TARGETS = CC3D ALIENFLIGHTF3 CHEBUZZF3 COLIBRI_RACE LUX_RACE MOTOLAB RCEXPLORERF3 SPARKY SPRACINGF3EVO SPRACINGF3MINI STM32F3DISCOVERY SPRACINGF1OSD SPRACINGF3     OSD

  48 OSD_TARGETS = SPRACINGF1OSD SPRACINGF3OSD

从这一段脚本中我们可以知道cleanflight支持哪些飞控。截止到目前在我们看到只支持 F1跟 F3两个系列的 MCU。其中TARGET是我们编译的目标平台,默认为NAZE。64K_TARGETS是目标平台的 Flash大小。正如我们所看到的,CJMCU的Flash是最小的为 64K,但其实我们编译出来之后:

merafour@TheTravels:~/workspace/cleanflight$ ls -lh obj/cleanflight_CJMCU.bin

-rwxrwxr-x 1 merafour merafour 60K 9月   6 17:29 obj/cleanflight_CJMCU.bin

merafour@TheTravels:~/workspace/cleanflight$

代码大小为 60KB。当然相对的它的功能也有限。如果你想做一个低成本的四轴,那么你显然可以考虑CJMCU。F3_TARGETS后面列举的是基于 F3芯片的硬件平台,因为是 M4带硬件浮点,虽然都是 72M主频,所以能够获得更快的运算速度,可以实现更多的功能以及获得更快的响应。不过基于我个人的研究,通过 SRAM提速也可以获得更快的运算速度,前提是你的 SRAM剩余有足够的空间。

后面的VCP_TARGETS是支持 USB虚拟串口的飞控。因为飞控跟上位机连接通常使用串口,而 STM32,不论是 F1还是 F3现在都带有 USB接口,而使用 USB虚拟串口一方面可以减少硬件成本,另一方面可以缩小 PCB尺寸。当然,这个在玩具四轴里面会特别明显,毕竟做玩具的就算是一块钱的成本那都是能省就省。

然后:

  50 # Configure default flash sizes for the targets

  51 ifeq ($(FLASH_SIZE),)

  52 ifeq ($(TARGET),$(filter $(TARGET),$(64K_TARGETS)))

  53 FLASH_SIZE = 64

  54 else ifeq ($(TARGET),$(filter $(TARGET),$(128K_TARGETS)))

  55 FLASH_SIZE = 128

  56 else ifeq ($(TARGET),$(filter $(TARGET),$(256K_TARGETS)))

  57 FLASH_SIZE = 256

  58 else

  59 $(error FLASH_SIZE not configured for target $(TARGET))

  60 endif

  61 endif

这一段就是设置FLASH_SIZE的值。接下来:

  65 # Working directories

  66 ROOT         := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

  67 SRC_DIR      = $(ROOT)/src/main

  68 OBJECT_DIR   = $(ROOT)/obj/main

  69 BIN_DIR      = $(ROOT)/obj

  70 CMSIS_DIR    = $(ROOT)/lib/main/CMSIS

  71 INCLUDE_DIRS     = $(SRC_DIR) 

  72                 $(ROOT)/src/main/target

  73 LINKER_DIR   = $(ROOT)/src/main/target

  74

  75 # Search path for sources

  76 VPATH       := $(SRC_DIR):$(SRC_DIR)/startup

  77 USBFS_DIR   = $(ROOT)/lib/main/STM32_USB-FS-Device_Driver

  78 USBPERIPH_SRC = $(notdir $(wildcard $(USBFS_DIR)/src/*.c))

  79

  80 CSOURCES        := $(shell find $(SRC_DIR) -name '*.c')

这里设置相关源码的路径以及编译后bin文件的路径。$(ROOT)就是你的源码路径,在我这里是:”~/workspace/cleanfligh”。并且把USB相关源文件列表保存在USBPERIPH_SRC中。 CMSIS_DIR实际上用的是ST官方提供的库。因为使用ST的库,那么相对来说比较容易一直到如 F4等平台上。实际上如果你下载cleanfligh早期源码你会发现它用就是用的keil编译器。

  82 ifeq ($(TARGET),$(filter $(TARGET),$(F3_TARGETS)))

  83 # F3 TARGETS

  84

  85 STDPERIPH_DIR   = $(ROOT)/lib/main/STM32F30x_StdPeriph_Driver

  86

  87 STDPERIPH_SRC = $(notdir $(wildcard $(STDPERIPH_DIR)/src/*.c))

  88

  89 EXCLUDES    = stm32f30x_crc.c

  90         stm32f30x_can.c

  91

  92 STDPERIPH_SRC := $(filter-out ${EXCLUDES}, $(STDPERIPH_SRC))

  93

  94 DEVICE_STDPERIPH_SRC = 

  95         $(STDPERIPH_SRC)

  96

  97

  98 VPATH       := $(VPATH):$(CMSIS_DIR)/CM1/CoreSupport:$(CMSIS_DIR)/CM1/DeviceSupport/ST/STM32F30x

  99 CMSIS_SRC    = $(notdir $(wildcard $(CMSIS_DIR)/CM1/CoreSupport/*.c 

100                $(CMSIS_DIR)/CM1/DeviceSupport/ST/STM32F30x/*.c))

101

102 INCLUDE_DIRS := $(INCLUDE_DIRS) 

103            $(STDPERIPH_DIR)/inc 

104            $(CMSIS_DIR)/CM1/CoreSupport 

105            $(CMSIS_DIR)/CM1/DeviceSupport/ST/STM32F30x

106

107 ifeq ($(TARGET),$(filter $(TARGET),$(VCP_TARGETS)))

108 INCLUDE_DIRS := $(INCLUDE_DIRS) 

109            $(USBFS_DIR)/inc 

110            $(ROOT)/src/main/vcp

111

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

113

114 DEVICE_STDPERIPH_SRC := $(DEVICE_STDPERIPH_SRC)

115            $(USBPERIPH_SRC)

116

117 endif

118

119 LD_SCRIPT    = $(LINKER_DIR)/stm32_flash_f303_$(FLASH_SIZE)k.ld

120

121 ARCH_FLAGS   = -mthumb -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant -Wdouble-promotion

122 DEVICE_FLAGS = -DSTM32F303xC -DSTM32F303

123 TARGET_FLAGS = -D$(TARGET)

124

125 else ifeq ($(TARGET),$(filter $(TARGET),EUSTM32F103RC PORT103R))

在这里根据你的硬件平台做不同的设置。如库肯定用F30x的,然后LD_SCRIPT很重要,这个是链接脚本,它决定的你的函数被编译到哪段地址空间。当然我们都知道 STM32的其实地址是0x08000000,但如果你使用了bootloader那么你显然不可以再链接到这个地址了,因为0x08000000地址存放的是bootloader,所以你需要为 bootloader让出一部分空间如0x08004000,这个时候你就需修改链接文件。然后ARCH_FLAGS是编译参数,”-mcpu=cortex-m4”一定要看得懂,F303是M4核。最后还有两个” -D”,实际上也是编译参数,用来定义宏。因为cleanfligh支持很多硬件平台,而这些宏正是用来控制我们的代码编译到哪个飞控板上使用的。而下面的 F103同样需要做这些设置。

    当这些设置完成之后:

202 ifneq ($(FLASH_SIZE),)

203 DEVICE_FLAGS := $(DEVICE_FLAGS) -DFLASH_SIZE=$(FLASH_SIZE)

204 endif

205

206 TARGET_DIR = $(ROOT)/src/main/target/$(TARGET)

207 TARGET_SRC = $(notdir $(wildcard $(TARGET_DIR)/*.c))

208

209 # VARIANTS

210 ifeq ($(TARGET),ALIENFLIGHTF1)

211 # ALIENFLIGHTF1 is a VARIANT of NAZE

212 TARGET_FLAGS := $(TARGET_FLAGS) -DNAZE -DALIENFLIGHT

213 TARGET_DIR = $(ROOT)/src/main/target/NAZE

214 endif

215 ifeq ($(TARGET),CHEBUZZF3)

216 # CHEBUZZ is a VARIANT of STM32F3DISCOVERY

217 TARGET_FLAGS := $(TARGET_FLAGS) -DSTM32F3DISCOVERY

218 endif

219 ifeq ($(TARGET),$(filter $(TARGET),RMDO IRCFUSIONF3))

220 # RMDO and IRCFUSIONF3 are a VARIANT of SPRACINGF3

221 TARGET_FLAGS := $(TARGET_FLAGS) -DSPRACINGF3

222 endif

223

224 # OSDs

225 ifeq ($(TARGET),$(filter $(TARGET),$(OSD_TARGETS)))

226 TARGET_FLAGS := $(TARGET_FLAGS) -DOSD

227 endif

TARGET_DIR就是我们板子的源文件路径,但实际上我们通常只需要一个 .h文件即可,用来对飞控的资源进行定义。这一点跟 PX4是一样的,PX4也是硬件资源单独定义。当然这并不是说增加一个资源定义文件就可以增加一块新的硬件平台了,公共部分源码你还需要修改,除非你是基于一块已经被支持的飞控板稍作修改。

当我们顺着 Makefile继续往下阅读,我们会看到很多如:SYSTEM_SRC、FC_COMMON_SRC等是源文件列表。我们也会看到如:NAZE_SRC、CJMCU_SRC等,其对应的就是我们的目标硬件。我们可以在这里拿两个平台过来对比:

472 CJMCU_SRC = 

473            startup_stm32f10x_md_gcc.S

474            $(STM32F10x_COMMON_SRC) 

475            drivers/accgyro_mpu.c

476            drivers/accgyro_mpu6050.c

477            drivers/compass_hmc5883l.c

478            drivers/pwm_mapping.c

479            drivers/pwm_output.c

480            drivers/pwm_rx.c

481            drivers/sound_beeper_stm32f10x.c

482            drivers/timer.c

483            drivers/timer_stm32f10x.c

484            hardware_revision.c

485            flight/gtune.c

486            blackbox/blackbox.c

487            blackbox/blackbox_io.c

488            $(FC_COMMON_SRC) 

489            $(SYSTEM_SRC)

490

491 CC3D_SRC = 

492            startup_stm32f10x_md_gcc.S

493            $(STM32F10x_COMMON_SRC) 

494            drivers/accgyro_mpu.c

495            drivers/accgyro_spi_mpu6000.c

496            drivers/barometer_bmp085.c

497            drivers/barometer_ms5611.c

498            drivers/bus_spi.c

499            drivers/compass_hmc5883l.c

500            drivers/display_ug2864hsweg01.c

501            drivers/flash_m25p16.c

502            drivers/inverter.c

503            drivers/light_ws2811strip.c

504            drivers/light_ws2811strip_stm32f10x.c

505            drivers/pwm_mapping.c

506            drivers/pwm_output.c

507            drivers/pwm_rx.c

508            drivers/serial_softserial.c

509            drivers/sonar_hcsr04.c

510            drivers/sound_beeper_stm32f10x.c

511            drivers/timer.c

512            drivers/timer_stm32f10x.c

513            io/flashfs.c

514            $(HIGHEND_SRC) 

515            $(FC_COMMON_SRC) 

516            $(SYSTEM_SRC) 

517            $(VCP_SRC)

最明显的区别是传感器不一样了,另外 CC3D支持串口,超声波模块,USB串口,HIGHEND_SRC中还包含有 GPS、telemetry等模块,而这些都是CJMCU_SRC所没有的功能。去掉了部分功能编译出来的代码自然就更小。那么可想而知, F3平台由于具有更大空间的 Flash以及更强的运算能力,那么也就拥有比 CC3D更多的功能。由于支持的硬件平台多样,设置源码列表占据相当大的篇幅。

    当所有源码列表都设置好了以后,会有不小篇幅用于设置编译参数,如:

826 # Tool names

827 CC          := $(CCACHE) arm-none-eabi-gcc

828 OBJCOPY     := arm-none-eabi-objcopy

829 SIZE        := arm-none-eabi-size

arm-none-eabi-gcc就是我们所使用的工具链。再往下:

900 # Things we will build

901 #

902 ifeq ($(filter $(TARGET),$(VALID_TARGETS)),)

903 $(error Target '$(TARGET)' is not valid, must be one of $(VALID_TARGETS))

904 endif

905

906 TARGET_BIN   = $(BIN_DIR)/$(FORKNAME)_$(TARGET).bin

907 TARGET_HEX   = $(BIN_DIR)/$(FORKNAME)_$(TARGET).hex

908 TARGET_ELF   = $(OBJECT_DIR)/$(FORKNAME)_$(TARGET).elf

909 TARGET_OBJS  = $(addsuffix .o,$(addprefix $(OBJECT_DIR)/$(TARGET)/,$(basename $($(TARGET)_SRC))))

910 TARGET_DEPS  = $(addsuffix .d,$(addprefix $(OBJECT_DIR)/$(TARGET)/,$(basename $($(TARGET)_SRC))))

911 TARGET_MAP   = $(OBJECT_DIR)/$(FORKNAME)_$(TARGET).map

912

913

914 ## Default make goal:

915 ## hex         : Make filetype hex only

916 .DEFAULT_GOAL := hex

917

918 ## Optional make goals:

919 ## all         : Make all filetypes, binary and hex

920 all: hex bin

921

922 ## binary      : Make binary filetype

923 ## bin         : Alias of 'binary'

924 ## hex         : Make hex filetype

925 bin:    $(TARGET_BIN)

926 binary: $(TARGET_BIN)

927 hex:    $(TARGET_HEX)

Hex、 bin就是我们所需要的目标代码。其编译的详细过程为:

998 $(TARGET_HEX): $(TARGET_ELF)

999     $(OBJCOPY) -O ihex --set-start 0x8000000 $< $@

1000

1001 $(TARGET_BIN): $(TARGET_ELF)

1002     $(OBJCOPY) -O binary $< $@

1003

1004 $(TARGET_ELF):  $(TARGET_OBJS)

1005     $(CC) -o $@ $^ $(LDFLAGS)

1006     $(SIZE) $(TARGET_ELF)

1007

1008 # Compile

1009 $(OBJECT_DIR)/$(TARGET)/%.o: %.c

1010     @mkdir -p $(dir $@)

1011     @echo %% $(notdir $<)

1012     @$(CC) -c -o $@ $(CFLAGS) $<

1013

1014 # Assemble

1015 $(OBJECT_DIR)/$(TARGET)/%.o: %.s

1016     @mkdir -p $(dir $@)

1017     @echo %% $(notdir $<)

1018     @$(CC) -c -o $@ $(ASFLAGS) $<

1019

1020 $(OBJECT_DIR)/$(TARGET)/%.o: %.S

1021     @mkdir -p $(dir $@)

1022     @echo %% $(notdir $<)

1023     @$(CC) -c -o $@ $(ASFLAGS) $<

熟悉Makefile的都知道$(TARGET_OBJS)最后通过 ” # Compile”后面的规则进行编译。而编译的源文件如 CC3D在CC3D_SRC列表中。

下面我们有几个源文件需要说明。

原文地址:https://www.cnblogs.com/eastgeneral/p/10879584.html