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

USB DFU 固件升级(鼠标方案)

设备描述

多模鼠标方案自定义了一个 USB DFU 固件升级流程,当使用此功能时,鼠标被初始化为双接口设备。

USB描述符

  • interface0作为鼠标通信接口,ep1 in作为鼠标上报通道

  • interface1作为dfu通信接口,ep2 in作为通信上报通道,ep3 out作为通信输出通道

    • ep2最大支持64B, 需要预留首位report id 0x0a作为扩展,避免与键盘ep冲突

    • ep3最大支持64B,需要预留首位report id 0x0a作为扩展,避免与键盘ep冲突

  • 识别USB设备为双接口设备后,上位机与Mouse下位机通过ep2,ep3进行协议升级

设备描述符

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
};

控制描述符

控制描述符只有一个,内容包含了双接口描述符,每个接口描述符子集具有hid描述符,每个hid描述符指定了端点,通过不同的hid report描述符进行对应描述

const uint8_t ConfigDscDat[] = {
	/* ============== CONFIGURATION 1 =========== */
	/* Configuration 1 descriptor */
	0x09,		// CbLength
	0x02,   	// CbDescriptorType
	0x42,   	// CwTotalLength 2 EP + Control 14+27=41=32+9=0x29
	0x00,
	0x02,   	// CbNumInterfaces
	0x01,   	// CbConfigurationValue
	0x00,   	// CiConfiguration
	0xA0,		// CbmAttributes Bus powered
	0xF8,   	// CMaxPower: 100mA

	/* Mouse Interface Descriptor Requirement */
	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
	0x11,		// bcdHIDL - HID version = 0x100
	0x01,		// bcdHIDH
	0x00,		// bCountryCode
	0x01,		// bNumDescriptors
	0x22,		// bDescriptorType
	M_MAXREPS,
	0x00,		// wItemLengthH

	/* Endpoint 1 descriptor */
	0x07,   	// bLength
	0x05,   	// bDescriptorType		Endpoint
	0x81,   	// bEndpointAddress		EP 02 - IN
	0x03,   	// bmAttributes			INT
	0x40,//0x07,		// wMaxPacketSize		0x0040 = 64 bytes
	0x00,		//
	0x01,   	// bInterval			1 ms





	/* HID Interface Descriptor Requirement */
	0x09,		// bLength
	0x04,		// bDescriptorType
	0x01,		// 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
	0x00,		// bcdHIDL - HID version = 0x100
	0x01,		// bcdHIDH
	0x00,		// bCountryCode
	0x01,		// bNumDescriptors
	0x22,		// bDescriptorType
	DFU_SIZE,
	0x00,		// wItemLengthH

	/* Endpoint 2 in descriptor */
	0x07,   	// bLength
	0x05,   	// bDescriptorType		Endpoint
	0x82,   	// bEndpointAddress		EP 02 - IN
	0x03,   	// bmAttributes			INT
	0x40,		// wMaxPacketSize		0x0040 = 64 bytes
	0x00,		//
	0x01,   	// bInterval			1 ms

	/* Endpoint 3 out descriptor */
	0x07,   	// bLength
	0x05,   	// bDescriptorType		Endpoint
	0x03,   	// bEndpointAddress		EP 03 - OUT
	0x03,   	// bmAttributes			INT
	0x40,		// wMaxPacketSize		0x0040 = 64 bytes
	0x00,		//
	0x01		// bInterval			1 ms
};

报告描述符

hid鼠标报告描述符

#define M_MAXREPS        				52
uint8_t report[M_MAXREPS]={
	0x05, 0x01, /* Usage Page (Generic Desktop Ctrls) */
	0x09, 0x02, /* Usage (Mouse) */
	0xA1, 0x01, /* Collection (Application) */
	// 0x85, 0x01, /* report id(1) */
	0x09, 0x01, /*   Usage (Pointer) */
	0xA1, 0x00, /*   Collection (Physical) */
	0x05, 0x09, /*     Usage Page (Button) */
	0x19, 0x01, /*     Usage Minimum (0x01) */
	0x29, 0x03, /*     Usage Maximum (0x03) */
	0x15, 0x00, /*     Logical Minimum (0) */
	0x25, 0x01, /*     Logical Maximum (1) */
	0x95, 0x03, /*     Report Count (3) */
	0x75, 0x01, /*     Report Size (1) */
	0x81, 0x02, /*     Input (Data,Var,Abs,No Wrap,Linear,...) */
	0x95, 0x01, /*     Report Count (1) */
	0x75, 0x05, /*     Report Size (5) */
	0x81, 0x03, /*     Input (Const,Var,Abs,No Wrap,Linear,...) */
	0x05, 0x01, /*     Usage Page (Generic Desktop Ctrls) */
	0x09, 0x30, /*     Usage (X) */
	0x09, 0x31, /*     Usage (Y) */
	0x09, 0x38, /*     Usage (Wheel) */
	0x15, 0x81, /*     Logical Minimum (129) */
	0x25, 0x7F, /*     Logical Maximum (127) */
	0x75, 0x08, /*     Report Size (8) */
	0x95, 0x03, /*     Report Count (3) */
	0x81, 0x06, /*     Input (Data,Var,Rel,No Wrap,Linear,...) */
	0xC0,       /*   End Collection */
	0xC0,       /* End Collection */
};

hid dfu报告描述符

#define DFU_SIZE						35

uint8_t dfu_report[DFU_SIZE]={

		0x05, 0x8C,				//0x01,//0x8C,
		0x09, 0x06,
		0xa1, 0x01, 			// app clooection c0 end
		0x85, 0x0a,				// report ID (0x0a)  reserver for keyboard implement
		0x09, 0x06,
		0x15, 0x00,
		0x26, 0x00,
	    0xff, 0x75,
		0x08, 0x95,
		0x40, 0x91,
		0x82, 0x09,
		0x06, 0x15,
		0x00, 0x26,
	    0x00, 0xff,
		0x75, 0x08,
		0x95, 0X40,
		0x81, 0x82,
		0xc0,

};

参考截图

设备描述

device_des

接口0 鼠标功能

interface0_mouse

接口1 DFU功能

interface1_dfu

模拟输入输出数据

ana_inout

通信协议

连接

连接命令,主机ep3发送,确认设备已连接

report id(1B)

cmd(1B)

0x0a

0x55

连接成功,从机ep2上报

report id(1B)

cmd(1B)

0x0a

0x55

USB DFU Control

DFU Control包括升级流程中,控制流程的实现,但不包括数据传输的cmd

DFU Control cmd最高4bit位为0x0

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

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;
};

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

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退出升级

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

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包后进行上报

扩展 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

扩展 EMI 命令

emi命令为rf test时的cmd

DFU Transfer cmd最高4bit位为0x3

例如

report id(1B)

dfu transfer cmd(1B)

data(xB)

0x0a

0x30(蓝牙测试模式)

蓝牙测试命令

report id(1B)

dfu transfer cmd(1B)

data(xB)

0x0a

0x31(2.4g测试模式)

2.4g测试命令(见如下命令格式)

2.4G 测试命令

1、test start

cmd

data

status

0x1a

0x01(test start)

0x01(send);0x00(recv)

2、tx carrier cmd

cmd

freq

tx power

status

0x1b

2byte(2402~2480)LSB

1byte(-45~7)

0x01(send);0x00(recv)

3、tx cmd

cmd

freq max

freq min

tx power

phy

0x1c

2byte(2402~2480)LSB

2byte(2402~2480)LSB

1byte(-45~7)

1byte(1M/2M)

hop time

tx count

status

1byte(0~10s)跳频间隔

2byte(0:一直发)LSB

0x01(send);0x00(recv)

4、rx cmd

cmd

freq

phy

status

0x1d

2byte(2402~2480)LSB

1byte(1M/2M)

0x01(send);0x00(recv)

5、test end

cmd

data

status

0x1a

0x00(test end)

0x01(send)

cmd

data

status

count

0x1a

0x00(test end)

0x00(recv)

2byte(rx模式才有该字段)LSB

获取mac地址命令

GET OWN ADDR

report id(1B)

dfu transfer cmd(1B)

0x0a

0x35

REPLY OWN ADDR

report id(1B)

dfu transfer cmd(1B)

own mac(6B)

0x0a

0x35

本设备的mac地址

GET PAIR ADDR

report id(1B)

dfu transfer cmd(1B)

0x0a

0x36

REPLY PAIR ADDR

report id(1B)

dfu transfer cmd(1B)

pair mac(6B)

0x0a

0x36

配对设备的mac地址

emi确认版本命令

EMI CHECK VERSION

report id(1B)

dfu transfer cmd(1B)

version Major(1B)

version Minor(1B)

version Revision(2B)

version Build Num(4B)

0x0a

0x37

EMI CHECK VERSION REPLY

report id(1B)

dfu transfer cmd(1B)

status(1B)

0x0a

0x37

0x00: success 0x01: fail