Usb hid что это

Приобщение к миру USB-устройств на примере микроконтроллеров от Silicon Laboratories

Устройства от Silicon Laboratories не пользуются широкой популярностью в любительских кругах, им далеко до таких флагманов, как Atmel. Однако у них есть и вполне доступные простому смертному микроконтроллеры основных линеек в корпусе TQFP, и стартовые комплекты USB ToolStick (о чем совсем недавно упоминалось на хабре). Я сам начал свое знакомство с микропроцессорной техникой, работая с «силабсами», и вполне успешно.
В данной статье я расскажу, каким образом можно организовать связь компьютера с МК, используя USB-интерфейс, и как Silabs попытались сделать это простым для разработчика.
В качестве испытуемого будем использовать плату С8051F320DK, с микроконтроллером соответственно F32x серии, поддерживающей USB аппаратно, и Keil’овскую среду разработки uVision4.

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

Создание USB совместимого HID-устройства типа джойстик

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

Для упрощения задачи составления дескриптора можно воспользоваться программой, лежащей на www.usb.org (HID Descriptor Tool). В комплекте с программой предоставляются примеры конфигураций некоторых HID-устройств, которые можно корректировать под свою задачу или создавать собственное HID-устройство.
На этом описание джойстика заканчивается и нужно подготовить данные для передачи в PC.

Процедуры передачи данных

Находим в примере следующий код:
void IN_Report(void)<

IN_PACKET[0] = VECTOR;
IN_PACKET[1] = BUTTONS;

// point IN_BUFFER pointer to data packet and set
// IN_BUFFER length to transmit correct report size
IN_BUFFER.Ptr = IN_PACKET;
IN_BUFFER.Length = 2;
>

В этой процедуре идет составление отправляемого пакета, который после через хитрый указатель (на самом деле это просто структура из указателя и его длины) и передается нашим устройством. Главное аккуратно составить пакет, о чем нам и намекает комментарий, а дальше уже с ним сделают все без нашего участия.
Теперь расскажу о том, как и откуда мы берем переменные VECTOR и BUTTONS (обе, к слову, имеют тип unsigned char размером в байт).
Глобальной переменной VECTOR присваиваются значения с АЦП во время возникновения прерывания от него:
void ADC_Conver_ISR(void) interrupt 10
<
AD0INT = 0;

VECTOR = ADC0H;
>

Глобальная переменная BUTTONS аналогично изменяет значение в зависимости от нажатия кнопок. Кнопки опрашиваются по прерыванию от таймера. Таймер настраивайте в соответствии с личными предпочтениями.
void Timer2_ISR (void) interrupt 5
<
P2 &=

if ((P2 & Sw1)==0) // Проверка нажатия кнопки #1
<
// pressed
BUTTONS = BUTTONS | (1

Дескриптор имени HID-устройства

Напоследок можем скорректировать строковые данные, чтобы устройство имело то название, какое мы хотим (в моем примере «JOYSTICK-HABR»).
Ищем строковый дескриптор String2Desc, переписываем
#define STR2LEN sizeof («JOYSTICK-HABR») * 2

Идентификация HID-устройства

После компиляции проекта и программирования микроконтроллера можно подключить устройство к USB-порту. Хост определяет, что устройство принадлежит к HID классу и передает управление устройством соответствующему драйверу.
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это
Теперь в Windows идем в Панель управления->Игровые устройства и видим там нашего пассажира. Смотрим свойства и проверяем функциональность.
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это
Низкая скорость передачи является главным ограничением HID-варианта построения устройства. Максимально возможная скорость передачи данных при такой организации обмена составляет 64 Кбит/сек. Такой показатель в сравнении с 12 Мбит/сек полной скорости USB-шины выглядит минусом HID-технологии в вопросе выбора конкретной USB-реализации. Однако для многих задач коммуникации указанной скорости вполне хватает и HID-архитектура как специализированный инструмент занимает достойное место среди способов организации обмена данными.

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

Создание полноценного USB-устройства с использованием инструментария Silabs USBXpress

Но вот наступает момент, когда вам необходимо использовать свой протокол работы с устройством на МК. При этом хотелось бы передавать много данных на большой скорости, и делать все это с помощью своего ноутбука, в котором много USB и ни одного COM, да еще и ваше устройство должно быть не больше спичечного коробка, и лепить на плату USB-UART на микросхеме FT232RL нет никакой возможности.
Тут-то ребята из Silabs и решили облегчить всем жизнь и показать “дорогу в будущее”, без тяжелого ломанья зубов об написание собственных дров и прошивок.
USBXpress Development Kit – это законченное решение для МК и хоста (PC), обеспечивающее простую работу с протоколом USB с помощью высокоуровневого API для обоих сторон. Не требуется особых знаний ни самого протокола USB, ни написания драйверов. Так пишут силабовцы в своем гайде.
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это
Кстати о Programmer’s Guid: занимая всего 30 страниц, он крайне прост и доходчив. Примеры же лично мне не нравятся, часто встречаются очень кривые места, программы же под PC вообще лучше не смотреть, крайне нечитабельны.
USBXpress DK предоставляется к микроконтроллерам линеек C8051F32x, C8051F34x и для CP210x (USB-to-UART Bridge Controller). Библиотека USBXpress включает в свой состав библиотеку нижнего уровня, драйверы USB для ПК и DLL-библиотеку для разработки приложений на верхнем уровне. Ну и, конечно же, набор документации и примеров.
В библиотеке реализована передача данных только в режиме BULK. При использовании всех функций библиотеки, их реализация займет всего 3 Кбайта Flash-памяти микроконтроллера.

Firmware
Написание USB-дескриптора

В отличие от HID с его хитро формализованной структурой тут все просто
code const UINT USB_VID = 0x10C4;
code const UINT USB_PID = 0xEA61;
code const BYTE USB_MfrStr[] = <0x1A,0x03,'S',0,'i',0,'l',0,'a,0,'b,0,'s,0>;
code const BYTE USB_ProductStr[] = <0x10,0x03,'U',0,'S',0,'B',0,'X',0,'_',0,'A',0,'P',0>;
code const BYTE USB_SerialStr[] = <0x0A,0x03,'H',0,'A',0,'B',0,'R',0>;
code const BYTE USB_MaxPower = 15;
code const BYTE USB_PwAttributes = 0x80;
code const UINT USB_bcdDevice = 0x0100;

С VID, PID и именами думаю все понятно, плюс еще можно задавать максимальный ток параметром MaxPower (макс.ток = _MaxPower*2), PwAttributes — параметр отвечающий за удаленный wake-up хоста, и bcdDevice — номер релиза устройства.

Нюанс инициализации устройства и USB на борту

0x40; // Disable Watchdog timer
USB_Clock_Start(); // Init USB clock *before* calling USB_Init
USB_Init(USB_VID,USB_PID,USB_MfrStr,USB_ProductStr,USB_SerialStr,USB_MaxPower,USB_PwAttributes,USB_bcdDevice);

Initialize();
USB_Int_Enable();
.

Здесь, как требует комментарий, в первую очередь необходимо инициализировать тактовый генератор для USB перед самой его инициализацией, только потом провести остальные стартовые операции для МК — Initialize(); — который настраивает порты, таймер и АЦП; затем разрешаем прерывания от USB.

Обработка входящих данных и формирование исходящего пакета

Вот подобрались к самому главному
//. продолжение main
while (1)
<
if (Out_Packet[0] == 1) Led1 = 1;
else Led1 = 0;
if (Out_Packet[1] == 1) Led2 = 1;
else Led2 = 0;

In_Packet[0] = Switch1State;
In_Packet[1] = Switch2State;
In_Packet[2] = Potentiometer;
In_Packet[3] = Temperature;
>
// конец main
>

Out_Packet – пакет, принятый от хоста;
In_Packet — пакет, отправляемый хосту;
Суть ясна, МК постоянно обновляет отправляемый пакет и считывает статус полученного.

Обработка прерываний

Теперь в 2-х словах о том, откуда получаем значения в отправляемый пакет. Как и в примере с HID, состояния кнопок получаем по прерываниям от таймера, а значения АЦП и термометра — по прерываниям от АЦП.
Вот здесь один тонкий момент — при инициализации АЦП настраиваем его так, чтобы конвертирование значений происходило по переполнению таймера (того же, который мы используем для кнопок), а само же прерывание от АЦП возникает по завершению конвертирования. И тут кроме получения значений преобразователя в конце процедуры вызываем API функцию
Block_Write(In_Packet, 8)
которая и отправляет собранные данные на компьютер.
Получение команд от компьютера происходит в процедуре обработки прерываний от USB:
void USB_API_TEST_ISR(void) interrupt 16
<
BYTE INTVAL = Get_Interrupt_Source();

if (INTVAL & DEV_CONFIGURED)
<
Initialize();
>
>

Этот момент подробно расписан в Programmer’s Guid. Суть в том, что вызывается API-функция Get_Interrupt_Source(), возвращающая код причины возникновения API прерывания. Далее код анализируется и выполняется необходимое действие.

Программ на PC

Разбирать программу для компьютера я не буду. Силабовцы предоставили примеры на Visual Basic и на C, но, даже не заглядывая в исходники, подключить библиотеку в используемой вами среде разработки и прочитать пару страниц о функциях сложности вызвать не должно.
Поэтому я воспользуюсь уже скомпилированной программой из примера.

Итак, компилируем проект для МК, зашиваем, устанавливаем универсальные драйвера для USBXpress и подключаем отладочную плату. Система определит новое устройство и установит для него драйвера.
Посмотрим после установки, что творится в диспетчере устройств Винды:
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это
Теперь запускаем программу:
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это
Видим, что она правильно нашла устройство.
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это
Все, теперь можно тут потыкать кнопки, поморгать диодами, погреть МК руками, увидеть как растет температура.

Заключение

В целом создание USB устройства с помощью библиотек USBXpress оказалось более быстрым и прозрачным процессом, нежели используя HID-архитектуру. Да и скорость будет однозначно выше. Наиболее тонким местом является то, что библиотека закрыта, и узнать насколько надежным является это решение невозможно, к тому же доступен только BULK режим передачи данных.

Источник

STM32 и USB-HID — это просто

На дворе 2014 год, а для связи микроконтроллеров с ПК самым популярным средством является обычный последовательный порт. С ним легко начать работать, он до примитивности прост в понимании — просто поток байт.
Однако все современные стандарты исключили COM порт из состава ПК и приходится использовать USB-UART переходники, чтобы получить доступ к своему проекту на МК. Не всегда он есть под рукой. Не всегда такой переходник работает стабильно из-за проблем с драйверами. Есть и другие недостатки.
Но каждый раз, когда заходит разговор о том, применять USB или последовательный порт, находится множество поклонников логической простоты UART. И у них есть на то основания. Однако, хорошо ведь иметь альтернативу?
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это
Меня давно просили рассказать как организовать пакетный обмен данными между ПК и МК на примере STM32F103. Я дам готовый рабочий проект и расскажу как его адаптировать для своих нужд. А уж вы сами решите — нужно оно вам или нет.

Выбор профиля HID

USB-HID — довольно обширный класс устройств, поэтому прежде всего придется выбрать какое именно устройство мы будем создавать.
Мы можем создать эмуляцию клавиатуры, мыши, джойстика и других устройств ввода, а можем создать свое устройство, чтобы не зависеть от довольно жестких рамок стандарта и свободно обмениваться данными с ПК.
Я расскажу как cделать Custom HID device. Это дает максимальную свободу. Чтобы не затягивать статью, постараюсь рассказать максимально кратко — описаний стандарта в сети и без меня много, но лично мне они слабо помогли, когда понадобилось решить конкретную задачу.

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

Инициализация USB

В функции Set_System() производится настройка пина подтяжки линии D+ к питанию для программного подключения/отключения устройства от ПК (в нашей плате не используется), настраивается прерывание и инициализируются светодиоды и кнопки для демонстрационного проекта.
В USB_Interrupts_Config() настраиваются прерывания в зависимости от семейства МК (поддерживаются F10x, F37x, L1x).
Функция USB_Init() запускает работу USB модуля. Если временно нужно отключить для отладки работу с USB, просто закомментируйте эту строку.
Далее в бесконечном цикле проверяется, удалось ли сконфигурировать USB модуль при подключении к ПК. Если все сработало верно и устройство успешно подключилось, ПК включен и не находится в режиме энергосбережения, то состояние будет CONFIGURED.
Далее проверяется, была ли закончена предыдущая передача данных в ПК и если да, то готовится к отправке новый пакет в функции RHIDCheckState()

Размер пакета и частота передачи

В комментариях все довольно прозрачно. Обратите внимание на DEVICE_VER_L, DEVICE_VER_H — это константы из usb_desc.h, которые вы можете изменить для идентификации версии своего устройства.

Здесь стоит обратить внимание на константу wMaxPacketSize — она определяет максимальный размер пакета, которым мы будем обмениваться с ПК. Проект так настроен, чтобы при ее изменении менялись и размеры буферов. Но не забывайте, что больше 0x40 по стандарту указывать не стоит. С этой константой будьте осторожны — если передаваемый пакет будет отличаться по размеру — будут проблемы!
Следующая за ним константа с комментарием bInterval — это период опроса устройства в миллисекундах. Для нашего устройства задано 32мс.

Это самый важный дескриптор — он описывает протокол обмена и функционал устройства. Его формирование — не самая простая задача. Если допустить ошибку при формировании дескриптора — устройство перестанет работать. Формат дескриптора очень жесткий. Есть даже специальная утилита HID Descriptor tool. А в корне проекта лежит файл «RHID.hid» с описанным выше дескриптором для редактирования в этой утилите. Но если вы не понимаете, что делаете, лучше не лезть.
Для простоты я сделал две константы:
RPT3_COUNT — размер OUTPUT буфера в байтах для передачи пакета в МК (в примере — 1 байт)
RPT4_COUNT — размер INPUT буфера в байтах для передачи пакета в ПК (в примере — 4 байта)
Размер любого из этих буферов не должен превышать wMaxPacketSize. Меньше — можно.
Кстати, превратить Custom HID в другой HID девайс, например, клавиатуру или джойстик можно фактически только переписав ReportDescriptor и изменив класс и подкласс устройства в дескрипторе конфигурации.

Что такое Report

Цикл обмена

Массив uint8_t Buffer[RPT4_COUNT+1] определен как размер полезных данных входящего (рассматривается всегда с точки зрения хоста) пакета + байт ID. Это важно — если размер буфера будет отличаться — будут проблемы. Поэтому для изменения размеров буфера редактируйте значение константы в usb_desc.h.
В функции мы собираем данные в пакет, устанавливаем флаг PrevXferComplete = 0, говорящий о том, что данные отправляются и вызываем функциии библиотеки USB_SIL_Write и SetEPTxValid для отправки данных хосту.
Все, на этом передача данных хосту закончена.

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

Обработка SET_FEATURE

Данные, отправленные методом SET_FEAUTRE обрабатываются в usb_prop.c

Здесь мы проверяем первый байт в репорте и в соответствии с ним обрабатываем остаток пакета — управляем светодиодами или просто берем байт, отправленный нам хостом и кладем в пакет для последующей отправки обратно в функции RHIDCheckState.
Под Report_Buf зарезервировано wMaxPacketSize байт, чтобы влез любой пакет, который нам отправит хост.

Данные, отправленные методом SET_REPORT обрабатываются в usb_endp.c

Здесь почти то же самое, только нужно самостоятельно забрать данные вызовом USB_SIL_Read(EP1_OUT, Receive_Buffer) и в конце сообщить, что мы закончили вызовом SetEPRxStatus(ENDP1, EP_RX_VALID);

Настраивать устройство, передавать и принимать данные в пакетах нужного размера с нужной нам периодичностью мы научились.
Собираем проект и прошиваем в устройство.
Работать, это будет примерно так:

Проект поддерживает взаимодействие с утилитой USB HID Demonstrator от ST Microelectronics.
Страница Device capabilities отображает возможности, описанные в Report Descriptor.
Input/Output transfer позволяет вручную поотправлять данные девайсу и посмотреть пакет, который от него приходит.
Graphic view позволяет управлять светодиодами, чекбоксами Led 1, Led 2, настроив соответствующий им Report ID, а также передавать байт ползунком (ReportID=3)
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это

Также я написал маленькую демо-софтинку, которая автоматически определяет подключение к компу и отключение нашего девайса по его VID и PID, отображает статус — подключено/отключено индикатором рядом с чекбоксом Auto Connect
Usb hid что это. Смотреть фото Usb hid что это. Смотреть картинку Usb hid что это. Картинка про Usb hid что это. Фото Usb hid что это
Радиокнока Send using позволяет выбрать метод отправки данных девайсу.
Report: отображает полученный от девайса пакет побайтно, начиная с ReportID.
Щелкая по светодиодам ниже — управляем светодиодами девайса. Их состояние отображает текущее состояние девайса. Считывается из репорта от девайса.
Перемещая ползунок, мы отправляем Report с и значением, соответствующим позиции ползунка. Девайс вернет это значение в 4 байте репорта.
В выпадающем комбобоксе отображаются HID девайсы, найденные в системе и если найден наш девайс, то отображается его название.

Скачать все, что необходимо, можно на GitHub. В составе:
DT — HID Descriptor tool
tstHID-STM32F103 — проект для EmBlocks
USB HID Demonstrator — утилита от ST Microelectronics
HIDSTM32.exe — моя демо-софтинка на Delphi аналогичного фукнционала, но не требующая настройки

Если остались вопросы — пишите в комментариях. Постараюсь ответить. Я постарался не утопить суть в куче мелочей, чтобы сложилось общее понимание. Остальное уже можно понять, изучая проект. Но если вам нужно быстро сделать свое устройство, а лезть в дебри некогда — все, что вам нужно, я описал.

Источник

USB HID интерфейс для STM32 в STM32IDE

Ряд микроконтроллеров 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. Вполне вероятно, что могут быть проблемы с системными частотами, которые маркируются малиновым цветом.

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

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

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

Стандартные массивы данных для передачи информации хосту, с чем он будет иметь дело. Для интереса можно посмотреть дескрипторы устройства и конфигурации. Сейчас их можно оставить такими, как получились, но в дальнейшем они наверняка потребуют редактирования. Впрочем, не исключено, что они будут генериться по тем параметрам, что ставятся в кубике. Что не может не радовать. А вот Report Descriptor стоит изучить получше — это фактически основное, что придётся в дальнейшем править ручками. Не знаю, откуда RaJa взял его дескрипторы, в нашём случае они генерируются кубиком и располагаются в следующих файлах проекта:

Дескриптор от 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

Ну, а собственно «сбор данных» (нажатие кнопок джойстика) и реакция на полученные от хоста данные в этом прото проекте делаю внутри бесконечного цикла в main.c Всё просто 🙂 В этом прото проекте нет разделения реакции на SET_FEATURE и SET_REPORT, с этим надо будет разобраться далее, в реальном проекте. Компилируем, запускаем, подключаем к хосту и там должен появиться новый CustomHID от STMicroelectronics.

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

Моей задачей для этого проекта было управлять парой светодиодов на плате, что стало работать сразу, как эта программа обнаружила подключенную плату, и включать «лампочки» этой платы при нажатии различных кнопок джойстика на плате, а вот здесь сразу не получилось. При указанных настройках все пять лампочек одновременно зажигались при нажатии на центр джойстика. Остальные кнопки не отображались. При этом, если перейти на Input/Otput transfer, то данные были вполне ожидаемы. Т.е. сам интерфейс работает, но отображение в программе на хосте не отвечает моим запросам. Слава богу ST предоставляетс исходники, а в соседнем кубике сидит программист нашей группы, пишущий в том числе и софт для компьютеров. В общем, он подправил одну функцию и сгенерил исполняемую программу. Всё стало работать, как хотелось. Конечно, можно было бы на каждую кнопку создать свой report с уникальным номером, что исходно и предусмотрено. В этом случае было бы достаточно посылать по одному байту для каждой кнопки, но мой проект предусматривает многобайтный отчёт. Исходник подправленной функции и подправленный исполняемый файл можно скачать по ссылке ниже.

На этом, пожалуй, всё. Если у Вас есть такая же плата 32L476GDISCOVERY, то для начала можно просто скачать мой прото проект, адаптированный для него демонстратор и исходник изменённой функции по этой ссылке. Исходный USB HID Demonstrator скачивается с сайта STM, инсталлируется и его исполняемый файл заменяется моим. Импортируете в STM32IDE мой проект, компилируете и должны получить работающую базу для своих проектов. Если у Вас другая плата, то адаптируете «сбор информации» и включение светодиодов под свою плату.

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

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

Источник

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

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