USB外设的bInterval如何执行?

时间:2019-02-13 12:32:27

标签: usb polling libusb peripherals

我有一个全速USB设备,用于发送报告描述符,其相关端点描述符声明bInterval为8,表示8ms。

当设备的驱动程序为HidUsb时,以下报告摘录是从USB描述符转储程序获得的:

Interface Descriptor: // +several attributes
------------------------------
0x04    bDescriptorType
0x03    bInterfaceClass      (Human Interface Device Class)
0x00    bInterfaceSubClass   
0x00    bInterfaceProtocol   
0x00    iInterface

HID Descriptor: // +bLength, bCountryCode
------------------------------
0x21    bDescriptorType
0x0110  bcdHID
0x01    bNumDescriptors
0x22    bDescriptorType   (Report descriptor)
0x00D6  bDescriptorLength

Endpoint Descriptor: // + bLength, bEndpointAddress, wMaxPacketSize
------------------------------
0x05    bDescriptorType
0x03    bmAttributes      (Transfer: Interrupt / Synch: None / Usage: Data)
0x08    bInterval         (8 frames)

将驱动程序切换到WinUSB以使其能够使用后,如果我使用libusb反复查询IN中断传输,并使用以下脚本对两次libusb调用之间以及libusb调用期间花费的实时时间进行计时:

for (int i = 0; i < n; i++) {
    start = std::chrono::high_resolution_clock::now();
    forTime = (double)((start - end).count()) / 1000000;

    <libusb_interrupt_transfer on IN interrupt endpoint>

    end = std::chrono::high_resolution_clock::now();
    std::cout << "for " << forTime << std::endl;

    transferTime = (double)((end - start).count()) / 1000000;
    std::cout << "transfer " << transferTime << std::endl;

    std::cout << "sum " << transferTime + forTime << std::endl << std::endl;
}

以下是获得的值的示例:

for 2.60266
transfer 5.41087
sum 8.04307     //~8

for 3.04287
transfer 5.41087
sum 8.01353     //~8

for 6.42174
transfer 9.65907
sum 16.0808     //~16

for 2.27422
transfer 5.13271
sum 7.87691     //~8

for 3.29928
transfer 4.68676
sum 7.98604     //~8

总和值始终保持非常接近8ms,除非在启动新的中断转移调用之前经过的时间过长(对于我的特定情况,阈值似乎在6到6.5之间),在这种情况下,该值等于16我曾经见过“ for”度量等于18ms,总和恰好等于24ms。使用URB跟踪器(在我的情况下为Microsoft Message Analyzer),Complete URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER消息之间的时间差也是8ms的倍数-通常为8ms。简而言之,它们与“求和”度量相匹配。

因此,很明显,两次“ libusb中断传输调用”返回之间的时间是8ms的倍数,我认为这与bInterval值8有关(FullSpeed-> * 1ms-> 8ms)。

但是,现在我希望我已经明确了我在说什么-强制执行在哪里?尽管进行了研究,但我找不到关于bInterval值如何影响事物的清晰解释。

显然,这是由驱动程序强制执行的。

因此,是:

  • 驱动程序禁止触发请求,直到经过8ms。对我来说,这听起来似乎是最合理的选择,但是从我的URB跟踪中,Dispatch message事件在请求返回之前被引发了几毫秒。这将意味着对主机/消息分析器隐藏的实时离开主机的数据。

  • 驱动程序对我和分析器隐藏了响应,直到上次响应以来已过去8毫秒。

如果确实由驾驶员处理,则在交换消息日志中显示给我的内容中有一个谎言。请求后应立即做出响应,但实际情况并非如此。因此,要么在显示的时间之后发送请求,要么响应早于显示的时间。

如何强制遵守bInterval?

我的最终目标是不理会bInterval值并以8ms以上的频率更频繁地轮询设备(我有充分的理由相信它可以每2ms轮询一次,使用8ms的时间是不可接受的),但首先我想知道它当前的局限性是如何工作的,如果我所寻求的完全可行,那么我就能理解下一步要学习的内容(例如,编写自定义WinUSB驱动程序)

1 个答案:

答案 0 :(得分:1)

  

我有一个FullSpeed USB设备

注意:您是否对此进行了验证? 8ms是速度USB设备的限制-许多常见的鼠标或键盘可能仍在使用。

8ms调度是在USB主机驱动程序(ehci / xhci)AFAIK中完成的。您可以尝试通过释放和回收接口来赌博(不过未经测试)。 (编辑:将不起作用,请参阅评论)。

USB设备无法自行讲话,因此必须延迟请求。请注意,当没有新数据可用时,设备也可以NAK任何中断IN请求。这只是在时间上增加了bInterval毫秒。

  

编写自定义WinUSB驱动程序

不推荐-更换Windows提供的驱动程序很麻烦。我们的USB CDC设备的libusb-win32替换程序在所有大型Windows 10升级中均告失败-升级完成后,该设备将使用COM端口而不是libusb。