Доброго всем дня, сегодняшняя статья будет посвящена реализации виртуального COM-порта для микроконтроллеров STM32. Эта тема уже поднималась на нашем сайте, но, в отличие от всех предыдущих случаев, сегодня мы будем производить все настройки при помощи STM32CubeMx. Собственно, стартуем.
И начинаем с действий, ставших привычными - создаем новый проект в CubeMx. Я буду использовать отладочную плату STM32F4Discovery и, соответственно, выбираю контроллер STM32F407VG при создании проекта.
С этим никаких сложностей возникнуть не должно, все-таки мы уже много раз проделывали это в предыдущих статьях, посвященных STM32CubeMx (статьи про STM32CubeMx), поэтому давайте сформулируем задачу, которую будем сегодня решать.
А задача проста - реализуем поддержку USB Virtual Com Port и отправим тестовый набор данных с платы на ПК. Таким образом, мы должны добиться определения нашей отладочной платы в системе как виртуального COM-порта. А открыв этот порт в какой-нибудь терминальной программе мы должны будем увидеть правильно принятые данные. Просто и наглядно, приступаем к осуществлению.
Первым делом включим поддержку USB в проекте. Для этого посещаем вкладку "Pinout & Configuration":
Кроме того, задействуем внешний тактовый генератор (8 МГц), установленный на плате - ровно так же как мы делали в статье про тактирование:
Осталось выбрать режим работы USB для нашего устройства:
На этом первый этап настроек проекта закончен, переходим в окно настроек тактирования (вкладка "Clock Configuration"). Здесь нам необходимо обеспечить подачу ровно 48 Мгц для тактирования модуля USB, привожу полную схему с выставленными значениями:
Среди многочисленных настроек USB давайте поменяем только PRODUCT_STRING
, исключительно теста ради, проверим, как это сработает. Остальное пока не трогаем:
В принципе, на этом все, можно смело переходить к генерации проекта и исходного кода...
Немного обождав, пока CubeMx завершит генерацию, получаем готовый проект, в котором выполнена вся необходимая инициализация. Давайте не будем вносить никаких изменений, а просто соберем проект и запрограммируем контроллер. После этого подключаем USB-кабель к плате и в диспетчере устройств видим новое устройство:
Если мы зайдем в свойства, то можем увидеть там значения VID и PID, которые были установлены в настройках STM32CubeMx, а кроме того измененную нами строку PRODUCT_STRING
:
Никаких сомнений в правильной работе сгенерированного проекта не остается 👍 Но это только часть задачи, нужно реализовать отправку данных. А необходимые для этого функции находятся в файле usbd_cdc_if.c:
CDC_Receive_FS()
- для приема данных.CDC_Transmit_FS()
- для передачи данных.
Итак, давайте в основном цикле нашей программы будем раз в секунду отправлять 8 тестовых байт. Кстати для реализации простейших временных задержек в HAL присутствует функция 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(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USB_DEVICE_Init(); /* USER CODE BEGIN 2 */ uint8_t testDataToSend[8]; for (uint8_t i = 0; i < 8; i++) { testDataToSend[i] = i; } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_Delay(1000); CDC_Transmit_FS(testDataToSend, 8); } /* USER CODE END 3 */ }
Не забываем также добавить в начале файла директиву #include
:
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "usbd_cdc_if.h" /* USER CODE END Includes */
Теперь остается только прошить контроллер, открыть терминал и убедиться, что данные принимаются верно. Так и делаем:
Все работает отлично, как и планировалось. Собственно, на этой мажорной ноте мы заканчиваем сегодняшнюю статью, а вместе с ней и обсуждение реализации USB Virtual COM Port при помощи STM32CubeMx. В следующих статьях мы будем работать уже с другими режимами USB, так что оставайтесь на связи 🤝
Здравствуйте, каким вы терминалом пользуетесь?
Advanced Serial Port Monitor
Попробовал эту программу - очень даже да, но!
Не смог найти где выбирать эмулируемый терминал - хотя бы VT102.
"терминал" без эмуляции терминалов - деньги на ветер.
скачай бесплатно)
Спасибо за статью)
Ну что за непруха. Опять (SD так и не заработала) не получается "USB составное устройство" с ошибкой. А могут мои проблемы быть связаны с особенностями компиляции работы ЮСБ и СД в Кейле 5? ктоньть пробовал на кейле?
в мене після кількох рестартів мк запускався нормальний драйвер, а не композіт девайс
щоб проект запрацював, треба у функції CDC_Transmit_FS змінну UserTxBufferFS змінити на Buf і плюс до того, якщо 64б віндовс, то у стартапі проекту змінити Stack_Size EQU 0x00004000 та Heap_Size EQU 0x00002000. А так все працює. Дякую.
Точно. Так и надо сделать. На 64 разрядной винде все заработало. Проект генерил в Keil 4.74
И еще в main.c добавить:
#include "usbd_cdc_if.h"
тогда не будет предупреждения
warning: #223-D: function «CDC_Transmit_FS» declared implicitly
Вопрос: как узнать что данные можно читать с помощью CDC_Receive_FS , а то она судя по всему блокирует пока не примет всё а мне этого не нужно?
Доброго времени суток! Спасибо за статью, очень полезно и интересно. Но есть у меня с данным примером проблема: отказ виртуального СОМ порта. Что я делаю не так, с чем это связано? Заранее спасибо!
Я вот пробую. Не работает. Но дело не в кейле.
Вообще в системе виртуальный ком-порт не появляется?
всем здравствуйте. Нужна помощь с генерировал по статье код для MDK-ARM v5 stm32l152 выдает предупреждение
..\Src\main.c(97): warning: #223-D: function "CDC_Transmit_FS" declared implicitly
и зависает при отправке. кто сталкивался с такой проблемой уже второй день борюсь помогите пожалуйста
Порт появляется в диспетчере, но он не работает. В свойствах указано: не удается запустить устройство (код 10). И при попытке обращение к этому порту, выдает ошибку, что такого порта нет.
А какая плата, IDE?
Keil v5, Dyscovery F407VGT
В файле startup_stm32f407xx.s поменяй Stack_Size на 4000 вместо 400 и Heap_Size на 2000 вместо 200. Проблема исчезнет.
Спасибо, хороший человек, ошибка исчезла
А где именно и что именно использует так много места?
Что если я хочу принимать, например, 1 Мб данных?
Они точно не влезут все в кучу.
у меня есть внешняя SDRAM, она прекрасно работате и я хочу часть ее памяти зарезервировать под обработку USB пакетов, Но что-то никак не могу найти где же это используется..
Причем нигде толком не нашел объяснения.
Все только и пишут, что нужно объем стека и кучи увеличить..
STM32F4-DISCOVERY c 407 контроллером. KEIL v5 и KEIL v4 пробовал.
Остается только попробовать IAR)
Был трабл с зависанием, теперь решился, благодаря
уроку отсюда
http://www.youtube.com/watch?v=enZqu2FV1eU
мб, кому-то поможет
работал на F103
но теперь другой трабл, при подкл./откл. от ПК никаких проблем нет, однако если во время подключения к ПК принять через ком порт данные и, закрыв соединение, отключить провод, то иногда при повторном подключении устройство улетает в HARDFAULT_handler из функции USBD_CDC_DeInit через функцию USBD_free(pdev->pClassData);
может, кто то сталкивался???
сам решил проблему:
в файле usbd_conf надо закоментить 494 строку
//free(p); проблема сразу решилась и без плясок с бубном как на видео
Большое СПАСИБО за статью. Есть проблема, драйвера ни в какую работать не хотят устройство видеться. Код ошибки 10. Если в CUBE поменять параметр USBD_MAX_NUM_CONFIGURATION на отличный от 1 код ошибки исчезает, однако данные через виртуальный ком порт не идут. При попытки отправить данные в ком порт есть ошибка превышения таймаута. Если можно по подробнее на счет настроек по точнее. Какие параметры выставить в cubemx чтобы виртуальный ком порт прочухался. Спасибо
А какая среда разработки?
В качестве среды разработки используется for IAR Embedded Workbench for ARM version 7.40.2 попробовал с платами stm32f4discovery и stm32f429 discovery эффект один и тот же
Может с самим драйвером проблема? Я сегодня буквально для F429 USB MSC генерировал через Cube - сразу заработало без проблем. IAR правда v6.
драйвера с сайта st пробовал под win_xp 32 Win 7 32 однотипно как в первом посте .... Подскажите куда копать ... а то смотришь красиво начинаешь ковырять и вот...((((((((
Посмотри тут - http://electronix.ru/forum/lofiversion/index.php/t120845.html. Вроде бы там есть пара вариантов решений такой проблемы. Но вообще странно, что у многих людей возникает эта ошибка, у меня на большом количестве разнообразных плат никогда такого не было.
Спасибо за ссылки посмотрел повертел и результат никакой ((( ... есть подозрение что с Н-ной версии CUBE MX стал страдать "прихрамыванием"...(
Вопрос с драйвером решился для iar следующим образом : в настройках IAR увеличение размера "кучи" и стека
Что за переменная lt в форе "for (uint8_t i = 0; i < 8; i++)"
А видимо глюк в коде на сайте!
Ага, иногда символы < и > внезапно подменяются такой вот ерундой)
У меня проблема решилась уменьшение максимального размера пакета с
512 до 64
#define CDC_DATA_HS_MAX_PACKET_SIZE 64
Нужно поставить Heap_Size EQU 0×00004000 и будет счастье
Отично! Все работает! Спасибо!
Будет пример реализации в качестве Host-a?
Вряд ли в ближайшее время... А какая стоит вообще задача, если понадобилось VCP host реализовать?
Спасибо за статью.
После прошивки МК с диспетчере пояляется Unknown Device. Ставил драйвера VCP_V1.3.1_Setup_x64. (http://www.st.com/web/en/catalog/tools/PF257938).
Подскажите где капать решение проблемы. И еще вопрос. Мне надо организовать мост USB - USART. Использую HAL драйвера и STM32_USB-FS-Device_Lib_V4.0.0. Может быть есть какой нить пример решения.
VCP после генерации в кубе должен сразу работать нормально. Возможно что-то не так в самом проекте, раз этого не происходит. Ну и собственно, по поводу USB-USART, принимаешь данные по USB и отправляешь их на любой USART.
Я извиняюсь. Прочитал многие Ваши статьи (спасибо за ваш труд), а ответ написал не в той)))
После генерации в кубе все работает, порт определяется, данные посылаются. Пробовал ваш проект из статьи Микроконтроллер STM32 и USB(https://microtechnics.ru/mikrokontroller-stm32-i-usb/). вот с этим проектом - неизвестное устройство. Хотел поэкспериментировать.... и никак. А по поводу моста - принцип понимаю, но есть вопросы. Если не ошибаюсь эти обработки надо писать в прерывании в файле stm32f3xx_it.c. Запутало то, что не могу понять где и как организовываются endPoint . Немного о проекте: по USB мне надо конфигурировать мое устройство (менять некоторые параметры). К устройству через usart подключен радио модем которые передает сигнал исполнительному устройству. Так вот через мост usb-usart надо настраивать модем( частоты , канал и тд.) В общем пока, что каша в голове, так как только вчера начал разбираться с USB. Ищу примеры что бы разобраться.
Можно просто в функции приема принимать байты по USB, сохранять их в буфер и выдавать по USART затем.
После генерации в кубе система определяет STMicroelectrinics Virtual COM Port. Хочу , что бы определялось типа Мое устройство(COM10). Меняю VID PID и соответственно устройство не определяется. Как можно написать свои драйвера для своего устройства. Может есть какая нить инструкция.
Ну в теории покупать PID/VID надо и писать свой драйвер для устройства. Вот в этом случае к примеру устройство использует драйвер ST для VCP.
У меня на старенькой Windows XP такая же проблема. vcp-драйвер версии 1.4.0 от STMicroelectronix не помог.
Спасибо автору за статью. Удалось разобраться с настройкой USB CDC. У меня осталось несколько неясных моментов. Особенно интересует как убедиться в готовности USB, прежде чем отправлять через него данные. У меня устройство работает автономно, передавая по USB данные измерений. Но подключено к компьютеру оно не всегда, периодически отключается. Так вот как мне в программе определить подключен ли USB или нет. Устройство перезапускать нельзя. Заранее спасибо 🙂
Можно с ЮСБ разъема подать 5В на какую-нибудь ножку. Если напряжение есть - ЮСБ подключен, иначе - не подключен =)
Как вариант - можно попробовать, но тогда еще придется ставить задержку при появлении питания на ноге для инициализации USB, и нет гарантии что она пройдет успешно. В результате при попытке отправить данные, контроллер вываливается в HardFault_Handler(((. Должен же быть более цивилизованный способ. В библиотеке HAL не нашел функции, сообщающей о состоянии USB.
Помогите! Может у кого было...? После сборки и загрузки проекта в KEILe подключаю USB, а определяется как 2 COM порта!? Это как? Я новичок прошу сильно не пинать!
В диспетчере устройств 2?
Спасибо за статью, всё заработало.
Но пока так и не нашёл, где менять настройки порта.
По умолчанию стоит 9600, и где менять - непонятно.
Смотрел Line_Coding, но там мало материала.
На стороне ПК можно любую скорость обмена ставить - будет работать.
Если настроить тактирование как у автора проблем не должно быть .Это я об ошибке 10(помогает CDC_DATA_HS_MAX_PACKET_SIZE 256). Следующая ошибка 28 относится к установке драйверов.Проблема в том что никто не читает инструкцию по установке драйвера .Одним запуском еxe из архива дело не обходится он драйвера не устанавливает , а распаковывает в STMicroelectronics/...читаем файл readme.txt и делаем все как написано.
У меня как-раз таки виртуальный ком-порт не появляется в системе
контроллер STM32F103C8T6 в системе определяется как ункновн девайс может кто подскажет, кто сталкивался (тестером кабель и от МК до порта все проверил) МК не выдает VIP и PID в чем проблема 🙁
Настройки тактирования скорее всего нужно править
Ув. Aveal настройки дефоултовые от кварца на 8М, частота на USB 48M куда еще смотреть?
Просто с таймером же так и остался вопрос открытым - он не на той частоте, на какой должен почему-то работает, может кварц не дает нужную частоту, может еще что, но проблема то есть точно...
Программно Cube по идее все сам делает, может в электрическом подключении проблема, в схеме?
Можно попробовать от внутреннего затактироваться и посмотреть, будут ли изменения, причем как с USB, там и в проекте с таймером.
Ув. Aveal от внутреннего не хочет, куб ругается
Значит что-то неверно. В чем конкретно проблема?
Ув. Aveal у меня контроллер STM32F103C8T6 кварц на 8Мгц в RCC ставлю внешний кварц, автоматом частота 48 Мгц, но могу и 72 (максимальная) поставить (могу скрины кинуть ), а от внутреннего пишет USB работать не будет
Значит надо настроить предделители, чтобы частота USB от внутреннего была верная.
Кроме того, можно было бы на схему взглянуть, поскольку плата я так понимаю своя, а не готовая отладочная.
Ув. Aveal готовая отладочная маде ин наши ускоглазые соседи https://detail.tmall.com/item.htm?spm=a230r.1.14.97.d3erSV&id=522586249180&ns=1&abbucket=9
Тогда вариант неверного подключения можно с большой вероятностью исключить.
Остаются варианты:
1. тактирование
2. проблема на ПК, драйвер к примеру не установлен нужный. (менее вероятно)
3. проблема в настройках USB в Cube
1. на счет тактирования куб сам ставит, что надо
2. так хоть бы vip и PID было видно, а то просто ункновн
3. есть такой вариант, т.к. я так понимаю еще правят в нем ошибки
а может просто где галки не хватает
Куб сам не ставит что надо, там есть куча переключателей/предделителей, которые надо настраивать, чтобы тактирование было верным. Если снова вернуться к проекту с таймерами, то можно точно сказать, что тактирование неверно, ведь расчетный период не совпал с реальным.
И даже если проблему с USB это не решит, разобраться, почему неверно работает таймер было бы не лишним в любом случае
Ув. Aveal
вот схема тактирования, которая сейчас с USB
http://s019.radikal.ru/i604/1603/d8/a200093d101b.jpg
с таймером брал значение частоты на APB1 Timer Cloсks там было 36, но результат был как будто значение было другим
Вот на таймере сейчас 48 МГц, я бы начал с того, что убедился, что таймер будет работать правильно
Прихожу к выводу, что куб генерирует некорректный код. проделал опыт с таймером и указал частоту 8МГц и значения 8000 и 499 соответственно, все ок. Потом добавил USB настройки частот как на фото выше, т.е. на таймере должно быть 48МГц, выставляю значения 48000 и 499 и получаю 6 секунд.
при частоте 72Мгц поставил 36000 и 499 и так же 6 секунд. хотя должно быть 2. В общем или я что не понимаю, или куб врет
Можешь скинуть проект для куба?
Добрый вечер. Попала в руки плата STM32F429I-DISCO. Решил освоить периферию и наконец перейти на STM32CubeMX(Так сказать убить двух зайцев сразу). Но вот незадача, решил начать с USB (VIrtual Com Port). Настраиваю USB_OTG_FS, RCC, USB Device как Virtual com port. Генерю код и ничего не изменяю загружаю прошивку. Просто хочу проверить связь с устройством, но не тут то было. Комп отказывается искать устройство вообще! То есть не всплывает даже "Неопознанное устройство". Вообще 0 эффекта. Не могу понять, что за грабли на которые я наткнулся.
Добрый вечер!
Выложи скрин из Куба, из окна PinOut.
Настройка PinOut
Настройка Clock (на всякий случай)
https://dropmefiles.com/qg3VM
Добрый вечер!
На F429-Disco USB к другим пинам подключен на плате, начиная с PB12, если мне не изменяет память
Ув. Aveal отправил вам на почту с контактов в архиве проект для воркбенха и репорт из куба
Есть схема платы?
Проект для R8, а не С8, но это вряд ли повлияло...
Странно. И правда пины РВ13, РВ14 и РВ15. А куб генерит под другие для этого микроконтроллера.
Просто у продвинутых контроллеров два модуля - USB High Speed и Full Speed (USB_OTG_HS/USB_OTG_FS).
А можно как нибудь в кубе изменить пины?или только самому в коде?
Ты задействуй просто HS вместо FS в кубе и он выводы поменяет.
Не помогло(((
Скинь проект)
https://dropmefiles.com/JRbsK
Вот...кубовский
Поправил - должно работать.
https://dropmefiles.com/tA6Ro
Большое спасибо)Наконец то плата определилась)
Схемы нет, но она простая как два пальца. ЮСБ идут точно от нужных ног прозвонил, кварц на 8 так же на месте
на выходных еще раз проделаю, мог промазать в кубе, но как я понимаю у этих чипов только разное кол во оперативки и пзу, хотя перепроверю
Ну если ты уверен на сто процентов, что китайцы сделали все правильно, то (еще раз повторю) нужно разбираться с тактированием:
1. Настроить внутренний
2. Проверить таймер от внутреннего
3. Проверить ЮСБ от внутреннего
4. Переходить к внешнему.
от внутреннего кварца таймер работает хорошо , USB проверить не могу, т.к. не позволяет, а вот только как вместо встроенного кварца выбираешь внешний, частота увеличивается (точнее снижается) в 6 раз. вместо герца 1 в 6 секунд
Что значит не позволяет?
http://s020.radikal.ru/i703/1603/2c/9e1b673b270e.jpg ругается в системе тактирования
Скинь кубовский файл .ioc текущий
Ув. Aveal замена кварца решила проблему 🙂 (ремонт обошелся в 36р) первый раз с таким сталкиваюсь, а так значит делал все правильно
Рад что заработало =) Китайцам нельзя доверять )
Если честно заказывал очень много чего, за все время, только второй раз вылез косяк, но тут чисто брак кварца (это как брак процессора 1-2 на 1000 штук), а так спасибо за помощь
Как понять подключен хост (ПК) или нет?
У меня если шнурок выдернут то при попытке CDC_Transmit_FS контроллер уходит HardDefault. В usbd_cdc_if.h и usbd_cdc_if.с ничего подобного не увидел.
Хотелось бы понять, когда делать CDC_Transmit_FS а когда нет.
Можно 5В от USB завести на вывод контроллера и анализировать уровень. Программный вариант - насколько я помню в какой-то структуре в HAL есть поле isConnected или что-то в этом роде. Возможно так получится мониторить подключение.