Как применяются 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 после завершения обновления.

Другие вопросы по тегам