当前文档版本为 v1.2.0,您可以访问当前页面的 开发中 版本以获取最近可能的更新。

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线两条

    1. 用于供电和查看串口打印Log

    2. 用于连接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.1 USB 识别

下载程序成功后,设备会被识别为多接口设备,使用工具Bus Hound识别后,参考截图如下

4.1.1 设备描述

device_des

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
0x01 app

上报当前运行固件信息,从机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
ex:首包block num0x0000,在收到5包后进行上报

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:       24008 B       384 KB      6.11%
SRAM:        5456 B        64 KB      8.33%