Создание проекта виртуального USB СОМ порта
Прием данных, функция CDC_Receive_FS
Часть 1 Основные сведения о USB
Левчук Александр dslev@yandex.ru
Создание виртуального USB СОМ порта не ограничивается только проектом для устройства на основе микроконтроллера. Вторая часть общего проекта требует написания приложения для хоста, которое будет реализовывать полноценный диалог хост-устройство в соответствии общими задачами проекта. В результате задача проектирования виртуального USB СОМ порта разделяется на две взаимосвязанные части, объединенные общим замыслом. В статье рассматривается как первая часть общего проекта, так и вторая часть, тестовое приложение для хоста. Приложение для хоста выполнено для реальной задачи установки и настройки часов RTC микроконтроллера.
Вы можете обратиться к автору за дополнительными материалами (исходники).
07-Jan-2020
Подключаем к плате stm32f103VE программатор-отладчик ST-Link, подаем питание и подключаем к компьютеру. Затем создадим новый проект на основе упомянутого в предыдущей статье проекта CubeUSB1. Для этого сохраним проект CubeUSB1 под именем CubeUSB_0, далее создаем проект VisualStudio+VisualGDB. В процессе создания проекта может появиться новое окно, предлагающее выполнить обновление некоторых продуктов, например.
Обновляем, все выполняется автоматически (или не обновляем). Продолжаем создание проекта под именем CubeUSB_0, как описано в предыдущей статье. После завершения создания проекта в окне Solution Explorer вы должны увидеть папки и файлы для виртуального СОМ порта.
На этом рисунке вы увидите папку из библиотеки HAL USB_DEVICE и файлы, созданные для работы с USB. Файл usbd_cdc_if.c раскрыт и можно увидеть его структуру.
Далее в свойствах проекта устанавливаем режим работы в памяти RAM и выполняем компиляцию проекта. По завершению компиляции возможно появление ошибки и в главном окне может появиться такое сообщение.
Найдена директория, которую нужно добавить в свойства проекта, нажимаем “Add selected…” и свойства проекта получают дополнения. Повторяем компиляцию. Обратите внимание на удобство работы, не нужно искать, куда добавить директорию, пересматривать весь проект и т.д.
В окне Output увидим результат компиляции.
Размер занимаемой памяти в режиме отладки приблизительно на 10 – 12 килобайт больше, чем режиме Release.
Примечание
Если в процессе работы вы делаете изменения в проекте CubeMX, то проект VisualStudio отображает изменения и предлагает провести повторную компиляцию. Однако не всегда компиляция происходит удачно. В таком случае следует перезагрузить проект VisualStudio.
Прежде чем перейти к рассмотрению файлов USB нужно иметь некоторое представление о строении и связях библиотеки USB, которая обеспечивает реализацию виртуального СОМ порта. Подробней можно изучить в документе UM1847 Getting started with STM32CubeF1 firmware package, который устанавливается вместе с библиотекой в папке документации. Второй документ UM1718 STM32CubeMX for STM32 configuration and initialization C code generation, который тауже устанавливается вместе с CubeMX и находится в папке Help. Однако, для того, чтобы понять взаимосвязь файлов USB и написать свой код виртуального СОМ порта, достаточно, на первых порах, ознакомиться с диаграммой связей, на которой показаны связи приложения с библиотекой высокого уровня HAL и низкоуровневой библиотекой LL. Если ваша задача ограничивается типовым применением, то этих знаний будет достаточно.
В проекте автоматически создано несколько файлов USB, обеспечивающих работу USB СОМ порта. Все файлы можно разделить на две группы, первая:
Файлы в папках STM32Cube HAL / USB_DEVICE. Папки находятся в двух директориях, для заголовочных файлов и для файлов источников. В этих папках находится код драйвера HAL для виртуального USB СОМ порта. Написание собственного кода в этих файлах недоступно (условно), подробней здесь.
Вторая группа, назовем их рабочие файлы. Файлы не скомпонованы в отдельную виртуальную папку. К ним относятся заголовочные файлы gpio.h, main.h, rtc.h, stm32f1xx_hal_conf.h, stm32flxx_it.h, usb_device.h usbd_cdc_if.h, usbd_conf.h, usbd_desc.h и файлы-источники gpio.c, main.с, rtc.c, stm32flxx_hal_msp.c, stm32flxx_it.c, usb_device.c, usbd_cdc_if.c, usbd_conf.c, usbd_desc.c. Имена файлов для USB порта начинаются с префиксов usb и usbd, они предназначены для написания своего кода, который обеспечит функционирование виртуального USB СОМ порта в соответствии с требованиями решаемой задачи. Для проектирования типового USB СОМ порта потребуется только один файл usbd_cdc_if.c со своим заголовочным файлом, в которых будет писаться свой код. Рассмотрим назначение этих файлов подробней:
Файл usbd_cdc_if.c содержит пять функций:
Все функции статические, кроме CDC_Transmit_FS. Код, обеспечивающий функционирование виртуального USB СОМ порта, уже создан CubeMX, потребуется только две последние функции из списка, да и то, функция CDC_Transmit_FS будет вызываться без именений.
Примечание
В случае создания переходника USB-COM потребуется написать код инициализации в функции CDC_Control_FS. Эта функциональность выходит за рамки статьи.
Для приема и передачи данных определены два буфера, приемный
uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]
и передающий uint8_t UserTxBufferFS[APP_TX_DATA_SIZE].
Размеры буферов, по умолчанию, одинаковы и равны 1000 байтов. При необходимости их размеры можно изменить. Хост передает данные на конечную точку в режиме передачи массива (bulk). Функция CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) блокирует передачу из хоста на конечную точку до выхода из функции. Функция вызывается каждый раз при получении нового пакета данных. Данные из приемного буфера UserRxBufferFS передаются в функцию частями по 64 байта максимум или меньше. Для выбора нужного участка приемного буфера следует установить указатель Buf на требуемую порцию данных, на размер принятых данных указывает параметр функции Len. В коде функции нужные вызовы для подготовки приемного буфера уже представлены двумя функциями.
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
}
Примечание
Размеры пакетов для конечных точек In и Out определены в файле usbd_cdc.h. В комментариях, относящихся к определению размеров, указано, что размеры пакетов можно изменить с целью увеличения производительности и скорости передачи. Специальных комментариев (USER CODE…) нет и возможно, что при изменении проекта CubeMX значение этих величин будет установлено по умолчанию. К этой фразе следует подходить с осторожностью, в книге USB Complete (Jan Axelson) для полно скоростных (FS) устройств в режиме bulk указаны размеры пакетов 8, 16, 32, 64, в режиме interrupt размер пакета равен 64 байта. Таким образом, не следует полагать, что можно установить размер пакета более чем 64 байта.
Передача данных в хост ведется в режиме прерывания. Функция CDC_Transmit_FS при вызове передает из буфера передачи не более 64 байта данных. Остальную часть пакета формирует функция USBD_CDC_TransmitPacket(…).
uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
uint8_t result = USBD_OK;
/* USER CODE BEGIN 7 */
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;
}
Для передачи всего буфера UserTxBufferFS потребуется выполнить многократный вызов функции. Эту задачу лучше возложить на подпрограмму, выполняемую на стороне хоста. В таком случае проще планировать возврат данных из устройства.
Для более глубокого изучения обмена данными USB и отладки существенную помощь может оказать программа Device_Monitoring_Studio, которая перехватывает трафик и детально отображает все нюансы передач.
Приложение для хоста TestUSB написано с использованием библиотеки WTL и STL в среде VisualStudio 2013 на языке С++. Приложение выполняет следующие задачи:
На рисунке показано главное окно приложения. В главном окне находятся три окна:
Назначение кнопок управления понятно из текста. Кнопка Adjust RTC предназначена для регулировки (подстройки) делителя часов. В связи с временным использованием обычного часового кварца и необходимостью длительного наблюдения за уходом часов данный режим не прошел окончательную отладку и может функционировать не корректно.
Классы CNtpTime, CNtpSocket, CSntpClient отвечают за связь с сервером точного времени. Первые два класса вспомогательные.
Файл xtime.h содержит функции формирования unix времени. Практически идентичный файл используется в проекте для виртуального порта.
Класс RichEditEx отвечает за окна приложения.
Класс CSTM32VP осуществляет связь с устройством по интерфейсу USB. Для обеспечения диалога класс обеспечивает собственные команды, которыми управляется устройство. Для снижения нагрузки на устройство вся возможная обработка данных производится в этом классе. Более подробно со строением классов можно ознакомиться, скачав заголовочные файлы, а также файл приложения и файл прошивки микроконтроллера здесь.
Мартин М. Инсайдерское руководство по STM32
Агуров П.В. - Практика программирования USB - 2006
Description of STM32F1 HAL and Low-layer drivers
USB Complete. The Developer’s Guide, Fifth Edition, Jan Axelson