
Целью этой статьи не является полный пересказ спецификации USB или книгу по USB. Я хочу приоткрыть магию работы USB и представить информацию таким образом, чтобы вы получили быстрый старт для понимания всего стека USB: от интерфейсов и конечных точек до электрических сигналов. Стандарты, используемые в USB устройствах, подробно расписаны в спецификациях.
В большинстве вводных статей по USB рассказывается, какие разъёмы используются, их распиновка, максимальные скорости. Статьи, где рассказывается о деталях протоколов USB, встречаются гораздо реже, читать огромнейшие спецификации желающих мало, поэтому у меня и возникла идея основные вехи USB уместить в одной статье.
Чтобы сосредоточиться на базе, я не рассказываю, как устроены и работают USB-хабы. В статье рассматривается работа USB на скорости FullSpeed (12 Мб/c) при подключении устройства к USB-порту.
Хост и устройство
В стандарте USB в зависимости от роли в обмене информацией различают хост и устройство. Хост — ведущая сущность, устройство — ведомая сущность.
Хостом обычно является компьютер, а устройством — периферийное устройство, умеющее работать по протоколу USB (клавиатура, камера, флешка).
Интерфейсы
Устройство обладает одним или несколькими интерфейсами, которые описывают функции устройства. В этом случае говорят о составном устройстве. Например, устройство может совмещать функции клавиатуры и мыши.
Конфигурации
Конфигурация описывает, какие интерфейсы будут доступны, а также требования, предъявляемые к питанию устройств. У устройства может быть несколько конфигураций, но активной является одна.
Конечные точки и адреса
Адреса и конечные точки в USB по смыслу близки к понятиям IP-адреса и порта в TCP/IP.
Для каждого USB-устройства, подключённого к USB-шине хост в процессе USB Enumeration присваивает адрес. Адрес может принимать значение от 1 до 127. Изначально при USB Enumeration пакеты данных отсылаются на адрес 0.
Конечные точки также нумеруются. Номера конечных точек уникальные в пределах одного устройства. Номер точки кодируется 4 битами, всего может быть 16 точек для отсылки данных на устройство и 16 точек для приёма данных с устройства. Для конфигурирования USB используется конечная точка по умолчанию, имеющая номер 0.
Дескрипторы и USB Enumeration
Работать с большинством USB устройств просто. Достаточно просто подключить устройство к разъёму USB компьютера, и операционная система сама обнаружит устройство и загрузит необходимые драйверы. Всё это возможно благодаря механизму USB Enumeration и дескрипторам.
Дескрипторы — это структуры данных, содержащие информацию об устройстве, его конфигурациях, интерфейсах, конечных точках, а также дополнительные строковые описания. Дескрипторы одного устройства образуют иерархическую (древовидную) структуру.
Удобнее всего эту структуру посмотреть в Linux при помощи команды:
lsusb -v
Эта команда выводит все дескрипторы подключённых USB-устройств в удобном для чтения виде.
Как только устройство подключается к USB-порту, хост начинает процесс USB Enumeration, в ходе которого, он запрашивает у устройства дескрипторы и назначает устройству адрес.
На высоком уровне это выглядит следующим образом:
-
Хост определяет факт подключения устройства.
-
Хост определяет скорость обмена информации с устройством.
-
Хост выполняет сброс шины USB.
-
Хост запрашивает дескриптор устройства на адресе 0.
-
Устройство возвращает дескриптор устройства.
-
Хост выполняет сброс шины USB.
-
Хост назначает устройству адрес и сообщает адрес устройству.
-
Хост повторно запрашивает дескриптор устройства, но уже на назначенном адресе.
-
Устройство возвращает дескриптор устройств.
-
Хост получает информацию из остальных дескрипторов интерфейсов, конфигураций.
-
Операционная система обнаруживает устройство, выбирает конфигурацию из списка доступных и, если это возможно, подбирает и загружает подходящий драйвер.
-
Устройство готово к работе.
Для более подробного рассмотрения процесса Enumeration необходимо сначала разобраться, как происходит передача данных по USB, и что представляют собой пакеты, транзакции и передачи.
Для наблюдения за физическим уровнем USB и всеми пакетами обычно используют USB-анализаторы, логические анализаторы или осциллографы. Однако значительную часть процесса Enumeration можно изучить и программными средствами, например, при помощи usbmon или Wireshark.
Передача данных
USB Enumeration это лишь небольшая часть спецификации USB. Ведь главная задача USB – обеспечить обмен данными между устройством и хостом.
И здесь нужно рассказать о передачах — процессах обмена информацией между хостом и устройством. Их всего четыре типа:
-
Control,
-
Interrupt,
-
Isochronous,
-
Bulk.
Тип передачи определяет, как во времени будет использоваться USB-шина и для чего.
Например, при USB Enumeration тип передачи — Control, при работе с флеш-накопителем используется Bulk, а при работе с USB-аудиокартой Isochronous. Может использоваться и несколько передач. При работе с USB-клавиатурой используется Control и Interrupt передачи.
Работа USB устроена так, что инициирует обмен информацией всегда хост. Устройство отвечает по запросу от хоста, даже если данные исходят от устройства, например, клавиатуры. То есть пока хост не спросит клавиатуру о состоянии клавиш, клавиатура никак не может сообщить.
Стадии USB-передач
При передаче хост инициирует транзакции, которые, в свою очередь, состоят из пакетов.
Передача может состоять из одной или нескольких транзакций. Например, запрос Get Descriptor, который использует Control передачу при USB Enumeration, будет состоять из трёх транзакций:
-
SETUP,
-
DATA,
-
STATUS.
Каждая из этих транзакций определяет, в какой стадии находится передача. Стадии передачи обычно относятся к Control передачи. Остальные типы передач (Interrupt, Isochronous, Bulk) — это последовательность DATA транзакций для конечных точек.
Транзакции и пакеты в USB
Транзакция — это неделимая (атомарная) операция обмена данными между хостом и устройством. Транзакция считается успешной, только если все её пакеты переданы без ошибок. Если транзакция не была успешно завершена, хост обычно повторяет её согласно правилам соответствующего типа передачи.
Типичная транзакция состоит из token, data и handshake-пакетов, однако в зависимости от типа передачи некоторые фазы могут отсутствовать.
-
Фаза токена (Token): Хост указывает тип операции, адрес устройства и номер конечной точки (Endpoint).
-
Фаза данных (Data): Передача полезной нагрузки (может отсутствовать).
-
Фаза подтверждения (Handshake): Приёмник сообщает статус приёма.
Структура пакета:
Не все поля пакета являются обязательными. На рисунке ниже я не указывал сигнал SYNC (сигнал синхронизации), который предшествует каждому пакету и сигнал EOP (сигнал End Of Packet), которым завершается каждый пакет, так как это уже относится к физическому уровню.

-
PID (Packet Identifier) — идентификатор пакета. Определяет его тип: Token-пакеты:
IN,OUT,SETUP,SOF, Data-пакеты:DATA0,DATA1, Handshake-пакеты:ACK,NAK,STALL, специальные пакеты. -
ADDR (Address) — адрес USB-устройства. Назначается хостом при Enumeration. В USB 2.0 адрес занимает 7 бит, допустимые значения — от 1 до 127.
-
EP (Endpoint) — номер конечной точки.
-
PAYLOAD — полезные данные. Присутствуют только в пакетах данных (
DATA0,DATA1). В token- и handshake-пакетах этого поля нет. -
CRC (Cyclic Redundancy Check) — контрольная сумма для обнаружения ошибок: в token-пакетах используется CRC5, в data-пакетах — CRC16, в handshake-пакетах CRC отсутствует.
Виды пакетов
Все пакеты делятся на четыре группы по их идентификатору (PID):
Token (Токены)
Генерируются только хостом. Задают направление данных.
-
SETUP: Инициирует транзакцию управления (Control Transfer).
-
IN: Запрос данных от устройства к хосту.
-
OUT: Передача данных от хоста к устройству.
Data (Данные)
Data-пакеты содержат полезную нагрузку. Для обеспечения правильной последовательности передачи данных используются идентификаторы DATA0 и DATA1.
-
DATA0 / DATA1: Основные пакеты данных. Хост и устройство чередуют их в соответствии с механизмом Data Toggle. Это позволяет обнаруживать повторно переданные пакеты и отличать новую порцию данных от уже полученной. Правила выбора между
DATA0иDATA1зависят от типа передачи и текущей стадии обмена и подробно описаны в спецификации USB.
Handshake (Подтверждение)
Статус выполнения фазы данных.
-
ACK: Данные приняты успешно, CRC совпал.
-
NAK: Устройство исправно, но временно не готово (хост повторит попытку).
-
STALL: Критическая ошибка или неподдерживаемая команда.
-
NYET: (Только High-Speed) Данные приняты, но к следующему пакету устройство ещё не готово.
SOF (Start of Frame)
Маркер начала кадра. Рассылается хостом для синхронизации таймингов всех устройств. В Full Speed отправляется каждые 1.0 мс и содержит 11-битный счётчик кадров.
Ограничения размера пакетов данных (Payload)
Максимальный объём полезных данных в одном пакете ограничен дескрипторами устройства:
-
Для стандартных конечных точек (EP 1–15): Максимальный размер payload определяется полем
wMaxPacketSizeв дескрипторе конкретной конечной точки. Хост никогда не превышает этот лимит. -
Для нулевой конечной точки (Control EP 0): Используется для начальной конфигурации. Её лимит жёстко задан в поле
bMaxPacketSize0главного дескриптора устройства (Device Descriptor). Для Full Speed это значение может быть равно только 8, 16, 32 или 64 байтам.
Физический уровень
Понимание физического уровня USB требует больше всего усилий. Но если вы поймёте:
-
как хост определяет скорость,
-
дифференциальные 0 и 1,
-
SE0, SE1,
-
состояния J,K,
-
система кодирования NRZI,
-
Bit Stuffing,
-
кадры.
Многое станет на свои места. Я физический уровень рассматриваю лишь базово, не углубляясь в детали того, как устроены контроллеры хостов и устройств USB.
Как хост определяет скорость
В статье я рассматриваю случай USB FS, более высокоскоростные варианты USB отставил за скобками. Расскажу, как хост отличает USB LS от USB FS. Для этого используется подтяжка по питанию к 3.3 В через резистор 1,5 кОм для линий D+ и D-. Если к питанию подтянута D- — USB LS, если D+ — USB FS.
Дифференциальный 0 и дифференциальная 1
Для передачи данных в USB используется дифференциальный сигнал.
Передача осуществляется дифференциальной парой D+ и D−. Информация определяется разностью напряжений между линиями, а не абсолютным уровнем каждой линии. Это добавляет надёжности и помехозащищённости к передаче сигнала.
Дифференциальным 0 считается состояние, когда на D+ низкий уровень, а на D- — высокий. Дифференциальной 1 считается случай, когда на D+ высокий уровень, а на D- — низкий.
SE0 и SE1
Возможны ещё два состояния, когда на D+ и D- имеют низкий уровень и когда на D+ и D- имеют высокий уровень. Их называют SE0 и SE1 соответственно. Состояние SE1 считается ошибочным. А SE0 используется, например, для сброса USB шины или обозначения конца пакета.
Состояния J, K
Так как из-за того, что при USB FS и USB LS подтягиваются к питанию D+ и D-, для унифицированного кодирования данных были введены состояния J и K.
J в Low Speed соответствует дифференциальному 0, а в Full Speed дифференциальной 1.
K в Low Speed соответствует дифференциальной 1, а в Full Speed дифференциальному 0.
NRZI
Суть NRZI-кодирования (Non Return to Zero Inverted) заключается в том, что информация кодируется не абсолютным уровнем сигнала, а фактом его изменения. В USB логические значения представляются состояниями J и K, а бит определяет, должен ли передатчик изменить текущее состояние или оставить его прежним.
Для USB действует следующее правило:
-
бит 0 вызывает переход из состояния J в K или из K в J,
-
бит 1 передаётся без изменения текущего состояния.
Пусть начальное состояние равно J, а необходимо передать биты:
10110010
Тогда получим:
|
Бит |
Изменение состояния |
Состояние |
|---|---|---|
|
старт |
— |
J |
|
1 |
нет перехода |
J |
|
0 |
переход |
K |
|
1 |
нет перехода |
K |
|
1 |
нет перехода |
K |
|
0 |
переход |
J |
|
0 |
переход |
K |
|
1 |
нет перехода |
K |
|
0 |
переход |
J |
В результате последовательность состояний будет:
J K K K J K K J
или, если учитывать начальное состояние:
J J K K K J K K J
Bit Stuffing
У NRZI-кодирования есть одна особенность: единица передаётся без изменения состояния линии. Поэтому длинная последовательность единиц приводит к отсутствию переходов сигнала.
Например, если передаются восемь единиц подряд
11111111
и передача начинается из состояния J, то состояние линии не будет изменяться:
J J J J J J J J
Отсутствие переходов затрудняет восстановление тактовой частоты приёмником. Чтобы этого не происходило, в USB применяется механизм Bit Stuffing.
Суть Bit Stuffing заключается в том, что после каждых шести подряд идущих единиц передатчик автоматически вставляет дополнительный нулевой бит. Этот бит не относится к передаваемым данным и удаляется приёмником.
Например, пусть необходимо передать последовательность:
11111111
После шестой единицы передатчик вставит дополнительный ноль:
111111011
Вставленный ноль вызовет переход сигнала, благодаря чему приёмник сохранит синхронизацию.
Если передача начинается из состояния J, то последовательность состояний будет выглядеть так:
Биты: 1 1 1 1 1 1 0 1 1
Состояния: J J J J J J K K K
Получатель также отслеживает последовательности единиц. Если после шести подряд идущих единиц следует ноль, то он понимает, что это вставленный бит, удаляет этот бит и восстанавливает исходные данные:
111111011 → 11111111
Таким образом, Bit Stuffing является служебным механизмом физического уровня USB, который обеспечивает наличие периодических переходов сигнала и позволяет приёмнику поддерживать синхронизацию.
Кадры
Хост определяет кадры, в пределах которых передаются пакеты. Длительность кадра составляет 1мс. В начале каждого кадра USB Full Speed передаётся SOF-пакет.
Какие транзакции и пакеты будут передаваться в пределах кадра, определяет планировщик USB хоста.
Практика
Как смотреть USB-трафик в операционной системе (Wireshark + usbmon / USBPcap / XHC)
Захват USB-трафика не настроен в операционных системах по умолчанию, поэтому будьте готовы к небольшим танцам с бубнами, чтобы включить этот функционал.
Суть перехвата USB-трафика в операционной системе заключается в том, что поднимается виртуальный сетевой интерфейс, который видит Wireshark. Wireshark анализирует пакеты URB, которыми оперирует ядро операционной системы. Вы не увидите пакеты, транзакции, кадры, используемые при USB-коммуникации, но посмотреть, что вообще происходит между USB-хостом и USB-устройством, вы сможете.
Настройка такого анализа USB-трафика немного отличается в операционных системах, но в целом вы получаете похожую картину. Хочу предупредить, что увидеть, что фактически передалось по проводам, вы не сможете, а увидите только высокоуровневую картину. Команды Reset и получения адреса, пакеты SOF в начале каждого фрейма USB FS USB будут недоступны для анализа, а только основной разобранный USB-трафик. Причём трафик может быть как FS, так и HS, SS, SS+.
Настройка в Linux
Настроить анализ USB-трафика в Linux просто.
-
Устанавливаем Wireshark, если он не установлен.
-
Загружаем модуль
usbmon.sudo modprobe usbmon -
Запускаем Wireshark
sudo wireshark -
Выбираем интерфейс usbmon, захватывающий трафик с шины USB, к которой вы подключаете USB-устройство.
-
Мониторим трафик в виде URB пакетов.
Настройка в Windows
Настройка в Windows ещё проще, чем в Linux. Дистрибутив Wireshark сам установит USBPcap, необходимый для захвата пакетов.
Настройка в macOS
Я рассматриваю настройку только на macOS для Apple Silicon. По умолчанию интерфейсы для анализа USB-трафика отсутствуют в операционной системе и активировать их из операционной системы у вас не получится, так как нужно отключить SIP. SIP отключается при помощи команды csrutil, но отключить SIP из операционной системы у вас не получится, необходимо загрузиться в Recovery Mode. А вот проверить статус SIP из операционной системы можно:
csrutil status
-
Устанавливаем Wireshark, если он не установлен.
-
Заходим в Recovery Mode: выключаем ноутбук, нажимаем кнопку питания и ждём, пока не появится надпись “Loading statup options”.
-
Запускаем терминал: Options -> Continue -> Utilities -> Terminal.
-
Проверяем статус SIP:
csruil status -
Отключаем SIP:
csrutil disable -
Выбираем операционную систему, если у вас их несколько, и соглашаемся.
-
Перезагружаемся:
reboot -
Загружаемся. Теперь в списке интерфейсов появились интерфейсы XHC0, XHC1, XHC2. Поднимаем их:
sudo ifconfig XHC0 up sudo ifconfig XHC1 up sudo ifconfig XHC2 up -
Проверяем, что интерфейсы поднялись:
sudo tcpdump -D | grep XHC -
Запускаем Wireshark.
-
Для доступа к интерфейсам Wireshark должен быть запущен с правами суперпользователя. Более безопасной альтернативой является использование ChmodBPF, о чём намекает сообщение в Wireshark. Кликните по ссылке и перезагрузите Wireshark.
Из командной строки Wireshark с правами суперпользователя можно запустить так:
sudo /Applications/Wireshark.app/Contents/MacOS/Wireshark
Использование логического анализатора для просмотра USB-трафика
Логический анализатор позволяет увидеть USB-трафик на более низком уровне. Например, вы сможете увидеть:
-
cброс USB-шины (шина находится в состоянии SE0),
-
начало каждого кадра (SOF-пакеты),
-
обмен пакетами в каждой транзакции (Token, Data, Handshake-пакеты).
Как правило, программное обеспечение для логического анализатора имеет декодирующий модуль для USB-трафика.
При выборе логического анализатора важна его максимальная частота дискретизации. Нужно руководствоваться правилом 5 отсчётов. То есть частота дискретизации должна быть в 5 раз выше захватываемого сигнала. Для USB FS (12 МГц) это будет 60 МГц. На 50 МГц у меня тоже нормально захватывался сигнал.
Я использовал логический анализатор Kingst LA1010. Для того, чтобы программное обеспечение для него с официального сайта заработало как надо, на операционной системе Debian Linux 13 работало странно, пришлось установить недостающие пакеты. На Windows 10 работало без проблем.
Использование микроконтроллеров для просмотра USB-трафика
Если у вас нет логического анализатора, то трафик можно посмотреть и, используя дешёвые микроконтроллеры, типа Raspberry Pi Pico.
Использование осциллографа для просмотра USB-трафика
Осциллограф, в отличие от логического анализатора позволяет увидеть форму сигнала, но в дешёвые и даже не очень осциллографы не умеют декодировать сигнал.
В качестве примера приведу несколько осциллограмм, которые показывают начало процесса USB Enumeration для USB FS устройства с разной степенью детализации. Синие осциллограммы показывают сигнал на D+, жёлтые на D-.
На осциллограмме выше видно, как на USB-шине два раза устанавливается состояние SE0 для сбрасывания USB-шины.
На следующей осциллограмме виден кадр с SOF-пакетом, после которого происходит активный обмен информацией.
Ну, наконец, как выглядит SOF-пакет на осциллограмме, которому предшествует SYNC и после которого следует EOP.
Также вы сможете, например, увидеть, как на уровне электрических сигналов выглядит chrip (handshake для переключения на скорость high speed в USB 2.0, про которую я не рассказываю в статье).
Использование аппаратных USB-анализаторов
У меня такой игрушки нет, поэтому только скажу, что аппаратные USB-анализаторы для High-Speed USB стоят довольно дорого. Поэтому, если вы только начинаете разбираться с USB на таком низком уровне, целесообразности в их покупки не вижу.
Есть дешёвые опенсорсные USB-анализаторы, но опыта работы с ними у меня нет.
Идеи для экспериментов
Простое USB-устройство на трёх резисторах
Чтобы заставить хост думать, что он работает с USB-устройством, не обязательно это устройство должно содержать микроконтроллер. Можно создать простое устройство на трёх резисторах, которое будет «эмулировать» USB-устройство. Полноценным устройством оно не будет, так как оно не будет отвечать хосту, но хост попробует начать процесс USB Enumeration для устройства.
Можно будет посмотреть, чем отличаются сигналы для USB LS и USB FS на линиях D+ и D-. Для этого достаточно подтяжку к 3.3 В через 1.5 кOм делать для D- в случае USB LS и для D+ в случае USB FS.
Работа с USB-клавиатурой
Экспериментирование с USB-клавиатурой удобно тем, что, наверное, у каждого она есть, и вы можете посмотреть и исследовать трафик, которым обменивается хост с ней. Так как USB-клавиатура уже полноценное устройство, можно увидеть весь процесс USB Enumeration. Рассмотрим лишь его часть — получения дескриптора устройства.
-
Хост обнаруживает подключение устройства и инициирует USB RESET (Bus Reset).
-
Хост инициирует Control Read Transfer (SETUP + DATA + STATUS):
-
В SETUP-стадии отправляет запрос
GET_DESCRIPTOR(Device Descriptor, обычно сwLength = 64). -
Устройство отвечает своим Device Descriptor (хост обычно интересует только
bMaxPacketSize0на этом этапе).
-
-
Хост инициирует второй USB RESET.
-
Хост инициирует Control Write Transfer (SETUP + STATUS) с запросом
SET_ADDRESS(новый адрес, обычно 1–127).-
Устройство принимает новый адрес после успешной STATUS-стадии.
-
-
Хост инициирует повторный Control Read Transfer (
GET_DESCRIPTORDevice Descriptor), теперь уже по новому адресу и обычно запрашивает полный дескриптор (wLength = 18 байт). -
Далее хост запрашивает Configuration Descriptor (
GET_DESCRIPTORConfiguration), String Descriptors и т. д.
Запроcы дескрипторов, как правило, отсылаются хостом дважды, первый раз указывается размер дескриптора по умолчанию, второй — уже размер, полученный на предыдущем шаге.
Ниже приведу логи, обмена данными по USB при получении дескриптора устройства. В первом для краткости я удалил часть пакетов SOF.
Первый лог получения дескриптора устройства на уровне пакетов:
Time [s],PID,Address,Endpoint,Frame #,Data,CRC
...
2.3861810800,SETUP,0x00,0x00,,,0x02
2.3861843400,DATA0,,,,0x80 0x06 0x00 0x01 0x00 0x00 0x40 0x00,0x94DD
2.3861929600,ACK,,,,,
2.3862037200,IN,0x00,0x00,,,0x02
2.3862071000,NAK,,,,,
2.3862296600,IN,0x00,0x00,,,0x02
2.3862330400,NAK,,,,,
2.3862607200,IN,0x00,0x00,,,0x02
2.3862641000,NAK,,,,,
2.3862866000,IN,0x00,0x00,,,0x02
2.3862899800,NAK,,,,,
2.3863198800,IN,0x00,0x00,,,0x02
2.3863232600,NAK,,,,,
2.3863456600,IN,0x00,0x00,,,0x02
2.3863490400,NAK,,,,,
2.3863777000,IN,0x00,0x00,,,0x02
2.3863810800,NAK,,,,,
2.3864219000,IN,0x00,0x00,,,0x02
2.3864256200,DATA1,,,,0x12 0x01 0x00 0x02 0x00 0x00 0x00 0x40 0xAE 0x24 0x03 0x20 0x01 0x10 0x01 0x02 0x00 0x01,0x79A1
2.3864409000,ACK,,,,,
2.3864455400,OUT,0x00,0x00,,,0x02
2.3864488200,DATA1,,,,,0x0000
2.3864521000,ACK,,,,,
2.4420779000,SOF,,,0x22B,,0x1F
2.4430781600,SOF,,,0x22C,,0x10
...
2.5090955000,SOF,,,0x26E,,0x0C
2.5100957600,SOF,,,0x26F,,0x13
2.5102195600,SETUP,0x00,0x00,,,0x02
2.5102228400,DATA0,,,,0x00 0x05 0x2E 0x00 0x00 0x00 0x00 0x00,0xBAEC
2.5102314600,ACK,,,,,
2.5102335200,IN,0x00,0x00,,,0x02
2.5102369000,NAK,,,,,
2.5102589600,IN,0x00,0x00,,,0x02
2.5102623400,NAK,,,,,
2.5102839600,IN,0x00,0x00,,,0x02
2.5102873400,NAK,,,,,
2.5103089800,IN,0x00,0x00,,,0x02
2.5103123600,DATA1,,,,,0x0000
2.5103156200,ACK,,,,,
2.5110960200,SOF,,,0x270,,0x0E
2.5120963000,SOF,,,0x271,,0x11
...
2.5250997000,SOF,,,0x27E,,0x10
2.5260999600,SOF,,,0x27F,,0x0F
2.5262339600,SETUP,0x2E,0x00,,,0x0D
2.5262372400,DATA0,,,,0x80 0x06 0x00 0x01 0x00 0x00 0x12 0x00,0xF4E0
2.5262458600,ACK,,,,,
2.5262489600,IN,0x2E,0x00,,,0x0D
2.5262523200,NAK,,,,,
2.5262744400,IN,0x2E,0x00,,,0x0D
2.5262778200,NAK,,,,,
2.5262994200,IN,0x2E,0x00,,,0x0D
2.5263028000,NAK,,,,,
2.5263424000,IN,0x2E,0x00,,,0x0D
2.5263457800,NAK,,,,,
2.5263674200,IN,0x2E,0x00,,,0x0D
2.5263708000,NAK,,,,,
2.5263924400,IN,0x2E,0x00,,,0x0D
2.5263958200,NAK,,,,,
2.5264276800,IN,0x2E,0x00,,,0x0D
2.5264310400,NAK,,,,,
2.5264534800,IN,0x2E,0x00,,,0x0D
2.5264568600,NAK,,,,,
2.5264844200,IN,0x2E,0x00,,,0x0D
2.5264881200,DATA1,,,,0x12 0x01 0x00 0x02 0x00 0x00 0x00 0x40 0xAE 0x24 0x03 0x20 0x01 0x10 0x01 0x02 0x00 0x01,0x79A1
2.5265034000,ACK,,,,,
2.5265053400,OUT,0x2E,0x00,,,0x0D
2.5265086000,DATA1,,,,,0x0000
2.5265119000,ACK,,,,,
И лог получения дескриптора устройства на уровне запросов:
USB RESET Time: 2.26216344
SETUP address: 0x00 time: 2.38618568
bmRequestType=0x80 Data direction=Device to host, Type=Standard, Recipient=Device
bRequest=0x06 GET_DESCRIPTOR
wValue=0x0100 Descriptor=DEVICE, Index=0x00
wIndex=0x0000
wLength=0x0040
DATA time: 2.38620438
<data IN packet NAKed by device. Time: 2.38620776>
<data IN packet NAKed by device. Time: 2.38623372>
<data IN packet NAKed by device. Time: 2.38626476>
<data IN packet NAKed by device. Time: 2.38629064>
<data IN packet NAKed by device. Time: 2.38632392>
<data IN packet NAKed by device. Time: 2.3863497>
<data IN packet NAKed by device. Time: 2.38638176>
Descriptor time: 2.38642696
bLength=0x12
bDescriptorType=0x01 DEVICE
bcdUSB=0x0200 2.00
bDeviceClass=0x00 Deferred to Interface Descriptors
bDeviceSubClass=0x00
bDeviceProtocol=0x00
bMaxPacketSize0=0x40
idVendor=0x24AE Vendor=<unknown>
idProduct=0x2003
bcdDevice=0x1001 10.01
iManufacturer=0x01
iProduct=0x02
iSerialNumber=0x00
bNumConfigurations=0x01
STATUS time: 2.3864462
ACK
USB RESET Time: 2.38652552
SETUP address: 0x00 time: 2.51022416
bmRequestType=0x00 Data direction=No data, Type=Standard, Recipient=Device
bRequest=0x05 SET_ADDRESS
wValue=0x002E Address=0x2E
wIndex=0x0000
wLength=0x0000
STATUS time: 2.51023418
<status IN packet NAKed by device. Time: 2.51023756>
<status IN packet NAKed by device. Time: 2.510263>
<status IN packet NAKed by device. Time: 2.51028802>
ACK
SETUP address: 0x2E time: 2.52623858
bmRequestType=0x80 Data direction=Device to host, Type=Standard, Recipient=Device
bRequest=0x06 GET_DESCRIPTOR
wValue=0x0100 Descriptor=DEVICE, Index=0x00
wIndex=0x0000
wLength=0x0012
DATA time: 2.52624962
<data IN packet NAKed by device. Time: 2.526253>
<data IN packet NAKed by device. Time: 2.52627848>
<data IN packet NAKed by device. Time: 2.52630346>
<data IN packet NAKed by device. Time: 2.52634644>
<data IN packet NAKed by device. Time: 2.52637146>
<data IN packet NAKed by device. Time: 2.5263965>
<data IN packet NAKed by device. Time: 2.52643172>
<data IN packet NAKed by device. Time: 2.52645754>
Descriptor time: 2.52648946
bLength=0x12
bDescriptorType=0x01 DEVICE
bcdUSB=0x0200 2.00
bDeviceClass=0x00 Deferred to Interface Descriptors
bDeviceSubClass=0x00
bDeviceProtocol=0x00
bMaxPacketSize0=0x40
idVendor=0x24AE Vendor=<unknown>
idProduct=0x2003
bcdDevice=0x1001 10.01
iManufacturer=0x01 RAPOO
iProduct=0x02 RAPOO 5G Wireless Device
iSerialNumber=0x00
bNumConfigurations=0x01
STATUS time: 2.526506
ACK
Заключение
Возможно, эксперты в USB сочтут эту статью тривиальной, или что я рассказываю очевидное. Но я целью ставил систематизировать и представить информацию для читателя, желающего разобраться с USB, но которого отпугивают длинные спецификации и толстые книги.
Я думаю, что у вас теперь нет страха перед пониманием USB. Много я не рассказал, и чтобы стать гуру, вам многое предстоит изучить. Может даже выполнить финансовые вложения для покупки дополнительного оборудования.
Приведу лишь только часть тем, которые ещё будет интересно изучить:
-
USB 2.0 HS,
-
USB 3.0 SS,
-
USB-C,
-
OTG,
-
Power Delivery,
-
Классы интерфейсов : CDC, MDC, HID.
Каждая из тем требует времени и сил на изучение, но с полученными знаниями продвигаться вам будет гораздо интереснее и быстрее. Чем больше вы будете изучать, тем проще будет изучать следующую спецификацию USB, глаза будут скользить по спецификации, встречая знакомые, уже понимаемые слова, а быстро понимать суть.
© 2026 ООО «МТ ФИНАНС»
Автор: artyomsoft
