下面的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
};
