Здравствуйте. Есть ли тут гуру, у кого есть успехи в USB на регистрах на stm32?
Конкретно чип stm32g474ceu6 Необходимо реализовать CDC (Serial Com)
В качестве базиса взял Middleware библитеку от ST, хоть там и крайне сложно разобраться из-за многочисленных переходов между разными модулями (HAL, LL, PCD и т.д.). Так же долго курил Reference Manual от ST и Документацию по USB протоколу в разных нарезках.
Первая проблема, с которой столкнулся: нигде нет рекомендованного процесса обработки запросов от хоста к устройству. С дебагом тоже сложно, т.к. таймауты на ответы очень маленькие.
Чего добился в своих изысканиях - полностью проходит инициализация: - все дескрипторы пересылаются - в списке USB устройств на хосте устройство появляется с нужными описаниями - serial-порт в системе есть - при подключении к serial-порту проходят стадии CDC_SET_CONTROL_LINE_STATE и CDC_SET_LINE_CODING, параметры передачи получаю
Т.к. я делал на базе Middleware от ST, двойную буферизацию не использовал, применены две доп точки: - ID=1 - Data = Bulk-type, in/out, размер буфера 64 байта - ID=2 - Notify = interrupt, 8 байт, передача только в сторону хоста.
Но вот при попытке передачи данных начались проблемы. Отправку в сторону хоста вообще не понял, как отладить. При отправке с хоста на устройство возникли две проблемы, пояснения по которым и прошу от гуру:
1. Прерывание USB_ISTR_CTR возникает, но получается ситуация, когда указанная в ISTR конечная точка точка в своём регистре не имеет битов RX/TX/SETUP, а напрямую бит CTR в регистре ISTR не снимается. Это делается только через снятие битов RX/TX/SETUP у конечной точки. Если игнорировать ситуацию, обработчик прерываний постоянно вызывается, пока есть флаг USB_ISTR_CTR.
В цикле проверил другие точки, там есть те, у которых данные биты установлены. Обработка таких точек со снятием RX/TX/SETUP решило проблему с флагом USB_ISTR_CTR, однако уткнулся во вторую проблему.
2. Решив костыльно проблему-1, получил запуск обработки RX (от хоста к устройству) для Data-точки (ID=1), однако, читаю RX-регистр этой точки и вижу там значение: 0x84c4.
Согласно документации: - 0x84 относится к размеру буфера и соответствует 64 байт (это то, что я сам указал). - 0xc4 - это размер данных = 196 байт, т.е. получается исходно некорректное значение.
Пробовал уменьшать размер буфера до 32 байт, верхний байт RX-буфера меняется корректно, а нижний остаётся 0xc4.
Подозреваю, что это всё ещё следствие первой проблемы. А первая проблема - следствие ещё более ранне ошибки. Только вот уже перестал понимать, в какую сторону копать. ИИ вообще на серьёзных щах утверждает, что проблема-1 - это вообще стандартная ситуация и её именно так надо решать, и что мол об этом даже ST говорит. Но таких утверждений от ST я не нашёл в интернетах, а в Middleware никаких подобных костылей тоже нет.
Я сейчас тоже "распрямляю" реализацию ST. Почти заработало, правда на данным момент только под STM32F1xx. Такая сложная реализация у них только из-за универсальности: там подключаются калбэки для обработки нужного железа (FS/HS CORE), подключаются калбэки нужного класса и т.д. Двойная и тройная буферизация. А ещё, что мне не нравится, бесконтрольные скрытые объекты в ОЗУ, я люблю контролировать распил ОЗУ. Я пару раз просто выносил эти объекты в свою структуру и пробрасывал указатели на них в недра этого бардака, но потом просто достало и решил для себя сделать прозрачный простой монолитный вариант. Кстати, до HAL был StdPeriph и у него не было поддержки USB (у HAL это внутри PCD и USB), поэтому тогда реализация USB была более прозрачной, а сейчас имеем что имеем.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 6 декабря 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
У меня, кстати, есть USB Custom HID на Паскале. Отлично работает, результат такого же распрямления юзером под ником Pelikan с форума mikroe. Я его адаптировал для 437 в прошлом и даже переключал между USB FS и USB HS. Можете его просто перекрасить в C, например, если надо.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 6 декабря 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
С дебагом тоже сложно, т.к. таймауты на ответы очень маленькие.
Прежде чем начинать разбираться с USB, желательно разобратся, чем и как вы отлаживаете. ST-Link для этой цели не очень подходит - вывод отладочной информации через SWO ломает логику работы USB контроллера. В последовательный порт можно выводить только буфер через DMA, иначе, тоже ломается логика. Точка останова в обработчике прерываний настоящее содержимое регистров не покажет, чтобы его посмотреть нужно до остановки копировать содержимое регистров в глобальные переменные. Полгода назад пилил совой стек для G474 на регистрах, в библиотеке от ST подсмотрел только инициализацию USB контроллера до первого прерывания по RESET, немного его не доделал. Отладчик J-Link, в проект подключен отладочный вывод через SEGGER RTT. Никаких чудес в работе не заметил, все как по даташиту.
_________________ Зачем делать сложным, то что проще простого...
В последовательный порт можно выводить только буфер через DMA, иначе, тоже ломается логика.
С этим не согласен. С DMA может быть лучше, но не факт. В одном проекте отлаживал работу USB-стека со сниффером (событий и USB-кадров) в UART - никаких проблем. Всё обошлось без DMA, с обычным выводом в UART по прерываниям. Если руки кривые - то и DMA не поможет их выпрямить, а если умеючи - то DMA не обязателен.
В качестве прямо экстремального варианта можно выделить один порт на выдачу 8 или 16 битных данных и собирать их через LA. При этом стоимость будет всего лишь в одной команде вывода в регистр ODR.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 6 декабря 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
В качестве прямо экстремального варианта можно выделить один порт на выдачу 8 или 16 битных данных и собирать их через LA. При этом стоимость будет всего лишь в одной команде вывода в регистр ODR.
Это чуть лучше, чем отлаживать USB посредством мигающего светодиода. Но зачем так жёстко-то? UART вполне нормально справляется с такой задачей. Вот вывод USB-сниффера моего текущего проекта во время энумерации: СпойлерПоток строк, начинающихся с "UDBG." выплёвывается в UART во время USB-энумерации на 921600 бод. Это расшифровка операций, выполняемых USB-стеком. Конечно это работает с буферизацией в ОЗУ МК. Но работает как видно и без DMA прекрасно. А для современных МК размер ОЗУ-буфера в ~8...16 КБ - как правило не является проблемой. Расшифровка всех USB-кадров выполняется в МК. И весь обмен виден наглядно. Отлаживаться удобно.
Если обмен по USB не очень интенсивный, то и после энумерации (при нормальной работе) этот снифер успевает всё прокачивать.
Но зачем так жёстко-то? UART вполне нормально справляется с такой задачей. Вот вывод USB-сниффера моего текущего проекта во время энумерации:
А мне такие выкрутасы не нужны, у меня аппаратный снифер есть. Поэтому, отладка USB на каком-нибудь STM32F042 вполне реально для меня. Я его показывал на соседнем форуме, если кому интересно. С фоточками кишочков. Ну а на безрыбье да, UART вполне годен при наличии достаточного количества ОЗУ.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 6 декабря 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
Спасибо большое, что откликнулось столько народу. Проблему решил. Первое сообщение можно игнорировать, всё там описанное не актуально. Бага оказалась в адресации регистров точек. Причём, настолько хорошо замаскировалась, что найти её не мог несколько недель, при всех вариациях отладки и сёрфинга по коду. Получилось, что data-point не была настроена совсем, хотя "всё говорило об обратном". Это при том, что подозрения на криво настроенную data-точку были приоритетными и этому уделялось много времени.
Сейчас всё работает, данные передаются в обе стороны. Такую цену за настолько мелкую помарку я ещё не платил, танцую уже второй час.
Зато перебрал много разных подходов к реализации обработки setup-запросов, в связи с чем у меня всё-таки есть несколько вопросов:
1. Правильно ли я понимаю, что по завершению обработки любого setup-запроса от хоста, включая data-stage, может быть только три варианта: - отправляем пустой пакет хосту (ок) - отправляем данные хосту (если он их хочет) - отправляем stall (выставлением stat-битов в регистре точки-0) Игнорировать запросы не стоит, но при этом нужно обработать STD_POINT_CLEAR_FEUTURE, в котором снять stall. Так?
2. stall-биты выставляем на RX или TX в зависимости от старшего бита в bmRequestType? Тут я так и не разобрался. Внутри ST там в каких-то ситуаций ставится только RX/TX, а в коких-то сразу оба. Логики я не понял.
3. В ST-библиотеке, как я понял, для точки-0 реализован принцип: сначала принимаем запрос полностью, оставляем RX-NAK, выполняем отправку ответа на хост, и только в TX-прерывании выставляем RX-VALID. Т.е. фазы приёма и передачи жёстко разделены. Является ли эта логика рекомендованной? Или можно сразу после обработки setup-пакета выставлять RX-VALID и дальше уже делать что хочется (отправлять, stall и т.д.), т.е. приём и передача параллелятся, как для остальных точек.
Кто как реализует?
4. Есть ли разница при обработке CTR-прерывания для точки-0 ориентироваться только на SETUP+CTR_RX/CTR_TX или ISTR_DIR + SETUP/CTR_RX. У ST реализован второй вариант и я решил остановиться на том же. Но видел у разных блогеров разные подходы. Есть какие-то рекомендации?
А мне такие выкрутасы не нужны, у меня аппаратный снифер есть. Поэтому, отладка USB на каком-нибудь STM32F042 вполне реально для меня. форуме, если кому интересно. С фоточками кишочков. Ну а на безрыбье да, UART вполне годен при наличии достаточного количества ОЗУ.
Аппаратный сниффер хорош когда USB-стек уже отлажен. Кем-то. И работает правильно. Но тема-то "USB на регистрах". Т.е. как я понимаю - "своими руками". Вот отлаживаете вы свой USB-стек, и не понимаете чего-то в работе внутренних регистров USB-периферии (потому как в мануале описано оно часто - из рук вон). Что-то работает не так, как вы ожидали. И вы хотите понаблюдать поведение каких-то полей регистров USB в реальном времени - во время обмена по USB. Как вам поможет ваш аппаратный сниффер? Очевидно - никак. И JTAG тут - слабый помощник (как уже отметили выше). А в свой сниффер я запросто добавлю захват интересующего меня регистра или переменной в нужном месте работы программы. И всё сразу увижу. Так что это внешний аппаратный сниффер - "на безрыбье". Аппаратный сниффер есть и у меня. Но если бы он помогал в отладке своего USB-стека - я бы свой сниффер не писал бы.
кстати, во какой нашёл (у меня нет аппаратного, решил полазить) "USB-анализатор протокола USB-снайпер USB-инструмент анализа данных адаптированный к Wireshark" https://aliexpress.ru/item/1005009237087361.html однако, он в три-четыре раза дешевле (и проще), чем у HardWareMan, что несколько смущает...
1. Правильно ли я понимаю, что по завершению обработки любого setup-запроса от хоста, включая data-stage, может быть только три варианта:
Что такое "setup-запрос" - я не знаю, но data-stage setup-транзакции всегда передаётся от хоста к ведомому. А значит - никакие данные к хосту в ней отправить вы не можете. И квитируется setup-транзакция как правило - автоматически самой USB-периферией (а не программным USB-стеком). Т.е. - если USB-периферия проинициализирована, то она сама автоматически отправит ACK на setup-транзакцию. Для отправки данных ведомый->хост (после setup-транзакции) хост, если нужно, инициирует следующую IN-транзакцию. В которой ведомый и может отправить свои ответные данные. Также и пакеты квитирования - есть: ACK, NACK, STALL. (в USB_HS ещё есть дополнительные)
jcxz, по внешнему поведению часто достаточно понимания, что не так внутри. Хотя, конечно, у каждого свои фломастеры.
Nranddek, есть такой прибор, да. Это клон опенсурсного варианта, причём на том же алике есть ещё дешевле. Вот исходный проект.
_________________ Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ Актуальность репозитория: 6 декабря 2025 года Если чего-то не хватает с сайта st.com - пишите, докачаю.
jcxz, по внешнему поведению часто достаточно понимания, что не так внутри. Хотя, конечно, у каждого свои фломастеры.
Эх! где-ж вы были, когда я свой USB-стек отлаживал. И спрашивал о поведении непонятных мне регистров USB на форумах, и никто не мог подсказать. Только этот сниффер и подсказал.
"По внешнему поведению" - это примерно как диагностировать и лечить больного, основываясь только на внешних проявлениях болезни - цвете мочи и густоте кала. Далеко не каждую болезнь можно победить не заглядывая внутрь больного. Чаще всего необходимо на внутренние органы регистры посмотреть.
Cliff 1 - в общем верно. Если девайс может обработать сетуп - отвечает ZLP или данными. Если не может обработать сетуп - выставляет STALL. Снимать STALL программно не нужно, для EP0 STALL снимается аппаратно при получении от хоста SOF. CLEAR_FEATURE от хоста приходит с адресом ендпоит 1..n вот для указного ендпоинта и нужно снимать STALL программно. 2 - логику я тоже не понял, поэтому всегда ставлю STALL и на RX и на TX. 3 - В режиме CONTROL ендпоинт работает по принципу запрос - ответ, пока девайс не ответит на запрос хоста очередного запроса не будет, поэтому работать будет любой из двух методов. Я, чтобы не плодить сущностный, EP0 обрабатываю ровно также как и остальные. 4 - второй вариант, потому, что он эффективнее по коду.
_________________ Зачем делать сложным, то что проще простого...
jcxz, вспоминаю себя в мои 18-25, когда я один умный, а кругом одни д.... конечно же я это всё изучил и прекрасно понимаю, о чём вы. Меня интересует работа с протоколом в связке с аппаратной реализацией в stm32.
nibelung, большое спасибо! максимально чётко и по делу! Все вопросы отпали.
2. stall-биты выставляем на RX или TX в зависимости от старшего бита в bmRequestType? Тут я так и не разобрался. Внутри ST там в каких-то ситуаций ставится только RX/TX, а в коких-то сразу оба. Логики я не понял.
Я переделывал ST-ую либу и оба там выставляются только в функции ctrlError(), не помню как она в оригинале называлась.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения