zoukankan      html  css  js  c++  java
  • 穿越机源码剖析 [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列表中。

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

  • 相关阅读:
    读书笔记:A Philosophy of Software Design
    面向对象编程—价值万亿美元的灾难
    刚哥谈架构 (二) 我眼中的架构师
    软件质量成本神话
    API 如何选择 REST,GraphQL还是gRPC
    影响您的代码库的10个编程代码味道
    为什么要不断重构
    php导出excel表格的使用
    浅谈HTTP中Get与Post的区别
    C# 程序配置文件的操作(ConfigurationManager的使用)
  • 原文地址:https://www.cnblogs.com/eastgeneral/p/10879584.html
Copyright © 2011-2022 走看看