Usb cdc что это
AVR280
Демонстрация USB CDC хоста
1.Введение
Цель этого документа — описание начала реализации и разработки CDC хост-приложения с использованием отладочного набора STK525 или USBKEY, и в конце демонстрируется простой пример двойного моста USB-UART между двумя ПК.
Предполагается, что разработчик знаком с программным шаблоном AVR USB (http://www.atmel.com) и спецификацией CDC (http://www.usb.org).
Рисунок 1-1. CDC хост приложение
2. Принцип работы
2.1 Конфигурирование CDC
Конфигурирование CDC класса заключается в конфигурировании двух интерфейсов:
В итоге, CDC приложение должно иметь два канала в добавок к управляющей конечной точке. Но заметьте, что CDC устройство распознается стандартным ПК, (с помощью драйвера по умолчанию) только если оно содержит опциональный элемент регистрации.
Спецификация CDC класса представляет различные модели связи. Каждая модель характеризуется типом реализованного интерфейса и поддерживаемыми командами или протоколом. Это особенно используеется при связи с USB модемами, которые могут использовать специфический уровень протокола (например V42bis), и даже с USB телефонами и т.д.
Но для пользователей, которые не принимают во внимание эти модели, а только хотят реализовать обмен данными между двумя приложениями, эти модели не имеют значения.
Эти «рекомендации» коротко представляют читателю эти модели и соответствующие команды и /или запросы. Как бы то ни было, основная цель этого документа — объяснить архитектуру низкого уровня CDC хост приложения и продемонстрировать простейшую конфигурацию на демонстрационном примере.
2.2.1. Передачи данных
2.2.1.1 Исходные данные
После того, как хост провел энумерацию устройства, можно легко пересылать данные между приложениями.
Это простейший способ для реализации обмена данными между двумя базовыми приложениями с использованием USB, но с простотой UART:
Это самый простой случай использования моста UART-USB. В такой конфигурации когда устройство прошло энумерацию и было сконфигурировано, интерфейс управления может не использоваться, а весь обмен данными осуществояться через интерфейс данных.
2.2.1.2 Инкапсулированные данные
Для приложений более высокого уровня CDC класс определяет формат инкапсуляции данных для обработки пакета упаковщиком данных протокола. Этот режим здесь обсуждаться не будет, т.к. Он выходит за рамки простой демонстрации. Для получения более подробной информации см. Таблицу 1 на стр 1 Спецификации CDC («CDC Class Specification v1.1»).
2.2.2 Управление связью
Эта часть класса не является обязательной для приложений осуществляющих простой обмен данными.
2.2.2.1 Управляющий элемент
Хост может посылать двунаправленные запросы устройству через управляющую конечную точку. Формат этих запросов соответствует Спецификации USB 2.0:
Таблица 2-1. Формат пакета управляющего запроса
bmRequestType | bRequest | wValue | wIndex | wLength | Data |
Можно рассматривать два типа запросов:
2.2.2.2 Регистрирующий элемент
Через этот опциональный канал (IN передача по прерываниям ) устройство может передавать хосту специальные сообщения о событиях.
Таблица 2-2. Формат сообщения о событии
bmRequestType | bNotification | wValue | wIndex | wLength | Optional Data |
Для получения более подробной информации о реализации связи, пожалуйста, прочитайте главу 6 спецификации CDC класса.
3. Архитектура программного обеспечения Atmel
Ниже приведен обзор архитектуры программного обеспечения CDC хоста, где представлены все необходимые для работы файлы.
Рисунок 3-1. Архитектура программного обеспечения CDC хоста
Управление CDC осуществляется с помощью файла «host_cdc_task.c». Главная функция, которая периодически вызывается планировщиком — host_cdc_task(void) — которая выполняет три основные операции:
Когда устройство подключается к хосту, начинается процесс энумерации. Если задача нижнего уровеня программного обеспечения хоста, которая сравнивает дескрипторы устройства со списком поддерживаемых интерфейсов, «принимает» интерфейс устройства, то host_cdc_task() «видит» сообщение о подключении (Is_new_device_connection_event() возвращает TRUE).
Текущее количество «принятых» интерфейсов возвращается функцией Get_nb_supported_interface(). Для каждого номера интерфейса программа имеет доступ к кодам класса, подкласса и протокола благодаря макросам Get_class(i), Get_subclass(i) и Get_protocol(i).
Во-первых, программа проверяет есть ли у подключенного устройства CDC интерфейс данных. Если интерфейс устройства принят, функция соединения обнаруживает, какой канал IN, какой OUT для связи их с более общими именами: pipe_cdc_data_bulkin и pipe_cdc_data_bulkout. После этого IN канал может принимать данные в канал.
Затем программа проверяет, есть ли у устройства CDC интерфейс связи (регистрирующий элемент). Если есть, адрес канала также сохраняется под более общим именем pipe_cdc_comm_int. Пользователь разрешает определение управляющего интерфейса с помощью определения CDC_USE_MANAGEMENT_INTERFACE. Номер интерфейса сохраняется в переменной cdc_interface_comm, потому что он будет нужен, если используются управляющие запросы.Когда соединение принято, флаг cdc_connected устанавливается в 1 и каналы могут быть использованы приложением пользователя. Ниже приведен соответствующий код функции:
Код 3-1. Определение подключения CDC устройства
3.2 Передача данных
Передачу данных очень легко реализовать.
3.2.1 Получение данных
Если подключено CDC устройство, программа проверяет так часто, как это возможно (каждый раз при входе в в функцию), приняты ли каналом новые данные.
Рассматриваемое программное обеспечение позволяет выполнять две операции с данными каналов:
Код 3-2. Чтение данных из устройства
Эти операции реализованы с целью оценки. Пользователь может использовать эту функцию «как есть», но также может реализовать свой собственный обработчик данных (или упаковщик данных, например), имеющий доступ непосредственно к каналу.
3.2.2 Посылка данных
Принцип работы очень похож на прием данных. Данные, которые нужно отправить, сначала сохраняются в массиве cdc_stream_out_array[CDC_STREAM_OUT_SIZE]. Глобальная переменная tx_counter содержит текущее количество сохраненных байт, и таким образом, указывает на положение следующего сохраняемого байта.
Существует два возможных источника данных для массива:
Более того, существует два возможных условия передачи данных массива в OUT канал:
Передача по каналам USB обеспечивается функцией cdc_pipe_out_usb_flush().
Код 3-3. Посылка данных устройству
Код 3-4. Дополнительные функции
3.3 Управление связью
3.3.1 Управляющий элемент
Через нулевую конечную точку пересылаются специфические запросы CDC? Определенные в спецификации CDC класса. Эти запросы могут быть определены в следующей форме:
Код 3-5. Схема управляющего запроса
Где параметры, написанные полужирным курсивом, должны быть заменены параметрами, соответствующими специфическому запросу.
Поле W_INDEX обычно равно «cdc_interface_comm», что соответствует интерфейсу управления (если он разрешен) устройства.
Поле W_LENGTH содержит число байт, передающихся в запросе. Данные (для передачи или полученные) храняться в соответствующем массиве.
Пользователь может легко добавить другой запрос путем изменения файла «host_cdc_task.h». Как бы то ни было некоторые из них уже интегрированы в програамное обеспечение CDC хоста от Atmel.
3.3.1.1 Инкапсулированные запросы
Эти запросы используются для передачи специфических запросов, которые инкапсулированы в соответствии со специфическим протоколом.
Таблица 3-1. Запрос SEND_ENCAPSULATED_COMMAND
bmRequestType | bRequest | wValue | wIndex | wLength | Данные |
00100001b | 0x00 | 0x00 | Интерфейс | Количество данных, предназначенных для этого приемника | Управляющая команда, согласно протооколу |
Таблица 3-2. Запрос GET_ENCAPSULATED_RESPONSE
bmRequestType | bRequest | wValue | wIndex | wLength | Данные |
10100001b | 0x01 | 0x00 | Интерфейс | Количество данных, предназначенных для этого приемника | Данные, соответствующие протоколу |
3.3.1.2 Запросы параметров связи
Эти запросы могут использоваться для посылки (получения) конфигурации CDC устройства, для связи по UART.
Таблица 3-3. Запрос SET_LINE_CODING
bmRequestType | bRequest | wValue | wIndex | wLength | Данные |
00100001b | 0x20 | 0x00 | Интерфейс | 0x07 | Структура строки |
Таблица 3-4. Запрос GET_LINE_CODING
bmRequestType | bRequest | wValue | wIndex | wLength | Данные |
10100001b | 0x21 | 0x00 | Интерфейс | 0x07 | Структура строки |
Таблица 3-5. Структура кодирования строки
3.3.2 Регистрирующий элемент
Регистрирующий элемент, который состоит из дополнительной IN конечной точки, получает сообщения о событиях от устройства.
Рассматриваемое программное обеспечение Atmel для CDC хоста не включает в себя упаковщика пакетов для этого канала. Но отведено место для пользовательского обработчика сообщений.
Пожалуйста, для получения более подробной информации о возможностях, предоставляемых этим интерфейсом, прочитайте спецификацию CDC класса.
Код 3-5. Шаблон обработчика сообщений канала
4. Пример
Вся эта теория может показаться сложной, поэтому здесь с целью ознакомления приведен простой пример — двойной мост UART-USB, — который позволяет осуществить быструю оценку и является введением в разработку устройства CDC класса. В этой конфигурации, CDC хост приложение соединено через UART с последовательным портом ПК-1. У CDC устройства также есть UART, который подключен или к другому последовательному порту этого же ПК-1 или к последовательному порту другого ПК-2. Оба CDC приложения соединены вмести через USB. Это приложение, бесполезное в промышленном или потребительском использовании, просто показывает механизм обмена данными в устройствах CDC.
Рисунок 4-1. Оценочный пример двойного моста USB-UART
Замечание: Могут использоваться дополнительные CDC платы для реализации портов RS232 на ПК, если на них доступны только USB порты.
CDC устройство может быть реализовано на любом AVR USB с использованием программного обеспечения, доступного на сайте Atmel. CDC хост использует соответствующее программное обеспечение, которое также доступно в интернет.
4.2 Аппаратное обеспечение
Оба программных обеспечения могут быть запущены на доступных стартовых наборах. На время написания программное обеспечение для CDC хоста может быть запущено на STK525 или USBKEY (для AT90USB647/1287 ), а програамное обеспечение для CDC устройства может быть запущено на STK525, USBKEY (AT90USB64x/128x) или STK526 (AT90USB82/162).
Плата с USB устройством должна быть сконфигурирована в режиме питания от шины для простейшей работы. Плата с USB хостом должна иметь собственный источник питания (внешний источник питания) и сконфигурирована так, чтобы обеспечивать питание платы с USB устройством.
4.3 Программное обеспечение
4.3.1.1 Описание работы
Этот пример не осуществляет обмен данными через управляющий интерфейс. Как бы то ни было, этот интерфейс может быть реализован для обеспечения совместимости с другими CDC приложениями. После энумерации каждый байт, полученный от ПК-1 будет отправлен из UART в OUT канал CDC хоста, получен в OUT конечную точку CDC устройства и в конце концов передан в ПК-2 через UART. Байты, посылаемые из ПК-2, идут в обратном направлении и «прибывают» в последовательный буфер ПК-1.
Некоторые параметры должны быть определены на каждом микроконтроллере для обеспечения правильной работы. Программное обеспечение требует модификации, и оно работает «как есть» и сконфигурировано значениями, приведенными ниже.
4.3.2 Последовательный порт ПК
Для простого использования последовательного порта ПК вы можете использовать терминал. Под Windows вы можете запустить Hyper Terminal (Accessories => Communications). Сначала вы должны выбрать COM порт, к которому подключено приложение (хост или устройство). Затем должна быть правильно проведена конфигурация порта. Используя программное обеспечение без изменений, вы должны установить следующую конфигурацию:
Рисунок 4-2. Конфигурация Hyper Terminal
Затем появляется диалоговое окно терминала, в которое вы можете вводить символы для посылки в открытый порт или видеть принятые символы.
Каждый символ, который вы введете на экране ПК-1 появится на ПК-2 и наоборот.
5. Вывод
В заключение следует отметить, что CDC класс — это широкая спецификация, которая охватывает много различных конфигураций, и соответствует нескольким стандартам связи для поддержки таких устройств, как: модем, мобильные телефоны, интерфейсы LAN.
Хотя работа по реализации таких устройств может быть очень значительной, базовая реализация обмена данными вполне доступна. Эти «рекомендации» были созданы, чтобы помочь людям, которые хотят использовать хост совместимость продуктов Atmel AVR USB для реализации мощной системы связи, легкой в использовании и надежной, с использованием современнфх технологий. Приложения, такие как мост USB-UART (или похожие) могут быть легко созданы.
Stm32 + USB на шаблонах C++. Продолжение. Делаем CDC
Продолжаю разработку полностью шаблонной библиотеки под микроконтроллеры Stm32, в прошлой статье рассказал об успешной (почти) реализации HID устройства. Еще одним популярным классом USB является виртуальный COM-порт (VCP) из класса CDC. Популярность объясняется тем, что обмен данными осуществляется аналогично привычному и простому последовательному протоколу UART, однако снимает необходимость установки в устройство отдельного преобразователя.
Интерфейсы
Устройство класса CDC должно поддерживать два интерфейса: интерфейс для управления параметрами соединения и интерфейс обмена данными.
Интерфейс управления представляет собой расширение базового класса интерфейса с тем отличием, что содержит одну конечную точку (хотя, насколько я понял, без необходимости поддержки всех возможностей можно обойтись вообще без конечной точки) и набор «функциональностей», определяющих возможности устройства. В рамках разрабатываемой библиотеки данный интерфейс представлен следующим классом:
В базовом случае интерфейс должен поддерживать три управляющих (setup) пакета:
SET_LINE_CODING: установка параметров линии: Baudrate, Stop Bits, Parity, Data bits. Некоторые проекты, на которые я ориентировался (основным источников вдохновения стал этот проект), игнорируют данный пакет, однако в этом случае некоторые терминалы (например, Putty), отказываются работать.
GET_LINE_CODING: обратная операция, в ответ на эту команду устройство должно вернуть текущие параметры.
SET_CONTROL_LINE_STATE: установка состояния линии (RTS, DTR и т.д.).
Код обработчика setup-пакетов:
Ключевой момент нумерации, а именно формирование дескрипторов, выполнен по уже привычной схеме раскрытия variadic-ов, что позволяет избавиться от зависимости классов в иерархии:
Второй интерфейс, предназначенный для непосредственно обмена данными, абсолютно примитивный, он не должен поддерживать управляющих сообщений, а является просто контейнером для двух конечный точек (точнее одной двунаправленной). Объявление класса:
Поскольку мои познания в CDC-устройствах весьма небольшие, из просмотренных примеров я сделал вывод, что управляющий интерфейс почти всегда одинаковый и содержит 4 функциональности: Header, CallManagement, ACM, Union, поэтому добавил упрощенный шаблон интерфейса:
Применение разработанных классов
Для использования разработанных классов достаточно объявить две конечные точки (Interrupt для первого интерфейса и двунаправленную Bulk для второго), объявить оба интерфейса, конфигурацию с ними и, наконец, инстанцировать класс устройства:
Непосредственно логика заключается лишь в обработке входящих пакетов, что умещается в одну функцию (в качестве примера управляю светодиодом и выдаю сообщение):
Отладка и тестирование
Написать код правильно с первого раза практически невозможно, поэтому очень полезным оказалось все-таки разобраться с инструментами перехвата USB-пакетов, поэтому кратко опишу особенности и проблемы, с которыми столкнулся лично я.
Так и не удалось применить логический анализатор, он просто ничего не показывает. Полагаю, что дело в том, что это самый дешевый клон Seale Logic и если бы был в наличи нормальный аппарат, то все бы получилось. Главное преимущество логического анализатора заключается в том, что он позволяет отслеживать обмен данными еще в процессе нумерации, в то время как программы на стороне хоста показывают пакеты только для тех устройств, которые эту нумерацию успешно прошли.
Сначала отфильтровать по заведомо известному значению. Например, по значению PID, которое присутствует в ответе устройства на запрос GET_DEVICE_DESCRIPTOR. Фильтр: «usb.idProduct == 0x5711». Это позволит быстро определить адрес устройства.
Далее отфильтровать по адресу устройства с помощью оператора contains. Дело в том, что отображаемый адрес состоит из трех частей, последняя из которых является номером конечной точки (можно, конечно, перечислить все адреса). Фильтр: «usb.addr contains «1.19»».
Однако стоит заметить, что UsbPcap может доставить некоторые трудности, под катом опишу ситуацию, в которую недавно попал и потратил кучу времени и нервов.
Проблема с usbpcap
Для большей мобильности завел себе внешний SSD, на котором установлена Windows 10 To Go (Windows, предназначенная для установки на внешние носители). Хотя Microsoft вроде отказалась от поддержки этой технологии, в целом все работает. Прихожу с диском в новое место, гружусь с него, система подтягивает драйвера и все нормально (и быстро) работает.
Однажды Windows просто не загрузилась с синим экраном «inaccessible boot device». Потратил целые выходные, восстановить так и не смог, пришлось все переустановить. Через некоторое время та же проблема и снова потраченные на переустановку выходные. Спустя пару дней система опять не грузится, начал вспоминать и анализировать, что я такого делал. Выяснил, что проблема возникала после установки как раз WireShark с usbpcap. На одном из форумов наткнулся на сообщение от пользователя, который жаловался на проблему с мышкой/клавиатурой после установки usbpcap. Снес через LiveCD драйвер и Windows запустилась. Не уверен на 100%, но предположение такое: при запуске компьютера Windows начинается загружаться, подгружает драйвера usbpcap, тот блокирует USB, система дальше грузиться не может и падает в BSOD. Очень неочевидное поведение, жаль потраченного времени.
Тестировал написанный код в программе Terminal v1.9b, на скриншоте приведен результат отправки на устройство сообщений «0» и «1».
Полный код примера можно посмотреть в репозитории. Пример протестирован на STM32F072B-DISCO. Как и в случае с HID, громоздкая библиотека (особенно менеджер конечных точек) сильно облегчили реализацию поддержки CDC, на все ушел примерно полный день. Далее планирую добавить еще класс Mass Storage Device, и на этом, наверно, можно остановиться. Приветствую вопросы и замечания.
mcu.by
Услуги разработки встраиваемого ПО и контрактная разработка электроники на ShuraCore
Старт ARM. Поднимаем USB CDC.
Всем привет! Сегодня будем поднимать USB CDC (VCP) на плате stm32f401c-disco.
USB communications device class (коммуникационный класс устройства) — является составным классом устройства Универсальной последовательной шины. Класс может включать один (или более) интерфейс, такой как интерфейс пользовательского элемента управления, интерфейс передачи данных, аудио или интерфейс запоминающего устройства.
VCP – Виртуальный COM-порт
Базовый класс 02h (Communications and CDC Control)
Этот базовый класс определен для устройств, которые относятся к классу устройств спецификации связи. Эта спецификация определяет используемый набор подкласса и Протокола значений. Значения за пределами определения спецификации защищены. Обратите внимание, что связи класса устройств спецификации требуется несколько значений Кода класса (три), которые будут использоваться в описания устройств, а некоторые, которые будут использоваться в интерфейсе дескрипторов.
Базовый класс 02h
Подкласс xxh
протокол xxh
смысл Communication device class
Базовый класс 0Ah (CDC-Data)
Этот базовый класс определен для устройств, которые относятся к классу устройств спецификации связи. Это спецификация определяет используемый набор подкласса и протокола значений. Значения за пределами определения спецификации защищены. Эти коды класса могут быть использованы только в интерфейсе дескрипторов.
Базовый класс 0Ah
Подкласс xxh
протокол xxh
смысл CDC data device
1. Находим строку HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0); и меняем на HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
2. Находим строку #define CDC_DATA_HS_MAX_PACKET_SIZE 512 /* Endpoint IN & OUT Packet size */ и меняем на #define CDC_DATA_HS_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */
3. Производим изменения в usbd_cdc_if.c
4. Теперь нужно добавить в usbd_cdc_if.h несколько строк кода
5. Устраняем баг для USBD_CDC_TransmitPacket()
6. И добавляем пример в main.c
И все готова!, подключаем микро USB к плате, второй вывод к host-у и у нас появляется виртуальный com порт.
6 thoughts on “ Старт ARM. Поднимаем USB CDC. ”
When i debbuged this code i found that for really big messages this doesn’t work right. There was some issue with size off offset. IT send multiple time the same think.
I corrected it with:
if (size > CDC_DATA_HS_OUT_PACKET_SIZE) <
int offset;
for (offset = 0; offset
with large data is not working, thanks
Точно, спасибо за инфу.
Есть одна проблема. Не передаются пакеты более 64 байт. Кто-нибудь решил ее?
Составное устройство USB на STM32. Часть 4: Два-в-одном
В заключительной части публикации о составном устройстве USB я расскажу о том, как заставил заработать составное устройство USB, а также поделюсь некоторыми неочевидными нюансами этого процесса.
Работа составных частей устройства была описана во второй и третьей частях публикации.
Ответы на вопрос, зачем это всё было затеяно, даются в начале первой части и в конце четвёртой.
Исходные коды публикуемой реализации составного устройства USB, состоящего из виртуального COM-порта и дуплексной звуковой карты находятся здесь.
Создаём Composite Device Class
Файлы драйвера составного устройства usbd_comp.c и usbd_comp.h расположены в папках Core/Scr и Core/Inc соответственно.
Структура класса составного устройства аналогична структуре класса звукового устройства и содержит подобный набор функций-обработчиков событий.
Основная функция драйвера составного устройства заключается в том, чтобы определить, драйвер какого устройства нужно подключить для обработки события. При обработке запросов (Requests) это определяется по номеру интерфейса в случае Standard Requests или атрибутам запроса в случае Class-Specific Requests. При обработке пакетов данных переключение производится, как правило, по номеру конечной точки (EP).
Запросы 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-порту могут и не подключиться.
Проверка работоспособности драйвера составного устройства USB
Неочевидный нюанс 5: при проверке работоспособности «эхо» через COM-порт возвращается, когда составное устройство уже «переключено на COM-порт». В реальном применении устройства передача может начаться, когда подключено звуковое устройство. Чтобы избежать подобной ситуации, перед началом передачи производится вызов функции COMP_CDC_Transmit_FS для подключения драйвера виртуального COM-порта:
Выводы
Автору удалось реализовать составное устройство USB, состоящее из виртуального COM-порта и дуплексной звуковой карты, на ресурсах платы NUCLEO-F446ZE.
Решение оформлено в виде проекта в среде разработки STM32CubeIDE. После генерации кода STM32CubeMX для восстановления работоспособности решения необходимо вручную изменить значения трёх байтов в стандартном дескрипторе устройства USB (USB standard device descriptor), размещённом в файле usbd_desc.c.
От автора
Данный цикл публикаций подводит черту, фиксирует результат проекта, которой мне удалось достичь в одиночку.
Хочу поблагодарить своих читателей за доброжелательность и тёплый приём. Я никогда не был и никогда уже не буду профессиональным разработчиком ПО для микроконтроллеров. И это моя первая публикация про разработку программного обеспечения.
Благодарю Георгия (RX9CIM) за моральную поддержку при запуске проекта.
Отдельная благодарность romanetz_omsk, без которого я бы забросил проект ещё два года назад.
По логике дальнейшего развития MVP нужно приступать к написанию DSP, а это уже достаточно сложная для меня математика. Как это осилить в одиночку, ума не приложу…