Доброго всем дня!
Сегодняшняя статья будет посвящена реализации виртуального COM-порта для микроконтроллеров STM32. Эта тема уже поднималась на нашем сайте (STM32 и USB), но в отличие от всех предыдущих экспериментов сегодня мы будем производить все настройки при помощи STM32CubeMx. Собственно, переходим к делу 🙂
Итак, начинаем с действий, ставших привычными! Создаем новый проект в STM32CubeMx, настраиваем его и выбираем микроконтроллер, для которого мы будем генерировать проект. Я буду использовать отладочную плату STM32F4-Discovery и, соответственно, контроллер STM32F407VG.
С этим никаких сложностей возникнуть не должно, все-таки мы уже много раз проделывали это в предыдущих статьях, посвященных STM32CubeMx (статьи про STM32CubeMx), поэтому давайте сформулируем задачу, которую мы будем сегодня решать.
А задача проста – реализуем поддержку USB Virtual Com Port и отправим тестовый набор данных с платы на ПК. Таким образом, мы должны добиться определения нашей отладочной платы в системе как виртуального COM-порта. А открыв этот порт в какой-нибудь терминальной программе мы должны будем увидеть правильно принятые данные. Перейдем к реализации задуманного!
Первым делом включим поддержку USB в нашем проекте в STM32CubeMx. Во вкладке Pinout ищем пункт USB_OTG_FS:
Кроме того, задействуем внешний тактовый генератор (8 МГц), установленный на плате:
Видим, что Cube отметил все занятые выводы микроконтроллера:
Осталось выбрать режим работы USB для нашего устройства:
На этом первый этап настроек проекта закончен, переходим в окно настроек тактирования (вкладка Clock Configuration). Здесь нам надо настроить использование внешнего генератора (8 МГц), а также все необходимые предделители частоты для всех шин микроконтроллера. Поскольку этому уже была посвящена целая статья (вот она), сейчас останавливаться на этом мы не будем и перейдем дальше 🙂 Приведу только финальные настройки тактирования:
Двигаемся дальше и переходим на вкладку Configuration, где мы можем получить доступ к многочисленным настройкам непосредственно USB. Для начала заходим в настройки USB_FS, там нам нужно включить использование Vbus (вывод PA9 микроконтроллера):
Здесь мы больше ничего пока менять не будем. Переходим к настройкам USB_DEVICE. В открывшемся окне мы видим идентификаторы VID и PID, используемые устройством, а также достаточно большое количество разных параметров USB. Не буду перечислять их все, их и так видно в окне Cube. Менять мы тут ничего не будем, хотя давайте просто ради тестирования зададим в качестве PRODUCT_STRING какое-нибудь наше название:
В принципе на этом все, можно смело переходить к генерации проекта и исходного кода.
Немного подождав, пока Cube завершит генерацию, получаем проект для IAR’а, в котором выполнена вся необходимая инициализация. Давайте не будем вносить никаких изменений, а просто соберем проект и запрограммируем микроконтроллер. После этого подключаем USB-кабель к плате и в диспетчере устройств видим новое устройство:
Если мы зайдем в свойства устройства, то можем увидеть там значения VID и PID, которые были установлены в настройках STM32CubeMx, а кроме того измененную нами строку PRODUCT_STRING:
Никаких сомнений в правильной работе сгенерированного проекта не остается 🙂 Но это только часть задачи, которую мы сами себе поставили. Нам нужно реализовать отправку данных. А необходимые для этого функции находятся в файле usbd_cdc_if.c:
- CDC_Receive_FS() – для приема данных.
- CDC_Transmit_FS() – для передачи данных.
Итак, давайте в основном цикле нашей программы будем раз в секунду отправлять 8 тестовых байт. Кстати для реализации временных задержек в HAL_Driver есть функция HAL_Delay(). В качестве аргумента мы должны передавать количество миллисекунд. В общем, получаем такой код:
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USB_DEVICE_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* USER CODE BEGIN 3 */ uint8_t testDataToSend[8]; for (uint8_t i = 0; i < 8; i++) { testDataToSend[i] = i; } /* Infinite loop */ while (1) { HAL_Delay(1000); CDC_Transmit_FS(testDataToSend, 8); } /* USER CODE END 3 */ }
Теперь остается только прошить контроллер, открыть терминал и убедиться, что данные принимаются верно. Так и поступим:
Все работает отлично, как и планировалось!
Собственно, на этой мажорной ноте мы заканчиваем сегодняшнюю статью, а вместе с ней и обсуждение реализации USB Virtual COM Port при помощи STM32CubeMx. В следующих статьях мы будем работать уже с другими режимами работы USB, так что оставайтесь на связи!