Составное usb устройство что это
Не так давно, была опубликована статья «Пастильда — открытый аппаратный менеджер паролей». Так как данный проект является открытым, то мы решили, что будет интересно, если мы будем писать небольшие заметки о процессе проектирования, о задачах, которые перед нами стоят и о трудностях, с которыми мы сталкиваемся.
Реализация USB хоста
Итак, во-первых мне нужно было реализовать на устройстве USB хост, чтобы оно могло распознавать и общаться с подключенной к нему клавиатурой. Так как в работе я использую связку Eclipse + GNU ARM Eclipse + libopencm3, то очень хотелось найти уже что-то готовое и желательно написанное с использованием библиотеки libopencm3. Желание мое было очень жирным, до последнего момента не верила, что мои поиски увенчаются успехом. Однако под конец рабочего дня, проскролив интернет до самого дна, я вдруг наткнулась вот на это. libusbhost? Серьезно? И это был не просто написанный на основе libopencm3 usb хост, он еще и был написан под STM32F4, под тот самый, который мы решили использовать в проекте. В общем, звезды сошлись и радости моей не было предела. Кстати, оказалось, что этот проект создавался как часть libopencm3, однако его так и не добавили в библиотеку.
Как библиотеку, libusbhost я не собирала, просто взяла необходимые мне исходники, написала драйвер для клавиатуры и, в общем-то все, погнали! Но обо всем по-порядку.
- usbh_device_driver.h
- usbh_config.h
- usbh_hubbed.[ch]
- usbh_lld_stm32f4.[ch]
По аналогии с usbh_driver_hid_mouse.[ch], я написала драйвер для клавиатуры (usbh_driver_hid_kbd.[ch]).
Далее был реализован простенький класс, для работы с хостом:
Реализация составного USB устройства
Далее мне нужно было сделать так, чтобы наше устройство отображалось в диспетчере устройств и как клавиатура, и как дисковый накопитель. Тут вся магия в дескрипторах=) В этом документе, в главе 9, подробно описан USB Device Framework. Эту главу нужно очень внимательно прочитать и в соответствии с ней описать дескрипторы устройства. В моем случае получилось следующее:
- usb_config_descriptor: поле bNumInterfaces должно отражать столько интерфейсов, сколько реально реализовано. В нашем случае два: HID и MSD
- usb_interface_descriptor: поле bInterfaceNumber обозначает номер интерфейса, но отсчет начинается с нуля, следовательно, номер первого интерфейса — 0.
Для работы с составным устройством был написан класс USB_composite, представленный ниже.
- Функция hid_control_request нужна для общения Пастильды как клавиатуры с хостом (в данном случае, хост — это ПК). Вне класса данная функция вызывается через USB_control_callback.
- Функция hid_set_config нужна для того, чтобы настроить конечные точки (endpoints) и зарегистрировать USB_control_callback, описанный в предыдущем пункте. Вне класса данная функция вызывается через USB_set_config_callback.
Как правило, функции control_request и set_config должны быть явно описаны для каждого устройства. Однако из этого правила есть исключение: Mass Storage Device. Итак, разберемся с конструктором класса USB_Composite.
Во-первых, мы инициализируем ноги USB OTG FS:
Во-вторых, нам нужно проинициализировать наше составное устройство, зарегистрировать USB_set_config_callback, о котором шла речь выше, и разрешить прерывание:
- Во вкладке «Контроллеры USB»: как составное устройство,
- В этой же вкладке, как «Запоминающее устройство для USB»,
- Во вкладке «Клавиатуры», как «Клавиатура HID».
- block_count: количество секторов памяти,
- read_block: функция для чтения сектора,
- write_block: функция для записи сектора.
Так вот. Теперь, когда конструктор класса USB_Composite дописан, можно собрать проект, прошить устройство и увидеть, что «Запоминающее устройство для USB» больше не помечено предупреждением, а во вкладке «Дисковые устройства» можно обнаружить «ThirdPin Pastilda USB Device». И, казалось бы, все хорошо. Но нет=) Проблем стало больше:
1. Зайти на диск невозможно. При попытке сделать это все виснет, умирает, компьютеру очень плохо.
2. Распознавание устройства как дискового занимает более 2-х минут.
Об этих проблемах и о том, как их решить без вреда для здоровья написано здесь: USB mass storage device и libopencm3.
И, о, чудо! Никаких пятен=) Теперь все работает. У нас есть USB хост и составное USB устройство. Осталось только объединить их работу.
История эта началась три года назад, когда я осознал, что мне скоро исполнится 50 лет, что я погряз в бумажной работе, и что мне хочется чего-то нового. Работу поменять в моём возрасте уже проблематично, поэтому я решил начать pet-проект.
Первое, что приходит в таких случаях на ум старому радиолюбителю: новая радиостанция. Стопроцентно аппаратные решения остались в далёком прошлом. Сейчас гораздо более актуальны SDR-трансиверы: решение это программно-аппаратное, есть опубликованные примеры реализации, к некоторым из них даже выложены исходные коды прошивок.
Основная проблема в разработке заключалась в том, что несложные SDR-радиостанции, работающие в связке со звуковой картой, требуют наличия у компьютера, к которому они подключены, двухканальных линейных входа и выхода для работы приёмо-передающего тракта, а также COM-порта для работы CAT-интерфейса. В современных же ноутбуках аудиовход обычно предназначен для подключения микрофона гарнитуры и бывает только монофоническим.
И опыт и навыки формируются практикой. Для их формирования необходимо:
- изучать документацию;
- проводить анализ существующих решений;
- разрабатывать собственные решения;
- воплощать собственные решения в «железе»;
- возвращаться к началу цикла если не заработало.
Язык C разрабатывался инженерами и для инженеров. Использование языка программирования C дало мне возможность абстрагироваться от ассемблера и машинных кодов с одной стороны, но в тоже время обращаться напрямую к регистрам или к памяти.
Нелюбимый многими STM32CubeMX с библиотекой HAL значительно облегчил мне процесс разработки хотя бы тем, что не надо было за каждой мелочью заглядывать в Reference Manual.
Кроме того, я очень многому научился, разбирая сгенерированный STM32CubeMX код:
- его писали разные люди, но он выдержан в одном стиле;
- назначение переменных и функций понятно из имени;
- комментарии к коду позволяют документировать его через Doxygen и т.п.
В силу того, что я не мог гарантировать результат своей программистской деятельности, пришлось вводить градации по функционалу MVP проекта от простого к сложному.
Минимальный функционал MVP подразумевал подключение приёмной части радиостанции к линейному входу звуковой карты компьютера и приём на фиксированной частоте.
Следующим шагом планировалась реализация перестройки частоты через CAT-интерфейс, подключение приёмного и передающего трактов радиостанции к линейным входу и выходу звуковой карты и приём-передача на любительских диапазонах.
И только после этого планировалось подключение SDR-трансивера к компьютеру как звукового устройства USB с управлением по CAT-интерфейсу.
Такой подход сразу дал плоды: уже к началу 2019 года, всего через шесть месяцев после установки на мой компьютер STM32CubeMX, был реализован минимальный MVP проекта: функциональный аналог SDR-приёмника Softrock Lite II RX уверенно принимал сигналы точного времени на частоте 9996 кГц.
В настоящее время MVP проекта является функциональным аналогом SDR-трансивера Peaberry SDR V2 и работает как на приём, так и на передачу.
Описываемое в публикации составное устройство USB работает в составе SDR-трансивера. Структура приёмопередающего тракта разрабатываемого SDR-трансивера включает в себя пока только самый необходимый минимум и представлена на рисунке ниже:
При приёме радиосигнал поступает из антенны через полосовой фильтр (BPF) в квадратурный детектор (QSD). Полученный в результате квадратурный сигнал (IQ) через двухканальный вход дуплексного звукового устройства USB поступает в компьютер для дальнейшей обработки.
При передаче сформированный в компьютере квадратурный сигнал (IQ) через двухканальный выход дуплексного звукового устройства USB поступает в квадратурный возбудитель (QSE).
Полученный в результате радиосигнал подаётся через полосовой фильтр (BPF) в антенну.
Обработка сигналов на стороне компьютера осуществляется программой HDSDR.
Частота приёма и передачи задаётся настройками генератора плавного диапазона (VFO). Управление VFO и режимом работы (приём-передача) осуществляется из программы HDSDR через CAT-интерфейс, подключенный к виртуальному COM-порту.
Связь HDSDR с виртуальным COM-портом осуществляется посредством программы OmniRig, созданной канадским радиолюбителем Alex Shovkoplyas (VE3NEA).
CAT-интерфейс трансивера использует ограниченный набор команд популярного во всём мире трансивера Yaesu FT-817.
Виртуальный COM-порт и дуплексное звуковое устройство объединены в составное устройство USB, работа которого и будет разобрана в данной публикации. Для облегчения проверки работоспособности публикуемого решения на входные и выходные потоки устройств установлены шлейфы.
Техническое решение разрабатывалось на основе анализа созданной немецким радиолюбителем Andreas Richter (DF8OE) open source прошивки для трансивера mcHF M0NKA и его клонов. Ряд нюансов был проработан при попытках разобраться в кодах дуплексного звукового устройства USB на базе расширения X-CUBE-AUDIO для STM32CubeMХ.
Описываемое в публикации составное устройство USB состоит из виртуального COM-порта и дуплексного звукового устройства USB 16 бит 48 кГц. Публикуемое решение реализовано на микроконтроллере STM32F446ZET6 из состава платы NUCLEO-F446ZE.
Упрощенная структура дескриптора представлена на рисунке ниже:
Дескриптор составного устройства USB создан по рекомендациям, содержащимся в документе:
Хотел бы заострить внимание на том, что в структуре дескриптора составного устройства USB важен порядок описания интерфейсов: сначала идёт описание интерфейса 0, затем интерфейса 1 и т.д. Номера используемых интерфейсами конечных точек (EP) могут идти не по порядку.
При генерации кода STM32CubeMX размещает дескриптор устройства (Device Descriptor) в файле usbd_desc.c. Нужно отметить, что STM32CubeMX при последующей генерации кода не сохранит изменения, вручную внесённые в дескриптор, т.к. они не находятся в области, помеченной как USER CODE.
Дескрипторы конфигурации и классов устройств размещаются в файлах usbd_cdc.c и usbd_audio.c, размещённых в папках директории Middlewares/ST/Class. Важно помнить, что STM32CubeMX даёт выбрать за раз только один класс устройств. Если ранее был выбран другой класс, при генерации кода файлы с драйверами этого класса из проекта будут удалены.
В заключительной части публикации о составном устройстве USB я расскажу о том, как заставил заработать составное устройство USB, а также поделюсь некоторыми неочевидными нюансами этого процесса.
Работа составных частей устройства была описана во второй и третьей частях публикации.
Ответы на вопрос, зачем это всё было затеяно, даются в начале первой части и в конце четвёртой.
Исходные коды публикуемой реализации составного устройства USB, состоящего из виртуального COM-порта и дуплексной звуковой карты находятся здесь.
Файлы драйвера составного устройства usbd_comp.c и usbd_comp.h расположены в папках Core/Scr и Core/Inc соответственно.
Структура класса составного устройства аналогична структуре класса звукового устройства и содержит подобный набор функций-обработчиков событий.
Основная функция драйвера составного устройства заключается в том, чтобы определить, драйвер какого устройства нужно подключить для обработки события. При обработке запросов (Requests) это определяется по номеру интерфейса в случае Standard Requests или атрибутам запроса в случае Class-Specific Requests. При обработке пакетов данных переключение производится, как правило, по номеру конечной точки (EP).
Подробно Standard Requests описаны на стр.248 – 260 документа:
[5] Universal Serial Bus Specification, Revision 2.0, April 27, 2000
Запросы Communication Device Class-Specific Requests подробно описаны на стр.18 – 30 документа [4], а Audio Device Class-Specific Requests, соответственно, на стр.74 – 85 документа [3].
Дескриптор описанного в публикации составного устройства USB состоит из девяти байтов раздела Configuration Descriptor, восьми байтов раздела Interface Association Descriptor (IAD) для двух интерфейсов виртуального COM-порта, 58 байтов дескриптора виртуального COM-порта, восьми байтов раздела IAD для трёх интерфейсов звукового устройства и 183 байтов дескриптора звукового устройства USB.
Виртуальный COM-порт использует интерфейсы 0 и 1, а также конечные точки 1 и 2. Дуплексное звуковое устройство использует интерфейсы 2, 3 и 4, а также конечную точку 3.
Рассмотрим доработанный файл usb_device.c, расположенный в папке USB_DEVICE/App:
Сначала создаётся переменная hUsbDeviceFS. Тип USBD_HandleTypeDef объявлен в usbd_def.h.
Функция MX_USB_DEVICE_Init вызывается из main.c.
Вызовом функции USBD_Init задаются начальные значения переменной hUsbDeviceFS.
Затем вызовом функций HAL_PCDEx_SetTxFiFo производится настройка буфера USB для каждой конечной точки составного устройства.
Неочевидный нюанс 1: по умолчанию настройка буфера USB производится при исполнении функции USBD_LL_Init, размещённой в файле usbd_conf.c. В теле этой функции области, помеченной как USER CODE, нет. Т.е. при каждой генерации кода STM32CubeMX будет удалять настройки буфера для конечных точек 2 и 3. Именно поэтому окончательная настройка буфера USB производится уже после того, как функция USBD_LL_Init отработала.
Вызовом функции USBD_RegisterClass в hUsbDeviceFS.pClass размещается указатель на созданную в usbd_comp.c переменную USBD_COMP, содержащую указатели на обработчики событий, относящихся к классу устройства. Тип USBD_ClassTypeDef объявлен в usbd_def.h.
Вызовом функции USBD_RegisterInterface в hUsbDeviceFS.pUserData размещается указатель на созданную в usbd_comp.h пустую переменную USBD_COMP_fops_FS.
В дальнейшем обработчики событий составного устройства USB будут вызывать обработчики событий нужного устройства, входящего в составное, а также подключать нужный интерфейс связи с оконечными устройствами.
Вызовом функции USBD_Start производится запуск устройства USB.
Неочевидный нюанс 2: составное устройство будет упорно определяться как виртуальный COM-порт, если не поменять значения трёх байтов в стандартном дескрипторе устройства USB (USB standard device descriptor), размещённом в файле usbd_desc.c, причём при каждой генерации кода STM32CubeMX эти изменения будет удалять:
Неочевидный нюанс 3: виртуальный COM-порт в данном решении работает корректно только в случае, когда номер используемой им конечной точки меньше, чем номер конечной точки звукового устройства.
Неочевидный нюанс 4: виртуальный COM-порт в данном решении работает корректно только в случае, когда при инициализации в его буфер прописываются параметры порта (см. USBD_COMP_Init). Без этой записи программы терминалов к COM-порту могут и не подключиться.
Соединяем воедино проверки работоспособности драйвера виртуального COM-порта и дуплексного звукового устройства USB. Убеждаемся, что они отлично уживаются.
Неочевидный нюанс 5: при проверке работоспособности «эхо» через COM-порт возвращается, когда составное устройство уже «переключено на COM-порт». В реальном применении устройства передача может начаться, когда подключено звуковое устройство. Чтобы избежать подобной ситуации, перед началом передачи производится вызов функции COMP_CDC_Transmit_FS для подключения драйвера виртуального COM-порта:
Попробуйте эти исправления:
- Обновите драйвер контроллера USB
- Обновите драйвер принтера
- Отрегулируйте настройки BIOS
От автора
Данный цикл публикаций подводит черту, фиксирует результат проекта, которой мне удалось достичь в одиночку.
Хочу поблагодарить своих читателей за доброжелательность и тёплый приём. Я никогда не был и никогда уже не буду профессиональным разработчиком ПО для микроконтроллеров. И это моя первая публикация про разработку программного обеспечения.
Благодарю Георгия (RX9CIM) за моральную поддержку при запуске проекта.
Отдельная благодарность romanetz_omsk, без которого я бы забросил проект ещё два года назад.
По логике дальнейшего развития MVP нужно приступать к написанию DSP, а это уже достаточно сложная для меня математика. Как это осилить в одиночку, ума не приложу…
Выводы
Автору удалось реализовать составное устройство USB, состоящее из виртуального COM-порта и дуплексной звуковой карты, на ресурсах платы NUCLEO-F446ZE.
Решение оформлено в виде проекта в среде разработки STM32CubeIDE. После генерации кода STM32CubeMX для восстановления работоспособности решения необходимо вручную изменить значения трёх байтов в стандартном дескрипторе устройства USB (USB standard device descriptor), размещённом в файле usbd_desc.c.
Попробуйте эти исправления
Вот 3 исправления, которые помогли многим другим пользователям решить проблему с композитным USB-устройством. Необязательно пробовать их все; просто продвигайтесь вниз по списку, пока не найдете тот, который вам подходит.
- Обновите драйвер композитного USB-устройства
- Переустановите драйверы контроллера USB.
- Используйте средство устранения неполадок USB в Windows
Исправление 3: используйте средство устранения неполадок Windows USB
Если описанные выше действия не помогли вам, вы можете попробовать средство устранения неполадок Windows USB.
Чтобы использовать его, во-первых, вам необходимо загрузить инструмент по этой ссылке .
Затем вы можете открыть инструмент и следовать инструкциям на экране для устранения проблемы.
Если у вас есть какие-либо вопросы или предложения, пожалуйста, не стесняйтесь оставлять комментарии ниже.
Выводы
Автору удалось реализовать составное устройство USB, состоящее из виртуального COM-порта и дуплексной звуковой карты, на ресурсах платы NUCLEO-F446ZE.
Решение оформлено в виде проекта в среде разработки STM32CubeIDE. После генерации кода STM32CubeMX для восстановления работоспособности решения необходимо вручную изменить значения трёх байтов в стандартном дескрипторе устройства USB (USB standard device descriptor), размещённом в файле usbd_desc.c.
Решение 1. Обновите драйвер USB-контроллера
Если ваш драйвер USB-контроллера поврежден, устарел или отсутствует, вероятно, возникает ошибка.
Вы можете обновить драйвер контроллера USB вручную или автоматически.
Вариант 1 — Вы можете перейти на веб-сайт производителя своего фирменного компьютера или USB-контроллера, а затем выполнить поиск последней версии USB-контроллера, соответствующей вашей конкретной версии Windows (например, Windows 64 bit) и загрузите драйвер вручную.
После того, как вы загрузили правильные драйверы для вашей системы, дважды щелкните загруженный файл и следуйте инструкциям на экране, чтобы установить d river.
Вариант 2 — Если у вас нет времени, терпения или компьютерных навыков для обновления драйвера USB-контроллера вручную, вы можете сделать это автоматически с помощью Driver Easy .
Driver Easy автоматически распознает вашу систему и найдет для нее правильные драйверы. Вам не нужно точно знать, в какой системе работает ваш компьютер, вам не нужно рисковать загрузкой и установкой неправильного драйвера, и вам не нужно беспокоиться об ошибке при установке.
Вы можете автоматически обновлять драйверы с помощью версии Driver Easy FREE или Pro . Но с версией Pro требуется всего 2 клика :
Загрузить и установите Driver Easy.
Запустите Driver Easy и нажмите кнопку Сканировать сейчас . Затем Driver Easy просканирует ваш компьютер и обнаружит все проблемные драйверы.
Нажмите Обновить все , чтобы автоматически загрузить и установить правильную версию всех отсутствующих или отсутствующих драйверов. даты в вашей системе (для этого требуется версия Pro — вам будет предложено выполнить обновление, когда вы нажмете «Обновить все»).
Примечание. Вы можете сделать это бесплатно , если хотите, но частично вручную.
После обновления драйвера USB-контроллера до последней версии перезагрузите компьютер, чтобы проверить, успешно ли подключен принтер.
Исправление 2: переустановите драйверы контроллера USB
Вы также можете попробовать удаление и повторная установка драйверов USB через диспетчер устройств. Это действие позволит Windows автоматически сканировать аппаратные изменения и переустанавливать необходимые драйверы. Вот что вам нужно сделать:
ключ
одновременно, чтобы открыть окно «Выполнить».
Исправление 1. Обновите драйвер составного USB-устройства
Наиболее вероятной причиной ошибки вашего составного USB-устройства является проблема с драйвером устройства.
К счастью, это одна из самых простых проблем, которую можно решить.
Есть два способа обновить драйвер композитного USB-устройства: вручную и автоматически .
Обновите драйвер комбинированного USB-устройства вручную . Вы можете обновить драйвер вручную, перейдя на веб-сайт производителя оборудования и выполнив поиск последней версии драйвера для ваше составное USB-устройство. Если вы воспользуетесь этим подходом, обязательно выберите драйвер, совместимый с точным номером модели вашего оборудования и вашей версией Windows.
Обновите драйвер композитного USB-устройства автоматически — Если у вас нет времени, терпения или компьютерных навыков для обновления драйвера вручную, вместо этого вы можете сделать это автоматически с помощью Driver Easy . Вам не нужно точно знать, в какой системе работает ваш компьютер, вам не нужно беспокоиться о неправильном драйвере, который вы будете загружать, и вам не нужно беспокоиться об ошибке при установке. Driver Easy справится со всем этим.
- Загрузите и установите Driver Easy.
- Запустите Driver Easy и нажмите Сканировать сейчас . Затем Driver Easy просканирует ваш компьютер и обнаружит все проблемные драйверы.
Решение 3. Отрегулируйте настройки BIOS
Для включения поддержки устаревших USB выполните следующие действия:
-
Перезагрузите свой компьютер. Немедленно нажмите функциональную клавишу, например F2 , чтобы войти в BIOS вашей системы.
После этого ваш компьютер загрузится в обычную систему . Посмотрите, сможете ли вы использовать свой принтер.
Вот и все. Возможно, теперь вы сможете использовать свой принтер с компьютером под управлением Windows. Не стесняйтесь комментировать ниже, если у вас есть какие-либо вопросы.
Что вас может беспокоить…
USB 3.0 — гораздо более надежный и более быстрый USB ( Универсальная последовательная шина) стандарт. Сегодня большинство новых компьютеров и других устройств поддерживают USB 3.0.
Однако большинство портов USb 3.0 обратно совместимы . То есть ваш принтер USB 2.0 должен без проблем работать с USB 3.0.
Когда вы получаете составное USB-устройство, которое не может работать с USB 3.0 или чем-то подобным, обычно это проблема с драйвером . Следуйте приведенным здесь решениям, чтобы попытаться решить вашу проблему.
Решение 2: Обновите драйвер принтера
Если драйвер USB-контроллера исправен, перейдите к проверке драйвера принтера .
Подобно обновлению драйвера принтера, вы можете получить последнюю версию драйвера принтера с веб-сайта производителя принтера или также можете получить его автоматически с помощью Driver Easy .
Читайте также: