Наш магазин на eBay Наш канал в telegram

Интерфейс USB. Часть 2. Как происходит передача данных по шине

Собственно говоря, про то, как происходит передача данных мы уже начали говорить ещё в прошлой статье (помните, мы обсуждали конечные точки, коммуникационные каналы и прочее), просто здесь мы обсудим это более детально и обстоятельно.

Итак, пусть мы хотим из клиентского ПО отправить какие-то данные к конечной точке нашего девайса. Мы посылаем IRP к каналу, который USBD установил с нашей точкой и сообщаем адрес буфера, где лежат данные, которые нам нужно отправить, и размер пересылаемого блока данных. Что происходит с этими данными дальше?

А дальше с ними начинает работать USBD.

Он нарезает наш блок данных на кусочки, которые можно передать за одну транзакцию и, в соответствии с приоритетом выбранного нами для данной конечной точки типа передачи, для каждого кусочка планирует, когда он может его отправить (т.е. планирует транзакции). Далее, в запланированное время он эти кусочки посылает конечной точке. И таким образом всю нашу посылку получит конечная точка.

Здесь у нас всплыл термин «транзакции», поэтому поясню, что это такое. Транзакция — это один сеанс связи с устройством. Поскольку к шине у нас подключено много устройств, то хост физически не может постоянно и одновременно обмениваться данными со всеми этими устройствами. Вместо этого он организует циклы (фреймы, кадры) в каждом из которых осуществляет несколько сеансов связи с различными устройствами. Вот эти сеансы связи и называются транзакциями.

Кадры и транзакции на шине USB

Кадры следуют друг за другом с периодичностью 1 кадр в мс. Ещё раз замечу, что в одном кадре не обязательно должны присутствовать сеансы связи со всеми устройствами на шине или сразу все кусочки информации, предназначенные для одного устройства. Расписание транзакций планируется USBD с учётом приоритета выбранных типов передач и с какими-то конечными точками хост может не осуществлять транзакций несколько фреймов подряд, даже при наличии запроса на обмен данными с этими точками (помните, мы в первой части обсуждали, что принтер может и подождать, а вот передача музыки в USB колонки ждать никак не может). Образно кадры и транзакции показаны на рисунке справа, подробнее их структуру мы рассмотрим позднее.

Вот теперь, с учётом новой информации, мы можем снова вернуться к типам передач и пропускной способности канала. Что для изохронных передач означает способность занять 90% пропускной способности канала. Это значит, что в каждом кадре 90% времени может быть отведено для транзакций этого типа передач. Аналогично, 10% пропускной способности канала, гарантированных для управляющих передач, означают, что в каждом кадре 10% времени гарантированно могут занять транзакции управляющих передач.

Далее ещё раз внимательно посмотрите на рисунок выше. На рисунке я не случайно выделил небольшие интервалы в начале и в конце каждого кадра. В реальности, в начале и конце каждого кадра тоже выделяются небольшие интервалы времени, которые используются специальным образом.

Начало каждого кадра помечается посылкой специального маркер-пакета SOF (start of frame), в состав которого входят 11 младших бит номера кадра. Этот маркер-пакет используется для синхронизации изохронных точек и хабов. В режиме HS каждый кадр делится на 8 микрокадров по 125 мкс, каждый из которых начинается с посылки маркер-пакета SOF (при этом в SOF всех микрокадров, относящихся к одному кадру, передаётся одинаковый номер).

Интервал времени в конце каждого кадра называется EOF. EOF — это время тишины. До наступления этого времени должны быть завершены все транзакции. Если в это время хаб обнаружит, что в какой-то нисходящий порт ему сыпят данные, то он этот порт просто отключит и сообщит об этом хосту.

Теперь вернёмся к транзакциям и разберём более подробно, что же происходит во время сеанса связи с конечной точкой и из чего состоят транзакции.

Сразу отвечу на второй поставленный нами вопрос — транзакции состоят из пакетов. Если помните, мы уже говорили, что любые сеансы обмена данными могут начинаться только по инициативе хоста. Так вот, любая транзакция начинается хостом. И начинается она с отправки маркер-пакета транзакции, в котором указывается адрес устройства, адрес конечной точки, с которой хост хочет «пообщаться», а также направление передачи данных. Получив такой пакет, адресуемое устройство готовится к обмену. Далее, после небольшого таймаута, следует пакет данных от источника (источник определяется направлением, указанным в маркер-пакете). Для изохронных передач транзакция на этом заканчивается (поскольку им не нужно никаких подтверждений доставки данных). Для всех остальных типов передач в транзакцию входит ещё третий пакет — пакет подтверждения или пакет квитирования (handshake). Для наглядности структура транзакций показана на рисунке ниже.

Структура транзакций на шине USB
Структура пакетов шины USB

Далее подробнее поговорим про пакеты. Всего существует 4 типа пакетов: маркер-пакеты (token), пакеты данных (data), пакеты подтверждения (handshake) и специальные пакеты (special). Эти пакеты имеют строго определённую структуру, которая зависит от типа пакета, хотя у всех типов пакетов можно выделить и некоторые общие поля. Общая структура пакетов показана на рисунке справа (для скоростей передачи LS/HS). Пакет можно условно разделить на заголовок (2 байта), имеющий общую для всех пакетов структуру (Sync+PID+Check), и тело, защищённое контрольной суммой. Наличие, размер и структура тела, а также количество бит контрольной суммы зависят от типа пакета.

Итак, любой пакет на LS/FS начинается с 8 бит синхронизации — поле Sync. Для синхронизации используется битовая последовательность b’10000000′. (Для HS длина поля синхронизации составляет 32 бита.)

Далее следует 4 бита идентификатора пакета — PID и его инверсная копия — Check. PID определяет назначение пакета и, соответственно, его последующую структуру. В таблице ниже представлено небольшое описание различных идентификаторов пакетов шины USB.

Имя PID Описание
Идентификаторы маркер-пакетов:
SOF 0101 Идентификатор маркер-пакета начала кадра. Пакет с таким PID содержит в теле 11 младших бит номера кадра, защищённых контрольной суммой CRC5.
SETUP 1101 Идентификатор маркер-пакета транзакции управления. Пакет с таким PID содержит в теле семибитный адрес устройства, четырёхбитный номер конечной точки, с которой хост хочет «пообщаться», и контрольную сумму CRC5.
OUT 0001 Идентификатор маркер-пакета транзакции вывода. Пакет с таким PID содержит в теле семибитный адрес устройства, четырёхбитный номер конечной точки, которой хост будет слать данные, и контрольную сумму CRC5.
IN 1001 Идентификатор маркер-пакета транзакции ввода. Пакет с таким PID содержит в теле семибитный адрес устройства, четырёхбитный номер конечной точки, откуда хост будет получать данные, и контрольную сумму CRC5.
Идентификаторы пакетов данных:
Data0 0011 Идентификатор пакета данных. Пакет с таким PID содержит в теле n байт данных, защищённых контрольной суммой CRC16.
Data1 1011 Идентификатор пакета данных. Пакет с таким PID содержит в теле n байт данных, защищённых контрольной суммой CRC16.
Data2 0111 Идентификаторы дополнительных типов пакетов, используемых в транзакциях с широкополосными изохронными точками (для HS в USB2.0)
MData 1111
Идентификаторы пакетов подтверждения:
ACK 0010 Пакет с таким PID состоит только из заголовка (тело пакета пустое — никаких данных и контрольной суммы нет) и используется для подтверждения безошибочного приёма пакета данных.
NAK 1010 Пакет с таким PID состоит только из заголовка и используется для сообщения хосту о неготовности конечной точки к обмену данными (индикация занятости).
STALL 1110 Пакет с таким PID состоит только из заголовка и используется для сообщения хосту о необходимости его вмешательства для разрешения проблемы.
NYET 0110 Пакет с таким PID состоит только из заголовка и используется для подтверждения безошибочного приёма и сообщения об отсутствии места для приёма следующего пакета максимального размера (в USB2.0)
Идентификаторы специальных пакетов:
PING 0100 Пакет с таким PID является пробным маркером управления потоком (USB2.0). Таким маркером хост как бы предварительно спрашивает устройство, готово ли оно принимать данные, вместо того, чтобы сразу эти данные послать (потому что, если устройство не готово и пришлёт NAK, то всю отправку данных придётся повторять заново).

Остальные специальные пакеты не будем рассматривать, поскольку они нам пока не понадобятся.

Идём дальше. Во всех полях пакетов, кроме поля CRC, данные передаются младшим битом вперёд.

Все пакеты состоят из целого числа байт (разрядность полей, входящих в пакет, специально так подобрана, чтобы сумма разрядов всех этих полей была кратна восьми).

Все пакеты заканчиваются специальным сигналом EOP, для LS/FS этот сигнал длится 2 битовых интервала (позже, когда дойдём до физики, мы рассмотрим, как формируется этот сигнал), для HS — таким специальным сигналом является передача определённой последовательности бит.

Передаваемые по шине данные кодируются по методу NRZI с техникой вставки бит (bit stuffing). Расшифруем что это значит. Это значит, что при передаче нулевого бита состояние сигнала на шине меняется на противоположное, а при перередаче единицы — состояние сигнала не меняется. Вставка бит используется для того, чтобы не потерять синхронизацию при монотонном единичном сигнале. Суть этой вставки сводится к тому, что после каждых 6 подряд единиц в передаваемые данные вставляется нулевой бит, независимо от того, какое значение имеет бит, следующий за этой группой единиц. (чтобы использовать NRZI и технику bit staffing — придётся разработать специальную процедурку для перекодирования передаваемых и принимаемых данных.)

Кроме того, нам нужно уметь вычислять CRC5 и CRC16. Вычисление CRC вообще отдельная тема, про неё подробно написано тут. А вот тут можно найти специальные процедурки для вычисления наших CRC5 и CRC16.

Теперь поговорим про интервал ожидания (помните, на рисунке со структурой транзакций, между пакетами нарисованы небольшие интервалы). Вот давайте поговорим, откуда они и зачем. Как все мы понимаем, сигнал не может дойти от источника до приёмника мгновенно. Во-первых, задержку вносят кабели, во-вторых, задержку вносят хабы (они, как мы помним, должны принять сигнал от источника и ретранслировать его приёмнику), в-третьих, нужно учитывать, что хабов в цепочке от хоста до устройства может быть несколько, ну и наконец, нужно понимать, что приёмник должен иметь некоторое время, чтобы «осмыслить» принятый пакет, решить есть ли в нём ошибки, кому он предназначен и т.д.

Таким образом, ответный пакет источник не может получить мгновенно, потому что приёмнику нужно время чтобы «подумать» над ответом, и всей этой транспортной сети нужно время чтобы «доставить» ответ. С другой стороны, ответ нельзя ждать бесконечно долго, вдруг он вообще не придёт.

Поэтому в устройствах USB нормируется, во-первых, «максимальное время оборота по шине» — это время, за которое данные должны добежать до приёмника и вернуться назад к источнику в самом худшем случае — при прохождении последовательно через 5 хабов (время на то, чтобы «доставить»), и, во-вторых, «максимальная задержка ответа» — максимальное время от конца увиденного EOP до начала передачи ответного пакета (время на то, чтобы «подумать»). В устройствах при ожидании пакета запускаются специальные таймеры, которые отсчитывают интервал, достаточный для формирования ответа и его доставки, и если ответ за это время не получен — это воспринимается как ошибка.

Для FS интервал ожидания составляет 16-18 битовых интервалов, для HS — 736-816 битовых интервалов. Максимальное время, за которое мы должны всё обдумать и начать посылать ответ, составляет 7,5 битовых интервалов на FS и 192 битовых интервала для HS.

Ну и раз уж мы заговорили про битовые интервалы, то следует сказать, что длительность битового интервала для скорости LS составляет примерно 667 нс (1,5 Мбит/с), для FS примерно 83 нс, для HS примерно 2 нс.

Ещё один интересный вопрос. Зачем придумали аж целых 4 идентификатора пакетов данных? Сделали это вот почему. При передачах типа bulk (массивы), control (управляющие) и interrupt (прерывания) приёмник после получения пакета данных должен послать назад к источнику пакет подтверждения. Этот пакет подтверждения (так же, как и сам пакет данных) может испортиться. А если источник не получит подтверждения успешной передачи пакета данных, то в следующей транзакции он повторит отправку отправку этого пакета. Чтобы приёмник понял, что он эти данные уже получал, пакеты данных посылают с чередующимся PID. Чётные пакеты посылают с PID Data0, а нечётные — с PID Data1. Таким образом, получив два раза пакет данных с одним и тем же PID, приёмник понимает, что это не какие-то новые данные, а просто повторная отправка предыдущего пакета, потому что источник в предыдущей транзакции не увидел пакет подтверждения. Специальный бит в конечной точке, который указывает, пакет данных с каким PID мы ждём, называется Toggle Bit.

Ладно, с Data0, Data1 всё ясно, а для чего нужны PID Data2 и MData? Да примерно для того же самого. Они позволяют различить пакеты данных внутри микрокадра для широкополосных изохронных точек (USB2.0).

Ну, на этом пожалуй хватит про всякие транзакции и пакеты (если что — потом допишем), перейдём теперь к самому низкому уровню реализации — к физике.

С точки зрения физики в USB всё достаточно просто. Для связи по USB используются 4 провода: +5В, D+, D- и GND. Эти провода имеют стандартную цветовую маркировку: красный провод — это +5В, чёрный — GND, зелёный — D+, белый — D-.

Для передачи битов используется дифференциальный сигнал между проводами D+ и D-. Провода +5В и GND используются для питания устройства, а так же для индикации некоторых специальных состояний (вместе с D+ и D-).

На линиях D+ и D- высокий уровень соответствует напряжению +3,3 В (от 2,7 до 3,6).

Дифференциальный сигнал, при котором разница между D+ и D- больше 200 мВ при уровне напряжения на линии D+ > 2В называется Diff1.

Дифференциальный сигнал, при котором разница между D- и D+ больше 200 мВ при уровне напряжения на линии D- > 2В называется Diff0.

Состояние, когда на обоих сигнальных линиях присутствует низкий уровень относительно GND (D+<0,8В и D-<0,8В) называется SE0 (single-ended zero).

Для идентификации скорости работы устройства используется резистор на 1,5 кОм, подтягивающий одну из сигнальных линий к высокому сигнальному уровню (+3,3В). Для LS-устройств подтягивается линия D-, для FS/HS-устройств подтягивается линия D+.

Сигналы Diff0 и Diff1 кодируют состояния шины, которые называются J (data J state) и K (data K state). Для LS состояние J соответствует сигналу Diff0, а состояние K — сигналу Diff1. Для FS/HS наоборот — J соответствует сигналу Diff1, K — сигналу Diff0.

Состояние покоя шины (bus idle) для LS/FS соответствует длительному состоянию J, а для HS — состоянию SE0.

Признаком начала передачи является переход из состояния покоя в состояние K. Поскольку первым всегда передаётся нулевой бит (любая передача начинается с передачи синхропоследовательности), то это первоначальное состояние K соответствует нулевому биту, дальнейшее значение передаваемых битов определяется в соответствии с NRZI кодированием.

Для обозначения конца пакета (EOP) на LS/FS используется сигнал SE0, длительностью 2 битовых интервала. На HS сигналом EOP служит передача специальной последовательности b’11111110′ (младшим битом вперёд, не используя технику bit stuffing). Приёмник отслеживает нарушение техники вставки бит (сигнал на шине не изменяется течении семи битовых интервалов) и считает это признаком конца пакета.

На этом пока всё, дальше мы рассмотрим, какие стандартные действия должно уметь делать любое USB-устройство, какую информацию содержать, как и на какие запросы отвечать.

  1. Часть 1. Основы.
  2. Часть 2. Как происходит передача данных по шине.
  3. Часть 3. Что должно уметь любое USB-устройство.
  4. Часть 4. Дескрипторы и классы.
  5. Часть 5. Программная реализация low speed устройства USB. Схема.
  6. Часть 6. Программная реализация LS устройства USB. Физика и приём пакетов.
  7. Часть 7. Программная реализация LS устройства USB. Разбираем пакеты по типам.
  8. Часть 8. Программная реализация LS устройства USB. Передача по USB произвольного буфера и пакетов подтверждения.
  9. Часть 9. Программная реализация LS устройства USB. Продолжаем разбираться с принятыми пакетами.

Добавить комментарий