Usb device что это
Usb device что это
USB (ю-эс-би, англ. Universal Serial Bus — «универсальная последовательная шина») — последовательный интерфейс передачи данных для среднескоростных и низкоскоростных периферийных устройств в вычислительной технике. Символом USB являются четыре геометрические фигуры: большой круг, малый круг, треугольник и квадрат, расположенные на концах древовидной блок-схемы.
Разработка спецификаций на шину USB производится в рамках международной некоммерческой организации USB Implementers Forum (USB-IF), объединяющей разработчиков и производителей оборудования с шиной USB.
Для подключения периферийных устройств к шине USB используется четырёхпроводный кабель, при этом два провода (витая пара) в дифференциальном включении используются для приёма и передачи данных, а два провода — для питания периферийного устройства. Благодаря встроенным линиям питания USB позволяет подключать периферийные устройства без собственного источника питания (максимальная сила тока, потребляемого устройством по линиям питания шины USB, не должна превышать 500 мА, у USB 3.0 — 900 мА).
Содержание
История
Первые спецификации для USB 1.0 были представлены в 1994—1995 годах. Разработка USB поддерживалась фирмами Intel, Microsoft, Philips, US Robotics. USB стал «общим знаменателем» под тремя не связанными друг с другом стремлениями разных компаний:
Поддержка USB вышла в виде патча к Windows 95b, в дальнейшем она вошла в стандартную поставку Windows 98. В первые годы устройств было мало, поэтому шину в шутку называли «Useless serial bus» — «бесполезная последовательная шина». [1] Впрочем, производители быстро осознали пользу USB, и уже к 2000 году большинство принтеров и сканеров работали с новым интерфейсом.
Hewlett-Packard, Intel, Lucent (ныне Alcatel-Lucent), Microsoft, NEC и Philips совместно выступили с инициативой по разработке более скоростной версии USB. Спецификация USB 2.0 была опубликована в апреле 2000 года, и в конце 2001 года эта версия была стандартизирована USB Implementers Forum. USB 2.0 является обратно совместимой со всеми предыдущими версиями USB.
Следует отметить, что в начале 2000-х годов корпорация Apple отдавала приоритет шине FireWire, в разработке которой она принимала активное участие. Ранние модели iPod были оснащены только интерфейсом FireWire, а USB отсутствовал. Впоследствии компания отказалась от FireWire в пользу USB, оставив в некоторых моделях FireWire только для подзарядки. Однако, клавиатуры и мыши, начиная со второй половины 90-х годов, имели интерфейс USB.
В середине 2000-х годов BIOS’ы компьютеров массового сегмента начали поддерживать USB (поддержка USB в корпоративном сегменте началась с середины 90-х). Это позволило загружаться с флэш-дисков, например, для переустановки ОС; пропала надобность в PS/2-клавиатуре. Современные материнские платы поддерживают до 20 USB-портов. В современных ноутбуках LPT-портов нет, всё чаще появляются настольные компьютеры без COM- портов.
Пока происходило распространение USB-портов второй версии, производители внешних жёстких дисков уже «упёрлись» в ограничение USB 2.0 — и по току, и по скорости. Потребовался новый стандарт, который и вышел в 2008 году. Уложиться в старые 4 провода не удалось, добавили 5 новых проводов. Первые материнские платы с поддержкой USB 3.0 вышли в 2010 году. На начало 2012 года USB 3.0 массово не поддерживается запоминающими устройствами и материнскими платами. Однако производители USB-накопителей уже начали поставлять на рынок устройства, поддерживающие USB 3.0. Также имеются платы расширения, добавляющие поддержку USB 3.0 в старых компьютерах.
Основные сведения
Кабель USB состоит из 4 медных проводников — 2 проводника питания и 2 проводника данных в витой паре — и заземленной оплётки (экрана).
Кабели USB ориентированы, то есть имеют физически разные наконечники «к устройству» и «к хосту». Возможна реализация USB устройства без кабеля, со встроенным в корпус наконечником «к хосту». Возможно и неразъёмное встраивание кабеля в устройство, как в мышь (стандарт запрещает это для устройств full и high speed, но производители его нарушают). Существуют (хотя и запрещены стандартом) и пассивные USB удлинители, имеющие разъёмы «от хоста» и «к хосту».
С помощью кабелей формируется интерфейс между USB-устройствами и USB-хостом. В качестве хоста выступает программно-управляемый USB-контроллер, который обеспечивает функциональность всего интерфейса. Контроллер, как правило, интегрирован в микросхему южного моста, хотя может быть исполнен и в отдельном корпусе. Соединение контроллера с внешними устройствами происходит через USB-концентратор (другие названия — хаб, разветвитель). В силу того, что USB-шина имеет древовидную топологию, концентратор самого верхнего уровня называется корневым (root hub). Он встроен в USB-контроллер и является его неотъемлемой частью.
Для подключения внешних устройств к USB-концентратору в нем предусмотрены порты, заканчивающиеся разъёмами. К разъёмам с помощью кабельного хозяйства могут подключаться USB-устройства, либо USB-хабы нижних уровней. Такие хабы — активные электронные устройства (пассивных не бывает), обслуживающие несколько собственных USB-портов. С помощью USB-концентраторов допускается до пяти уровней каскадирования, не считая корневого. USB-интерфейс позволяет соединить между собой и два компьютера, но это требует наличия специальной электроники, эмулирующей Ethernet-адаптер с драйверной поддержкой с обеих сторон.
Устройства могут быть запитаны от шины, но могут и требовать внешний источник питания. По умолчанию устройствам гарантируется ток до 100 мА, а после согласования с хост-контроллером — до 500 мА. Поддерживается и дежурный режим для устройств и разветвителей по команде с шины со снятием основного питания при сохранении дежурного питания и включением по команде с шины.
USB поддерживает «горячее» подключение и отключение устройств. Это достигнуто увеличенной длиной заземляющего контакта разъёма по отношению к сигнальным. При подключении разъёма USB первыми замыкаются заземляющие контакты, потенциалы корпусов двух устройств становятся равны и дальнейшее соединение сигнальных проводников не приводит к перенапряжениям, даже если устройства питаются от разных фаз силовой трёхфазной сети.
На логическом уровне устройство USB поддерживает транзакции приема и передачи данных. Каждый пакет каждой транзакции содержит в себе номер оконечной точки (endpoint) на устройстве. При подключении устройства драйверы в ядре ОС читают с устройства список оконечных точек и создают управляющие структуры данных для общения с каждой оконечной точкой устройства. Совокупность оконечной точки и структур данных в ядре ОС называется каналом (pipe).
Оконечные точки, а значит, и каналы, относятся к одному из 4 классов — поточный (bulk), управляющий (control), изохронный (isoch) и прерывание (interrupt). Низкоскоростные устройства, такие, как мышь, не могут иметь изохронные и поточные каналы.
Управляющий канал предназначен для обмена с устройством короткими пакетами «вопрос-ответ». Любое устройство имеет управляющий канал 0, который позволяет программному обеспечению ОС прочитать краткую информацию об устройстве, в том числе коды производителя и модели, используемые для выбора драйвера, и список других оконечных точек.
Канал прерывания позволяет доставлять короткие пакеты и в том, и в другом направлении, без получения на них ответа/подтверждения, но с гарантией времени доставки — пакет будет доставлен не позже, чем через N миллисекунд. Например, используется в устройствах ввода (клавиатуры/мыши/джойстики).
Изохронный канал позволяет доставлять пакеты без гарантии доставки и без ответов/подтверждений, но с гарантированной скоростью доставки в N пакетов на один период шины (1 КГц у low и full speed, 8 КГц у high speed). Используется для передачи аудио- и видеоинформации.
Поточный канал дает гарантию доставки каждого пакета, поддерживает автоматическую приостановку передачи данных по нежеланию устройства (переполнение или опустошение буфера), но не дает гарантий скорости и задержки доставки. Используется, например, в принтерах и сканерах.
Время шины делится на периоды, в начале периода контроллер передает всей шине пакет «начало периода». Далее в течение периода передаются пакеты прерываний, потом изохронные в требуемом количестве, в оставшееся время в периоде передаются управляющие пакеты и в последнюю очередь поточные.
Активной стороной шины всегда является контроллер, передача пакета данных от устройства к контроллеру реализована как короткий вопрос контроллера и длинный, содержащий данные, ответ устройства. Расписание движения пакетов для каждого периода шины создается совместным усилием аппаратуры контроллера и ПО драйвера, для этого многие контроллеры используют крайне сложный DMA со сложной DMA-программой, формируемой драйвером.
Размер пакета для оконечной точки есть вшитая в таблицу оконечных точек устройства константа, изменению не подлежит. Он выбирается разработчиком устройства из числа тех, что поддерживаются стандартом USB
Версии спецификации
Предварительные версии
USB 1.0
Спецификация выпущена 15 января 1996 года.
USB 1.1
Спецификация выпущена в сентябре 1998 года. Исправлены проблемы и ошибки, обнаруженные в версии 1.0. Первая версия, получившая массовое распространение. 15 мбит/с
USB 2.0
Спецификация выпущена в апреле 2000 года.
USB 2.0 отличается от USB 1.1 введением режима Hi-speed.
Для устройств USB 2.0 регламентировано три режима работы:
Последующие модификации
Последующие модификации к спецификации USB публикуются в рамках Извещений об инженерных изменениях (англ. Engineering Change Notices — ECN). Самые важные из модификаций ECN представлены в наборе спецификаций USB 2.0 (англ. USB 2.0 specification package ), доступном на сайте USB Implementers Forum.
USB OTG
USB OTG (аббр. от On-The-Go) — дальнейшее расширение спецификации USB 2.0, предназначенное для лёгкого соединения периферийных USB-устройств друг с другом без необходимости подключения к ПК. Например, цифровой фотоаппарат можно подключать к фотопринтеру напрямую, если они оба поддерживают стандарт USB OTG. К моделям КПК и коммуникаторов, поддерживающих USB OTG, можно подключать некоторые USB-устройства. Обычно это флэш-накопители, цифровые фотоаппараты, клавиатуры, мыши и другие устройства, не требующие дополнительных драйверов. Этот стандарт возник из-за резко возросшей в последнее время необходимости надёжного соединения различных устройств без использования ПК.
Хотя соединение USB OTG выглядит как одноранговое, на самом деле только создаётся такое ощущение — в действительности устройства «договариваются»: сами определяют, какое из них будет мастер-устройством (хостом), а какое — подчинённым. Одноранговый интерфейс USB существовать не может.
USB Wireless
USB wireless — технология USB (официальная спецификация доступна с мая 2005 года), позволяющая организовать беспроводную связь с высокой скоростью передачи информации (до 480 Мбит/с на расстоянии 3 метра и до 110 Мбит/с на расстоянии 10 метров).
23 июля 2007 года USB Implementers Forum (USB-IF) объявила о сертификации шести первых потребительских продуктов с поддержкой Wireless USB. [2]
USB 3.0
Area SD-PEU3N-2EL (USB 3.0 PCIe card), USB 3.0 хост на базе микросхемы µPD720200 фирмы Renesas
USB 3.0 хаб, демонстрационная плата на базе микросхемы VL810 фирмы VIA
В спецификации USB 3.0 разъёмы и кабели обновлённого стандарта физически и функционально совместимы с USB 2.0, причём для однозначной идентификации разъёмы USB 3.0 принято изготавливать из пластика синего цвета. Кабель USB 2.0 содержит в себе четыре линии — пару для приёма/передачи данных, плюс и ноль питания. В дополнение к ним USB 3.0 добавляет ещё четыре линии связи (две витые пары), в результате чего кабель стал гораздо толще. Hовые контакты в разъёмах USB 3.0 расположены отдельно от старых в другом контактном ряду. Спецификация USB 3.0 повышает максимальную скорость передачи информации до 5 Гбит/с — что на порядок больше 480 Мбит/с, которые может обеспечить USB 2.0. Таким образом, скорость передачи возрастает с 60 Мбайт/с до 600 Мбайт/с и позволяет передать 1 Тб не за 8-10 часов, а за 40-60 минут.
Версия 3.0 отличается не только более высокой скоростью передачи информации, но и увеличенной силой тока с 500 мА до 900 мА. Таким образом, от одного хаба можно подпитывать большее количество устройств либо избавить сами устройства от отдельных блоков питания.
Хост-контроллер USB-3(xHCI) обеспечивает аппаратную поддержку потоков для команд, статусов, входящих и исходящих данных, что дает более полное использование пропускной способности USB-шины. Потоки были добавлены к протоколу USB 3.0 SuperSpeed для поддержки UASP.
Аппаратная поддержка 4 портов USB 3.0 реализована в 3-м поколении процессоров Intel Core чипсетов 7-й серии Ivy Bridge. Apple установила порты USB 3.0 в своих новых MacBook Air и MacBook Pro.
Linux поддерживает USB 3.0, начиная с версии ядра 2.6.31. [7]
В Windows 8 интерфейс USB 3.0 поддерживается без установки дополнительных драйверов.
Кабели и разъёмы USB
Кабели и разъёмы USB 1.x и 2.0
Спецификация 1.0 регламентировала два типа разъёмов: A — на стороне контроллера или концентратора USB и B — на стороне периферийного устройства. Впоследствии были разработаны миниатюрные разъёмы для применения USB в переносных и мобильных устройствах, получившие название Mini-USB. Новая версия миниатюрных разъёмов, называемых Micro-USB, была представлена USB Implementers Forum 4 января 2007 года.
Помогаем компьютеру, если он не смог опознать USB устройство
Бывает, что при подключении USB 3.0 устройства, оно работает в режиме USB 2.0. Этим грешат, в частности, некоторые WiFi адаптеры с интерфейсом USB. Как решить данную проблему и заставить коварный гаджет перейти в скоростной режим USB 3.0, путем внесения изменений системный в реестр, я подробно написал здесь, поэтому повторяться не буду. Единственное, что могу добавить, если в роли «тормоза» выступает не сетевой адаптер, а внешний USB 3.0 диск, идентифицируемый как скази (SCSI) накопитель, попробуйте поковырять его настройки в этой ветке реестра: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class<4d36e97b-e325-11ce-bfc1-08002be10318>\00xx.
реклама
Казалось бы, ну разве может быть что-нибудь еще хуже, чем замедленная работа устройства на порту USB? Еще как может! Новехонькое устройство, воткнутое в USB порт, может не заработать вообще.
Самое удивительное, что на самом деле, это вовсе не страшно. Я как раз на днях столкнулся с подобным случаем, поэтому поделюсь впечатлениями…
Итак, воткнув только что купленный USB гаджет в свободный USB порт своего компьютера, пользователь может получить на экране сообщение:
реклама
Это сообщение свидетельствует о неработоспособности подключенного USB-устройства.
Вынув это устройство, и вставив в тот же USB-порт другое, заведомо исправное USB-устройство (мышь там, или флэшку) – пользователь получает на экран точно такое же сообщение об ошибке, а исправное устройство на порту также не работает.
Через некоторое время вышеприведенное сообщение об ошибке с рабочего стола исчезает, но в диспетчере устройств системы можно лицезреть неприглядную картину:
реклама
Некоторые пользователи, столкнувшись с такой проблемой, склонны впадать в панику, решив, что подключаемое USB устройство неисправно, и его нужно возвращать/менять по гарантии/ремонтировать, плюс «по пути» этот зловредный гаджет еще и «унес на тот свет» как минимум USB-порт на материнской плате, к которому его подключали. На самом деле нет! Все не так грустно, как кажется, и торопиться с выводами тут не стоит.
Справедливости ради уточню, что в очень редких случаях подключаемый USВ девайс действительно может оказаться неисправен. Но вероятность этого крайне низка.
С очень высокой вероятностью и само подключаемое USB устройство, и USB порт на плате исправны и абсолютно рабочие. Так почему же возникла ошибка, целенаправленно убивающая нервные клетки и добавляющая пользователям седых волос?
Причина появления данной ошибки в том, что при быстром последовательном подключении/отключении USB устройства несколько раз подряд в системе происходит сбой USB контроллера. Причина череды подключений/отключений гаджета может быть разной: вы намеренно подключили/отключили устройство несколько раз подряд; у вас просто «дрогнула рука» и при подключении в «расшатанный» порт устройство само быстро переподключилось непроизвольно; наконец вы могли совать штекер USB-кабеля в сильно запыленный USB-порт и скопившаяся в порту грязь (а также возможная коррозия на контактах разъема) привела к быстрому повторному переподключению USB-устройства. В любом случае USB контроллер воспринял этот процесс неадекватно и произошел сбой в его функционировании. Только и всего. Чтобы устранить возникшую проблему зачастую (хотя не всегда) достаточно реинициализировать (отключить и снова включить) соответствующий контроллер в диспетчере задач Windows.
реклама
Но! Обычный пользователь не всегда знает, какой именно контролер нужно реинициализировать. Скажу больше, многие даже не знают, где этот контроллер искать вообще. Поэтому побороть данную проблему лучше универсальным и наиболее надежным методом: нужно перезагрузить компьютер, чтобы произошла аппаратная реинициализация USB контроллера. А лучше выключите компьютер, выньте устройство/шнур из USB порта, очистите штекер и сам разъем USB от грязи, снова плотно вставьте USB устройство или шнур от него в порт на материнской плате и затем включите компьютер.
Учимся работать с USB-устройством и испытываем систему, сделанную на базе контроллера FX3
В двух предыдущих статьях мы сделали USB 3.0 систему на базе контроллера FX3. Пришла пора научиться работать с нею из своих программ для PC. Ну, и попутно понять, насколько получившаяся система пригодна для практического применения. Действительно ли ширины канала хватает на весь поток? И не теряются ли единичные байты из потока? Кто хоть немного поработал тестировщиком, не поверит в то, что если система в принципе работает, значит, работает и в деталях. А я на этой должности проработал лет пять, не меньше, поэтому привык проверять всё на практике. В общем, приступаем.
1 Теория о методах доступа к USB
1.1 Windows
Когда новое, доселе неизвестное системе USB-устройство впервые вставлено в ЭВМ, работающую под управлением Windows, оно отображается в диспетчере устройств с жёлтым знаком вопроса. Это связано с тем, что Windows обязательно нужен драйвер для работы с ним. Давайте я немного порассуждаю про эти драйверы, но не с научной точки зрения, а как инженер, раскрыв чисто практические аспекты, но несколько упростив теорию. Потому что мне не нужно, чтобы все уснули. Мне нужно, чтобы суть была понятна, так что ряд скучных деталей придётся опустить.
1.1.1 Драйверы, работающие на функциональном уровне
Что такое USB-устройство? Это набор конечных точек. Но прикладному программисту, если честно, эти точки не интересны. Давным-давно, ещё в прошлом тысячелетии, когда последовательные порты делались на микросхеме UART16550, под неё был сделан функциональный драйвер для Windows, и все прикладные программисты привыкли работать с абстракциями именно этого драйвера. И с этой привычкой трудно спорить. Представим на минутку, что с переходником USB-COM придётся работать в USB-шном стиле, на уровне конечных точек. Есть идеология CDC: две конечных точки туда-обратно, одна точка статуса в режиме прерываний и определённый набор команд, подаваемых через конечную точку EP0. Это всё описано в стандартах, относящихся к USB.
Всё? Нет, некоторым этого мало! Prolific сделала свой набор команд для точки EP0, не совместимый с CDC. А FTDI – свой. Он не совместим ни с CDC, ни с Prolific. Так что, если бы прикладной программист работал бы с переходниками USB-COM на уровне конечных точек, ему пришлось бы нелегко. К счастью, Prolific и FTDI предоставляют функциональные драйверы для своих чипов, а для CDC функциональный драйвер разработала сама Microsoft и прилагает его в составе Windows. Поэтому прикладной программист понятия не имеет, как работать с конкретным переходником (помню, мы целый NDA лет 15 назад с FTDI подписывали, чтобы получить от них руководство по их командам, причём я сразу же им послал информацию об ошибке в документе, так как пока работали бюрократы, я через дизассемблер всё сам уже успел изучить, так что сразу нашёл несовпадение их описания с моим). На прикладном уровне драйверы всех упомянутых производителей дают интерфейс такой же, как и при работе со старым добрым UART16550.
То же касается и USB-накопителей. Мало кто знает, что физически там две конечных точки. Почти никому не интересно, как там надо гонять пакеты, чтобы посылать команды и данные. Как разруливать ошибки, знает ещё меньше людей. Все работают через драйвер usbstor.sys, предоставляемый Microsoft, который обеспечивает работу точно так же, как и с дисками, подключёнными через локальную шину материнской платы.
Удобно? Однозначно! Но вот мы сделали своё устройство, не совместимое по логике работы ни с каким из стандартных. И что нам теперь, всенепременно писать для него персональный драйвер?
Не обязательно. Если нас устраивает работа на прикладном уровне через конечные точки, то уже имеется целый ряд готовых драйверов, которые позволяют общаться с устройством через них. Некоторые из них мы сейчас и рассмотрим.
1.1.2 CyUSB
С этим драйвером я познакомился раньше других. Было это 12 лет назад. Вот с него и начну рассказ. Правда, скажу лишь вскользь. Фирма Cypress, выпуская замечательные контроллеры FX2LP, просто обязана была сделать драйвер, работающий на уровне конечных точек, чтобы облегчить жизнь своим клиентам. И она его сделала. Кому интересно – ищите по слову CyAPI. Это DLL-ка, предоставляющая ряд функций для прикладного программиста. Я как системщик старался обойтись без DLL, поэтому сделал себе библиотеку, работающую с драйвером на уровне IOCTL запросов.
Главный недостаток данной библиотеки заключается в её лицензионном соглашении. Её можно использовать только с контроллерами Cypress. А чтобы всё было убедительнее, начиная с некоторых версий, драйвер стал просто зависать, если он работает с контроллерами других производителей. По крайней мере, старые версии с AT90USB работали, а более свежие – нет. Поэтому я решил, что не буду пользоваться данным драйвером. Даже написал свой… Но вскоре обнаружился замечательный готовый вариант от Microsoft, и я перешёл на него.
1.1.3 WinUSB
Этот драйвер уходит своими корнями в инфраструктуру UMDF. Когда фирма Microsoft работала над возможностью запускать драйверы на пользовательском уровне защиты, они сделали специальный драйвер-прослойку WinUSB. Но через этот же драйвер можно работать и из обычных прикладных программ, а не только из UMDF-драйверов. Кому интересно – вбейте в поиск WinUSB API. Через эту функциональность можно делать то же самое, что и через CyUSB, но с контроллерами любых производителей.
Сам драйвер входит в состав Windows, поэтому в Win7 его можно было вообще ставить без каких-либо проблем с подписыванием. Можно было создать по инструкции от Microsoft или найти и скачать готовый inf файл, поменять в нём VID/PID на свои и установить. К сожалению, начиная с WIN8, обязательно надо подписывать не только сам драйвер, но и INF файл. Однако никто не мешает поправить VID/PID у устройства на тот, который будет найден. Вот у меня есть вот такой подписанный inf файл.
Раньше таких inf файлов на просторах сети было много. Андроид-телефоны через них подключались. Сейчас надо искать по слову WinUSB.sys внутри. Ну, или «ServiceBinary = %12%\WinUSB.sys».
Я поправил «Прошивку» для FX3 вот так:
И теперь могу собирать варианты хоть под CyUSB, хоть под WinUSB с привязкой к имеющемуся у меня inf файлу. А так — можно перевести ОС в режим, не требующий подписывания драйверов, хоть это и не очень удобно.
1.1.4 Библиотека libusb
Вариант с WinUSB отличный, но не кроссплатформенный. Насколько мне известно, под Linux нет точно такого же API, который предоставляет Microsoft для Windows. Кроссплатформенный вариант – это использование библиотеки libusb. Причём под Windows эта библиотека по умолчанию опирается на всё тот же драйвер WinUSB. Нашли драйвер, накатили его на устройство. Скачали библиотеку, начали через неё работать с этим драйвером. Надо будет – через неё же можно будет работать и под Linux. Замечательно? Да. Особенно если мы разработали полностью своё устройство. Но, увы, я просто обязан указать недостаток данного метода для общего случая.
Когда мы устанавливаем на устройство драйвер WinUSB, мы убираем оригинальный драйвер. В рамках данного блока статей мы теряем возможность общаться с нашим устройством при помощи утилиты ControlCenter. Ну, и я не упоминал в статьях про утилиту Streamer, позволяющую измерять скорость устройства… В общем, ею мы тоже не сможем пользоваться, если заменим штатный драйвер на WinUSB.
В рамках другой задачи мне надо было экспериментировать с аудиоустройствами из своего приложения. При этом я не хотел постигать все тонкости работы с ними. Я хотел только некоторые команды подавать, а чтобы всё остальное за меня делала сама операционка. Но если бы я посадил устройства на WinUSB, ОС бы потеряла контроль над ними и не могла бы оказывать мне всемерное содействие.
Можно ли работать из прикладной программы с устройствами, не пересаживая их на специальный драйвер? В принципе, да (правда, это очень аккуратное утверждение). Давайте я покажу этот метод… Правда, в конце — сильно раскритикую его.
1.1.5 Драйвер UsbDk
Библиотека libusb существует в двух версиях. Версия 0.1 и версия 1.0. Обе версии в настоящее время развиваются, создавая некоторую путаницу. И вот версия 1.0 может работать не только через драйвер WinUSB, но и через драйвер UsbDk. Последний является фильтр-драйвером. Что такое фильтр-драйверы? Вспоминаем детство, сказку о царе Салтане:
Собственно, фильтр-драйвер встаёт на пути IRP-пакетов от прикладной программы к основному драйверу и обратно. IRP — это гонцы, которые бегают туда-сюда. А фильтр-драйвер может их пропустить, не изменяя, а может подменить их содержимое. Он придуман для исправления ошибок, чтобы не менять основной драйвер, а просто немножко подправить пакеты, дабы те не вызывали проблем. Их можно править на прямом и на обратном пути. Но в целом, никто не мешает через этот фильтр-драйвер запустить в основной драйвер запросы от приложения, которое общается именно с фильтром. И UsbDk этим и занимается.
Очень схематично, опустив ряд неважных подробностей, это можно показать так:
Вот тут мы видим, что фильтр-драйвер UsbDK подсел на пути пакетов к нашему устройству (на самом деле, он подсел на пути ко всем USB-устройствам, так как прицепился к драйверу класса USB):
Если при открытии библиотеки libusb 1.0 сказать:
то она будет использовать в качестве основы не WinUSB, а UsbDk. Ура? Не совсем. Приведу минимум две проблемы, создаваемые при использовании данного пути.
Первая проблема организационная. Если мы запустили программу, поработали, вышли, то всё будет хорошо. Но вот мы запустили программу, начали работать, а потом почему-то прервались. Да хоть у меня стояла точка останова, исполнение прервалось, я осмотрел переменные, увидел, что программа работает неверно, и завершил её. Могу я так сделать? Дело-то житейское при разработке программы. Или просто зациклилась она. В общем, мы её прервали. Снова запускаем – устройство уже не открывается. Смотрим код ошибки – он очень интересный.
И всё. Выдёргивать-вставлять USB-кабель – бесполезно. Только полная перезагрузка Windows спасёт Отца Русской Демократии. Когда перезапускаешься третий-четвёртый раз за час – это начинает несколько раздражать. Поиск в сети не дал никаких результатов. Попытка бегло осмотреть исходники UsbDk – тоже, а на детальные разбирательства нет времени. Может, кто в комментариях чего подскажет…
Но на самом деле, эта проблема раздражает, но не является фатальной. Вторая проблема более серьёзная. Вот я поставил VirtualBox. Я просто запустил виртуальную машину и хочу подключить к ней, скажем, бластер. И что получаю?
Аналогично – любое другое устройство.
Поиск по сети даёт много вариантов типа: «У меня всё заработало после того, как я потёр заячьей лапкой по бубну из кожи тушканчика, спрыснутому кровью семидесятидвухлетней девственницы, полученной…» … Что там дальше в рецепте — сейчас уже не помню… Тем более, мне он не помог… Более осмысленные рекомендации требуют сносить фильтр-драйверы USB, пока не полегчает. Проблема уходит, когда сносишь именно UsbDK. Ну, значится, так тому и быть. Хотя для экспериментов с аудио, других приемлемых вариантов я не нашёл. Так что драйвер я снёс, но дистрибутив – оставил. Пригодится. Именно поэтому описываю эту методику. Ну, и вдруг кто в комментариях подскажет, как обходить эти две проблемы. Тогда станет совсем здорово.
Итого, сегодня мы будем работать через библиотеку libusb, посадив устройство на драйвер WinUSB. Да, мы потеряем возможность работать с устройством через стандартные приложения от Cypress. Зато всё будет стабильно и хорошо.
1.2 Linux
1.2.1 Драйвер
Я уже много раз писал, что не очень сильно разбираюсь в уходе за пингвинами, поэтому просто перескажу слова своего начальника, опрошенного специально для написания данной статьи.
Некоторые устройства уже поддержаны в Линуксе по классу, либо по VID/PID. Вот, скажем, я подключил макетную плату ICE40 с ПЛИС Latice и подал сначала команду lsusb, чтобы увидеть USB устройства, а затем – уже полюбившуюся нам по прошлым статьям команду:
ls –l /dev/serial/by-path, чтобы увидеть, что мост фирмы FTDI сам прикинулся двумя последовательными портами.
С такими устройствами, если ничего не предпринимать, можно работать только на функциональном уровне. Однако, если функциональный драйвер не подключился, как уверяет начальник, в отличие от Windows такие устройства не станут неизвестными (а потому недоступными). Напротив, с ними можно сразу и без какой-либо подготовки работать через библиотеку libusb. А разработанное нами устройство относится к таковым. Поэтому никакой подготовки для начала работы не требуется. Надеюсь, начальник меня не обманул.
Правда, есть чисто организационная подготовка, которую мы вынесем в собственный раздел.
1.2.2 Отключение требований прав администратора при работе с USB-устройствами
Главная особенность USB-устройств в Linux состоит в том, что по умолчанию для доступа к ним надо обладать правами администратора. То есть, для сборки «прошивки» для ПЛИС ICE40 (к теме статьи они не относятся, но по проекту я сейчас их осваиваю, причём под Linux, так что скриншоты готовить проще для них) мне достаточно набрать make, а вот если для «прошивки» я наберу make prog, то получу такое сообщение:
Не хватает прав. Надо набирать sudo make prog.
Чтобы понизить требуемые права, надо прописать правила. А чтобы быстро выяснить, как их прописать, я обычно даю такой запрос Гуглю:
Ссылок будет много, все они разной степени шаманства. Вот более-менее подробная ссылка:
Using USB Blaster / USB Blaster II under Linux | Documentation | RocketBoards.org
Вообще, мне стало интересно, и я вбил в Гугля строку поиска
/etc/udev/rules.d/
Он нашёл мне много статей про udev. Некоторые более теоретические. Некоторые слишком практические. Пересказывать их не вижу смысла. При желании вы можете погуглить сами. Дам только ссылку на статью, которая мне кажется хорошо сбалансированной по теории и практике:
Igorka: Знакомство с udev в ubuntu
Итак. Иду в каталог /etc/udev/rules.d. Вижу файл 70-snap.snapd.rules, в котором есть правило, относящееся ко всем FTDI чипам:
FTDI-based serial adapters:
Не понимая до конца, что творю, запускаю не просто mc, а sudo mc и в его редакторе создаю файл /etc/udev/rules.d /71-ice40.rules со следующим содержимым:
Закрываю терминал с админскими правами, открываю новый, с правами обычными. Отключаю-включаю устройство, и… Вуаля! Оно уже доступно без прав администратора!
Поэтому можете просто повторить мои шаманства, можете – почитать теорию по ссылкам, после чего у вас всё получится уже с пониманием физики процесса. А так – в рамках данной статьи я буду работать только через Windows, но через кроссплатформенную библиотеку libusb версии 1.0 (не путать с 0.1). Поэтому в Линуксе прописывать правила для устройства FX3 не буду.
2 Практика
Ох, и огромный сегодня получился теоретический раздел! Но наконец, мы владеем достаточным количеством знаний, чтобы приступить к опытам. Напомню, я буду работать в ОС Windows, пользуясь библиотекой libusb 1.0, опираясь на драйвер WinUSB. Я сейчас осваиваю работу с кроссплатформенной библиотекой Qt, поэтому буду разрабатывать код под неё.
2.1 Добавляем libusb в проект
Я скачал библиотеку libusb и распаковал её в каталог своего проекта. Чтобы подключить её к проекту, в файл *.pro пришлось добавить блок:
2.2 Класс для доступа к библиотеке
Обычно примеры для статей я пишу в слитном стиле. Но сегодняшний код получился несколько запутанным, поэтому пришлось вынести работу с платой FX3 в примитивный класс. Вот его интерфейсная часть:
По функциям мы ещё пройдёмся, а пока я отмечу то, что у класса есть переменная-член, хранящая указатель на контекст, который будет нужен для вызова некоторых функций тонкой настройки библиотеки, и манипулятор (в простонародии — хэндл) устройства, необходимый для обращения к устройству.
В конструкторе происходит инициализация и тонкая настройка библиотеки:
Как видим, возможна работа библиотеки через драйвер CyUSB и фильтр UsbDk, но сейчас она отключена. И мы включаем расширенную диагностику работы библиотеки. Все сообщения о проблемах будут сыпаться в окно отладочного вывода. Помните, я показывал сообщение об ошибке при работе UsbDk? Без этой опции никто бы ничего не узнал. Ошибка и ошибка.
Деструктор, соответственно, всё деинициализирует. Класс тестовый, заботиться о наличии дополнительных пользователей библиотекой нет смысла. Так что просто деинициализируем и всё.
Подключение к устройству интересно лишь тем, что может работать по разным парам VID/PID. Как я уже говорил, я могу собирать «прошивку» под штатные VID/PID от Cypress, если идёт работа через UsbDk, и под те, на которые у меня нашёлся inf-файл, устанавливающий драйвер WinUSB. В остальном, ничем не примечательные типовые вызовы функции библиотеки libusb:
Ну, и отключаемся от устройства тоже типовым методом:
Собственно, всё. Функцию чтения из устройства я буду вызывать напрямую. Это противоречит принципам проектирования классов, но для опытов сойдёт. Я просто заметил, что код инициализации сильно разросся и отделил его от основного кода, вынеся в класс. А чтение — оно в одну строку выполняется, его отделять было не нужно.
2.3 Тестовая программа
Программа состоит из функции main() и тестовой функции.
Тестовая функция делится на две части. Первая часть измеряет скорость передачи данных. Вторая — проверяет то, что данные из счётчика приходят с инкрементом. При обнаружении разрыва – сведения об этом выдаются в консоль отладочного вывода. Собственно, вот текст функции:
В будущем я планирую вызывать эту функцию многократно, но пока — функция main() вызывает её один раз:
Собственно, и вся программа.
2.4 Результат тестового прогона
2.4.1 Скорость
При тестовом прогоне мы видим, что скорость близка к требуемой. Напомню, что источник гонит 16-битные данные на скорости 60 МГц, так что нам требуется поток 120 миллионов байт в секунду. Когда на временных диаграммах наблюдался огромный дефицит колбасы, скорость была всего 30 Мегабайт в секунду. Даже меньше, чем практически достижимая скорость на шине USB 2.0. Так что текущие результаты вполне приемлемые.
Правда, чтобы окончательно успокоиться, я решил немного поэкспериментировать со скоростью. Чаще всего она была равна 119 0XX XXX байт в секунду. Изредка – 119 4XX XXX. Ну, и совсем редко – промежуточные значения, похожие на указанные выше. Сначала я решил, что это могут быть ошибки округления. У нас идёт округление показаний таймера, и возникают округления при делении. Тогда я переписал вычисление скорости так (перешёл на наносекунды и стал умножать перед делением, чтобы минимизировать ошибку округления):
Результат ничуть не изменился. Следующее подозрение было, что источник имеет некоторую ошибку кварцевого резонатора и шлёт данные чуть медленнее, чем надо. Но другая плата даёт точно такие же показания! Значит, дело не в экземпляре. Мало того, осциллограф (правда, весьма дешёвый китайский) говорит, что тактовая частота нисколько не занижена, даже чуть завышена.
Тогда я полез в исходники библиотеки libusb и просто-таки утонул в коде, который исполняется при ожидании конца передачи данных. Там такая цепочка функций – просто закачаешься! И много, где может возникать задержка. Но давайте прикинем, какова задержка.
120 мегабайт в секунду… Округлим до ста. Это 1 мегабайт в 10 миллисекунд. А у нас просадка как раз на 1 мегабайт. Неужели начало и конец прокачки съедают так много времени? Как бы проверить хотя бы начерно? Я решил переписать на пробу код под прямой вызов WinUSB API. Полностью объяснять я его не стану, там устройство открывается хитро, через SetupDi API. Я просто воспользовался готовыми своими старыми классами, поэтому всё было сделано под Visual Studio. Но вместо страшных километровых текстов ожидания завершения библиотеки WinUSB, моя функция чтения выглядит вполне канонически:
А тест теперь выглядит так:
Теперь скорость стабильно находится в районе 119 2XX XXX байт в секунду. Вот какой красивый результат я подловил для красного словца:
А вот результат нескольких прогонов подряд:
В общем, никто не запрещает просадке возникать и на входе-выходе в функцию чтения. Если разрывов в показаниях счётчика не будет, то и ладно.
2.4.2 Пропуски в показаниях счётчика
Но на тему разрывов у нас тоже имеется пара строк в выводе основной тестовой программы:
Имеется два нарушения последовательности счёта. Неужели мы нарвались на выпадение данных? К счастью, всё в порядке. Множественные прогоны говорят, что проблемы всегда в одном и том же месте. И мы с таким уже сталкивались в одной из старых статей. У нас есть две точки буферизации данных: буфер контроллера и FIFO в ПЛИС. Готовы ли мы принимать данные или нет, они с выхода счётчика будут заливаться в буфер FX3. Когда тот переполнится, заливка остановится. Кроме буфера FX3, есть ещё FIFO в ПЛИС. Вот у нас и имеется две ёмкости, которые заполнились, но счётчик продолжил работу. При чтении мы увидели разрывы в счёте.
Соответственно, мы наблюдаем явление переходных процессов. При реальной работе надо будет настроить источник так, чтобы он не заполнял буфер данными, пока мы не готовы их принимать (собственно, в статье про голову USB-Анализатора мы уже делали такую функцию через добавление бита «Go»), а пока – просто будем игнорировать ошибки в этой области. Считаем, что это – не баги, а фичи. Меняем проверку разрывов на такую:
Делаем массовый прогон для такого варианта… И тут я понял, кто даёт задержку… Отладочный вывод. Вот так всё выглядит:
Масса вспомогательных текстов, выдаваемых библиотекой. Ну и отлично. Закомментируем в конструкторе класса, обслуживающего libusb, строку:
// libusb_set_option(m_ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_DEBUG);
Получаем красоту, ничем не отличимую от того, что мы получали при прямом вызове WinUSB API (жаль только, что не идеальный результат):
Но главное – нет сообщений про разрывы в показаниях счётчика (известные точки разрывов мы игнорируем).
А что там нам про таймауты промежуточные говорили? Попробуем читать не 128, а 32 мегабайта! Получаем уже скорость вплоть до 119 8XX XXX мегабайт в секунду!
В общем, всё хорошо… Кроме одного. Я нашёл такой нестандартный вариант теста, при котором штатная «прошивка» FX3 подвисает. Но статья получилась такой большой, что как это найти, а главное – как исправить, я расскажу в следующий раз.