Как применяются bIntervals периферийных устройств USB?
У меня есть USB-устройство FullSpeed, которое отправляет дескриптор отчета, соответствующий дескриптор конечной точки которого объявляет bInterval
из 8, что означает 8 мс.
Следующий фрагмент отчета получается из дампа дескриптора USB, когда драйвер устройства - HidUsb:
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, чтобы иметь возможность использовать его, если я неоднократно запрашиваю IN прерывания передачи с использованием libusb, и время реального времени, потраченного между 2 вызовами 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
Значения суммы постоянно остаются очень близкими к 8 мс, за исключением случаев, когда время, предшествующее инициированию нового вызова передачи прерывания, слишком велико (пороговое значение кажется между 6 и 6,5 для моего конкретного случая), и в этом случае оно равно 16. Я имею однажды увидела меру "за", равную 18 мс, а сумма точно равна 24 мс. Используя трекер URB (в моем случае Microsoft Message Analyzer), разница во времени между Complete URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER
сообщение также кратно 8 мс - обычно 8 мс. Короче говоря, они соответствуют "сумме" мер.
Итак, ясно, что время, прошедшее между двумя возвратами "вызовов передачи прерываний libusb", кратно 8 мс, что, как я полагаю, связано со значением bInterval, равным 8 (FullSpeed -> *1ms -> 8 мс).
Но теперь, когда я, я надеюсь, дал понять, о чем я говорю - где это применяется? Несмотря на исследования, я не могу найти четкого объяснения того, как значение bInterval влияет на вещи.
Видимо, это обеспечивается драйвером.
Следовательно, это:
Водитель запрещает запуск запроса до истечения 8 мс. Звучит как самый разумный вариант для меня, но из моей трассировки URB,
Dispatch message
события были подняты за несколько миллисекунд до того, как запрос вернулся. Это будет означать, что в реальном времени данные, оставленные хостом, скрыты от меня / анализатора сообщений.Драйвер скрывает ответ от меня и анализатора до тех пор, пока с момента последнего ответа не пройдет 8 мс.
Если это действительно обрабатывается драйвером, то где-то есть ложь к тому, что показано мне в журнале обмена сообщениями. Ответ должен прийти сразу после запроса, но это не так. Таким образом, либо запрос отправляется после указанного времени, либо ответ приходит раньше, чем отображается.
Как работает соблюдение уважения bInterval?
Моя конечная цель - игнорировать значение bInterval и опрашивать устройство чаще, чем за 8 мс (у меня есть веские основания полагать, что он может опрашиваться каждые 2 мс, а период 8 мс неприемлем для его использования), но сначала я бы хотел чтобы узнать, как работает его текущее ограничение, если то, что я ищу, вообще возможно, чтобы я мог понять, что изучать дальше (например, написание собственного драйвера WinUSB)
1 ответ
У меня есть USB-устройство FullSpeed
Осторожно: вы это подтвердили? 8 мс - это предел для низкоскоростных USB-устройств, которые все еще могут использовать многие обычные мыши или клавиатуры.
Планирование 8 мс выполняется внутри драйвера хоста USB (ehci/xhci) AFAIK. Вы можете попытаться сыграть в эту игру, выпустив и восстановив интерфейс - но не проверено. (Изменить: не будет работать, см. Комментарий).
USB-устройство не может общаться самостоятельно, поэтому запрос должен быть отложен. Обратите внимание, что устройство может также принимать любые запросы IN прерывания, когда нет новых доступных данных. Это просто добавляет еще один bInterval
мс до времени.
написание собственного драйвера WinUSB
Не рекомендуется - замена драйвера, поставляемого с Windows, довольно хлопотна. Наш заменитель libusb-win32 для устройства USB CDC ломается на всех больших обновлениях Windows 10 - устройство использует COM-порт вместо libusb после завершения обновления.