STM32Cube и USB. Virtual Com Port.

Доброго всем дня!

Сегодняшняя статья будет посвящена реализации виртуального com-порта для микроконтроллеров STM32. Эта тема уже поднималась на нашем сайте (STM32 и USB), но в отличие от всех предыдущих экспериментов сегодня мы будем производить все настройки при помощи STM32Cube. Собственно, переходим к делу =)

Работа с USB

Итак, начинаем с действий, ставших привычными 😉 Создаем новый проект в STM32Cube, настраиваем его и выбираем микроконтроллер, для которого мы будем генерировать проект. Я буду использовать отладочную плату STM32F4-Discovery и, соответственно, контроллер STM32F407VG.

С этим никаких сложностей возникнуть не должно, все-таки мы уже много раз проделывали это в предыдущих статьях, посвященных STM32Cube (статьи про STM32Cube), поэтому давайте сформулируем задачу, которую мы будем сегодня решать.

А задача проста — реализуем поддержку Virtual Com-Port и отправим тестовый набор данных с платы на ПК. Таким образом, мы должны добиться определения нашей отладочной платы в системе как виртуального com-порта. А открыв этот порт в какой-нибудь терминальной программе мы должны будем увидеть правильно принятые данные. В общем, ничего сложного 😉

Перейдем к реализации задуманного.

Первым делом включим поддержку USB в нашем проекте в STM32Cube. Во вкладке Pinout ищем пункт USB_OTG_FS:

Использование USB в STM32Cube

Кроме того, задействуем внешний тактовый генератор (8 МГц), установленный на плате:

Внешний кварцевый генератор

Видим, что Cube отметил все занятые выводы микроконтроллера:

Настройка выводов контроллера

Осталось выбрать режим работы USB для нашего устройства:

Настройка Virtual com port

На этом первый этап настроек проекта закончен, переходим в окно настроек тактирования (вкладка Clock Configuration). Здесь нам надо настроить использование внешнего генератора (8 МГц), а также все необходимые предделители частоты для всех шин микроконтроллера. Поскольку этому уже была посвящена целая статья (вот она), сейчас останавливаться на этом мы не будем и перейдем дальше ) Приведу только финальные настройки тактирования моего проекта:

Тактирование в STM32

Двигаемся дальше и переходим на вкладку Configuration, где мы можем получить доступ к многочисленным настройкам непосредственно USB. Для начала заходим в настройки USB_FS, там нам нужно включить использование Vbus (вывод PA9 микроконтроллера):

Конфигурация USB_FS

Здесь мы больше ничего пока менять не будем. Переходим к настройкам USB_DEVICE. В открывшемся окне мы видим идентификаторы VID и PID, используемые устройством, а также достаточно большое количество разных параметров USB =) Не буду перечислять их все, их и так видно в окне Cube. Менять мы тут ничего не будем, хотя давайте просто ради тестирования зададим в качестве PRODUCT_STRING какое-нибудь наше название:

USB Configuration

В принципе на этом все, можно смело переходить к генерации проекта и исходного кода.

Немного подождав, пока Cube завершит генерацию, получаем проект для IAR’а, в котором выполнена вся необходимая инициализация. Давайте не будем вносить никаких изменений, а просто соберем проект и запрограммируем микроконтроллер. После этого подключаем USB-кабель к плате и в диспетчере устройств видим новое устройство:

Виртуальный com-порт в Windows 8

Если мы зайдем в свойства устройства, то можем увидеть там значения VID и PID, которые были установлены в настройках STM32Cube, а кроме того измененную нами строку PRODUCT_STRING:

Virtual Com Port на плате STM32F4-Discovery

Никаких сомнений в правильной работе сгенерированного проекта не остается 😉

Но это только часть задачи, которую мы сами себе поставили. Нам нужно реализовать отправку данных. А необходимые для этого функции находятся в файле 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 */
 
}

Теперь остается только прошить контроллер, открыть терминал и убедиться, что данные принимаются верно. Так и поступим )

Реализация приема данных

Все работает отлично, как и планировалось! =)

Собственно, на этой мажорной ноте мы заканчиваем сегодняшнюю статью, а вместе с ней и обсуждение реализации драйвера виртуального com-порта при помощи STM32Cube. В следующих статьях мы будем работать уже с другими режимами работы USB, так что оставайтесь на связи!

Понравилась статья? Поделись с друзьями!

STM32Cube и USB. Virtual Com Port.: 166 комментариев
  1. Ну что за непруха. Опять (SD так и не заработала) не получается «USB составное устройство» с ошибкой. А могут мои проблемы быть связаны с особенностями компиляции работы ЮСБ и СД в Кейле 5? ктоньть пробовал на кейле?

  2. в мене після кількох рестартів мк запускався нормальний драйвер, а не композіт девайс

  3. щоб проект запрацював, треба у функції 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

  4. Вопрос: как узнать что данные можно читать с помощью CDC_Receive_FS , а то она судя по всему блокирует пока не примет всё а мне этого не нужно?

  5. Доброго времени суток! Спасибо за статью, очень полезно и интересно. Но есть у меня с данным примером проблема: отказ виртуального СОМ порта. Что я делаю не так, с чем это связано? Заранее спасибо!

  6. всем здравствуйте. Нужна помощь с генерировал по статье код для MDK-ARM v5 stm32l152 выдает предупреждение
    ..\Src\main.c(97): warning: #223-D: function «CDC_Transmit_FS» declared implicitly
    и зависает при отправке. кто сталкивался с такой проблемой уже второй день борюсь помогите пожалуйста

  7. Порт появляется в диспетчере, но он не работает. В свойствах указано: не удается запустить устройство (код 10). И при попытке обращение к этому порту, выдает ошибку, что такого порта нет.

  8. Был трабл с зависанием, теперь решился, благодаря
    уроку отсюда
    http://www.youtube.com/watch?v=enZqu2FV1eU
    мб, кому-то поможет
    работал на F103
    но теперь другой трабл, при подкл./откл. от ПК никаких проблем нет, однако если во время подключения к ПК принять через ком порт данные и, закрыв соединение, отключить провод, то иногда при повторном подключении устройство улетает в HARDFAULT_handler из функции USBD_CDC_DeInit через функцию USBD_free(pdev->pClassData);
    может, кто то сталкивался???

  9. сам решил проблему:
    в файле usbd_conf надо закоментить 494 строку
    //free(p); проблема сразу решилась и без плясок с бубном как на видео

  10. Большое СПАСИБО за статью. Есть проблема, драйвера ни в какую работать не хотят устройство видеться. Код ошибки 10. Если в CUBE поменять параметр USBD_MAX_NUM_CONFIGURATION на отличный от 1 код ошибки исчезает, однако данные через виртуальный ком порт не идут. При попытки отправить данные в ком порт есть ошибка превышения таймаута. Если можно по подробнее на счет настроек по точнее. Какие параметры выставить в cubemx чтобы виртуальный ком порт прочухался. Спасибо

  11. В качестве среды разработки используется for IAR Embedded Workbench for ARM version 7.40.2 попробовал с платами stm32f4discovery и stm32f429 discovery эффект один и тот же

    • Может с самим драйвером проблема? Я сегодня буквально для F429 USB MSC генерировал через Cube — сразу заработало без проблем. IAR правда v6.

  12. драйвера с сайта st пробовал под win_xp 32 Win 7 32 однотипно как в первом посте …. Подскажите куда копать … а то смотришь красиво начинаешь ковырять и вот…((((((((

  13. Спасибо за ссылки посмотрел повертел и результат никакой ((( … есть подозрение что с Н-ной версии CUBE MX стал страдать «прихрамыванием»…(

  14. Вопрос с драйвером решился для iar следующим образом : в настройках IAR увеличение размера «кучи» и стека

  15. У меня проблема решилась уменьшение максимального размера пакета с
    512 до 64
    #define CDC_DATA_HS_MAX_PACKET_SIZE 64

    • Вряд ли в ближайшее время… А какая стоит вообще задача, если понадобилось VCP host реализовать?

  16. Спасибо за статью.
    После прошивки МК с диспетчере пояляется 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(http://microtechnics.ru/mikrokontroller-stm32-i-usb/). вот с этим проектом — неизвестное устройство. Хотел поэкспериментировать…. и никак. А по поводу моста — принцип понимаю, но есть вопросы. Если не ошибаюсь эти обработки надо писать в прерывании в файле stm32f3xx_it.c. Запутало то, что не могу понять где и как организовываются endPoint . Немного о проекте: по USB мне надо конфигурировать мое устройство (менять некоторые параметры). К устройству через usart подключен радио модем которые передает сигнал исполнительному устройству. Так вот через мост usb-usart надо настраивать модем( частоты , канал и тд.) В общем пока, что каша в голове, так как только вчера начал разбираться с USB. Ищу примеры что бы разобраться.

        • Можно просто в функции приема принимать байты по USB, сохранять их в буфер и выдавать по USART затем.

  17. После генерации в кубе система определяет STMicroelectrinics Virtual COM Port. Хочу , что бы определялось типа Мое устройство(COM10). Меняю VID PID и соответственно устройство не определяется. Как можно написать свои драйвера для своего устройства. Может есть какая нить инструкция.

    • Ну в теории покупать PID/VID надо и писать свой драйвер для устройства. Вот в этом случае к примеру устройство использует драйвер ST для VCP.

  18. У меня на старенькой Windows XP такая же проблема. vcp-драйвер версии 1.4.0 от STMicroelectronix не помог.

  19. Спасибо автору за статью. Удалось разобраться с настройкой USB CDC. У меня осталось несколько неясных моментов. Особенно интересует как убедиться в готовности USB, прежде чем отправлять через него данные. У меня устройство работает автономно, передавая по USB данные измерений. Но подключено к компьютеру оно не всегда, периодически отключается. Так вот как мне в программе определить подключен ли USB или нет. Устройство перезапускать нельзя. Заранее спасибо 🙂

    • Можно с ЮСБ разъема подать 5В на какую-нибудь ножку. Если напряжение есть — ЮСБ подключен, иначе — не подключен =)

  20. Как вариант — можно попробовать, но тогда еще придется ставить задержку при появлении питания на ноге для инициализации USB, и нет гарантии что она пройдет успешно. В результате при попытке отправить данные, контроллер вываливается в HardFault_Handler(((. Должен же быть более цивилизованный способ. В библиотеке HAL не нашел функции, сообщающей о состоянии USB.

  21. Помогите! Может у кого было…? После сборки и загрузки проекта в KEILe подключаю USB, а определяется как 2 COM порта!? Это как? Я новичок прошу сильно не пинать!

  22. Спасибо за статью, всё заработало.

    Но пока так и не нашёл, где менять настройки порта.
    По умолчанию стоит 9600, и где менять — непонятно.
    Смотрел Line_Coding, но там мало материала.

  23. Если настроить тактирование как у автора проблем не должно быть .Это я об ошибке 10(помогает CDC_DATA_HS_MAX_PACKET_SIZE 256). Следующая ошибка 28 относится к установке драйверов.Проблема в том что никто не читает инструкцию по установке драйвера .Одним запуском еxe из архива дело не обходится он драйвера не устанавливает , а распаковывает в STMicroelectronics/…читаем файл readme.txt и делаем все как написано.

  24. контроллер STM32F103C8T6 в системе определяется как ункновн девайс может кто подскажет, кто сталкивался (тестером кабель и от МК до порта все проверил) МК не выдает VIP и PID в чем проблема 🙁

  25. Ув. Aveal настройки дефоултовые от кварца на 8М, частота на USB 48M куда еще смотреть?

    • Просто с таймером же так и остался вопрос открытым — он не на той частоте, на какой должен почему-то работает, может кварц не дает нужную частоту, может еще что, но проблема то есть точно…

      Программно Cube по идее все сам делает, может в электрическом подключении проблема, в схеме?

    • Можно попробовать от внутреннего затактироваться и посмотреть, будут ли изменения, причем как с USB, там и в проекте с таймером.

  26. Ув. Aveal у меня контроллер STM32F103C8T6 кварц на 8Мгц в RCC ставлю внешний кварц, автоматом частота 48 Мгц, но могу и 72 (максимальная) поставить (могу скрины кинуть ), а от внутреннего пишет USB работать не будет

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

    • Тогда вариант неверного подключения можно с большой вероятностью исключить.
      Остаются варианты:
      1. тактирование
      2. проблема на ПК, драйвер к примеру не установлен нужный. (менее вероятно)
      3. проблема в настройках USB в Cube

  27. 1. на счет тактирования куб сам ставит, что надо
    2. так хоть бы vip и PID было видно, а то просто ункновн
    3. есть такой вариант, т.к. я так понимаю еще правят в нем ошибки
    а может просто где галки не хватает

    • Куб сам не ставит что надо, там есть куча переключателей/предделителей, которые надо настраивать, чтобы тактирование было верным. Если снова вернуться к проекту с таймерами, то можно точно сказать, что тактирование неверно, ведь расчетный период не совпал с реальным.

    • И даже если проблему с USB это не решит, разобраться, почему неверно работает таймер было бы не лишним в любом случае

    • Вот на таймере сейчас 48 МГц, я бы начал с того, что убедился, что таймер будет работать правильно

  28. Прихожу к выводу, что куб генерирует некорректный код. проделал опыт с таймером и указал частоту 8МГц и значения 8000 и 499 соответственно, все ок. Потом добавил USB настройки частот как на фото выше, т.е. на таймере должно быть 48МГц, выставляю значения 48000 и 499 и получаю 6 секунд.
    при частоте 72Мгц поставил 36000 и 499 и так же 6 секунд. хотя должно быть 2. В общем или я что не понимаю, или куб врет

  29. Добрый вечер. Попала в руки плата STM32F429I-DISCO. Решил освоить периферию и наконец перейти на STM32CubeMX(Так сказать убить двух зайцев сразу). Но вот незадача, решил начать с USB (VIrtual Com Port). Настраиваю USB_OTG_FS, RCC, USB Device как Virtual com port. Генерю код и ничего не изменяю загружаю прошивку. Просто хочу проверить связь с устройством, но не тут то было. Комп отказывается искать устройство вообще! То есть не всплывает даже «Неопознанное устройство». Вообще 0 эффекта. Не могу понять, что за грабли на которые я наткнулся.

  30. Ув. Aveal отправил вам на почту с контактов в архиве проект для воркбенха и репорт из куба

  31. Странно. И правда пины РВ13, РВ14 и РВ15. А куб генерит под другие для этого микроконтроллера.

  32. Схемы нет, но она простая как два пальца. ЮСБ идут точно от нужных ног прозвонил, кварц на 8 так же на месте
    на выходных еще раз проделаю, мог промазать в кубе, но как я понимаю у этих чипов только разное кол во оперативки и пзу, хотя перепроверю

    • Ну если ты уверен на сто процентов, что китайцы сделали все правильно, то (еще раз повторю) нужно разбираться с тактированием:
      1. Настроить внутренний
      2. Проверить таймер от внутреннего
      3. Проверить ЮСБ от внутреннего
      4. Переходить к внешнему.

  33. от внутреннего кварца таймер работает хорошо , USB проверить не могу, т.к. не позволяет, а вот только как вместо встроенного кварца выбираешь внешний, частота увеличивается (точнее снижается) в 6 раз. вместо герца 1 в 6 секунд

  34. Ув. Aveal замена кварца решила проблему 🙂 (ремонт обошелся в 36р) первый раз с таким сталкиваюсь, а так значит делал все правильно

  35. Если честно заказывал очень много чего, за все время, только второй раз вылез косяк, но тут чисто брак кварца (это как брак процессора 1-2 на 1000 штук), а так спасибо за помощь

  36. Как понять подключен хост (ПК) или нет?
    У меня если шнурок выдернут то при попытке CDC_Transmit_FS контроллер уходит HardDefault. В usbd_cdc_if.h и usbd_cdc_if.с ничего подобного не увидел.
    Хотелось бы понять, когда делать CDC_Transmit_FS а когда нет.

    • Можно 5В от USB завести на вывод контроллера и анализировать уровень. Программный вариант — насколько я помню в какой-то структуре в HAL есть поле isConnected или что-то в этом роде. Возможно так получится мониторить подключение.

  37. isConnected не нашел.
    Пока вставил в CDC_Transmit_FS() такую строку
    if( hUsbDevice_0 ==NULL) return 100;
    и дополнил
    static int8_t CDC_DeInit_FS(void)
    {
    /* USER CODE BEGIN 4 */
    hUsbDevice_0 = NULL; // my code
    return (USBD_OK);
    /* USER CODE END 4 */
    }
    Зависать перестал.
    Не знаю пока к чему это приведёт но пока как-то работает.

  38. віталік говорит 11.05.2015 в 16:49:

    щоб проект запрацював, треба у функції CDC_Transmit_FS змінну UserTxBufferFS змінити на Buf і плюс до того, якщо 64б віндовс, то у стартапі проекту змінити Stack_Size EQU 0x00004000 та Heap_Size EQU 0x00002000. А так все працює. Дякую.
    Ответить ↓

    помогло, забрацював. За статью огромное спасибо. Тяжеловато для любителя, после AVR, особенно первые 2 часа ))

  39. пытаюсь повторить урок и устройство определяется как ункновн девайс, но стоит только закомментировать строку передачи CDC_Transmit_FS(testDataToSend, 8); и о чудо все работает, но вот передать ни чего не можем. кто сталкивался с подобным как решили?

  40. все оказалось до безобразия просто при работе стлинка видать что то некорректно работает в МК, стоило залить программу и отключить стлинк, как все заработало без проблем (вот интересно как в такой ситуации производить отладку — МК F103CBT6)

  41. Пробую повторить проект с stm32f407 discovery. После генерации кода в кубе, компилирую, прошиваю, в диспетчере устройств появляется виртуальный ком-порт, но с ошибкой «This device cannot start. (Code 10)». Подскажите, где искать причину?

    • Привет, посмотри там в комментариях чуть выше была подобная проблема — решилось увеличением размера стека и кучи.

  42. Привет.
    Возникла проблема с приемом данных через com порт stm32f429i. Проблема заключается в приеме больше 64 байт данных. Вот если передавать менее 64 байт то все в норме все данные принимаются корректно. Usb HS (вроде как должен поддерживать прием 512 байт и в сгенерированном коде cuba ) стоит
    #define CDC_DATA_HS_MAX_PACKET_SIZE 512 /* Endpoint IN & OUT Packet size */
    Буфер на прием сделал 512 байт #define APP_RX_DATA_SIZE 512.Продолжая дальнейшее изучение проблемы наткнулся на сброс длины принимаемого пакета. В сгенерированом кубе коде есть строчка приема данных
    Код:
    static int8_t CDC_Receive_HS (uint8_t* Buf, uint32_t *Len)
    {
    /* USER CODE BEGIN 11 */
    USBD_CDC_ReceivePacket(hUsbDevice_1); //добавляем сами
    return (USBD_OK);
    /* USER CODE END 11 */
    }

    Указатель uint32_t *Len сбрасывается на нулевой адрес массива после приема 64 байт и начинает перезаписывать данные в массиве UserRxBufferHS[APP_RX_DATA_SIZE]. В итоги мы получаем остаток от наших данных. Почему *Len сбрасывается на адрес первого элемента массива ? Может кто уже решал данную проблему? Использую плату stm32f429i-disco

    • Привет, теска)
      В моей работе возникает проблема, описанная тобой в данном посте. Банально не получается принять ни одного байта….
      Скинь, пожалуйста, фрагмент кода, где ты принимаешь данные с виртуального ком порта.

  43. на удивление !!!! проект собрался скомпилировался и запустился.
    уменьшил объем буфера до 475.
    позже проект выложу на сайте.
    задача передовать 1 мегабайт в секунду.
    сейчас проверяю реальную скорость

  44. while (1)
    {
    while (CDC_Transmit_FS(testDataToSend, 10)!=0);
    }
    виснет через некоторое время.

    while (1)
    {
    while (CDC_Transmit_FS(testDataToSend, 150)!=0);
    }
    136 ,137,138 байты испорчены

  45. Несомненно тема USB всегда вызывает повышенный интерес, на грани волшебства (собранное устройство вдруг определяется компьютером и даже в некоторых случаях работает!)
    Но CubeMX изменился и теперь появились такие пункты:
    External Phy
    Internal FS Phy
    Что то не пойму — что они означают? В справке Cube нет ничего про это.
    И ещё вопрос: пин Activate_SOF подключается только когда у нас тактирование MCU от внутреннего или нестабильного источника тактов? Или я ошибаюсь и его назначение другое?
    Спасибо.

    • SOF используется для синхронизации с хостом, насколько я знаю, часто используется в аудио-устройствах.

      External PHY — если используется внешняя микросхема физического уровня, опять же, насколько я помню, High Speed можно поднять только с внешним Phy.

  46. Добрый день! Вот такой вопрос. Работаю с платой STM324x9I.
    В Cube в Pinout есть группы:
    — USB_OTG_FS
    — USB_OTG_HS (а в ней External Phy, Internal FS Phy).

    Что это такое? И почему Internal FS Phy отнесен к USB_OTG_HS, а USB_OTG_FS?

    • Это указывает на то, что будет использоваться в качестве физического уровня для USB (либо аппаратные модули МК, либо внешняя микросхема). У STM32 без внешней микросхемы возможно использовать только FS, поэтому для USB_OTG_FS этот вариант выбран по умолчанию. А HS можно использовать как FS (с internal), либо как HS, но тогда уже нужно подключать external.

  47. Уважаемый, Aveal, подскажите пожалуйста…

    В проекте часто встречается команда «USBH_UsrLog».
    Как она работает, что она делает? В определении (Go to definition of «USBH_UsrLog» ) видим следующий код (у меня #define USBH_DEBUG_LEVEL 0 ):

    #if (USBH_DEBUG_LEVEL > 1)

    #define USBH_ErrLog(…) printf(«ERROR: «) ;\
    printf(__VA_ARGS__);\
    printf(«\n»);
    #else
    #define USBH_ErrLog(…)
    #endif

    #if (USBH_DEBUG_LEVEL > 2)
    #define USBH_DbgLog(…) printf(«DEBUG : «) ;\
    printf(__VA_ARGS__);\
    printf(«\n»);

    Далее сама суть вопроса. Printf. Как она работает? Никак не пойму. Предположу как Uart. Если да, то при каких параметрах (скорость, стоп биты и тд)….

    • Разобрался.
      Запускаем Debugger и выбираем View -> Serial Windows-> Debug printf() Viever. После запуска программы на выполнение, наблюдаем вывод в окне Debug printf() Viever

  48. #define APP_RX_DATA_SIZE 4
    #define APP_TX_DATA_SIZE 4

    uint8_t UserRxBufferHS[APP_RX_DATA_SIZE];
    uint8_t UserTxBufferHS[APP_TX_DATA_SIZE];

    static int8_t CDC_Receive_HS (uint8_t* Buf, uint32_t *Len)
    {
    /* USER CODE BEGIN 11 */
    USBD_CDC_SetRxBuffer(&hUsbDeviceHS, &Buf[0]);
    USBD_CDC_ReceivePacket(&hUsbDeviceHS);
    CDC_Transmit_HS(Buf, *Len);
    return (USBD_OK);
    /* USER CODE END 11 */
    }

    Почему при отправке с компьютера на device массив значений, размер которого большее, чем APP_RX_DATA_SIZE, не обрезается.
    Отправили с компьютера на контроллер Tx: 1234567890.
    Получаем Rx: 1234567890, а не 1234.

    • Видимо с размером буфера количество принимаемых байт не связано… Скорее всего если памяти будет меньше свободной в контроллере, то данные будут искажены, то есть первые байты, которым «хватило» места в массиве будут верные, а последующие — нет.

  49. Добрый день.
    Можно ли с помощью HAL определить подключен МК к компьютеру или нет? Есть ли какие нибудь флаги или колбэки при подключении (отключении) МК к ПК?
    использую stm32f3

    • Вроде бы такая проблема уже возникала в комментариях и решения не нашлось ( Надежнее всего, конечно, если есть возможность электрически отслеживать 5В от USB.

  50. Добрый день. Немного играюсь с размером пакета передаваемых данных.

    #define CDC_DATA_FS_MAX_PACKET_SIZE 256 //в usbd_cdc.h Максимальный размер пакета для конечной точки
    //Далее в main.c
    #define NUM 508
    uint8_t testDataToSend1[1024];
    CDC_Transmit_FS(testDataToSend1, NUM);

    Все нормально передается до значений NUM 509, CDC_DATA_FS_MAX_PACKET_SIZE 512. Изменения CDC_DATA_FS_MAX_PACKET_SIZE, размера кучи, стека на ситуацию не повлияли.

    Почему?

  51. Любопытный эпизод. Есть 2 платы. STM324x9I и STM3220G.
    Один и тот же код, сгенерированный в Кубе (естественно с учетом пинов, тактирования), работает по-разному. Для второй платы — Ком порт определяется, все работает, для первой — «Unknown Device»

    С чем это может быть связано??

  52. Спасибо, получилось.
    WIN10, NUCLEO F070RB, Keil uVision5.

    В режиме отладки SW при отправке данных улетает в HardFault.
    Без отладки работает норм.

  53. Как можно смотреть напряжения на vbus? Контроллер stm32f429i. Настроен usb cdc. Vbus активен. Когда включаю контроллер без подключения к usb происходит зависания на строчки CDC_Transmit_HS((uint8_t*)&Mes,sizeof(Mes)); .

  54. А что вы думаете если смотреть подключено usb или нет вот таким образом?
    uint8_t Get_USB_Connect(void){
    USB_Connect = CDC_Init_HS();
    return (USB_Connect);
    }

    и в main()
    if(Get_USB_Connect() == USBD_OK){
    CDC_Transmit_HS((uint8_t*)&Mes,sizeof(Mes));
    }

    • Главное, чтобы функция инициализации не вызывалась постоянно в процессе работы контроллера.

  55. Немного не понял ответа. Вы про эту функцию MX_USB_DEVICE_Init();? Или CDC_Init_HS();?

    • Про вторую, просто если вызывать в while(1), например, периодически Get_USB_Connect(), то она будет дергать Init() постоянно.

  56. Ясно. Нашел в документации две api функции но не понял как с ними работать
    USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev)
    USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev)
    Как понял эти api функции проверяют напряжения vbus.

  57. Здравствуйте, а не скинете пример работы с приемом данных от компьютера, с передачей разобрался, всё прекрасно работает, с приемом — вообще ничего не получается.

    • Добрый день!

      Примера готового нет… Я вечером поищу отрывки кода, которые за прием отвечают и напишу как запустить.

    • Насколько я помню в прошлаых версиях Cube было так (наверно и в текущей версии примерно так же или так же).
      Все операции в файле usnd_cdc_if.c:
      1. В начала файла объявляем буфер для приема данных:
      uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
      2. В функции CDC_Init_FS() устаналиваем:
      USBD_CDC_SetRxBuffer(hUsbDevice_0, UserRxBufferFS);
      3. Теперь при приеме данных мы попадем в функцию CDC_Receive_FS, и в ней можем напрямую оперировать с буфером UserRxBufferFS, там уже будут находиться принятые данные.

  58. Приветствую. Пытаюсь реализовать данный проект на базе STM32f103. Отправка проходит четко, без проблем. А вот прием вообще не пойму, как тут организовывается. В связи с чем несколько вопросов.
    1) Почему функция static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) изначально недоступна глобально (бозначена staic). Зачем это сделано?
    2) Зачем длина принимаемых данных *Len в виде указателя? И чего туда вообще в таком случае загружать.
    3) Прерывание соответствующее для usb тут какую роль вообще играет? Я привык что на всяких SPI и USART есть колбеки всякие. Тут вообще этого не вижу? Как организовывается взаимодействие? Какова последовательность действий при отправке и приеме?

    • Добрый день!
      Вотя чуть выше про это писал:

      «Насколько я помню в прошлаых версиях Cube было так (наверно и в текущей версии примерно так же или так же).
      Все операции в файле usnd_cdc_if.c:
      1. В начала файла объявляем буфер для приема данных:
      uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
      2. В функции CDC_Init_FS() устаналиваем:
      USBD_CDC_SetRxBuffer(hUsbDevice_0, UserRxBufferFS);
      3. Теперь при приеме данных мы попадем в функцию CDC_Receive_FS, и в ней можем напрямую оперировать с буфером UserRxBufferFS, там уже будут находиться принятые данные.»

  59. Данные как я понял принимаются по одному байту. Как-то можно объяснить системе, сколько байт будет отправлено?

    • Скорее всего callback будет вызываться после окончания транзакций USB, поэтому сколько бы не было отправлено (в разумных пределах) столько мы и получим, попав в callback.

  60. А подскажите какая принципиальная разница между данным режимом и HID? Какие есть ограничения? Где скорость приемо-передачи выше? Мне нужно выжать в итоге из USB максимум скорости

    • Если просто передавать/принимать данные, то лучше CDC, HID все-таки несколько для других целей используется. По поводу максимальной скорости не скажу, нужно эксперимент проводить и замерять, буду сам рад узнать конкретные цифры, которых удастся достигнуть =)

    • Если при разработке устройства обеспечить соответствие спецификации HID, то оно будет работать независимо от программного обеспечения объекта, к которому оно подключается. К примеру, есть класс HID для поддержки клавиатур. Можно сделать свою собственную клавиатуру и она будет работать на любом ПК.
      С другой стороны, можно сделать Custom HID и использовать и для передачи данных, например, но все-таки я думаю CDC для этого лучше подойдет.

  61. А какова в режиме CDC логика срабатывания прерывания «USB high priority or CAN Tx interrupts» ? Какое условие его срабатывания?

    • HP прерывание (CTR_HP()) аналогично LP работает, используется для увеличения скорости и насколько я помню срабатывает в режиме double-buffer bulk. По поводу того как аппаратно этот режим в USB настроить точно не скажу, надо смотреть в Кубе.

  62. Еще несколько вопросик по приему данных. Процесс идет. Отправляю из стандартного терминала для связи с COM портом со стороны ПК. Вот что все таки не ясно.
    1) Какой смысл тут в буфере APP_RX_DATA_SIZE в 4 байта, если сколько бы символов я не отправил, они по очереди заносятся в него, перезаписывая предыдущий байт.
    2) К этому одному байту в буфер всегда дописывается второй, хотя в колбек мы при этом зашли один раз. Что это за второй байт?
    3) Ну и соответственно функция int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len). Все таки, указатель *Len она откуда берет?

    • 1. Значит скорость отправки низкая и данные успевают обрабатываться в контроллере до начала следующей транзакции. Если отправлять сразу несколько, то буфер должен заполниться данными, а не только одним из байт.
      2. Не знаю, я такой феномен не наблюдал.
      3. Чтобы найти конкретное место нужно по исходникам пройтись и посмотреть места, где функция вызывается и там будет понятно, что передается ей в качестве аргументов.

  63. Здравствуйте!
    Я новичок в программировании STM, и прошу дать пример для работы с CDC_Receive_FS, прочитать буфер в заранее объявленную структуру и потом её разбирать.

    • Добрый день!
      Вотя чуть выше про это писал:

      «Насколько я помню в прошлаых версиях Cube было так (наверно и в текущей версии примерно так же или так же).
      Все операции в файле usnd_cdc_if.c:
      1. В начала файла объявляем буфер для приема данных:
      uint8_t UserRxBufferFS[APP_RX_DATA_SIZE];
      2. В функции CDC_Init_FS() устаналиваем:
      USBD_CDC_SetRxBuffer(hUsbDevice_0, UserRxBufferFS);
      3. Теперь при приеме данных мы попадем в функцию CDC_Receive_FS, и в ней можем напрямую оперировать с буфером UserRxBufferFS, там уже будут находиться принятые данные.»

      • Здравствуйте!
        Да, я этот пример разобрал, вся беда в том, что в main эти данные недоступны. Мне проверять, пришло-не пришло, попасть в этот буфер, скопировать в глобальную переменную структуру принятый буфер, потом разобрать и всё повторяется. Если Вы предоставите более подробный пример, как в передаче от прибора к компу, я буду очень признателен. Не сочтите за труд…

        • Ну раз структура глобальная, то она доступна везде будет. В функции CDC_Receive_FS нужно заполнять ее данными:

          myStruct.filed1 = UserRxBufferFS[0];
          myStruct.filed2 = UserRxBufferFS[1];
          ……

          • Хорошо, а как мне этот массив объявить? Если я его объявляю в файле main, то он недоступен в usbd_cdc_if,(выводится ошибка identifier «UserData» is undefined) и наоборот. (Работаю в JAR 7.70.01).
            Растолкуйте, плиз, где и что я не то делаю?
            Может всё-таки дадите рабочий пример, а не будете отделываться обрывками?

  64. К сожалению Virtual com port в Cube, все еще нормально не реализован. Функция CDC_Receive_FS поностью игнорирует второй параметр len. Т.е. длину принимаемых данных предсказать не возможно.
    Да и странно это сразу выглядело в статье, что функции объявляются в файле с расширением «.с». В заголовочном файле, как положено объявлена только функция CDC_Transmit_FS, и она только и работает.
    П.с. библиотеки у меня для stm32f4 версии 1.13

  65. Прочитал комментарии выше, понял что ошибся. Как оказывается функцию CDC_Receive_FS вызывать самому не нужно. Она вызывается по прерыванию, данные приходят в нее. Было бы не плохо дополнить урок о том как ее использовать, хотя бы просто упоминанием. Комментариев слишком много и не каждый будет читать их все.
    Сам уже разобрался с приемом данных, но заметил одну не приятную вещь, если данных приходит больше чем размер буфера, то программа в stm32 «виснет».
    Может у кого есть решение этой проблемы без увеличения размера буфера?

  66. помогите, кто в теме.
    третий день голову ломаю.
    взял поиграться stm32f29 плату, в кубе собрал проект — все как у автора, скомпилировал без ошибок (ничего не меняя в коде, как есть), залил в плату — реакции ноль.
    при подключении через user_usb к компьютеру тот не видит вообще никаких com портов.
    китайцы с платой накосячили, или я где то дурак?

  67. Здравствуйте. Я использую STM32F4-Discovery в Keil, передаю даные через USB FS CDC. Не пробовали ли вы передавать данные более 64 байт, а точнее принимать? В этом случае данные разбиваются на фрэймы. Вы не знаете, можно ли в этом случае узнать размер всего сообщения, принимая его кусок. И есть ли какой-то признак, который говорит о том, что идет прием сообщения, разбитого на части, а не отдельного сообщения?

  68. Просто сгенерив в Кубе и прошив, комп ругался, требовал драйвер. Установив таки ST VCP driver v.1.4.0 все заработало. Принимает даже на скорости 57600. Можно от демо платы полученный опыт использовать в реальных проектах.

    Спасибо ST и автору.

  69. Работает и прием и передача. Только надо в файле usbd_cdc_if.c поубирать квалификаторы statis у функции CDC_Receive_FS.

  70. Попробую подвести итог своих экспериментов на основе ваших, уважаемая публика, коментов)))
    Keil uVision 5, Windows10, STMCubeMX 4.19.0 библиотека для STM32F4 — v1.14.0, драйвер VCP_v1.4.0
    1) Проект сгенерен с нуля для STM32F439.
    2) Драйвер на РС установлен без проблем.
    3) В проекте сразу изменены размеры Стека до 0х4000 и Хипа до 0х2000. В тексте обнаружены функции динамического выделения памяти и, видимо, размера по-умолчанию не хватает. В функциях US-библиотеки тоже, видимо, используются временные объекты большого размера, поэтому нужен большой стек.
    4) Текст скомпилирован, прошит, запущен. При втыкании USB шнурочка устройство обнаруживается, определяется и устанавливается влет.
    5) Дописан периодический вывод сообщения на экран терминала (использую Tera Term v4.75) — выводится нормально.
    6) С приемом пришлось достать «Бубен» и поплясать )))) Следил за приемным буфером. Обнаружил, что буфер приема UserRxBufferFS[ ] принимает в 1-ый элемент символ с клавиатуры, а за ним еще какие-то «левые» два байта, остальное 00. Сделал тупо 100мс цикл чтения символа из UserRxBufferFS[ 0], если он 0, на начало цикла — остальное на вывод одного байта через функцию CDC_Transmit_FS(UserRxBufferFS, 1);
    Получил вывод нажатого символа на экран терминала.
    Функция CDC_Receive_FS() действительно Callback-овая, ее вызывает USB-стек. Что он там делает при приеме, не очень понятно )). Следить за буфером в поллинге занятие совершенно неблагодарное! Особенно, если собираешься работать под РТОС-ом. Поэтому тут еще надо подумать уже конкретно над вопросом куда впихнуть приемные семафоры (понятно, что где-то в прерывание, но вот где?).
    Как-то вот так))) Спасибо за долготерпение читать столько Буков!

    — обнуляю приемный буфер;

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *