DFU运行时设备示例
2026-10-22
本文链接为:http://www.usbzh.com/article/detail-1814.html ,欢迎转载,转载请附上本文链接。
DFU运行时(RUNTIME)的测试示例来源于tinyusb
使用示例,创建的描述符如下:
---------------- Interface Descriptor -----------------
bLength : 0x09 (9 bytes)
bDescriptorType : 0x04 (Interface Descriptor)
bInterfaceNumber : 0x01 (Interface 1)
bAlternateSetting : 0x00
bNumEndpoints : 0x00 (Default Control Pipe only)
bInterfaceClass : 0xFE (Application Specific)
bInterfaceSubClass : 0x01 (Device Firmware Upgrade)
bInterfaceProtocol : 0x01 (Runtime)
iInterface : 0x04 (String Descriptor 4)
Language 0x0409 : "USBZH DFU"
----- Device Firmware Update Functional Descriptor ----
bLength : 0x09 (9 bytes)
bDescriptorType : 0x21 (DFU Functional Descriptor)
bmAttributes : 0x0D
Bit 7..4: reserved : 0x00
Bit 3: WillDetach : 0x01
Bit 2: ManifestTolerant : 0x01
Bit 1: CanUpload : 0x00
Bit 0: CanDownload : 0x01
wDetachTimeOut : 0x03E8 (1000 ms)
wTransferSize : 0x1000 (max 4096 bytes)
bcdDFUVersion : 0x0101 (Version 1.1)
可以看到,其并没有其它端点描述符。所以从这里也可以看到,DFU使用的是USB控制类请求。
USB类主请求主要包括可详见:https://www.usbzh.com/article/detail-794.html
其实这些USB类请求也只是USB控件端点通过不同的类请求实现传输固件信息到固件的过程。
在tinyusb中定义的回调主要有2个
switch (request->bRequest)
{
case DFU_REQUEST_DETACH:
{
TU_LOG_DRV(" DFU RT Request: DETACH\r\n");
tud_control_status(rhport, request);
tud_dfu_runtime_reboot_to_dfu_cb();
}
break;
case DFU_REQUEST_GETSTATUS:
{
TU_LOG_DRV(" DFU RT Request: GETSTATUS\r\n");
dfu_status_response_t resp;
// Status = OK, Poll timeout is ignored during RT, State = APP_IDLE, IString = 0
TU_VERIFY(tu_memset_s(&resp, sizeof(resp), 0x00, sizeof(resp))==0);
tud_control_xfer(rhport, request, &resp, sizeof(dfu_status_response_t));
}
break;
default:
{
TU_LOG_DRV(" DFU RT Unexpected Request: %d\r\n", request->bRequest);
return false; // stall unsupported request
}
}
- DFU_REQUEST_DETACH ->tud_dfu_runtime_reboot_to_dfu_cb
- DFU_REQUEST_GETSTATUS
// DFU Status Request Payload typedef struct TU_ATTR_PACKED { uint8_t bStatus; uint8_t bwPollTimeout[3]; uint8_t bState; uint8_t iString; } dfu_status_response_t;
DFU RUNTIME也定义了一些其它的回调请求,不过这些都是根据USB设备的状态来进行回调的
| 回调 | 触发时机 |
|---|---|
| tud_mount_cb() | 主机发 SET_CONFIGURATION(配置号非 0),设备成功解析配置并打开所有接口驱动后 |
| tud_umount_cb() | ① SET_CONFIGURATION(0);② 设备被拔出(DCD_EVENT_UNPLUGGED) |
| tud_suspend_cb(remote_wakeup_en) | 总线空闲 3ms 触发挂起事件(DCD_EVENT_SUSPEND),且设备已连接 |
| tud_resume_cb() | 总线恢复活动(DCD_EVENT_RESUME),且设备已连接 |
| tud_dfu_runtime_reboot_to_dfu_cb() | 收到 DFU 类请求 DFU_REQUEST_DETACH(0x00)时 |
- DFU 无数据端点 :靠 Endpoint 0 的控制传输(SETUP/DATA/STATUS)完成所有通讯,所以描述符里没有 endpoint 描述符。
- 回调时机 :mount /umount /suspend /resume 是设备通用回调,由枚举/总线事件触发;tud_dfu_runtime_reboot_to_dfu_cb 是 DFU Runtime 专属,只在收到 DETACH 时触发。
- led_blinking_task 是应用自己的后台轮询任务 ,回调只负责改blink_interval_ms 变量来间接控制 LED。
- 完整链路 :tusb_init 初始化 → 枚举(GET_DESCRIPTOR → SET_ADDRESS → SET_CONFIGURATION →tud_mount_cb )→ 通讯(SET_INTERFACE → DETACH 触发回调 → GETSTATUS 回状态),全程由tud_task() 在后台驱动。
windows下的DFU
DFU在Windows下没有对应的驱动,所以应该配成WINUSB设备,可以选择基于MSOS-V1.0或基于MSOS-V2.0,然后再自己写应用通讯。
当然,这里我将其与一个HID UPS设备复合,故使用zadig强行安装winusb驱动,最终效果如下
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936 USB技术交流3:1031974172
DFU





