LINUX.ORG.RU

STM32 и USB

 ,


0

1

Я пытаюсь разобраться с USB-модулем в STM32F103. На низком уровне, без библиотек.

Для начала настраиваю PLL с использованием внешнего кварца (бит RCC_CFGR_PLLSRC = 1) и с делением USB-частоты на 3 (бит RCC_CFGR_OTGFSPRE = 0), коэффициент умножения 9 (частота кварца 8 МГц, частота ядра 72 МГц). PLL точно успешно запускается, это видно по тому, что USART и SysTick работают адекватно.

Затем включаю тактирование USB, разрешаю прерывания USB_FS_WKUP_IRQ и CAN1_RX0_IRQ. Выполняю начальную инициализацию USB:

USB->CNTR = 0;
USB->ISTR = 0;
USB->BTABLE = 0;
USB->CNTR = USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_CTRM;

В обработчике прерывания (любого из двух) смотрим на USB->ISTR, чтобы понять что случилось. Сначала, разумеется, при подключении к компьютеру приходит RESET. Сбрасываем флаг прерывания и выполняем настройку 0-ой конечной точки, а также устанавливаем бит EF в USB->DADDR (теперь USB->ADDR = 0x80). В результате настройки конечной точки у нас в USB->EP0R оказывается 0x3220. По идее это значит, что EP0 готова работать, как на приём, так и на передачу, причём данных для передачи пока нет (NAK), а к приёму мы готовы (VALID).

Ну а ещё мы настроили дескриптор буфера (из-за BTABLE == 0, дескриптор нулевой точки находится в самом начале области буферов USB). Таким образом, USB_ADDR0_TX = 80, USB_COUNT0_TX = 0, USB_ADDR0_RX = 64, USB_COUNT0_RX = 0x2000. Что значит, что максимальный размер пакета для приёма 16 байт.

Готово. Выходим из обработчика прерывания.

Далее я ожидаю получить прерывание по состоянию CTR, что бы означало, что пришёл первый SETUP-пакет и с ним нужно что-то сделать. А получаю прерывание по состоянию WKUP и ESOF. И даже не одно, а очень много. Пока хосту не надоест ждать ответа и он не пошлёт новый RESET (предварительно плюнув в dmesg, что устройство отказывается принимать назначенный адрес функции), затем ситуация повторяется.

Что я забыл сделать?

★★★★★

Почему ты не хочешь взять opencm3?

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Я использовал её какое-то время. Однако она меня не устраивает по нескольким причинам:

1) Недопиленность. Например, I2C реализован до конца только для STM32F3xx.

2) Местами быдлокод. Например, в той же реализации USB. Там есть поля регистра, которые нельзя просто так взять и записать. Нужно записать единички в те битики, которые должны изменить состояние на противоположное, а куда запишется нолик останется неизменным. И в libopencm3 реализовано считывание значение в регистра во временную переменную, цикл по всем битам этого значения, проверка надо ли его менять, запись единички если надо, а потом запись нового значения в регистр. А ведь достаточно REG = REG & (~FIELD_MASK) ^ field_value.

3) Местами слишком платформоспецифичные решения. Например, настройка GPIO и PLL для STM32F1xx и остальных серий очень и очень сильно отличается, вплоть до разных функций и разной последовательности операций. Да, я понимаю, что у STM32F1xx соответствующие модули немного другие, но ведь можно было бы как-то сгладить этот угол.

В результате мне это надоело и я решил запилить свою библиотеку с блек-джеком и шлюхами. Которая должна удовлетворять двум противоречащим критериям - по максимуму скрывать особенности платформы, чтобы код приложения был полностью одинаков во всех случаях, однако в отличии от всяких ардуин предоставлять штатные возможности для деланья всяких платформоспецифичных вещей. Это реализовано с помощью классов C++ (да, у меня даже ножка GPIO имеет свой класс, правда, код всё равно получается оптимальнее, чем у Arduino, ибо вызов виртуальной функции быстрее, чем поиск пина в таблице всех пинов платы). Базовый класс умеет то, что должна уметь соответствующая периферия на любом контроллере, а для каждой платформы я его расширяю с учётом её особенностей. В итоге, когда не нужны особые вещи, можно вызывать базовые функции, семантика которых не отличается от платформы к платформе.

https://github.com/KivApple/controllerFramework - вот текущее состояние. Уже умею GPIO (STM32, в планах поддержка Linux), USART (STM32, Linux), I2C (STM32, в планах поддержка Linux i2c-dev) и EXTI (STM32). Есть библиотеки для OneWire на базе USART, а также некоторых I2C-датчиков.

Сейчас работаю над поддержкой USB для STM32.

KivApple ★★★★★ ()
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

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

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Я знал, что это тебе не понравится, но алгоритм посмотреть в любом случае сможешь.

KivApple ★★★★★ ()
Ответ на: комментарий от KivApple

Я на мьютексах делал и асинхронно (буфер отсылается либо при заполнении, либо 1 раз в миллисекунду — по таймеру).

Кстати, не хочешь утащить к себе мою «полуаппаратную» реализацию 1-wire на ПДП с таймером?

Eddy_Em ☆☆☆☆☆ ()
Ответ на: комментарий от Eddy_Em

Вполне возможно потом гляну, пока есть только простая реализация с использованием UART. Пока у меня нет поддержки DMA в моих классах, поэтому не на чем реализовывать будет, но я добавлю её позднее.

KivApple ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.