Обновить

Разработка цифровой аппаратуры нетрадиционным методом: Контроллер USB 1.0 на SpinalHDL

Уровень сложностиСредний
Время на прочтение127 мин
Охват и читатели4K
Всего голосов 23: ↑23 и ↓0+30
Комментарии33

Комментарии 33

Автор молодец, Хабр - торт. Большое спасибо! Очень круто!

Такой фундаментальный труд полезно держать под рукой. Отдельно спасибо за pdf

Сохранил в закладки , надо бы выделить месяц на прочтение статьи))) Чувствую что-то шедевральное вы там натворили

Вроде-бы HID'ы имеют обратную совместимость с PS/2.

Честно говоря я не представляю как это возможно. PS/2 это последовательный синхронный интерфейс с побайтовой передачей работающий на частотах 7-12 кГц, у него два сигнала: DATA и CLK, оба имеют TTL уровни +5V. USB 1.0 - это асинхронная шина с пакетной коммутацией, сигналы D+ и D- имеют уровни +3.6V max, частоты: 1.5 и 12 МГц. Как это совместить ?

Тоже программно. Контроллер клавиатуры/мыши определяет, куда его подключили и переопределяет свои выводы в PS/2.
Переходник - 4 провода.

Это не HIDы, а конкретные реализации типа мышек Logitech древних времен.

На Wikipedia в статье про PS/2 написано, что некоторые клавиатуры и мыши, предназначенные для работы в процессе загрузки ОС, могут определить куда они подключены и задействовать две имеющиеся сигнальные линии либо для встроенного USB Device устройства, либо для PS/2. Для этого промышленностью выпускались специальные переходники позволяющие подключить одно и то же устрйство с USB type A разъемом либо в USB type A (HID), либо в круглый PS/2. Но это не совместимость на уровне стандартов, это такой костыль от производителей устройств ввода нацеленный на облегчение перехода пользователей на USB HID.

Есть мышки с клавами, которые умеют и в usb, и в ps/2 аппаратно включаиься. Не пипец как это сложно.

А программно: Если в HID-дескрипторе описать классическое поведение устройств рс/2, то да, можно о какой-то совместимости говорить. Типа ту же последовательность байт при событии слать.

Но - совместимы в каком месте? Для пользователя и программиста под любой ОС они по определению совместимы, хоть они рс/2, хоть usb, хоть rs232, хоть TCP/IP с удалëнной машины .

У USB и PS/2 абслютно разные электрические интерфейсы, это не просто посылка байтов. Никакой совместимости между этими двумя стандартами нет и быть не может. Может быть только общий уровень абстракций, как например в Input Device в Linux который формирует общий поток событий для ПО прикладного уровня.

USB можно даже на AVR микроконтроллерах реализовать программно.
Проект называется V-USB
https://ru.wikipedia.org/wiki/V-USB

Спасибо. Про V-USB мне подсказали на конференции FPGA-Systems уже после моего доклада, не знал. Хочу посмотреть как там вычисляется CRC16 и при этом библиотека успевает вложиться в жесткие тайминги. У меня это сделать не получилось на RV32 ядре 60+ МГц, поэтому пришлось отдать расчет CRC на железную часть.

Я добавил в конце статьи ссылку на презентацию (PDF, 56 слайдов) к моему докладу на эту же тему с которым я выступил на конференции FPGA-Systems 2025 прошедшей 29 ноября 2025 в Москве. Это для тех, кто хочет быстро ознакомиться с содержимым статьи не читая её. :-)

Спасибо за хаброторт! До конца дочитаю, наверное, только в следующем году) Но всякие справочные штуки типа форматов сообщений - и я буду искать здесь, и поисковики, надеюсь, тоже (когда раздуплят свои ИИ. ЫЫ) Давно хотел видеть открытое и понятное описание открытого протокола. Осцилл вот у меня умеет в анализ uart/spi/i2c, но вот usb - как-то не срослось, собственными глазами приходится отлаживать.

Пользуясь случаем вынесу тему на всеобщиее срач обсуждение. Как вы считаете, почему в 2000х годах USB победил конкурирующую технологию FireWire? Хотя в FireWire тогда уже было всё, что сейчас USB 3 только внедряет - две скоростные дифф.пары точка-точка, PowerDelivery больше 3 Вт. С какого?

На мой взгляд FireWire гораздо более сложен в реализации. Если перенестись в конец 90-х, то можно понять что не всякий производитель мог себе позволить проектировать такие сложные интерфейсы. USB 1.0 (и даже 2.0) относительно простой протокол. Ну и я думаю Apple приложила не мало усилий, чтобы усложнить сторонним разработчикам адаптацию этого стандарта.

С программной точки зрения - оба хороши. Они оба предполагают более-менее умный девайс на том конце линии, который по крайней мере способен назвать своё имя текстом. А аппаратно - ну тут вопросики:

Схема USB-изолятора ADUM4160. Оранжевым отмечена половина схемы, достаточная для LVDS
Схема USB-изолятора ADUM4160. Оранжевым отмечена половина схемы, достаточная для LVDS

В то время, как FireWire основан на обычном LVDS, стандартизированным IEEE, ISO и даже ГОСТ успел скопировать это всё. Что на 100 Мбит/c, что на 3 гигабит. И Две дифф.пары USB3.0 на этом фоне выглядят, как костыль.

Возможно, не взлетело из-за отсутствия низких скоростей. Сразу, понимаш, давай мышку на 100 Мбит/c, понимашь. Наверное. Но стандарт мог бы и в сторону низких скоростей развиться, было бы желание.

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

Ну, USB 1.0 вообще не является дифф линией, а в USB 2.0 есть её жалкое подобие. Зато аппаратная часть очень просто реализуется и не требуется дорогостоящих трансиверов. При желании можно программно модулировать сигнал на шине. Иными словами, USB взял рынок дешевизной.

На мой взгляд маркер EOP это очень годное решение - избавляет от необходимости вводить поле с размером пакета или полезной нагрузки, занимает всего три битовых интервала.

Ну вообще да. Дифф. пара и согласование волнового сопротивления кабеля начинается только с 2.0. Но, wtf, тогда для 1.0 и 1.1 вполне должно и одного сигнального провода хватать. I1C называлось бы))), т.к. 1wire уже к этому времени был запатентован.

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

С двумя проводами надежней - можно закодировать тактовый сигнал, и еще ряд управляющих "символов". :)

Мощно. Объем впечатляющий. Апплодирую стоя!

Надеюсь когда-нибудь дойду до глубокого погружения в прочтение :)

Распечатать и положить на полку. Авось, сгодиться когда нибудь. :)

Норм талмуд. Почти нет фактических ошибок, так по мелочи. В своё время тоже занимался такой ерундой)

Могу разве что добавить, что автор хоть и упомнял смену протокола для HID устройств, но почему-то в коде этого не сделал. Желательно принудительно отправить SetProtocol, чтоб устройство точно работало в Boot Protocol режиме.

  req = (USB_Request_Header) {
    .bmRequestType = (REQ_DIR_HOSTTODEVICE | REQ_TYPE_CLASS | REQ_REC_INTERFACE),
    .bRequest      = REQ_SetProtocol,
    .wValue        = 0,
    .wIndex        = 0,
    .wLength       = 0,
  };    

Ну и на практике у меня некоторые клавиатуры не заводились (не отправляли данных "Interrupt IN") пока я не дергал GetDescriptor(HID_Report)

  uint8_t data[0x100];
  req = (USB_Request_Header) {
      .bmRequestType = (REQ_DIR_DEVICETOHOST | REQ_TYPE_STANDARD | REQ_REC_INTERFACE),
      .bRequest      = REQ_GetDescriptor,
      .wValue        = (HID_Report << 8),
      .wIndex        = 0,
      .wLength       = sizeof(data),
  };

  // requesting descriptors for HID reports to let device know that we are ready to interact with it   



Спасбо за Ваше ревью. Похоже, что Вы единственный кто смог прочесть статью целиком. :-)

На счет установки Boot Protocol принудительно. Мне где-то попадалась инфа (помоему на OSDev), что с некоторых пор все клавы и мыши, по просьбам разработчиков BIOS, по умолчанию работают в Boot протоколе. Во всяком лучае, мне пока что другие не попадались. :-) Но я подправлю код конечно же.

Есть идея расширить до USB 1.1 и сделать поддержку Mass Storage Class, чтобы загружать на ПЛИСе какую нибудь ОС.

Тогда в статье есть неоднозначность:
"Согласно спецификации, все USB HID устройства по-умолчанию активируют «Report Protocol». "

Я не помню была ли у меня проблема с какими-то устройствами без принудительной установки протокола, но думаю что код у меня не возник из ниоткуда, и всё же что-то там глючило.

 И «Keepalive» и «SOF» используются в том числе для синхронизации внутренних часов на устройстве.

Можно про это по подробнее?
Тут имеется в виду RTC?
Какой формат пакета со временем? Год месяц день тоже передается?

Это кривой перевод. "Часы" это "clock" в оригинале, что означает обычный тактовый генератор, потому что "часы" в нашем смысле у них это RTC или ЧРВ если по-русски.

К RTC это не имеет никакого отношения. "Внутренние часы" это тактовый генератор с обратной связью.

Спасибо, понятно.

Какой порядок байт в параметрах пакетах USB? Litttle endian или big endian?

Следва на право: от младшего бита к старшему, от младшего байта к старшему.

 от младшего байта к старшему.

Значит Litttle endian 

Не совсем. В Little Endian биты в байтах идут от старшего к младшему, а тут - наоборот.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации