2. Overview
四个阶段:
- Enumeration
- device告知host具备的能力。通过Run-Time Descriptor中增加的DFU class-interface descriptor和functional descriptor实现。
- Reconfiguration
- host和device同意初始固件升级。host会发送一次USB reset,设备会exports DFU descriptors出来。
- Transfer
- Manifestation
- device告知设备完成升级,host会再次发送USB reset, 重新枚举设备,运行新固件。
总体流程:
3. Requests
bRequest分别从DFU_DETACH: 0 ~ DFU_ABORT: 6
4. Enumeration Phase
4.1 Run-Time Descriptor Set
支持DFU的设备,在run-time时需要额外增加两个描述符:
- A single DFU class interface descriptor
- A single functional descriptor
因此Configuration descriptor的bNumInterfaces域需要加1。
Run-time DFU Interface Descriptor
DFU Functional Descriptor
static void PrepareDFUFunDesc(DFUFunDesc_t *pDFUFunDesc)
{
pDFUFunDesc->bLength = sizeof(DFUFunDesc_t);
pDFUFunDesc->bDescriptorType = 0x21;
pDFUFunDesc->bmAttributes = g_DFUVar.bmAttributes; /// BIT0 | BIT1 | BIT2 | BIT3
pDFUFunDesc->wDetachTimeOut = 200;
pDFUFunDesc->wTransferSize = g_DFUVar.wTransferSize; // 4096
pDFUFunDesc->bcdDFUVersion = 0x0110;
if(IsDFUMode())
{
pDFUFunDesc->wDetachTimeOut = 2000;
}
}
4.2 DFU Mode Descriptor Set
host和device一致同意执行DFU操作后,host会重新枚举设备。这时候设备会export出DFU descriptor set包括:
- A DFU device descriptor
- A single configuration descriptor
- A single interface descriptor (including descriptors for alternate settings, if present)
- A single functional descriptor
DFU Device Descriptor
// rom code UsbDescCore_Rom.c
USBDevDesc_t USBDevDesc =
{
sizeof(USBDevDesc), // bLength:
0x01, // USB_DEVICE_DESCRIPTOR_TYPE,bDescriptorType:
0x0201, // bcdUSB version:NORM:0200H
DEV_CLS_MULTI, // bDeviceClass:-> This is a Multi-interface Function Code Device
DEV_SUBCLS_COMMON, // bDeviceSubClass: -> This is the Common Class Sub Class
DEV_PROTOCOL_IAD, // bDeviceProtocol: -> This is the Interface Association Descriptor protocol
0x40, // bMaxPacketSize0: = (64) Bytes
ROM_RT_VID, // idVendor: = Realtek Corp.
ROM_RT_FP_PID, // idProduct:
0x0001, // FW_TRUNK_VERSION, //bcdDevice:1.00
I_MANUFACTURER, // iManufacturer:
I_PRODUCT, // iProduct:
I_SERIALNUMBER, // iSerialNumber:
0x01 // bNumConfigurations:
};
if(IsDFUMode())
{
// USBDevDesc.bcdUSB = 0x0200;
USBDevDesc.bDeviceClass = 0x00;
USBDevDesc.bDeviceSubClass = 0x00;
USBDevDesc.bDeviceProtocol = 0x00;
USBDevDesc.idProduct = 0x5800;
if(DevIdcfg.cfgDevId_en==1)
{
USBDevDesc.idVendor = DevIdcfg.dfu_idVendor;
USBDevDesc.idProduct = DevIdcfg.dfu_idProduct;
USBDevDesc.bcdDevice = DevIdcfg.dfu_bcdDevice;
}
}
DFU Mode Configuration Descriptor
与USB1.0 spec中标准配置描述符相同,除了bNumInterfaces域为01h
DFU Mode Interface Descriptor
DFU Functional Descriptor
与4.1中的相同。
5. Reconfiguration Phase
- host发送DFU_DETACH request on EP0
- host发送USB reset
- device枚举DFU descriptor
5.1 DFU_DETACH
6. Transfer Phase
6.1 Downloading
把固件文件分为N pieces。
\(N = ((F - S) / O) + 1\)
F: 传输固件大小,S: 固件文件suffix大小,O:每次传输的size
如果传输过程中发生error,device会返回STALL给host,随后host会发送DFU_GETSTATUS来判断错误的原因。
device有三种方式从host接收firmware image:
把image数据全读进一个buffer, 在下一阶段Manifestation phase中执行真正的programming
erase一块memory,把image写进去
方法2的变种,erase一大块memory,然后分次把image block传进去,这是用于要写的内存大于buffer size的情况。
6.1.1 DFU_DNLOAD
每次最大的传输长度为functional descriptor的wTransferSize域。
host一次control-write transfer传输长度位于bMaxPacketSize0 and wTransferSize bytes。
当最后一个block传输完成,host还会发送一次DFU_DNLOAD,其中wLength为0。
6.1.2 DFU_GETSTATUS
host发送DFU_GETSTATUS,device返回
其中,
bStatus:
bState:
6.1.3 DFU_CLRSTATUS
清除dfuERROR状态,进入dfuIDLE
6.1.4 DFU_ABORT
强行进入dfuIDLE状态
6.1.5 DFU_GETSTATE
相当于只返回DFU_GETSTATUS中的bState域