реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> STM32F4Discovery USB_HID, посылка данных в PC, непонятки
ilkz
сообщение Aug 26 2015, 09:16
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084



Добрый день!

Понадобилось организовать обмен данными стмки с пк на основе USB_HID.
За основу взял темплейт от TM с его либами.

В целом, туда-сюда пакетики бегают, но есть несколько крайне непонятных для меня моментов:
1. Коллбек USBD_HID_DataOut. Насколько я понял, прием данных происходит именно в нем. Но откуда достать сами данные? Во всех примерах используют переменную USB_Rx_Buffer, которая объявляется в том же файле. Но она нигде не заполняется, а при попадании в коллбек данные в ней чудесным образом оказываются. Как так?

2. Непонятно поведение: если буфер объявить внутри коллбека, то вместо значений из буфера отсылается мусор. Если же объявление сделать глобальным, то отсылаются верные значения. Почему так?

3. В коллбек вписана отправка ответного пакета. Но иногда (в основном после включения) ответный пакет отсылается лишь с 3-го раза. Почему такое может возникать?

Спасибо.
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Aug 26 2015, 10:55
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



1. Очевидно её заполняет обработчик прерывний USB который не был найден.
2. Видимо функция сохраняет адрес буфера для последующего прерывания. В итоге если буфер лежит в стеке, то на момент реального использвоания там уже может быть мусор.
3. Могут быть разные причины.
Go to the top of the page
 
+Quote Post
ilkz
сообщение Aug 26 2015, 11:39
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084



Цитата(Kabdim @ Aug 26 2015, 13:55) *
1. Очевидно её заполняет обработчик прерывний USB который не был найден.
2. Видимо функция сохраняет адрес буфера для последующего прерывания. В итоге если буфер лежит в стеке, то на момент реального использвоания там уже может быть мусор.
3. Могут быть разные причины.


1. Так ведь обращение к ней нигде не производится. Я даже указателя нигде на нее не нашел. Может кто знает сей фокус?
2. Более-менее понятно.
3. Пока тоже неясно, разбираюсь.

Появился еще один вопрос:
Для отправки данных используется функция USBD_HID_SendReport(&USB_OTG_dev, buff, count).
И для того, чтобы послать буфер в 64 байта надо указывать count равным 65, а не 64 как казалось бы... Никто с таким не сталкивался?
Go to the top of the page
 
+Quote Post
Golikov A.
сообщение Aug 26 2015, 16:39
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454



64 байта - граница пакета, должна быть снабжена пустым пакетом с 0 данными, может дело в этом?

еще не забывайте что есть ДМА для заполнения массивов....
Go to the top of the page
 
+Quote Post
ilkz
сообщение Aug 27 2015, 04:50
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084



Цитата(Golikov A. @ Aug 26 2015, 19:39) *
64 байта - граница пакета, должна быть снабжена пустым пакетом с 0 данными, может дело в этом?


Не совсем понял: т.е., чтобы отослать 64 байта, надо отослать 65 с последним нулевым? Или в 64 байтах последний болжен быть нулевой?

Хорошо, давайте разбираться детально sm.gif

Вот есть такой код отправки ответа:
Код
#define buf_size  8
uint8_t buf[buf_size];

static uint8_t  USBD_HID_DataOut (void  *pdev, uint8_t epnum) {
  uint16_t USB_Rx_Cnt;
  uint8_t i = 0;
  
  /* Get the received data buffer and update the counter */
  USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count; // pointer to usb packet

  if(USB_Rx_Buffer[1] == 0x01) {
    TM_DISCO_LedOn(LED_GREEN);
  }
  else if(USB_Rx_Buffer[1] == 0x00) {
    TM_DISCO_LedOff(LED_GREEN);
  }
  
  for(i = 0; i<buf_size; i++) buf[i] = i;
  TM_USB_HIDDEVICE_SendCustom(buf, buf_size);
  
  /* Prepare Out endpoint to receive next packet */
  DCD_EP_PrepareRx(pdev, HID_OUT_EP, USB_Rx_Buffer, MAX_DATA_LENGTH);
  
  return USBD_OK;
}


Т.е., в ответ на прием пакета я отправляю 8 байт со счетчиком внутри.
TM_USB_HIDDEVICE_SendCustom() - это просто обертка над USBD_HID_SendReport(&USB_OTG_dev, buff, count).

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

Ответы приходят (правда почему-то только с 3-го раза после включения девайса), длина 8 байт, вроде все как заказывали.


Смотрим како-нить пакетик:
Прикрепленное изображение

Сниффер говорит что пакет принят успешно.

Однако, принимающая прога на компе в упор ничего не видит.
Вот репу уже сломал, прям руки опускаются. И что-то мне подсказывает что дело, скорее всего, в дескрипторах. Вроде я их пилил-пилил, но может чего не допилил. Посмотрите опытным взглядом:
Прикрепленное изображение

Там по идее заложено 64 байта туда, 64 байта обратно и все.

Сообщение отредактировал ilkz - Aug 27 2015, 04:53
Go to the top of the page
 
+Quote Post
ilkz
сообщение Aug 27 2015, 06:24
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084



Опа-ля, йа креведко розобралсо.

Дело было вот в чем:
1. Если мы хотим отправить N Байт, то реально надо отправить на 1 байт больше, т.е. N+1.
2. В дескрипторе репорта должно быть указано количество отправляемых элементов (REPORT_COUNT) равное N.
3. Первым байтом в отправляемых данных должен быть REPORT ID.
4. И усё.

Теперь понятны слова Golikov A. про 65 байт.

Осталось понять кто заполняет USB_Rx_Buffer.

Сообщение отредактировал ilkz - Aug 27 2015, 06:24
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 27 2015, 06:25
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(ilkz @ Aug 27 2015, 09:06) *
1. Если мы хотим отправить N Байт, то реально надо отправить на 1 байт больше, т.е. N+1.
....
Теперь понятны слова Golikov A. про 65 байт.
Вы поняли неправильно. Конечная точка имеет ограничение на длину пакета. В вашем случае оно равно 64 байта. Если вам нужно передать больше - вы передаете несколько пакетов. Но как вторая сторона определит, что вы уже закончили передачу? А очень просто: если пришел пакет с длиной, меньшей, чем максимальная длина для этой рабочей точки, то он последний. А что делать, если вам надо передать ровно столько данных, какова максимальная длина пакета? Получив такой пакет вторая сторона будет ждать продолжения. Поэтому передающая в этом и только в этом случае посылает следом пакет с нулевой длиной, т.е. без данных (zlp, zero-length payload). Но это все внутренние дела стека., вас они волновать не должны.

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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ilkz
сообщение Aug 27 2015, 06:39
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084



Цитата(Сергей Борщ @ Aug 27 2015, 09:25) *
Вы поняли неправильно. Конечная точка имеет...

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



С первым понятно, спасибо за внятное разъяснение.
Со вторым: если в репорте используется один IN и один OUT, то это считается за два вида сообщений или за один?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 27 2015, 08:13
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(ilkz @ Aug 27 2015, 09:39) *
Со вторым: если в репорте используется один IN и один OUT, то это считается за два вида сообщений или за один?
Рапорты считаются отдельно для каждой конечной точки. IN и OUT - разные конечные точки, между разными конечными точками рапорты идентифицирутся по номеру конечной точки.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ilkz
сообщение Aug 27 2015, 09:05
Сообщение #10


Частый гость
**

Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084



Сергей Борщ, ясно.

Последний пока что вопрос: кто же все-таки заполняет USB_Rx_Buffer?
Пока что единственное что я нашел связанное с буфером приема/передачи - это указатель xferr_buff в структуре USB_OTG_hc (файл usb_core.h). Но как-то оно не то...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 27 2015, 09:39
Сообщение #11


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(ilkz @ Aug 27 2015, 12:05) *
Последний пока что вопрос: кто же все-таки заполняет USB_Rx_Buffer?
Заполняется она в прерывании. Где-то в процессе инициализации конечной точки в стек передается адрес и размер этого буфера. Но это уже не ко мне. Я вместо этого ужаса написал свой стек на плюсах. Поищите по файлам все упоминания USB_Rx_Buffer, наверняка наткнетесь на функцию инициализации. А дальше уже копайте от нее.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ilkz
сообщение Aug 27 2015, 09:54
Сообщение #12


Частый гость
**

Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084



Искал - пусто.

Сергей Борщ, хотите прикол?
Было (это единственное объявление данной переменной на весь проект, сидит в том же файле что и код ниже):
Код
__ALIGN_BEGIN uint8_t USB_Rx_Buffer   [MAX_DATA_LENGTH] __ALIGN_END;


Меняю на:
Код
__ALIGN_BEGIN uint8_t SuperMegaBuffer   [MAX_DATA_LENGTH] __ALIGN_END;


, соответственно, в коллбеке приема:
Код
static uint8_t  USBD_HID_DataOut (void  *pdev, uint8_t epnum) {
  uint16_t USB_Rx_Cnt;
  uint8_t i = 0;
  
  USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count; // pointer to usb packet

  USB_Rx_Buffer[0] = 0x01;
  TM_USB_HIDDEVICE_SendCustom(USB_Rx_Buffer, 65);

  DCD_EP_PrepareRx(pdev, HID_OUT_EP, USB_Rx_Buffer, MAX_DATA_LENGTH);
  return USBD_OK;
}


меняю на:
Код
static uint8_t  USBD_HID_DataOut (void  *pdev, uint8_t epnum) {
  uint16_t USB_Rx_Cnt;
  uint8_t i = 0;
  
  USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count; // pointer to usb packet
  
  SuperMegaBuffer[0] = 0x01;
  TM_USB_HIDDEVICE_SendCustom(SuperMegaBuffer, 65);
  
  DCD_EP_PrepareRx(pdev, HID_OUT_EP, SuperMegaBuffer, MAX_DATA_LENGTH);
  return USBD_OK;
}


и все, больше ничего и нигде не трогаю. И что же я вижу? А то, что чудесным, мать его, образом - в SuperMegaBuffer оказываются принятые данные. КАААК?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 27 2015, 11:53
Сообщение #13


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(ilkz @ Aug 27 2015, 12:54) *
КАААК?

Видимо как-то отсюда:
Цитата(ilkz @ Aug 27 2015, 12:54) *
Код
  TM_USB_HIDDEVICE_SendCustom(USB_Rx_Buffer, 65);
Тут же вы передаете адрес этого буфера стеку. Копайте эту функцию.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ilkz
сообщение Aug 27 2015, 13:18
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 135
Регистрация: 9-09-11
Пользователь №: 67 084



Цитата(Сергей Борщ @ Aug 27 2015, 14:53) *
Видимо как-то отсюда:
Тут же вы передаете адрес этого буфера стеку. Копайте эту функцию.


Весь цимес в том, что если убрать строки
Код
  TM_USB_HIDDEVICE_SendCustom(USB_Rx_Buffer, 65);
  DCD_EP_PrepareRx(pdev, HID_OUT_EP, USB_Rx_Buffer, MAX_DATA_LENGTH);


,то волшебный буфер все равно оказывается заполнен принятыми данными )))
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 27 2015, 17:25
Сообщение #15


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(ilkz @ Aug 27 2015, 16:18) *
Весь цимес в том, что если убрать строки
Чудес не бывает sm.gif Не верю. Что-то вы не перекомпилировали или не то зашили


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 27th June 2025 - 11:43
Рейтинг@Mail.ru


Страница сгенерированна за 0.01487 секунд с 7
ELECTRONIX ©2004-2016