Subsys: Panchip DFU¶
1 功能概述¶
USB应用方案中,通常需要有USB升级功能,panchip_dfu
Sample提供了可以参考的PANCHIP私有协议USB DFU升级方式参考(USB驱动是用上层自定义驱动程序,不同于Zephyr USB驱动程序),配合磐启DFU升级工具可以升级程序,并且端点3可以扩展更多自定义协议消息
2 环境准备¶
pan108xxb1_evb (LQFP封装、1MB Flash、64 Pin)
Type-C USB线两条
用于供电和查看串口打印Log
用于连接usb端口与PC,输出数据模拟usb鼠标通信
硬件接线:
将EVB板上的P02,P03通过跳线帽与USB DM和USB DP相连
PC软件: 串口调试助手(UartAssist)或终端工具(SecureCRT),波特率921600
PANCHIP DFU上位机软件获取:https://docs.panchip.com/pan1080dk-doc/latest/docs-zdk/05_manufacturing_and_testing/pan108x_dfu_tool_intro.html
3 编译和烧录¶
例程位置:zephyr\samples_panchip\subsys\usb\panchip_dfu
使用 ZAL 工具可以对其进行编译、烧录、打开 VS Code 调试等操作。关于 ZAL 工具的详细介绍请参考:Zephyr APP Launcher 工具介绍。
4 演示说明¶
4.2 打开DFU工具,参考工具内的帮助文档PAN108X DFU 用户指南
完成升级¶
注意:如果修改的VID PID及接口,需要正确写入VID PID及接口序号
升级过程中可以使用Bus Hound
抓包,观察数据流
5 开发说明¶
5.1 设备描述¶
多模鼠标方案自定义了一个 USB DFU 固件升级流程,当使用此功能时,鼠标被初始化为多接口设备。
5.1.1 USB描述符¶
interface0作为鼠标通信接口,ep1 in作为鼠标上报通道
interface2作为dfu通信接口,ep3 in作为通信上报通道,ep3 out作为通信输出通道
ep3最大支持64B,预留首位report id 0x0a作为扩展
识别USB设备为双接口设备后,上位机与Mouse下位机ep3进行协议升级
5.1.1.1 设备描述符¶
const uint8_t DeviceDscDat[] = {
/* Device descriptor */
0x12, // bLength
0x01, // bDescriptorType
0x00, // bcdUSB L - USB version(2.0), LSB
0x02, // bcdUSB H - USB version(2.0), MSB
0x00, // bDeviceClass
0x00, // bDeviceSubclass
0x00, // bDeviceProtocol
0x08, // bMaxPacketSize0
0x6d, 0x04, //idVendor;
0x77, 0xc0, //idProduct;
0x00, // bcdDeviceL - device code
0x01, //
0x22, // iManufacturer - string index
0x10, // iProduct - string index
0x00, // SerialNumber - string index
0x01 // bNumConfigs
};
5.1.1.2 控制描述符¶
控制描述符只有一个,内容包含了三接口描述符,每个接口描述符子集具有hid描述符
Interface 0和1 通常为用户usb接口描述符(demo以鼠标,键盘为interface 0 和 1)
Interface 2 为Panchip提供的 USB DFU 参考描述符,包含了Endpoint 3的输入和输出两个端点
const uint8_t ConfigDscDat[] = {
/* ============== CONFIGURATION 1 =========== */
/* Configuration 1 descriptor */
0x09, /* CbLength */
0x02, /* CbDescriptorType */
0x5b, /* 91 */
0x00,
0x03, /* CbNumInterfaces */
0x01, /* CbConfigurationValue */
0x00, /* CiConfiguration */
0xA0, /* CbmAttributes Bus powered */
0xF8, /* CMaxPower: 100mA */
/* ============== interface 0 =============== */
/* Interfac Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x00, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID code */
0x01, /* bInterfaceSubclass */
0x02, /* 0: None, 1: keyboad, 2: mouse */
0x00, /* iInterface */
/* HID Descriptor */
0x09, /* bLength */
0x21, /* bDescriptor type - HID Descriptor */
USB_WBVAL(0x111), /* bcdHIDH */
0x00, /* bCountryCode */
0x01, /* bNumDescriptors */
0x22, /* bDescriptorType */
USB_WBVAL(DEF_Intface0_ReportDes_SIZE), /* wItemLengthH */
/* Endpoint 1 descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType Endpoint */
0x81, /* bEndpointAddress EP 02 - IN */
0x03, /* bmAttributes INT */
USB_WBVAL(0x40), /* wMaxPacketSize */
0x01, /* bInterval 1 ms */
/* ============== interface 1 =============== */
/* Interface Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x01, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x01, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID code */
0x01, /* bInterfaceSubclass */
0x01, /* 0: None, 1: keyboad, 2: mouse */
0x00, /* iInterface */
/* HID Descriptor */
0x09, /* bLength */
0x21, /* bDescriptor type - HID Descriptor */
USB_WBVAL(0x111), /* bcdHID */
0x00, /* bCountryCode */
0x01, /* bNumDescriptors */
0x22, /* bDescriptorType */
USB_WBVAL(DEF_Intface1_ReportDes_SIZE), /* wItemLengthH */
/* Endpoint descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType Endpoint */
0x82, /* bEndpointAddress EP 02 - IN */
0x03, /* bmAttributes INT */
USB_WBVAL(0x40), /* wMaxPacketSize */
0x01, /* bInterval 1 ms */
/* ============== interface 2 =============== */
/* Interface Descriptor */
0x09, /* bLength */
0x04, /* bDescriptorType */
0x02, /* bInterfaceNumber */
0x00, /* bAlternateSetting */
0x02, /* bNumEndpoints */
0x03, /* bInterfaceClass: HID code */
0x00, /* bInterfaceSubclass */
0x00, /* 0: None, 1: keyboad, 2: mouse */
0x00, /* iInterface */
/* HID Descriptor */
0x09, /* bLength */
0x21, /* bDescriptor type - HID Descriptor */
USB_WBVAL(0x111), /* bcdHID */
0x00, /* bCountryCode */
0x01, /* bNumDescriptors */
0x22, /* bDescriptorType */
USB_WBVAL(DEF_Intface2_ReportDes_SIZE), /* wItemLengthH */
/* Endpoint descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType Endpoint */
0x83, /* bEndpointAddress EP 03 - IN */
0x03, /* bmAttributes INT */
USB_WBVAL(0x40), /* wMaxPacketSize */
0x01, /* bInterval 1 ms */
/* Endpoint descriptor */
0x07, /* bLength */
0x05, /* bDescriptorType Endpoint */
0x03, /* bEndpointAddress EP 03 - OUT */
0x03, /* bmAttributes INT */
USB_WBVAL(0x40), /* wMaxPacketSize */
0x01, /* bInterval 1 ms */
};
5.1.1.3 报告描述符¶
hid dfu报告描述符
#define DEF_Intface2_ReportDes_SIZE 35
uint8_t dfu_report[DEF_Intface2_ReportDes_SIZE] = {
0x05, 0x8C, /* 0x01 */ /* 0x8C, */
0x09, 0x06,
0xa1, 0x01, /* app clooection c0 end */
0x09, 0x06,
0x15, 0x00,
0x26, 0xff,
0x00, 0x75,
0x08, 0x95,
0x40, 0x91,
0x02, 0x09,
0x06, 0x15,
0x00, 0x26,
0xff, 0x00,
0x75, 0x08,
0x95, 0X40,
0x81, 0x02,
0xc0,
};
5.2 通信协议¶
5.2.1 连接¶
连接命令,主机ep3发送,确认设备已连接
report id(1B) |
cmd(1B) |
---|---|
0x0a |
0x55 |
连接成功,从机ep2上报
report id(1B) |
cmd(1B) |
---|---|
0x0a |
0x55 |
5.2.2 USB DFU Control¶
DFU Control包括升级流程中,控制流程的实现,但不包括数据传输的cmd
DFU Control cmd最高4bit位为0x0
5.2.2.1 Get Version¶
查询当前运行固件信息,主机ep3发送
report id(1B) |
dfu control cmd(1B) |
version area(1B) |
---|---|---|
0x0a |
0x00 |
0x00 controller |
上报当前运行固件信息,从机ep2上报 len 7
report id(1B) |
dfu control cmd(1B) |
version area(1B) |
version Major(1B) |
version Minor(1B) |
version Revision(2B) |
version Build Num(4B) |
---|---|---|---|---|---|---|
0x0a |
0x00 |
0x00 controller 0x01 app |
5.2.2.2 Check Version¶
发送确认待升级固件信息,从机ep3发送
report id(1B) |
dfu control cmd(1B) |
start addr(4B) |
version Major(1B) |
version Minor(1B) |
version Revision(2B) |
version Build Num(4B) |
image size(4B) |
crc(4B) |
---|---|---|---|---|---|---|---|---|
0x0a |
0x01 |
固件img解析出的下载地址 |
image size hex |
上位机运算整个image的crc32信息 |
从机收取待升级固件信息,检查版本兼容性(待升级固件是否可以在程序中升级),检查固件大小,存储crc信息
确认后通过ep2上报确认信息 len 4
report id(1B) |
dfu control cmd(1B) |
status(1B) |
version area(1B) |
---|---|---|---|
0x0a |
0x01 |
0x00: success else: fail reason |
0x00 controller 0x01 app |
PS: image 头部信息存储格式如下,对应bin文件首地址开始ih_img_size
ih_ver
VERSION_PATCH 对应 iv_revision低位
VERSION_APP 对应 iv_build_num 低位
image size(4B) 对应 固件bin整体大小
struct image_version {
uint8_t iv_major;
uint8_t iv_minor;
uint16_t iv_revision;
uint32_t iv_build_num;
};
/** Image header. All fields are in little endian byte order. */
struct image_header {
uint32_t ih_magic;
uint32_t ih_load_addr;
uint16_t ih_hdr_size; /* Size of image header (bytes). */
uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */
uint32_t ih_img_size; /* Does not include header. */
uint32_t ih_flags; /* IMAGE_F_[...]. */
struct image_version ih_ver;
uint32_t _pad1;
};
5.2.2.3 DFU Start¶
Check Version成功后,主机ep3发送DFU开始命令
report id(1B) |
dfu control cmd(1B) |
---|---|
0x0a |
0x02 |
从机收到 DFU start后,首先ep2回复进行消息收到确认
report id(1B) |
dfu control cmd(1B) |
---|---|
0x0a |
0x02 |
从机收到 DFU start后,开始擦除指定区域和大小的flash,擦除成功后,停止ep1的通信端点上报,ep2上报回复信息
fail reason 包含擦除失败,固件未确认等(可以扩展) len 3
report id(1B) |
dfu control cmd(1B) |
status(1B) |
---|---|---|
0x0a |
0x02 |
0x00: success else: fail reason |
5.2.2.4 DFU Finish¶
发送完所有数据后,主机ep3发送传输完成命令
report id(1B) |
dfu control cmd(1B) |
---|---|
0x0a |
0x03 |
从机收到完成命令后,首先进行消息收到确认
report id(1B) |
dfu control cmd(1B) |
---|---|
0x0a |
0x03 |
之后对收到数据进行crc校验,与Check Version获取到的CRC信息进行核对,通过ep2进行上报 len 7
report id(1B) |
dfu control cmd(1B) |
status(1B) |
crc check value(4B) |
---|---|---|---|
0x0a |
0x03 |
0x00: success else: fail reason |
若主机收到失败消息,可以选择重新升级(重新点击开始升级)或者发送DFU END退出升级
5.2.2.5 DFU End¶
升级成功结束后,主机ep3发送结束命令,指定是否重启进行固件搬运升级,升级失败时reboot flag置为0x01
report id(1B) |
dfu control cmd(1B) |
reboot flag(1B) |
---|---|---|
0x0a |
0x04 |
0x00: reboot 0x01: not reboot |
从机收到升级结束命令,开启鼠标正常ep1上报功能,若不需要重启,通过ep2上报回复消息 len 2
report id(1B) |
dfu control cmd(1B) |
---|---|
0x0a |
0x04 |
5.2.3 USB DFU Transfer¶
DFU Transfer为数据传输的cmd
DFU Transfer cmd最高4bit位为0x1
DFU Transfer预定义一条消息,主机通过ep3连续传输待升级固件
report id(1B) |
dfu transfer cmd(1B) |
data(62B) |
---|---|---|
0x0a |
0x10 |
升级数据 |
*从机收到传输消息后,暂定不回复,如果需要回复可以回复相同数据进行确认(参考客户方案)
report id(1B) |
dfu control cmd(1B) |
data(62B) |
---|---|---|
0x0a |
0x10 |
回复收到的数据 |
实际参考panlink升级,指定从机flash write单元256B,当收到的数据超过flash write单元后,ep2上报一条写成功消息通知主机继续发送
report id(1B) |
dfu control cmd(1B) |
block num(2B) |
---|---|---|
0x0a |
0x10 |
数据长度/256 |
5.2.4 扩展 EP1 操作消息¶
ep1 test cmd最高4bit位为0x2
需要手动关闭开启ep1上报功能时(暂时不确认升级过程中是否需要关闭ep1),主机通过ep3发送控制消息
report id(1B) |
ep1 control cmd(1B) |
ep1 status |
---|---|---|
0x0a |
0x20 |
0x00: off 0x01: on |
从机收到消息成功控制后,通过ep2回复确认消息
report id(1B) |
ep1 control cmd(1B) |
ep1 status |
---|---|---|
0x0a |
0x20 |
0x00: off 0x01: on |
5.3 开发接口¶
基于Endpoint3通信,用户可以直接通过修改协议解析方式,在不与DFU冲突的前提下,制作一些私有的通信消息
EP3输出接口
void usb_vendor_ep3_out(void)
EP3输入上报接口
void usb_vendor_ep3_in(uint8_t len, uint8_t *data)
6 RAM/Flash资源使用情况¶
Memory region Used Size Region Size %age Used
FLASH: 23900 B 384 KB 6.08%
SRAM: 5456 B 64 KB 8.33%