Разбираем и собираем обратно стек USB
Иллюстрированная проекция модели сетевого взаимодействия OSI на универсальную последовательную шину.
Три «замечательных» уровня стека USB
Меня не устроил вид стека USB, который можно встретить чаще всего на просторах сети:
Уровень шины, логический, функциональный… Это, конечно, замечательные абстракции, но они скорее для тех, кто собирается делать драйвер или прикладной софт для хоста. На стороне же микроконтроллера я ожидаю шаблонный конечный автомат, в узлы которого мы обычно встраиваем свой полезный код, и он сперва будет по всем законам жанра глючить. Или же глючить будет софт на хосте. Или драйвер. В любом случае кто-то будет глючить. В библиотеках МК тоже с наскока не разобраться. И вот я смотрю на трафик по шине USB анализатором, где происходящие события на незнакомом языке с тремя замечательными уровнями вообще не вяжутся. Интересно, это у меня от гриппозной лихорадки в голове такой диссонанс?
Если у читателя бывали сходные ощущения, предлагаю альтернативное, явившееся мне неожиданно ясно в перегретом мозгу видение стека USB, по мотивам любимой 7-уровневой модели OSI. Я ограничился пятью уровнями:

Я не хочу сказать, что весь софт и библиотеки уже сделаны или должны проектироваться, исходя из этой модели. Из инженерных соображений код c уровнями будет сильно перемешан. Но я хочу помочь тем, кто начинает своё знакомство с шиной USB, кто хочет понять протоколы обмена устройств и терминологию предметной области, подобраться поближе к готовым примерам, библиотекам и лучше ориентироваться в них. Эта модель не для загрузки в МК, но в ваши блестящие умы, дорогие друзья. А ваши золотые руки потом всё сами сделают, я не сомневаюсь:)
Итак, поехали, поправляйте, если увидите косяки. Это draft-версия, и если уже такое где-то было нарисовано, прошу простить, я не нашёл и потому скрутил сам. Думаю, картинка никуда не убежит, а я пока объясню почтенной публике, зачем вообще взялся за эту публикацию.
Хотим мы этого или нет, но эволюция микроконтроллеров на месте стоять явно не собирается. Нет, нет, да и мелькнёт в публикациях (http://habrahabr.ru/post/208026/, http://habrahabr.ru/post/233391/) «тяжёлая периферия» — вмонтированные в МК реализации шины USB, с разборами примеров, использованием HID и т.п. Надо воздать должное автору RaJa: из восьми примеров, приведённых в стандартной библиотеке STSW-STM32121 (UM0424) и кое-как документированных, он выбрал самый полезный (Custom HID), портировал его в бесплатную среду Em::Blocks, изложил понятным языком, немного приукрасил, браво! Это сэкономило мне уйму времени.
Как пройти в библиотеку?
Получив на GitHub любезно выложенный автором проект RHIDDemo для Em::Blocks, я начал портировать его в Keil (мой отладчик CoLink на базе FTDI; кто-нибудь, подскажите плагин от Coocox для Em::Blocks). Но никак не мог понять: где, чёрт возьми, автор раздобыл SPL 3.6.1 выпуска 2012г, если на сайте выложен 3.5.0 от 2011г? Я прошёл довольно скучный квест, который к моему удивлению привёл… прямо на готовый проект Custom HID для Keil в составе библиотеки USB FS 4.0.0. Лежит у всех на виду, как мышь под веником. Ну и ладно. Зато я раскурил, наконец, релизы STMicroelectronics, нашёл описание библиотеки USB FS STSW-STM32121 (UM0424) и пресёк попытки разработчика свести меня с ума. Вот скажите, это нормально подкладывать винтажный CMSIS 1.30 образца 2009г в набор SPL 3.5.0 выпуска 2011г, новый SPL 3.6.1 релиза 2012г прятать в USB-FS 4.0.0 релиза 2013г (подложив туда же и CMSIS 3.0.1 от 2012г), при том, что у них же выложена актуальная версия CMSIS 3.30 релиза 2014г? Кстати, в SPL 3.6.x для STM32F10X исправили пару багов с USART, касающихся сигналов о переполнении буфера. Спасибо, хоть release notes оставили…
HID vs SNMP
Итак, взявшись за STM32F103C8T6, я тоже решил слегка задвинуться по теме USB HID, уж больно хорошо абстракция USB HID укладывается в концепцию всяческих датчиков, сенсоров и прочих ШИМ-управляемых драйверов питания. Чем-то напомнило мне SNMP, только в сильно упрощённом виде: дескрипторы HID играют роль SNMP MIB. Когда устройство инициализируется хостом: «Привет, хост! Я кофеварка. У меня есть кнопка [старт], регуляторы [сливки], [сахар], датчики [остаток кофе], [остаток воды], [остаток сахара], [остаток сливок]. Подтягивай драйвера, дави на кнопку, кофейку попьём». Ничего не напоминает? Пример диалога по SNMP: «Ну, привет, управляющая станция с софтом за $100000. А я шасси коммутатора за $200000, и на мне сидят ещё 4 модуля по $100000 за штуку; в каждом ещё по 16 портов с неприличной скоростью, и всех функций тут просто не перечислить… спрашивай отдельно по каждому пункту; ах, да загрузка процессора такая-то, памяти столько-то…». И ещё на дюжину страниц в таком же духе.
Понравилась мне идея HID. Но стоило выйти из Windows за рамки учебных задач мигания светодиодами (вперёд к реальным окружениям UNIX!), как начало сквозить из всех незаделанных щелей, и я почувствовал себя каким-то беспомощным ламером. Отлаживая проект, я инстинктивно схватился за некое подобие tcpdump (так и называется: usbdump(8), или usbmon), но увидел лишь сообщения на незнакомом языке.
Стало очевидно: не хватает фундаментальных знаний о шине USB. Если модель OSI и стек TCP/IP любой тёртый айтишник осознаёт где-то на уровне спинного мозга просто в силу необходимости, то с USB ситуация другая. Оно и понятно: там можно (нужно) подсмотреть трафик через тот же tcpdump да настроить железо с софтом, а тут полный plug and play, и исправить что-то можно, обновив драйвер или прошивку (или переустановив ОС). Но ведь мы тут с вами собрались как раз за тем, чтобы делать хорошие прошивки, не так ли? Почитав некоторые описания USB в сети, я был удивлён, насколько запутанной может быть документация. У меня даже возникло ощущение, что нас специально хотят сбить с пути истинного, напустив туману и избавившись от конкуренции в зародыше. Я не согласен с таким положением вещей!
Ещё одна замечательная схема
На просторах сети встретил ещё такую иллюстрацию (лежало в формате BMP, без шуток): 
Сперва выглядит оптимистично. Наконец-то, стек в разобранном виде. Кадры, правда, обозначены неудачно: я бы нарисовал их вертикальными пунктирными линиями, а EOF — это просто пауза, реально данные не передаются. Но начинаем читать контекст и теряем понимаем истинный замысел автора (запутать нас):
Вроде бы и нарисовано всё правильно, но по мере прочтения вопросов становится всё больше. Минимальная передаваемая структура данных по шине — это кадр или пакет? Вообще, это сверху вниз надо смотреть или наоборот? И что кодируется по методу NRZI — кадры, пакеты или просто весь битовый поток по шине? Из транзакций состоит посылка, передача, или, может быть, ценная бандероль какая?
Почему нельзя просто: хост группирует пакеты в транзакции и распределяет их по временным квантам, именуемым кадрами, чтобы давать приоритет критичным по времени данным (видео, аудио) исходя из текущей пропускной способности шины? Да, в USB есть нюансы с планированием передачи пакетов, я их пока не затрагиваю.
Моё видение стека USB
Хорошей документацией считаю упоминавшийся тут на хабре USB in a NutShell (ура, перевод), а также USB Made Simple. По ним я и собрал свою версию стека USB, нарисую её ещё раз.

Физический уровень
На физическом уровне используется набор электрических режимов дифференциальной пары проводников (вместе с землёй) для обозначения состояний, с помощью которых кодируется битовый поток по методу NRZI со вставкой битов (bit stuffing): здесь после шести идущих подряд «1» (ну захотелось передать, скажем, 0xffff) вставляется «0», чтобы приёмник подолгу не залипал в одном состоянии; приёмник узнает вставленный «0» и как данные не засчитает, это довольно распространённый приём в кодировании для лучшей автоподстройки частот. Пара проводов вместе с землёй даёт возможность сформировать, как минимум, четыре статических состояния (они обозначаются J, K, SE0, SE1). В USB 2.0 SE1 не используется, а три оставшихся дополнительно разыгрываются в динамике (с часами и переходами) для передачи ещё нескольких управляющих символов (границы пакетов, сброс, подключение/отключение, энергосбережение/выход). Хорошие иллюстрации есть в USB Made Simple, Part 3 — Data Flow.
Т.е. в итоге передаются данные в виде ноликов и единичек, плюс всякие управляющие символы, чтобы можно было из всей этой электродинамической кухни готовить нормальные пакеты данных.
(дополнено по просьбе читателей)
Пакетный уровень
На пакетном уровне между хостом и устройством передаются безадресные пакеты (пара устройств на полудуплексной линии может обойтись и без адресации). Пакет состоит из маркера SYNC для синхронизации тактов приёмника, последовательности байт и символа EOP. Длина пакета переменная, но оговаривается через верхние уровни стека. Первый байт называется Packet Identifier (PID), имеет простой избыточный формат для помехоустойчивости и пригоден для скармливания автомату следующего уровня (для сборки транзакций из пакетов). Пакеты с начинкой (длиннее одного байта PID) снабжаются контрольной суммой (короткой CRC5 или длинной CRC16, в зависимости от типа пакета). Анализатор протоколов должен, как минимум, показывать нам пакеты.
Уровень транзакций
На следующем уровне из пакетов собираются транзакции. Транзакция — это малый набор пакетов (в Full Speed USB 1, 2 или 3), следующих строго друг за другом, которыми (в полудуплексном режиме) хост обменивается с оконечной точкой (endpoint), и только с одной. Очень важно, что транзакцию открывает только хост, это специфика USB (нам в прошивке МК меньше мороки). На уровне транзакций можно говорить о канале (pipe) между хостом и одной из оконечных точек устройства, но я намеренно избегаю термина «канальный уровень» (Data Link) из модели OSI. Анализатор протоколов должен хотя бы декодировать транзакции.
Уровень передач
Поверх транзакций расположим уровень передач (transfers). Их в USB используется четыре типа: контрольные с оконечной точкой №0 (control transfers), передачи с прерываниями (interrupt transfers), изохронные (isochronous transfers) и крупноблочные передачи (bulk transfers). Последние три являются вариантами потоковых каналов (stream pipe), про которые я ещё скажу несколько слов. Этот уровень тоже должен отобразить хороший анализатор протоколов.
Прикладной уровень
Венчает стек, как обычно, прикладной уровень. Здесь происходят: установка адреса устройству хостом, рассказ устройства о себе на языке дескрипторов, команды хоста на выбор конфигурации (контрольные передачи), обмен данными с HID-устройствами (в примерах пока нашёл передачу с прерываниями, хочу попробовать контрольную), печать на принтере и сканирование, доступ к накопителю USB (крупноблочные), общение через гарнитуры и веб-камеры (изохронные) и многие другие замечательные вещи.
Последний штрих
Сбежав на секунду вниз по уровням, можно добавить, что хост периодически вбрасывает по шине те самые пакеты Start of Frame (SOF), разбивая время на равные интервалы, но так, чтобы не разбить при этом сами транзакции. Поэтому пакеты SOF можно считать самостоятельными транзакциями. Не следует путать кадр (фрейм) USB с омонимом канального уровня модели OSI. Лучше уж вспомнить кадры (фреймы) аудио CD, это просто квант времени: хост «тикает» в шину пакетами SOF, чтобы подключённые устройства заранее планировали участие в т.н. изохронных передачах, гоняющих потоки данных в реальном времени. Ну или вот так: группы транзакций планируются хостом по временным интервалам, именуемым кадрами. Кадр составляет 1мс на Full Speed и 125мкс на High Speed USB, но High Speed — более сложный стандарт, его лучше изучать отдельно.
UPD:
Хороший вопрос задали читатели: а как насчёт фрагментации? Я не нашёл в USB 2.0 признаков фрагментации на уровне транзакций и ниже, т.е. транзакции для того и есть, чтобы передаваться целиком. Передачи же в ряде случаев могут и должны разбиваться на несколько транзакций, особенно с учётом изохронных режимов. И я повторю, что всем планированием у нас пока заведует хост (на стороне МК меньше думать приходится).
Смотрим на трафик по USB
Итак, транзакция всегда инициируется хостом в отношении одной выбранной оконечной точки на устройстве (помимо специальной точки с номером 0, их может быть ещё до 15 штук на одном устройстве, например, комбинированная клавиатура с мышью, термометром, флэшкой, кофеваркой и кнопкой вызова сантехника заказа пиццы).
В случае приёма хостом данных с устройства последнее не может само открыть транзакцию, но может только дождаться нужного момента и поучаствовать в ней. Хост открывает транзакцию устройству пакетом с PID = IN (группа Token) и гарантирует на нужное время свободу шины, устройство вбрасывает пакет из группы Data, в зависимости от типа транзакции хост может подтвердить успех третьим пакетом из группы Handshake (ACK, NAK, STALL, NYET), транзакция закрыта.
При отправке данных на устройство (PID = OUT, группа Token) хост открывает транзакцию, отправляет пакет с данными (Data), также в зависимости от режима может принять пакет Handshake с подтверждением успешности транзакции.
По окончании транзакции всё вернётся на круги своя, устройство снова будет ждать управляющих пакетов от хоста.
Режимы передачи USB в примерах STM32 USB FS
Чтобы по одной паре проводов можно было гнать копирование с диска одновременно с аудио-видео потоком, жестами мышью и сигналом скоростного осциллографа, существуют разные типы сообщений и передач.
Чуть выше я только что описал простой потоковый канал (Stream Pipe) между хостом и оконечной точкой, где пакеты с начинкой (группы Data) не несут никакой специальной или управляющей информации самой подсистеме USB. Полная свобода переписки, библиотека контроллера должны предоставлять примитивы для закачки буфера произвольного размера из памяти МК хосту или обратно. Нарезкой на пакеты, пересылкой и «дефрагментацией» пусть занимаются библиотека МК на пару с драйвером хоста. В STM32 это USB_SIL_Write() и USB_SIL_Read(), описаны в UM0424. Они и есть тот самый логический уровень абстракции. На стороне хоста см. описание соответствующего драйвера (например, во FreeBSD это ugen(4)).
Однако использовать тяжёлую периферию вроде USB для организации простого потокового канала я считаю кощунством (спрашивается: чем USART не угодил?). Но ситуации, конечно, бывают всякие.
В любом случае, чтобы подсистема USB вообще ожила и устройство определилось, требуется обмен контрольными транзакциями.
DISCLAIMER
Дальше будут упоминаться примеры из той самой библиотеки UM0424 для работы с Full Speed USB от STMicroelectronics, но они рассчитаны под их родные демоплаты. Берите пример с автора Raja, проявляйте инженерную смекалку в адаптации проектов под свою демоплату.
По софту всё понятно: это примеры не для промышленного использования, там могут быть баги, некоторые части (типа таблицы ссылок в примере Mass storage) защищены патентом, и вы не имеете прав их использовать в коммерческом проекте. Но это ещё ничего, китайцы ухитряются потом продавать на рынке USB-изделия, у которых даже библиотечные VID и PID не удосужились поменять.
По железу, как я понял, надо начинать с кварца. У меня челябинский PinBoard II с кварцем 12Мгц (все библиотеки заточены под 8МГц), я менял умножитель ФАПЧ с 9 на 6 (ссылка с разъяснениями), иначе МК разгонится до 108МГц вместо 72МГц, а USB на 72МГц вместо положенных 48МГц вообще не поедет. Можно ещё сбавить обороты МК до 48МГц, поменяв делитель шины USB с полутора до единицы. Использовать внутренний генератор МК HSI спецы не любят: частота может слегка уплыть от нагрева, последствия для USB предсказать затрудняюсь. Ну и не забываем о периферии, конечно. Без флэш-памяти SPI/SDIO из примера Mass storage можно сделать разве что аналог /dev/null, но его ведь хрен отформатируешь:-)
Контрольные передачи и каналы сообщений
Передачи с прерываниями
Эта разновидность (interrupt transfer) предназначена для обмена небольшими транзакциями, сходными с контрольными. Нет, устройство не может прерывать хоста, оно ждёт опроса, их частота и размеры пакетов оговариваются заранее в дескрипторе устройства. Хорошо подходят для всевозможных пультов, датчиков, сенсоров, мышек, светодиодов и прочих HID-кофеварок. Канал с прерываниями каждой точки однонаправленный.
Примеры: Custom HID, Joystick mouse, Virtual COM port
Передачи изохронные
Χρόνος по-гречески значит «время». Изохронная передача (isochronous transfer) — местный хайтек, позволяющий управлять потоками данных в реальном времени. Отличается гарантированной (но необязательно широкой) полосой пропускания и отсутствием подтверждающих транзакций, почти как UDP с QoS. Битый пакет? Это бог Хронос толкнул МК по ноге. Не надо пытаться отправить пакет заново, иначе бог огорчится. Контрольные суммы, тем не менее, проверяем втихую от Хроноса. Изохронные передачи хороши для аудио-видео и измерительных систем реального времени, а также прочих игрушек двойного назначения. Хотя на некоторые из них м.б. интереснее повесить какой-нибудь AVR, связав его с нашим ARM по USART или SPI. Изохронные операции участвуют во фреймовой сигнализации (вспомним про тиканье пакетом SOF).
Пример: USB voice speaker
Передачи крупноблочные
Нет, мешки с цементом таскать не будем. Я думаю, все узнали режим работы всевозможных накопителей USB. Передачи bulk transfer имеют цель отправить данных как можно больше и быстрее, обязательно с пересылкой битых пакетов, но без гарантий по полосе пропускания, уступая её изохронным передачам при необходимости (как в TCP без QoS). О внутреннем устройстве USB флэшек я как-то уже рассказывал, теперь можно скачать и запустить действующий прототип. Я сам его не пробовал, но таблица команд SCSI в описании примера (как-бы, между прочим) весьма символизирует. Признаков алгоритма управления износом для NAND-памяти я не нашёл:-)
ВНИМАНИЕ: местами действует патентная защита STM.
Пример: Mass storage
Что осталось нераскрытым
Я не имею цель сделать ещё один учебник по USB, их и без меня хватает, и там хорошо описаны: электрическая часть, подробности протоколов, работа с концентраторами, дескрипторный язык и уровень абстракции HID, проблемы с уникальностью VID/PID, USB 3.0 и многие другие замечательные возможности шины USB, как полезные нам, так и не очень. Айтишникам особо рекомендую экскурсию на тёмную сторону с обзором вражеских девайсов (флэшка с замаскированной HID-клавиатурой, которая будет делать страшные вещи).
Ссылки
Адаптация примера Custom HID к бесплатной среде Em::Blocks и бюджетной демо-плате STM32F103C8T6 производства LC-Tech: habrahabr.ru/post/208026
Битва за ИБП: habrahabr.ru/post/233391 ещё одна битва за ИБП: habrahabr.ru/post/233391/#comment_7944489
Экскурсия на тёмную сторону (шпионский девайс из AVR): habrahabr.ru/post/153571
Инструкции по анализу USB в Wireshark для Windows и Linux: wiki.wireshark.org/CaptureSetup/USB
Книжка USB in a NutShell: www.beyondlogic.org/usbnutshell/usb1.shtml
Перевод USB in a NutShell: microsin.ru/content/view/1107/44
Книжка USB Made Simple (действительно упростили): www.usbmadesimple.co.uk
STSW-STM32121, библиотека STMicroelectronics USB full speed device library и все упомянутые примеры (UM0424) www.st.com/web/en/catalog/tools/PF258157
P.S.
Читая публикации на хабре, посвящённые в той или иной степени микроэлектронике, я разглядел две инженерных касты, назовём их условно: Промэлектронщики и Айтишники. Это своего рода инженерный Инь и Ян, в каждом из нас есть доля того и другого.
Промэлектронщики имеют блестящие знания и навыки по железу, паяют радиодетали толщиной с волос левой рукой с закрытыми глазами (причём потом это работает). Взглянув на электронную схему, почти физически начинают ощущать все её токи с потенциалами, работают также и с силовыми схемами, и с (большими, быстрыми, опасными) промышленными изделиями. Подход к программированию МК соответствующий: он просто должен выдать нужные логические уровни на нужные ножки в нужное время, не столь важно каким способом. Консервативны в технологиях (не влезай — работает), тяжёлую периферию МК не особо жалуют. При обсуждении объектно-ориентированного программирования, информационной безопасности, гигантских проектов в миллион строк кода и всяких навороченных графических интерфейсов скучнеют. Вместо пакетно-ориентированной шины USB предпочитают потоковый режим USART, усиленный либо привычным RS-232, либо более брутальным RS-485 (последовательная шина для промышленных применений, до 10Мбит/с на 15м, до 100кБит/с на 1200м, до 32 устройств).
Айтишники воспитаны на понимании операционных систем, сетевой инфраструктуры и сложных взаимодействий, элита хорошо подкована в информационной безопасности и разбирается во всяких незримых способах проникновения в чужую систему. Некоторые при этом очень любят котиков (ну как их можно не любить? я, правда, не держу, не развожу и не готовлю:-). Многие любят свободу информации, ругать корпорации/правительства и побеждать силы природы усилием мысли. Паталогически ленивы, но обожают новые технологии и закрученные инженерные ребусы с дорогими игрушками (желательно решаемые на уровне софта или, в крайнем случае, перемычек). Отношения с паяльником настороженные: не спрашивайте у айтишника, любит ли он паяльник, может неправильно понять; лучше спросите, любит ли он паять электронные схемы.
К чему я? Мы просто видим этот мир по-разному… Ведь ядро Linux кроили такие же ребята, из модулей на С и ассемблерных вставок для конкретных платформ, и без холиваров вроде обошлись. По-настоящему серьёзный проект я вижу как многоядерную систему, сочетающую современнейшие МК с тяжёлой периферией, но не исключаю связки с классическими моделями типа AVR: ими можно обвесить какие-нибудь критичные быстровращающиеся острия технического прогресса. Если код проверенный годами, то почему нет?
5. Типы передачи данных
USB поддерживает как однонаправленные, так и двунаправленные режимы связи. Передача данных производится между ПО хоста и конечной точкой устройства. Устройство может иметь несколько конечных точек, связь с каждой из них (канал) устанавливается независимо.
Архитектура USB допускает четыре базовых типа передачи данных:
* Управляющие посылки (Control Transfers), используемые для конфигурирования во время подключения и в процессе работы для управления устройствами. Протокол обеспечивает гарантированную доставку данных. Длина поля данных управляющей посылки не превышает 64 байт на полной скорости и 8 байт на низкой.
* Сплошные передачи (Bulk Data Transfers) сравнительно больших пакетов без жестких требований ко времени доставки. Передачи занимают всю свободную полосу пропускания шины. Пакеты имеют поле данных размером 8, 16, 32 или 64 байт. Приоритет этих передач самый низкий, они могут приостанавливаться при большой загрузке шины. Допускаются только на полной скорости передачи.
* Прерывания (Interrupt) — короткие (до 64 байт на полной скорости, до 8 байт на низкой) передачи типа вводимых символов или координат. Прерывания имеют спонтанный характер и должны обслуживаться не медленнее, чем того требует устройство. Предел времени обслуживания устанавливается в диапазоне 1-255 мс для полной скорости и 10-255 мс — для низкой.
* Изохронные передачи (Isochronous Transfers) — непрерывные передачи в реальном времени, занимающие предварительно согласованную часть пропускной способности шины и имеющие заданную задержку доставки. В случае обнаружения ошибки изохронные данные передаются без повтора — недействительные пакеты игнорируются. Пример — цифровая передача голоса. Пропускная способность определяется требованиями к качеству передачи, а задержка доставки может быть критичной, например, при реализации телеконференций.
Полоса пропускания шины делится между всеми установленными каналами. Выделенная полоса закрепляется за каналом, и если установление нового канала требует такой полосы, которая не вписывается в уже существующее распределение, запрос на выделение канала отвергается.
Архитектура USВ предусматривает внутреннюю буферизацию всех устройств, причем чем большей полосы пропускания требует устройство, тем больше должен быть его буфер. USB должна обеспечивать обмен с такой скоростью, чтобы задержка данных в устройстве, вызванная буферизацией, не превышала нескольких миллисекунд.
Изохронные передачи классифицируются по способу синхронизации конечных точек — источников или получателей данных — с системой: различают асинхронный, синхронный и адаптивный классы устройств, каждому из которых соответствует свой тип канала USB.
Интерфейс USB. Часть 1. Основы
В настоящий момент один из самых популярных интерфейсов — это безусловно USB. Девайсов, которые его используют, просто огромное количество. Это и мышки, и клавиатуры, и принтеры, и сотовые телефоны, и много чего ещё. В отличии от стремительно исчезающего RS-232, USB встречается во всех современных компьютерах, ноутбуках, телефонах… так что, если мы хотим создавать действительно универсальные девайсы, придётся нам этот интерфейс изучать. Вот прямо сейчас и начнём, а заодно, по ходу изучения, попытаемся сами посоздавать каких-нибудь USB-девайсов.
Итак, USB (universal serial bus) — универсальная последовательная шина. Большинство USB-устройств соответствуют спецификациям 1.1 и 2.0. В спецификации 1.1 определены две скорости передачи информации: LS (low speed) — низкая скорость, 1,5 Мбит/с и FS (full speed) — полная скорость, 12 Мбит/с. В редакции 2.0 к ним добавлена ещё и высокая скорость HS (high speed), 480 Мбит/с. Не так давно вышла ещё спецификация — 3.0, но устройства, поддерживающие этот стандарт, пока не очень распространены, поэтому и бог с ней.
Физические устройства на шине USB бывают трёх типов: хост-контроллер, хаб и конечное устройство.
Хост-контроллер — это главный управляющий шиной USB. Именно он обеспечивает связь устройств, подключенных к шине, с компьютером (с ОС и с клиентским ПО). Любые сеансы обмена данными может начинать только хост-контроллер, остальные устройства молчат в тряпочку, пока хост-контроллер к ним не обратится.
Контроллер взаимодействует с ОС через драйвер хост-контроллера (HCD — host controller driver). Этот драйвер привязан к конкретной модели хост-контроллера. Только он знает какие данные, в какие регистры и в каком порядке пихать в хост-контроллер, а также откуда какие данные брать, чтобы хост-контроллер сделал то, чего от него хотят.
Со стороны ОС шиной USB управляет ещё один драйвер — USBD (universal serial bus driver). Ему совершенно пофиг, как там конкретно реализован хост-контроллер и где у него какие регистры (для этого есть HCD), USBD решает общие (неспецифические для конкретного хост-контроллера) вопросы: взаимодействие с клиентским ПО, нумерация устройств на шине, их конфигурирование, распределение питания и пропускной способности шины и так далее. Это, можно сказать, своеобразный диспетчер, который осуществляет общий контроль над шиной и её взаимодействие с внешним миром (с клиентским ПО).
Хост-контроллер — птица гордая и пугливая, поэтому непосредственно ни с кем из подданных он не разговаривает. Для общения с подданными у него есть специальные помощники — хабы (их ещё иногда называют концентраторами).
Хабы — это устройства, которые позволяют физически подключить устройства USB к шине. Они предоставляют порты для подключения, ретранслируют трафик от хост-контроллера к конечным устройствам и обратно, отслеживают состояние и физически управляют электропитанием портов. У хабов есть один восходящий (upstream) порт, — это тот порт, который подключен по направлению к хост-контроллеру, и несколько нисходящих (downstream) портов, — это порты, к которым подключаются конечные устройства. Хабы можно каскадировать, подключая к нисходящему порту хаба ещё один хаб. Самый главный хаб, интегрированный с хост-контроллером, называется корневым хабом (он же — корневой концентратор или root hub).
Другими словами можно сказать, что у хаба есть две основных задачи: 1) создать хост-контроллеру иллюзию, что он непосредственно разговаривает с подключенным к хабу устройством; 2) наблюдать за своим сегментом шины (за девайсами, подключенными к нисходящим портам), сообщать «наверх» обо всех изменениях и, если надо, — подключать и отключать питание портов.
Конечные устройства — это все те полезные устройства, которые мы подключаем к шине USB (флэшки, принтеры, мышки и т.д.)
Нужно сказать, что физические устройства и логические устройства — это не всегда одно и тоже. Существуют, например, такие конечные устройства (называемые составными — compound devices), которые содержат внутри себя хаб, к которому подключено ещё несколько устройств. Несмотря на то, что в этом случае хаб и все, подключенные к нему устройства, запакованы в один корпус, с точки зрения логики шины это будут совершенно разные устройства.
Для логических конечных устройств обычно используют термин «функции». Таким образом, с точки зрения логики шины, устройства на ней можно разделить на хабы и функции (и неважно, запакованы ли они в один корпус или нет). Каждое логическое устройство на шине имеет уникальный адрес (1-127), присваеваемый ему хостом при подключении.
Исходя из описанного выше, получается, что физическая топология шины USB — дерево (ну, потому что хабы можно каскадировать), а логическая топология — звезда, центром которой является хост-контроллер. Физическая и логическая топологии шины USB показаны на рисунке ниже.
Идём дальше. Что же вообще представляет собой логическое устройство USB (как хабы, так и функции)?
Логическое устройство представляет собой набор так называемых конечных точек (endpoints или просто EP). Физически, конечные точки — это просто разные буферы в логическом устройстве USB, через которые происходит обмен данными с хостом. Логичный вопрос — а зачем нам иметь несколько буферов? Ну, просто потому что удобно для разных задач иметь разные буферы. Устройство же у нас может выполнять параллельно несколько разных задач. (Минимум две — отслеживать команды управления от хоста и делать что-то полезное.) У этих разных задач могут могут быть разные степени важности, требования к надёжности, своевременности и скорости доставки данных и, наконец, источники и потребители пересылаемой информации также могут быть разные (источником и потребителем полезной инфы обычно является клиентский драйвер, в то же время всякая управляющая инфа ему обычно нафиг не нужна).
Поскольку для решения описанных выше проблем недостаточно иметь просто разные буферы для разной передаваемой информации, то в дополнение к этому придумали ещё кое-что.
Во-первых, придумали 4 различных типа передач. Для каждой конечной точки должно быть определено, каким из этих типов передач с ней нужно общаться. Типы передач в USB существуют следующие:
- изохронные передачи (isochronous transfers). Они предназначены для передачи потоковых данных в реальном времени. Такие передачи гарантируют время доставки, но не гарантируют, что все данные будут доставлены. Если во время передачи происходит ошибка, то данные просто теряются. Кроме того, для передач такого типа должно быть предварительно согласовано, какую часть пропускной способности шины эта передача будет занимать. Изохронные передачи имеют наивысший приоритет и имеют право занять до 90% пропускной способности канала. Передачи этого типа используются, например, для видеокамер, или колонок. Никого ведь не устроит, если звук в колонках будет лагать. Лучше уж потерять часть данных, но слушать песню не рывками, а непрерывно.
- прерывания (interrupts). Этот тип предназначен для спонтанных небольших сообщений, но с гарантированным временем обслуживания и гарантированной доставкой. Примером может служить USB клавиатура. Мы можем нажать на кнопку в любой момент (может 3 часа не нажимали, а может так и заклацали клавой каждую секунду). Пока мы спим за компом — и передавать ничего не надо. Но как только мы всё же щелканули по кнопкам — будьте любезны, сообщите об этом куда следует и желательно побыстрее.
- передача массивов данных (bulk data transfers). Для этого типа нет никаких гарантий по скорости, единственное в чём можно быть уверенным — что данные дойдут в целости и сохранности (когда-нибудь, гы-гы). Такие передачи имеют самый низкий приоритет, но зато им ничего не надо согласововать, — сколько останется свободной от других типов передач ширины канала — столько они и займут. Не останется вообще — будут ждать, когда канал освободится. Такие передачи можно использовать для обмена данными с устройствами, которым некуда спешить, например, с принтерами. Представьте, что вы отправили на печать USB-принтеру фотку и одновременно слушаете музыку в USB-колонках. Согласитесь ли вы, чтобы фотка напечаталась на 3 секунды раньше, но при этом начал лагать звук в колонках? Вероятнее всего нет, так ведь. Пусть лучше данные принтеру передаются медленнее, но зато музыка играет непрерывно, без всяких дёрганий.
- управляющие передачи (control transfers). Это передачи типа запрос-ответ. С помощью них передаются комады управления устройствами. Тут важна не только безошибочная передача, но и получение ответа о результатах выполнения команды. Кроме того, поскольку эти передачи являются служебными, то им гарантировано 10% пропускной способности канала.
Вернёмся к нашим конечным точкам. Для того, чтобы отличить одну точку от другой, — конечные точки, должны иметь уникальный номер. Но это не всё. Кроме номера, каждая конечная точка имеет ещё и направление. IN — если точка предназначена для передачи данных хосту, OUT — если точка предназначена для приёма данных от хоста. Точки с одинаковыми номерами, но с разными направлениями передачи данных — это разные с точки зрения логики шины конечные точки.
Единственное исключение — конечная точка EP0. У неё вообще особый статус. Она является служебной и предназначена для общего управления устройством (конфигурирование, настройка и т.д.). Кроме того, эта конечная точка двунаправленная и она должна обязательно присутствовать в любом USB-устройстве.
Исходя из всего вышеописанного, для идентификации какой-то конечной точки на шине, нам нужно знать адрес устройства, к которому относится конечная точка, её номер в устройстве и направление передачи данных через эту точку.
Поскольку устройство не всегда делает абсолютно всё на что оно только способно, да и способов решения одной и той же задачи оно может иметь несколько, то обычно нет необходимости задействовать абсолютно все конечные точки. Поэтому придумали такие понятия, как интерфейс, конфигурация и альтернативные установки. Интерфейс объединяет конечные точки, предназначенные для решения какой-либо одной задачи. Наборы используемых одновременно интерфейсов называются конфигурациями. Альтернативные установки позволяют включать или отключать какие-то входящие в конфигурацию конечные точки, в зависимости от способа решения задач для которых предназначена эта конфигурация.
Самих конфигураций и альтернативных установок у каждой из этих конфигураций для одного логического устройства может существовать несколько, но в каждый момент времени только один из этих наборов может быть активен. Причём хост должен знать, какой именно набор активен и в соответствии с этим обеспечивать связь с входящими в этот набор конечными точками. Остальные конечные точки, не входящие в активный набор, не будут доступны для связи.
Поясню, что значит «обеспечивать связь с конечными точками». Для связи клиентского ПО с каждой активной конечной точкой хост создаёт коммуникационный канал (communication pipe). Клиентское ПО, которое хочет пообщаться с конечной точкой, должно отправить к соответствующему каналу пакет запроса ввода/вывода (IRP — input/output request packet) и ждать уведомления о завершении его обработки. В IRP указывается только адрес буфера, куда надо складывать или откуда брать данные и длина передачи. Всё остальное за вас сделает хост и обслуживающие его драйвера (USBD и HCD)
В зависимости от типа передач, используемых в канале, коммуникационные каналы делятся на два типа: потоковые (streaming pipes) и каналы сообщений (message pipes).
Коммуникационный канал к точке EP0 является служебным и называется основной канал сообщений (default pipe, control pipe 0). Владельцем основных каналов сообщений всех подключенных устройств является драйвер USBD, поскольку, как мы уже говорили, через EP0 осуществляется конфигурирование и настройка устройства.
На этом, пожалуй, с основами закончим и в следующей статье попробуем более детально рассмотреть механизм передачи данных по интерфейсу USB.
Компьютерная Энциклопедия
Кабель USB содержит две пары проводов: одну для сигнальных цепей (D+ и D-) и одну пару для схемной земли (GND) и подачи питания +5 В (Vbus). Допустимая длина сегмента (кабеля от устройства до хаба) — до 5 м. Ограничения на длину сегмента диктуются затуханием сигнала и вносимыми задержками. Задержка распространения сигнала по кабельному сегменту не должна превышать 26 нс, так что при большой погонной задержке допустимая длина кабеля может сократиться. Максимальное удаление устройства от хост-контроллера определяется задержкой, вносимой кабелями, промежуточными хабами и самими устройствами.
В кабеле USB 1.x для сигнальных цепей используется витая пара проводов калибра 28AWG с импедансом 90 Ом. Характеристики кабеля нормированы в частотном диапазоне до 16 МГц. Для питания используется неперевитая пара проводов калибра 20AWG–28AWG. Требований к экранированию кабелей в USB 1.x не выдвигалось. Для низкой скорости может использоваться кабель с неперевитой парой сигнальных проводов (он дешевле и тоньше), но его длина не должна превышать 3 м.
В кабелях USB 2.0 используются провода тех же калибров, но в спецификации описана конструкция кабеля, в которую входит обязательный экран и связанный с ним дополнительный проводник. Такой кабель пригоден для работы на любых скоростях, включая и HS (480 Мбит/с).
Разъемы USB сконструированы с учетом легкости подключения и отключения устройств. Для обеспечения возможности «горячего» подключения разъемы обеспечивают более раннее соединение и позднее отсоединение питающих цепей по отношению к сигнальным. В USB определено несколько типов разъемов:
- тип «A»: гнезда (рисунок а) устанавливаются на нисходящих портах хабов, это стандартные порты подключения устройств. Вилки типа «A» устанавливаются на шнурах периферийных устройств или восходящих портов хабов;
- тип «B»: используются для шнуров, отсоединяемых от периферийных устройств и восходящих портов хабов (от «мелких» устройств — мышей, клавиатур и т. п. кабели, как правило, не отсоединяются). На устройстве устанавливается гнездо (рисунок б), на кабеле — вилка;
- тип «Mini-B» (рисунок в): используются для отсоединяемых шнуров малогабаритных устройств;
- тип «Mini-A»: введен в спецификации OTG, вилки используются для подключения устройств к портам малогабаритных устройств с гнездом «mini-AB».
- тип «Mini-AB»: гнезда введены в спецификации OTG для портов двухролевых устройств, которые могут вести себя как хост (если в гнездо вставлена вилка miniA) или как периферийное устройство (если в гнездо вставлена вилка mini-B).

Назначение выводов разъемов USB приведено в таблице, нумерация контактов показана на рисунке выше. Штырьковые разъемы, устанавливаемые на системной плате (рисунок г), предназначены для кабелей-«выкидышей», которыми подключаются дополнительные разъемы USB, устанавливаемые на передней или задней стенках корпуса компьютера (иногда и на боковых). На эти разъемы порты выводятся парами, причем у разных производителей подход к универсальности и защите от ошибочных подключений различен. Подключение «выкидыша», не подходящего к разъему, приводит к неработоспособности порта (к счастью, как правило, временной). Ошибка в подключении цепей GND и +5V может приводить к нагреванию кабелей и разъемов из-за короткого замыкания питающей цепи.
Все кабели USB «прямые» — в них соединяются одноименные цепи разъемов, кроме цепи ID, используемой для идентификации роли устройства в OTG. На вилке mini-A контакт 4 (ID) соединен с контактом 5 (GND), что заставляет порт, к которому подсоединена такая вилка, взять на себя роль нисходящего порта хаба. На вилке miniB такого соединения нет.
Ошибка в полярности подводимого питания может повредить подключаемое устройство (и необратимо). По этой причине наиболее безопасными для подключаемого устройства являются внешние разъемы USB, запаянные на системной плате или карте контроллера USB.
Таблица. Назначение выводов разъема USB
| Цепь | Контакт стандартного разъема | Контакт миниразъема |
| VBus (+5 В) | 1 | 1 |
| D– | 2 | 2 |
| D+ | 3 | 3 |
| GND | 4 | 5 |
| ID | — | 4 |
Приемопередатчики
Для передачи сигналов используются два провода D+ и D–. На каждой стороне интерфейса (порте хаба и подключенного устройства, см. рисунок ниже) имеются:
- дифференциальный приемник, выход которого используется при приеме данных;
- управляемый (отключаемый) дифференциальный FS/LS-передатчик — источник напряжения, позволяющий кроме дифференциального сигнала формировать и «линейный 0» (SE0), а также отключаться для обеспечения полудуплексного обмена;
- линейные приемники, сообщающие текущее состояние каждого сигнального провода;
- резисторы, подтягивающие уровни сигналов для обнаружения подключения устройства:
— Rd1, Rd2 (15 кОм) у хаба;
— Ruf (у FS/HS-устройства) или Rul (у LS-устройства); - Дополнительные элементы для работы на высокой скорости (только для устройств HS):
— коммутатор, отключающий резистор Ruf при выборе высокой скорости;
— последовательные резисторы Rz1 и Rz2 на выходах дифференциального передатчика, обеспечивающие согласование с линией и нагрузку;
— управляемый дифференциальный источник тока;
— детектор амплитуды сигнала;
— детектор отключения (только на нисходящих портах хабов).
Уровни сигналов передатчиков FS/LS в статическом режиме должны быть ниже 0,3 В (низкий уровень) или выше 2,8 В (высокий уровень). Приемники должны выдерживать входное напряжение в пределах –0,5. +3,8 В. Чувствительность дифференциальных приемников — 200 мВ при синфазном напряжении 0,8–2,5 В. Линейные приемники должны обладать гистерезисом с нижним порогом 0,8 В и верхним порогом 2 В.

Передача данных
Передача по двум проводам USB не ограничивается лишь дифференциальными сигналами. Приемники и передатчики позволяют использовать множество состояний линий и команд, используемых для организации аппаратного интерфейса. При этом учитываются не только уровни электрических сигналов, но и время нахождения их в том или ином состоянии. По уровням напряжения на входах приемников различают сигналы:
- Diff0: (D+) — (D-) > 200 мВ при (D+) > 2 В;
- Diff1: (D-) — (D+) > 200 мВ при (D-) > 2 В;
- SE0 (single-ended zero): (D+) < 0,8 В и (D-) < 0,8 В.
Для передачи данных используются сигналы Diff0 и Diff1, они кодируют состояния J (Data J State) и K (Data K State). На полной и высокой скорости состояние J соответствует сигналу Diff1, состояние K — сигналу Diff0. На низкой скорости назначение обратное: J — Diff0 и K — Diff1. Последовательная передача информации ведется с использованием кодирования NRZI (см. рисунок ниже): при передачи нулевого бита в начале битового интервала состояние сигнала (J или K) меняется на противоположное; при передаче единичного — не меняется. Длительность битового интервала определяется номинальной частотой передачи: 0,666… мкс для низкой скорости (LS, 1,5 Мбит/с); 83,3… нс для полной (FS, 12 Мбит/с) и 2,0833… нс для высокой (HS, 480 Мбит/с).
Состояние покоя (Bus Idle) на FS/LS соответствует длительному состоянию J, а на HS — состоянию SE0.
Признаком начала пакета является переход из состояния покоя в состояние K, что является первым битом синхропоследовательности (Sync), — последовательности нулей, которая в NRZI кодируется переключением состояний (J и K) в начале каждого битового интервала. Синхропоследовательность позволяет приемнику настроиться на нужною частоту и фазу синхронизации. Синхропоследовательность завершает единичный бит (нет смены состояния), последующие за ним биты относятся к идентификатору и телу пакета. На HS начальная часть синхропоследовательности может быть потеряна хабом (из-за задержки реакции на детектор сигнала). С учетом этого синхросполедовательность для HS удлинена до 32 бит (включая последний единичный бит). Проходя через 5 хабов, каждый из которых может потерять до 4 синхробит, синхропоследовательность может оказаться сокращенной до 12 бит.
Для того чтобы синхронизация не терялась на монотонном сигнале (при передаче длинной последовательности единиц), применяется техника вставки бит (bit stuffing): после каждых 6 подряд следующих единиц передатчик вставляет «0», приемник эти вставленные биты удаляет. Если принимается более 6 единиц подряд, это считается ошибкой вставки бит.
Конец пакета (EOP) на FS/LS обозначается сигналом SE0, длящимся 2 битовых интервала, за которым следует переход в состояние покоя (Bus Idle). На HS для признака EOP используется нарушение правила вставки бит. Здесь в качестве EOP используется передача последовательности 01111111 без вставки бит. Прием седьмой единицы вызовет индикацию ошибки вставки бит, которая на HS и является признаком конца пакета. Нормальный пакет при этом от действительно ошибочного будет отличаться целым количеством принятых байт (это условие может и не проверяться) и верным значением CRC. Начальный нолик (вызывающий смену состояния) в EOP облегчает точное определение границы тела пакета. В пакетах SOF поле EOP удлинено до 40 бит для обнаружения отключения устройства.

Особенности сигналов в режиме HS
Высокая скорость (480 Мбит/с — всего в 2 раза медленнее, чем Gigabit Ethernet) требует тщательного согласования приемопередатчиков и линий связи. На этой скорости может работать только кабель с экранированной витой парой для сигнальных линий. Для высокой скорости аппаратура USB должна иметь дополнительные специальные приемопередатчики. К разводке проводов на печатной плате устройства от интерфейсной микросхемы USB до разъема (или подключения кабеля) предъявляют жесткие требования (максимальная длина, совпадение длин сигнальных проводников, удаленность от других сигнальных цепей, окружение «землей»).
В отличие от формирователей потенциала для режимов FS и LS передатчики HS являются источниками тока, ориентированными на наличие резисторов-терминаторов на обеих сигнальных линиях. Роль терминаторов играют резисторы Rz1 и Rz2 (см. рис. 12.2): при работе на HS дифференциальный передатчик FS/LS формирует SE0, то есть оба его выхода заземляются и эти резисторы оказываются нагрузками для линий D+ и D-. Их сопротивление (с учетом выходного импеданса передатчика) составляет 2×45 = 90 Ом, что и обеспечивает согласование с волновым сопротивлением линии (90 Ом). Устройство и хаб включают свои HS-терминаторы (и отключают Ruf) после успешного взаимного подтверждения режима HS, выполняемого в процессе сброса устройства.
Дифференциальные токовые передатчики формируют импульсы тока с номинальным значением 17,78 мА, который протекает через нагрузку 22,5 Ом (два нагрузочных резистора на обоих концах каждой сигнальной линии соединяются параллельно). При передаче сигнала J ток пропускается в линию D+, при K — в D-. Таким образом обеспечивается дифференциальный сигнал передачи около ±400 мВ.
На вход дифференциального приемника сигнал придет ослабленным; чтобы исключить влияние шумов, в схему устройства введен детектор амплитуды сигнала с порогом 100–150 мВ. Сигнал с дифференциального приемника игнорируется, пока не сработает детектор амплитуды сигнала (в спецификации USB этот прием называется receiver squelch). От срабатывания детектора амплитуды до включения дифференциального приемника может быть задержка до 4 bt, но это приведет лишь к сокращению длины принятой синхропоследовательности в начале пакета.
К статическим (уровни) и динамическим (длительности и время нарастания и спада) параметрам сигналов на HS предъявляются жесткие требования, и существуют специальные шаблоны (Eye Pattern), в которые должны укладываться сигналы. Для тестирования могут быть использованы широкополосные (не уже 1 ГГц) дифференциальные осциллографы и генераторы; выпускаются и специализированные тестеры устройств USB 2.0. Для тестирования HS-устройств (включая и хабы) в USB 2.0 определены специальные управляющие запросы, переводящие выбранный порт в тестовый режим. В стандартных запросах определены следующие тесты:
- Test_SE0_NAK — перевод порта в HS-режим для тестирования выходного импеданса, уровня сигнала SE0 и нагрузочных характеристик;
- Test_J — передача состояния J (подача тока в D+) для проверки уровня сигнала, выводимого на линию D+;
- Test_K — передача состояния K (подача тока в D-) для проверки уровня сигнала, выводимого на линию D-;
- Test_Packet — передача пакетов фиксированной структуры, позволяющая проверять динамические параметры сигнала и подключенные к нему приемники. Тестовый пакет выглядит как пакет данных DATA0, у которого в поле данных последовательно расположены 6 тестовых образцов (test pattern). Далее приводятся последовательности сигналов, передающихся на шину в этих образцах (вставка бит уже произведена):
— Pattern 1 — 36 пар «JK»;
— Pattern 2 — 16 повторов «JJKK»;
— Pattern 3 — 8 повторов «JJJJKKKK» (4J и 4K);
— Pattern 4 — 8 повторов «JJJJJJJKKKKKKK» (7J и 7K);
— Pattern 5 — 8 повторов «JJJJJJJK» (7J и 1K);
— Pattern 6 — 10 повторов «JKKKKKKK» (1J и 7K). - Test_Force_Enable — принудительный перевод нисходящих портов хаба в режим HS, даже при отключенных устройствах (для настройки детектора отключения).
Специальная сигнализация: обнаружение подключения-отключения, сброс устройств, приостановка и пробуждение
Хаб обнаруживает подключение устройства по уровням напряжения на линиях D+ и D–:
- при отключенном устройстве на линиях D+ и D- уровни сигнала низкие (состояние SE0), что обусловлено резисторами Rd1 и Rd2 хаба;
- при подключении LS-устройства повышается уровень сигнала D- за счет резистора Rul в устройстве (переход в состояние LS-Idle);
- при подключении FS/HS-устройства повышается уровень сигнала D+ за счет резистора Rul в устройстве (переход в состояние FS-Idle).
Последовательность обнаружения подключения и сброса устройств FS и LS приведена на рисунках а и б соответственно. Хаб следит за сигналами нисходящего порта и сигнализирует об их смене. После обнаружения смены состояния системное ПО выжидает около 100 мс (время на успокоение сигналов) и проверяет состояния порта. Обнаружив факт подключения и тип устройства (LS или FS/HS), ПО дает для этого порта команду сброса шины.

Для выполнения сброса шины (команда Bus Reset) хаб опускает уровень поднятого устройством сигнала (D+ или D) на 10–20 мс (то есть подает сигнал SE0 в течение 10–20 мс). Считается, что через 10 мс после этого сброса устройство должно быть готово к конфигурированию (отзываться только на обращения к EP0 по нулевому адресу устройства).
Сброс шины для устройства HS запускает протокол согласования скорости. При подключении, как и по сигналу сброса, HS-устройство устанавливает свои схемы в состояние FS (отключая терминаторы и включая Ruf). Таким образом, поначалу HS-устройство выглядит для хаба как FS-устройство. Для согласования скорости используется так называемое «чириканье» (chirp-sequence): в ответ на состояние SE0, введенное хабом для сброса (заземлением линии D+), HS-устройство своим дифференциальным токовым передатчикам вводит состояние «chirp-K» (пуская импульс тока в линию D-). На этот импульс HS-хаб ответит импульсом на линии D+, так что получится состояние «chirp-J». Такой обмен импульсами повторяется еще дважды; после успеха согласования и устройство и хаб принимают режим работы HS (и резистор Ruf отключается). Все это «чириканье» занимает 10–20 мс, после чего шина переходит в состояние покоя HS-Idle (длительный сигнал SE0). Теперь хосту надо снова опросить состояние порта хаба, чтобы уточнить режим подключенного устройства (FS или HS). Если HS-устройство подключено к FSпорту, хаб на «чириканье» устройства не ответит.
Отключение устройств FS/LS обнаруживается хабом просто по длительному (более 2 мкс) состоянию SE0. Этот факт хаб доводит до сведения системного ПО (USBD), чтобы устройство было вычеркнуто из всех рабочих списков. Отключение устройств HS таким способом обнаружить не удается, поскольку состояние шины (SE0) при отключении устройства не изменится. Для обнаружения отключения HS-устройства используют эффект отражения сигнала при потере согласованности линии. Специально для этих целей в схему хаба введен дополнительный детектор отключения, а в маркере микрокадра SOF признак EOP (0111…111) удлинен до 40 битовых интервалов. Транслируя SOF на высокоскоростной порт, детектор отключения следит за уровнем сигнала J, и если он превышает порог (625 мВ дифференциального сигнала), значит, нагрузки на другой стороне нет, то есть устройство отключено. Удлинение EOP необходимо, поскольку устройство может отключиться внутренне, и из-за задержки в кабеле устройства (2×26 нс) отраженный сигнал может задержаться до 25 нс. С целью сокращения накладных расходов это удлинение EOP сделали только для пакетов SOF, появляющихся всего раз в 125 мкс.
Команду приостановки устройства — Suspend хаб сигнализирует длительным состоянием покоя (Bus Idle). При этом он должен переставать транслировать все кадры, включая и маркеры микрокадров на порты, для которых подается эта команда. На порты, работающие в LS-режиме, маркеры кадров не транслируются; чтобы LS-устройство не приостанавливалось при отсутствии полезного трафика, ему вместо маркеров SOF хаб с тем же периодом посылает сигнал LS-EOP (SE0 в течении 1,33 мкс). Приостановка делается не менее чем на 20 мс — за это время устройство должно успеть перейти в приостановленное состояние и стать готовым к получению сигнала возобновления.
Команду приостановки HS-порта хаб сигнализирует покоем (SE0) в течение 3 мс, после чего переключает свои цепи в режим FS (отключает терминаторы), но помнит, что порт находится в режиме HS. Для HS-устройства команда приостановки поначалу неотличима от сброса. Чтобы их различить, через 3–3,125 мс непрерывного состояния SE0 HS-устройство переключает свои цепи в режим FS (отключает терминаторы и включает Ruf). Далее, через 100–875 мкс устройство проверяет состояние линий. Если обе лини D+ и D- оказались в низкоуровневом состоянии, значит, хаб подал команду сброса (и устройство должно выполнить chirp-последовательность). Если уровень D+ высокий, а D- низкий (FS-Idle), то это сигнал к приостановке. Таким образом, по состоянию сигналов на шине приостановка выглядит как покой LS/FS — то есть состояние J.
Сигналом к возобновлению работы (resume) является перевод шины в состояние K на длительное время (20 мс), достаточное для «оживления» устройств, после чего хаб посылает сигнал LS-EOP (SE0 в течение 1,33… мкс). После этого шина переходит в состояние покоя соответствующей скорости и начинает передаваться трафик. Сигнал возобновления может подать как хаб, так и приостановленное устройство; последний случай называется удаленным пробуждением. По сигналу возобновления устройство, работавшее в HS-режиме, и его порт хаба переключают свои цепи в HS-режим без всякого согласования (они помнят свой режим).
Удаленное пробуждение — Remote Wakeup — это единственный случай на USB, когда сигнальную инициативу проявляет устройство (а не хост). Сигнал пробуждения может подать только приостановленное устройство, для которого шина находится в FS/LS-состоянии J (резисторами подтягивается вверх D+ или D-). Для сигнализации пробуждения устройство на некоторое время (1–15 мс) формирует состояние K, которое воспримется хабом как сигнал Resume и транслируется им на восходящий порт и на все разрешенные нисходящие порты, включая и тот порт, с которого пришел данный сигнал.