Сегодняшняя статья будет посвящена, как уже видно из названия, обсуждению основ интерфейса USB. Рассмотрим основные понятия, структуру данных, разберемся, как происходит передача, а в ближайшем будущем реализуем все это на практике. Приступаем!
Существует ряд различных спецификаций USB. Началось все с USB 1.0 и USB 1.1, затем интерфейс эволюционировал в USB 2.0, относительно недавно (на момент написания статьи) появилась окончательная спецификация USB 3.0. Но на данный момент наиболее распространенной является реализация USB 2.0. И для начала рассмотрим основные характеристики. Интерфейс USB 2.0 поддерживает три режима работы:
- High Speed - до 480 Мб/с
- Full Speed - до 12 Мб/с
- Low Speed - до 1.5 Мб/с
Командует на шине USB хост (например, ПК), к которому можно подключить до 127 различных устройств. Если этого мало, то нужно добавить еще один хост. Причем немаловажно, что устройство не может само послать/принять данные хосту/от хоста, необходимо, чтобы хост сам обратился к устройству.
Почти во всех статьях про интерфейс USB, которые я видел, используется термин "конечная точка", но о том, что это такое обычно написано довольно туманно. Так вот, конечная точка - это часть устройства USB, имеющая свой уникальный идентификатор. Каждое устройство может иметь несколько конечных точек. По большому счету - конечная точка - это всего лишь область памяти USB устройства, в которой могут храниться какие-либо данные (буфер данных). И в итоге мы получаем вот что - каждое устройство имеет свой уникальный адрес на шине USB, и при этом каждая конечная точка этого устройства также имеет свой номер.
Давайте немного отвлечемся и поговорим о "железной части" интерфейса. Существуют два типа коннекторов - Type A и Type B.
Как уже понятно из рисунка Type A всегда обращен к хосту. Именно такие разъемы мы можем наблюдать на ПК. Коннекторы Type B всегда относятся к подключаемым USB-устройствам. Кабель состоит из 4 проводов разных цветов. Ну, собственно, красный - это питание (+5 В), черный - земля, белый и зеленый предназначены для передачи данных.
Несмотря на то, что именно такая цветовая маркировка является наиболее распространенной, тем не менее некоторые производители могут использовать и другие цвета. Более того, у меня был кабель, в котором провода красного и черного цветов были перепутаны, то есть красный шел на землю. Так что, если оперируете непосредственно с внутренностями кабеля, будьте аккуратны и не доверяйте цвету безоговорочно. Лучше прозвонить и перепроверить.
Помимо изображенных на рисунке, существуют также другие варианты исполнения USB-коннекторов, например, mini-USB и другие, тут я думаю секрета никакого не открою.
Пожалуй, стоит коснуться способа передачи данных, но углубляться в это пока не будем. Итак, при передаче данных по шине USB используется принцип кодирования NRZI (без возврата к нулю с инверсией). Для передачи логической "1" необходимо повысить уровень линии D+ выше +2.8 В, а уровень линии D- понизить ниже +0.3 В. Для передачи нуля ситуация противоположная - (D- > 2.8 В) и (D+ < 0.3 В).
Отдельно стоит обсудить питание устройств. И тут также возможно несколько вариантов. Во-первых, устройства могут питаться от шины, тогда их можно разделить на два класса:
- Low-power
- High-power
Разница тут заключается в том, что low-power устройства не могут потреблять больше, чем 100 мА. А устройства high-power должны потреблять не более 100 мА лишь на этапе конфигурации. После того, как они сконфигурированы хостом, их потребление может составлять до 500 мА. Кроме того, устройства могут иметь свой собственный источник питания. В этом случае они могут получать до 100 мА от шины, а все остальное забирать у своего источника.
С этим вроде бы все, так что логичным образом переходим к структуре передаваемых данных. Тем более это представляет для нас наибольший интерес.
Структура данных интерфейса USB.
Вся информация передается кадрами, которые отправляются через равные промежутки времени. В свою очередь каждый кадр состоит из транзакций::
Каждый кадр включает в себя пакет SOF (Start Of Frame), затем следуют транзакции для разных конечных точек, и завершается все это пакетом EOF (End Of Frame). Если говорить совсем точно, то EOF - это не совсем пакет в привычном понимании этого слова - это интервал времени, в течение которого обмен данными запрещен.
Каждая транзакция имеет следующий вид:
Первый пакет (его называют Token-пакет) содержит в себе информацию об адресе устройства USB, а также о номере конечной точки, которой предназначена эта транзакция. Кроме того, в этом пакете хранится информация о типе транзакции (какие бывают типы мы еще обсудим, но чуть позже). Data-пакет - с ним все понятно, это данные, которые передает хост, либо конечная точка (зависит от типа транзакции). Последний пакет - Status - предназначен для проверки успешности получения данных.
Уже очень много раз прозвучало слово "пакет" применительно к интерфейсу USB, так что следует разобраться, что он из себя представляет. Начнем с пакета Token:
Пакеты Token бывают трех типов:
- In
- Out
- Setup
- Start Of Frame
Пакет In сообщает USB-устройству, что хост готов принять от него информацию. Пакет Out, напротив, сигнализирует о готовности и желании хоста поделиться информацией. Пакет Setup нужен для использования управляющих передач. Ну а пакет Start Of Frame используется для того, чтобы инициировать начало кадра.
В зависимости от типа пакета значение поля PID в Token-пакете может принимать следующие значения:
- Token пакет типа OUT - PID = 0001
- Token пакет типа IN - PID = 1001
- Token пакет типа SETUP - PID = 1101
- Token пакет типа SOF - PID = 0101
Кроме того, есть еще один немаловажный нюанс. Поле PID включает в себя 4 бита, но при передаче они дополняются еще 4-мя битами, которые получаются путем инвертирования первых 4-ых.
Переходим к следующей составной части пакета Token - поля Address и Endpoint - в них содержатся адрес USB устройства и номер конечной точки, которой предназначена транзакция. И, наконец, поле CRC - это контрольная сумма, с этим понятно. Она как и обычно используется для контроля целостности и безошибочности данных.
На очереди Data пакет - то есть пакет данных:
Тут все, в принципе, так же, как и в пакете Token, только вместо адреса устройства и номера конечной точки здесь в наличии передаваемые данные. Таким образом, осталось рассмотреть Status пакеты и пакеты SOF, начинаем с первого из них:
Тут PID может принимать всего лишь два значения:
- Пакет принят корректно - PID = 0010
- Ошибка при приеме пакета - PID = 1010
Start Of Frame пакет:
Видим новое поле Frame - оно содержит в себе номер передаваемого кадра. Давайте в качестве примера рассмотрим процесс записи данных в USB-устройство, то есть полную структуру кадра для записи. Кадр, как вы помните состоит из транзакций и имеет следующий вид:
Что представляют из себя все эти транзакции? Сейчас разберемся, транзакция SETUP:
Транзакция OUT:
Аналогично при чтении данных из USB-устройства кадр выглядит так:
Транзакцию SETUP мы уже видели, посмотрим на транзакцию IN:
Как видите, все эти транзакции имеют именно такую структуру, как мы обсуждали выше. В общем, думаю достаточно на сегодня, довольно-таки длинная статья получилась, в ближайшее время обязательно будем использовать данные теоретические аспекты на практике 👍
Ура! Спасибо!
=)
Добрый вечер! Отличная статья, спасибо! У меня вопрос, а почему PID одинаковые?
В зависимости от типа пакета значение поля PID в Token пакете может принимать следующиЕ значения:
Token пакет типа OUT — PID = 0001
...
Token пакет типа SETUP - PID = 0001
Опечатка =) Большое спасибо)
Статьи просто классные! Спасибо!
Возник вопросик по поводу поля SYNC. Что оно из себя представляет не могу найти нигде. Буду очень благодарен за ответ.
Приветствую. Тут было упоминание о CRC.
1) Означает ли это, что если проверка контрольной суммы не пройдет успешно, то устройство, принимающее данные просто их проигнорирует и мы в отладчике увидим отсутствие изменений? Как будто ничего и не приходило. Как тогда организовывать обмен правильно?
2) Каков полином для этого CRC? Но это так, скорее вопрос из любопытства
Вот здесь есть вся информация - http://www.usb.org/developers/docs/whitepapers/crcdes.pdf
Здравствуйте, уважаемый Aveal, я не уверен, но кажется, что в вашей статье есть некоторая неточность. Вы написали: "ну и завершается все это пакетом EOF (End Of Frame).". Но такого пакета не существует, EOF - это просто временная пауза, интервал времени, в течении, которого на линии не должно происходить никаких обменов. Насколько мне известно, крайний интервал времени, когда должна завершиться транзакция, это время между флагами EOF1 и EOF2, которые выставляются за 32(EOF1) и 10(EOF2) битовых интервала, до следующего пакета SOF. Если хост продолжает пихать данные после поднятия флага EOF2, то мк, просто обрубит порт, и как следствие придется предпринимать соответствующие меры.
Добрый вечер!
Спасибо большое за отличное дополнение! )
Замечательная статья
Маленькое, но очень важное уточнение по статье.
High Speed — до 480 МБ/с
Full Speed — до 12 МБ/с
Low Speed — до 1.5 МБ/с
Исправить на "Мб/с", либо "Мбит/с".
А то у вас получается что шина USB 2.0 качает 480 мегабайт в секунду, не многовато ли?
Добрый день!
Благодарю за замечание!
Отличная статья, спасибо! Кажется у Вас опечатка на последней картинке. Первым должен идти token типа in? Или все таки setup?
Благодарю за отличный отзыв и за дополнения!
Да, действительно, опечатка, исправил!
Статьи всегда написаны очень доходчиво, для начинающих то что надо.
Благодарю!