下面的Table 1和Table 2简单列举了DFU特定类请求和他们的参数
Table 1. DFU类请求
Request | Request code | Request description |
---|---|---|
DFU_DETACH | 0X00 | 请求设备离开DFU模式,进入应用程序 |
DFU_DNLOAD | 0x01 | 请求Host主机端数据发送到设备端,将数据加载到设备内部Flash.这个过程包含擦除Flash命令的过程 |
DFU_UPLOAD | 0x02 | 请求设备端的数据传输到主机端,将设备内部Flash相应的数据加载到Host主机端的文件中 |
DFU_GETSTATUS | 0x03 | 请求设备发送状态报告到主机端(包括上一个请求执行的状态和这个状态之后设备即将进入的状态) |
DFU_CLRSTATUS | 0x04 | 请求设备清除错误状态并移动到下一步 |
DFU_GETSTATE | 0x05 | 在这个请求之后,请求设备仅仅发送当前即将进入的状态 |
DFU_ABORT | 0x06 | 请求设备离开当前状态/操作,并立即进入空闲状态 |
==注==:Detach请求在bootloader启动时是无意义的,bootloader从系统复位开始,依赖启动模式的配置,即其他应用程序不能在此期间运行
Table 2. DFU特定类请求的参数总结
bmRequest | bRequest | wValue | wIndex | wLength | Data |
---|---|---|---|---|---|
00100001b | DFU_DETACH | wTimeout | Interface | Zero | None |
00100001b | DFU_DNLOAD | wBloackNum | Interface | Length | Firmware |
10100001b | DFU_UPLOAD | Zero | Interface | Length | Firmware |
00100001b | DFU_GETSTATUS | Zero | Interface | 6 | Status |
00100001b | DFU_CLRSTATUS | Zero | Interface | Zero | None |
00100001b | DFU_GETSTATE | Zero | Interface | 1 | State |
00100001b | DFU_ABORT | Zero | Interface | Zero | None |
==注==:State和Status在程序代码中的区别
State 表达的是形态,而 Status 表达的是从一种形态转换成另一种形态的过程中,那些有显著特征的离散中间值。
举一个旅馆房间的例子,一个房间可以是婚房、普通房、豪华总统房,这些都是用 State 来表达。把一个普通房改造成豪华总统房,这个过程就有设计、材料准备、工人就位、施工、验收等步骤,这个时候就用 Status 来表达。那么,区分点在哪?区分点就在于一个房间当用 State 描述时,它是个彼此独立的枚举值,可以没有前后顺序的在婚房、普通房、豪华总统房之间来回转换。而当使用 Status 时,是存在前后状态依赖关系的一个变化量,不能没有做设计就施工,也不能没施工就验收。
所以,State 和 Status 的核心区别,就是它们的枚举值之间是否有依赖关系,没有依赖关系的用 State,有依赖关系的用 Status
- DFU_DNLOAD请求命令简介:
下载请求通常会执行不同的命令,所执行的命令是通过USB请求结构体中的wValue参数来选择具体命令去执行的,其中支持下面的操作:
- 写内存 (wValue > 1)
- 设置地址指针(wValue = 0, 第一个字节 = 0x21)
- 擦除(wValue = 0, 第一个字节 = 0x41)
- 读(wValue = 0, 第一个字节 = 0x92)
- 离开DFU(离开DFU模式并跳转执行相应应用程序)
- 离开DFU状态简介
通过DFU download请求之后,应用程序会被加载到内部Flash或直接加载到RAM中,最后就会离开DFU模式跳转到相应的加载地址(bootloader决定,即运行地址可以在用户的image中,download第一步先下载IVT头解析出将来要加载运行的地址)。
当Host发送最后一个0字节(无数据阶段)的DFU_DNLOAD请求后,意味着通知device即将要离开DFU模式,当前设备处于DFU DNLOAD IDLE/DFU IDLE空闲状态时,设备即确认这个请求。
==注==:在完成所有的下载操作后,device会进入manifestation状态,告诉host已经完成了一个完整的传输.
1)在完全能跳入应用程序后并执行,首先要确保在加载地址处正确设置中断向量表的位置。
2)通过USB IP将应用程序加载到相应地方后,在从bootloader跳转时,必须要禁掉相应的USB中断,否则会干扰到用户代码。
下图时完整的DFU运行过程的流程图:
以下是定义的DFU结构体参数和DFU状态函数表:
// H → D send request to device
/* Define DFU event struct */
typedef struct _usb_device_dfu_event_struct
{
usb_device_dfu_state_event_t name;
uint16_t wValue;
uint16_t wLength;
} usb_device_dfu_event_struct_t;
// D → H return status to host
/*! @brief DFU status definition. */
typedef struct _usb_dfu_status_struct
{
uint8_t bStatus; /* status result */
uint8_t bwPollTimeout[3U]; /* The minimum time host should wait before sending
a subsequent DFU GETSTATUS request */
uint8_t bState; /* dfu state */
uint8_t iString; /* Index of status description in string table */
uint8_t reserved[2];
} usb_dfu_status_struct_t;
/* DFU state function table. */
const static dfu_state_func s_dfuStateFunc[11] = {
USB_DeviceStateAppIdle, USB_DeviceStateAppDetach, USB_DeviceStateDfuIdle,
USB_DeviceStateDfuDnLoadSync, USB_DeviceStateDfuDnBusy, USB_DeviceStateDfuDnLoadIdle,
USB_DeviceStateDfuManifestSync, USB_DeviceStateDfuManifest, USB_DeviceStateDfuManifestWaitReset,
USB_DeviceStateDfuUpLoadIdle, USB_DeviceStateDfuError
};