Клавиатура своими руками stm32

Добавил пользователь Валентин П.
Обновлено: 05.10.2024

Ряд микроконтроллеров STM32 имеют на борту USB интерфейс для связи с компьютерами. Как правило, удобнее всего использовать предоставляемый компаний ST Microelectronics драйвер класса CDC (Communication Device Class ). Он позволяет использовать на стороне компьютера UART через USB и не требует установки драйверов. Со стороны STM32 при этом требуется только поменять операции вывода данных, остальное делается самостоятельно. Причём скорость такого соединения может быть практически любой, поддерживаемой компьютером.

Однако ряд разработок, особенно, когда приходишь в другую компанию, где используется HID Class (Human Interface Device), в случае разработки новой версии устройства требуется поддерживать ранее выбранный интерфейс. Что, собственно, и случилось. Примеры проектов от самой ST, которые они дают при загрузке STM32 Cube MX и IDE, как обычно, дали только минимальное понимание, но не раскрыли, что и как надо делать. Я когда-то разбирался с USB, даже писал собственный драйвер, но это было так давно… Остались только общие воспоминания. Посему пришлось искать дополнительную информацию, чтобы получить стартовую точку.

Первое найденное было видеороликом на youtube в стиле HID за 5 минут :-) Автор даёт доступ к своему коду на GitHub. Всё, типа круто, красиво, просто вставляйте к себе и всё будет чудесно. Судя по отзывам под роликом, некоторым этого хватило. Изучив исходники понял, что минимального прозрения не наступило, да и уровень полученной информации мал для того, чтобы решить поставленную задачу. Но закомство с этим материалом было явно полезным. Решение вопроса с использованием кубика (STM32Cube MX) мне лично импонирует больше, чем другие подходы, поскольку позволяет отвлечься от ряда низкоуровневых операций и генерация проекта всегда происходит в одном стиле. Соответственно, изучение этого примера показало, на какие файлы надо обратить внимание, где и что надо поменять или добавить, какие функции использовать для получения и отправки данных именно для нашей выбранной среды программирования.

Следующий поиск оказался весьма удачным. Хабр — известный сайт, на котором можно найти много полезного по разной электронной тематике. Нашлась там и статья STM32 и USB-HID — это просто. Я не являюсь постоянным клиентом Хабра и не знаю автора этой статьи RaJa, но на мой взгляд это очень хорошая статья, описывающая основные положения работы HID интерфейся. Без её прочтения читать дальше здесь бессмысленно, поскольку далее будут, в основном, комментарии для адаптации кода к среде разработки STM32IDE/STM32CubeMX + Atollic TrueStudio. (Далее STM32IDE). Да и столь популярный в 2014 году и реально очень неплохой проект EmBlocks, увы, умер.

Первое, что необходимо решить — как тестировать вновь создаваемое устройство. Лет… дцать назад я использовал для этого анализатор и синтезатор трафика USB — очень полезные, но дорогие игрушки :-) Сейчас у меня такой возможности нет, да и должен же быть более простой путь. Тем более для простого стандартного интерфейса без написания собственного драйвера. Авторы обоих рассмотренных выше проектов пошли самы простым для них путём — написание простой программы на известных им языках. Но автор статьи на Хабре сделал очень правильный шаг — он написал свой проект, совместимый с программой ST HID Demonstrator (ссылка есть в статье), позволяющей поуправлять нашим устройством, как графически, так и послать свои данные и посмотреть, что пришло от нашего устройства. Фактически программа может использоваться и в дальнейшем для отладки будущей программы на выбранном микроконтроллере.

Своё ознакомление с проектом для HID я осуществлял с платой STM32L476 Discovery. Плата, вообще говоря, может быть любой, где USB интерфейс микроконтроллера физически подключён к отдельному разъёму USB. Есть у меня и Nucleo 32 с STM32L4, но там один разъём USB тспользуется и для программирования/отладки, и для связи с хостом, что добавляет интриги в интерфейс и может служить источником дополнительных непоняток. Оно нам надо?

Итак, комментарии и дополнения к статье по привязке HID к STM32IDE примерно по тем же шагам, как и в хабровской статье.

Структура проекта

В STM32IDE структура всех проектов задаётся при генерации проекта из среды назначения функциональности пинов и пользователю о том заботиться не надо. В частности, в кубике (что отдельном STM32Cube MX, что в встроенном в STM32IDE) активируем USB, как Device, и добавляем Middleware USB Custom HID.

Заходим в Clock Configuration. Вполне вероятно, что могут быть проблемы с системными частотами, которые маркируются малиновым цветом.


Рис. 3 Возможные проблемы по установке частот

Если так, нажимаем Resolve Clock Issues и, скорее всего, всё будет настроено на максимальные частоты. Главное — USB Clock будет выставлен на 48 МГц. Надо заметить, что в семействе STM32L4 генератор на 48МГц имеет автоподстройку по SOF (Start Of Frame), что позволяет создавать USB устройства без внешнего кварца/генератора. Если, конечно, остальной дизайн допускает использование некварцованных генераторов. Для других семейств не проверял, поскольку для моего текущего проекта был выбран именно L4. Только надо отметить, что при использовании USB есть некоторая минимальная частота работы микроконтроллера. Я делал прикидку для другого проекта, где надо общаться с хостом и при этом потреблять минимум тока. Задачи простые, не требуют большой скорости и я хотел запустить МК на 8МГц. Оказалось, что меньше 14МГц при подключении USB ставить не могу, RCC не позволяет. Пришлось остановиться на следующем круглом значении 16МГц.

Это страшное слово Descriptor

Дескриптор от RajaДескриптор от STФайл в проекте
RHID_DeviceDescriptorUSBD_FS_DeviceDescusbd_desc.c
RHID_ConfigDescriptorUSBD_CUSTOM_HID_CfgFSDescusbd_customhid.c
RHID_ReportDescriptorCUSTOM_HID_ReportDesc_FSusbd_custom_hid_if.c

Поскольку для простоты сейчас будем работать только с ST HID Demonstrator, то не мудрствуя лукаво я просто скопировал содержимое RHID_ReportDescriptor в соответствующее место моего проекта. Только подставил свои константы на место длины. Надо отметить, что надо точно посчитать количество байтов в этом дескрипторе (в этом проекте 79) и убедиться, что именно это значение стоит в Class Parameters. Не больше и не меньше. Иначе хост не опознает подключённое устройство. Проверено :-)

Далее заходим в файл usbd_customhid.h и меняем значения CUSTOM_HID_EPIN_SIZE и CUSTOM_HID_EPOUT_SIZE на 0x40U. Честно говоря, немного напрягает то, что ST не даёт альтернатив смене значения по умолчанию 2 на другое значение и далее в коде с использованием этих констант стоит комментарий, что не более 2х байт. Но, с другой стороны, это было рекомендовано в первом найденном описании и, вообще говоря, установка такого значения выглядит достаточно логично. Иначе в чём отличие CustomHID от обычного? Проблема в том, что при регенерации проекта из кубика, что на этапе первичного кода происходит довольно часто, это значение не сохраняется и его надо восстанавливать ручками. Для этого я себе в main вывел строку warning, чтобы не забывать проверить эти константы. Возможно я ошибаюсь, и в дальнейшем всё окажется проще. Но в такой конфигурации работает :-)

Цикл обмена (пишем/читаем)

Для выдачи данных на хост всё достаточно аналогично описанию на Хабре. Только название функции другое: USBD_CUSTOM_HID_SendReport(). Все остальные реомендации из той статьи подходят по полной программе.

А вот чтение здесь интереснее, чем на Хабре. И на самом деле несколько проще. Обработка принятого массива происходит в usbd_custom_hid_if.c / static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state).

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

Звпускаем на хосте USB HID Demonstrator. На плате, с которой я запускал этот проект, не имеет органов для работы с Variable Inputs/Outputs, поэтому в разделе Graphic customization были убраны соответствующие назначениями, оставлено 5 кнопок и назначены ID, определённые в проекте: 1, 2 для Output report (входные данные для ST) и 4 для Input Report (выход от ST).


Рис. 4 Настройка демонстратора

Для дальнейшей работы обязательно прочтите указанную статью RaJa с Хабра. Она даст понимание того, что и как должно быть сделано для других проектов с USB HID интерфейсом. А ещё лучше начать с неё :-)

И при выборе класса устройства для Вашего проекта надо учитывать следующее: минимальный период опроса HID устройств — 1ms. И если я правильно помню, это скорее пожелание системе от внешнего устройства. В стандартном HID устройстве за один кадр (frame) передаётся только два байта, т.е. скорость обмена не более 2 кбайт/с. В Custom HID на
Full Speed (12 мбит/с) объём данных отчёта (report) - не более 64 байт, т.е. скорость обмена с Вашим HID не более 64 кбайт/с. Для High Speed (480 мбит/с) — максимальный объём данных 512 байт (512 кбайт/с). Не будь у меня ограничения совместимости с предыдущим софтом, используемым в компании, использовал хотя бы CDC.

У меня изучение статей и адаптация под мои хотелки заняло три дня. Описание заняло больше :-) Надеюсь, что у тех, кто воспользуется этой статьёй, аналогичный процесс займёт не более одного дня. Комментируйте, спрашивайте. Что смогу — отвечу. Что не смогу, вместе поищем решение.

Хотите прокачать ваши Arduino проекты? Заставить их работать быстрее, измерения и регулировку сделать точнее, ну и добавить баги(с новыми девайсами они неизбежны). Тогда эта статья для Вас.

Краткое изложение данной статьи в видео формате:

Ладно, меньше лирики и ближе к теме. В этой статье, я буду рассматривать дешёвую отладочную плату, которая основана на базе микроконтроллера :


Для начала, сравним основные параметры STM32 платы, и её аналога по цене - Arduino Nano V3.0:



Для чего нужны BOOT0 и BOOT1 джамперы

Дело в том, что в STM32 с завода прошит, в так называемую системную память(system memory), специальный загрузчик, который позволяет прошивать плату через самый обычный USB to UART переходник, не прибегая к специфическим программаторам типа ST-Link V2 .



Дальше нам понадобиться переходник с USB на UART. Стоит помнить, что STM32, это 3.3 В логика , совместимость с 5-ти вольтовой не гарантируется, поэтому рекомендовано использовать USB to UART, у которого есть возможность выбора режимов работы с 3.3/5В логикой. Я использовал дешёвый переходник на базе CH340G:



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

Плату подключил к USB to UART переходнику следующим образом:

G GND;
5V 5V;
PA10 TXD;
PA9 RXD.



* PA10/PA9 на плате подписаны просто как A10/A9 - эти порты являются первым аппаратным USART"ом, всего их на плате 3, так же тут 2 аппаратных I2C и 2 SPI.

Качаем, устанавливаем и запускаем Flash Loader Demonstrator (есть в архиве к статье):





Так как моя отладочная плата основана на микроконтроллере STM32F103C8 - здесь 64 Кбайт Flash памяти, есть ещё STM32F103CB микроконтроллер, где в два раза больше Flash.





Потом надо скачать, для среды разработки Arduino IDE, специальное STM32 ядро (так же есть в архиве к статье). Тут есть один нюанс, на момент написания статьи, ядро не работает на версиях среды разработки свыше 1.6.5 , у меня стоит 1.6.5-r5 которую .
Проверенна работоспособность ядра на .





Не совсем понятно почему после первого подключения плата определяется по-разному, на разных компьютерах, но не суть, приступаем к настройке Arduino IDE.







* К стати, загорается он по низкому уровню на ножке PC13.


Couldn"t find the DFU device


Это означает, что плату прошить не удалось.

Searching for DFU device .

Когда среда разработки выдаёт:


И больше ничего не происходит, попробуйте в этот момент перезагрузить плату клацнув кнопку ресет. По аналогии это как с Arduino Pro Mini.

По поводу распиновки:

Кликабельно

Лучшее что мне удалось найти, это распиновка самого микроконтроллера(открывайте в новой вкладке):

К порту нужно обращаться по полному имени, например:

digitalWrite(PB0, LOW);
analogWrite(PA8, 65535); pwmWrite(PA8, 65535);
analogRead(PA0);
LiquidCrystal lcd(PB0, PA7, PA6, PA5, PA4, PA3);

Я порылся в файлах ядра, и нашёл один интересный файл:
Documents\Arduino\hardware\Arduino_STM32\STM32F1\variants\generic_stm32f103c\board.cpp

Там прописаны все порты, которые поддерживают:

  • ШИМ, то есть функция analogWrite(); pwmWrite(); - PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8, а это далеко не все, которые размечены на распиновке чипа;
  • АЦП, аля analogRead(); - PB0, PA7, PA6, PA5, PA4, PA3, PA2, PA1, PA0.

Так что имейте это ввиду. Хотя этого более чем достаточно от платы, стоимостью в 1.9 доллара.

Ещё заметил, что пины PA12/PA11 подключены к D+/D- USB, их лишний раз лучше вообще не трогать, ибо чуть что, на кону не 2-х долларовый кусок стеклотекстолита с чипом, а материнская плата компьютера.

Схема отладочной платы:

Ну и на последок:


Линейка микроконтроллеров STM32 представляет собой достаточно интересный объект для изучения. Часто можно услышать мнение, что работа с ним сложна для начинающего и лучше браться за что – нибудь более простое. В этой статье мы постараемся показать, что микроконтроллеры STM32 не так страшны.

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

При работе, описанной в данной статье, использовалась отладочная плата STM32F4Discovery и матричная клавиатура, в нашем случае, имеющая 7 выводов. Среда разработки CoIDE 1.7.6.

Для того, чтобы разобраться в программе, реализующей данную операцию, необходимо иметь минимальные знания и навыки работы с портами ввода/вывода и системными таймерами. С существующими методами подключения клавиатуры можно познакомиться по ссылке .

Перед тем, как приступать к написанию программы, определимся с условными обозначениями:

Рисунок 1 – Подключение клавиатуры

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

В данном примере, для того чтобы понять правильно или нет написана программа, использованы различные комбинации светодиодов, расположенных на плате, клавиша 5 – выключает все светодиоды.

Поясним выше сказанное на примере. Подключаем щуп мультиметра к крайнему столбчатому выводу, а второй к любому строчному и проверяем последовательно каждую клавишу из столбика, соответствующего выбранному столбиковому выводу, на прозвонку. При появлении контакта смотрим на номер нажатой клавиши и каким выводам из рисунка 1 соответствует это событие. Далее мы переносим соответственно значение для столбикового контакта и строчного.

Теперь поговорим об инициализации используемой периферии. В этом проекте используются порты A и D, как порты ввода-вывода, а так же таймеры TIM2 и TIM3. Листинг программы снабжен подробными комментариями по пунктам настройки периферии.

«. Сегодня подключаем матричную клавиатуру к плате Arduino, а также рассматриваем интересные схемы с ней. Сделать такую клавиатуру можно и самому из кнопок и печатной платы. В статье видео-инструкция, листинги программ, схемы подключения и необходимые компоненты.

Большая часть текста содержит объяснение программного кода, его можно скачать либо посмотреть видео под статьей.

Сделать такую клавиатуру можно и самому. Для этого понадобится печатная плата, 12 или 16 обычных кнопок и соединительные провода. Я же буду использовать готовую.


Для чего нужна матричная клавиатура?

Для этого и придумали такую клавиатуру, чтобы упростить подключение большего числа кнопок. Такие устройства встречаются везде — в клавиатурах компьютеров, калькуляторах и так далее.

Подключать ее к плате следует 8 выводами, каждый из них считывает значения с определенных строк и столбцов. Подключать их следует к выводам на панели Digital. Я подключу, например, к выводам от 2 до 9 включительно. Нулевой и первый трогать не желательно, поскольку они предназначены для UART интерфейса (например, для подключения блютуз-модуля). Рациональнее оставить их свободными.


После того, как вы установили в библиотеку, можно зайти в Ардуино IDE (программа с сайта Arduino) и посмотреть примеры скетчей.

Возьмем самый простой скетч для ознакомления. Он позволяет считывать значение с клавиатуры при нажатии определенной клавиши и выводить их в порт. В данном случае это монитор порта на компьютере.


void setup() Serial.begin(9600);
>
void loop()

if (customKey) Serial.println(customKey);
>
>

Скетч очень простой. Стоит отметить первые строчки кода. Сначала подключаем библиотеку, затем указываем сколько строк и столбцов у клавиатуры, а потом нужно правильно расположить названия клавиш, чтобы было удобнее работать.

Если это сделать неправильно, то, например, при нажатии цифры 4, в порт выйдет цифра 6 или любой другой символ. Это можно определить опытным путем и расположить символы, как они расположены на клавиатуре.

В функции void setup указываем скорость последовательного соединения с монитором порта 9600 бод . Функция нужна только для подачи питания на модули. В функции Void Loop прописываем условие. Переменная Char используется для хранения только одного символа, например, 1, А или 5, что подходит к ситуации. Если нажатие зафиксировано, то происходит вывод символа в монитор порта с помощью функции Serial Print. В скобках нужно указывать, какую переменную выводим в порт. Если все сделано верно, в мониторе порта получим символ, на который нажимали. Не забудьте в мониторе порта внизу справа указать скорость передачи данных такую же, как в скетче.

Схема с дисплеем и матричной клавиатурой

Давайте выведем данные на дисплей.


Далее нужно указать размерность дисплея. Используемый в примере дисплей вмещает по 16 символов в каждой из 2-ух строк, это я и указываю. В функции Void Setup нужно подать питание на дисплей и включить подсветку. Делается это с помощью двух функций: lcd.begin и lcd.backlight .

В функции Voil Loop нужно в самом условии прописать строчку lcd.print для вывода данных на дисплей. И еще нужно предварительно установить положение курсора. В скобках идут 2 цифры: первая — это номер символа, а вторая — номер строки. Нужно помнить, что у этого дисплея отсчет строк и столбцов начинается не с единицы, а с нуля. То есть здесь имеются строчки под номерами 0 и 1, а не 1 и 2, как может показаться сначала. Затем загрузим код в плату и посмотрим, что будет.

Как видим, нажимая на любой символ, видим его отображение на дисплее.


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

Подключение клавиатуры к Arduino и управляющее действие

Последняя схема в уроке — выполнение заданного действия при нажатии определенной клавиши. Это основная цель подключения матричной клавиатуры к Arduino. По этой теме будут две отдельные статьи и видео, описывающие более сложные и интересные схемы. А сейчас знакомимся с этим модулем и запоминаем построение кода с его использованием.

Попробуем при нажатии определенной клавиши включать или выключать светодиод. Добавляем его в схему.


Я буду использовать макетную плату и резистор (желательно использовать от 150 до 220 Ом). Двумя перемычками замкну схему, подключив их к пинам питания и земли на плате Ардуино.

Схема будет работать так: при нажатии на 1 включается светодиод, при нажатии на 2 — выключается.

Светодиод в примере подключен к пину 8 на плате Ардуино.

Давайте разберем скетч.

Возьмем первый скетч урока и просто его дополним. В начале с помощью полезной функции Define присвоим название подключенному к пину 8 светодиоду ledpin . В функции Void setup указываем сигнал со светодиода как выход.


Отладочная плата F103C8T6 на базе STM32 по параметрам значительно опережает аналогочные по размеру Arduino Nano или Leonardo, а по скорости близка к Arduino DUE. Есть интерес попробовать, но у новичка могут возникнуть трудности с первым запуском и программированием данной платы. Теперь есть возможность заливать скетчи через Arduino IDE. Подробности далее.

  1. Отличия STM32F103C8T6 от Arduino Nano v3.0
  2. Подготовка железа
  3. Подготовка ПО
  4. Закачка скетча (blink) в плату

1. Отличия STM32F103C8T6 от Arduino Nano v3.0

2. Подготовка железа

Для работы нам понадобится:

  • Сама плата STM32F103C8T6
  • Соединительные провода Dupont мама-мама

Для активации режима программирования на плате STM следует преставить перемычки: первая на 1, вторая на 0.

Конвертер FTDI переключить на питание 3.3 Вольта (перемычкой/джампером)

Соединить проводами плату (П) и конвертер (К):

3. Подготовка ПО

4. Закачка скетча (blink) в плату

В папке которую мы распаковали в п.3.б заходим по следующему пути: Arduino_STM32\examples\Digital\Blink\ и через Arduino IDE открываем файл blink.ino либо можете взять текст отсюда:

Жмем кнопку Вгрузить и результат сразу должен быть виден.

Иногда мы сталкиваемся с проблемой нехватки портов на Arduino. Чаще всего это относится к моделям с небольшим количеством выводов. Для этого была придумана матричная клавиатура. Такая система работает в компьютерных клавиатурах, калькуляторах, телефонах и других устройств, в которых используется большое количество кнопок.

Для Arduino чаще всего используются такие клавиатуры:

Самыми распространенными являются 16 кнопочные клавиатуры 4x4. Принцип их работы достаточно прост, Arduino поочередно подает логическую единицу на каждый 4 столбцов, в этот момент 4 входа Arduino считывают значения, и только на один вход подается высокий уровень. Это довольно просто, если знать возможности управления портами вывода в Arduino , а так же портами входа/ввода.


Для программирования можно использовать специализированную библиотеку Keypad, но в этой статье мы не будем её использовать для большего понимания работы с матричной клавиатуры.

Подключаем клавиатуру в любые порты ввода/вывода.


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

В программе будем вычислять нажатую кнопку и записывать её в Serial порт.
В данном методе есть один значительный недостаток: контроллер уже не может выполнять других задач стандартными методами. Эта проблем решается подключением матричной клавиатуры с использованием прерываний .

Микроконтроллеры STM32F3

Продолжаем работать с интерфейсом USB, и сегодня пришло время практики. Как вы помните, теоретические аспекты мы уже рассмотрели (вот), так что сегодня возьмем в руки STM32 и напишем небольшой примерчик. Сразу скажу, что я решил поэкспериментировать с контроллером STM32F303 и, соответственно, с платой STM32F3Discovery.

На плате уже есть два USB разъема, один под ST-Link и второй для пользовательских задач, то есть как раз то, что нам надо.

С платой разобрались, теперь по поводу софта. STMicroelectronics любезно предоставили библиотеки для работы с USB для различных семейств микроконтроллеров, а кроме того, выпустили кучу примеров под разные отладочные платы. Но плат Discovery в этом списке нет, поэтому не станем вносить свои изменения в уже готовые проекты от ST, а лучше создадим свой новый проект, взяв из примеров и библиотек только то, что нам реально понадобится.

Задача будет такая — по приему байта данных по USB, контроллер зажигает определенное количество светодиодов. Если пришел байт 0х01 — светится один диод, 0х02 — два, 0х03 — три, ну и так далее. Для того, чтобы реализовать отправку данных с компьютера, поставим драйвер виртуального ком-порта и будем общаться с платой через обычный терминал (я использую Advanced Serial Port Monitor).

Нужный драйвер без проблем можно скачать на официальном сайте STMicroelectronics. Устанавливается тоже без проблем и в итоге в диспетчере устройств появляется следующее:

USB устройство на STM32.

С этим разобрались, давайте теперь откроем какой-нибудь примерчик от ST и посмотрим как же вообще в их библиотеках устроен обмен данными по USB. Вот архив со всеми библиотеками и примерами — ST USB Library.

Заходим в папку с примерами и выбираем Virtual Com Port, там без труда находим нужную нам папку с проектом для Keil’а и запускаем его. Давайте сразу же посмотрим на файл main.c:

Видим, что в теле цикла while(1) пусто, соответственно вся работа происходит в прерываниях. В функции main() всего лишь вызываются функции инициализации. Все эти функции реализованы в файле hw_config.c, его мы поправим под себя чуть позже. Для приема и передачи данных по USB в файле usb_endp.c предусмотрены соответствующие обработчики:

Как вы помните из предыдущей статьи, транзакции IN нужны для передачи данных хосту (то есть ПК), а транзакции OUT для приема данных от хоста. Соответственно, для отправки данных используется конечная точка 1 (End Point 1), а для приема — End Point 3. Как программа попадает в эти обработчики? Сейчас разберемся! В файле stm32_it.c есть обработчик прерывания:

В его теле вызывается всего лишь одна функция — USB_Istr(), которая описана в файле usb_istr.c. Идем в этот файл и изучаем функцию… А там все в принципе просто, программа выясняет какое именно событие вызвало прерывание и в соответствии с этим происходит дальнейшая работа. Соответственно, при транзакциях IN или OUT вызываются именно те функции которые мы уже рассмотрели выше, а именно:

Этот проект вообще по умолчанию адаптирован для контроллеров STM32F10x, да и файлов очень много лишних, так что давайте-ка создадим свой новый пустой проект и в нем уже будем работать. Напоминаю, что я буду работать с STM32F3Discovery, поэтому проект создаю для контроллера STM32F303VC. Забираем из папки с библиотеками и примерами все файлы, которые нам понадобятся. Вот их полный список:

Файлы библиотеки USB.

В папку SPL я просто запихал все файлы из Standard Peripheral Library для STM32F303. Не забываем в настройках проекта указать все пути к файлам и прописать подключение SPL ( в общем, все как тут — ссылка). Проект создан, файлы все на месте, давайте писать код. И начинаем с функций инициализации, расположенных в файле hw_config.c:

Что за пины мы настраиваем тут? А вот:

Выводы для работы с USB в STM32.

С PA11 и PA12 разобрались, а все остальные ножки — это светодиоды, которые есть на плате.

Идем дальше… Из функций для работы с USART’ом я просто все удалил, поскольку мы приемопередатчиком пользоваться не будем. Настраиваем прерывания:

И еще я добавил небольшую функцию в этот же файл. Она просто гасит все светодиоды:

Не забываем в файл hw_config.h дописать прототип для этой функции:

С инициализацией вроде бы все. Открываем файл usb_endp.c. Мы будем только анализировать принятые от хоста данные, поэтому обработчик транзакций IN нам не понадобится:

В обработчике транзакций OUT принимаем данные и в зависимости от того, какой байт принят зажигаем определенное количество светодиодов, которые у нас висят на GPIOE:

Так… Ну вроде бы на этом все. Вот полный проект: Проект для USB

Прошиваем микроконтроллер и тестируем! Вот, что получилось:

Программа для работы с USB

Послали байт 0х04 — загорелось 4 светодиода, аналогично работает и для любого другого количества светодиодов. Так что, на сегодня, пожалуй все, но опыты с USB, на этом только начинаются!

Когда вы первый раз заходите с помощью соцсетей, мы получаем публичную информацию из вашей учетной записи, предоставляемой провайдером услуги соцсети в рамках ваших настроек конфиденциальности. Мы также автоматически получаем ваш e-mail адрес для создания вашей учетной записи на нашем веб сайте. Когда она будет создана, вы будете авторизованы под этой учетной записью.

Когда вы первый раз заходите с помощью соцсетей, мы получаем публичную информацию из вашей учетной записи, предоставляемой провайдером услуги соцсети в рамках ваших настроек конфиденциальности. Мы также автоматически получаем ваш e-mail адрес для создания вашей учетной записи на нашем веб сайте. Когда она будет создана, вы будете авторизованы под этой учетной записью.

А не могли бы Вы дать подсказку как настроить передачу, с помощью функции USB_SIL_Write(), и может ли плата только передавать хосту, не принимая ничего.

В принципе при передаче все точно также, callback само собой для транзакций IN используется

Спасибо за описание, но проект по ссылке не полный нет файла самого проекта и он не собирается сразу.

Сорри. Всё нормально. У меня архив чем-то порезало

Доброе время суток! 🙂
очень хорошая статья! большое спасибо! вот начинаю пробовать работать с ЮСБ, очень интересно! вот только вопросы возникают! можно ли на 10х процессорах сделать преобразователь например в 2 кома, или сделать хид клавиатуры и мыши? или хотябы на 207?! по одному устройству примеры работоспособны. заранее спасибо!

HID можно я думаю без проблем сделать)

Пиши, если будут какие-нибудь трудности )

Здравствуйте.
Спасибо за статью. Но появились проблемы при отладке. Постоянно возникает прерывание USB_LP_IRQHandler. Это нормально? При этом отладчик уходит в завис и прервать его можно только насильно. Процессор STM32F373V8, установленный в STM32F3Discovery вместо 303-го. Может в этом проблема кроется?
Пробовал и исходный проект от STM — тоже самое.

Видимо да, проблема в контроллере

Здравствуйте.
Подскажите пожалуйста, а как переменную типа uint32_t ( ADC_Result из вашей статьи Работа с ADC и DMA) можно передать по USB, так как в этом проэкте переменная которая передается по USB — типа uint8_t.
Заранее благодарен за ответ!

Передавать 4 байта просто:
ADC_Result_1 = (ADC_Result & 0xFF000000) >> 24;
ADC_Result_2 = (ADC_Result & 0x00FF0000) >> 16;
ADC_Result_3 = (ADC_Result & 0x0000FF00) >> 8;
ADC_Result_4 = (ADC_Result & 0x000000FF);

uint8_t tBuff[4];
uint32_t *tADC;

tADC = (uint32_t) tBuff;
*tADC = ADC->DATA;

Здравствуйте.
Подскажите пожалуйста, программировал через Keil было все в норме потом вдруг стало. Error
No target connected.
Flash Download failed-Target DLL has beeh cancelled. На втором компе уже такое произошло. Дрова переустанавливал не помогло. Через STM32 ST-LINK Utility зашивает без проблем.

Может настройки в Кейле слетели?

Нет все настройки на месте. Сам не пойму почему так.

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

Да, и где в проекте вышеизложенная функция:
void EP3_OUT_Callback(void). Она в main.c отсутствует.

И еще, можно по подробнее о функциях USB_SIL_Write и USB_SIL_Read, можно ли просто бит считать без всяких буферов?

этот вопрос отпал)

Под F1 у меня нет проекта — надо на сайте ST смотреть, вроде бы у них были примеры.

Только пример от ST глюченый, мк без соединения с компом зависает намертво даже отладчик от него отваливается.

Вроде бы, STM32 с нуля, а как его питать, шить и отлаживать статей нет. Все на готовых платах.

Тогда это не STM32 с нуля, а программирование STM32 для начинающих.
С нуля, это как у буржуев, когда закрыта пропасть между МК и готовой платой, а в этой пропасти односторонняя макетка утюгом, прошивка всеми способами, моргание лампочкой, отладка и прочие радости.

Скажите пож что делать Я запрограммировал STM32SISCOVERY проектом который вы выложили, но после этого не могу больше запрограммировать чип Программатор выдает : Internal command error Похоже , что где-то установилась защита по записи в чип. Спасибо

При программировании попробуй так:
— зажимай кнопку reset на плате
— нажимай кнопку Program
— через секунду-две отпускай кнопку reset

Спасибо за статью. Наконец-то удалось запустить usb на stm32f3discovery. Возникла такая проблема. Если я использую библиотеки из Вашего проекта в своем проекте, то все работает нормально. Если же я беру исходные ST USB Library то проект не собирается, хотя список файлов, прикрепленных к проекту, идентичен. Нужно ли вносить какие-либо изменения в библиотеки, за исключением описанных Вами в статье? Хотел бы разобраться в этом вопросе, т к собираюсь использовать usb библиотеку для stm32f103.

Вроде бы я тут все описывал, что менял в файлах библиотек…

Посмотрел внимательнее — в Вашем проекте отличается заголовочный файл platform_config.h, раздел include. Но даже после его исправления проект не собрался, похоже есть еще какие-то различия.

Установил все драйвера с официального сайта. USB ST-LINK работает исправно, а вот при подключении разъема USB USER в диспетчере устройств плата отображается как Unknown Device. Подскажите пожалуйста, в чем может быть проблема ?

А драйвер virtual com-port поставил?

Добрый день, что означают эти строчки ?
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;
Где можно почитать это?

В даташите описаны режимы, в которых может работать вывод микроконтроллера. В этих строках вывод просто настраивается.

Могли бы Вы указать страницу даташита

Ставил, даже несколько разных скачивал

Тогда еще вариант ) Может система 64 битная? Были случаи (и не единичные), когда на х64 отказывалось напрочь работать.

Сам понял свою ошибку — пытался подключить непрошитое устройство. После прошивки примера — все заработало и com-порт появился.

Хорошо, что заработало )

Здравствуйте! Пытаюсь собрать проект в Keil, но выходят ошибки. Не подскажите в чём проблема.


Я покажу вам некоторые важные функции этой платы, как настроить существующую среду Arduino для работы с этой платой, а также написать первую программу, которая является ничем иным, как, как вы уже догадались, Blink. Итак, начнем.

Вступление

В последнее десятилетие Arduino стала платформой для быстрого создания прототипов, хобби-проектов или в качестве платы отладки для начинающих радиолюбителей. Но мы все знаем об ограничениях платы Arduino. Давайте обсудим Arduino UNO, так как это самый популярный Arduino.

Эта плата медленная, работает на частоте 16 МГц, имеет очень ограниченное внутреннее оборудование и не имеет достаточной вычислительной мощности, ОЗУ и Flash для запуска приложения на основе FreeRTOS (теоретически вы можете запустить FreeRTOS на Arduino, но это не практично).

Альтернативой Arduino является плата разработки на основе микроконтроллера STM32F103C8T6, которую часто называют Blue Pill. Этот микроконтроллер основан на архитектуре ARM Cortex-M3 производства STMicroelectronics.

STM32F103C8T6 является очень мощным микроконтроллером и с 32-разрядным процессором легко может превзойти по производительности Arduino UNO. В качестве дополнительного бонуса вы можете легко запрограммировать эту плату, используя вашу Arduino IDE (хотя и с некоторыми хитростями и дополнительным программатором, например конвертером USB в U (S) ART).

Краткая заметка о плате разработки STM32F103C8T6

На следующем рисунке показана лицевая и задняя стороны типичной платы Blue Pill STM32. Как видите, макет платы очень прост, и некоторые могут даже спутать ее с Arduino Nano.


Важной особенностью этих плат является то, что они очень дешевы, дешевле, чем клонированная версия Arduino UNO. Я получил эту плату примерно за 2,5 доллара в местном магазине электроники. Таким образом, это, очевидно, клонированная версия (возможно, поддельный микроконтроллер STM32). На рынке доступно много клонированных версий этой платы.



Особенности платы

  • Она содержит основной микроконтроллер — STM32F103C8T6.
  • Кнопка сброса — для сброса микроконтроллера.
  • Порт microUSB — для последовательной связи и питания.
  • Перемычки выбора BOOT — перемычки BOOT0 и BOOT1 для выбора загрузочной памяти.
  • Два светодиода — пользовательский светодиод и индикатор питания.
  • Кварц на 8 МГц.
  • Кварц 32,768 кГц — часы RTC.
  • SWD Interface — для программирования и отладки с использованием ST-Link.
  • Стабилизатор питания 3,3 В — преобразует 5 В в 3,3 В для питания микроконтроллера.

На каждой длинной стороне платы есть контакты для подключения различных аналоговых и цифровых устройств ввода-вывода и питания. На следующем рисунке показана конфигурация контактов платы, а также различные функции, поддерживаемые каждым контактом.

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

Проблемы с STM32 Blue Pill Board

Если вы планируете купить более дешевую версию (вероятно, большинство из нас так и поступают), то есть некоторые известные проблемы с платами, о которых вы должны знать. Я собрал эти вопросы на разных форумах и сам столкнулся с некоторыми проблемами (связанными с USB).

  • Первым основным вопросом является стабилизатор напряжения 3,3 В. Хотя на некоторых платах использовались оригинальные регуляторы напряжения 3,3 В на LM1117 от TI, на большинстве дешевых плат разработки установлены не имеющие аналогов стабилизаторы напряжения. Эти стабилизаторы не имеют никакой тепловой защиты и легко выходят из строя. Решением является использование внешнего регулируемого источника питания, если у вас есть такая возможность.
  • Следующие две проблемы связаны с USB. Во-первых, качество пайки порта microUSB очень низкое, и если вы часто отсоединяете и вставляете кабель в этот порт, то существует высокая вероятность того, что разъем microUSB отсоединится от платы. Вы можете использовать горячий клей для усиления разъема.
  • Другой проблемой, связанной с USB, является использование неправильного подтягивающего резистора. Согласно справочному руководству MCU, USB D + (называемый USBDP) должен быть поднят до 3,3 В с использованием резистора 1,5 кОм. Но согласно схемам нескольких плат Blue Pill, все они используют резистор 10 кОм. Если вы планируете работать с передачей данных через USB, вы можете не получить точных результатов. Если вы хотите испровить это, тогда вы можете припаять резистор 1,8 кОм параллельно существующему резистору 10 кОм. Для этого подключите резистор 1,8 кОм между контактами A12 и 3,3 В.
  • Другие известные проблемы: очень трудно нажимать на кнопку сброса, аналоговое питание подключено к цифровому питанию, нет защиты диода Шоттки для USB и т. д.

Основные моменты STM32F103C8T6

Теперь, когда мы немного узнали о плате Blue Pill, давайте теперь разберемся с некоторыми важными особенностями самой платы, то есть микроконтроллера STM32F103C8T6. Как упоминалось ранее, этот микроконтроллер содержит 32-битное ядро ​​ARM Cortex-M3 с максимальной частотой 72 МГц.

Давайте теперь посмотрим, какие технические характеристики этого микроконтроллера реализованы на плате Blue pill.

Характеристики STM32F103C8T6

  • Память: содержит 64 Кбайт Flash и 20 Кбайт SRAM
  • GPIO Pins — 32 с возможностью внешнего прерывания
  • Таймеры — 3 16-битных таймера, 1 16-битный ШИМ-таймер
  • PWM Pins — 15
  • Аналоговый — 10 каналов 12-битного АЦП
  • I2C — 2 периферийных устройства I2C
  • USART — 3 периферийных устройства USART с аппаратным управлением
  • SPI — 2 SPI периферийных устройства
  • Другие периферийные устройства — USB 2.0 Full Speed, CAN 2.0B

Это некоторые из основных моментов, и если вы хотите узнать больше информации о периферийных устройствах, вам следует обратиться к datasheet (настоятельно рекомендуется).

В качестве дополнительной темы позвольте мне рассказать вам о маркировке, используемое в микроконтроллерах STM32 на примере STM32F103C8T6. Каждая буква в названии микроконтроллера обозначает особую характеристику:


Как использовать выводы BOOT ?

Как упоминалось ранее, контакты BOOT0 и BOOT1 микроконтроллера используются для выбора памяти, с которой он загружается. На следующем рисунке показаны три различных варианта загрузочных пространств на основе этих контактов:


Когда контакты BOOT0 и BOOT1 имеют НИЗКИЙ уровень, тогда внутренняя флэш-память выступает в качестве основного загрузочного пространства, а когда BOOT0 — ВЫСОКИЙ, а BOOT1 — низкий, системная память выступает в качестве основного загрузочного пространства. Эти два варианта важны для нас.

Чтобы загрузить код во флэш-память микроконтроллера, вы должны выбрать системную память в качестве основного загрузочного пространства. Причина этого заключается в том, что системная память содержит встроенный загрузчик, который программируется во время производства.

Загрузив в системную память, т. е. в bootloader ROM, вы можете перепрограммировать флэш-память в своем приложении, используя последовательный интерфейс USART1.

Как только программа будет загружена во флэш-память, вы можете переключить BOOT0 на LOW, чтобы после следующего сброса или включения питания микроконтроллера программа загрузилась из флэш-памяти.

Если вы заметили, в обоих случаях, т.е. при выборе флэш-памяти и выборе системной памяти в качестве загрузочных пространств, вывод BOOT1 имеет НИЗКИЙ. Только BOOT0 переключается между LOW (флэш-память) и HIGH (системная память).

Для удобства, давайте назовем эти варианты загрузки как режим программирования и рабочий режим. Для режима программирования вывод BOOT0 устанавливается ВЫСОКИМ, а для режима работы вывод BOOT0 — НИЗКИМ (по умолчанию). В обоих режимах контакт BOOT1 остается НИЗКИМ.

Требования к оборудованию для проекта

Поскольку это наша вводная часть, и все, что мы будем делать, это мигать светодиодом (который уже присутствует на плате), нам не нужно много оборудования в отношении проекта и микроконтроллера.

Но для программирования микроконтроллера нам нужен модуль USB-последовательный преобразователь, такой как плата FTDI (или что-то подобное). Как упомянуто в разделе BOOT Pins, к загрузчику можно получить доступ с помощью контактов USART1 микроконтроллера для программирования флэш-памяти. И чтобы микроконтроллер мог обмениваться данными с USART1, нам необходим USB-последовательный преобразователь.

Список необходимых компонентов

  • STM32F103C8T6 на основе STM32 Blue Pill Development Board
  • Модуль преобразования USB в последовательный интерфейс (например, программатор FTDI)
  • Соединительные провода
  • ПК или ноутбук с ОС Windows и подключением к Интернету

ПРИМЕЧАНИЕ. У меня нет программатора в стиле FTDI, но есть конвертер USB в последовательный интерфейс более старого типа. Вы можете использовать любые модули USB to Serial Converter, если они имеют контакты VCC (5 В), GND, RX и TX.

Соединение

Для упрощения представления я использую FTDI, такой как USB to Serial Converter.

Соединения должны быть следующими:

STM32 Blue Pill — программатор FTDI

  • 5 В — VCC
  • GND — GND
  • A9 — RX
  • A10 — TX


Настройка Arduino IDE для STM32F103C8T6 Blue Pill


Если у вас уже есть несколько URL-адресов в этом разделе, вы можете добавить больше, разделив их запятой. Если вы работали с платами ESP8266, то вы, возможно, уже знакомы с этим процессом. После добавления URL нажмите ОК.

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




Загрузка STM32CubeProgrammer

Итак, мы должны установить его вручную. Для этого перейдите на официальную страницу загрузки STM32CubeProgrammer, предоставленную STMicroelectronics, по следующей ссылке.

Нажмите на опцию Get Software, и вы попадете на страницу входа / регистрации. Я предлагаю вам зарегистрироваться в STMicroelectronics с действительным адресом электронной почты. После регистрации вы можете войти и загрузить программное обеспечение.

Убедитесь, что каталог установки установлен по умолчанию, и ничего не меняйте. Может потребоваться разрешение на установку некоторых драйверов для ST-Link. Вы можете предоставить необходимые разрешения.


ПРИМЕЧАНИЕ. Это может быть либо Program Files, либо Program Files (x86) по указанному выше пути.

На этом завершается настройка программного обеспечения для Arduino IDE для программирования STM32 Blue Pill. Давайте приступим к написанию небольшой программы для мигания светодиода и загрузки ее в нашу плату STM32 Blue Pill.

Программа Blink для платы Blue Pill STM32F103C8T6

Убедитесь, что вы внесли необходимые изменения в IDE Arduino, как указано в предыдущем разделе (выбор правильной платы и т. д.). Как только это будет сделано, установите соединение между программатором FTDI (т. е. с USB Serial Converter) и платой STM32, как указано выше.

Напишите программу Blink следующим образом. Это похоже на скетч Arduino Blink, но вместо этого LED_BUILTIN я использовал PC13, так как светодиод подключен к этому выводу микроконтроллера.



Как только компиляция будет завершена, она автоматически вызовет инструмент STM32CubeProgrammer. Если все пойдет хорошо, IDE успешно запрограммирует плату STM32.


Он автоматически сбросит настройки микроконтроллера, и вы увидите, что светодиод мигает. Не забудьте переставить контакты BOOT0 обратно в положение LOW, чтобы при следующем включении питания на платформе запускалась ранее загруженная программа.

Вывод

Это было длинное руководство по началу работы с STM32 Blue Pill Board, т.е. STM32F103C8T6. Я обсудил некоторые важные функции платы, основные сведения о микроконтроллере, известные проблемы платы и способы их устранения, настройки Arduino IDE, загрузки необходимых инструментов, написания нашей первой программы для STM32 для Arduino Ide и, наконец, загрузки программы.


В чём проблема-то?

Начну с низкоуровневой части. Сколько я ни видел статей на эту тему, ни в одной так нормально и не разобраны были следующие моменты:

Вот по этим пунктам я постараюсь вкратце пробежаться, объяснить, что и как необходимо сделать, чтобы устройство работало корректно, и показать это на практике. Базовые понятия работы USB HID устройств я не буду объяснять, про это уже много и доступно писали до меня.

Теперь про саму библиотеку. В оригинальной и потом чуть допиленной мною было ещё очень немало багов и недочётов, которые мне довольно сильно мешали в моём неспешном проекте CV Meter (да-да, он НЕ заброшен, и уже много чего поменялось со времён той статьи, постараюсь опубликовать наработки в виде статьи + новой версии в ближайшие месяцы), что только добавляло непонимания или горения пятой точки от того, что работало оно совсем не так, как задумывалось. И в какой то момент меня это всё достало, что и вылилось в полном пересмотре библиотеки, написании своего тестового ПО (UsbHidDemonstrator от ST меня также не устраивал своими ограничениями по VID\PID и логикой работы).

Firmware — STM32


Открываем STM32CubeMX и включаем тактирование, SPI, USB и несколько GPIO на выход и один на вход для кнопки:


Тактирование у меня от кварцевого резонатора 16 МГц, да, он перепаян (для своего удобства, т. к. в проектах часто ставится именно такой номинал), на плате же изначально идёт 25 МГц, учитывайте это (просто поменяйте настройки тактирования):


SPI никаких особенностей не имеет, просто Master Transmit.

USB — включаем Device без дополнительных фич:


Настройки интерфейса можно не трогать, т. к. ничего дополнительного не потребуется:


Не забываем включить реализацию различных классов USB устройств (библиотека от ST):


И выбираем именно USB Custom HID (а не просто USB HID):


В настройках нас интересуют три параметра:


  • CUSTOM_HID_FS_BINTERVAL — 1 мс, это интервал желаемого опроса устройства со стороны ПК;
  • USBD_CUSTOM_HID_REPORT_DESC_SIZE — это размер дескриптора, который будет описывать возможности устройства (скорее всего, вы будете редактировать его размер уже позже генерации проекта, не столь важно, какое значение поставить сейчас);
  • USBD_CUSTOMHID_OUTREPORT_BUF_SIZE — это максимальный размер буфера для принимаемых из ПК репортов (т. е. необходимо выставить максимальный размер Output или Feature репорта + 1 байт на Report ID, иначе устройство не сможет принять репорт).

Далее заходим в настройки дескриптора описания устройства:


В целом и всё, можно сгенерировать проект:


Главное, структура проекта — Basic, стек и кучу я не менял, стандартных размеров хватит более чем, а также — опционально уже — тип проекта Makefile, т. к. я буду работать с прошивкой в Visual Studio Code.

Теперь об небольших изменениях в сгенерированном проекте. Открываем файл Src\usbd_custom_hid_if.c и добавляем объявление на обработчик входящих репортов:

Далее редактируем (точнее, добавляем, изначально дескриптор пуст) дескриптор возможностей устройства:

Примечание: для удобства я пишу рядом с каждым объявлением типа репорта количество байт, которое содержит это описание, чтобы потом можно было быстро посчитать и отредактировать объявление USBD_CUSTOM_HID_REPORT_DESC_SIZE .

Важное замечание: в описании Input Report я написал размер (33-1), как напоминалку, т. е. 33 байта — это полный размер репорта, но -1 байт (Report ID) = 32 байта полезная нагрузка. Аналогично всё работает и для остальных типов. Ниже будет объяснено, почему так, и в тестовом приложении мы увидим настоящий размер репортов.

И ближе к концу этого файла вставляем вызов обработчика репортов:

Примечение: в обработчике CUSTOM_HID_OutEvent_FS параметр event_idx является Report ID полученного репорта, который содержится в hhid->Report_buf[0].

В файле Src\usbd_desc.c можно отредактировать VID, PID, описания устройства.

В файле Inc\usbd_conf.h содержится, собственно, USBD_CUSTOM_HID_REPORT_DESC_SIZE, задающее размер дескриптора возможностей, а также можно проверить значения USBD_CUSTOMHID_OUTREPORT_BUF_SIZE и CUSTOM_HID_FS_BINTERVAL.

И последнее, в файле Middlewares\ST\STM32_USB_Device_Library\Class\CustomHID\Inc\usbd_customhid.h содержатся объявления хардварных endpoint’ов на приём и отправку, меняем их на максимально возможные (для Full Speed USB):

Репорты, размером > 64 байта будут автоматически нарезаны и склеены, от вас не требуется ничего делать.

Также стоит отметить два важных замечания по поводу Report ID, которые часто упускают в других туториалах:

  • Если в дескрипторе НЕ указано значение Report ID для какого-либо типа репорта, то будут пропускаться все, а если указано, то репорты, не соответствующие этому значению, для конкретного типа будут игнорироваться автоматически, как на стороне устройства, так и на стороне ПК.
  • Исходя из первого замечания, выходит, что часто, не указывая значение Report ID для любого типа репорта, можно подумать, что выделяемый буфер (к примеру, 32 байта) полностью и есть данные, которые отправляются\принимаются, но на самом деле первый байт в репорте всегда = Report ID (т. е. фактически полезной нагрузки в репорте 31 байт), и если он не используется по своему прямому назначению, то да, его как бы можно использовать в качестве байта данных.

Ну и файл Src\main.c, добавляем обработчик репортов с дополнительными переменными:

И в главном цикле добавляем отображение данных на экране (счетчики отправленных и принятых репортов, а также применение цветов на тестовую строку) и обработку нажатия на кнопку (отправка Input Report):

Минимально-простой функционал для тестирования реализован.

Software — UsbHid

Итак, теперь библиотеку можно подключать фактически из любого места (обычно я во ViewModel это делаю), раньше же только из класса окна можно было:

Сам обработчик MainWindow_Loaded назначается так:

Появился статичный метод GetDevicesList(), который возвращает список доступных устройств в виде List :

И теперь можно подключаться к устройству различными способами: VID/PID, Device Path или экземпляр HIDDeviceAvalible.

Из ключевых особенностей это, вроде, всё.

Software — Custom HID App (WPF)

И время проверить это дело на практике с примером приложения, которое отображает список доступных устройств, краткие возможности выбранного устройства и позволяет отправлять\принимать репорты.

Про реализацию приложения особо нечего сказать, почти всё стандартно, могу отметить только то, что при приёме Input Report намеренно сделано окно в 100 мс (по коду смотрите DispatcherTimer refreshtimer), которое отбрасывает все Input Report, которые пришли на время действия этого окна, сделано это для того, чтобы интерфейс не залипал, если устройство шлёт репорты каждые 10 мс или даже чаще.

Выглядит приложение вот так:


Выбираю из списка доступных устройств созданный только что пример:


После подключения к нему отображаются размеры репортов (если какой-то тип репорта не поддерживается, его размер = 0):


И тут мы видим размеры репортов, которые больше на +1, чем объявлено в CUSTOM_HID_ReportDesc_FS, всё сходится!

Переключаемся на вкладку с RAW данными:


Здесь в целом ничего замудрёного, сверху Input Report, который обновляется при поступлении нового репорта от устройства, и если значение байта в одной конкретной позиции отличается от значения байта в той же позиции, то он подсвечивается красным.

Примечание: да, тут видно, что Input Report содержит далеко не только счетчик в первых байтах, который мы пишем туда в прошивке, а ещё какие-то статичные значения в последующих байтах. Догадались, почему так? ;)

В динамике это выглядит так:

И отправка репорта в устройство, для наглядного примера прошивка разбирает пришедший Output\Feature Report следующим образом:


Примечание: реализация Feature Report не совсем полноценная в прошивке, не приходит ответ от устройства, но это уже оставлю для тех, кому это действительно нужно, сделать это несложно, но решение пока не буду выкладывать.

На этом всё. Мог что-то забыть или ошибиться, буду рад, если напишете об этом. Спасибо, что прочитали! ;)

Читайте также: