Stm32 virtual com port driver linux

Stm32 virtual com port driver linux

Попробуем разобраться с реализацией USB на STM32L. Библиотека от ST просто ужасна. Нет, она прекрасно работает, но на ее примере разобраться с USB навряд ли получится. Она написана очень сложно. А вот на примере от keil (у них есть свой пример для USB) разобраться можно. Вот на таком немного переработанном примере я и постараюсь объяснить (хотя бы для самого себя) как можно реализовать USB на микроконтроллере.

В примере реализуется CDC устройство.

USB на ПК определяет подключение к шине какого-то типа устройства по появлению подтяжки на DM или DP.

  • pull-up на D- на стороне девайса — девайс говорит, что он Low-speed;
  • pull-up на D+ на стороне девайса — девайс говорит, что он Full-speed или High-speed (уточняется в дальнейшем диалоге с хостом);
  • оба пина без подтяжек на стороне девайса — он отключен от шины, и хост с ним не работает;

Для подключения резистора к DP нам понадобится модуль SYSCFG и регистр PMC(кроме того, в библиотеки периферии от ST в файле stm32l1xx_syscfg.c есть функция SYSCFG_USBPuCmd, которая поможет вам записать в этот регистр нужные значение — вкл/выкл подтяжку. Я ей буду пользоваться, поэтому ее надо подключить к проекту).

Инициализацию USB, для нашего микроконтроллера, разделим на 3 части.

  • Настройка частоты тактирования микроконтроллера и вкл. тактирования модулей периферии;
  • Настройка прерываний от USB;
  • Инициализация самого USB модуля (настраиваем через соответствующие регистры);

В самом начале надо настроить тактирование самого микроконтроллера — для этого я обычно изменяю сам файл system_stm32l1xx.c (из стандартного проекта keil дляSTM32). А точнее, функцию SetSysClock. Для USB нам необходимо, чтобы после PLLMUL была частота 96 МГц.

Если используем HSI 16 МГц, то надо выбрать коэффициент умножения 6. А после, для того, что-бы тактировать микроконтроллер от PLL выбрать, коэффициент деления 3. Тогда на выходе PLL, частота будет 32 МГц. При такой частоте, не забываем настроить пропуск такта при чтении FLASH (она может работать максимум на частоте 24 МГц, и если пропуск не настроить программа будет просто виснуть).

Теперь включаем тактирование USB периферии и SYSCFG (для включения подтягивающего резистора — см. выше).

Теперь переходим к настройке прерываний. В нашей программе мы будем использовать только вектор прерывания USB_LP_IRQHandler.

Он был использован в примере, и если честно, с другими векторами USB прерываний я не работал и не знаю как работать. В Reference Manual про них написано:

  • USB low-priority interrupt (USB_LP_IRQHandler) — страбатывает на всех USBсобытиях (корректная передача, USB reset и т.д.)
  • USB high-priority interrupt (USB_HP_IRQHandler) — срабатывает только на событии корректной передачи для isochronous and double-buffer bulk и используется для достижения наибольшей возможной скорости обмена.
  • USB wakeup interrupt (USB_FS_WKUP_IRQHandler) — срабатывает по просыпанию из Suspend mode.

Теперь перейдем к самой последовательности инициализации USB периферии. Объяснение действий — см. комментарии в коде. Все регистры для USB и значения, которые в них пишутся задефайнены в файле usb.h, можете посмотреть его скачав проект по ссылке ниже.

Дальнейшая настройка будет происходить в прерывании USB_LP_IRQHandler.

При общении с той или иной конечной точкой, вызывается соответствующая функция — USB_EndPoint0, USB_EndPoint1, USB_EndPoint2, USB_EndPoint3.

Именно в нулевой конечной точки реализованы все стандартные запросы USB, запросы специфические для CDC устройства (вирт. COM-порта). При запросе к нулевой точки, отдается дескриптор устройства (который необходимо заранее прописать).

Читайте также:  Почему не загружается windows через биос

Вторая и третья конечная точка вызываются при приеме и передачи данных соответственно. Точнее на передачу конечная точка вызывается постоянно с какой-то периодичностью, просто, грубо говоря, передается ноль байт (можете посмотреть в отладчике — постоянное попадание в функцию USB_EndPoint3). А в конечную точку на прием попадаем, лишь когда пришли данные с ПК.

Первая конечная точка для CDC устройства используется для настроек параметров самого COM-порта (хотя не уверен, я уже забыл — разбирался давно).

Дескрипторы для CDC устройства, с комментариями:

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

Проект — USB_CDC — для скачивания (проект сделан в keil, заархивирован 7Zip). Драйвер для ПК я брал от ST, его можно скачать или на сайте ST или скачать — stsw-stm32102.

Источник

I did some development on a Nucleo-64 board (specifically the NUCLEO-F303RE with the STM32F303RE microcontroller) and used OpenOCD and GDB with target remote :3333 to flash my code (with load ) onto my microcontroller.

During this time, I used the ST-LINK’s virtual COM port on my Linux machine (Ubuntu 16.04 (Xenial Xerus)) to talk with the microcontroller’s USART. Now I would like to just use the virtual COM port to talk the microcontroller without needing to start OpenOCD or GDB.

I was surprised to discover that this doesn’t just work. The symptoms are that my device doesn’t receive bytes send by the host nor vice-versa. (I detect bytes arriving at the target device by blinking an LED.) Therefore, it seems that the state of the ST-LINK microcontroller, or perhaps the Linux kernel on my host machine, is somehow changed by the process of connecting via OpenOCD and flashing the program.

My main question is: Is it possible to get to this virtual COM port working state on my Ubuntu 16.04 machine without launching OpenOCD or GDB? Ideally, I would not need to use any additional program, but perhaps just change some configuration setting.

My second question is: Why is this happening? Is the ST-LINK device itself changing modes here?

And my third question: Why is the following happening and what can I do about it? Sometimes, even after successful flashing, the target microcontroller can send bytes successfully, but is unable to receive them. Furthermore, I think one of my boards is neither able to send or receive bytes using this method although the firmware seems to upload just fine.

Источник

STM Урок 33. HAL. USB. Virtual Com Port

Урок 33

HAL. USB. Virtual Com Port

Отладочную плату ипользуем ту же: STM32F4-DISCOVERY.

Проект создаём из проекта I2CLCD80. Назовем его USB_OTG_CDC. Запустим проект в Cube, включим USB_OTG_FS в режим Device_Only

В USB_DEVICE в разделе Class For FS IP выберем пункт Communication Device Class (Virtual Port Com).

Лапки портов PD4-PD7, PB8, PB9 отключим, это пережиток прошлых занятий

В Clock Configuration выберем следующие делители (нажмите на картинку для увеличения изображения)

В Configuration ничего не трогаем, т.к. прерывания там выставились сами.

Сгенерируем и запустим проект, подключим lcd.c и настроим программатор на автоперезагрузку.

Соберем проект. Прошьём контроллер. У нас появится неизвестное устройство, скачаем драйвер на наше виртуальное устройство usb. Для этого зайдем на сайт st.com, в строке поиска там вводим virtual com port, скачиваем и устанавливаем драйвер. Затем желательно зайти в папку с установленным драйвером, выбрать папку, соответствующую разрядности нашей операционной системы, и запускаем также установку и оттуда.

Читайте также:  Системные драйвера windows для usb

У нас скорей всего устройство установится с ошибкой (код 10)

Есть несколько типов решений, мне понравился именно этот, т.к. более простой: в файле usbd_cdc.h заменим размер пакета, вместо 512 напишем 256 в данной строке:

#define CDC_DATA_HS_MAX_PACKET_SIZE 256 /* Endpoint IN & OUT Packet size */

Соберём, прошьём и увидим, что ошибка исчезла.

Начнём писать код.

Сначала попытаемся передать данные на ПК.

Для этого мы сначала откроем файл usbd_cdc_if.c и исправим там в 2х строчках 4 на 64

/* It’s up to user to redefine and/or remove those define */

#define APP_RX_DATA_SIZE 64

#define APP_TX_DATA_SIZE 64

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

/* USER CODE BEGIN 2 */

/* USER CODE END 2 */

Также в main.c подключим файл usbd_cdc_if.h для видимости функций приема и передачи

/* USER CODE BEGIN Includes */

Немного изменим в главной функции строковую переменную, убавив в ней размер и добавив префикс tx

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

В файле usbd_cdc_if.c добавим прототип функции передачи, скопировав объявление из реализации данной функции в том же файле

/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);

/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */

В main() внесём данные в строку

/* USER CODE END 2 */

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

CDC_Transmit_FS((unsigned char*)str_tx, strlen(str_tx));

/* USER CODE END WHILE */

Соберём код, прошьём контроллер и посмотрим результат в терминальной программе.

Вроде передать нам что-то удалось. Теперь попробуем что-нибудь принять. Здесь чуть посложнее, т.к. для этого используется уже обработчик прерывания, коим является в файле usbd_cdc_if.c функция CDC_Receive_FS.

Добавим ещё одну строковую глобальную переменную в main()

/* USER CODE BEGIN PV */

/* USER CODE END PV */

Объявим её также и в файле usbd_cdc_if.c

/* USER CODE BEGIN PRIVATE_VARIABLES */

extern char str_rx[21];

/* USER CODE END PRIVATE_VARIABLES */

В функцию CDC_Receive_FS в этом же файле добавим некоторый код и кое-что закомментируем

static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len)

/* USER CODE BEGIN 6 */

Добавим переменную в main()

/* USER CODE BEGIN 1 */

Занесенные в наш буфер данные попробуем вывести на дисплей, для этого в бесконечном цикле в функции main() добавим определённый код

CDC_Transmit_FS((unsigned char*)str_tx, strlen(str_tx));

Соберём проект. Прошьём код и посмотрим результат, вводя в терминальной программе и отправляя в порт USB какие-нибудь строки.

22 комментария на “ STM Урок 33. HAL. USB. Virtual Com Port ”

«Есть несколько типов решений, мне понравился именно этот, т.к. более простой: в файле usbd_cdc.h заменим размер пакета, вместо 512 напишем 256 в данной строке….»

Просто измените размер кучи (Minimum Heap Size) в настройка CubeMX. Вместо значения 0x200 задайте 0x400.

И комп увидит устройство без ошибок.

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

Пардон, очепятка вышла. Не компилятору, а функции malloc.

Спасибо, так действительно проще.

Спасибо огромное за ваши материалы по STM32 , подключил TFT 320×240 – все отлично работает . Вернулся к материалу для подключения флешки . Все отладочные средства у меня находятся на VirtualBox ( W7 ) . Скачал по вашей инструкции и поставил драйвер Virtual com port . Он поставился , но в диспетчере задач ничего не появилось ни в разделе com портов , ни в других . Может вы сталкивались с подобной проблемой ? Если нет – в любом случае еще раз спасибо за проделанную работу .

Сначала не смог реализовать данный пример на SystemWorkbench в части приёма данных и передачи их из функции приёма в main посредством массива str_rx с модификатором extern – компилятор ругается на использование неопределённых переменных, а если задать ему какие-нибудь значения, то только эти заданные значения и будут передаваться. Вышел из положения объявив массив обмена str_rx в заголовочном файле usbd_cdc_if.h

Читайте также:  Как обновить оценку производительности windows

Спасибо.Я сделал так.В хидер usbd_cdc_if.h добавил две строчки
extern uint8_t UserRxBufferFS[1000];
uint8_t receiveBufLen;
В метод CDC_Receive_FS добавил перед return receiveBufLen = *Len;
И в main ловил данные просто одним условием
if(receiveBufLen > 0)// если получены данные от ПК
<
HAL_Delay(250);
CDC_Transmit_FS((uint8_t*) UserRxBufferFS,receiveBufLen);
// эхо для наглядности
receiveBufLen = 0;// сброс получения
>
Всё просто,а UserRxBufferFS чистить не нужно от мусора,он сам чистится.

может в usbd_cdc_if.c ?

Здравствуйте! Спасибо огромное за ваши уроки, тут пожалуй лучший ресурс с уроками по стм32!
Хочу спросить, а как использовать CDC_Receive_FS в main.c? Я проделал в usbd_cdc_if.c «эхо», но мне нужно принимать из него и гнать дальше. Наверное вопрос больше в целом по си чем по контроллеру, а то иначе мне получается надо много всего переносить в usbd_cdc_if.c.

Думаю, что следует добавить в main.c функцию, а в файле usbd_cdc_if.c – на неё прототип и вызвать её в CDC_Receive_FS, И весь свой пользовательский код затем писать в файле main.c.
Это именно СИ. Так что обязательно подтяните свои знания по языку.

Ох, видимо сперва надо читать коментарии, прочитал тот что выше.

При переходе на USB cтолкнулся с такой проблемой. Скажем, конструкция, приведённая в примере, а именно
sprintf(str_tx,»USB Transmit\r\n»);
CDC_Transmit_FS((unsigned char*)str_tx, strlen(str_tx));
работает без проблем. Но, если я делаю так
sprintf(str_tx,»USB Transmit»);
CDC_Transmit_FS((unsigned char*)str_tx, strlen(str_tx));
CDC_Transmit_FS((unsigned char*)»\r\n», 2);
то CDC_Transmit_FS((unsigned char*)»\r\n», 2); не срабатывает (не успевает) и данные летят без переноса строки. Если ставить задержку, то работает как надо. По неопытности, может, это я и принял бы как должное, если бы перед этим не работал бы с UART где такая же конструкция работает без проблем. Для работы с UART уже написана довольно хорошая часть программы и менять её структуру очень не хочется, тем более, что данные передаются не в текстовом формате а в посылке имеется несколько меток. Что можно сделать, чтобы посылки могли идти подряд без задержки?

Скорей всего придется делать конкатенацию передаваемых строк с помощью strcat. Была аналогичная проблема при использовании CDC. Автор применял этот метод в одном из уроков.

Здравствуйте
А если я хочу передавать данные с микроконтроллера на компьютер?

Константин:
А мы их туда и передали.

Установил различные драйвера VCP от STM, но при этом плата не определяется при подключении её к компьютеру. только виден STLink Virtual COM Port. Кто уже сталкивался с такой проблемой.

Оказалась, что проблема с дровами. Надо их полностью сносить и устанавливать заново.

Hello, I’m new to STM32. How do I send int32_t value via usb CDC from ADC input ? or How to convert int32_t to char?

You can use(for example):

sprintf(str_tx,»ADC:%d \r\n»,ADC_Data);
CDC_Transmit_FS((unsigned char*)str_tx, strlen(str_tx));

where ADC_Data is your ADC value.

Спасибо за примеры. С USB в базовой библиотеке что-то не так. При первом подключении ком порт работает, но при передергивании USB – становится неизвестным устройством, иногда не сразу а через 5-10 секунд после повторного подключения…
Сейчас копаю в сторону функций вызываемых на отключение и подключение USB. Первое что кажется подозрительным, то что на подключение вызывается инициализация а на отключение USBD_LL_Suspend, затем на подключение снова инициализация, хотя есть USBD_LL_Resume. Пока дальнейших идей нет. Может что-то подскажете?

могу скачать драйвера для виртуального ком порта. У меня STM32F415RG, может есть у кого?

Источник

Оцените статью