МАРСОХОД

Open Source Hardware Project

Поговорим о USB.

Я не буду говорить ни о USB2 ни тем более о USB3. Это для меня в пока основном «высокие материи». Давайте поговорим о старом добром USB1.1.
И пожалуйста не смейтесь. На самом деле, если Вы поищите в русскоязычном интернете техническую спецификацию на USB1.1 (я уже не говорю про USB2, а в USB3 наверное Intel вообще не публикует деталей), то вряд ли Вы найдете там что нибудь стоящее. В основном у нас можно найти общие сведения и общие фразы. Нас же, как разработчиков аппаратуры интересуют технические детали стандарта и возможность реализации устройств поддерживающих его.
Еще конкретнее вопрос стоит так: сможем ли мы подключить платку Марсоход через USB к компьютеру?


Естественно прежде всего нужно ознакомиться со спецификацией USB1.1. Теоретически нужно посетить сайт www.usb.org и взять там все, что нужно. Однако не все так просто. Взять оттуда скорее всего у Вас просто так не получится. Спецификации они почему-то продают http://www.usb.org/developers/estoreinfo/USB_product_order_form.pdf да и найти нужное в дебрях этого сайта не просто.
Теперь спецификацию на USB1.1 можно взять на нашем сайте!

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

Итак, приступим.
В разъеме USB1.1 всего четыре контакта:

  • Земля (4, обычно черный провод в кабеле);
  • DP (3, обычно зеленый провод в кабеле);
  • DM (2, обычно белый провод в кабеле);
  • +5V (1, обычно красный провод в кабеле).

Таким образом, мы видим всего 2 сигнала для обмена данными между хостом (компьютером) и подключаемым устройством. Эти сигналы DP и DM (иногда их обозначают D+ и D-) – это дифференциальная пара. Сигнал передается по ним в противофазе. Это позволяет на приемном конце бороться с помехами.

Как хост определяет, что подключено новое устройство? Довольно просто. На стороне хоста обе линии DP и DM притянуты к GND через резисторы 15кОм. Контроллер хоста проверяет состояние этих линий. Если на обеих линиях ноль, то это значит, что ничего не подключено. На стороне подключаемого устройства один из сигналов притянут через резистор 1,5кОм к напряжению питания. Таким образом, если устройство подключено, то одна из линий либо DP либо DM поднимается в состояние «единица» и хост контроллер видит, что подключено новое устройство.

Устройства для USB1.1 бывают двух типов: полноскоростные (full speed) и низкоскоростные (low speed). Посмотрите на эти две картинки:
usb_low_speed

usb_full_speed

Таким образом, полноскоростные устройства имеют подтягивающий резистор на +5В для сигнала D+, а низкоскоростные устройства – для сигнала D-.

Частота передачи данных для полноскоростных устройств 12МГц, а для низкоскоростных 1,5МГц. Низкоскоростное устройство принимает и посылает данные до 8 байт длиной. Высокоскоростное устройство может посылать или принимать до 64 байт данных.

Особо следует отметить, что эти две линии D+ и D- служат для передачи данных в обе стороны. Как же разрешаются конфликты на линиях, если оба и хост и подключенное устройство захотят передавать данные? Такая ситуация не должна случаться в принципе. Дело в том, что передача полностью управляется хост контроллером компьютера. Если хост контроллера должен прочитать данные с устройства, то он посылает соответствующую команду и переключается в режим приема, а затем ждет пакета от подключенного устройства.

Хост контроллер компьютера ведет опрос подключенных устройств каждую миллисекунду – этот временной промежуток называется фреймом. В начале каждого фрейма хост контроллер посылает специальный SOF (Start Of Frame) пакет для полноскоростных подключенных устройств или SE0 для низкоскоростных устройств.

Если устройство не получает SOF или SE0 некоторое время (несколько фреймов), то это означает, что оно должно уйти в спячку (suspend) и по возможности снизить энергопотребление.

Отдельно нужно обратить внимание на состояние SE0. Это состояние, когда обе линии DP и DM находятся «в нуле». Это состояние используется в 3-х случаях.

Во-первых, после подключения устройства программное обеспечение хоста дает ему команду «сброс» (Reset). Хост опускает обе линии DP и DM в «ноль» на время большее 10мс. Подключенное устройство должно воспринять это действие как общий «сброс».

Во-вторых, как я уже сказал, для низкоскоростных утройств каждый фрейм начинается с состояния SE0 (обе линии DP и DM в нуле) длительностью 2 такта от 1.5МГц.

В-третьих, каждый посланый пакет в любую сторону, от хоста к устройству или наоборот, всегда заканчивается состоянием EOP (End Of Packet), и этот EOP - это тот же самый SE0 – обе линии DP и DM в нуле на протяжении времени 2 бит передачи данных. Для полноскоростных устройств это 2 такта от 12МГц. Для низкоскоростных устройств это 2 такта от 1,5МГц.

Все данные в любую сторону оформлены в виде пакетов. Давайте посмотрим как они выглядят на физическом уровне. Лучше всего изучать по картинкам, а они в спецификации USB1.1 какие-то не очень понятные. Я нарисовал свою картинку.
ls_usb_signals
Здесь видно, что подключено низкоскоростное устройство, так как фрейм начинается с SE0 – по времени 2 бита DP и DM находятся в нуле.

Дальше видно 3 пакета: хост посылает пакет SETUP, посылает пакет DATA0 и получает от устройства пакет ACK. Каждый пакет всегда начинается со специального символа SYN, его значение 0x80. Байт передается младшими битами вперед. Кодировка несколько странная. Каждый нулевой бит кодируется изменением сигнала DP/DM на противоположный. Каждый единичный бит состояние линий не изменяется. Однако есть исключение – если в передаваемом потоке окажется подряд шесть единиц, то состояние линий DP/DM принудительно меняется на противоположный. Этот нулевой бит должен быть удален на приемном конце при приеме пакета. Этот алгоритм называется «bit stuffing». Обратите внимание на завершение пакетов состоянием SE0 – EOP (End Of Packet). Интервал между пакетами должен быть не менее времени 2 бит, на практике обычно больше. Это был физический уровень связи.

Рассмотрим уровень протокола. Здесь все гораздо более запутанно. Без поллитра не разобраться (конечно если Вам больше восемнадцати). Для чего разработчики стандарта сделали все это так сложно я и сам не пойму.

Существуют пакеты нескольких типов. В каждом типе есть под-типы (это мое определение, в спецификации так не говорят).
Итак вот таблица:

Тип пакета Идентификатор пакета PID в шестнадцатеричном виде Описание
Token OUT 0xE1 Используется для передачи адреса устройства и номера канала (endpoint) во время транзакции передачи данных от хоста к уствойству
Token IN 0x69 Используется для передачи адреса устройства и номера канала (endpoint) во время транзакции передачи данных от устройства к хосту
Token SETUP 0x2D Используется для передачи адреса устройства и номера канала (endpoint) во время транзакции передачи данных от хоста к уствойству к специальному управляющему каналу (control pipe)
Token SOF 0xA5 Маркер начала фрейма и номер фрейма
Data DATA0 0xC3 Используется для передачи четного пакета данных
Data DATA1 0x4B Используется для передачи нечетного пакета данных
Handshake ACK 0xD2 Подтверждение о приеме данных
Handshake NAK 0x5A Либо приемник не может принят данных либо передатчик не может послать
Handshake STALL 0x1E Останов endpoint или служебный запрос не поддерживается
Special PRE 0x3C Посылается USB хабу, когда требуется переключить скорость в низкоскоростную

Рассмотрим формат основных пакетов: token, data, handshake.
Не забудьте, что в линии USB пакеты посылаются начиная с символа SYN 0х80, а уж затем вот эти пакеты и завершаются они EOP (2 такта линии DP и DM в нуле).
usb_token_pkt

usb_data_pkt

usb_handshake_pkt

Для token и data еще нужно посчитать контрольные суммы. Их можно считать вот так (написано на языке C):

//функция принимает двухбайтовое слово где адрес и номер канала, считает CRC5 и //вписывает контрольную сумму прямо в нужное место этого слова
USHORT CalcCrc5ForUsbTokenPacket(USHORT a)
{
ULONG  b = 0x1f;
USHORT d = a;
for(int i=0; i<11; i++)
{
    if((d^b)&1)
    {
         b >>= 1;
         b ^= 0x14;
    }
    else
         b >>= 1;
    d >>= 1;
}

b ^= 0xffffffff;
b <<= 11;
a |= b;
return (USHORT)a;
}


//функция принимает указатель на пакет данных (без PID) и длину пакета
//возвращает CRC16

USHORT CalcCrc16ForUsbDataPacket(char *pData, int len)
{
USHORT b = 0xFFFF;
for(int i=0; i<len; i++)
{
     char a = *pData++;
     for(int j=0; j<8; j++)
     {
          if((a^b)&1)
          {
               b >>= 1;
               b ^= 0xa001;
          }
          else
               b >>= 1;
          a >>= 1;
     }
}
b ^= 0xffffffff;
return (USHORT)b;
}

Ну а на последок, чтобы Вы оценили все «прелесть» диалога между хостом (компьютером) и подключенным устройством посмотрите на следующую картинку:
usb_dialog

Это снимок экрана с программы USB Tracker – устройства позволяющего записывать и анализировать весь трафик между хостом и устройством.

На самом деле, сделать что нибудь с USB не имея подобного инструмента практически нереально. У нас он есть и мы попробуем реализовать простую функцию USB в плате Марсоход. А что у нас получится возможно скоро Вы узнаете.

Комментарии  

0 #6 Stress 29.06.2015 12:58
Цитирую nckm:
[quote name="Stress"]Может быть нужно было вообще писать 80 2D 00 10 и 80 C3 80 06 00 01 00 00 40 00 DD 94..

Да, так наверное меньше всего путаницы будет
+1 #5 nckm 29.06.2015 12:44
Цитирую Stress:
Странная у вас картинка с транзакцией (фронты-спады DP/DM). PID пакета данных (DATA0) должен быть 0xC3, а написано 0x06 (80 06 00 01 00 00 40 00 DD 94)

да, похоже ошибка в картинке.
Скорее всего должно быть подписано так: C3 80 06 00 01 00 00 40 00 DD 94 по аналогии с предыдущим пакетом 2D 00 10
Здесь 80 - это не SYN, а уже данные.. Хотя любой пакет начинается с байта SYN. Может быть нужно было вообще писать 80 2D 00 10 и 80 C3 80 06 00 01 00 00 40 00 DD 94..
0 #4 Stress 29.06.2015 11:18
Странная у вас картинка с транзакцией (фронты-спады DP/DM). PID пакета данных (DATA0) должен быть 0xC3, а написано 0x06 (80 06 00 01 00 00 40 00 DD 94)
0 #3 anonymouse 14.05.2012 13:11
программы USB Tracker – устройства
Исправьте
0 #2 Никита 12.05.2012 16:58
Цитирую DOZA:
А где взять USB Tracker ??? :lol:

Походу только купить можно.
0 #1 DOZA 22.07.2011 12:14
А где взять USB Tracker ??? :lol:

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



facebook  GitHub  YouTube  Twitter
Вы здесь: Начало Статьи о разном Поговорим о USB.