‮Сдвиг по фазе (kincajou) wrote,
‮Сдвиг по фазе
kincajou

Categories:

worklog: продолжаю распутывать библиотеку STM32 USB Device Library

...и всё крепче уверенность в том, что её писала группа весьма необщительных товарищей, слабо заинтересованнных в успехе их совместного дела.

Например, заведена структура типа PCD_HandleTypeDef - хэндлер, который собсно и абстрагирует физический интерфейс. В ней там внутри много чего интересного, в т.ч. два массива структур типа USB_OTG_EPTypeDef. Массивы на карте обозначены бувами IN_ep[] и OUT_ep[], соотв. они реализуют "абстрактное представление" конечных точек. Внутри них тоже много чего.. и вот тут уже начинается реально смешное.

Вероятно, кто-то решил, что оторвать индекс в массиве от реальной конечной точки - неплохая идея. Ну, то есть,. предположим, что нам нужно всего две точки, но по каким-то эстетическим соображениям мы не хотим оптимально использовать железо, поэтому это будут не EP1 и EP2, а совсем даже EP5 и EP6. То есть IN_ep[1] это будет EP5, а OUT_ep[2] это будет EP6, например. Чтобы никто не догадался, нахрена так усложнять, в структуре USB_OTG_EPTypeDef есть поле num, скрозь которое и можно было бы так сделать... но, насколько я вижу, даже те функции, что непосредственно перемещают данные между абстрактной абстракцией и реальным железом, получают прописанный в явном виде параметр epnum, полностью игнорируя это вышеобозначенное поле. Зачем оно такое надо? Я не знаю.

Кроме того, внутри USB_OTG_EPTypeDef есть поле is_in, в которое прописывается 1 для конечных точек направления IN и 0 для OUT. Но я пока не вижу, чтобы это поле всерьёз где-нибудь использовалось (в хэндлере-то всё равно два отдельных массива с явно заданным направлением!).

И это далеко не все признаки расщепления сознания у тех, кто всё это писал. Например, вот зачем тут проверяется, используем ли мы DMA (которое, к тому же, вообще не работает в режиме FS, оно возможно только для HS (!!!) -- в Reference Manual, в описании регистров DMA конечных точек, есть ремарка: Note: Configuration register applies only to USB OTG HS):
	if(hpcd->Init.dma_enable == 1)
	{
		if((epnum == 0) && (hpcd->OUT_ep[epnum].xfer_len == 0)) { 
			USB_EP0_OutStart (hpcd->Instance, 1, (uint8_t *)hpcd->Setup);
		};
	}

Неужели обработку пакетов ZLP (zero-length packet, это такой специальный случай в протоколе) и подготовку конечной точки EP0 к приёму пакета Setup нужно вести только если используется DMA?! нет же, протокол USB знать не знает о том, как перемещаются данные внутри устройства, ему вообще плевать на эту механику. Так зачем же тут так сделано?!

Аналогичный бред есть и внутри функции USB_EP0_OutStart -- она взводит флаг разрешения работы конечной точки (DOEPCTL.EPENA) только если ей передан параметр dma = 1 (что, повторю, не имеет смысла для FS, так как в этом режиме железо не поддерживает работу через DMA). То есть, если мы в режиме FS, то никакая конечная точка никогда не передаст никаких данных. Ну прелесть же. Как оно вообще работает? Или же, назвав этот параметр dma, назвав флаг dma_enable, авторы библиотеки подразумевали нечто совершенно иное -- но тогда что именно они подразумевали?

Ну и этсамое. Код там временами смотрит на значение полей, обозначенных в Reference Manual как "reserved"... :(


Всё под нож! Всё!

Upd: несколько дней возни вслепую и паникующего отчаяния -- и вот я уже дошёл до того, что нужно написать коллбэки для обработчика прерываний на почти все возможные ситуации, начиная от события "обнаружен VBus", заканчивая "получен пакет данных от хоста", и затем уже приступать к реализации конкретного драйвера класса. Зато я теперь примерно представляю, как же это таинственное USB устроено внутри (хотя бы применительно к семейству STM32F7).
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 7 comments