Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F4 USB CDC
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
hd44780
Понимаю, что может быть избитая и изъезженная тема тема, но всё же.

Короче, взял пример COM-порта отсюда - http://we.easyelectronics.ru/STM32/primery...4-discovey.html
Порт опознаётся, устанавливается, всё ок. Данные принимает, передаёт.

Но. Не могу передать на комп более 32 байт. Комп просто ничего не принимает. Когда 32 байта и меньше всё в порядке. Это ж отстой полный, хуже чем даже USB HID Generic - 64 байта туда-сюда-обратно. И тот кстати не получается. Примеры - сплошные мыши и джойстики sad.gif ...

Это что, норма? И как этого избежать? Размер буферов в прошивке вроде 2 кила - макрос APP_RX_DATA_SIZE = 2048.

И ещё.
Не хочется, чтобы железка торчала в списке COM-портов. Взял финский пример отсюда - http://forum.easyelectronics.ru/viewtopic....=35&t=10245
Он пошёл без проблем, комп его увидел. Но где взять драйвер? Нашёл libusb, драйвер им сгенерил, но как с ним дальше работать не понял...

Может ли кто-нибудь помочь?

Спасибо.


KnightIgor
Цитата(hd44780 @ Mar 7 2013, 09:53) *
И ещё.
Не хочется, чтобы железка торчала в списке COM-портов.

Очень странное требование. Суть USB CDC есть эмуляция COM-порта, поэтому он и виден как COM-порт, чтобы приложения, которые работают с COM-портами, могли без изменений работать с новым железом. Если нужна коммуникация между железом и компьютером без COM-порта, надо создать иной класс USB устройства (например, HID) и гонять свой собственный протокол.
hd44780
Ну пусть COM-порт уже, фиг с ним ...

А чего только 32 байта гоняет? Кривизна ST-шных библиотек? Или моих рук?
Juk1976
Цитата(hd44780 @ Mar 7 2013, 15:07) *
Ну пусть COM-порт уже, фиг с ним ...

А чего только 32 байта гоняет? Кривизна ST-шных библиотек? Или моих рук?


КакбЕ

#ifdef USB_OTG_FS_CORE
#define RX_FIFO_FS_SIZE 128
#define TX0_FIFO_FS_SIZE 32
#define TX1_FIFO_FS_SIZE 128
#define TX2_FIFO_FS_SIZE 32
#define TX3_FIFO_FS_SIZE 0

в файле usb_conf.h строка 144

Глубоко не копал - может отсюда ноги ростут???

У меня HID - проблем нет
hd44780
Нашёл в интернете вот такое:

Код
#define RX_FIFO_FS_SIZE                          128
#define TX0_FIFO_FS_SIZE                          64
#define TX1_FIFO_FS_SIZE                         128
#define TX2_FIFO_FS_SIZE                          0
#define TX3_FIFO_FS_SIZE                          0


Поставил себе - ничего не изменилось.
Кстати размер конечных точек - по 64 байта ...
Flexz
А пример из библиотеки ST вы брать не пробовали? у меня на его базе пара проектов построена, работает без нареканий.
hd44780
FlexZ, это из архива STM32_USB-Host-Device_Lib_V2.1.0?
Попробовал - то же самое sad.gif . А у Вас сколько байт за раз передаёт?
Можно конечно самому дробилку-сшивалку пакетов написать, но, может, готовое есть?

Может ещё какой-то пример есть? Или Вы поделитесь, если можете ....
Спасибо.
Flexz
Да, пример из этого архива.
Пачки уходят вплоть до 24кб за раз. Правда на каком-то этапе они разбиваются на блоки размером не более 4кб (видно в USBTrace). Подробно не вникал где именно, но это явно больше чем 32 байта.
Один из проектов есть в открытом доступе https://code.google.com/p/logicdiscovery/so...FLogicDiscovery
PS а вы случайно не в HS режиме его запускаете? У меня в HS режиме с внешней физикой этот код тоже тупил.
hd44780
Спасибо.
Цитата(Flexz @ Mar 8 2013, 21:39) *
Пачки уходят вплоть до 24кб за раз. Правда на каком-то этапе они разбиваются на блоки размером не более 4кб (видно в USBTrace). Подробно не вникал где именно, но это явно больше чем 32 байта.

Круто laughing.gif .

Цитата(Flexz @ Mar 8 2013, 21:39) *
Один из проектов есть в открытом доступе https://code.google.com/p/logicdiscovery/so...FLogicDiscovery

Да, натыкался на него, только с головы вылетел, посмотрю. Вот, кстати, статья от этого кода - http://habrahabr.ru/post/165853/

Цитата(Flexz @ Mar 8 2013, 21:39) *
PS а вы случайно не в HS режиме его запускаете? У меня в HS режиме с внешней физикой этот код тоже тупил.

Нет, FS. HS физика в виде маленькой платки с USB3300 ко мне пока едет ... С ней буду потом разбираться. Когда доедет.
hd44780
Короче, мудохался-мудохался, добился 1024 байт за раз. Сам не понял как laughing.gif
Прога на C# нормально принимает в потоке.

Flexz, если можете, поделитесь, как у Вас 24кил получилось?
Спасибо.
Flexz
Может у вас проблема в другом месте? Кабель плохой, например..
У меня с USB на STшных процессорах никогда проблем не было - просто брал пример, заменял верхнюю часть и оно просто работало. (если не учитывать некоторых косяков в HS режиме, с которыми я так и не взялся разобраться)
hd44780
Кабель длиной где-то 30 см от телефона Nokia X2-02. Точнее куплен был отдельно для этого телефона. Плюс USB удлинитель 1.8м, т.к. эти 30 см короткие...

Может я отсылку данных неправильно осуществляю.
В библиотеках драйвера есть метод uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len), который вроде и предназначен для отсылки данных в комп:

CODE
uint16_t VCP_DataTx (uint8_t* Buf, uint32_t Len)
{
uint32_t i;

// loop through buffer
for( i = 0; i < Len; i++ )
{
// буфер APP_Rx_Buffer используется драйвером USB
APP_Rx_Buffer[APP_Rx_ptr_in] = (uint8_t) Buf[i];

//increase pointer value
APP_Rx_ptr_in++;
// To avoid buffer overflow
if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
{
APP_Rx_ptr_in = 0;
}
} // for

return USBD_OK;
} // VCP_DataTx


Т.е. он просто копирует мои данные во внутренний буфер драйвера. Константа APP_RX_DATA_SIZE равна 2048, т.е. 2 кила он должен вроде отсылать.
Этот метод я и вызываю для отсылки своих данных в комп.
Единственное, что я изменил - убрал с него модификатор static, чтобы его можно было извне вызывать ... Может из-за этого косяки и его надо через какую-то функцию-обёртку вызывать (я такое где-то видел)?
Flexz
Вот в этом месте у меня во всех проектах немного по-другому - тело цикла вынесено в функцию, которая кладет в буфер один единственный байт (изначально делалось для putchar).
Код
uint16_t VCP_ByteTx (uint8_t dataByte)
{
  APP_Rx_Buffer[APP_Rx_ptr_in] = dataByte;
  APP_Rx_ptr_in++;

  /* To avoid buffer overflow */
  if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
  {
    APP_Rx_ptr_in = 0;
  }

  return USBD_OK;
}

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

У меня сейчас работа организована в формате "запрос-ответ", т.е. комп шлёт команду (символ 'S'), железяка в ответ должна выплюнуть некий объём информации. Сейчас для отладки выплёвывает синусоиду, которая рассчитывается в коде и ни от чего не зависит.

Так вот, когда я выплёвываю до 32 байт, все работает как и задумано, а если больше (например килобайт), то на первую команду ответа нет вообще (ждал до 10 сек), но как только я пуляю в него ещё один 'S', то я мгновенно получаю 2 кила синусоиды (причём там явно видно, что это именно 2 разных независимых ответа, т.к. синусоида на конце килобайта "оторванная", не дошедшя до конца периода).

Такое ощущение, что данные где-то "залипают". Буфер приёма на компе задан 10 кил, т.е. он с гарантией ничего не потеряет.

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

Если ставлю больше килобайта, то ответов нет вообще.


Может это вообще косяки ST-шного драйвера порта, а не прошивки?
Драйвер версии 1.3.1 от 23 июля 2010, найден где-то на форумных развалах. Понимаю, что старьё, но на ST- шном сайте сам чёрт ногу сломит, ещё и глючит, зараза sad.gif
винда - 2003 сервер. С COM-портами работать умею, т.к. по профессии программист. Недавно 3 кассоовых аппарата завёл через COM-порт. Работают нормально. Из 2-х из них данные вообще льются как из ведра непрерывным потоком, успевай ловить....
hd44780
Победил я кажись эту хреновину biggrin.gif .

Западло (по крайней мере в моём случае) заключалось в том, что объём передаваемых данных должен быть как минимум на килобайт меньше размера буфера APP_RX_DATA_SIZE.
Последнее, чего я достиг - APP_RX_DATA_SIZE = 11 кил, передаёт по 10 кил стабильно, без глюков и подвисаний.

Работает и с ST-шными дровами и общими, виндозными.
Golikov A.
какой странный подход. По мне последние сообщение не "победил" а "нашел" непонятную вещь. Вот когда вы скажете почему так должно быть, тогда можете считать что победили. Почему по 2 запроса надо? и кучу других почему. Пока что вы нашли куда забить костыль чтобы оно хоть как то зашевелилось...
hd44780
Согласен полностью.
Но ковыряться в потрохах этого CDC драйвера у меня нет никакого желания. У меня голова гудит от него ... Тем более, что в устройстве и без этого полно других проблем и нерешённых подзадач.
Если у Вас есть вариант получше, работающий без этого костыля, предложите пожалуйста.

Уважаемый Flexz тоже не писал, как именно оно у него работает .... Он писал только, что у него гоняет до 24кБ и про VCP_SendByte.
Golikov A.
увы...
rudy_b
И снова та же тема...
Поднял CDC (VirtualComPort) на STM32F207. Использовал либу STM32_USB-Host-Device_Lib_V2.1.0 (stm32_f105-07_f2_f4_usb-host-device_lib_v2.1.0).

И все вроде замечательно пашет с родным виндовым драйвером от ST (на usbser.sys). И контрольные пакеты ходят и скорость передачи данных порядка 700 кбит.

Но вот если размер пакета кратен 64 - то от компа в процессор пакеты ходят прекрасно, а вот обратно не ходит ничего. И вроде ошибка старая и давно известная - если размер пакета кратен 64, то винда посылает дополнительный запрос на пакет длиной 0 байт и на него нужно ответить. А контроллер считает, что все послал и молчит. Я думал ее давно исправили, но вот напоролся.

Пакеты с любыми другими размерами отлично передаются и туда и сюда. Никто не сталкивался с этим? Может кто знает что нужно поправить в либе?

Есть и еще редкие ошибки, примерно одна на 300 транзакций пакетов размером порядка 255 байт. Проявляются только если размер пакета более 64 байт. Но тут все как-то странно, пока не понял в чем дело. Ошибки вроде случайные, но ходят пачками и зависят от загрузки винды.
Golikov A.
последняя ошибка вроде ошибка драйвера винды если я правильно понял о чем идет речь. Там почему то не происходит запрос или происходит но с большим таймаутом, но может не о том...

насчет пакета нулевой длинны - это правила стандарта, если последний пакет имеет длину равную буферу, то он требует после себя посылки пакета 0 длинны, как подтверждение окончания пакета. Ответом на этот пакет 0 длинны - должен быть АКК, то есть так же пакет 0 длинны.
rudy_b
Вторая ошибка действительно похожа на придурь виндов. Несмотря на то что выставлены немалые таймауты и я пытаюсь докачать пакет 10 раз - этого не хватает, а в ответ на следующий запрос я получаю предыдущие данные. Но у 7-ки блокировка всех секунд на 10 - норма поведения.

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

Мне просто важно понять - это что-то не то у меня или это действительно ошибка либы. Никто не гонял пакеты с такой длиной?
Axel
Цитата(rudy_b @ Mar 2 2014, 14:46) *
Мне просто важно понять - это что-то не то у меня или это действительно ошибка либы. Никто не гонял пакеты с такой длиной?


Я слепил свой bulk-девайс на основе ST-шной либы. Обмен только пакетами, кратными 64 байтам. Никаких проблем не отмечал. В предыдущих проектах с LPC17 - та же ситуация (в смысле все нормально).
Golikov A.
балк обменивается не по контрольной конечной точке, и у него размер буфера больше 64 байт.
CDC работает через контрольную конечную точку, у которой буфер как раз 64 байта (про slow speed не говорим), потому при посылке пакета кратного 64 байтам, последняя передача идет с полным буфером, и требует по стандарту USB досылки еще одного пакета 0 длинны, как признак окончания.

думаю в этом подвох, странно что либа сама не добавляет 0 посылку, а исходники либы есть? может просто посмотреть глазьями есть там проверка на кратность длинны и досылка 0 пакета?
rudy_b
А какой именно либы? Я использовал stm32_f105-07_f2_f4_usb-host-device_lib_v2.1.0 (файлы V1.1.0 19-March-2012) и сравнивал с верией от 2011 (нет существенных различий).

Программа в контроллере (режим эхо) ничего не знает о размерах пакетов. К ней на вход валятся блоки по 64 байта или менее. Разбивку пакетов на блоки делает драйвер виндюков (пакеты заданного размера отправляются по WriteFile прогой в компе), а контроллер только перекладывает принятые блоки из буфера приемника в буфер передатчика. И я вижу, что все пакеты нормально приходят в контроллер (стоит счетчик принятых байт) и, скорее всего, нормально отправляются в комп. А вот прога в компе (ReadFile с заданным размером) не получает ничего, даже при нескольких перезапросах если длина отправленного пакета кратна 64.

Поскольку это VirtualCom, то драйвер в контроллере должен передавать любое количество байт. Но если в буфер передатчика положено сразу 64 байта, то, после их передачи, он, похоже, не отправляет пакета нулевой длины несмотря на то, что буфер пуст. И вот тут-то ReadFile (usdser.sys) похоже считает передачу незавершенной и сбрасывает весь пакет - не приходит ни одного байта при любом количестве перезапросов. Ну или что-то в этом роде, хотя и непонятно как такого можно добиться.




Цитата(Golikov A. @ Mar 2 2014, 17:11) *
балк обменивается не по контрольной конечной точке, и у него размер буфера больше 64 байт.
CDC работает через контрольную конечную точку, у которой буфер как раз 64 байта (про slow speed не говорим), потому при посылке пакета кратного 64 байтам, последняя передача идет с полным буфером, и требует по стандарту USB досылки еще одного пакета 0 длинны, как признак окончания.

думаю в этом подвох, странно что либа сама не добавляет 0 посылку, а исходники либы есть? может просто посмотреть глазьями есть там проверка на кратность длинны и досылка 0 пакета?

Балк в FS все равно работает пакетами с максимальным размером 64 байта. Я это смотрел. Происходит прмерно так, если правильно понял исходники.
По фрейму происходит проверка на наличие данных в пользовательском буфере. Если данные есть то из них выкусывается блок размером до 64 байт и устанавливается размер для передачи и указатель данных. После этого в более глубоких потрохах драйвера происходит его загрузка в фифо и передача в данном фрейме.

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

Но исходники есть, могу послать если нужно, размер-порядка 4 метров (с примерами).
Golikov A.
не надо мешать все в одну кашу.
балк, изохронный, прерывания, и контрольные обмены. Что какой то из них тоже использует буфер 64 байта это ничего не значит.

Правда заключается в том что контрольная точка может послать максимум 64 байта. Когда на компьютер приходит пакет длинной меньше 64 байт - это конец послания. И вам становится доступно сообщение по ReadFile в винде.
Если же приходит пакет длинной 64 байта, то не понятно это все сообщение, или нет, так как ограничение длинны может быть из-за максимального размера конечной точки. Поэтому драйвер винды кладет себе это сообщение и ждет следующего пакета, если придет пакет длинной меньше, он поймет что это конец и все вам отдаст, потому по стандарту пакеты длинной в макс буфер конечной точки обязательно должны быть дополнены пакетом 0 длины.

Если вы монитором USB порта после прихода пакета длинной 64 байта, не видите закрывающего пакета 0 длинны (его иногда могут как АКК воспринимать мониторы порта), то это явная ошибка процедуры посылки данных, и эти данные вы не получите, в винде. Проверяйте либу
rudy_b
Угу, еще раз посмотрел внимательно. При приеме из компа в контроллер все аккуратно. А вот при передаче из контроллера в комп - все криво. До конца еще не разобрался, но, похоже, понял в чем дело.

Эта зараза рассчитана на то, что приходящие снаружи (на СОМ) данные никогда не достигнут 64 за один фрейм, т.е. за 1 мсек. И, поэтому, она вообще не заботится о полном размере посылки, а тупо посылает все, рассчитывая, что число посланных байт всегда меньше 64 и проблем с завершением пакета не возникнет.

Это в чем-то обосновано, 64 байта за 1 мсек - это примерно 640кбит - намного выше стандартных скоростей СОМ порта.

Похоже, что для обмена пакетами нельзя использовать CDC, нужно брать что-то другое или не допускать размера пакетов кратного 64.

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

Да, это не контрольная точка - это реальный балк.
Golikov A.
очень странно что это балк, мне казалась что стандартный виндовый драйвер через контрольную работает, ну да ладно...

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

Собственно когда я сам писал USB у меня так и была организованна посылка, получала данные, и слала, проверяя длину последнего пакета, дополняя нулем если что.

И еще одна вещь которую вам надо знать про USB, это то что в винде реально боле менее поддержаны только CDC и HID, все остальное потребует от вас в реальности написания собственного драйвера.
rudy_b
Они, почему-то, используют EP1 для приема и передачи данных в режиме балк, а EP2 - для команд (BaudRate и т.п.) в режиме interrupt. А EP0 не используют совсем. Она используется только в режиме HS и странным образом.

#define CDC_IN_EP 0x81 /* EP1 for data IN */ //USB_OTG_EP_BULK
#define CDC_OUT_EP 0x01 /* EP1 for data OUT */ //USB_OTG_EP_BULK
#define CDC_CMD_EP 0x82 /* EP2 for CDC commands */ //USB_OTG_EP_INT

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

Тут, похоже, и это может не помочь. Возможно возникнут еще и проблемы с виндюковым usbser.sys - он ведь тоже VirtualComPort и не должен реагировать на отсутствие общего размера посылки, только на длину конкретного блока данных. И проблемы у него есть - редкие ошибки при трансляции пакетов с размером более 64 байт связаны именно с его глюками, я специально поигрался. А если пакет меньше 64 байт - ошибок нет вообще.

Цитата
И еще одна вещь которую вам надо знать про USB, это то что в винде реально боле менее поддержаны только CDC и HID, все остальное потребует от вас в реальности написания собственного драйвера.

Вот этого я и боюсь. HID тоже не рассчитан на передачу блоков данных и фиг знает, что нам накручено. А в аудио и вообще лезть не хочется. Ну а писать свой драйвер под виндюки жутко не хочется, мои мозги не в состоянии воспринять их идеологию, хотя под нормальную ОС раньше писал без проблем.

Похоже прийдется обойтись пакетами 63 байта. Правда скорость при этом получается порядка 200 кбит, но, надеюсь, мне этого хватит.
Golikov A.
Да нет никакой проблемы, все равно для уравнивания скоростей надо делать ФИФО, и никто не мешает выдавать данные из этого фифо не более чем по 63 байта, и скорость будет 63 КБайта. Неудобство в сборе пакета потом, сom port - это потоковый протокол, а не пакетный, пакеты все равно придется собирать.

А вот что касается HID, то там как раз прям пакетно ориентированная идея. Основная единица обмена информацией у HID - это отчет. Отчет это фиксированная структура данных, определяемой вами длинны. Причем отчетов может быть несколько типов, так что можно определить несколько видов структур.

Обмен отчетам происходит по 2 конечным точкам интерапт типа, входной и выходной, или через контрольную, в контрольной будут теже сложности с делением пакета на 8-64 байта, но по интерапт точкам данные ходят одним куском. И проблем с драйверами HID сильно меньше, судя по отзывам...
rudy_b
Так тогда мне проще сразу работать блоками по 63 байта. Сборщик/делитель более длинных пакетов на блоки по 63 - все одно писать, либо в проге либо в драйвере. Все одинаково получается.

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

Тут только один вопрос возникает, может ли одна ЕР передать или принять более 64 байт за один фрейм в случае если пакет занимает несколько блоков? При блоках по 256 байт скорость передачи была не менее 400кбит, а при передаче пакетов по 63 байта - порядка 200 кбит. Такое ощущение, что может. Вот тогда причесывание передающей части драйвера становится осмысленным.
Axel
Цитата(rudy_b @ Mar 2 2014, 22:46) *
Они, почему-то, используют EP1 для приема и передачи данных в режиме балк, а EP2 - для команд...


При балк обмене драйвер хоста должен знать размер принимаемого пакета, иначе он выйдет из приема по таймауту с потерей информации. Именно для передачи этого знания используется ЕР2, а через ЕР1 идут собственно данные. Если Вам просто нужно организовать обмен и не строго использовать Virtual Com или HID, то (ИМХО) самый простой путь - выдрать из либы минимум для балк обмена и определить фиксированную длину пакета. Со стороны хоста - libusb или winusb. Они достаточно хорошо описаны и несложны в использовании, правда (как и все остальные) не снимают геморроя при удаленной инсталляции, особенно под Windows8.
EmbedElektrik
Господа, а никто не поделится проектом под stm32f4 с чистым bulk USB? что-то вроде под libusb? Уже неделю воюю, не могу победить.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.