В примере от STM тоже встречал настройки UART. Он с USB как-нибудь взаимодействует в МК?4.5.4.2 Реализация
Поскольку запрос SET_CONTROL_LINE_STATE не имеет полезной нагрузки (data payload), устройство должно просто подтвердить этот запрос оправкой ZLP (zero-length packet, пакет нулевой длины), используя функцию USBD_Write с нулевой длиной данных.
Перед этим поле wValue должно быть проанализировано для получения нового состояния линии управления. Одиночная переменная типа boolean может использоваться для отслеживания состояния соединения. Если оба бита, и D0, и D1, установлены в 1, то конвертер должен работать нормально, т. е. должен пересылать данные между USART и хостом USB. Иначе конвертер должен перестать работать.
STM32 и USB (практика)
- Сообщения: 2316
- Зарегистрирован: Вс июн 26, 2011 20:03:21
Набрел на статью:
- Реклама
С одной стороны мне ком порт ЮСБ не нужен, но с другой стороны любопытно. Но все-таки HID проще.
Скачал я документы с официального сайта.
Давайте попробуем разобраться, немного времени выдалось.
bmrequesttype 0x21 - специфический запрос для класса от хоста к интерфейсу, это я уже писал
bRequestCode 0x22 - SET_CONTROL_LINE_STATE
wValue - имеют значения младшие два бита
wIndex - номер интерфейса (у Вас их вроде два)
WLength - Zero -
Как я понял это приходит команда активировать деактивировать линии DTR/RTS согласно wValue или что-то в этом роде. Ответ ZLP думаю тут верен.
Следующий запрос
bmrequesttype 0xA1 - специфический запрос для класса только обратное направление, т.е. просит данные
bRequestCode 0x21 - GET_LINE_CODING
wValue - zero
wIndex - номер интерфейса
WLength - количество запрашиваемых данных
Вы должны ответить
3:0 - скорость в секунду
4 - количество стоп битов (1, 1.5,2)
5 - контроль четности
6 - количество бит данных ( от 5 до 16)
--------------
Я наверное больше не буду углубляться в данный вопрос, мне вроде как оно не надо, по крайней мере пока, но за темой следить буду.
Скачал я документы с официального сайта.
Давайте попробуем разобраться, немного времени выдалось.
bmrequesttype 0x21 - специфический запрос для класса от хоста к интерфейсу, это я уже писал
bRequestCode 0x22 - SET_CONTROL_LINE_STATE
wValue - имеют значения младшие два бита
wIndex - номер интерфейса (у Вас их вроде два)
WLength - Zero -
Как я понял это приходит команда активировать деактивировать линии DTR/RTS согласно wValue или что-то в этом роде. Ответ ZLP думаю тут верен.
Следующий запрос
bmrequesttype 0xA1 - специфический запрос для класса только обратное направление, т.е. просит данные
bRequestCode 0x21 - GET_LINE_CODING
wValue - zero
wIndex - номер интерфейса
WLength - количество запрашиваемых данных
Вы должны ответить
3:0 - скорость в секунду
4 - количество стоп битов (1, 1.5,2)
5 - контроль четности
6 - количество бит данных ( от 5 до 16)
--------------
Я наверное больше не буду углубляться в данный вопрос, мне вроде как оно не надо, по крайней мере пока, но за темой следить буду.
- Сообщения: 2316
- Зарегистрирован: Вс июн 26, 2011 20:03:21
Спасибо за ответ, но я уже разобрался. Чуть позже опишу весь процесс. Пока времени к сожалению не хватает
.
Вот ведь незадача. Хост постоянно сбрасывает шину и просит дескриптор девайса. А он никак не отправляется.
Давно не занимался этим и теперь не пойму что творится. А ведь еще 4 страницы назад все было более-менее хорошо.
Следуя даташиту - если произойдет транзакция типа setup - контроллер установит биты STAT_TX в NAK. Остается только заполнить пакетную память по заранее определенному адресу (а она заполняется, если верить отладчику) и установить STAT_TX в Valid. По запросу IN данные должны сами улететь.
Обновляю регистр КТ вот так:
А тут непонятки творятся. То раз 10 перезапустишь контроллер - опа успешная транзакция и назначение адреса, то постоянные запросы дескриптора. У всех протокол так неадекватно ведет себя? Или у кого-нибудь прям стройными рядами корректные запросы идут?
UPD:
Кабель виноват был. Вот так вот.
Давно не занимался этим и теперь не пойму что творится. А ведь еще 4 страницы назад все было более-менее хорошо.
Следуя даташиту - если произойдет транзакция типа setup - контроллер установит биты STAT_TX в NAK. Остается только заполнить пакетную память по заранее определенному адресу (а она заполняется, если верить отладчику) и установить STAT_TX в Valid. По запросу IN данные должны сами улететь.
Обновляю регистр КТ вот так:
Код: Выделить всё
USB->EP0R = USB_EP0R_EP_TYPE_0|USB_EP0R_STAT_TX_0;UPD:
Кабель виноват был. Вот так вот.
Несколько человек уже просили выложить мой код. А я все обещал, что как-нибудь. Сегодня, в мое бездельное время, я понял что начал забывать что делал. Поэтому решил сегодня выдернуть его из проекта и выложить (пока совсем не забыл). Он во вложении.
Для начала некое предисловие к коду. Я не занимаюсь профессиональным, ну или хотя бы частым программированием. Потому перед каждым проектом я все изучаю с нуля (ну почти), а потом успешно забываю. Хотя я и старался программировать красиво, без быдлокодства не обошлось. Собственно на Си то я прогать начал только с осени 2015 года. С этого же времени начал изучать STM32 и сразу USB . Потому, например, у меня в коде есть определения регистров, хотя они уже определены в CMIS, аж до каждого бита. Я просто тупо не знал этого. Или например, если изменить размер передаваемых данных, то придется править многие места в коде, что не является хорошим стилем программирования и т.д. Тоже самое с дескрипторами, даже длину массивов придется тогда менять. Но есть и плюсы
, еще слепым котенком я понял что комменты обязательно нужны и нельзя экономить время на них, ибо потом потеряешь значительно больше. Так что комментов не меньше чем кода, правда некоторые могут быть не верны из-за копипасты с других участок кода, но такого немного.
Теперь как им пользоваться. Это по сути библиотека.
Инклудите вот это
#include "USB_INIT.H"
Сразу после старта МК вызываете функцию
USB_INIT();
И все. Комп определит МК как HID. (Единственное, нужно будет в файле дескрипторов установить пид/вид, я там киррилицу поставил, так что при компиляции выдаст ошибку).
У данного HID устройства всего одна конечная точка, нулевая. Весь обмен данных происходит через нее. А именно через репорты типа фьюча. Для обмена данными у меня есть две структуры, на самом деле наверное удобнее обычный массив, но структура у меня определена именно под мой проект, а данные все равно передаются побайтно линейно.
Например, в основном файле вы объявляете две внешние структуры (они уже есть в библиотеке)
extern Data_USB_t Data_USB_In;//для отправки на комп
extern Data_USB_t Data_USB_Out;//для приема с компа
Хост (компьютер) отправляет репорт девайсу. Как только он придет, он будет лежать в Data_USB_Out. Если хост запросит репорт от девайса, то девайс отправит хосту все то что лежит в Data_USB_In.
Важный момент, нужно соблюдать атомарность. Вы не должны изменять или пользоваться данными, пока USB модуль изменяет эти структуры. И еще один момент, когда обработчик прерывания USB работает с этими структурами, запрещаются обычные прерывания и прерывания SysTick, а затем включаются.
МК STM32F103, брал сразу на платке, там уже есть необходимая обвязка для USB.
-----------------
В винде есть встроенная библиотека HID.dll, название подсказывает, что она для HID. Какой-то товариЗЧ создал hidlibrary.h, там есть заголовки функций из HID.dll, не все, но как раз достаточно для энумерации и отправки или запроса репортов типа фьюч. И примеры в инете тоже есть. По этому поводу, я писать точно ничего не буду, я там совсем забыл что делал
.
Для начала некое предисловие к коду. Я не занимаюсь профессиональным, ну или хотя бы частым программированием. Потому перед каждым проектом я все изучаю с нуля (ну почти), а потом успешно забываю. Хотя я и старался программировать красиво, без быдлокодства не обошлось. Собственно на Си то я прогать начал только с осени 2015 года. С этого же времени начал изучать STM32 и сразу USB . Потому, например, у меня в коде есть определения регистров, хотя они уже определены в CMIS, аж до каждого бита. Я просто тупо не знал этого. Или например, если изменить размер передаваемых данных, то придется править многие места в коде, что не является хорошим стилем программирования и т.д. Тоже самое с дескрипторами, даже длину массивов придется тогда менять. Но есть и плюсы
Теперь как им пользоваться. Это по сути библиотека.
Инклудите вот это
#include "USB_INIT.H"
Сразу после старта МК вызываете функцию
USB_INIT();
И все. Комп определит МК как HID. (Единственное, нужно будет в файле дескрипторов установить пид/вид, я там киррилицу поставил, так что при компиляции выдаст ошибку).
У данного HID устройства всего одна конечная точка, нулевая. Весь обмен данных происходит через нее. А именно через репорты типа фьюча. Для обмена данными у меня есть две структуры, на самом деле наверное удобнее обычный массив, но структура у меня определена именно под мой проект, а данные все равно передаются побайтно линейно.
Например, в основном файле вы объявляете две внешние структуры (они уже есть в библиотеке)
extern Data_USB_t Data_USB_In;//для отправки на комп
extern Data_USB_t Data_USB_Out;//для приема с компа
Хост (компьютер) отправляет репорт девайсу. Как только он придет, он будет лежать в Data_USB_Out. Если хост запросит репорт от девайса, то девайс отправит хосту все то что лежит в Data_USB_In.
Важный момент, нужно соблюдать атомарность. Вы не должны изменять или пользоваться данными, пока USB модуль изменяет эти структуры. И еще один момент, когда обработчик прерывания USB работает с этими структурами, запрещаются обычные прерывания и прерывания SysTick, а затем включаются.
МК STM32F103, брал сразу на платке, там уже есть необходимая обвязка для USB.
-----------------
В винде есть встроенная библиотека HID.dll, название подсказывает, что она для HID. Какой-то товариЗЧ создал hidlibrary.h, там есть заголовки функций из HID.dll, не все, но как раз достаточно для энумерации и отправки или запроса репортов типа фьюч. И примеры в инете тоже есть. По этому поводу, я писать точно ничего не буду, я там совсем забыл что делал
- Вложения
-
- USB_HID.rar
- (9.42 КБ) 342 скачивания
- Реклама
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
Проект собирался в кокосе. Там все нормально, но много предупреждений.
Ваша среда не понимает кодировку кириллицы, а я же написал, что вместо кодов PID VID в дескрипторе устройства я прописал кириллицу. Кому надо, пускай их себе сам ставит правильно. Вы их как раз на первом скришоте привели.
По второму скрину. Видимо для Вашей среды программирования нужно указать явное преобразование типов.
Ваша среда не понимает кодировку кириллицы, а я же написал, что вместо кодов PID VID в дескрипторе устройства я прописал кириллицу. Кому надо, пускай их себе сам ставит правильно. Вы их как раз на первом скришоте привели.
По второму скрину. Видимо для Вашей среды программирования нужно указать явное преобразование типов.
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
Подскажите пожалуйста, что Вы здесь делаете, а то не получается исправить ошибку
Вы получаете значение лежащее по адресу 0x40006008 умножаете его на два и прибавляете 0x40006000.
Модет не надо получать значение по адресу 0x40006008 или такм тоже лежит адрес?
Ну если переменная pBufer типа uint8_t* то и адрес 0x40006008 надо к этому же типу приводить?
Может это должно выглядеть так
и тут то же
Для чего получать значение по адресу умножать его на 2 и прибавлять судя по всему адрес?
а туточки присваивается значение указателя числу типа uint32_t
а далее в этом адресе проверяется последний бит
Это мне вообще непонятно.
Код: Выделить всё
uint8_t *pBufer;
pBufer=(*((uint32_t*)0x40006008))*2 + 0x40006000;
Модет не надо получать значение по адресу 0x40006008 или такм тоже лежит адрес?
Ну если переменная pBufer типа uint8_t* то и адрес 0x40006008 надо к этому же типу приводить?
Может это должно выглядеть так
Код: Выделить всё
uint8_t *pBufer;
pBufer=(uint8_t*)((0x40006008)*2 + 0x40006000);
Код: Выделить всё
pTXBuf=*pTXBuf*2+0x40006000;а туточки присваивается значение указателя числу типа uint32_t
Код: Выделить всё
uint32_t contr=pRXBuf;Код: Выделить всё
contr&0x00000002"Надо, Федя, надо" ©.baghear писал(а):Модет не надо получать значение по адресу 0x40006008
Вы знаете, baghear, в этом топике все это неоднократно уже обсуждено. Вам всего-лишь надо его почитать. И комментариев в исходнике чуть не для каждой строки.
Забыл указать, что исходник компилировался с отключенной оптимизацией. С какой-либо включенной оптимизацией даже не пробовал и, соответственно, не тестировался.
С contr перемудрил, эта переменная избыточна. Можно сделать проверку условия без нее конечно.
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
Я не придираюсь, мне просто очень хочется запустить.
Так в чем смысл с pBufer?
Вы могли бы объяснить?
Мой компилятор запрещает присваивать указателю типа uint8_t число типа uint32 _t?
Так в чем смысл с pBufer?
Вы могли бы объяснить?
Мой компилятор запрещает присваивать указателю типа uint8_t число типа uint32 _t?
Для модуля USB есть область памяти начиная с адрес 0x40006000. В которой лежат данные для отправки и приема, в ней же лежит таблица-дескриптор, на эту таблицу указывает специальный регистр. Модуль USB видит ее (область памяти) своеобразно и с нулевого адреса, наверное своя шина.
Я функции старался писать боле-менее универсальными. Изначально у меня было несколько конечных точек. Для каждой конечно точки выделяется память, размеры и адреса которых лежат таблице-дескрипторе. Одна и та же функция должна была работать с любой конечной точкой. А вот значение регистра BTABLE,у меня считается что всегда равно нулю.
Я понимаю что Вы не придираетесь, но и в моем ответе нет сарказма, но повторять тоже самое, что уже в этом топике с коллегами 100 раз обсудили я не хочу. Увы, не берется USB с наскока, это не UART.
Я функции старался писать боле-менее универсальными. Изначально у меня было несколько конечных точек. Для каждой конечно точки выделяется память, размеры и адреса которых лежат таблице-дескрипторе. Одна и та же функция должна была работать с любой конечной точкой. А вот значение регистра BTABLE,у меня считается что всегда равно нулю.
Я понимаю что Вы не придираетесь, но и в моем ответе нет сарказма, но повторять тоже самое, что уже в этом топике с коллегами 100 раз обсудили я не хочу. Увы, не берется USB с наскока, это не UART.
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
Но так нельзя делать посмотрите, что говорит компилятор.
http://prntscr.com/cm7948
Нельзя указателю типа uint8_t * присвоить число.
http://prntscr.com/cm7948
Нельзя указателю типа uint8_t * присвоить число.
Наверное мы неправильно понимаем Си, я и мой компилятор. Потому что я присваиваю указателю число и компилятор с этим соглашается. Кроме того, у меня все работает.
Вы понимаете что такое указатель? Что ему еще можно присваивать, как не число?
Вы понимаете что такое указатель? Что ему еще можно присваивать, как не число?
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
указателю можно присвоить число, предварительно сказав ему, какого типа этот указатель.
ПРосто присвоить число указателю нельзя, можно сделать так
НА это компилятор не ругается.
Еще вопрос, вы снова числу присваиваете указатель
так делать нельзя!!!
У меня к Вам встречный вопрос про понимание указателей.
Так что там всё таки Вы хотели сделать.
ПРосто присвоить число указателю нельзя, можно сделать так
Код: Выделить всё
uint8_t *pBufer;
pBufer=(uint8_t *)((*((uint32_t*)0x40006008))*2 + 0x40006000);
Еще вопрос, вы снова числу присваиваете указатель
Код: Выделить всё
uint8_t *pRXBuf;
uint32_t contr=pRXBuf;У меня к Вам встречный вопрос про понимание указателей.
Так что там всё таки Вы хотели сделать.
Последний раз редактировалось baghear Вс сен 25, 2016 18:55:45, всего редактировалось 1 раз.
Указатель, это всего-лишь адрес памяти. У STM32 шина адреса 32битная, на какой бы тип данных он не ссылался, он все равно будет 32битным. По факту тип данных имеет значение только, когда вы получаете/записываете данные на которые указывает указатель.
Видимо для Вашей среды программирования нужно указать явное преобразование типов.
Нет, числу я ничего не присваиваю. Там есть комментарий, что я хотел и что сделал. Разберитесь в памятью USB и Вам станет понятно.baghear писал(а):Еще вопрос, вы снова числу присваиваете указатель
- Сообщения: 791
- Зарегистрирован: Вт июн 17, 2014 00:34:26
В коде выше с одной стороны от равно указатель с другой число..
Наверное по этому у Вас ворнинги, а у меня ошибки.
Наверное по этому у Вас ворнинги, а у меня ошибки.
Итак, удалось создать HID джойстик. Пока что передаю последовательностью байт, зашитую в прошивке. В панели управления все определяется, кнопки светятся попеременно и полоска меняет размер. Да, можно довести до конца, но это не моя цель.
Все это работает благодаря дескриптору репорта, который я подсмотрел на хабре. Он составлен не совсем понятно, но мой упрощенный Дескриптор система не приняла. Я то хочу просто слать пакеты байт некоторой длинны - 20-50 байт. Я так понимаю, надо просто переписать Дескриптор репорта. Кстати, серые мыши говорят, что если перепишешь Дескриптор, то девайс с заданным VID /PID перестанет работать. Не знаю, не проверял, а просто поменял пару раз PID.
Так вот, есть у кого опыт написания репорта кастомного девайса? Не создавать же клавиатуру...
UPD:
Нашел в одном месте дескриптор репорта кастомного hid. Завтра попробую, вот только не знаю как к этому отнесется система.
Все это работает благодаря дескриптору репорта, который я подсмотрел на хабре. Он составлен не совсем понятно, но мой упрощенный Дескриптор система не приняла. Я то хочу просто слать пакеты байт некоторой длинны - 20-50 байт. Я так понимаю, надо просто переписать Дескриптор репорта. Кстати, серые мыши говорят, что если перепишешь Дескриптор, то девайс с заданным VID /PID перестанет работать. Не знаю, не проверял, а просто поменял пару раз PID.
Так вот, есть у кого опыт написания репорта кастомного девайса? Не создавать же клавиатуру...
UPD:
Нашел в одном месте дескриптор репорта кастомного hid. Завтра попробую, вот только не знаю как к этому отнесется система.
Спойлер
Код: Выделить всё
const uint8_t HID_ReportDesc[] =
{
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x19, 0x01, //USAGE MINIMUM
0x29, 0x01, //USAGE Maximum
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 41,//sizeof(Data_USB_t)-1, // REPORT_COUNT
//0x85, 0x01, // REPORT_ID (1)
//0x81, 0x02, // INPUT (Data,Var,Abs)
0xb1, 0x02, // feature (Data,Var,Abs)
0xc0 // END_COLLECTION
};Во вложении прога для создания дескрипторов репорта.
- Вложения
-
- dt2_4.zip
- (99.24 КБ) 300 скачиваний
Да, спасибо, я уже проверил на совершенно ином репорте - тоже определилось. Вопрос теперь в проге для хоста. Нашел программу hclient - она отображает список подключенных HID девайсов. Поглядел - мой там есть. Причем прога говорит ,что длина репорта 13 байт, а Report count 12 байт. Ну да ладно может там приплюсовывается PID или ID пакета. Вроде как прога может выполнять запись/чтение устройства. Но пока безрезультатно. Виснет при попытке чтения. Если бы раздобыть HID клиент который точно 100% рабочий, вот это было бы замечательно. Сейчас я готов отправлять n-е количество байт.
UPD: Это я к тому, чтобы быть точно уверенным что косяков со стороны контроллера нет. Хотя на анализаторе видно, что хост зачем-то запрашивает 1 раз данные с устройства и отсылается ровно 12 байт, но все-таки надо быть уверенным, что передача происходит корректно.
UPD: Это я к тому, чтобы быть точно уверенным что косяков со стороны контроллера нет. Хотя на анализаторе видно, что хост зачем-то запрашивает 1 раз данные с устройства и отсылается ровно 12 байт, но все-таки надо быть уверенным, что передача происходит корректно.
- Вложения
-
- hclient.zip
- (285.58 КБ) 269 скачиваний
Последний раз редактировалось Radist_M Чт сен 29, 2016 16:21:25, всего редактировалось 1 раз.



