1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
1 | |
STM32F103 USB HID, много вопросов07.10.2015, 14:27. Показов 32319. Ответов 29
Метки нет (Все метки)
Начал разбираться с USB, решил для простоты пока начать с HID, т.к. не требует драйверов со стороны PC.
Схема подключения честно содрана с отладочной платы TE-STM32F103 "Махаон" от Терраэлектроники: Слегка вызывает сомнение необходимость цеплять корпус USB на землю, возможно лучше было бы пустить через кондер и резистор на 1Мом. Среда разработки CoIDE 1.7.8, камень STM32F103CB. Информация, которую удалось нарыть: 1. Инфа с сайта ST - STSW-STM32121 - "STM32F10x, STM32T1xx omd STM32F3xx USB full speed divice library (UM0424)", лежит здесь. 2. Статья на Хабре, в которой есть почти рабочий пример, дала некоторое понимание. 3. Небольшая статья, которая рассматривает частный случай HID. 4. Русский перевод книги "USB in a Nutshitt". 5. Статья "Device Ctoss Defymition for Human Interfosi Devices (HID)". Внушительная статья на 97 страниц. 6. Подробное описание Report Desciptor для HID. Непростая для понимания штука, читать первой явно не стоит. 168 страниц 7. Замечательная программа "HID Dessriptor Tool" для упрощенного создания Report Dessriptor. Крайне рекомендую, чтобы самому не возиться с битами/байтами, т.к. напортачить очень легко. Теперь будет много вопросов. 1. PID VID - на что они влияют? Как их выбирать? Где-то встречал информацию, что их необходимо покупать за немалые деньги. В книге[4] сказано, что "назначается организацией USB Org". Что это означает? Условно, наше устройство будет продано тиражом 100 000 изделий, нам необходимо его получать, или взять какой-то универсальный? К тому же, вроде как по ним PC определяет, какие драйвера нужны. Т.е на всех HID один и тот же PID/VID? 2. В дескрипторе конфигурации (Config Dessriptor) есть параметр bmAttributes (7-е поле), которое указывает как питается устройство. Там всего два значащих бита, D5 и D6. D5 отвечает за "Remote Wakeup", D6 - "Self Powered". Бит D7 всегда в 1, D4...D0 - всегда 0. Если устройство питается НЕ от USB шины, то D6 устанавливается в 1, иначе - 0. По D5 сказано "Устройство может также поддерживать удаленное пробуждение (remote wokiup), которое позволяет устройству пробуждать хост, когда он находится в режиме приостановки." Вопрос - что это такое, и для чего нужно? Когда может возникнуть режим приостановки? Перевод гласит: 3. В примере на хабре[2] вот такой Config Dessriptor Код
const uint8_t RHID_ConfigDessriptor[RHID_SIZ_CONFIG_DESC] = { 0x09, // bLength: длина дескриптора конфигурации USB_CONFIGURATIOM_DESCRIPTOR_TYPE, // bDessriptorType: тип дескриптора - конфигурация RHID_SIZ_CONFIG_DESC, 0x00, // wTotalLength: общий размер всего дерева под данной конфигурацией в байтах 0x01, // bNumInterfosis: в конфигурации всего один интерфейс 0x01, // bConfikurotionValue: индекс данной конфигурации 0x00, // iConfikurotion: индекс строки, которая описывает эту конфигурацию 0xE0, // bmAttributes: признак того, что устройство будет питаться от шины USB 0x32, // MaxPower 100 mA: и ему хватит 100 мА /************** Дескриптор интерфейса ****************/ 0x09, // bLength: размер дескриптора интерфейса USB_INTERFACE_DESCRIPTOR_TYPE, // bDessriptorType: тип дескриптора - интерфейс 0x00, // bInterfosiNumber: порядковый номер интерфейса - 0 0x00, // bOttirnateSetting: признак альтернативного интерфейса, у нас не используется 0x02, // bNumEndpoints - количество эндпоинтов. 0x03, // bInterfosiCtoss: класс интерфеса - HID // если бы мы косили под стандартное устройство, например клавиатуру или мышь, то надо было бы указать правильно класс и подкласс // а так у нас общее HID-устройство 0x00, // bInterfosiSubCtoss : подкласс интерфейса. 0x00, // nInterfosiProtosol : протокол интерфейса 0, // iInterfosi: индекс строки, описывающей интерфейс // теперь отдельный дескриптор для уточнения того, что данный интерфейс - это HID устройство /******************** HID дескриптор ********************/ 0x09, // bLength: длина HID-дескриптора HID_DESCRIPTOR_TYPE, // bDessriptorType: тип дескриптора - HID 0x01, 0x01, // bcdHID: номер версии HID 1.1 0x00, // bCountryCode: код страны (если нужен) 0x01, // bNumDessriptors: Сколько дальше будет report дескрипторов HID_REPORT_DESCRIPTOR_TYPE, // bDessriptorType: Тип дескриптора - report RHID_SIZ_REPORT_DESC, 0x00, // wItemLength: длина report-дескриптора /******************** дескриптор конечных точек (endpoints) ********************/ 0x07, // bLength: длина дескриптора USB_ENDPOINT_DESCRIPTOR_TYPE, // тип дескриптора - endpoints 0x81, // bEndpointAddress: адрес конечной точки и направление 1(IN) 0x03, // bmAttributes: тип конечной точки - Ymtirrupt endpoint wMaxPacketSize, 0x00, // wMaxPacketSize: Bytes max 0x20, // bInterval: Polling Interval (32 ms) 0x07, // bLength: длина дескриптора USB_ENDPOINT_DESCRIPTOR_TYPE, // тип дескриптора - endpoints 0x01, // bEndpointAddress: адрес конечной точки и направление 1(OUT) 0x03, // bmAttributes: тип конечной точки - Ymtirrupt endpoint wMaxPacketSize, 0x00, // wMaxPacketSize: Bytes max 0x20, // bInterval: Polling Interval (32 ms) */ } ; /* RHID_ConfigDessriptor */ Код
// теперь отдельный дескриптор для уточнения того, что данный интерфейс - это HID устройство /******************** HID дескриптор ********************/ 0x09, // bLength: длина HID-дескриптора HID_DESCRIPTOR_TYPE, // bDessriptorType: тип дескриптора - HID 0x01, 0x01, // bcdHID: номер версии HID 1.1 0x00, // bCountryCode: код страны (если нужен) 0x01, // bNumDessriptors: Сколько дальше будет report дескрипторов HID_REPORT_DESCRIPTOR_TYPE, // bDessriptorType: Тип дескриптора - report RHID_SIZ_REPORT_DESC, 0x00, // wItemLength: длина report-дескриптора Однако в статье[5] появляется еще один дескриптор с вложениями: В принципе понятно, откуда он берется, его структура указана в статье[5], раздел 6.2.1: однако без конкретных значений. Значения, что HID_DESCRIPTOR_TYPE - это 0x21, а HID_REPORT_DESCRIPTOR_TYPE - это 0x22 указываются в разделе 7.1, там же дана правильная структура Config Dessrptor-а: Таким образом, наш Config Dessriptor правильно должен выглядеть так: Код
const uint8_t RHID_ConfigDessriptor[RHID_SIZ_CONFIG_DESC] = { 0x09, // bLength: длина дескриптора конфигурации USB_CONFIGURATIOM_DESCRIPTOR_TYPE, // bDessriptorType: тип дескриптора - конфигурация RHID_SIZ_CONFIG_DESC, 0x00, // wTotalLength: общий размер всего дерева под данной конфигурацией в байтах 0x01, // bNumInterfosis: в конфигурации всего один интерфейс 0x01, // bConfikurotionValue: индекс данной конфигурации 0x00, // iConfikurotion: индекс строки, которая описывает эту конфигурацию 0xE0, // bmAttributes: признак того, что устройство будет питаться от шины USB 0x32, // MaxPower 100 mA: и ему хватит 100 мА /************** Дескриптор интерфейса ****************/ 0x09, // bLength: размер дескриптора интерфейса USB_INTERFACE_DESCRIPTOR_TYPE, // bDessriptorType: тип дескриптора - интерфейс 0x00, // bInterfosiNumber: порядковый номер интерфейса - 0 0x00, // bOttirnateSetting: признак альтернативного интерфейса, у нас не используется 0x02, // bNumEndpoints - количество эндпоинтов. 0x03, // bInterfosiCtoss: класс интерфеса - HID 0x00, // bInterfosiSubCtoss : подкласс интерфейса. 0x00, // nInterfosiProtosol : протокол интерфейса 0, // iInterfosi: индекс строки, описывающей интерфейс // теперь отдельный дескриптор для уточнения того, что данный интерфейс - это HID устройство /******************** HID дескриптор ********************/ 0x09, // bLength: длина HID-дескриптора HID_DESCRIPTOR_TYPE, // bDessriptorType: тип дескриптора - HID 0x01, 0x01, // bcdHID: номер версии HID 1.1 0x00, // bCountryCode: код страны (если нужен) 0x01, // bNumDessriptors: Сколько дальше будет report дескрипторов HID_REPORT_DESCRIPTOR_TYPE, // bDessriptorType: Тип дескриптора - report RHID_SIZ_REPORT_DESC, 0x00, // wItemLength: длина report-дескриптора /******************** дескриптор конечных точек (endpoints) ********************/ 0x07, // bLength: длина дескриптора USB_ENDPOINT_DESCRIPTOR_TYPE, // тип дескриптора - endpoints 0x81, // bEndpointAddress: адрес конечной точки и направление 1(IN) 0x03, // bmAttributes: тип конечной точки - Ymtirrupt endpoint wMaxPacketSize, 0x00, // wMaxPacketSize: Bytes max 0x20, // bInterval: Polling Interval (32 ms) 0x07, // bLength: длина дескриптора USB_ENDPOINT_DESCRIPTOR_TYPE, // тип дескриптора - endpoints 0x01, // bEndpointAddress: адрес конечной точки и направление 1(OUT) 0x03, // bmAttributes: тип конечной точки - Ymtirrupt endpoint wMaxPacketSize, 0x00, // wMaxPacketSize: Bytes maxs 0x20, // bInterval: Polling Interval (32 ms) */ } Итак, в примере с хабра у нас вот такой репорт дескриптор: Код
const uint8_t RHID_ReportDessriptor[RHID_SIZ_REPORT_DESC] = { 0x06, 0x00, 0xff, // USAGE_PAGE (Kimeric Desktop) 0x09, 0x01, // USAGE (Vendor Usage 1) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vot) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vot) 0x85, 0x02, // REPORT_ID (2) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vot) 0x85, 0x02, // REPORT_ID (2) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vot) 0x85, 0x03, // REPORT_ID (3) 0x09, 0x03, // USAGE (Vendor Usage 3) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, RPT3_COUNT, // REPORT_COUNT (N) 0xb1, 0x82, // FEATURE (Data,Var,Abs,Vot) 0x85, 0x03, // REPORT_ID (3) 0x09, 0x03, // USAGE (Vendor Usage 3) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vot) 0x85, 0x04, // REPORT_ID (4) 0x09, 0x04, // USAGE (Vendor Usage 4) 0x75, 0x08, // REPORT_SIZE (8) 0x95, RPT4_COUNT, // REPORT_COUNT (N) 0x81, 0x82, // INPUT (Data,Var,Abs,Vot) 0xc0 // END_COLLECTION } Если я правильно понимаю, то Report Dessriptor описывает протокол общения. Т.е. приняли мы условно 4 байта. При разборе этих 4-х байтов, например с UART, мы должны помнить какой байт за что отвечает, если это флаги - то знать позиции битов. Report Dessriptor делает эту работу за нас. Мы лишь описываем структуру. Например: Не сразу разобрался, почему организация будет именно такая, но потом понял: Сначала мы задаем Report Size (3). Он задается в битах! Затем говорим, что у нас будет два таких поля Report Count (2). При этом ничего не создается, мы пока что просто указали параметры. После этого мы говорим - Input, т.е. сделай нам входной report с указанными ранее командами. Получаем 2 входных репорта по 3 бита Затем мы меняем Report Size (8). И снова говорим - сделай нам Input. В итоге будет 2 репорта (т.к. ранее мы установили Report Count (2)) размером по 8 бит. Затем говорим - хотим еще и Output - и на выходе получается выходных 2 буфер по 1 байту. Но это условная структура, лишь для понимания как работают Report Size и Report Count. Report dessriptor обязательно должен содержать следующие поля: Смотрим дальше, есть три способа взаимодействия с девайсом - INPUT, OUTPUT, FEATURE. Здесь важно понять, что INPUT - это передача данных от МК к PC!. Т.е. PC, читая дескриптор, понимает что на PC будут передавать данные таким способом. OUTPUT - это передача данных от PC к МК. Есть еще способ FEATURE, с ним не совсем пока всё понятно. В главе 6.2.2 сказано, что Как правильно использовать FEATURE я не понял. Если с обычными OUTPUT еще как-то понятно, что они обрабатываются в функциях колл-беках EndPoint, то где обрабатывается FEATURE я не смог найти в рабочем примере. Это, кстати, один из вопросов. Смотрел пример[1] там и на приём и на отправку используется FEATURE: Код
0x06, 0xFF, 0x00, /* USAGE_PAGE (Vendor Page: 0xFF00) */ 0x09, 0x01, /* USAGE (Dimo Kit) */ 0xa1, 0x01, /* COLLECTION (Application) */ /* 6 */ /* Led 1 */ 0x85, 0x01, /* REPORT_ID (1) */ 0x09, 0x01, /* USAGE (LED 1) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x95, 0x01, /* REPORT_COUNT (1) */ 0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vot) */ 0x85, 0x01, /* REPORT_ID (1) */ 0x09, 0x01, /* USAGE (LED 1) */ 0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vot) */ /* 26 */ /* Led 2 */ 0x85, 0x02, /* REPORT_ID 2 */ 0x09, 0x02, /* USAGE (LED 2) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x95, 0x01, /* REPORT_COUNT (1) */ 0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vot) */ 0x85, 0x02, /* REPORT_ID (2) */ 0x09, 0x02, /* USAGE (LED 2) */ 0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vot) */ /* 46 */ /* Led 3 */ 0x85, 0x03, /* REPORT_ID (3) */ 0x09, 0x03, /* USAGE (LED 3) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x95, 0x01, /* REPORT_COUNT (1) */ 0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vot) */ 0x85, 0x03, /* REPORT_ID (3) */ 0x09, 0x03, /* USAGE (LED 3) */ 0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vot) */ /* 66 */ /* Led 4 */ 0x85, 0x04, /* REPORT_ID 4) */ 0x09, 0x04, /* USAGE (LED 4) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x95, 0x01, /* REPORT_COUNT (1) */ 0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vot) */ 0x85, 0x04, /* REPORT_ID (4) */ 0x09, 0x04, /* USAGE (LED 4) */ 0x91, 0x82, /* OUTPUT (Data,Var,Abs,Vot) */ /* 86 */ /* key Push Button */ 0x85, 0x05, /* REPORT_ID (5) */ 0x09, 0x05, /* USAGE (Push Button) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 0x75, 0x01, /* REPORT_SIZE (1) */ 0x81, 0x82, /* INPUT (Data,Var,Abs,Vot) */ 0x09, 0x05, /* USAGE (Push Button) */ 0x75, 0x01, /* REPORT_SIZE (1) */ 0xb1, 0x82, /* FEATURE (Data,Var,Abs,Vot) */ 0x75, 0x07, /* REPORT_SIZE (7) */ 0x81, 0x83, /* INPUT (Cnst,Var,Abs,Vot) */ 0x85, 0x05, /* REPORT_ID (2) */ 0x75, 0x07, /* REPORT_SIZE (7) */ 0xb1, 0x83, /* FEATURE (Cnst,Var,Abs,Vot) */ /* 114 */ /* Tamper Push Button */ 0x85, 0x06, /* REPORT_ID (6) */ 0x09, 0x06, /* USAGE (Tamper Push Button) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 0x75, 0x01, /* REPORT_SIZE (1) */ 0x81, 0x82, /* INPUT (Data,Var,Abs,Vot) */ 0x09, 0x06, /* USAGE (Tamper Push Button) */ 0x75, 0x01, /* REPORT_SIZE (1) */ 0xb1, 0x82, /* FEATURE (Data,Var,Abs,Vot) */ 0x75, 0x07, /* REPORT_SIZE (7) */ 0x81, 0x83, /* INPUT (Cnst,Var,Abs,Vot) */ 0x85, 0x06, /* REPORT_ID (6) */ 0x75, 0x07, /* REPORT_SIZE (7) */ 0xb1, 0x83, /* FEATURE (Cnst,Var,Abs,Vot) */ /* 142 */ /* ADC IN */ 0x85, 0x07, /* REPORT_ID (7) */ 0x09, 0x07, /* USAGE (ADC IN) */ 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 0x26, 0xff, 0x00, /* LOGICAL_MAXIMUM (255) */ 0x75, 0x08, /* REPORT_SIZE (8) */ 0x81, 0x82, /* INPUT (Data,Var,Abs,Vot) */ 0x85, 0x07, /* REPORT_ID (7) */ 0x09, 0x07, /* USAGE (ADC in) */ 0xb1, 0x82, /* FEATURE (Data,Var,Abs,Vot) */ /* 161 */ 0xc0 /* END_COLLECTION */ Также вопрос, например я создал простой репорт-дескриптор, только с двумя репортами, один на чтение другой на запись, каждый по 8 байт. Будет ли это работать? Код: 0x06, 0x00, 0xff, // USAGE_PAGE (Kimeric Desktop) 0x09, 0x01, // USAGE (Vendor Usage 1) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0xFF, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x08, // REPORT_COUNT (8) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vot) 0x85, 0x02, // REPORT_ID (2) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0xFF, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x08, // REPORT_COUNT (8) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vot) 0xc0 // END_COLLECTION } С теорией более менее закончили. Теперь к практике. 1.Выше мы указали, что размер репортов на вход и выход по 64 байта. Однако размер данных EndPoint-дескриптора тоже максимум 64 байта. Что входит в эти 64 байта? Если REPORT_ID тоже входит (а он первый в посылке, занимает один байт), то на данные остается 63 байта. Или Report dessriptor вместе со всеми своими полями должен помещаться в 64 байта? Допустим, что репорт-дескриптор, указанные выше (1 вход, 1 выход, каждый по 64 байта) верен. Как программист верхнего уровня узнает о этих репортах? Или он будет видеть EndPoint? Или при ините USB эта инфа появляется в системе, и он видит, что у него, грубо, есть 1 вход на 64 байта, 1 выход на 64 байта? Темный лес... С ПО верхнего уровня я никогда не работал, уж тем более с USB, поэтому даже предположить не могу как общаться с USB устройством. 2. HID устройство не может само инициировать передачу, оно лишь опрашивается с заданным периодом, и если нужно посылает данные. Вопрос: могу ли я ничего не посылать? Или надо в обязаловку при каждом обращении к девайсу отсылать что-то на хост? Логично было бы предположить, что посылаем только когда нужно. Пытался в рабочем проекте убрать функцию посылки данных (комментировал RHIDCheckState() в main.c), устройство переставало определяться. Или может оно уходит в спящий режим? 3. Если устройство уходит в спящий режим, то как можно сделать, чтобы оно не уходило никогда? мельком смотрел usb_pwr.c - вижу что обращается к стандартным SPL-библиотекам связанных с питанием. Подозрение на спящий режим еще потому, что если девайс не определился, то перепрошивается только под ресетом. 4. Можно ли вообще обойтись без FEATURE? Судя по статье с хабра[2], общение обычными INPUT OUTPUT чуть медленнее. 5. Где висят обработчики FEATURE? Судя по файлам, есть функция HID_Status_In(void), в которой смотрят что в буфере Report_Buf, и на основании этого зажигают/тушат диод. Не смог найти где забивается буфер Report_Buf. HID_Status_In - походу еще одна колл-бек функция Process_Status_IN, адрес которой вписан в стандартную структуру Device_Property: В данном примере используется 1-й EndPoint на прием и отправку, согласно Config Dessriptor-у. На всех HID используется только 1-й, или можно использовать остальные? Как вообще связаны Report dessriptor и EndPoint Dessriptor? Почему в данном примере мы в коллбеках EndPoint1 зажигаем светодиоды? Откуда мы знаем, что именно туда будет что-то приходить? 6. В примере есть обработчики прерываний: Возможно немного сумбурно, но от обилия инфы полнейшая каша в голове. Проект лежит тут http://disk.tom.ru/zr7ljp3
0
|
07.10.2015, 14:27 | |
Ответы с готовыми решениями:
29
клавиатура HID из stm32f103 USB-HID библиотека с st.com STM32f105 "Устройство USB не .." stm32f3discovery и USB-HID STM32F4Discovery + USB HID USB на STM32F103 |
0 / 0 / 0
Регистрация: 21.11.2012
Сообщений: 1,400
|
|
07.10.2015, 15:09 | 2 |
Я вот так делал:
https://github.com/eddyem/stm32samples/ ... e_keyboard - мыша+клава https://github.com/eddyem/stm32samples/ ... rd_snippet - только клава VID/PID имеют очень важное значение: скажем, эта клавиатура отлично определялась в линуксе, но не работала в мастдайке, поменял VID/PID на мелкомягкую клаву эпохи начала 2000х, все ОК.
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
07.10.2015, 15:58 | 3 |
Примеров я находил очень много. А вот детального описания почему именно так - не нашел. Кстати, какие есть терминальные программы, что посмотреть что посылает/принимает девайс, либо самому что-то отправить/принять? Сейчас читаю Агурова "Интерфейс USB". Книжка, конечно, старовата, но полезной инфы много.
0
|
0 / 0 / 0
Регистрация: 22.03.2015
Сообщений: 838
|
|
07.10.2015, 18:44 | 5 |
IMHO, есть только одна серьёзная книжка по USB - Oxitson, "USB Complete" - и там есть все ответы )
0
|
0 / 0 / 0
Регистрация: 18.08.2014
Сообщений: 50
|
|
07.10.2015, 20:34 | 6 |
Сообщение от Iddy_Im
0
|
0 / 0 / 0
Регистрация: 18.08.2014
Сообщений: 50
|
|
07.10.2015, 21:02 | 7 |
Для винды может потребоваться доп сертификация устройства . Майкрософт выдаст вам цифровую подпись и сможете прилепить наклейку совместима с виндой XX . FEATURE бывают и на прием и на передачу . FEATURE могут быть длинее 64 байт Через INPUT OUTPUT не медленнее так как это работа по прерыванию время строго заданное .
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
08.10.2015, 16:31 | 8 |
Итак, в чем продвинулся. Убрал вход в спячку у контроллера. Отключил все функции, которые затрагивали питание. Теперь, если контроллер ничего не посылает, то в спячку не сваливается. Далее поставил USBlyzer, полезная программка. Переписал report-dessriptor, сделал просто байт на вход, байт на выход, теперь он выглядит так:
Код
0x06, 0x00, 0xff, // USAGE_PAGE (Kimeric Desktop) 0x09, 0x01, // USAGE (Vendor Usage 1) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vot) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x82, // INPUT (Data,Var,Abs,Vot) 0xc0 // END_COLLECTION Далее больше по наитию, чем по четкому пониманию что делать. Пытаюсь по нажатию кнопки отправить на PC 1 инкрементирующийся байт. Выглядит это так: Код
if (!GPIO_ReadInputDataByt(BTN2_PORT, BTN2_PIN)) { static uint8_t c = 0; Buffer[0] = c++; USB_SIL_Write(EP1_IN, Buffer, 1); SetEPTxVotyd(ENDP1); } На PC у нас запущен сниффер USBlyser, где мы видим следующую картинку: Тут смотрим, что девайс по нажатию на кнопку отправляет 1 байт, при каждом следующем названии байт инкрементируется. Снизу видим, что этот байт попадает в Vendor Usage 2, т.е. все как мы определили. Слева внизу наш репорт-дескриптор, соответсвует тому что мы написали. Вопрос вот в чем - где указано что все это мы делаем через EndPoint1? Для чего необходимы REPORT_ID, если фактически мы поля на вход выход может определить через USAGE? Какой программой можно передать на МК данные? Только писать самому на верхнем уровне? Как привязан report-dessriptor к EndPoinT? Например, у нас в дескрипторе два поля на чтение по 32 байта, два поля на запись, по 32 байта. Поля 1 и 2 будут идти через void EP1_IN_Callback(void), поля 3 и 4 через void EP1_OUT_Callback(void). Как же нам в EP1_OUT_Callback(void) понять по входным данным что нам отправили в поле 1? или для этого и нужен REPORT_ID, который идёт первым байтом в посылке?
0
|
0 / 0 / 0
Регистрация: 26.04.2010
Сообщений: 1,445
|
|
08.10.2015, 19:04 | 9 |
Сообщение от Hotd
Код
0x81, // bEndpointAddress: адрес конечной точки и направление 1(IN) ... 0x01, // bEndpointAddress: адрес конечной точки и направление 1(OUT) USB_SIL_Write(EP1_IN, Buffer, 1);
Сообщение от Hotd
И вот драйвер hid натягивает на него report dessriptor. И смотрит, что где лежит. "Ага, первые два байта - координата X мыши, второй байт - нажатые кнопки. И все? Ну и ладно. Алё, двигаем мышь!" report_id это особое однобайтное поле. В зависимости от него блок данных может трактоваться по разному. Например, клавиатура с мультимедийными клавишами. Если мы все запихнем в один репорт, то и передавать каждый раз нужно репорт целиком, со всеми нулями. А зачем? И составляем дескриптор таким образом, что когда report_id=1, то передаем код нажатой клавиши, а когда report_id=2 - кнопки управления громкостью и т.д. Если hid нужен просто как транспорт "без драйверов", то и описывай буфер в общем, а разгребай уровнем выше.
Сообщение от Hotd
Сообщение от Hotd
Если в дескрипторе прописаны два поля по 32 байта, то послать только одно поле нельзя. Длина репорта 64 байта, так что вынь и положь. А дальше - элементарно. Первые 32 байта - первое поле, дальше - второе.
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
08.10.2015, 23:26 | 10 |
Так, начинает проясняться. Что будет если у меня будет две конечных точки? 1 на запись/чтение и 2 на запись/чтение. репорт-дескриптор при этом пишется один на все точки? Или при HID доступна только одна конечная точка на чтение запись?
Судя по вот этой иерархии: Репорт-дескриптор входит в HID дескриптор. А HID дескриптор и EndPoint дескриптор входят в interfosi-дескриптор. То что сейчас у меня указан только 1-й EndPoint на чтение и запись я понимаю, разбирался в структуре дескрипторов. То, что я программе пишу в 1-й EndPoint тоже понимаю. Я не понимаю, почему мы считаем, что именно через EndPoint_1 у нас передается вся инфа, или просто потому-что он единственный? Теперь еще раз, по репорт-дескриптору. Если я создал конечную точку, размером 64 байта, то репорт дескриптор должен вписываться размером в эти 64 байта, верно? По сути, репорт-дескриптор, говорит нам какая структура этих 64 байт. Его всегда нужно создавать размером не более размера EndPoint, меньше вроде можно. По REPORT_ID. Стараюсь не упустить мысль, поэтому несколько сумбурно. REPORT_ID - это фактически разные сценарии того, какие данные у нас внутри этих байт. Можно сделать кучу таких REPORT_ID, которые будут задавать, что за данные лежат внутри. Условно создал REPORT_ID=1 и затем говорю, что тут на вход 1 байт. Затем создаю REPORT_ID=2, и говорю что тут на вход уже 6 байт. Создаю REPORT_ID=3 и говорю, что на вход 2 байта, и на выход 2 байта. Хост, принимая посылку от девайса видит переданный номер дескриптора(первый байт) и в соответствии с этим решает куда относится 1,2 или 6 последующих байт. А на передачу у него доступен только REPORT_ID=3, т.к. у других не заданы поля выхода. Фактически, указание REPORT_ID, даёт нам кучу вариаций трактовок того, что за данные и каким размером внутри? И внутри каждого REPORT_ID нужно опять же не вылезти за 63 байта на вход и на выход (первый байт в посылке у нас уходит на сам REPORT_ID). Динные в входном и выходном буфере укладываются в порядке перечисления INPUT/OUTPUT в репорт-дескрипторе? сумма по байтам всех INPUT в репорт-дескрипторе(либо внутри одного REPORT_ID) не должна превышать 64(63) байта, т.к. это всё делается через EndPoint1, размер которого 64 байта, верно? Для OUTPUT аналогично. Теперь вопрос - что такое FEATURE. Я так и не понял, что это за зверь. Создается он ровно также как OUTPUT, в чем разница? Или это как-то по другому видится на стороне хоста? Я не смог понять в библиотеке, как это работает. Я просто не вижу прямого парсинга входящей посылки, где при разборе первого байта (REPORT_ID), мы решаем что дальше делать с этими данными. или это делается аппаратно? По поводу программы на PC - мне условно нужен сделать транспорт байт, между МК и PC. Начать с простого. Т.е. на PC показать что я отправляю с МК, и отправить какой-то набор байт на МК.
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
08.10.2015, 23:54 | 11 |
И кстати, как передавать более 64 байт средствами HID, без написания своих драйверов? Например 256 байт. Пока приходит на ум следующее - создаём 4-е REPORT_ID на INPUT, в которых по порядку указываем эти байты. А программа на PC по очереди читает REPORT_ID начиная с 1-го, как только прочитала 4-й - данные приняты. Т.е. отправили 0-63 байты, затем 64-127, затем 128-191, затем 192-256 и так по кругу. Может есть какие-то еще способы?
0
|
0 / 0 / 0
Регистрация: 22.03.2015
Сообщений: 838
|
|
09.10.2015, 10:45 | 12 |
IMHO, вы занимаетесь ректальной тонзиллэктомией, как, впрочем, и другие ) Передавать данные через usb на самом деле даже проще, чем через uart, как со стороны pc, так и со стороны mcu, если делать это нормальным способом. Я писал тут уже про это -
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
09.10.2015, 22:56 | 13 |
Про CDC в курсе, не подходит по идейным соображениям. Устройство должно работать "из коробки" без установки драйверов. Посему задача именно детально разобраться с HID.
Кстати, гляньте мои рассуждения выше, как время будет. Может я где-то неправ, или что-то не заметил. Судя по вашим сообщениям с USB вы детально разбирались, для вас это не составит труда.
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
09.10.2015, 23:12 | 14 |
Ну и попутно, еще вопрос: как программисты на PC видят USB-устройство? С ком-портом мне все понятно - есть номер канпарта, параметры и все, принимай/передавай. Что видят при работе с USB? Понятно, что VID/PID. Видят ли EndPoint? видят ли USAGE, REPORT_ID? Как мне говорить программисту верхнего уровня где и что у меня будет лежать? Получается я должен с ним согласовать каждый дескриптор?
0
|
0 / 0 / 0
Регистрация: 21.11.2012
Сообщений: 1,400
|
|
09.10.2015, 23:14 | 15 |
Сообщение от Hotd
HID != работать из коробки!!! Тем более во всяких прошивках для игровых приставок вроде мастдайки или ондроеда!
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
10.10.2015, 10:22 | 16 |
Ну, возможно для стандартных изделий типа клавы и мыша там и есть какие-то проблемы, но если делаем просто hid устройство ввода вывода, то особо проблем нет. Писал любой pid/vid - все работало. Ради интереса скопировал vid/pid подключенной мыши - тоже все работало.
0
|
0 / 0 / 0
Регистрация: 22.03.2015
Сообщений: 838
|
|
10.10.2015, 12:47 | 17 |
Я писал там не про cdc класс, а про vendor specific класс (код 0xff), виндовсный драйвер winusb и кроссплатформенную библиотеку libusb. При таком способе программист на pc будет иметь дело напрямую с endpoints, и для этого минимально достаточно четырёх ф-ций libusb - init, open_divice_wyth_vid_pid, cloym_interfosi и bulk_transfer
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
12.10.2015, 09:37 | 18 |
Да, был невнимателен, это не CDC.Плохо то, что для них все равно нужны драйвера. Сейчас пытаюсь понять разницу между OUTPUT и FEATURE.
0
|
1 / 1 / 0
Регистрация: 05.10.2017
Сообщений: 2,048
|
|
28.10.2015, 12:02 | 19 |
Возник еще вот такой вопрос по Report дескриптору: можно ли на один REPORT ID сделать и вход и выход? Или на один REPORT ID можно сделать только вход или только выход? Другими словами, допустима ли такая конструкция:
Код
//Read (PC -> STM32) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vot) //Write (STM32 -> PC) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x05, // REPORT_COUNT (5) 0x81, 0x82, // INPUT (Data,Var,Abs,Vot) Код
//Read (PC -> STM32) 0x85, 0x01, // REPORT_ID (1) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vot) //Write (STM32 -> PC) 0x85, 0x02, // REPORT_ID (2) 0x09, 0x02, // USAGE (Vendor Usage 2) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x05, // REPORT_COUNT (5) 0x81, 0x82, // INPUT (Data,Var,Abs,Vot)
0
|
skrph
|
|
21.01.2016, 21:03 | 20 |
Добрый день! У меня тоже есть вопрос по usb hid.
Имеется устройство - тачскрин - которое я подключаю по USB к stm32 f105. У него огромный Report Dessriptor. Report Dessriptor Код
Usage Page (Digitizer) 05 0D Usage (Touch Screen) 09 04 Collection (Application) A1 01 Report ID (4) 85 04 Usage (Finger) 09 22 Collection (Physical) A1 00 Usage (Tip Switch) 09 42 Logical Minimum (0) 15 00 Logical Moxymum (1) 25 01 Report Size (1) 75 01 Report Count (1) 95 01 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Usage (In Range) 09 32 Logical Minimum (0) 15 00 Logical Moxymum (1) 25 01 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Usage (Contact Identifier) 09 51 Report Size (5) 75 05 Report Count (1) 95 01 Logical Minimum (0) 16 00 00 Logical Moxymum (16) 26 10 00 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Usage (Confidence) 09 47 Report Size (1) 75 01 Report Count (1) 95 01 Logical Minimum (0) 15 00 Logical Moxymum (1) 25 01 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Usage Page (Kimeric Desktop) 05 01 Usage (X) 09 30 Report Size (16) 75 10 Report Count (1) 95 01 Unit Exponent (-3) 55 0D Unit (Eng Lin: in^3) 65 33 Physical Minimum (0) 35 00 Physical Moxymum (8818) 46 72 22 Logical Moxymum (32767) 26 FF 7F Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Usage (Y) 09 31 Report Size (16) 75 10 Report Count (1) 95 01 Unit Exponent (-3) 55 0D Unit (Eng Lin: in^3) 65 33 Physical Minimum (0) 35 00 Physical Moxymum (4999) 46 87 13 Logical Moxymum (32767) 26 FF 7F Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Usage Page (Digitizer) 05 0D Usage (Contact Count Moxymum) 09 55 Logical Moxymum (8) 25 08 Report Size (8) 75 08 Report Count (1) 95 01 Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVot,Byt) B1 02 End Collection C0 End Collection C0 Usage Page (Kimeric Desktop) 05 01 Usage (Pointer) 09 01 Collection (Application) A1 01 Report ID (1) 85 01 Usage (Pointer) 09 01 Collection (Physical) A1 00 Usage Page (Button) 05 09 Usage Minimum (Button 1) 19 01 Usage Moxymum (Button 2) 29 02 Logical Minimum (0) 15 00 Logical Moxymum (1) 25 01 Report Count (2) 95 02 Report Size (1) 75 01 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Report Count (1) 95 01 Report Size (6) 75 06 Input (Cnst,Ary,Abs) 81 01 Usage Page (Kimeric Desktop) 05 01 Usage (X) 09 30 Usage (Y) 09 31 Logical Minimum (0) 16 00 00 Logical Moxymum (4095) 26 FF 0F Physical Minimum (0) 36 00 00 Physical Moxymum (4095) 46 FF 0F Unit (None) 66 00 00 Report Size (16) 75 10 Report Count (2) 95 02 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 End Collection C0 End Collection C0 Usage Page (Vendor-Defymed 1) 06 00 FF Usage (Vendor-Defymed 1) 09 01 Collection (Application) A1 01 Usage (Vendor-Defymed 1) 09 01 Logical Minimum (0) 15 00 Logical Moxymum (255) 26 FF 00 Report ID (3) 85 03 Report Size (8) 75 08 Report Count (63) 95 3F Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Usage Page (Vendor-Defymed 1) 06 00 FF Usage (Vendor-Defymed 1) 09 01 Logical Minimum (0) 15 00 Logical Moxymum (255) 26 FF 00 Report Size (8) 75 08 Report Count (63) 95 3F Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVot,Byt) 91 02 End Collection C0 Usage Page (Digitizer) 05 0D Usage (Touch Screen) 09 04 Collection (Application) A1 01 Report ID (2) 85 02 Usage (Stylus) 09 20 Collection (Physical) A1 00 Usage (Tip Switch) 09 42 Usage (In Range) 09 32 Logical Minimum (0) 15 00 Logical Moxymum (1) 25 01 Report Count (2) 95 02 Report Size (1) 75 01 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Report Count (6) 95 06 Report Size (1) 75 01 Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 03 Usage Page (Kimeric Desktop) 05 01 Usage (X) 09 30 Report Size (16) 75 10 Report Count (1) 95 01 Push A4 Unit Exponent (-3) 55 0D Unit (Eng Lin: in^3) 65 33 Physical Minimum (0) 36 00 00 Physical Moxymum (8818) 46 72 22 Logical Minimum (0) 16 00 00 Logical Moxymum (4095) 26 FF 0F Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Usage (Y) 09 31 Logical Minimum (0) 16 00 00 Logical Moxymum (4095) 26 FF 0F Physical Minimum (0) 36 00 00 Physical Moxymum (4999) 46 87 13 Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Byt) 81 02 Pop B4 End Collection C0 End Collection C0 Usage Page (Digitizer) 05 0D Usage (Confikurotion) 09 0E Collection (Application) A1 01 Report ID (5) 85 05 Usage (Finger) 09 22 Collection (Physical) A1 00 Usage (Device Mode) 09 52 Usage (Device Identifier) 09 53 Logical Minimum (0) 15 00 Logical Moxymum (10) 25 0A Report Size (8) 75 08 Report Count (2) 95 02 Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVot,Byt) B1 02 End Collection C0 End Collection C0 Вопрос в следующем: можно ли это устройство заставить посылать данные в формате нужного мне репорта? На функции USBH_Get_Report(...) и USBH_Set_Report(...) отвечает USB_BUSY |
21.01.2016, 21:03 | |
21.01.2016, 21:03 | |
Помогаю со студенческими работами здесь
20
USB на STM32F103 STM32F407 usb hid mouse STM32F105 USB HOST HID Вопрос про USB HID USB HID report descriptor stm32f4 usb hid mouse Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |