我的芯片用的是CH549L,注册成HID设备下的第0x0C项consumer类型应用。目的是通过旋钮调节电脑音量。
正常使用都没有问题。但是有一个BUG是,部分时候电脑关机以后重启,这时候设备就不能工作了,必须要重新插拔一下HID设备才行。
通过大量测试后初步判断,是因为电脑重启时,整个过程中电脑的USB口没有断电,以至于重新开机以后,HID设备并没有重启。电脑这边枚举的USB设备的数据已经清空了,但是我这个HID设备却还记着之前枚举的信息,这时候电脑没有检测到重新插入的USB设备的信号,就不会自动的重新枚举。导致旧的信息不能用了,以至于失效。
我尝试了一个简单的办法,就是人工判断设备失效以后,按一下一下我的板上的一个按钮,然后在程序里直接goto到程序的最开始,直接重新初始化,但是不能够解决这个问题。
所以我想问问,有没有什么能够检测到USB通信失效了的变量啊之类的?还有检测到失效以后,又如何通过软件重新让电脑枚举我的设备?
----------------------------
我的代码主要修改自给的demo代码里面的“CompositeKM.C”文件。上面附上我的描述符,USB中断服务函数没敢改。
/*设备描述符*/
UINT8C DevDesc[] = {
0x12, // bLength。描述符长度(18字节,十六进制为0x12),就是标志描述符数据结构的长度。
0x01, // bDescriptorType。描述符类型。0x01为设备描述符
0x00,0x02, // bcdUSB。设备使用的USB协议版本。表示形式0xJJMN版本JJ.M.N(JJ-主要版本号,M-次要版本号,N-次要版本)。
// 例子:如果是USB2.0,写成:0200H。如果是USB1.1,写成。0110H 如果是USB3.11,写成:0311H。
// 注意是小端模式,所以低字节写在前面
0x00, // bDeviceClass。类代码。表示设备类型。为0时指示用接口描述符来标识类别。详见https://www.usb.org/defined-class-codes
0x00, // bDeviceSubClass。子类型。
0x00, // bDeviceProtocol。设备使用的协议。
THIS_ENDP0_SIZE, // bMaxPackeSize0。端点一次最大传多少个字节。
0x86,0x1a, // idVender。厂商ID。
0xe1,0xe6, // idProduct。产品ID。
0x00,0x01, // bcdDevice。产品版本号。
0x01, // iManufacturer。描述厂商的字符串的索引。
0x02, // iProduct。描述产品的字符串的索引。
0x00, // iSerialNumber。描述产品序列号字符串的索引.
0x01 // bNumConfigurations。指示设备有多少个配置
};
/*字符串描述符*/
// 语言ID描述符
UINT8C MyLangDescr[] = {
0x04, // bLength。描述符长度。
0x03, // bDescriptorType。描述符类型。语言ID描述符也是字符串描述符,类型为0x03。
0x09, 0x04 // wLANGID[0]。要支持的语言ID号。
// wLANGID[n]。有可能会支持多种语言。但是这里没写了。
};
// 厂家信息描述符
UINT8C MyManuInfo[] = {
0x0E, // bLength。描述符长度。
0x03, // bDescriptorType。描述符类型。字符串描述符类型为0x03。
'C', 0, 'S', 0, 'Y', 0, '.', 0, 'U', 0, 'S', 0, 'B', 0 // bString。UNICODE编码的字符串。
};
// 产品信息描述符
UINT8C MyProdInfo[] = {
0x0C, // bLength。描述符长度。
0x03, // bDescriptorType。描述符类型。字符串描述符类型为0x03。
'A', 0, 'u', 0, 'd', 0, 'i', 0, 'o', 0 // bString。UNICODE编码的字符串。
};
/*HID类报表描述符*/
UINT8C ConsumerRepDesc[] =
{
0x05,0x0C, // Usage Page (Consumer)
0x09,0x01, // Usage(Consumer Control)
0xA1,0x01, // Collection (Application), Main Items —— Collection —— Application
0x15,0x00, // Logical Minimum (0), Global Items —— Logical Minimum —— 0
0x25,0x01, // Logical Maximum (1), Global Items —— Logical Maximum —— 1
0x75,0x01, // Report Size (1), Global Items —— Report Size —— 1
0x95,0x01, // Report Count (1), Global Items —— Report Count —— 1
0x09,0xCD, // Usage(Play/Pause),开始暂停
0x81,0x06, // Input (Data, Value, Relative),
0x09,0xB5, // Usage(Scan Next Track),下一曲
0x81,0x06, // Input (Data, Value, Relative),
0x09,0xB6, // Usage(Scan Previous Track),上一曲
0x81,0x06, // Input (Data, Value, Relative),
0x09,0xE2, // Usage(Mute),静音
0x81,0x06, // Input (Data, Value, Relative),
0x09,0xE9, // Usage(Volume Increment),音量+
0x81,0x06, // Input (Data, Value, Relative),
0x09,0xEA, // Usage(Volume Decrement),音量-
0x81,0x06, // Input (Data, Value, Relative),
0x09,0xB3, // Usage(Fast Forward),快进
0x81,0x02, // Input (Data, Value, Absolute),
0x09,0xB4, // Usage(Rewind),倒带
0x81,0x02, // Input (Data, Value, Absolute),
0xC0 // End Collection, Main Items —— End Collection
};
/*配置描述符集合(必须按照顺序)*/
UINT8C CfgDesc[] =
{
// 标准配置描述符
0x09, // bLength。配置本描述符的长度。
0x02, // bDescriptorType。描述符类型。配置描述符为0x02。
0x3b,0x00, // wTotalLength。配置描述符集合总长度。
0x01, // bNumInterfaces。当前配置下面有多少个接口。
0x01, // bConfigurationValue。当前配置的标识。一个USB设备可能有多个配置,但是当前只能选择一种配置。
0x00, // iConfiguration。描述该配置的字符串的索引值。如果没有字符串,那这个值就是0。
0xE0, // bmAttributes。在这个配置下,设备的一些特性。
// D7是保留位,默认为1;
// D6表示供电方式,0是自供电,1是总线供电;
// D5表示是否支持远程唤醒,为1表示设备支持远程唤醒;
// D4~D0保留,默认为0。
0x32, // bMaxPower。配置设备需要的电流。单位是2ma。如果一个设备耗电量100ma,那么本字节设置为0x32即可。
// 接口描述符(Consumer)
0x09, // bLength。配置本描述符的长度。
0x04, // bDescriptorType。描述符类型。接口描述符为0x04。
0x00, // bInterfaceNumber。接口编号。如果一个配置有多个接口的话,那么每个接口的编号都有一个独立的编号,编号从0开始递增。
0x00, // bAlternateSetting。备用接口编号。一般很少用,设置为0。
0x01, // bNumEndpoints。该接口使用的端点个数。
0x03, // bInterfaceClass。接口类。当设备描述符设备类型bDeviceClass为0时,也就是指示用接口描述符来标识类别。
0x01, // bInterfaceSubClass。接口子类。
0x01, // bInterfaceProtocol。接口协议。
0x00, // iInterface。此接口的字符串索引值。没有的话一般为0.
// HID类描述符
0x09, // bLength。配置本描述符的长度。
0x21, // bDescriptorType。描述符类型。HID描述符为0x21。
0x11,0x01, // bcdHID。HID设备所遵循的HID版本号,为4位16进制的BCD码。1.0即0x0100,1.1即0x0101,2.0即0x0200。
0x00, // bCountryCode。HID设备国家/地区代码。
0x01, // bNumDescriptor。HID设备支持的下级描述符的数量。由于HID设备至少需要包括一个报告描述符,故其值至小为0x01,一般的HID设备也为1,也就是有一个报告描述符,物理描述符很少用到。
0x22, // bDescriptorTyep。下级描述符的类型。下级描述符第1个必须是报告描述符,所以这里存放报告描述符类型,报告描述符的类型为0x22。
sizeof(ConsumerRepDesc)&0xFF,sizeof(ConsumerRepDesc)>>8, // wDescriptorLength。下级描述符的长度
// 端点描述符(Consumer)
0x07, // bLength。配置本描述符的长度。
0x05, // bDescriptorType。描述符类型。端点描述符为0x05。
0x81, // bEndpointAddress。
// Bit 3…0: 端点编号;
// Bit 6…4: 保留,默认为0;
// Bit 7:如果是控制端点可以忽略,因为控制端点有两个方向,否则一般表示数据传输方向,0 = OUT endpoint 1 = IN endpoint。
0x03, // bmAttributes。Bits 1..0: 表示传输类型
// 00 = Control-控制传输
// 01 = Isochronous-同步传输
// 10 = Bulk-批量传输
// 11 = Interrupt-中断传输
// Bits 7..2: 还没讲
ENDP1_IN_SIZE,0x00, // wMaxPackeSize(双字节)。表示当前配置下此端点能够接收或发送的最大数据包的大小。
0x0a // bInterval。查询时间。就是主机多久和设备通讯一次。低速和全速称为帧,一个值代表1ms。高速称为微帧,一个值代表125us。
};