
1. 项目概述从“9.9包邮”到“刷DFU”的折腾之旅最近在电子爱好者圈子里合宙的Air32开发板绝对是当红炸子鸡。不到十块钱还包邮就能拿到一块基于ARM Cortex-M33内核的MCU开发板这性价比简直让人无法拒绝。我手痒也跟风买了几块到手后发现这板子默认的固件和开发环境对于想玩点花样的我来说有点不够“趁手”。于是一个核心需求就冒出来了给它刷上DFUDevice Firmware Upgrade功能。你可能要问原厂不是有下载工具吗为什么还要折腾DFU原因很简单方便和独立。原厂的下载器通常需要特定的上位机软件有时还得装驱动换台电脑就得重新配置。而DFU特别是基于USB的DFU意味着你只需要一根USB线就能在任何支持标准DFU协议的电脑上像给U盘拷贝文件一样更新固件。这对于项目调试、现场升级甚至是做成产品后的维护都是一种“解放生产力”的操作。今天我就来详细拆解一下如何给这块“白菜价”的Air32开发板刷上DFU功能让它从一个简单的评估板变成一个可以随时“无线”这里指免专用下载器升级的智能硬件核心。2. 核心需求解析与方案选型2.1 为什么是DFU而不是其他给MCU刷写固件常见的方式有好几种JTAG/SWD调试器、串口ISP、USB DFU、OTA空中升级等。对于Air32这块板子我们逐一分析JTAG/SWD这是最底层、最强大的调试和下载方式需要专用的调试器如J-Link、DAP-Link。虽然稳定可靠但额外增加了硬件成本和携带负担不符合我们追求极致简便和低成本的目标。串口ISP很多MCU都支持通过串口UART进行程序烧录通常需要配合特定的Bootloader和上位机软件。Air32原厂工具主要就是这个模式。它的缺点是速度相对较慢且需要用到USB转串口模块虽然开发板可能集成了仍然不够“纯粹”。OTA通常需要设备已经具备网络连接能力如Wi-Fi、蓝牙和一套复杂的升级协议。对于刚到手的基础开发板这属于“远期目标”不是当前能直接实现的。USB DFU这正是我们想要的。Air32F103系列芯片以Air32F103CBT6为例内部自带USB接口这为实现USB DFU提供了硬件基础。DFU是USB设备的一个标准类协议操作系统如Windows、macOS、Linux有原生或通用的驱动支持。一旦刷入DFU模式的Bootloader后续更新固件就只需要USB线 - 进入DFU模式 - 系统识别为DFU设备 - 使用dfu-util等通用工具或图形化工具拖拽烧录。整个过程无需安装任何芯片厂商特定的软件极度便捷。所以刷DFU的核心需求实质上是为开发板更换或植入一个支持USB DFU协议的Bootloader。Bootloader是一段存储在MCU Flash起始地址的小程序它负责在芯片上电后首先运行判断是否满足进入固件升级的条件如检测某个按键是否按下如果满足则跳转到DFU程序段等待主机连接如果不满足则直接跳转到用户应用程序。2.2 方案选型基于社区开源方案合宙的生态很大程度上依赖于活跃的社区。对于Air32刷DFU目前最成熟、接受度最高的方案是使用社区大神们基于STM32的DFU Bootloader移植和适配的版本。为什么可以用STM32的方案因为Air32F103与STM32F103在硬件引脚和内核上是高度兼容的这也是它性价比的来源之一许多为STM32编写的软件经过少量修改就能在Air32上运行。我们将采用以下方案路径目标Bootloader使用经过验证的、适用于STM32F103的USB DFU Bootloader开源代码并针对Air32的时钟配置特别是外部晶振频率进行适配。刷写工具第一次刷Bootloader我们仍然需要借助一种“底层”方式。由于Air32开发板通常自带了一个USB转串口芯片如CH340并连接到了MCU的串口1PA9/PA10我们将使用串口ISP的方式通过这个现成的USB口来刷入最初的DFU Bootloader。这被称为“鸡生蛋”的第一步。后续升级工具一旦DFU Bootloader刷入成功后续所有用户应用的固件升级都将通过USB DFU模式完成使用通用的dfu-util命令行工具或类似STM32CubeProgrammerDFU模式这样的图形化工具。这个方案的优点是稳妥、可复用、社区支持好。我们站在了巨人的肩膀上避免了从零编写Bootloader的复杂性和风险。3. 准备工作与工具链搭建3.1 硬件准备与确认首先确保你的Air32开发板在手边。常见的9.9元版本是Air32F103CBT6核心板搭载一颗LQFP48封装的MCU。你需要确认以下几点USB口板上应该有两个Micro-USB或Type-C接口。一个用于MCU的USB DP/DM实现USB通信另一个用于USB转串口芯片实现串口通信和供电。请仔细查看板子丝印或原理图区分这两个口。通常连接串口芯片的那个口也负责给整个板子供电。Boot模式选择STM32/Air32系列芯片有启动模式选择引脚BOOT0, BOOT1。大多数DFU Bootloader需要芯片从系统存储器System Memory或SRAM启动才能被激活。但一个设计良好的DFU Bootloader通常会集成到用户Flash区并通过检测某个GPIO引脚如用户按键的状态来决定是否进入DFU模式。因此我们可能需要查看目标Bootloader代码的进入条件。对于初次刷写为了通过串口ISP下载我们需要确保芯片能从系统存储器启动这通常需要将BOOT0接高电平BOOT1接低电平。有些开发板通过跳线帽设置有些则通过按钮组合。请根据你的板子情况准备。注意很多合宙的板子为了简化已经将启动模式固定为从用户Flash启动并通过一个复位按钮和一个可编程按钮如BOOT键来实现DFU进入。具体需要查阅你手上的板子资料或社区帖子。3.2 软件工具准备我们需要在电脑上准备以下软件环境串口ISP刷写工具用于第一次刷入DFU Bootloader。推荐工具stm32flash。这是一个开源、跨平台的命令行工具非常好用。对于Windows用户可以下载预编译的exe文件Linux和macOS用户通常可以通过包管理器安装如apt install stm32flash,brew install stm32flash。备用工具合宙官方提供的Luatools。虽然主要针对Lua开发但其“下载器”功能底层也是串口ISP可以作为备选。DFU Bootloader源码与固件我们需要获取针对Air32适配好的DFU Bootloader二进制文件.bin或.hex。你可以在GitHub、Gitee或合宙社区论坛搜索“Air32 DFU Bootloader”。一个常见的来源是air32f103/Arduino_Core_STM32相关的社区分支里面通常会包含编译好的bootloader.bin。如果你想自己从源码编译则需要准备ARM GCC工具链如arm-none-eabi-gcc和构建系统如Make。这适合想深度定制或学习的用户。对于大多数使用者直接下载预编译的bin文件即可。DFU模式刷写工具为后续使用准备dfu-util这是最核心、最通用的DFU设备刷写命令行工具。跨平台支持。图形化工具可选如STM32CubeProgrammer它支持多种连接方式包括DFU。界面友好适合不习惯命令行的用户。驱动程序仅Windows可能需要USB转串口驱动确保连接串口ISP的那个USB口能被系统识别为COM口。CH340/CH341芯片需要安装对应驱动。WinUSB/LibUSB驱动为DFU模式当设备进入DFU模式后Windows可能无法自动识别需要借助Zadig工具为其安装通用的WinUSB或LibUSB驱动这样dfu-util才能与之通信。3.3 关键步骤原理梳理在动手前理解整个流程的时序很重要板子初始状态板载Flash里是原厂出厂程序或你之前写的程序。进入串口ISP模式通过设置BOOT引脚或上电时序让芯片从系统存储器启动运行内置的串口Bootloader。连接与擦写电脑通过串口工具stm32flash连接这个Bootloader擦除用户Flash区域并将我们准备好的DFU Bootloader程序写入Flash的起始地址通常是0x08000000。重启并验证让芯片从用户Flash启动BOOT0置低。此时新的DFU Bootloader开始运行。我们通过触发其进入DFU模式的条件如长按某个按键再复位让电脑的USB口识别到一个DFU设备。DFU模式测试使用dfu-util列出设备确认能正确识别。至此DFU Bootloader刷写成功。刷写用户程序以后你的应用程序代码需要编译成DFU可用的格式.dfu或.bin并通过dfu-util在DFU模式下刷入。注意你的应用程序链接地址需要避开Bootloader占用的空间例如从0x08000000 Bootloader大小 开始。4. 实操过程一步步刷入DFU Bootloader4.1 步骤一获取正确的DFU Bootloader固件这是最关键的一步用错了固件可能导致板子“变砖”虽然可以通过串口ISP救回。由于Air32的外部高速晶振HSE频率可能与标准的STM32F1038MHz不同Bootloader中的时钟初始化配置必须匹配否则USB时钟无法正确产生导致DFU设备无法被识别。经过社区验证Air32F103CBT6核心板常用的晶振是12MHz。因此你必须寻找或编译一个针对12MHz HSE时钟源配置好的DFU Bootloader。操作前往合宙社区论坛或开源代码托管平台如GitHub搜索关键词“Air32 DFU bootloader 12MHz”。找到一个可靠的发布帖或仓库下载编译好的air32_dfu_bootloader_12mhz.bin文件名称可能略有不同。将下载的.bin文件放在一个容易找到的路径例如D:\Air32\dfu_bootloader.bin。实操心得如果找不到现成的你可以尝试自己修改源码编译。通常需要修改system_air32f10x.c或类似文件中的#define HSE_VALUE将其从80000008MHz改为1200000012MHz然后重新编译。但这需要搭建完整的编译环境对新手有一定门槛。优先使用社区验证过的二进制文件。4.2 步骤二通过串口ISP刷写Bootloader假设你的开发板通过USB线连接串口芯片的那一端连接电脑后在设备管理器中识别为COM3Windows或/dev/ttyUSB0Linux。操作让板子进入串口ISP模式查看你的板子是否有BOOT0跳线或按钮。如果有将BOOT0设置为高电平接3.3VBOOT1设置为低电平接GND。对于只有按键的板子通常的操作是先按住板子上标记为BOOT或FLASH的按键不要松手再按一下RESET复位键然后松开RESET键最后松开BOOT键。这个操作模拟了BOOT0在上电时为高的状态。成功后板子上的主芯片应该不会运行之前的用户程序而是等待串口指令。使用stm32flash工具刷写打开命令行终端Windows CMD/PowerShell Linux/macOS Terminal。切换到存放dfu_bootloader.bin的目录。执行刷写命令。命令格式因操作系统和芯片系列略有不同以下提供常见示例对于STM32F1系列Air32兼容通常使用-v验证和-g 0x0刷完后从0地址开始运行参数# Windows 示例假设COM3波特率115200 stm32flash.exe -v -g 0x0 -w dfu_bootloader.bin COM3 -b 115200 # Linux/macOS 示例假设设备为/dev/ttyUSB0 stm32flash -v -g 0x0 -w dfu_bootloader.bin /dev/ttyUSB0 -b 115200执行命令后工具会尝试连接擦除Flash写入文件并进行验证。看到类似Flash written and verified!的信息表示成功。退出ISP模式并复位将BOOT0跳线改回低电平接GND或者直接给板子断电再上电。现在芯片将从用户Flash0x08000000启动也就是运行我们刚刷进去的DFU Bootloader。4.3 步骤三验证DFU Bootloader工作现在DFU Bootloader应该已经在运行了。大多数DFU Bootloader的触发方式是在芯片复位或上电时检测某个特定的GPIO引脚是否为低电平即按键按下。这个引脚通常是板上一个未被其他功能占用的用户按键比如PA0。操作查找触发引脚你需要知道你使用的那个DFU Bootloader固件其进入DFU模式的触发条件是什么。查看其源码的README或社区帖子。假设我们用的是社区某个版本其触发条件是“上电时PA0连接按键为低电平则进入DFU模式”。触发DFU模式找到板上连接PA0的按键可能需要查看原理图。如果没有明确标注可以尝试按住板上除了复位键以外的另一个按键常被称为KEY或USER。按住这个按键不放然后按一下RESET复位键或者重新插拔USB线给板子重新上电。保持按键按住几秒钟。检查系统识别将板子的另一个USB口直接连接MCU USB D/D-的那个插入电脑。在Windows下打开设备管理器在Linux下使用lsusb命令在macOS下使用system_profiler SPUSBDataType。你应该能看到一个新设备在Windows上可能显示为“STM32 BOOTLOADER”或“USB DFU DEVICE”在Linux下lsusb的输出中会有类似ID 0483:df11 STMicroelectronics STM Device in DFU Mode的信息。如果没看到检查按键触发条件是否正确USB线是否完好Bootloader固件时钟配置是否正确12MHz。这是最容易出问题的环节。4.4 步骤四安装DFU工具并测试通信安装dfu-utilWindows从dfu-util官网或开源项目发布页下载编译好的Windows二进制包解压后将dfu-util.exe所在目录添加到系统PATH环境变量或在命令行中直接使用其完整路径。Linux使用包管理器安装例如sudo apt install dfu-util。macOS使用Homebrew安装brew install dfu-util。Windows驱动处理重要如果设备管理器中的DFU设备显示为“未知设备”或带有黄色叹号你需要使用Zadig工具为其安装通用驱动。打开Zadig在Options菜单中勾选“List All Devices”。从设备列表中找到你的DFU设备如“STM32 BOOTLOADER”。选择驱动程序为WinUSB或libusb-win32点击“Replace Driver”或“Install Driver”。成功后设备管理器里应该显示为“STM32 BOOTLOADER (WinUSB)”。测试DFU连接打开命令行输入以下命令dfu-util -l如果一切正常你会看到类似下面的输出列出了找到的DFU设备及其详细信息内部Flash、RAM等Found DFU: [0483:df11] ver2200, devnum12, cfg1, intf0, path1-4, alt0, nameInternal Flash /0x08000000/128*001Kg, serialFFFFFFFEFFFF看到这个就大功告成了你的Air32开发板已经成功变身为一台支持USB DFU升级的设备。5. 使用DFU模式刷写用户应用程序Bootloader刷好了接下来就是享受成果的时候。以后你编译好的用户程序都可以通过DFU模式来刷入无需再碰串口和跳线帽。5.1 准备用户程序固件你的应用程序代码比如用Keil、Arduino、PlatformIO等编译需要输出为.bin或.hex文件。为了使用dfu-util我们通常使用.bin文件。关键点链接地址偏移DFU Bootloader本身会占据一段Flash空间例如从0x08000000到0x08002FFF共12KB。你的用户程序不能覆盖这段区域否则Bootloader会被破坏导致无法再进入DFU模式。因此你必须在IDE或链接脚本中设置用户程序的起始地址VECT_TAB_OFFSET或FLASH_ORIGIN为Bootloader之后。例如如果Bootloader占用了0x8000字节32KB那么用户程序起始地址应设置为0x08000000 0x8000 0x08008000。同时在Bootloader代码中其跳转到用户程序的地址也必须与此匹配。5.2 使用dfu-util刷写固件将你的用户程序.bin文件准备好例如my_app.bin。让板子进入DFU模式按住指定按键上电或复位。在命令行中使用以下命令刷写dfu-util -a 0 -s 0x08000000:leave -D my_app.bin-a 0指定DFU设备的ALT交替设置通常内部Flash对应alt0。-s 0x08000000:leave指定起始地址为0x08000000:leave参数表示刷写完成后让设备退出DFU模式并跳转到该地址执行即运行你的应用程序。注意如果你的用户程序链接地址有偏移这里的起始地址也应该是偏移后的地址例如-s 0x08008000:leave。-D my_app.bin指定要下载的固件文件。命令执行后会显示擦除、编程、校验的进度。完成后设备会自动复位并运行你的新程序。5.3 图形化工具刷写以STM32CubeProgrammer为例对于喜欢点击操作的用户打开STM32CubeProgrammer。在连接方式中选择“USB”。点击“Refresh”刷新如果DFU设备驱动已装好会在下方列表中显示出来。选择该设备点击“Connect”。连接成功后切换到“Erasing Programming”标签页。在“Download”区域选择你的.bin或.hex文件并填写正确的起始地址例如0x08008000。勾选“Verify download”和“Run after”等选项。点击“Start Programming”即可。6. 常见问题与排查技巧实录即使按照步骤操作也可能会遇到各种问题。下面是我在多次实践中总结的“坑”和解决方案。6.1 问题使用stm32flash无法连接提示“Failed to init device.”可能原因1串口端口错误或驱动未安装。排查检查设备管理器确认USB转串口芯片如CH340对应的COM口号是否正确驱动是否正常无感叹号。解决安装正确的CH340驱动并在命令中使用正确的COM口。可能原因2板子未正确进入串口ISP模式。排查严格按照步骤操作BOOT0和复位时序。对于只有按键的板子按住BOOT键再上电的操作要确保在USB连接电脑供电的情况下进行。解决多尝试几次上电时序。也可以尝试先按住BOOT键再插入USB线供电。可能原因3波特率不匹配。排查STM32内置Bootloader支持的波特率有限如9600, 14400, 19200, 38400, 57600, 115200, 128000, 256000。stm32flash默认可能尝试所有波特率但有时会失败。解决在命令中明确指定一个常用波特率如-b 115200或-b 57600。6.2 问题DFU Bootloader刷入后无法触发进入DFU模式电脑不识别DFU设备可能原因1触发按键或引脚不对。排查这是最常见的原因。你用的Bootloader固件可能定义了不同的触发引脚如PC13,PA8等而不是你按的那个。解决仔细阅读你所用的Bootloader的说明文档。如果没有一个“笨办法”是将板子上所有能按的按键除了复位分别尝试长按然后上电。也可以尝试将某个引脚通过杜邦线短接到地GND来模拟按键按下。可能原因2Bootloader时钟配置错误。排查如果Bootloader是针对8MHz晶振编译的而你的板子是12MHz晶振那么USB时钟无法正确产生自然无法被识别为USB设备。解决必须使用针对12MHz HSE编译的Bootloader固件。这是Air32和STM32原版的一个重要区别。可能原因3USB数据线或端口问题。排查有些USB线只能充电不能传输数据。或者电脑的某个USB口供电不足。解决换一根确认能传输数据的USB线并换到电脑后置的USB口试试。6.3 问题dfu-util -l 能找到设备但刷写时失败可能原因1地址或文件格式错误。排查-s参数指定的地址是否合理.bin文件是否有效解决确保地址是Flash的起始地址考虑偏移。确保.bin文件是最近一次成功编译生成的。可能原因2Flash被写保护。排查某些情况下Flash可能被设置了读保护RDP等级阻止写入。解决通过串口ISP模式使用stm32flash的-u参数解除保护或-j参数解除保护并擦除先解除保护。命令如stm32flash -u COM3。注意解除保护会擦除整个Flash包括Bootloader。可能原因3Bootloader未正确实现DFU协议。排查使用dfu-util -l查看设备信息时确认其提供的存储介质描述是否正确如内部Flash的大小。解决如果描述异常可能是Bootloader代码有缺陷。尝试换用另一个来源的、经过更多人验证的Bootloader固件。6.4 问题用户程序刷入后不运行可能原因1用户程序链接地址与Bootloader跳转地址不匹配。排查这是最可能的原因。你的程序编译时中断向量表起始地址VECT_TAB_OFFSET是否设置为偏移后的地址Bootloader跳转时是否跳到了同样的地址解决检查并统一两边的地址设置。确保用户程序从正确的偏移地址开始链接。可能原因2用户程序本身有问题。排查尝试将用户程序通过串口ISP方式直接烧录到0x08000000不经过Bootloader看是否能运行。如果不能则是程序本身的问题。解决调试你的用户程序确保其时钟初始化、外设配置等正确。6.5 高级技巧与注意事项备份原厂固件在刷写任何Bootloader之前可以通过串口ISP模式用stm32flash -r original.bin COM3命令将原厂Flash内容读出来备份以备不时之需。Bootloader大小与优化社区开源的DFU Bootloader通常大小在12KB到20KB之间。如果你的用户程序很大需要关注Flash容量Air32F103CBT6为128KB。在资源紧张时可以考虑裁剪Bootloader功能如只保留USB DFU去掉其他接口或者寻找更精简的实现。双Bank Flash设备的考虑有些大容量STM32/Air32芯片支持双Bank Flash可以实现“滚动升级”一边运行旧程序一边后台写入新程序。如果你的Bootloader和应用程序支持这个特性可以实现更安全的OTA。但这属于更高级的应用。生成.dfu文件dfu-util也支持专用的.dfu文件格式它包含了目标地址等信息。可以使用dfu-tool或dfu-suffix等工具将.bin文件封装成.dfu文件这样刷写命令可以更简洁dfu-util -D my_app.dfu。给合宙Air32刷DFU的过程本质上是一次对MCU启动流程和Bootloader技术的深度实践。虽然步骤看起来有些繁琐但一旦成功后续的开发体验会得到质的提升。它让这块9.9元的开发板摆脱了专用下载器的束缚变得更加灵活和强大。