☰
Momentum-Firmware 硬件目标(Targets)体系全解析:f7 / f18 与全局 HAL 的设计与构建机制
2026/10/14 18:35:26 网站建设 项目流程
  • 嵌入式
  • 物联网

【免费下载链接】Momentum-Firmware

🐬 Feature-rich, stable and customizable Flipper Firmware

项目地址:https://gitcode.com/GitHub_Trending/mo/Momentum-Firmware
点击查看免费下载

本篇指南聚焦 Momentum-Firmware 仓库中targets/目录所承载的硬件目标(Hardware Target)体系:它如何在同一个代码库中同时支持 Flipper Zero(f7)与另一款非 Flipper Zero 的 Flipper Nano(f18)硬件,如何通过target.json定义差异、通过继承与排除机制复用代码,以及fbt构建系统如何按目标组织源码、SDK 与链接脚本。读完本文,你将掌握硬件目标的目录组织、target.json全部字段语义、TARGET_HW构建参数、目标级应用裁剪方法,并能独立为指定硬件目标构建与排查固件。

一、targets/目录总览:三种角色的目标

targets/ReadMe.md用三行点明了整个目录的核心划分:

目录含义
targets/f18Not Flipper Zero(Flipper Nano,非 Flipper Zero 硬件)
targets/f7Flipper Zero(官方 Flipper Zero 硬件)
targets/furi_hal_includeGlobal Furi HAL includes,所有目标共享的全局 Furi HAL 头文件

三个目录各司其职:f7与f18是真正的硬件实现目录,包含各自平台的furi_hal源码、启动与链接文件、SDK 符号表;而furi_hal_include则是"伞形" API 头文件集合,其核心入口 furi_hal.h 通过#include一次性汇总了 cortex、clock、adc、power、nfc、usb、bt、spi、i2c、subghz 等全部 HAL 接口,为上层应用提供与具体硬件无关的统一抽象。

Flipper 的固件采用模块化设计,能够在同一代码库中支持不同的硬件配置:硬件相关的差异被封装进furi_hal、板级初始化代码、链接脚本、SDK 数据等,统一收敛在一个**目标定义(target definition)**中,详情见仓库文档 documentation/HardwareTargets.md。目标相关的文件全部放置在targets下的子文件夹内,每个目标必须包含一份target.json定义文件,并可按需引用其他文件;默认情况下fbt会收集目标文件夹内的全部源码文件,除非这些文件被显式排除。

二、target.json:目标定义文件字段全解

每个硬件目标的核心是target.json,它是一份 JSON 定义文件,支持的字段如下(完整字段语义来自 documentation/HardwareTargets.md):

字段类型说明
include_paths字符串列表相对当前目标文件夹的路径,追加到全局 C/C++ 头文件搜索路径
sdk_header_paths字符串列表相对当前目标文件夹的路径,用于收集头文件并纳入生成的 SDK
startup_script字符串启动脚本文件名,执行初始硬件初始化
linker_script_flash字符串用于构建主固件镜像的链接脚本
linker_script_ram字符串"updater" 构建配置使用的链接脚本
linker_script_app字符串链接.fap外部应用使用的链接脚本
sdk_symbols字符串当前目标 SDK 配置的.csv文件
linker_dependencies字符串列表固件需要链接的库列表;不在列表中的库不会被fbt构建,特殊场景下同一库名可能需要出现两次以完成多轮链接
inherit字符串指定从哪个硬件目标借用主配置;当前配置可对字符串列表类参数追加值,或对非列表参数覆盖值
excluded_sources字符串列表从继承配置中不参与构建的源文件名
excluded_headers字符串列表从继承配置中不纳入 SDK的头文件名
excluded_modules字符串列表从构建环境配置中排除的 fbt 库(模块)名称

以 Flipper Zero 目标 targets/f7/target.json 为例,它声明了完整的配置:include_paths包含ble_glue、fatfs、furi_hal、inc四个目录;sdk_header_paths包含全局../furi_hal_include以及本目标的furi_hal、platform_specific、BLE 相关目录;指定了三份链接脚本stm32wb55xx_flash.ld、stm32wb55xx_ram_fw.ld、application_ext.ld;SDK 符号表为api_symbols.csv(该文件在仓库中长达数千行,以Version,+,87.1,,为起始行,逐项列出每个 SDK 版本号、导出头文件与符号)。linker_dependencies则列出了print、furi、freertos、stm32wb、fatfs、subghz、toolbox、nfc、infrared、mjs、mbedtls、flipper_application、momentum、nanopb、update_util、heatshrink、flipperformat等 30 余个库。

三、继承与裁剪:f18 如何"站在 f7 肩膀上"做减法

f18目标没有重新定义全部内容,而是在 targets/f18/target.json 第一行通过"inherit": "7"直接继承了 f7 的主配置。这是理解整个目标体系的关键设计:目标之间可以继承绝大部分代码,以减少公共代码的重复(见 documentation/HardwareTargets.md)。

继承之外,f18 通过三组排除字段对 f7 的能力做了显著裁剪,这从源码结构上印证了 f18 与 f7 的硬件能力差异:

  • excluded_sources:排除了furi_hal_infrared.c、furi_hal_nfc.c、furi_hal_nfc_timer.c、furi_hal_nfc_irq.c、furi_hal_nfc_event.c、furi_hal_nfc_iso15693.c、furi_hal_nfc_iso14443a.c、furi_hal_nfc_iso14443b.c、furi_hal_nfc_felica.c、furi_hal_rfid.c、furi_hal_subghz.c等源文件;
  • excluded_headers:排除了furi_hal_infrared.h、furi_hal_nfc.h、furi_hal_rfid.h、furi_hal_subghz.h、furi_hal_ibutton.h等头文件,使其不进入 SDK;
  • excluded_modules:排除了nfc、lfrfid、subghz、ibutton、infrared五个 fbt 库模块。

也就是说,f18 目标是一个没有 NFC / RFID / SubGHz / iButton / 红外收发能力的硬件平台,固件构建时会整体跳过这些模块与对应源码。这与 f18 目录的furi_hal实现相吻合——targets/f18/furi_hal/furi_hal_target_hw.h 仅是一个空文件(#pragma once),而 targets/f7/furi_hal/furi_hal_target_hw.h 则引用了 subghz、ibutton、rfid、nfc 的头文件。

f18 同时维护了自己的差异实现,例如 targets/f18/furi_hal/furi_hal_resources.c 重新定义了该硬件平台的 GPIO 资源表(SWDIO/SWCLK、按键、SPI、扩展引脚等),以及 targets/f18/furi_hal/furi_hal_power_config.c 中面向 1300 mAh 电芯的 BQ27220 电量计数据内存配置。

四、链接脚本与 SDK:目标级的内存布局与接口导出

链接脚本是目标定义中最直接影响固件形态的文件。f7 的主固件链接脚本 targets/f7/stm32wb55xx_flash.ld 定义了 STM32WB55 的内存布局:FLASH 起始地址0x08000000、容量 1024K,RAM1/RAM2A/RAM2B 等区段,并包含.isr_vector、.text、.rodata、.init_array等标准段布局。而 targets/f7/application_ext.ld 则是.fap外部应用使用的链接脚本,它以FORCE_COMMON_ALLOCATION开头并采用 0 基址的相对段布局,确保外部应用以与地址无关的方式链接后加载。

这些脚本在构建时由 site_scons/firmwareopts.scons 按场景选用:updater构建配置使用TARGET_CFG.linker_script_ram,并设置IMAGE_BASE_ADDRESS=0x20000000;常规固件使用linker_script_flash(基址0x8000000),.fap使用linker_script_app。由此可见target.json中的链接脚本字段直接驱动着三种产物的内存布局。

SDK 方面,api_symbols.csv定义了该目标对外导出的 API 集合,用于生成 SDK 头文件与符号表(如 targets/f7/api_symbols.csv 从Version、Header条目开始,逐条列出applications/...、furi/...、lib/...中的公开头文件与函数符号),并通过sdk_symbols字段与构建系统关联,是 FAP 外部应用编译期依赖的目标级接口契约。

五、构建系统源码级解析:fbt如何加载与聚合目标

fbt构建系统通过 scripts/fbt_tools/fbt_hwtarget.py 中的HardwareTargetLoader类加载目标定义,其工作流程清晰可循:

  1. 定位目标目录:_getTargetDir()根据target_id映射到targets/f{target_id}目录;
  2. 解析 target.json:_loadDescription()读取并 JSON 解析target.json,失败即抛出异常;
  3. 处理继承链:_processTargetDefinitions()递归处理inherit字段,把继承链上每一层目标的include_paths、sdk_header_paths等追加合并,文件类属性(链接脚本、SDK 符号表)则"先到先得";
  4. 聚合源码:gatherSources()在layered_target_dirs(继承链各级目录)上递归收集*.c文件,并用excluded_sources中的文件名做全局去重与过滤——这也是"默认收集全部源码、除非显式排除"机制的实现位置;
  5. 聚合 SDK 头文件:gatherSdkHeaders()遍历sdk_header_paths收集头文件,跳过excluded_headers中列出的名字;
  6. 注入构建环境:ConfigureForTarget()将解析结果写入环境变量TARGET_CFG、SDK_DEFINITION与SKIP_MODULES,同时把include_paths追加到CPPPATH、SDK 头文件集合写入SDK_HEADERS。

随后 targets/SConscript 以flipper${TARGET_HW}为库名创建静态库环境,调用TARGET_CFG.gatherSources()获得全部目标源码并构建安装到LIB_DIST_DIR。

目标的选择入口在命令行选项层:site_scons/commandline.scons定义了TARGET_HW枚举变量,仅允许"7"和"18"两个取值,默认值为"7";而 fbt_options.py 中的TARGET_HW = 7则是默认硬件目标的仓库级配置。

六、应用与硬件目标的匹配:内置应用与 FAP 的两种裁剪方式

并非所有应用都能运行在所有硬件目标上,仓库文档(documentation/HardwareTargets.md)给出了两条配套机制:

  • 内置固件应用:通过FIRMWARE_APP_SET=...指定与目标兼容的应用集(具体构建配置参见 documentation/fbt.md)。在 fbt_options.py 中可见FIRMWARE_APPS定义了default、unit_tests、unit_tests_min等应用集,例如unit_tests_min仅包含basic_services、updater_app、radio_device_cc1101_ext、unit_tests、js_app、infrared、archive;
  • 外部 FAP 应用:在应用的application.fam清单中显式声明兼容目标,例如添加targets=["f7"]即可将应用限制为仅在 f7 构建,其他目标直接跳过。该逻辑实现在 scripts/fbt/appmanifest.py 的supports_hardware_target()方法中:target in self.targets or "all" in self.targets,即清单中声明了目标或声明了"all"的应用才会被纳入当前目标的构建(详见appmanifest.py第 98-99 行与构建时的目标不匹配跳过逻辑)。

七、为指定目标构建固件:实操命令

在仓库根目录使用fbt构建非默认目标时,必须显式指定TARGET_HW(可选加FIRMWARE_APP_SET)。例如为 f18 目标构建并烧录调试固件:

./fbt TARGET_HW=18 flash_usb_full

若使用 Windows 环境,则对应fbt.cmd脚本。默认目标为 f7(Flipper Zero),可直接省略TARGET_HW。烧录、更新、FAP 构建等其他目标操作沿用fbt的标准子命令体系。

八、硬件身份识别:型号与合规信息的目标级实现

目标级差异最终会体现到运行时的设备身份识别上。两个目标各自的furi_hal_version_device.c实现了同一组 HAL 版本接口:

  • targets/f7/furi_hal/furi_hal_version_device.c:furi_hal_version_do_i_belong_here()在硬件目标为 7 或 0 时返回真,型号名为"Flipper Zero"、型号代码"FZ.1",并提供 FCC ID2A2V6-FZ、IC27624-FZ等合规编号;
  • targets/f18/furi_hal/furi_hal_version_device.c:对应逻辑检查硬件目标为 18 或 0,型号名为"Flipper Nano"、型号代码"FN.1",各项合规编号目前均为"Pending"(待定)。

这组接口与 targets/furi_hal_include/furi_hal_version.h 对应的全局声明配合,构成了"同一套 HAL API、按目标实现不同行为"的又一实例。

九、总结

Momentum-Firmware 的硬件目标体系可以概括为三句话:

  1. 一个代码库,多套硬件:targets/f7与targets/f18用target.json声明各自的头文件路径、链接脚本、SDK 符号与依赖库,furi_hal_include提供跨目标统一的 HAL API 入口;
  2. 继承为主、排除为辅:f18 通过"inherit": "7"复用 f7 的绝大部分配置,再用excluded_sources/excluded_headers/excluded_modules精确裁剪掉不存在的无线外设能力;
  3. 构建链全程贯通:TARGET_HW=7|18参数驱动HardwareTargetLoader解析定义、聚合源码与 SDK,firmwareopts.scons按场景选取链接脚本,appmanifest.py依据应用清单与FIRMWARE_APP_SET完成应用级裁剪。

对开发者而言,理解这套体系的意义在于:新增硬件平台时只需新建targets/f{id}/目录并编写target.json(必要时继承既有目标);为特定设备构建固件时只需指定TARGET_HW;而排查"某应用为何未构建"时,则应同时检查FIRMWARE_APP_SET、应用清单的targets字段与目标的excluded_modules三处配置。

  • 嵌入式
  • 物联网

【免费下载链接】Momentum-Firmware

🐬 Feature-rich, stable and customizable Flipper Firmware

项目地址:https://gitcode.com/GitHub_Trending/mo/Momentum-Firmware
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询