ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从零编译BetaFlight固件:STM32H7飞控源码搭建与烧录全攻略

从零编译BetaFlight固件:STM32H7飞控源码搭建与烧录全攻略 玩穿越机也有五六年了从最初只会刷写别人编译好的BetaFlight固件到后来自己动手改源码、加功能、适配硬件这条路走下来最大的感受是飞控源码其实没有想象中那么神秘真正动手去改一遍你对整个飞控系统的理解会完全不一样。这篇文章就以STM32H7平台为例记录我从零开始搭建穿越机固件的完整过程从环境准备到源码编译再到烧录调试每一步都有实操经验和踩坑记录希望能帮到想深入了解BetaFlight的玩家。先说说这篇文章适合谁。如果你已经能熟练使用BetaFlight Configurator调参、会刷固件但一直对固件是怎么来的充满好奇或者你是嵌入式方向的学生想找一个真实、活跃、代码量适中的开源项目练手再或者你是穿越机老玩家想给飞控加一些自定义功能——这篇文章就是为你准备的。我默认你有基础的C语言功底了解GPIO、UART、I2C这些外设概念但不需要你是嵌入式专家很多细节我会展开讲。1. 环境准备把编译工具链一次性搞定1.1 为什么选择Linux环境编译BetaFlight的编译工具链在Linux下是最顺畅的这不是我随口说的而是被Windows用户的血泪教训验证过的。虽然官方文档也支持Windows下的msys2环境但ARM交叉编译工具链在Windows上的路径处理、依赖管理确实容易出幺蛾子光是环境变量就能折腾你半天。我是直接用WSL2Windows Subsystem for Linux 2这样既能保留Windows日常使用的便利性又能获得接近原生Linux的编译体验。你不需要装双系统也不需要单独的Linux电脑一个WSL2就够了。WSL2的安装很简单管理员权限打开PowerShell执行wsl --install重启后按提示设置用户名密码然后安装Ubuntu 22.04 LTS。装完以后在Ubuntu终端里先跑一遍sudo apt update sudo apt upgrade把系统更新到最新后面装东西才不会碰到依赖版本太旧的问题。1.2 安装ARM编译工具链与GitBetaFlight用的是arm-none-eabi工具链这是ARM Cortex-M系列芯片的标准编译套件。在Ubuntu 22.04上可以直接用apt安装不过我强烈建议你去ARM官网下载最新版本的工具链因为apt仓库里那个版本往往偏旧有时候会编译不过。我自己用的是gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2这个版本实测很稳定。下载后解压到~/tools/目录然后把bin目录加进PATH。# 安装依赖工具 sudo apt install git make cmake python3 python3-pip # 解压ARM工具链到主目录 cd ~ mkdir -p tools tar xjf gcc-arm-none-eabi-10.3-2021.10-x86_64-linux.tar.bz2 -C tools/ # 将工具链加入环境变量 echo export PATH$PATH:~/tools/gcc-arm-none-eabi-10.3-2021.10/bin ~/.bashrc source ~/.bashrc # 验证工具链是否安装成功 arm-none-eabi-gcc --version看到版本信息输出就说明工具链装好了。Git用于拉取源码和版本管理这个没啥好说的BetaFlight的源码托管在GitHub上更新频率很高用Git可以方便地切换版本、查看历史改动。我把BetaFlight的仓库克隆到~/betaflight目录下后面所有操作都在这个目录里进行。2. 源码获取与工程结构解读先看懂地图再出发2.1 拉取源码与分支选择克隆BetaFlight源码很简单但分支选择有讲究。主分支master是开发版代码更新快但偶尔会有编译不过或者行为改变的情况不适合稳定飞行。正式发布的版本会打tag比如4.4.2、4.5.0这些稳定性和性能都经过大量测试适合日常使用和第一次尝试编译。# 克隆稳定版源码以4.5.0为例 git clone --branch 4.5.0 https://github.com/betaflight/betaflight.git cd betaflight # 查看当前版本信息 git describe --tags这里我建议第一次编译的人选择你手上飞控对应的官方release版本不要上来就编译master分支。原因很简单release版本的配置和文档是匹配的出了问题也好查资料master分支的代码可能引入了新的配置格式网上搜到的教程不一定适用。2.2 源码目录结构与核心文件BetaFlight源码的组织结构很清晰理解它的结构是后续改代码的基础。我用树形图把核心目录梳理一下betaflight/ ├── src/main/ │ ├── target/ # 目标板配置文件 │ │ ├── STM32H7/ # H7平台通用代码 │ │ └── STM32F4/ # F4平台通用代码 │ ├── flight/ # 飞控核心算法 │ │ ├── pid.c # PID控制器 │ │ ├── mixer.c # 混控器 │ │ └── position.c # 位置控制 │ ├── drivers/ # 底层驱动 │ │ ├── accelgyro/ # 加速度计/陀螺仪驱动 │ │ ├── barometer/ # 气压计驱动 │ │ └── light_led.c # LED驱动 │ ├── fc/ # 飞控核心逻辑 │ ├── io/ # 输入输出处理 │ └── msp/ # MSP协议实现 ├── Makefile # 顶层编译脚本 ├── src/main/target/ # 各种飞控板的配置目录 └── src/main/build/ # 版本信息与构建配置src/main/target/目录下每个子目录对应一款飞控板目录名就是target名称比如STM32F745表示使用STM32F745芯片的飞控板。每个target目录里最关键的文件是target.h和target.c前者定义了引脚映射、外设配置、功能开关等宏后者实现了板级初始化逻辑。如果你想给自己的飞控板适配BetaFlight主要就是改这两个文件。2.3 查看H7平台目标板配置文件以STM32H7平台的飞控板为例在src/main/target/下找到对应的target目录打开target.h你会看到大量宏定义。挑几个核心的来说#define TARGET_BOARD_IDENTIFIER S7H7 // 板卡标识符 #define USBD_PRODUCT_STRING S7H7 // USB识别名称 // 定义CPU频率 #define SYSTEM_CLOCK 400MHz // H7高性能模式 // 陀螺仪SPI总线配置 #define USE_GYRO_SPI_MPU6500 #define GYRO_MPU6500_ALIGN CW180_DEG // 陀螺仪安装方向 #define USE_ACC_SPI_MPU6500TARGET_BOARD_IDENTIFIER是BetaFlight识别不同飞控板的唯一ID升级固件时Configurator会检查这个ID是否匹配。GYRO_MPU6500_ALIGN定义了陀螺仪的安装方向这个配置错了会导致飞控姿态混乱严重的话上电自检都过不了。这些宏就是在告诉编译器我这块板子有哪些硬件、引脚怎么接的、传感器朝什么方向编译的时候会根据这些宏裁剪代码把用不到的驱动和功能统统去掉这也是BetaFlight的固件能塞进容量不大不小的Flash的原因。3. 核心配置解析把板子翻译给固件3.1 target.h的引脚映射机制引脚映射是target.h里最核心也最容易出错的部分。STM32H7芯片的引脚资源丰富但每个引脚的功能是固定的引脚复用所以必须把飞控板上STM32H7的每个引脚用在了哪里明确地告诉固件。比如你的飞控板上陀螺仪MPU6500接在SPI1总线CS引脚是PE4那就要这样配置#define USE_GYRO_SPI_MPU6500 #define GYRO_SPI_INSTANCE SPI1 #define GYRO_CS_PIN PE4 #define GYRO_EXTI_PIN PE3 // 陀螺仪数据就绪中断引脚SPI几个引脚SCK、MISO、MOSI是固定的不需要单独定义但CS片选引脚和EXTI中断引脚必须指定。EXTI引脚很重要陀螺仪数据准备好后通过这个引脚通知MCU读取如果这根线接错了固件虽然能启动但陀螺仪数据会一直读不到飞控会报传感器故障。我曾经在一块自制飞控上把EXTI接错了引脚整整排查了两天才发现所以说引脚配置这种错误很难从代码上找原因只能对着原理图一根一根核对。资源映射不止支持SPI还支持UART、I2C、ADC、DMA等外设。每个外设引脚都定义在target.h里配置好后编译进固件这就是为什么同一个BetaFlight源码能支持几十种飞控板——硬件差异全被target.h里的宏隔离了。3.2 功能裁剪与宏开关BetaFlight支持通过宏定义裁剪功能不需要的驱动和功能模块不会被编译这样可以节省Flash空间和RAM占用。STM32H7的Flash足够大1MB到2MB实际使用中不太会空间不够但功能裁剪能让固件更精简、启动更快、内存占用更低。// 根据硬件情况启用/禁用功能 #define USE_ACC_SPI_MPU6500 // MPU6500加速度计 #define USE_BARO_BMP280 // BMP280气压计 #define USE_FLASH_W25Q128 // 板载Flash存储器用于黑匣子 #define USE_MAX7456 // MAX7456模拟OSD芯片 // 禁用不需要的功能 // #undef USE_BARO_BMP280 // #undef USE_FLASH_W25Q128在配置这些宏的时候一个比较实用的思路是先看自己的飞控板硬件上有哪些芯片再去target.h里找到对应的宏打开没有的芯片对应的宏就关掉。我自己遇到过一种情况飞控板上有气压计但我没打开USE_BARO的定义导致固件不识别气压计在Configurator里死活看不到高度数据。这里给个建议如果你不确定某个功能是否被启用在源码里搜USE_BARO或者相关关键词看宏的位置和注释比自己瞎猜靠谱得多。3.3 自定义target基于现有板卡修改最省事的方式不是从零创建一个target而是基于现有相近的target修改。比如你手上的飞控板用了新的陀螺仪型号但其他硬件和某个已知target完全一致那就复制那个target目录改个名字然后把陀螺仪相关的驱动和引脚映射换掉就行。# 复制现有target目录 cp -r src/main/target/STM32H743 src/main/target/MYCUSTOMH7 # 修改target.h中的板卡标识符 # 把 TARGET_BOARD_IDENTIFIER 改成自己定义的标识符在src/main/target/MYCUSTOMH7/target.h里有几处需要认真处理TARGET_BOARD_IDENTIFIER改为自定义的4字符标识符不能与现有board冲突。USBD_PRODUCT_STRINGUSB识别名称随便起一个。引脚映射宏对照原理图逐条核对传感器、电机、LED、接收机等外设的引脚是否和当前板卡一致。DEFAULT_RX_TYPE等默认配置根据自己使用的接收机协议修改。创建自定义target后编译需要指定这个target名称。在BetaFlight 4.5.x中Makefile支持TARGET变量语法是make TARGETMYCUSTOMH7编译完成后会在obj目录下生成betaflight_4.5.0_MYCUSTOMH7.hex文件。这个hex就是你要烧录的固件。注意直接修改现成的target并烧录到不同型号的飞控板上有可能因为引脚不匹配导致硬件损坏。一定要确认每个引脚的连接关系特别是电源引脚、电机IO、电池电压采样这些关键信号。4. 完整编译流程从源代码到hex固件4.1 编译命令与构建系统说明BetaFlight的构建系统就是Makefile比较简单直接。在确保工具链配置正确、依赖安装完整后编译只需要一条命令。但为了成功编译H7平台有些细节需要注意。# 清理之前的编译产物如果需要干净编译 make clean # 编译指定target以STM32H743为例 make TARGETSTM32H743 # 只编译不链接检查代码语法编译速度快 make TARGETSTM32H743 build如果只是改了一些配置想快速检查是否有语法错误用make build会很快它只编译C文件生成目标文件不进行链接能省不少时间。确认无误后再执行不带build的完整编译生成最终的hex固件。BetaFlight的整个编译过程大概3-5分钟H7平台代码量更大比F4平台慢一些。编译过程中终端会滚动输出大量信息包括每个C文件的编译状态最后几步会链接、生成hex文件。看到betaflight_4.5.0_STM32H743.hex文件生成就代表编译成功了。4.2 常见编译错误与解决方法编译H7平台时最常见的错误几乎都集中在工具链版本不匹配、定义缺失、内存越界这几类。我把自己实际遇到过的错误和解决方法整理成了表格错误信息主要原因解决方法arm-none-eabi-gcc: not found工具链没加入PATH确认路径重新export或修改.bashrcobject directory obj/... does not exist目录未自动创建执行mkdir -p obj或先执行make cleanundefined reference to xxx某些驱动没被包含确认target.h里对应USE_开关已打开region FLASH overflowed by xxx bytes固件超过Flash容量裁剪不需要的功能或换用更高容量芯片Error: unknown type name xxx头文件互相依赖问题检查include顺序必要时添加#include这里特别说一下region FLASH overflowed这个错误很多人第一次遇到会慌。这通常是因为启用了太多功能而H7的Flash容量不够。解决思路很简单关掉不用的驱动和功能。在target.h里把用不到的传感器驱动注释掉把#define USE_MAX7456这种OSD相关功能去掉固件体积能瘦身不少。我有一块板子把所有用不到的功能裁掉之后Flash占用从92%降到了65%运行更稳定。4.3 Makefile中的高级编译选项正式编译中可能用到的几个Makefile高级选项也一并分享给各位。这些选项在排查问题和验证功能的时候特别有用# 编译带调试信息的固件体积更大不能直接飞行 make TARGETSTM32H743 DEBUGGDB # 指定编译过程中使用的CPU核心数加速编译 make TARGETSTM32H743 -j8 # 编译时保留中间产物汇编文件等 make TARGETSTM32H743 V1-j8这个参数我建议加上H7平台编译时间比F4长了一倍不止我试过8核并行后编译时间能缩短到1分钟左右。DEBUGGDB会生成带调试符号的固件这种固件体积很大Flash塞不下我只在需要GDB调试底层驱动时才会用。还有一种情况是修改了target.h后编译报错提示宏定义重复或冲突。这种情况多半是因为不同头文件都定义了一个宏但值不一样。遇到这种问题别急着改代码先在源码里全局搜一下这个宏看它在哪里定义、在哪里使用理清楚关系后再动手。记住一个原则BetaFlight的代码质量很高宏观设计清晰你遇到编译错误大概率是配置问题而不是源码问题。5. 固件烧录与首飞配置让固件跑起来5.1 使用BetaFlight Configurator烧录固件固件编译好了接下来就要把它烧录进飞控。最直接的方式是用BetaFlight Configurator它内置的烧录功能很完善支持本地hex文件烧录。打开BetaFlight Configurator先把飞控通过USB连接到电脑。然后点击左侧的固件烧写按钮在界面里选择从本地文件加载固件选中编译生成的hex文件点击写入固件。烧录过程中飞控板的指示灯会闪烁电脑上也会出现确认弹窗一切正常的话十几秒就能完成。烧录完成后一定要先点击连接按钮确认固件能正常运行。如果出现固件已损坏或者无法连接、串口识别不到设备等问题多半是烧录过程中出错了重新进入DFU模式再刷一次基本都能解决。5.2 使用命令行烧录STM32CubeProgrammerConfigurator虽然方便但偶尔会有识别不到飞控的情况特别是你改过自定义target后USB的描述字符串变化了Configurator可能不认识这块板子。这时候用ST官方工具STM32CubeProgrammer简称STM32CubeProg就是最稳妥的方案它能绕过所有上层逻辑直接对STM32H7芯片进行烧录。# 进入DFU模式的常用方法按住飞控板上的BOOT按钮同时插入USB线 # 然后使用STM32CubeProgrammer的命令行模式烧录 STM32_Programmer_CLI -c portUSB1 -w betaflight_4.5.0_MYCUSTOMH7.hex -v命令行的参数解释如下-c portUSB1指定连接方式为USB1接口。-w xxx.hex写入固件文件。-v烧录完成后校验确保固件写入无误。STM32CubeProgrammer会先识别MCU信息然后擦除Flash、写入固件、校验数据。整个过程在终端里打印进度非常清晰。5.3 第一次启动与CLI配置烧录完成后拔掉USB线重新插上让飞控以正常运行模式启动然后在Configurator里点击连接。连接成功后第一件事不是去调PID而是依次完成这几项基本配置在配置页面选择正确的飞行器类型四旋翼X型、四旋翼型等。在端口页面设置接收机的UART端口和协议SBUS、CRSF等。在电机页面验证电机转向和顺序。在传感器页面校准加速度计和磁力计。BetaFlight也支持通过CLI命令行进行配置。CLI的入口在Configurator右上角的图标用起来和路由器命令行很像。CLI的优势是能精确控制每一个参数适合批量修改和脚本化操作。举个例子如果你把电机IO引脚改了但不想在Configurator里一级级菜单找可以直接用CLI查看和修改资源映射# 在CLI中输入dump命令查看当前全部配置参数 dump # 输入resource命令查看所有引脚映射 resourceresource命令会在终端列出所有当前引脚映射情况这是排查硬件问题时最常用的命令。如果陀螺仪没有数据先看resource输出里陀螺仪的SCK、MISO、MOSI、CS、EXTI引脚是否和原理图一致。在CLI下还能用get和set命令查看或修改参数比如get pid可以查看当前PID参数set pid_dashboard ON可以开启PID仪表盘。5.4 电机顺序与传感器校准电机顺序应该是新固件烧录后最需要小心的一步。电机接错了顺序推油门的时候飞控会直接翻转严重的话就是炸机。BetaFlight Configurator在电机设置页面有个方向测试功能可以逐一让每个电机转动你把飞控放在桌面上试转确认每个电机都对应正确的通道和方向。在CLI里可以用motor命令进行同样的测试输入motor 1再输入一个0到100的值比如motor 1 10电机1就会以10%的油门转动松开即停。测试完之后记得给飞控断电再上电把电机IO复位到正常模式。传感器校准这步也很重要尤其是加速度计。在Configurator的传感器页面把飞控平放点击校准加速度计整个过程几秒钟就完成了。磁力计校准要麻烦一些需要把飞控拿在手上在空中画8字让磁力计的每个方向都得到充分的数据覆盖。校准完成后CLI里会显示校准状态一切正常就能进入下一步了。6. 常见问题与排查技巧实录6.1 编译阶段典型问题与解决做这个项目的过程中我在编译阶段遇到的问题最多这里挑几个典型的案例说。第一个是工具链版本问题。有段时间我换了新版本的工具链结果编译H7平台时老是报r0 operand is incompatible with...这种莫名其妙的内联汇编错误。查了一堆资料才发现是新工具链的汇编语法要求更严格了BetaFlight源码里一些用于任务切换的汇编代码不再兼容。后来我固定在10.3版本工具链再也没出过这种问题。所以如果你编译遇到汇编相关的错误先检查工具链版本别先去改源码。第二个问题是target.h中包含的头文件顺序。我自定义target时把#include platform.h放在了一个很奇怪的位置结果编译时系统头文件、飞控头文件、外设头文件互相交叉引用报了一堆undefined type的错误。后来按其他target的标准格式调整了include顺序编译就顺畅了。这个教训告诉我改动target文件时要保持和官方target结构的一致性不要随意摆弄。第三个常见问题是编译输出信息中有很多warning让人心里没底。实际上BetaFlight官方代码编译时本身就会有一些warning很多是无害的比如未使用的变量、隐式类型转换等。能不能忽略warning要看内容如果是关于类型不匹配、指针越界的warning最好重视一下这种往往对应着真实的问题。如果是未使用变量的warning直接忽略即可。6.2 硬件启动阶段的排查思路每次烧录新固件后第一次上电都是我最紧张的时刻。如果飞控能正常连接一切安好但有时候飞控就是连不上或者传感器报错这时候就需要系统地排查了。排查思路从底层往上走先确认芯片有没有正常启动。方法是在CLI里输入version如果能看到系统版本信息说明MCU已经正常运行问题出在软件配置上。如果CLI完全无响应先检查USB线是否数据线很多USB线只能充电、驱动是否装好、飞控是否处于DFU模式忘记退出。传感器报错是另一个常见问题。Configurator里如果陀螺仪或加速度计显示红色警告先用resource命令确认引脚映射是否正确再用sensors命令查看传感器检测状态。很多时候传感器检测失败是因为SPI总线的CS引脚冲突了——比如两个传感器共用了同一个CS引脚或者CS引脚被其他外设占用了。在resource命令的输入里检查有没有重复使用同一个引脚的情况。6.3 烧录失败后的救砖技巧烧录失败这件事几乎每个玩飞控的人都遇到过。所谓变砖就是飞控的固件被写坏了无法正常启动也无法连接Configurator。但STM32H7这代芯片都有硬件DFU模式只要不是Flash被彻底锁死基本都能救回来。进入DFU模式的方法很简单拔掉USB线按住飞控板上的BOOT按钮不放再插入USB线等2秒后松开BOOT按钮。此时电脑设备管理器里应该会出现一个STM32 Bootloader设备。然后用前面提到的STM32CubeProgrammer重新烧录一个正常固件就行了。如果BOOT按钮不好按我有一块板子的按钮位置特别反人类也可以短接BOOT引脚和GND再上电效果一样。进入DFU模式后别急着烧录先用STM32CubeProgrammer读取一下芯片信息确认芯片型号和Flash大小避免固件和目标芯片不匹配导致烧录后依旧无法启动。只要DFU模式能进救砖就成功了一大半。注意烧录过程中千万不要在固件写入到一半的时候拔掉USB线这是把飞控彻底变砖的最快方式。如果烧录过程中断等10秒以上再重新插线让Flash完成写入和掉电保护然后再重新进入DFU模式重刷。6.4 飞行调试阶段的经验技巧固件烧录成功、所有校准都做完了飞机也应该能正常悬停了但实际飞行中我还是遇到过几个很有意思的问题这里一起说一下希望能帮各位少走弯路。第一件事是电机怠速不稳。如果你发现解锁后电机转速忽高忽低、飞机在地面上抖动先别急着怀疑PID参数。检查一下电机是否使用了正确的协议。在Configurator的配置页面里把电机协议改成你电调支持的协议常见的有DShot600、DShot300、PWM等。我用的是DShot600之前误选成了DShot300导致通信频率不匹配电机响应明显延迟看上去就像怠速不稳。协议改对之后问题立刻消失了。第二件事是电压监测不准。H7飞控的板载ADC采样电池电压很常见但我第一次编译完固件后发现电压读数比万用表量出来的高了0.5V。这个问题的根源是分压电阻网络的分压比固件通过voltage meter参数计算实际电压如果分压电阻值和默认值不一致读数就会偏。解决办法是在CLI里计算实际分压比然后设置set vbat_scale参数。计算方法很简单用万用表量出电池真实电压再看Configurator里的显示值两者相除就是修正系数。比如真实值是16.8V显示是16.2V那分压比修正系数就是16.8/16.2≈1.037把vbat_scale乘以这个系数就行了。第三件事是黑匣子数据记录。黑匣子丢失了很多关键数据后来才发现是我没在target.h里正确配置板载Flash芯片。我用的Flash芯片是W25Q128在target.h里打开USE_FLASH_W25Q128宏并正确配置CS引脚后黑匣子功能才正常工作。黑匣子的数据对分析飞行中的抖动、机架共振、PID响应非常有帮助强烈建议确保它正常工作。经验总结几个受用很久的习惯一次性讲了很多最后分享几个我在做这个项目过程中积累的习惯如果你能从一开始就养成的话后面真的会少很多麻烦。第一修改源码之前一定先备份。不管是改target.h还是改PID算法先把原始文件复制一份再动手。我吃过亏的一次改坏了target里的引脚映射想恢复却发现git已经提交了新的版本来回对比了半天才找到改动的地方。用git diff查看改动细节是最理想的建议你从一开始就用Git管理自己的修改。第二每次编译成功后把固件文件和对应的源码版本一起保存起来。换电脑、升级系统、重新拉取源码之后经常发现同样的配置编出来效果和原来不一样工具链版本、依赖库的变化都会影响编译结果。我曾经在一台新电脑上重新编译结果固件飞行手感完全变了排查了几天最后发现是工具链版本差异导致的。飞控的每一个参数都和固件版本强相关保留完整的版本信息能让后续调试少走很多弯路。第三善用Git分支功能。我在适配一块新飞控板时习惯先基于官方正式版本拉一个分支在这个分支上做修改保证modification和原始版本完全隔离。这样出了问题可以快速切回官方版本对比排查是源码的问题还是自己改动的问题。如果测试稳定了再考虑把改动合并到自己的主用分支这个过程很舒服也符合嵌入式开发的良好实践。第四多去读官方文档和源码里的注释少盲猜。BetaFlight的源码注释虽然不算多但每个关键数据结构的定义、每个复杂宏的用途都有清楚的解释。我在配置文件里经常看到类似// Set this to the right value这样的提醒这种地方往往就是最容易出错的点读注释能帮你省掉大量排查时间。搭建穿越机固件这件事本质上是一个硬件、软件、工艺三者结合的系统工程。整个过程下来你对BetaFlight的理解会远超那些只会刷固件的玩家。什么东西能改、改了有什么影响、出了问题从哪里查脑子里会有一个完整的图景。如果你也喜欢这种知其所以然的感觉那就动手吧从编译第一个固件开始你会打开一扇新的大门。
返回列表