0

我一直在为 NXP LPC1788 微控制器开发一个应用程序,该应用程序涉及使用 USB 与主机 PC 通信。

一般来说,该应用程序工作正常。但是,我注意到多台不同的计算机是,如果微控制器通电并连接到断电的计算机,然后计算机又打开,计算机将无法启动。拔下微控制器并尝试再次启动计算机将解决问题。

为什么微控制器会阻止计算机启动?我已经用谷歌搜索了这个问题,似乎这个问题发生在 Windows 试图将 USB 设备视为可启动时,而它不应该是。

有没有办法可以防止我的应用程序发生这种情况?我应该提供哪些信息来帮助其他人诊断问题?

如果它有用,下面是 micro 的设备描述符:

/* USB Standard Device Descriptor */
const uint8_t USB_DeviceDescriptor[] = {
  USB_DEVICE_DESC_SIZE,              /* bLength */
  USB_DEVICE_DESCRIPTOR_TYPE,        /* bDescriptorType */
  WBVAL(0x0200), /* 2.00 */          /* bcdUSB */
  0xFF,                              /* bDeviceClass */
  0x00,                              /* bDeviceSubClass */
  0x00,                              /* bDeviceProtocol */
  USB_MAX_PACKET_SIZE,               /* bMaxPacketSize0 */
  WBVAL(<...>),                      /* idVendor */
  WBVAL(<...>),                      /* idProduct */
  WBVAL(0x0100), /* 1.00 */          /* bcdDevice */
  0x04,                              /* iManufacturer */
  0x30,                              /* iProduct */
  0x42,                              /* iSerialNumber */
  0x01                               /* bNumConfigurations */
};

这是配置描述符:

const uint8_t USB_ConfigDescriptor[] = {
/* Configuration 1 */
  USB_CONFIGURATION_DESC_SIZE,       /* bDescriptorType */
  USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
  WBVAL(                             /* wTotalLength */
    1*USB_CONFIGURATION_DESC_SIZE +
    1*USB_INTERFACE_DESC_SIZE     +
    2*USB_ENDPOINT_DESC_SIZE
  ),
  0x01,                              /* bNumInterfaces */
  0x01,                              /* bConfigurationValue */
  0x00,                              /* iConfiguration */
  USB_CONFIG_SELF_POWERED /*|*/      /* bmAttributes */
/*USB_CONFIG_REMOTE_WAKEUP*/,
  USB_CONFIG_POWER_MA(100),          /* bMaxPower */
/* Interface 0, Alternate Setting 0, MSC Class */
  USB_INTERFACE_DESC_SIZE,           /* bLength */
  USB_INTERFACE_DESCRIPTOR_TYPE,     /* bDescriptorType */
  0x00,                              /* bInterfaceNumber */
  0x00,                              /* bAlternateSetting */
  0x02,                              /* bNumEndpoints */
  0xFF,                              /* bInterfaceClass */
  0x0,                               /* bInterfaceSubClass */
  0x0,                               /* bInterfaceProtocol */
  0x5C,                              /* iInterface */
/* Bulk In Endpoint (data) */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_IN(2),                /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,            /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  0x0,                               /* bInterval */
/* Bulk Out Endpoint (data) */
  USB_ENDPOINT_DESC_SIZE,            /* bLength */
  USB_ENDPOINT_DESCRIPTOR_TYPE,      /* bDescriptorType */
  USB_ENDPOINT_OUT(2),               /* bEndpointAddress */
  USB_ENDPOINT_TYPE_BULK,            /* bmAttributes */
  WBVAL(0x0040),                     /* wMaxPacketSize */
  0x0,                               /* bInterval */
/* Terminator */
  0                                  /* bLength */
};

编辑

字符串描述符(用下划线替换字母):

const uint8_t USB_StringDescriptor[] = {
/* Index 0x00: LANGID Codes */
  0x04,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  WBVAL(0x0409), /* US English */    /* wLANGID */
/* Index 0x04: Manufacturer */
  0x2C,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  '_',0,
  '_',0,
  '_',0,
  ' ',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  ' ',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  ' ',0,
/* Index 0x30: Product */
  0x14,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  '_',0,
  ' ',0,
/* Index 0x42: Serial Number */
  0x1A,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
/* Index 0x5C: Interface 0, Alternate Setting 0 */
  0x0E,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
  '0',0,
};

编辑 2

iManufacturer将,iProduct和分别更改iSerialNumber为 0x1、0x2 和 0x3 使得 USBLyzer 不会获取字符串描述符,这不是一个有希望的迹象。如果我使用原始索引值,它确实如此。我还没有检查这如何影响计算机的启动能力。

编辑 3

我注意到我的iSerialNumberiInterface参数是 2。0x30+0x14 = 0x44.

我会看看这是否解决了任何问题。

编辑 4

更正上面的两个参数后,我的问题似乎得到了解决。TurboJ 让我注意到索引值应该很小,例如 0x1、0x2、0x3...

NXP 似乎对如何做到这一点有不同的想法,我复制了他们的方式,但我认为我可以稍后修改代码,使其像其他 USB 设备一样工作。

4

2 回答 2

2
 0x04,                              /* iManufacturer */
 0x30,                              /* iProduct */
 0x42,                              /* iSerialNumber */

您的iProductiSerialNumber字节似乎已关闭-这些是索引号,通常很小。您的描述符将需要字符串描述符中的 66 个字符串。这些不寻常的高数字可能会导致 BIOS USB 实现溢出。

于 2014-10-17T22:45:18.933 回答
0

我纠正了我的问题并改进了恩智浦的方法。

NXP 的示例 USB 项目将所有字符串描述符保存在一个数组中。然后他们通过以下方式实现了“USB Get Descriptor”功能:

case USB_STRING_DESCRIPTOR_TYPE:
  EP0Data.pData = (uint8_t *)USB_StringDescriptor + SetupPacket.wValue.WB.L;
  len = ((USB_STRING_DESCRIPTOR *)EP0Data.pData)->bLength;
  break;

这意味着他们必须使用荒谬的索引值来指定iManufacturer,iProduct等,例如(在他们的情况下0x040x200x48

在我自己的代码中,我修改了他们的方法。我将字符串描述符维护为数组数组:

const uint8_t USB_StringDescriptor[][100] = {
  {
  /* Index 0x00: LANGID Codes */
  0x04,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  WBVAL(0x0409), /* US English */    /* wLANGID */
  },

  {
  /* Index 0x01: Manufacturer */
  0x2A,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  // ...
  },

  {
  /* Index 0x02: Product */
  0x12,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  // ...
  },

  {
  /* Index 0x03: Serial Number */
  0x1A,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  // ...
  },

  {
  /* Index 0x04: Interface 0, Alternate Setting 0 */
  0x0E,                              /* bLength */
  USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
  // ...
  }
};

然后我更改处理字符串描述符请求的方式:

case USB_STRING_DESCRIPTOR_TYPE:
  EP0Data.pData = (uint8_t *)USB_StringDescriptor[SetupPacket.wValue.WB.L];
  len = ((USB_STRING_DESCRIPTOR *)EP0Data.pData)->bLength;
  break;

这样,在我的设备描述符中,我可以简单地指定iManufacturer,iProduct0x010x02

我已经用两台计算机对此进行了测试,当我的应用程序连接并运行时,它们都能够成功启动。

于 2014-10-20T10:31:31.837 回答