Jump to content

    
Sign in to follow this  
V_M_Luck

STM32 USB FS OTG

Recommended Posts

Всмысле? Функция hwtx() выше, вызываю её вручную, по команде в UART консоль.

 

    while(1){
        if((USART3->SR & USART_SR_RXNE)){ // data received
            char c=USART3->DR;
            //...
            if(c=='3'){hwtx();}
        }

Share this post


Link to post
Share on other sites

Кажется, чего-то я в этой жизни не понимаю :(

Из девайса в комп через второй эндпоинт отправляется только один пакет, после чего этот эндпоинт наглухо виснет. Пробовал:

1. Сбрасывать FIFO через регистр GRSTCTL. Как выборочно, так и все.

2. Отключать-включать эндпоинт, ставить CNAK

3. Сбрасывать весь регистр DIEPCTL2 в ноль, и заново конфигурировать

4. Плясать с бубном

 

Идеи закончились. После успешной отправки "Hello world" на комп, второй раз отправить не удаётся. Только перетыкание кабеля срабатывает.

Share this post


Link to post
Share on other sites

(Назначение hwtx - слать Hello World. Исключительно для дебага, поэтому упрощена до безобразия)

Скорее всего, я упустил что-то важное, но не могу понять что :(

Для общения через нулевой эндпоинт используется тот же алгоритм, и он работает. Разница только в типах эндпоинтов (control и bulk). И вот с bulk что-то не выходит.

 

void hwtx(){
    volatile uint32_t * fifo=(uint32_t *)OTG_FS_DFIFO2_BASE;
    int i;
    int len=12;
    char data[]={"Hello world\n"};
    pprintf("1. FIFO: %i words free", OTG_FS->DTXFSTS2&0xFFFF);
    OTG_FS->DIEPTSIZ2=(1<<19)|(len<<0); // PKTCNT; XFRSIZ
    OTG_FS->DIEPCTL2|=(1UL<<31)|(1<<26); // EPENA; CNAK
    for(i=0;i<len;i+=4){
        *fifo=((data[i+0]&0xFF)<<0)|((data[i+1]&0xFF)<<8)|((data[i+2]&0xFF)<<16)|((data[i+3]&0xFF)<<24);
    }
    pprintf("2. FIFO: %i words free", OTG_FS->DTXFSTS2&0xFFFF);
}

Edited by SviMik

Share this post


Link to post
Share on other sites

Собственно, я ошибок не вижу. Я делаю все примерно тоже самое, единственное, дополнительно устанавливаю NAK в конце отправки пакета. Но, по идее, он должен ставиться автоматом.

Share this post


Link to post
Share on other sites

Подниму тему.

Подскажите плз, все глаза стёр уже где узнать адрес Rx FIFO для STM32F4. Пишу собственный стек (на базе их либы правда), с Tx адресами мне всё понятно, а Rx у них один на всех насколько я понял, а вот как из него читать не доходит.

Share this post


Link to post
Share on other sites

Подниму древнюю тему.

 

STM32F107, родной стек из Cube напугал множеством лишних телодвижений. Почти 20 К кода за виртуальный COM мне кажется многовато. Пишу свой, запнулся на элементарном - не отсылаются данные (дескриптор). Получаю setup запрос на device descriptor размером 8 байт. Проверяю наличие места в FIFO (DTXFSTS0), там 0x40 слов. Прописываю в DIEPTSIZ0 количество пакетов (PKTCNT) = 1 и размер посылки (XFRSIZ) = 8. Прописываю в FIFO два слова. После записи каждого слова наблюдаю уменьшение на 1 содержимого DTXFSTS0. После записи обоих слов XFRSIZ становится равным нулю, а DTXFSTS0, соответственно, 0x3E. Запускаю обмен (одновременно выставляю CNAK и EPENA в DIEPCTL0). Попадаю в прерывание XFRC, то есть ядро думает, что пакет отправило. При этом PKTCNT становится равен нулю. Но комп посланного дескриптора не видит, а свободное место в FIFO увеличивается всего на одно слово (DTXFSTS0 становится равным 0x3F). Как будто ядро вместо восьми байтов отсылает не более четырех. Родной пример из Cube работает, и если никто не подскажет - буду вставлять отладочный вывод в пример Cube. Но, мало ли, кто-то знает что ему не нравится?

Такое ощущение, что ядро при передаче неправильно воспринимает записанный в XFRSIZ размер, но он уменьшается до нуля именно в момент записи в FIFO последнего слова, четко в соотвествии с руководством пользователя. В общем уже третий вечер перечитываю руководство, хожу по шагам по своей программе и по примеру из Cube, вроде все делаю так же, а каменный цветок не выходит хоть тресни. Отсылка пакета нулевого размера (ZLP) после установки адреса проходит нормально.

Share this post


Link to post
Share on other sites
Но комп посланного дескриптора не видит, а свободное место в FIFO увеличивается всего на одно слово (DTXFSTS0 становится равным 0x3F). Как будто ядро вместо восьми байтов отсылает не более четырех.
Разобрался. Нужно сначала запускать передачу установкой CNAK и EPENA, а уже потом запихивать данные в FIFO. Надо внимательнее читать документацию:

Using one of the above mentioned methods, when the application determines that

there is enough space to write a transmit packet, the application must first write into the

endpoint control register, before writing the data into the data FIFO.

Share this post


Link to post
Share on other sites

Ещё разик подниму тему.

 

На эти грабли: https://my.st.com/public/STe2ecommunities/m...rrentviews=1592 никто не наступал?

 

Прикрутил библиотеку libopencm3, сделал из неё HID. Обмен - по нулевому endpoint'у блоками в 32 байта.

setup-пакеты ходят нормально, а от data out пропадают первые 4 байта. Странный костыль в библиотеке - добавить тысячу NOP'ов перед считыванием - не помогает. Да и выглядит он некрасиво...

Share this post


Link to post
Share on other sites
Ещё разик подниму тему.

 

На эти грабли: https://my.st.com/public/STe2ecommunities/m...rrentviews=1592 никто не наступал?

 

Прикрутил библиотеку libopencm3, сделал из неё HID. Обмен - по нулевому endpoint'у блоками в 32 байта.

setup-пакеты ходят нормально, а от data out пропадают первые 4 байта. Странный костыль в библиотеке - добавить тысячу NOP'ов перед считыванием - не помогает. Да и выглядит он некрасиво...

 

Попробуйте стандартную от st - у меня вполне нормально завелась как CustomHID. Использовал STM32_USB-Host-Device_Lib_V2.1.0 на проце stm32f105, плюс FreeRtos. Делал CAN-USB сниффер - сливать дампы FMS j1939 с грузовиков. На стресс тестах правда пропускной способности USB не хватает - ограничение HID, но не хочется отказываться от использования дефолтных драйверов в windows. И я надеюсь что в реальных условиях такого потока не будет. :)

 

Правда на текущий момент есть два "нюанса":

1) Не работает на одном из ноутбуков у сотрудника - устройство обнаруживается, но данные в программу от устройства не поступают.

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

2) Несколько раз были замечены случаи переподключения устройства - внешне проявляется как будто устройство отключили и сразу подключили. Опять же склоняюсь к мысли, что это не из-за либы. Скорее всего это ошибки в моей реализации остального функционала - похоже что попадаю в HardFault и перегружаюсь по WDT. Проявляется этот глюк крайне редко - пока пытаюсь поймать.

 

libopencm3 мельком смотрел - смутила необходимость в цикличном выполнении функции usbd_poll. В библиотеке от st все callback'и из OTG_FS_IRQHandler дергаются.

 

Share this post


Link to post
Share on other sites

Рекомендацию библиотеки ST спасибо. Знать, что оно таки работоспособно, это хорошо :-)

 

Допилил этот CustomHID из крайней версии CubeMX (он там сломаный, просто куда-то потеряли кусок кода).

Да, действительно, работает. Да, действительно, данные не теряет.

 

При сравнении CubeMX и libopencm3 была обнаружена интересная особенность. Как известно, эндпоинт после завершения обмена становится неактивным, и его надо постоянно включать.

Авторы libopencm3 делают это при первой же возможности (для OUT-транзакции - сразу после вычитывания из FIFO), а в "родной" библиотеке - после многочисленных действий (обработать пакет, подумать, какой будет следующим, какого он размера...). В итоге, в в libopencm3 в один фрейм попадает и SETUP с указанием "а сейчас будет SET REPORT" и собственно данные этого report'а. Точнее, не все данные, а сдвинутые на 4 байта (и дополненные мусором в конце).

 

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

 

Если по приему setup пакета ничего не делать и не разрешать обратно эндпоинт в течении 1 мс, всё начинает работать корректно. Но меееедленно.

 

 

Собственно, вопрос:

1) я правильно понимаю, что спецификация USB 2.0 Full Speed не запрещает посылать setup и out в один эндпоинт за один фрейм?

2) у кого-нибудь на этом FS OTG использовал возможность использовать несколько транзакций в одном фрейме?

 

 

 

2) Несколько раз были замечены случаи переподключения устройства - внешне проявляется как будто устройство отключили и сразу подключили. Опять же склоняюсь к мысли, что это не из-за либы. Скорее всего это ошибки в моей реализации остального функционала - похоже что попадаю в HardFault и перегружаюсь по WDT. Проявляется этот глюк крайне редко - пока пытаюсь поймать.

Возможно, это какие-то "электрические" проблемы. Если рядом есть грузовик, надо рассчитывать, что в любой момент с неожиданной стороны придёт помеха.

 

libopencm3 мельком смотрел - смутила необходимость в цикличном выполнении функции usbd_poll. В библиотеке от st все callback'и из OTG_FS_IRQHandler дергаются.

Не понимаю, почему так сделали, но там уже почти всё готово для оборачивания этого poll() в прерывание. Собственно, эта часть заработала почти сразу. Дальше - аналогично, штатными callback'оми (правда, тут они динамические - через указатели).

Share this post


Link to post
Share on other sites

По спецификации USB 2.0 если мы говорим о SETUP то это control tranfer, а он описан так

 

Control transfers minimally have two transaction stages: Setup and Status. A control transfer may

optionally contain a Data stage between the Setup and Status stages.

 

то есть как бы да, данные опционально пихаются прямо в середину до статуса.

 

Но естественно пакеты разные, потому что как минимум должны иметь разные токены DATA0 всегда у сетапа и первые данные придут уже как DATA1

 

Share this post


Link to post
Share on other sites

Подумал-подумал, и окончательно запутался.

 

Два bulk-пакета подряд ведь повсеместно встречаются? Соответственно, если бы была проблема "теряется начало любого второго пакета", народ бы много где ругался.

 

А в control можно ведь засунуть длинный пакет, чтоб оно "само" резало-склеивало?.. Вроде б не запрещают.

Сейчас посмотрю, что происходит на границе второй-третий пакет...

 

Share this post


Link to post
Share on other sites

окончанием данных служит пакет длинной меньше максимального

если надо передать данные кратной длине пакета, то за последним полным пакетом посылают пакет 0 длинны как признак окончания.

 

целостность пакета как я понимаю берет на себя железо. А вот деление на пакеты я встречал разные реализации. У кого-то надо прям руками заполнять по пакетно, у кого-то один здоровый буфер и железо контроллера само режет. Я не знаю реализации STM, у них USB какой-то чудной...

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this