本篇总结
使用 USB DFU 实现 W55MH32 固件升级全流程,配套 KEIL 工程:DFU 引导加载程序(BOOT,按键 PG6)+ SysTick 测试 APP,支持现场反复升级。
🔑 KEIL MDK、UART调试、USB、DFU、dfu-util
硬件平台:本例程基于 W55MH32L-EVB 开发板运行。
采购推荐:点击前往 WIZnet 官方淘宝店铺 选购 W55MH32L-EVB
本示例演示 W55MH32 通过 USB DFU 实现固件升级的全流程。
DFU 支持直接通过 USB 接口进行可靠的固件恢复和更新,将 FLASH 分为 BOOT 引导区和 APP 应用区,引导程序根据按键状态和应用程序有效性决定进入 DFU 模式或跳转执行用户程序。
方案配套两份 KEIL 例程:BOOT 引导加载程序(USB DFU 设备)与 SysTick 测试 APP(延时/时钟打印),编译、烧录、升级、验证全部在 Windows 下完成。
前置工具准备
开始本例程前,请确认以下工具已安装:
- WIZ UartTool V1.0:串口调试工具,用于查看 APP 运行输出:点击下载
- Zadig:WinUSB 驱动安装工具,首次使用需为 DFU 设备安装驱动:点击下载
硬件连接
W55MH32 开发板提供两个 USB 端口:DAPLink 调试端口用于 KEIL 烧录引导程序,USB Device 端口用于 DFU 固件升级。开发板自带的按键(丝印 KEY:PG6)用于强制进入 DFU 模式。
| 接口/引脚 | 功能 | 说明 |
| DAPLink USB | 调试/烧录口 | 通过 KEIL 烧录 DFU 引导加载程序 |
| USB Device | DFU 设备端口 | 固件升级时使用,连接主机 USB |
| KEY:PG6(板载按键) | BOOT 按键 | 按下时强制进入 DFU 模式(低电平有效) |
| RESET | 复位按键 | 配合 KEY:PG6 进入 DFU 模式 |
DFU 特性与应用领域
| 特性类别 | 功能说明 |
| 引导恢复 | 从变砖状态恢复,APP 无效时自动进入 DFU 等待升级 |
| 编程支持 | USB DFU 类协议,兼容 dfu-util,支持 bin 固件格式 |
| 易用性 | 组合按键进入 DFU,兼容工厂编程,支持终端用户现场更新 |
应用领域覆盖工业(生产线更新、远程维护、紧急补丁)、IoT(智能家居、传感器网络、边缘计算)、消费电子(家电、安防、医疗设备)以及开发(快速原型、生产编程、现场更新)。
FLASH 存储架构设计
固件升级需要在 FLASH 中存储多个程序:BOOT 程序负责判断是否升级及跳转,APP 程序是主应用程序。因此需要对 FLASH 进行分区。
| 分区 | 起始地址 | 大小 | 用途 |
| BOOT | 0x08000000 | 20KB | DFU 引导加载程序 |
| APP | 0x08005000 | 1004KB | 用户应用程序(APP) |
| RAM | 0x20000000 | 96KB | 运行时内存 |
分区关键点
前 20KB(0x08000000~0x08005000)预留给 DFU 引导加载程序,APP 必须以 0x08005000 开始编译。KEIL 工程内存窗口中 APP 的 IROM 起始地址必须与此地址一致,同时 APP 启动时需将中断向量表重定位到 0x08005000。
步骤1:编译并烧录 DFU 引导加载程序(BOOT)
配套 KEIL 工程 Device_Firmware_Upgrade_BOOTDFU 引导加载程序包含关键决策逻辑,决定设备启动进入主应用程序还是 DFU 模式。以下三段代码构成引导加载程序的核心。
1.1 DFU 引导逻辑 (main.c)
代码首先初始化 BOOT 按键 GPIO,检查按键是否未按下(低电平有效)。若未按下,验证 ApplicationAddress(0x08005000)处是否存在有效应用程序——检查该地址第一个 32 位值(初始堆栈指针)是否在 RAM 范围(0x20000000~0x20020000)内。验证通过则提取复位向量并跳转;否则进入 DFU 模式等待主机命令。
int main(void)
{
DFU_Button_Init(); // 初始化 BOOT 按键 GPIO
/* 关键决策点:检查 BOOT 按键是否按下 */
if (DFU_Button_Read() != 0x00) // 按键未按下(低电平有效)
{
/* 验证 0x08005000 处是否存在有效用户程序 */
if (((*(__IO uint32_t *)ApplicationAddress) & 0x2FFE0000) == 0x20000000)
{
/* 跳转到用户应用程序 */
// 1. 获取应用复位向量地址 (ApplicationAddress + 4)
JumpAddress = *(__IO uint32_t *)(ApplicationAddress + 4);
Jump_To_Application = (pFunction)JumpAddress;
// 2. 从向量表设置主堆栈指针
__set_MSP(*(__IO uint32_t *)ApplicationAddress);
// 3. 跳转到应用程序复位向量
Jump_To_Application();
}
} /* 否则进入 DFU 模式 */
/* 进入 DFU 模式 */
DeviceState = STATE_dfuERROR;
DeviceStatus[0] = STATUS_ERRFIRMWARE;
DeviceStatus[4] = DeviceState;
// 初始化 USB DFU 系统
Set_System();
Set_USBClock();
USB_Init();
DP_PUUP = 1; // 使能 USB 上拉
while (1)
{
}
}
堆栈指针验证原理
&0x2FFE0000 掩码检查 SP 高 3 位是否为 0x200,即 SP 落在 0x20000000~0x2001FFFF 范围内。W55MH32 RAM 共 96KB(0x20000000~0x20018000),此范围内即为合法堆栈指针。若 FLASH 未编程,值为 0xFFFFFFFF,掩码结果为 0x20000000≠0x20000000,校验不通过。
1.2 DFU 按键配置 (hw_config.c)
配置 GPIOG 引脚 6(PG6)为上拉输入模式。按键按下 = 低电平(0)→ 强制进入 DFU 模式;按键未按下 = 高电平(1)→ 尝试启动应用程序。
void DFU_Button_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; // PG6
GPIO_Init(GPIOG, &GPIO_InitStruct);
}
uint8_t DFU_Button_Read(void)
{
return GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_6);
}
1.3 应用程序地址配置 (hw_config.h)
/* Flash memory address from where user application will be loaded */
#define ApplicationAddress 0x08005000
1.4 烧录 BOOT
打开 KEIL MDK → 加载 Device_Firmware_Upgrade_BOOT 工程 → 选择调试器 CMSIS-DAP → 编译 → F8 下载(写入 0x08000000 起始的 BOOT 区)。烧录完成后验证:按住 KEY:PG6 同时复位,设备应枚举为 "WIZ DFU" 设备。
步骤2:编译测试 APP
配套 KEIL 工程 SysTick_Test_App,基于 W55MH32 SysTick 系统定时器例程:USART1 打印系统时钟,循环进行中断方式与轮询方式延时测试。该工程已按 DFU 分区完成适配。
2.1 链接地址配置 (SysTick.uvprojx 内存窗口)
APP 的 IROM 起始地址必须偏移到 0x08005000,大小 0xFB000(1004KB),避开前 20KB BOOT 区:
<!-- 内存窗口:IROM 从 0x08005000 开始,大小 0xFB000 -->
<IROM>
<StartAddress>0x08005000</StartAddress>
<Size>0xFB000</Size>
</IROM>
2.2 中断向量表重定位 (main.c)
APP 启动早期必须重定位中断向量表,否则任何中断(SysTick/UART 等)都会去 0x08000000(BOOT 区)取向量导致跑飞。本工程采用双保险:SystemInit 中 VECT_TAB_OFFSET=0x5000 + main 首行显式设置:
/* system_w55mh32.c:SystemInit 中 VECT_TAB_OFFSET */
#define VECT_TAB_OFFSET 0x5000 /* 0x08005000 - 0x08000000 */
/* main.c:main 函数首行显式重定位(双保险) */
int main(void)
{
SCB->VTOR = 0x08005000; /* 重定位中断向量表到 APP 区 */
...
}
2.3 编译 APP
KEIL 中编译工程,生成 SysTick.bin,烧录地址从 0x08005000 开始。编译后可用文本编辑器打开 SysTick.hex 首行确认地址记录为 0x08005000。
APP 适配必要条件
任意自研 APP 接入本 DFU 方案,必须满足 4 个条件:① 链接地址偏移 0x08005000;② 启动早期 SCB->VTOR = 0x08005000;③ 0x08005000 首字为合法 SP(0x20000000~0x2001FFFF 范围);④ 烧录地址一致(dfu-util 用 -s 0x08005000 指定)。
步骤3:安装驱动并烧录 APP
3.1 进入 DFU 模式
- 按住开发板按键 KEY:PG6 → 按下并松开 RESET 按键 → 松开 KEY:PG6 → 开发板进入 DFU 模式
- 设备管理器应出现 "WIZ DFU" 设备(VID 0483 / PID DF11)
设备管理器-通用串行总线设备-WIZ DFU3.2 安装 WinUSB 驱动(首次必需)
Windows 默认不识别 DFU 设备,需用 Zadig 安装 WinUSB 驱动:
- 首先,按住开发板按键 KEY:PG6 → 按下并松开 RESET 按键 → 松开 KEY:PG6 → 开发板进入 DFU 模式
- 运行 Zadig 默认自动识别WIZ DFU
- 若未识别,则运行 Zadig → 菜单 Options → 勾选 List All Devices
- 下拉框选择 WIZ DFU(USB ID 显示 0483 DF11)
- 确认目标驱动为 WinUSB (v6.1.7600.16385) → 点击 Install Driver
首次使用未安装驱动
打开Zadig-WIZ DFU
安装完毕3.3 验证设备并烧录 APP
烧录 APP 使用命令行工具 dfu-util 完成。命令由固定参数与 APP 固件路径组成,下面按步骤说明路径与命令的对应关系。
① 打开命令提示符
按 Win 键 → 输入 cmd → 回车(或按 Win+R,输入 cmd 后回车),打开命令提示符窗口。
② 确认 DFU 设备可见
输出中出现 0483:df11 即设备已就绪。若主机存在多个 DFU 设备(如带 DFU 接口的摄像头),烧录命令中必须加 -d 0483:df11 指定目标设备,避免误烧。
③ 执行烧录命令
命令格式如下,将 -D 后双引号内的路径替换为你电脑上 SysTick.bin 的实际路径:
dfu-util -d 0483:df11 -a 0 -s 0x08005000:leave -D "SysTick.bin 的完整路径"
示例:APP 例程解压到 D:\W55MH32_DFU_APP_SysTick,bin 文件位于 ModuleDemo\SysTick\USER\Bin\SysTick.bin,则完整命令为:
dfu-util -d 0483:df11 -a 0 -s 0x08005000:leave -D "D:\W55MH32_DFU_APP_SysTick\ModuleDemo\SysTick\USER\Bin\SysTick.bin"
也可以先用 cd 命令进入 bin 所在目录,再直接写文件名(路径不含中文时更稳妥):
cd /d D:\W55MH32_DFU_APP_SysTick\ModuleDemo\SysTick\USER\Bin
dfu-util -d 0483:df11 -a 0 -s 0x08005000:leave -D SysTick.bin
命令无法识别的处理
若执行时报 'dfu-util' 不是内部或外部命令,说明 dfu-util 未加入系统 PATH 环境变量(见前置工具准备)。此时改用 dfu-util.exe 完整路径调用,命令参数不变,仅将开头的 dfu-util 替换为解压目录下的完整路径:
"C:\dfu-util-0.11-win64\dfu-util.exe" -d 0483:df11 -a 0 -s 0x08005000:leave -D "D:\W55MH32_DFU_APP_SysTick\ModuleDemo\SysTick\USER\Bin\SysTick.bin"
将双引号内的路径替换为实际解压目录与 bin 文件路径即可。建议按前置工具准备完成 PATH 配置,之后直接使用简洁命令。
dfu-util 输出 "File downloaded successfully" 即烧录成功,开发板自动复位并跳转运行 APP。
命令参数说明:
| 参数 | 含义 |
| -d 0483:df11 | 指定烧录目标设备(防止多设备误烧) |
| -a 0 | 选择内部 Flash 接口 |
| -s 0x08005000:leave | 从 0x08005000 开始写入(保护前 20KB BOOT 区),烧录完成后自动跳转运行 |
| -D 文件路径 | 指定要烧录的固件文件(SysTick.bin 的路径) |
步骤4:验证固件
4.1 DFU 模式验证
- 按住开发板按键 KEY:PG6 → 按下并松开 RESET 按键 → 松开 KEY:PG6 → 开发板进入 DFU 模式
- 运行 dfu-util -l 确认枚举 "STM Device in DFU Mode"(0483:df11)
4.2 WIZ UartTool 验证
烧录完成后复位开发板,BOOT 检测按键未按下且 APP 有效,跳转执行 SysTick 测试 APP。打开 WIZ UartTool V1.0,选择开发板对应 COM 口验证输出:
| 参数 | 值 |
| 波特率 | 115200 |
| 数据位 | 8 |
| 校验位 | 无 |
| 停止位 | 1 |
| 流控制 | 无 |
选择对应 COM 端口(USART1:PA9 发送 / PA10 接收),波特率 115200,按下 RESET 按键,应看到系统时钟打印及 SysTick 延时循环输出:
SYSCLK: 72.0Mhz, HCLK: 72.0Mhz, PCLK1: 36.0Mhz, PCLK2: 72.0Mhz, ADCCLK: 36.0Mhz
SysTick Delay Test.
[0] interrupt delay 1s ...
[1] polling delay 500ms ...
[2] interrupt delay 1s ...
[3] polling delay 500ms ...
...
4.3 再次升级验证(核心闭环)
APP 运行中,随时可再次升级:按住 PG6 → 复位 → 松开 → 重新进入 DFU 模式 → 重新执行 dfu-util 烧录命令。BOOT 引导程序永久驻留 0x08000000~0x08005000,升级只擦写 APP 区,BOOT 不会被覆盖。
擦除与烧录
SysTick.bin 运行常见问题
Q: 设备未枚举为 "WIZ DFU"
确认引导加载程序已正确烧录到 0x08000000。按住板载按键 KEY:PG6 后按 RESET 进入 DFU,检查设备管理器是否出现 DFU 设备。若未出现,可能 BOOT 程序未烧录或 USB Device 线连接到错误端口。
Q: dfu-util 报 "No DFU capable USB device" / "More than one DFU capable USB device"
设备未进入 DFU 模式,或主机存在多个 DFU 设备(如带 DFU 接口的摄像头)。先按住 PG6 复位进入 DFU,再用 dfu-util -l 查看;多设备时使用 -d 0483:df11 指定目标。
Q: 跳转到 APP 后立即 HardFault
APP 的中断向量表起始地址与 ApplicationAddress(0x08005000) 不一致。检查 KEIL 内存窗口 IROM 起始地址是否为 0x08005000,并在 APP 启动早期调用 SCB->VTOR = 0x08005000 重定位向量表。
Q: 烧录 APP 成功后,设备管理器仍显示 "WIZ DFU"
这是正常现象。BOOT 引导程序跳转 APP 时未关闭 USB 外设,设备管理器会残留一个 "WIZ DFU" 空壳设备,不影响 APP 运行。拔掉 USB 线重新插入,或再次复位开发板后该残留设备即消失。若希望彻底避免,可在 APP 代码中调用 USB_DeInit() 关闭 USB 外设。
Q: 按住 PG6 复位后仍然运行 APP
BOOT 未读到按键按下。确认 BOOT 工程 hw_config.c 中按键配置为 GPIOG GPIO_Pin_6(PG6)且已重新编译烧录;用万用表量 PG6 引脚,按下时应为低电平。
Q: dfu-util 烧录失败(驱动问题)
DFU 设备需要 WinUSB 驱动。用 Zadig 重新安装:Options → List All Devices → 选择 STM Device in DFU Mode → Replace Driver 为 WinUSB,然后重试烧录。
Q: 堆栈指针验证始终不通过
APP 未烧录或烧录地址错误。检查 0x08005000 处第一个 32 位值是否为合法 SP(0x2000xxxx)。若为 0xFFFFFFFF 说明 APP 未编程;KEIL 内存窗口 IROM 起始地址不对会导致向量表写入错误位置。
总结
本 DFU 解决方案为 W55MH32 平台提供了可靠的固件恢复与更新能力:
- FLASH 分区:前 20KB 留给 BOOT 引导加载程序,APP 以 0x08005000 开始,KEIL 内存窗口与地址宏必须一致
- 引导决策:检查 PG6 按键 + 验证 SP 合法性(&0x2FFE0000 == 0x20000000),通过则跳转 APP,否则进入 DFU
- 跳转三步:提取复位向量 → 设置 MSP → 调用函数指针跳转,APP 需在 SystemInit 中设置 VTOR
- Windows 直烧:Zadig 安装 WinUSB 驱动后,dfu-util 从 0x08005000 开始编程
- 双重验证:dfu-util 烧录结果 + WIZ UartTool 115200 连接确认 APP 运行,支持现场反复升级