WCH沁恒单片机
直播中

华强一条街

9年用户 752经验值
擅长:处理器/DSP
私信 关注
[问答]

电脑重启后,但注册的HID设备没有重启,导致设备失效不能工作如何解决?

我的芯片用的是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。
};

回帖(1)

h1654155275.5916

2022-10-8 09:27:01
有几个还需要确认的点:1、可以在USB中断函数中处理控制传输(回传描述符)的地方加个printf,看一下在开机时电脑是否有做枚举,通常电脑重启之后会重新枚举的。
2、在相同电脑环境下,其余的键盘鼠标能不能正常工作,是否有条件对USB数据线进行抓包,看一下关机到开机这个过程中您的代码行为和键鼠行为的差异。
3、你说的当出现这种问题的时候goto到开头重新运行,需要先将USB_CTRL清零,延时一会,在做USB的初始化,目的是撤销数据线上的上拉电阻,然后重新生效。此时是否能够正常工作起来。


4、解决这个问题,可以尝试使用SOF中断,通常电脑关机后总线会处于挂起,USB中断中会进入suspend,以这个时间节点等后续是否有SOF中断,如果超过若干SOF周期还是没有产生SOF中断,可以判断电脑处于关掉或者不和你通讯的状态,这个时候可以尝试执行3中的操作。具体逻辑可以测试后修改。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分