Русский
Русский
English
Статистика
Реклама

Stm32cubeide

CAT-интерфейс для трансивера Радио-76

13.05.2021 12:17:12 | Автор: admin
В предыдущей публикации о трансивере Радио-76 упоминалось о синтезаторе частоты с CAT-интерфейсом. В этой статье тема CAT-интерфейса будет раскрыта подробней.

CAT-интерфейс (Computer Aided Transceiver) предназначен для управления частотой, видами модуляции и другими функциями радиостанции с помощью компьютера.

В сети есть множество описаний радиолюбительских синтезаторов на базе Si5351, но в массе своей CAT они не поддерживают. Данная публикация этот пробел должна восполнить.

Аппаратное решение


Аппаратное решение не несёт никакой новизны. Синтезатор создавался из того, что было под рукой: плата Black Pill c микроконтроллером STM32F411CEU6, дисплей SSD1306 и микросхема синтезатора частоты Si5351A-B-GT.

Схема подключения Si5351A-B-GT приведена ниже.


Подтягивающие резисторы R1, R2 устанавливаются на выводы дальнего от микроконтроллера устройства на шине I2C. Сигнал с выхода CLK0 подаётся на первый смеситель основной платы трансивера Радио-76. Сигнал с выхода CLK2 подаётся на второй смеситель трансивера. Делители напряжения на резисторах R3, R6 и R4, R5 препятствуют перегрузке смесителей.

Вся схема собрана на печатной плате переходника SSOP-DIP:


Из имеющихся у меня в наличии кварцевых резонаторов на частоту 25MHz и 27MHz ни один на этих частотах не запустился. Параллельно включенные резисторы и конденсаторы ситуацию не спасали. На фотографии кварц, который запустился на частоте 24MHz, когда параллельно ему был включен резистор номиналом 1МОм.

Конфигурация микроконтроллера


Проект создан на основе платы Black Pill c микроконтроллером STM32F411CEU6 в среде разработки STM32CubeIDE:


Шина I2C подключена к выводам PB9, PB10 микроконтроллера. К выводам PB0, PB1, PB2 подключены тангента (PTT, Push-To-Talk) и контакты телеграфного ключа (KEY_DIT, KEY_DAH). Вывод PC13 служит для аппаратного переключения режима приём/передача (RX/TX). Режиму TX соответствует сигнал низкого логического уровня, при этом светится индикатор на плате.

Виртуальный COM-порт создан на основе IP Commucation Device Class. Максимальное количество интерфейсов равно двум. Размер буферов задан равным 64 Bytes.

Программная реализация CAT


Ссылка на репозиторий: https://github.com/dmitrii-rudnev/radio-76-cat

За основу решения была принята система команд для управления популярным трансивером Yaesu FT-817. Описание работы CAT-интерфейса этой радиостанции занимает в руководстве пользователя всего четыре страницы.

Управляющие программы сторонних производителей обычно используют для связи с радиостанцией драйвер OmniRig, созданный канадским радиолюбителем Alex Shovkoplyas (VE3NEA). Описанная реализация CAT-интерфейса использует ограниченный набор команд Yaesu FT-817, поддерживаемый этим драйвером.

При настройке OmniRig для работы с публикуемым решением нужно выбрать в конфигураторе OmniRig тип трансивера FT-817, COM-порт, к которому подключен CAT, и установить скорость порта 9600 бит/с.

Для управления радиостанцией один раз в 200 мс через COM-порт посылается пять байт данных. Пятый байт содержит команду управления, первые четыре байта могут содержать данные или быть пустыми. Радиостанция распознает команду, выполняет её и посылает отклик.

Описанная реализация CAT-интерфейса поддерживает работу в составе радиостанции двух генераторов плавного диапазона VFO A и VFO B. Наличие двух VFO позволяет работать на разнесённых частотах (режим Split), когда приём осуществляется на частоте одного VFO, а передача на частоте другого.

Описанное решение позволяет осуществлять переключение между VFO, перестройку частоты активного VFO управляющей программой, а также производить переключение режимов приём/передача.

Помимо этого, хотя для Радио-76 это и не актуально, оставлена возможность переключения вида модуляции.

Собственно трансивер реализован переменной trx со структурой, приведённой ниже:
typedef enum{  MODE_LSB = 0x00,  MODE_USB = 0x01,  MODE_CW  = 0x02,  //CW-USB  MODE_CWR = 0x03,  //CW-LSB  MODE_AM  = 0x04,  MODE_FM  = 0x08,  MODE_DIG = 0x0A,  //DIG-U  MODE_PKT = 0x0C   //DIG-L} Mode;typedef struct{  Mode mode;     //используемая модуляция из списка  uint64_t vfoa; //частота VFO A в герцах  uint64_t vfob; //частота VFO A в герцах  uint8_t vfo;   //активный VFO: 0, если активен VFO A; 1, если VFO B  uint8_t split; //режим работы на разнесенных частотах: 1, если включен   uint8_t is_tx; //режим передачи: 1, если включен  uint32_t sysclock; //системное время  uint8_t systicks;  //счётчик прерываний SysTick до десяти} TRX_TypeDef;

Системное время используется для отслеживания тайм-аутов. Инкремент trx.sysclock происходит по каждому десятому прерыванию SysTick.

Переключение режима RX/TX осуществляет программный модуль ptt_if.c.

Переключение в режим передача (TX) и возврат в режим приём (RX) производится двумя разными способами:
1. По нажатию (TX) тангенты и её отпусканию (RX) (низкий/высокий уровень на входе PTT).
2. При получении по CAT команды FT817_PTT_ON (0x08) (TX) и получении по CAT команды FT817_PTT_OFF (0x88) (RX).

Следует учесть, что возврат в режим приём возможен только при условии отсутствия всех сигналов переключения в режим передачи.

Обработка состояния телеграфного ключа, а также линий RTS и DTR виртуального COM-порта в публикуемой реализации CAT-интерфейса не предусмотрена.

Связь с драйвером микросхемы синтезатора частоты осуществляет программный модуль vfo_if.c. Модуль меняет настройки синтезатора в зависимости от полученной по CAT частоты, а также режима работы радиостанции.

Модуль cat_if.c содержит драйвер CAT-интерфейса.

Обработчик состояния CAT-интерфейса запускается в бесконечном цикле main.c. Обработчик проверяет наличие подключения по виртуальному COM-порту, и если оно есть, то проверяется наличие данных в буфере CAT-интерфейса.

Если данные в буфере есть, обработчик извлекает из буфера пять байт данных и распознаёт команду по списку поддерживаемых. Если команда распознана, запускается обработчик команды, который обращается или к ptt_if.c, или к vfo_if.c. По результатам обработки формируется отклик, который передаётся в компьютер через виртуальный COM-порт.

Наиболее часто трансивер получает две команды: FT817_GET_FREQ (код команды 0x03) и FT817_READ_TX_STATE (0xF7). По ним он возвращает частоту настройки, вид модуляции, текущий режим приём/передача и режим работы на разнесённых частотах.

Виртуальный COM-порт


Виртуальный COM-порт создан на основе IP Commucation Device Class.

Команды CAT передаются из приёмного буфера CDC в приёмный буфер CAT функцией CDC_Receive_FS из состава файла usbd_cdc_if.c, расположенного в папке USB_DEVICE\App.

Отклик на команды передаётся из обработчика команд CAT-интерфейса запуском функции CDC_Transmit_FS.

Для корректной работы COM-порта в его буфер необходимо прописать параметры подключения:
static int8_t CDC_Init_FS(void){  /* USER CODE BEGIN 3 */  USBD_CDC_HandleTypeDef   *hcdc;  USBD_CDC_LineCodingTypeDef line_coding =  {    /* 9600 8n1 */    .bitrate    = 9600U, /* Data terminal rate, in bits per second */    .format     = 0U,    /* Stop bits: 0 - 1 Stop bit */    .paritytype = 0U,    /* Parity:    0 - None */    .datatype   = 8U,    /* Data bits */  };  hcdc = (USBD_CDC_HandleTypeDef*) hUsbDeviceFS.pClassData;  memcpy ((uint8_t*) hcdc, &line_coding, 7U);  /* Set Application Buffers */  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);  return (USBD_OK);  /* USER CODE END 3 */} 

Без этой записи в буфере OmniRig к COM-порту может и не подключиться.

От автора



Данное решение CAT-интерфейса может работать с любыми доступными радиолюбителям синтезаторами частоты и контроллерами дисплеев с минимальными переделками main.c и vfo_if.c.

Мне будет очень приятно, если эта публикация поможет кому-нибудь реализовать управление по CAT своим радиоприёмником или радиостанцией.

Подробнее..

Составное устройство USB на STM32. Часть 2 USB Audio Speaker

04.03.2021 10:11:49 | Автор: admin

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

В первой части публикации были описаны предпосылки запуска проекта по разработке составного устройства USB и приведены общие сведения о назначении и составе устройства.

Ссылка на первую часть публикации:
Составное устройство USB на STM32. Часть 1: Предпосылки

Подготовка проекта


Проект был создан в STM32CubeIDE из шаблона для платы NUCLEO-F446ZE. Особенностью платы является наличие двух разъёмов USB, к одному из которых подключены встроенный в плату ST-Link V2.1 и виртуальный COM-порт с подключенным к нему UART3. Через этот разъём USB может также осуществляться электропитание платы.

К виртуальному COM-порту можно подключиться на скорости 115200 bps любой терминальной программой и использовать этот канал связи для приёма сообщений при отладке. Прерывание для UART3 по умолчанию отключено, его надо включить.

Пользовательское устройство USB Full Speed использует второй разъём USB. Для корректной работы порта USB в составе проекта опцию Activate_VBUS нужно отключить.


При настройке конфигурации порта была обнаружена интересная особенность: при включении опции Low power микроконтроллер терял связь с интерфейсом SWD. К счастью, встроенный в плату ST-Link поддерживает режим Connect under reset, что позволяет выводить MCU из состояния кирпича без применения дополнительных аппаратных средств.

Создаём Audio Device Class


Приступим к созданию двухканального дуплексного звукового устройства USB, для чего переходим в раздел Middleware и выбираем IP Audio Device Class. Задаём максимальное количество интерфейсов равное трём. Частоту дискретизации устанавливаем равной 48000 samples/s.


Сохраняем проект. Запускаем генерацию кода. Пытаемся разобраться, что получилось в результате.

Хочу отметить, что использование STM32CubeMX и библиотеки HAL позволяет прятать под капот большой объём кода. Для профессиональной разработки такой подход может быть и не приемлем, но для любительского проекта экономит много времени и сил.

Из всего проекта нас пока интересуют только файлы, расположенные в папках USB_DEVICE/App и Middlewares/ST/Class/AUDIO.

Для начала разберем, как в файле usb_device.c происходит процесс формирования и запуска устройства USB:

#include "usb_device.h"#include "usbd_core.h"#include "usbd_desc.h"#include "usbd_audio.h"#include "usbd_audio_if.h"USBD_HandleTypeDef hUsbDeviceFS;void MX_USB_DEVICE_Init (void){  USBD_Init (&hUsbDeviceFS, &FS_Desc, DEVICE_FS);  USBD_RegisterClass (&hUsbDeviceFS, &USBD_AUDIO);  USBD_AUDIO_RegisterInterface (&hUsbDeviceFS, &USBD_AUDIO_fops_FS);  USBD_Start (&hUsbDeviceFS);}

Сначала создаётся переменная hUsbDeviceFS. Тип USBD_HandleTypeDef объявлен в usbd_def.h.

Функция MX_USB_DEVICE_Init вызывается из main.c.

Вызовом функции USBD_Init задаются начальные значения переменной hUsbDeviceFS.

Вызовом функции USBD_RegisterClass в hUsbDeviceFS.pClass размещается указатель на созданную в usbd_audio.c переменную USBD_AUDIO, содержащую указатели на обработчики событий, относящихся к классу устройства. Тип USBD_ClassTypeDef объявлен в usbd_def.h.

Вызовом функции USBD_RegisterInterface в hUsbDeviceFS.pUserData размещается указатель на созданную в usbd_audio_if.c переменную USBD_AUDIO_fops_FS, содержащую указатели на обработчики событий, относящихся к пользовательскому интерфейсу устройства. Тип USBD_AUDIO_ItfTypeDef объявлен в usbd_audio.h.

Вызовом функции USBD_Start производится запуск устройства USB.

Читаем дескрипторы


Дескрипторы устройств USB являются своеобразными техническими паспортами или руководствами по эксплуатации, из которых хост получает всю необходимую информацию о составе устройства USB и режимах его работы.

Что именно хост получает от сгенерированного в STM32CubeMX звукового устройства, можно узнать с помощью бесплатной утилиты Thesycon USB Descriptor Dumper.

Посмотреть листинг дескриптора
Information for device STM32 Audio Class (VID=0x0483 PID=0x5740):Connection Information:------------------------------Device current bus speed: FullSpeedDevice supports USB 1.1 specificationDevice supports USB 2.0 specificationDevice address: 0x000ACurrent configuration value: 0x00Number of open pipes: 0Device Descriptor:------------------------------0x12bLength0x01bDescriptorType0x0200bcdUSB0x00bDeviceClass      0x00bDeviceSubClass   0x00bDeviceProtocol   0x40bMaxPacketSize0   (64 bytes)0x0483idVendor0x5740idProduct0x0200bcdDevice0x01iManufacturer0x02iProduct0x03iSerialNumber0x01bNumConfigurationsConfiguration Descriptor:------------------------------0x09bLength0x02bDescriptorType0x006DwTotalLength   (109 bytes)0x02bNumInterfaces0x01bConfigurationValue0x00iConfiguration0xC0bmAttributes   (Self-powered Device)0x32bMaxPower      (100 mA)Interface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x00bInterfaceNumber0x00bAlternateSetting0x00bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x01bInterfaceSubClass   (Audio Control Interface)0x00bInterfaceProtocol   0x00iInterfaceAC Interface Header Descriptor:------------------------------0x09bLength0x24bDescriptorType0x01bDescriptorSubtype0x0100bcdADC0x0027wTotalLength   (39 bytes)0x01bInCollection0x01baInterfaceNr(1)AC Input Terminal Descriptor:------------------------------0x0CbLength0x24bDescriptorType0x02bDescriptorSubtype0x01bTerminalID0x0101wTerminalType   (USB Streaming)0x00bAssocTerminal0x01bNrChannels   (1 channels)0x0000wChannelConfig0x00iChannelNames0x00iTerminalAC Feature Unit Descriptor:------------------------------0x09bLength0x24bDescriptorType0x06bDescriptorSubtype0x02bUnitID0x01bSourceID0x01bControlSizebmaControls:  0x01Channel(0) 0x00Channel(1)0x00iFeatureAC Output Terminal Descriptor:------------------------------0x09bLength0x24bDescriptorType0x03bDescriptorSubtype0x03bTerminalID0x0301wTerminalType   (Speaker)0x00bAssocTerminal0x02bSourceID0x00iTerminalInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x01bInterfaceNumber0x00bAlternateSetting0x00bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x01bInterfaceNumber0x01bAlternateSetting0x01bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceAS Interface Descriptor:------------------------------0x07bLength0x24bDescriptorType0x01bDescriptorSubtype0x01bTerminalLink0x01bDelay0x0001wFormatTag   (PCM)AS Format Type 1 Descriptor:------------------------------0x0BbLength0x24bDescriptorType0x02bDescriptorSubtype0x01bFormatType   (FORMAT_TYPE_1)0x02bNrChannels   (2 channels)0x02bSubframeSize0x10bBitResolution   (16 bits per sample)0x01bSamFreqType   (Discrete sampling frequencies)0x00BB80 tSamFreq(1)   (48000 Hz)Endpoint Descriptor (Audio/MIDI 1.0):------------------------------0x09bLength0x05bDescriptorType0x01bEndpointAddress  (OUT endpoint 1)0x01bmAttributes      (Transfer: Isochronous / Synch: None / Usage: Data)0x00C0wMaxPacketSize    (1 x 192 bytes)0x01bInterval         (1 frames)0x00bRefresh0x00bSynchAddressAS Isochronous Data Endpoint Descriptor:------------------------------0x07bLength0x25bDescriptorType0x01bDescriptorSubtype0x00bmAttributes0x00bLockDelayUnits   (undefined)0x0000wLockDelayMicrosoft OS Descriptor is not available. Error code: 0x0000001FString Descriptor Table--------------------------------Index  LANGID  String0x00   0x0000  0x01   0x0000  Request failed with 0x0000001F0x02   0x0000  Request failed with 0x0000001F0x03   0x0000  Request failed with 0x0000001F------------------------------Connection path for device: xHCI-??????????? ????-?????????? USBRoot HubSTM32 Audio Class (VID=0x0483 PID=0x5740) Port: 2Running on: Windows 10 or greaterBrought to you by TDD v2.11.0, Mar 26 2018, 09:54:50


Данные из листинга становятся более понятными, если обратиться к следующим документам:

[2] Universal Serial Bus Audio Device Class Specification for Basic Audio Devices. Release 1.0. November 24, 2006
[3] Universal Serial Bus Device Class Definition for Audio Devices. Release 1.0. March 18, 1998

Из раздела Device Descriptor мы видим, что устройство поддерживает USB 2.0, имеет единственную конфигурацию, и что класс, подкласс и протокол устройства определяются классом, подклассом и протоколом интерфейса.

Из раздела Configuration Descriptor мы видим, что длина дескриптора конфигурации класса устройства составляет 109 байт, что в устройство входят два интерфейса, что устройство самозапитанное (self-powered) и не может потреблять от шины USB ток более 100 мА.

Далее идёт описание интерфейса управления (Audio Control Interface, AC), из которого мы узнаём, что структура устройства выглядит так:


Подробней об этой структуре можно прочитать в [2] на стр.15, 19 26.

Для связи с хостом интерфейс управления использует конечную точку 0 (EP0).

Данные дескриптора интерфейса воспроизведения (Audio Streaming Interface, AS) описаны в [2] на стр.30 34. Сначала идёт описание интерфейса, затем описание используемых им конечных точек.

У интерфейса воспроизведения есть два состояния:

  • в состоянии Alternate Setting 0 интерфейс не использует ни одной конечной точки и имеет нулевую полосу пропускания;
  • в состоянии Alternate Setting 1 интерфейс использует одну конечную точку и принимает поток данных для воспроизведения по двум каналам 16-битного звука с частотой дискретизации 48 кГц.

Конечная точка с адресом 0x01 работает в асинхронном изохронном режиме и принимает пакеты размером ((48000 Гц * 2 байта * 2 канала) / 1000 мс) = 192 байта с интервалом 1 мс.

Разбираем работу устройства


Файлы сгенерированного в STM32CubeMX драйвера звукового устройства USB расположены в папках Middlewares/ST/Class/AUDIO и USB_DEVICE.

Функции, с помощью которых драйвер звукового устройства взаимодействует со своим оконечным оборудованием (например ЦАП или кодеком), содержатся в файле usbd_audio_if.c.

Во время инициализации устройства функции AUDIO_Init_FS передаются значения частоты дискретизации в герцах и начального уровня громкости. Эти данные могут быть использованы для инициализации оконечного оборудования.

После первоначального заполнения циклического буфера звукового устройства драйвер формирует команду AUDIO_CMD_START и передаёт оконечному оборудованию указатель типа uint8_t* на начало буфера и число типа uint_32, равное половине длины буфера в байтах.

В идеальном случае, когда скорость чтения данных оконечным устройством из буфера и скорость приёма данных по USB совпадают, было бы достаточно запустить оконечное оборудование на вывод данных с параметрами, преданными вместе с командой AUDIO_CMD_START, прямо из циклического буфера звукового устройства.

В реальном же мире потребуется синхронизация скорости потоков данных. В сгенерированном в STM32CubeMX звуковом устройстве это реализовано путём подгонки скорости вывода данных через оконечное оборудование под скорость приёма данных по USB.

Обратная связь организована через вызов оконечным оборудованием функции HalfTransfer_CallBack_FS после окончания чтения половины буфера, а затем вызов функции TransferComplete_CallBack_FS после полного окончания чтения буфера.

При запуске функции TransferComplete_CallBack_FS драйвер звукового устройства формирует команду AUDIO_CMD_PLAY и сравнивает скорости записи в буфер и чтения из буфера по положению указателей чтения и записи. Если расстояние между этими указателями меньше четверти размера буфера, оконечному оборудованию передаётся указатель типа uint8_t* на начало буфера, а также число типа uint_32, равное уменьшенной на 4 половине длины буфера в байтах, если чтение происходит медленней записи, или увеличенной на 4 половине длины буфера в байтах, если чтение происходит быстрей.

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

От автора


В следующей части публикации мы:

  • дополним звуковое устройство USB трактом записи;
  • приведем дескриптор звукового устройства USB в читаемый вид;
  • сохраним доработанный драйвер звукового устройства USB в безопасное место;
  • сгенерируем в STM32CubeMX драйвер виртуального COM-порта.
Подробнее..

Составное устройство USB на STM32. Часть 3 Звуковое устройство отдельно, виртуальный СОМ-порт отдельно

09.03.2021 08:15:06 | Автор: admin

В третьей части публикации о составном устройстве USB я расскажу о том, как переделать сгенерированный в STM32CubeMX USB Audio Speaker, описанный во второй части публикации, в дуплексное звуковое устройство.

Затем мы создадим в STM32CubeMX драйвер виртуального COM-порта.

Зачем мы всё это делаем, подробно описано в первой части публикации.

Ссылки на первую и вторую части публикации:
Составное устройство USB на STM32. Часть 1: Предпосылки
Составное устройство USB на STM32. Часть 2: USB Audio Speaker

Исходные коды публикуемой реализации составного устройства USB, состоящего из виртуального COM-порта и дуплексной звуковой карты находятся здесь: http://github.com/dmitrii-rudnev/selenite-habr

Доработка дескриптора


Дорабатываемый дескриптор размещается STM32CubeMX в файле usbd_audio.c. В работе использовались документы [2] и [3].

Обилие в сгенерированном дескрипторе макросов, заданных в файле usbd_audio.h, на мой взгляд, затрудняет работу с ним. Поэтому я заменил большую часть макросов на шестнадцатеричные значения, чтобы части дескриптора выглядели подобно их описанию в таблицах из [2] и [3], а также как в листинге, сгенерированном утилитой Thesycon USB Descriptor Dumper.

Однако, для удобства конфигурирования отдельные макросы пришлось оставить, а также добавить несколько новых:
// Размер дескриптора конфигурации#define USB_AUDIO_CONFIG_DESC_SIZ  192U// Номера интерфейсов#define AUDIO_CTRL_IF              0x00U#define AUDIO_OUT_IF               0x01U#define AUDIO_IN_IF                0x02U// Номера конечных точек (EP)#define AUDIO_OUT_EP               0x01U#define AUDIO_IN_EP                0x81U// Размер пакета и размер циклического буфера#define AUDIO_OUT_PACKET_NUM       4U // 80U#define USBD_AUDIO_FREQ            48000U#define AUDIO_OUT_PACKET           (uint16_t)(((USBD_AUDIO_FREQ * 2U * 2U) / 1000U))#define AUDIO_TOTAL_BUF_SIZE       (uint16_t)(AUDIO_OUT_PACKET * AUDIO_OUT_PACKET_NUM))

Хотел бы заострить внимание на том, что размеры циклических буферов трактов записи и воспроизведения определяются значением AUDIO_OUT_PACKET_NUM. Для стабильной работы драйвера достаточно использовать буферы размером 4 пакета, в то время как размер по умолчанию равен 80 пакетам.

Доработанный дескриптор описывает дуплексное звуковое устройство USB со структурой, приведённой на рисунке ниже:


Устройства ID2 и ID5 (Feature Unit) оставлены в структуре звукового устройства на вырост. Управление ими осуществляется через Class-Specific Requests. При обработке этих запросов драйвер звукового устройства должен передавать оконечному устройству набор команд для управления уровнями громкости, настройками эквалайзера, звукового процессора и т.п. В доработанном дескрипторе набор этот состоит пока из одной только команды MUTE.

Посмотреть листинг доработанного дескриптора
Information for device STM32 Audio Class (VID=0x0483 PID=0x5740):Connection Information:------------------------------Device current bus speed: FullSpeedDevice supports USB 1.1 specificationDevice supports USB 2.0 specificationDevice address: 0x0008Current configuration value: 0x01Number of open pipes: 0Device Descriptor:------------------------------0x12bLength0x01bDescriptorType0x0201bcdUSB0x00bDeviceClass      0x00bDeviceSubClass   0x00bDeviceProtocol   0x40bMaxPacketSize0   (64 bytes)0x0483idVendor0x5740idProduct0x0200bcdDevice0x01iManufacturer   "STMicroelectronics"0x02iProduct   "STM32 Audio Class"0x03iSerialNumber   "317C33753434"0x01bNumConfigurationsConfiguration Descriptor:------------------------------0x09bLength0x02bDescriptorType0x00C0wTotalLength   (192 bytes)0x03bNumInterfaces0x01bConfigurationValue0x00iConfiguration0xC0bmAttributes   (Self-powered Device)0xFAbMaxPower      (500 mA)Interface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x00bInterfaceNumber0x00bAlternateSetting0x00bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x01bInterfaceSubClass   (Audio Control Interface)0x00bInterfaceProtocol   0x00iInterfaceAC Interface Header Descriptor:------------------------------0x0AbLength0x24bDescriptorType0x01bDescriptorSubtype0x0100bcdADC0x0046wTotalLength   (70 bytes)0x02bInCollection0x01baInterfaceNr(1)0x02baInterfaceNr(2)AC Input Terminal Descriptor:------------------------------0x0CbLength0x24bDescriptorType0x02bDescriptorSubtype0x01bTerminalID0x0101wTerminalType   (USB Streaming)0x00bAssocTerminal0x02bNrChannels   (2 channels)0x0003wChannelConfig0x00iChannelNames0x00iTerminalAC Feature Unit Descriptor:------------------------------0x09bLength0x24bDescriptorType0x06bDescriptorSubtype0x02bUnitID0x01bSourceID0x01bControlSizebmaControls:  0x01Channel(0) 0x00Channel(1)0x00iFeatureAC Output Terminal Descriptor:------------------------------0x09bLength0x24bDescriptorType0x03bDescriptorSubtype0x03bTerminalID0x0301wTerminalType   (Speaker)0x00bAssocTerminal0x02bSourceID0x00iTerminalAC Input Terminal Descriptor:------------------------------0x0CbLength0x24bDescriptorType0x02bDescriptorSubtype0x04bTerminalID0x0200wTerminalType   (Input Undefined)0x00bAssocTerminal0x02bNrChannels   (2 channels)0x0003wChannelConfig0x00iChannelNames0x00iTerminalAC Feature Unit Descriptor:------------------------------0x09bLength0x24bDescriptorType0x06bDescriptorSubtype0x05bUnitID0x04bSourceID0x01bControlSizebmaControls:  0x01Channel(0) 0x00Channel(1)0x00iFeatureAC Output Terminal Descriptor:------------------------------0x09bLength0x24bDescriptorType0x03bDescriptorSubtype0x06bTerminalID0x0101wTerminalType   (USB Streaming)0x00bAssocTerminal0x05bSourceID0x00iTerminalInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x01bInterfaceNumber0x00bAlternateSetting0x00bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x01bInterfaceNumber0x01bAlternateSetting0x01bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceAS Interface Descriptor:------------------------------0x07bLength0x24bDescriptorType0x01bDescriptorSubtype0x01bTerminalLink0x01bDelay0x0001wFormatTag   (PCM)AS Format Type 1 Descriptor:------------------------------0x0BbLength0x24bDescriptorType0x02bDescriptorSubtype0x01bFormatType   (FORMAT_TYPE_1)0x02bNrChannels   (2 channels)0x02bSubframeSize0x10bBitResolution   (16 bits per sample)0x01bSamFreqType   (Discrete sampling frequencies)0x00BB80 tSamFreq(1)   (48000 Hz)Endpoint Descriptor (Audio/MIDI 1.0):------------------------------0x09bLength0x05bDescriptorType0x01bEndpointAddress  (OUT endpoint 1)0x01bmAttributes      (Transfer: Isochronous / Synch: None / Usage: Data)0x00C0wMaxPacketSize    (1 x 192 bytes)0x01bInterval         (1 frames)0x00bRefresh0x00bSynchAddressAS Isochronous Data Endpoint Descriptor:------------------------------0x07bLength0x25bDescriptorType0x01bDescriptorSubtype0x00bmAttributes0x00bLockDelayUnits   (undefined)0x0000wLockDelayInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x02bInterfaceNumber0x00bAlternateSetting0x00bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x02bInterfaceNumber0x01bAlternateSetting0x01bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceAS Interface Descriptor:------------------------------0x07bLength0x24bDescriptorType0x01bDescriptorSubtype0x06bTerminalLink0x01bDelay0x0001wFormatTag   (PCM)AS Format Type 1 Descriptor:------------------------------0x0BbLength0x24bDescriptorType0x02bDescriptorSubtype0x01bFormatType   (FORMAT_TYPE_1)0x02bNrChannels   (2 channels)0x02bSubframeSize0x10bBitResolution   (16 bits per sample)0x01bSamFreqType   (Discrete sampling frequencies)0x00BB80 tSamFreq(1)   (48000 Hz)Endpoint Descriptor (Audio/MIDI 1.0):------------------------------0x09bLength0x05bDescriptorType0x81bEndpointAddress  (IN endpoint 1)0x01bmAttributes      (Transfer: Isochronous / Synch: None / Usage: Data)0x00C0wMaxPacketSize    (1 x 192 bytes)0x01bInterval         (1 frames)0x00bRefresh0x00bSynchAddressAS Isochronous Data Endpoint Descriptor:------------------------------0x07bLength0x25bDescriptorType0x01bDescriptorSubtype0x00bmAttributes0x00bLockDelayUnits   (undefined)0x0000wLockDelayMicrosoft OS Descriptor is not available. Error code: 0x0000001FString Descriptor Table--------------------------------Index  LANGID  String0x00   0x0000  0x0409 0x01   0x0409  "STMicroelectronics"0x02   0x0409  "STM32 Audio Class"0x03   0x0409  "317C33753434"------------------------------Connection path for device: xHCI-??????????? ????-?????????? USBRoot HubSTM32 Audio Class (VID=0x0483 PID=0x5740) Port: 2Running on: Windows 10 or greaterBrought to you by TDD v2.11.0, Mar 26 2018, 09:54:50


Доработка драйвера звукового устройства USB


При доработке драйвера в структуру звукового устройства был добавлен циклический буфер тракта записи, а состав команд, передаваемых пользовательскому интерфейсу, расширен командами AUDIO_CMD_STOP и AUDIO_CMD_RECORD.

Тракт записи дуплексного звукового устройства USB начинает работу при установке интерфейса AUDIO_IN_IF в состояние Alternate Setting 1, после чего драйвер ожидает событие SOF, во время обработки которого формирует команду AUDIO_CMD_RECORD, по которой заполняет половину буфера тракта записи пакетами из буфера DSP. Далее эти пакеты передаются из циклического буфера тракта записи вовне через конечную точку AUDIO_IN_EP.

После того, как тракт записи был запущен, команда AUDIO_CMD_RECORD формируется драйвером после окончания передачи каждой половины циклического буфера тракта записи.

Особенностью использования конечной точки AUDIO_IN_EP драйвером звукового устройства является необходимость запуска USBD_LL_FlushEP(pdev, AUDIO_IN_EP) для очистки буфера конечной точки после окончания передачи каждого пакета.

Тракт воспроизведения дуплексного звукового устройства USB включается при установке интерфейса AUDIO_OUT_IF в состояние Alternate Setting 1. Команда AUDIO_CMD_PLAY формируется драйвером звукового устройства по событию заполнения каждой половины циклического буфера тракта воспроизведения, после чего эти пакеты передаются в буфер DSP.

Команда AUDIO_CMD_STOP формируется драйвером при установке интерфейса AUDIO_OUT_IF в состояние Alternate Setting 0, после чего DSP включает в тракте воспроизведения режим тишины.

Синхронизация потоков данных доработанным драйвером не производится, поэтому функция USBD_AUDIO_Sync не производит никаких действий и оставлена в составе драйвера только для совместимости.

Проверка работоспособности драйвера дуплексного звукового устройства USB


При генерации драйвера виртуального COM-порта STM32CubeMX удалит из проекта файлы драйвера звукового устройства. Поэтому переносим usbd_audio.c и usbd_audio_if.c в папку Core/Scr, а usbd_audio.h и usbd_audio_if.h в Core/Inc.

Пересобираем проект, перепрошиваем устройство. Подключаем устройство к компьютеру, включаем тракт записи через панель управления звуком. Назначаем тракты воспроизведения и записи дуплексного звукового устройства USB устройствами по умолчанию.

Для демонстрации работоспособности драйвера звукового устройства USB данные с выхода тракта воспроизведения поступают на вход тракта записи через шлейф, организованный в буфере DSP (см. файл dsp_if.c). Программная реализация шлейфа выбрана, чтобы не подключать к отладочной плате никаких дополнительных устройств и не синхронизировать никакие потоки.

Включаем в панели управления звуком для тракта записи нашего устройства прослушивание через звуковую карту компьютера. Убеждаемся в работоспособности драйвера дуплексного звукового устройства USB.

Создаём Communication Device Class


Приступаем к созданию виртуального COM-порта, для чего переходим в раздел Middleware и выбираем IP Commucation Device Class. Задаём максимальное количество интерфейсов равное пяти. Размер буферов задаём равным 64 Bytes.



Интерфейсов пять, т.к. в составе дуплексного звукового устройства их три, а в составе виртуального COM-порта два.

Сохраняем проект. Генерируем код. Смотрим, что получилось в результате.

Разбираем работу устройства


Файлы сгенерированного в STM32CubeMX драйвера виртуального COM-порта расположены в папках Middlewares/ST/Class/CDC и USB_DEVICE.

Функции, с помощью которых драйвер виртуального COM-порта взаимодействует со своим оконечным оборудованием, содержатся в файле usbd_cdc_if.c.

Во время инициализации устройства функция CDC_Init_FS задаёт настройки буферов трактов приёма и передачи.

При получении команд управления драйвер виртуального COM-порта запускает функцию CDC_Control_FS. Список команд управления приводится на стр.19 документа:

[4] Universal Serial Bus Communications Class Subclass Specification for PSTN Devices, Revision 1.2, February 9, 2007

В описании функции следует обратить внимание на структуру переменных типа USBD_CDC_LineCodingTypeDef, объявленного в usbd_cdc.h. При дальнейшем использовании драйвера мы можем с помощью переменной такого типа жёстко задать параметры COM-порта, которые он передаёт вовне по запросу.

Функция CDC_Receive_FS запускается по событию получения данных по виртуальному COM-порту.

Для передачи данных по виртуальному COM-порту используется функция CDC_Transmit_FS.

Проверка работоспособности драйвера виртуального COM-порта


Виртуальный COM-порт начинает работать прямо из коробки. Для контроля работоспособности организуем функцию эха.

Открываем в папке USB_DEVICE\App файл usbd_cdc_if.c и добавляем в функцию CDC_Receive_FS шлейф, как показано ниже:
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len){  /* USER CODE BEGIN 6 */  CDC_Transmit_FS (Buf, *Len); //++++++  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);  USBD_CDC_ReceivePacket(&hUsbDeviceFS);  return (USBD_OK);  /* USER CODE END 6 */}

Собираем проект, прошиваем устройство. Подключаем устройство к компьютеру, обнаруживаем новый COM-порт, при необходимости устанавливаем на компьютер драйверы.

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

От автора


В следующей части публикации мы объединим виртуальный COM-порт и дуплексное звуковое устройство в составное устройство USB и разберём несколько не совсем очевидных нюансов этого объединения.
Подробнее..

Составное устройство USB на STM32. Часть 4 Два-в-одном

11.03.2021 10:22:28 | Автор: admin

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

Работа составных частей устройства была описана во второй и третьей частях публикации.

Ответы на вопрос, зачем это всё было затеяно, даются в начале первой части и в конце четвёртой.

Ссылки на предыдущие части публикации:
Составное устройство USB на STM32. Часть 1: Предпосылки
Составное устройство USB на STM32. Часть 2: USB Audio Speaker
Составное устройство USB на STM32. Часть 3: Звуковое устройство отдельно, виртуальный СОМ-порт отдельно

Исходные коды публикуемой реализации составного устройства USB, состоящего из виртуального COM-порта и дуплексной звуковой карты находятся здесь: http://github.com/dmitrii-rudnev/selenite-habr

Создаём Composite Device Class


Файлы драйвера составного устройства 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
Information for device Selenite TRX (VID=0x0483 PID=0x5740):Connection Information:------------------------------Device current bus speed: FullSpeedDevice supports USB 1.1 specificationDevice supports USB 2.0 specificationDevice address: 0x0014Current configuration value: 0x00Number of open pipes: 0Device Descriptor:------------------------------0x12bLength0x01bDescriptorType0x0201bcdUSB0xEFbDeviceClass      (Miscellaneous device)0x02bDeviceSubClass   0x01bDeviceProtocol   0x40bMaxPacketSize0   (64 bytes)0x0483idVendor0x5740idProduct0x0200bcdDevice0x01iManufacturer   "STMicroelectronics"0x02iProduct   "Selenite TRX"0x03iSerialNumber   "317C33753434"0x01bNumConfigurationsConfiguration Descriptor:------------------------------0x09bLength0x02bDescriptorType0x010AwTotalLength   (266 bytes)0x05bNumInterfaces0x01bConfigurationValue0x00iConfiguration0xC0bmAttributes   (Self-powered Device)0xFAbMaxPower      (500 mA)Interface Association Descriptor:------------------------------0x08bLength0x0BbDescriptorType0x00bFirstInterface0x02bInterfaceCount0x02bFunctionClass      (Communication Device Class)0x02bFunctionSubClass   (Abstract Control Model - ACM)0x01bFunctionProtocol   (ITU-T V.250)0x00iFunctionInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x00bInterfaceNumber0x00bAlternateSetting0x01bNumEndPoints0x02bInterfaceClass      (Communication Device Class)0x02bInterfaceSubClass   (Abstract Control Model - ACM)0x01bInterfaceProtocol   (ITU-T V.250)0x00iInterfaceCDC Header Functional Descriptor:------------------------------0x05bFunctionalLength0x24bDescriptorType0x00bDescriptorSubtype0x0110bcdCDCCDC Call Management Functional Descriptor:------------------------------0x05bFunctionalLength0x24bDescriptorType0x01bDescriptorSubtype0x00bmCapabilities0x01bDataInterfaceCDC Abstract Control Management Functional Descriptor:------------------------------0x04bFunctionalLength0x24bDescriptorType0x02bDescriptorSubtype0x02bmCapabilitiesCDC Union Functional Descriptor:------------------------------0x05bFunctionalLength0x24bDescriptorType0x06bDescriptorSubtype0x00bControlInterface0x01bSubordinateInterface(0)Endpoint Descriptor:------------------------------0x07bLength0x05bDescriptorType0x82bEndpointAddress  (IN endpoint 2)0x03bmAttributes      (Transfer: Interrupt / Synch: None / Usage: Data)0x0008wMaxPacketSize    (1 x 8 bytes)0x10bInterval         (16 frames)Interface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x01bInterfaceNumber0x00bAlternateSetting0x02bNumEndPoints0x0AbInterfaceClass      (CDC Data)0x00bInterfaceSubClass   0x00bInterfaceProtocol   0x00iInterfaceEndpoint Descriptor:------------------------------0x07bLength0x05bDescriptorType0x01bEndpointAddress  (OUT endpoint 1)0x02bmAttributes      (Transfer: Bulk / Synch: None / Usage: Data)0x0040wMaxPacketSize    (64 bytes)0x00bInterval         Endpoint Descriptor:------------------------------0x07bLength0x05bDescriptorType0x81bEndpointAddress  (IN endpoint 1)0x02bmAttributes      (Transfer: Bulk / Synch: None / Usage: Data)0x0040wMaxPacketSize    (64 bytes)0x00bInterval         Interface Association Descriptor:------------------------------0x08bLength0x0BbDescriptorType0x02bFirstInterface0x03bInterfaceCount0x01bFunctionClass      (Audio Device Class)0x01bFunctionSubClass   (Audio Control Interface)0x00bFunctionProtocol   0x00iFunctionInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x02bInterfaceNumber0x00bAlternateSetting0x00bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x01bInterfaceSubClass   (Audio Control Interface)0x00bInterfaceProtocol   0x00iInterfaceAC Interface Header Descriptor:------------------------------0x0AbLength0x24bDescriptorType0x01bDescriptorSubtype0x0100bcdADC0x0046wTotalLength   (70 bytes)0x02bInCollection0x03baInterfaceNr(1)0x04baInterfaceNr(2)AC Input Terminal Descriptor:------------------------------0x0CbLength0x24bDescriptorType0x02bDescriptorSubtype0x01bTerminalID0x0101wTerminalType   (USB Streaming)0x00bAssocTerminal0x02bNrChannels   (2 channels)0x0003wChannelConfig0x00iChannelNames0x00iTerminalAC Feature Unit Descriptor:------------------------------0x09bLength0x24bDescriptorType0x06bDescriptorSubtype0x02bUnitID0x01bSourceID0x01bControlSizebmaControls:  0x01Channel(0) 0x00Channel(1)0x00iFeatureAC Output Terminal Descriptor:------------------------------0x09bLength0x24bDescriptorType0x03bDescriptorSubtype0x03bTerminalID0x0301wTerminalType   (Speaker)0x00bAssocTerminal0x02bSourceID0x00iTerminalAC Input Terminal Descriptor:------------------------------0x0CbLength0x24bDescriptorType0x02bDescriptorSubtype0x04bTerminalID0x0200wTerminalType   (Input Undefined)0x00bAssocTerminal0x02bNrChannels   (2 channels)0x0003wChannelConfig0x00iChannelNames0x00iTerminalAC Feature Unit Descriptor:------------------------------0x09bLength0x24bDescriptorType0x06bDescriptorSubtype0x05bUnitID0x04bSourceID0x01bControlSizebmaControls:  0x01Channel(0) 0x00Channel(1)0x00iFeatureAC Output Terminal Descriptor:------------------------------0x09bLength0x24bDescriptorType0x03bDescriptorSubtype0x06bTerminalID0x0101wTerminalType   (USB Streaming)0x00bAssocTerminal0x05bSourceID0x00iTerminalInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x03bInterfaceNumber0x00bAlternateSetting0x00bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x03bInterfaceNumber0x01bAlternateSetting0x01bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceAS Interface Descriptor:------------------------------0x07bLength0x24bDescriptorType0x01bDescriptorSubtype0x01bTerminalLink0x01bDelay0x0001wFormatTag   (PCM)AS Format Type 1 Descriptor:------------------------------0x0BbLength0x24bDescriptorType0x02bDescriptorSubtype0x01bFormatType   (FORMAT_TYPE_1)0x02bNrChannels   (2 channels)0x02bSubframeSize0x10bBitResolution   (16 bits per sample)0x01bSamFreqType   (Discrete sampling frequencies)0x00BB80 tSamFreq(1)   (48000 Hz)Endpoint Descriptor (Audio/MIDI 1.0):------------------------------0x09bLength0x05bDescriptorType0x03bEndpointAddress  (OUT endpoint 3)0x01bmAttributes      (Transfer: Isochronous / Synch: None / Usage: Data)0x00C0wMaxPacketSize    (1 x 192 bytes)0x01bInterval         (1 frames)0x00bRefresh0x00bSynchAddressAS Isochronous Data Endpoint Descriptor:------------------------------0x07bLength0x25bDescriptorType0x01bDescriptorSubtype0x00bmAttributes0x00bLockDelayUnits   (undefined)0x0000wLockDelayInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x04bInterfaceNumber0x00bAlternateSetting0x00bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceInterface Descriptor:------------------------------0x09bLength0x04bDescriptorType0x04bInterfaceNumber0x01bAlternateSetting0x01bNumEndPoints0x01bInterfaceClass      (Audio Device Class)0x02bInterfaceSubClass   (Audio Streaming Interface)0x00bInterfaceProtocol   0x00iInterfaceAS Interface Descriptor:------------------------------0x07bLength0x24bDescriptorType0x01bDescriptorSubtype0x06bTerminalLink0x01bDelay0x0001wFormatTag   (PCM)AS Format Type 1 Descriptor:------------------------------0x0BbLength0x24bDescriptorType0x02bDescriptorSubtype0x01bFormatType   (FORMAT_TYPE_1)0x02bNrChannels   (2 channels)0x02bSubframeSize0x10bBitResolution   (16 bits per sample)0x01bSamFreqType   (Discrete sampling frequencies)0x00BB80 tSamFreq(1)   (48000 Hz)Endpoint Descriptor (Audio/MIDI 1.0):------------------------------0x09bLength0x05bDescriptorType0x83bEndpointAddress  (IN endpoint 3)0x01bmAttributes      (Transfer: Isochronous / Synch: None / Usage: Data)0x00C0wMaxPacketSize    (1 x 192 bytes)0x01bInterval         (1 frames)0x00bRefresh0x00bSynchAddressAS Isochronous Data Endpoint Descriptor:------------------------------0x07bLength0x25bDescriptorType0x01bDescriptorSubtype0x00bmAttributes0x00bLockDelayUnits   (undefined)0x0000wLockDelayMicrosoft OS Descriptor is not available. Error code: 0x0000001FString Descriptor Table--------------------------------Index  LANGID  String0x00   0x0000  0x0409 0x01   0x0409  "STMicroelectronics"0x02   0x0409  "Selenite TRX"0x03   0x0409  "317C33753434"------------------------------Connection path for device: xHCI-??????????? ????-?????????? USBRoot HubSelenite TRX (VID=0x0483 PID=0x5740) Port: 2Running on: Windows 10 or greaterBrought to you by TDD v2.11.0, Mar 26 2018, 09:54:50


Разбираем работу устройства


Рассмотрим доработанный файл usb_device.c, расположенный в папке USB_DEVICE/App:
#include "usb_device.h"#include "usbd_core.h"#include "usbd_desc.h"#include "usbd_cdc.h"#include "usbd_cdc_if.h"/* USER CODE BEGIN Includes */#include "usbd_conf.h"#include "usbd_comp.h"/* USER CODE END Includes *//* USER CODE BEGIN PV */extern PCD_HandleTypeDef hpcd_USB_OTG_FS;/* USER CODE END PV *//* USB Device Core handle declaration. */USBD_HandleTypeDef hUsbDeviceFS;void MX_USB_DEVICE_Init(void){  /* USER CODE BEGIN USB_DEVICE_Init_PreTreatment */  USBD_Init (&hUsbDeviceFS, &FS_Desc, DEVICE_FS);  //HAL_PCDEx_SetRxFiFo (&hpcd_USB_OTG_FS, 0x80);  //HAL_PCDEx_SetTxFiFo (&hpcd_USB_OTG_FS, 0, 0x40);  HAL_PCDEx_SetTxFiFo (&hpcd_USB_OTG_FS, 1, 0x10);  HAL_PCDEx_SetTxFiFo (&hpcd_USB_OTG_FS, 2, 0x10);  HAL_PCDEx_SetTxFiFo (&hpcd_USB_OTG_FS, 3, 0xC0);  USBD_RegisterClass (&hUsbDeviceFS, &USBD_COMP);  USBD_COMP_RegisterInterface (&hUsbDeviceFS, &USBD_COMP_fops_FS);  USBD_Start (&hUsbDeviceFS);  return;  /* USER CODE END USB_DEVICE_Init_PreTreatment */

Сначала создаётся переменная 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 эти изменения будет удалять:

/** USB standard device descriptor. */__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END ={  0x12,                       /*bLength */  USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/#if (USBD_LPM_ENABLED == 1)  0x01,                       /*bcdUSB */ /* changed to USB version 2.01                                             in order to support LPM L1 suspend                                             resume test of USBCV3.0*/#else  0x00,                       /*bcdUSB */#endif /* (USBD_LPM_ENABLED == 1) */  0x02,  //0x02,                     /*bDeviceClass*/  //0x02,                     /*bDeviceSubClass*/  //0x00,                     /*bDeviceProtocol*/  0xEF,                       /*bDeviceClass    = Misc */  0x02,                       /*bDeviceSubClass = Common Class */  0x01,                       /*bDeviceProtocol = IAD */  USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/  LOBYTE(USBD_VID),           /*idVendor*/  HIBYTE(USBD_VID),           /*idVendor*/  LOBYTE(USBD_PID_FS),        /*idProduct*/  HIBYTE(USBD_PID_FS),        /*idProduct*/  0x00,                       /*bcdDevice rel. 2.00*/  0x02,  USBD_IDX_MFC_STR,           /*Index of manufacturer string*/  USBD_IDX_PRODUCT_STR,       /*Index of product string*/  USBD_IDX_SERIAL_STR,        /*Index of serial number string*/  USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/};

Неочевидный нюанс 3: виртуальный COM-порт в данном решении работает корректно только в случае, когда номер используемой им конечной точки меньше, чем номер конечной точки звукового устройства.

Неочевидный нюанс 4: виртуальный COM-порт в данном решении работает корректно только в случае, когда при инициализации в его буфер прописываются параметры порта (см. USBD_COMP_Init). Без этой записи программы терминалов к COM-порту могут и не подключиться.

Проверка работоспособности драйвера составного устройства USB


Соединяем воедино проверки работоспособности драйвера виртуального COM-порта и дуплексного звукового устройства USB. Убеждаемся, что они отлично уживаются.
Неочевидный нюанс 5: при проверке работоспособности эхо через COM-порт возвращается, когда составное устройство уже переключено на COM-порт. В реальном применении устройства передача может начаться, когда подключено звуковое устройство. Чтобы избежать подобной ситуации, перед началом передачи производится вызов функции COMP_CDC_Transmit_FS для подключения драйвера виртуального COM-порта:

/* USER CODE BEGIN INCLUDE */#include "usbd_comp.h"/* USER CODE END INCLUDE */uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len){  uint8_t result = USBD_OK;  /* USER CODE BEGIN 7 */  result = COMP_CDC_Transmit_FS (Buf, Len); //++++++  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;  if (hcdc->TxState != 0){    return USBD_BUSY;  }  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);  /* USER CODE END 7 */  return result;}


Выводы


Автору удалось реализовать составное устройство USB, состоящее из виртуального COM-порта и дуплексной звуковой карты, на ресурсах платы NUCLEO-F446ZE.

Решение оформлено в виде проекта в среде разработки STM32CubeIDE. После генерации кода STM32CubeMX для восстановления работоспособности решения необходимо вручную изменить значения трёх байтов в стандартном дескрипторе устройства USB (USB standard device descriptor), размещённом в файле usbd_desc.c.

От автора


Данный цикл публикаций подводит черту, фиксирует результат проекта, которой мне удалось достичь в одиночку.

Хочу поблагодарить своих читателей за доброжелательность и тёплый приём. Я никогда не был и никогда уже не буду профессиональным разработчиком ПО для микроконтроллеров. И это моя первая публикация про разработку программного обеспечения.

Благодарю Георгия (RX9CIM) за моральную поддержку при запуске проекта.

Отдельная благодарность romanetz_omsk, без которого я бы забросил проект ещё два года назад.

По логике дальнейшего развития MVP нужно приступать к написанию DSP, а это уже достаточно сложная для меня математика. Как это осилить в одиночку, ума не приложу

73! de RD9F
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru