stm32 USB host

Кто любит RISC в жизни, заходим, не стесняемся.
danone78
Встал на лапы
Сообщения: 82
Зарегистрирован: Вт фев 15, 2022 21:28:35

stm32 USB host

Сообщение danone78 »

Здравствуйте. Не могу установить постоянное подключение контроллера(stm32h745) с мышкой.
Хронология:
1. На прерывании Port connect detected делаю Port reset
2. ядро устанавливает Port enable
3. В GINTSTS прилетает disconnect и сбрасывается Port enable.
и так по кругу с частотой 1-2 гц.
Я должен успеть что-то отправить мышке (например get descriptor) или соединение уже должно быть постоянным?
Мышь low speed-ная, я вижу это в статусе подключения в HPRT. Я уж и фрейм интервал поставил 1мс (резет валуе 1.25) и частоту PHY 48/8=6 сделал. Может мне D+ D- поменять местами?
Пробую отправить get descriptor в момент подключения, в ответ... нифига.
В device режиме все работает, скопировал по дескрипторам мышку, жму кнопку - мышь едет.
danone78
Встал на лапы
Сообщения: 82
Зарегистрирован: Вт фев 15, 2022 21:28:35

Re: stm32 USB host

Сообщение danone78 »

Я точно не понял что произошло, но все заработало. Сначала я подключил флешку вместо мышки на FS, потом и мышка стала отвечать на LS.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: stm32 USB host

Сообщение jcxz »

[uquote="danone78",url="/forum/viewtopic.php?p=4652393#p4652393"]Я точно не понял что произошло, но все заработало. Сначала я подключил флешку вместо мышки на FS, потом и мышка стала отвечать на LS.[/uquote]Если "не понял", то значит завтра с большой вероятностью снова отвалится. Раз причина не найдена.
Martian
Друг Кота
Сообщения: 12867
Зарегистрирован: Сб дек 18, 2021 19:25:32
Контактная информация:

Re: stm32 USB host

Сообщение Martian »

Притом, с большой вероятностью сработает такая же последовательность действий. Я бы проверил цепи питания, на предмет ненужных пульсаций, всплесков/провалов, помех.
danone78 писал(а):Может мне D+ D- поменять местами?
Эти слова (если не в шутку сказаны) немного пугают и наводят на всякие мысли... это демо-отладочная плата, или что-то самодельное? если последнее, то к схеме и трассировке USB множество вопросов может быть.
danone78
Встал на лапы
Сообщения: 82
Зарегистрирован: Вт фев 15, 2022 21:28:35

Re: stm32 USB host

Сообщение danone78 »

Не то чтобы все отвалилось, но далеко я не продвинулся. Все что удалось это отправить get descriptor, получить ACK+XFRC одновременно, потом отправить пустой пакет. Пытаюсь отправить токен IN - или ошибка передачи или STALL. Можно принимать ответы на том же канале на котором отправляю запросы? А то с другими каналами совсем плохо, все зависает по непонятным причинам, размаскировываю канал, отправляю пустой пакет или токен IN(то есть FIFO не трогаю) и зависаю, пытаюсь прочитать и очистить его регистр прерывания, а там нули и сбрасывать нечего, но с прерывания не выйти.

Добавлено after 13 minutes 41 second:
В Device режиме можно включить несколько конечных точек одновременно, с каналами видимо, надо выключать канал перед включением другого, хотя они по xfrc должны сами выключатсья, ща залогаю регистр управления каналом гляну что там происходит.

Добавлено after 5 hours 53 minutes 17 seconds:
Лед тронулся. Вот уж такую козу я не ожидал. Отправил get descriptor на CH0, получил АСК+XFRC. При отправке токена IN на CH1 выскакивают прерывания конечных точек! В общем я их замаскал и вуаля, получаю первый дескриптор.
danone78
Встал на лапы
Сообщения: 82
Зарегистрирован: Вт фев 15, 2022 21:28:35

Re: stm32 USB host

Сообщение danone78 »

Вообще из всей периферии на stm32, USB самая вредная. Все упирается в прерывания и статусный регистр:
- Некоторые прерывания просто не маскируются вообще
- некоторые маскируются (не срабатывают), но биты в статусном регистре устанавливаются
- есть и такие которые не устанавливают бит, но срабатывают.
- IEPINT срабатывает в принудительном хост режиме при DAINT=0.
Самое веселье начинается, когда переключаешь режим и делаешь core soft reset - карета превращается в ТЫКВУ! :shock:
Весь этот выпендрешь с On-The-Go приводит к глюкам в работе конечных автоматов.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: stm32 USB host

Сообщение jcxz »

[uquote="danone78",url="/forum/viewtopic.php?p=4654784#p4654784"]Вообще из всей периферии на stm32, USB самая вредная. Все упирается в прерывания и статусный регистр:
- Некоторые прерывания просто не маскируются вообще
- некоторые маскируются (не срабатывают), но биты в статусном регистре устанавливаются[/uquote]Вообще-то это и правильно. Странно ожидать другого.

[uquote="danone78",url="/forum/viewtopic.php?p=4654784#p4654784"]- есть и такие которые не устанавливают бит, но срабатывают.[/uquote]С stm32h745 не работал, но ваял USB-device в STM32Lxxx. Не Кубом, а самостоятельно. И особенных проблем не встретил. Почти всё работало нормально. Единственный косяк, на который наткнулся - неполная поддержка изохронного режима.

Но у меня был только device-режим. Без всяких host или OTG.
danone78
Встал на лапы
Сообщения: 82
Зарегистрирован: Вт фев 15, 2022 21:28:35

Re: stm32 USB host

Сообщение danone78 »

Мне повезло, раньше на куб инфы не было вообще, и мне пришлось начинать в Keil. А там есть возможность писать прямо в асме, что меня несказанно радовало. АРМовцы поздно прочухали что такое людям давать нельзя, вся их инфа вместе с архитектурами ядер разлетелась по свету.
STM-щики в своих RM-ах гениально обтекают многие нюансы. Мне вообще кажется, что у них наш Сергей Лавров работает на RM-ах.

Добавлено after 28 minutes 4 seconds:
У меня уже все работает, но вся эта возня с дескрипторами мне кажется не обязательна.
Если я подключаю USB устройство и знаю что это мышь и что она с конечной точки 1 будет слать мне interrupt данные, почему бы просто сразу не открыть ей канал и послать set_configuration, без адресации без ничего?
Я например так реализовал микро веб сервер, все htm страницы умещаются в один сегмент 1420 байт, я просто разворачиваю секвенции и отправляю ответы. Все гениально, просто и работает с любого смартфона через вайфай.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: stm32 USB host

Сообщение jcxz »

[uquote="danone78",url="/forum/viewtopic.php?p=4657655#p4657655"]мне пришлось начинать в Keil. А там есть возможность писать прямо в асме, что меня несказанно радовало. АРМовцы поздно прочухали что такое людям давать нельзя, вся их инфа вместе с архитектурами ядер разлетелась по свету.[/uquote]Вообще не понял что тут написано... :facepalm:
Как именно ARMовцы мешают вам писать на асме? Что "давать нельзя" и почему?

Или вы - конспиролог? 8)
Аватара пользователя
HardWareMan
Мучитель микросхем
Сообщения: 429
Зарегистрирован: Ср сен 02, 2015 07:47:20

Re: stm32 USB host

Сообщение HardWareMan »

[uquote="danone78",url="/forum/viewtopic.php?p=4657655#p4657655"]Мне повезло, раньше на куб инфы не было вообще, и мне пришлось начинать в Keil. А там есть возможность писать прямо в асме, что меня несказанно радовало. АРМовцы поздно прочухали что такое людям давать нельзя, вся их инфа вместе с архитектурами ядер разлетелась по свету.
STM-щики в своих RM-ах гениально обтекают многие нюансы. Мне вообще кажется, что у них наш Сергей Лавров работает на RM-ах.[/uquote]

А мужики то не в курсе! Вот пример моего говнокодинга на асме под Eclipse для ARM EABI:
Спойлер

Код: Выделить всё

// Набор функций для дампинга картриджей Денди

#include "dumper/dendy.h"

// Отключение режима Денди
void Dendy_Off()
{	// Параметры
	GPIO_InitTypeDef	GPIO_InStr;
	// Отключаем шину
	ADR_BUS_Off(); CHR_BUS_Off(); PRG_BUS_Off();
	// Деинит управляющих ног Dendy
	PRG_F2_Off(); PRG_RnW_Rd(); CHR_PRD_Off(); CHR_PWR_Off(); CHR_nPA13_Off();
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM5, DISABLE); TIM5->CR1 = 0x0000;
	GPIO_InStr.GPIO_Pin = 0x0001;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOA, &GPIO_InStr );
	GPIO_ResetBits( GPIOA, 0x0001 );
}

// Включение режима Денди
void Dendy_On()
{	// Параметры
	GPIO_InitTypeDef	GPIO_InStr;
	// Инит общих управляющих ног
	ADR_BUS_On(); CHR_BUS_Off(); PRG_BUS_Off();
	// Инит управляющих ног Dendy
	PRG_F2_Off(); PRG_RnW_Rd(); CHR_PRD_Off(); CHR_PWR_Off(); CHR_nPA13_Off();
	GPIO_InStr.GPIO_Pin = 0x0001;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOA, &GPIO_InStr );
	GPIO_PinAFConfig( GPIOA, GPIO_PinSource0, GPIO_AF_TIM5 );
	// F2: ____------- 200ns/360ns = 560ns/1.786MHz
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM5, ENABLE); TIM5->PSC = 0x0000; TIM5->ARR = 0x0000002E; TIM5->CCR1 = 0x0000001E; TIM5->CCMR1 = 0x0060;
	TIM5->CCMR2 = 0x0000; TIM5->CCER = 0x0001; TIM5->SMCR = 0x0000; TIM5->DIER = 0x0000; TIM5->CR2 = 0x0000; TIM5->CR1 = 0x0001;
	// Сбрасываем картридж
	Dendy_Reset();
}

// Включить программный режим денди
void Dendy_Manual()
{	// Параметры
	GPIO_InitTypeDef	GPIO_InStr;
	// Инит общих управляющих ног
	ADR_BUS_On(); CHR_BUS_Off(); PRG_BUS_Off();
	// Инит управляющих ног Dendy
	PRG_F2_Off(); PRG_RnW_Rd(); CHR_PRD_Off(); CHR_PWR_Off(); CHR_nPA13_Off(); // PRG_ROM_Off();
	GPIO_InStr.GPIO_Pin = 0x0001;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOA, &GPIO_InStr );
	// Деактивация F2
	GPIO_ResetBits( GPIOA, 0x0001 );
}

// Сброс картриджа
void Dendy_Reset()
{	// Выключаем шину
	ADR_BUS_Off(); Delay( 0x3567DFE );
	GPIOC->ODR &= 0xFF00; GPIOE->ODR = 0x0000;
	ADR_BUS_On(); Delay( 0x3567DFE );
}

// Чтение данных PRG в буфер
__attribute__ ((naked)) void Read_PRG( uint8_t *PBuf, uint32_t Start, uint32_t Size )
{	// Начинаем
	__asm volatile
	(	"PUSH	{R0-R8}\n"
		// R0 = PBuf
		// R1 = Start
		// R2 = Size
		// R3 = GPIOA_IDR (Для чтения F2)
		"MOVW	R3, #0x0010\n"
		"MOVT	R3, #0x4002\n"
		// R4 = GPIOE_ODR (Для вывода адреса)
		"MOVW	R4, #0x1014\n"
		"MOVT	R4, #0x4002\n"
        // R5 = GPIOD_IDR (Для ввода данных)
		"MOVW	R5, #0x0C10\n"
		"MOVT	R5, #0x4002\n"
		// R6 = Маска $0000FFFF
		"MOVW	R6, #0xFFFF\n"
		"MOVT	R6, #0x0000\n"
		// Выделим
		"AND	R1, R1, R6, LSL #0\n"
		"AND	R2, R2, R6, LSL #0\n"
		// Синхронизируемся
		"CPSID	f\n"
		"Read_PRG_Syn0:\n"
		"LDR	R7, [R3, #0]\n"
		"ANDS	R7, R7, #1\n"
		"IT		EQ\n"
		"BEQ	Read_PRG_Syn0\n"
		"Read_PRG_Syn1:\n"
		"LDR	R7, [R3, #0]\n"
		"ANDS	R7, R7, #1\n"
		"IT		NE\n"
		"BNE	Read_PRG_Syn1\n"
        // Цикл чтения
		"Read_PRG_Loop:\n"
		// Выставляем адрес
		"STR	R1, [R4, #0]\n"
		// Ждем F2 = 1
		"Read_PRG_LWt0:\n"
		"LDR	R7, [R3, #0]\n"
		"ANDS	R7, R7, #1\n"
		"IT		EQ\n"
		"BEQ	Read_PRG_LWt0\n"
		// Увеличиваем адрес чтения
		"ADD	R1, R1, #1\n"
		// Ждем F2 = 0
		"Read_PRG_LWt1:\n"
		"LDR	R8, [R5, #0]\n"
		"LDR	R7, [R3, #0]\n"
		"ANDS	R7, R7, #1\n"
		"IT		NE\n"
		"BNE	Read_PRG_LWt1\n"
		// Сохраняем данные
		"AND	R8, R8, #0x00FF\n"
		"STRB	R8, [R0, #0]\n"
		// Следующий байт
		"ADDS	R0, R0, #1\n"
		// Счетчик байт
		"SUB	R2, R2, #1\n"
		"ANDS	R2, R2, R6, LSL #0\n"
		"IT		NE\n"
		"BNE	Read_PRG_Loop\n"
		"CPSIE	f\n"
		// Обнулим адрес
		"MOVW	R6, #0x0000\n"
		"STR	R6, [R4, #0]\n"
		"POP	{R0-R8}\n"
		"BX		LR\n"
	);
}

// Чтение данных из картриджа в буфер
void Dendy_Read( uint8_t *PBuf, uint32_t Start, uint32_t Size )
{	// Переменные
	uint32_t			Delay;
	GPIO_InitTypeDef	GPIO_InStr;
	// Начальные установки
	PRG_RnW_Rd(); CHR_In(); PRG_In(); GPIOC->ODR &= 0xFF00;
	GPIO_InStr.GPIO_Pin = 0xFFFF;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOD, &GPIO_InStr );
	CHR_BUS_On(); PRG_BUS_On();
	// Это PRG или CHR?
	if ((Start & 0x00FF0000) == 0)
	{
		Read_PRG( PBuf, Start, Size );
	}
	else
	{	// Маски адресов и размеров
		Start &= 0x00003FFF; Size &= 0x00003FFF;
		while ((Size & 0x00003FFF) != 0)
		{	// Выставляем адрес
			GPIOE->ODR = Start & 0x0000FFFF;
			// Активируем строб чтения CHR
			CHR_PRD_On();
			// Ждем
			Delay = 3; while (Delay) { Delay -= 1; }
			// Забираем данные и отключаем строб
			*(PBuf) = (GPIOD->IDR >> 8) & 0x00FF;
			// Деактивируем чтение
			CHR_PRD_Off();
			// Счетчики
			PBuf += 1; Start += 1; Size -= 1;
		}
	}
	CHR_BUS_Off(); PRG_BUS_Off();
}

// Запись данных буфера в PRG
__attribute__ ((naked)) void Write_PRG( uint8_t *PBuf, uint32_t Start, uint32_t Size )
{	// Начинаем
	__asm volatile
	(	"PUSH	{R0-R11}\n"
		// R0 = PBuf
		// R1 = Start
		// R2 = Size
		// R3 = GPIOA_IDR (Для чтения F2)
		"MOVW	R3, #0x0010\n"
		"MOVT	R3, #0x4002\n"
		// R4 = GPIOA_BSRR (Для управления R/W)
		"MOVW	R4, #0x0018\n"
		"MOVT	R4, #0x4002\n"
		// R5 = GPIOE_ODR (Для вывода адреса)
		"MOVW	R5, #0x1014\n"
		"MOVT	R5, #0x4002\n"
		// R6 = GPIOD_ODR (Для вывода данных)
		"MOVW	R6, #0x0C14\n"
		"MOVT	R6, #0x4002\n"
		// R7 = Маска $0000FFFF
		"MOVW	R7, 0xFFFF\n"
		"MOVT	R7, 0x0000\n"
		// R8 = Маска $00020000
		"MOVW	R8, 0x0000\n"
		"MOVT	R8, 0x0002\n"
		// R9 = Маска $00000002
		"MOVW	R9, 0x0002\n"
		"MOVT	R9, 0x0000\n"
		// R10 - данные записи
		"LDRB	R10, [R0, #0]\n"
		"AND	R10, R10, 0x00FF\n"
		// Выделим
		"AND	R1, R1, R7, LSL #0\n"
		"AND	R2, R2, R7, LSL #0\n"
		"CPSID	f\n"
		// Синхронизируемся
		"Write_PRG_Syn0:\n"
		"LDR	R11, [R3, #0]\n"
		"ANDS	R11, R11, #1\n"
		"IT		EQ\n"
		"BEQ	Write_PRG_Syn0\n"
		"Write_PRG_Syn1:\n"
		"LDR	R11, [R3, #0]\n"
		"ANDS	R11, R11, #1\n"
		"IT		NE\n"
		"BNE	Write_PRG_Syn1\n"
		// Выставляем запись
		"STR	R8, [R4, #0]\n"
		// Цикл записи
		"Write_PRG_Loop:\n"
		// Выставляем адрес
		"STR	R1, [R5, #0]\n"
		// Выставляем данные
		"STR	R10, [R6, #0]\n"
		// Ждем F2 = 1
		"Write_PRG_LWt0:\n"
		"LDR	R11, [R3, #0]\n"
		"ANDS	R11, R11, #1\n"
		"IT		EQ\n"
		"BEQ	Write_PRG_LWt0\n"
		// Увеличиваем адрес записи
		"ADD	R1, R1, #1\n"
		// Считываем новые данные
		"ADD	R0, R0, #1\n"
		"LDRB	R10, [R0, #0]\n"
		"AND	R10, R10, 0x00FF\n"
		// Ждем F2 = 0
		"Write_PRG_LWt1:\n"
		"LDR	R11, [R3, #0]\n"
		"ANDS	R11, R11, #1\n"
		"IT		NE\n"
		"BNE	Write_PRG_LWt1\n"
		// Счетчик байт
		"SUB	R2, R2, #1\n"
		"ANDS	R2, R2, R7, LSL #0\n"
		"IT		NE\n"
		"BNE	Write_PRG_Loop\n"
		// Убираем запись
		"STR	R9, [R4, #0]\n"
		"CPSIE	f\n"
		// Обнулим адрес
		"MOVW	R7, 0x0000\n"
		"STR	R7, [R5, #0]\n"
		"POP	{R0-R11}\n"
		"BX		LR\n"
	);
}

// Запись данных из буфера в картридж
void Dendy_Write( uint8_t *PBuf, uint32_t Start, uint32_t Size )
{	// Переменные
	uint32_t			Delay;
	GPIO_InitTypeDef	GPIO_InStr;
	// Начальные установки
	PRG_RnW_Rd(); CHR_Out(); PRG_Out(); GPIOC->ODR &= 0xFF00;
	GPIO_InStr.GPIO_Pin = 0xFFFF;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOD, &GPIO_InStr );
	CHR_BUS_On(); PRG_BUS_On();
	// Это PRG или CHR?
	if ((Start & 0x00FF0000) == 0)
	{
		Write_PRG( PBuf, Start, Size );
	}
	else
	{	// Маски адресов и размеров
		Start &= 0x00003FFF; Size &= 0x00003FFF;
		while ((Size & 0x00003FFF) != 0)
		{	// Выставляем адрес и данные
			GPIOE->ODR = Start & 0x0000FFFF; GPIOD->ODR = (GPIOD->ODR & 0x00FF) | (*(PBuf) * 0x100);
			// Активируем строб записи CHR
			CHR_PWR_On();
			// Ждем
			Delay = 3; while (Delay) { Delay -= 1; }
			// Деактивируем чтение
			CHR_PWR_Off();
			// Счетчики
			PBuf += 1; Start += 1; Size -= 1;
		}
	}
	// Начальное состояние
	GPIO_InStr.GPIO_Pin = 0xFFFF;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOD, &GPIO_InStr );
	CHR_BUS_Off(); PRG_BUS_Off(); CHR_In(); PRG_In();
}

// Чтение данных в буфер из картриджа в ручном режиме
void Dendy_ManualRead( uint8_t *PBuf, uint32_t Start, uint32_t Size )
{	// Переменные
	uint32_t			Delay;
	GPIO_InitTypeDef	GPIO_InStr;
	// Начальные установки
	PRG_F2_Off(); PRG_RnW_Rd(); CHR_In(); PRG_In(); GPIOC->ODR &= 0xFF00;
	GPIO_InStr.GPIO_Pin = 0xFFFF;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOD, &GPIO_InStr );
	CHR_BUS_On(); PRG_BUS_On();
	// Маски адресов и размеров
	Start &= 0x0000FFFF; Size &= 0x0000FFFF;
	while ((Size & 0x0000FFFF) != 0)
	{	// Выставляем адрес
		GPIOE->ODR = Start & 0x0000FFFF;
		// Активируем строб чтения CHR
		PRG_F2_On();
		// Ждем
		Delay = 3; while (Delay) { Delay -= 1; }
		// Забираем данные и отключаем строб
		*(PBuf) = GPIOD->IDR & 0x00FF;
		// Деактивируем чтение
		PRG_F2_Off();
		// Счетчики
		PBuf += 1; Start += 1; Size -= 1;
	}
	// Начальное состояние
	PRG_F2_Off(); CHR_BUS_Off(); PRG_BUS_Off();
}

// Запись данных из буфера в картридж в ручном режиме
void Dendy_ManualWrite( uint8_t *PBuf, uint32_t Start, uint32_t Size )
{	// Переменные
	uint32_t			Delay;
	GPIO_InitTypeDef	GPIO_InStr;
	// Начальные установки
	PRG_F2_Off(); PRG_RnW_Wr(); CHR_Out(); PRG_Out(); GPIOC->ODR &= 0xFF00;
	GPIO_InStr.GPIO_Pin = 0xFFFF;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOD, &GPIO_InStr );
	CHR_BUS_On(); PRG_BUS_On();
	// Маски адресов и размеров
	Start &= 0x0000FFFF; Size &= 0x0000FFFF;
	while ((Size & 0x0000FFFF) != 0)
	{	// Выставляем адрес и данные
		GPIOE->ODR = Start & 0x0000FFFF; GPIOD->ODR = (GPIOD->ODR & 0xFF00) | *(PBuf);
		// Активируем строб чтения CHR
		PRG_F2_On();
		// Ждем
		Delay = 3; while (Delay) { Delay -= 1; }
		// Деактивируем чтение
		PRG_F2_Off();
		// Счетчики
		PBuf += 1; Start += 1; Size -= 1;
	}
	// Начальное состояние
	PRG_F2_Off(); PRG_RnW_Rd();
	GPIO_InStr.GPIO_Pin = 0xFFFF;
	GPIO_InStr.GPIO_Mode = GPIO_Mode_IN;
	GPIO_InStr.GPIO_Speed = GPIO_High_Speed;
	GPIO_InStr.GPIO_OType = GPIO_OType_PP;
	GPIO_InStr.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init( GPIOD, &GPIO_InStr );
	CHR_BUS_Off(); PRG_BUS_Off(); CHR_In(); PRG_In();
}
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 22 апреля 2026 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.
/!\ Обновлений для STM32PowerMon и STM32PowerMon-UCPD временно не будет.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: stm32 USB host

Сообщение jcxz »

[uquote="HardWareMan",url="/forum/viewtopic.php?p=4657762#p4657762"]А мужики то не в курсе! Вот пример моего говнокодинга на асме под Eclipse для ARM EABI:

Код: Выделить всё

...
		"IT		EQ\n"
		"BEQ	Read_PRG_Syn0\n"
...
		"IT		NE\n"
		"BNE	Read_PRG_Syn1\n"
...
		"IT		EQ\n"
		"BEQ	Read_PRG_LWt0\n"
...
[/uquote]Ваш код полон таких пар. А какой смысл в них? Зачем??? :dont_know:

PS: Код конечно..... ээээ... :facepalm: как будто главная цель была - сделать как можно более громоздко и медленно. :)))

Добавлено after 1 hour 14 minutes 22 seconds:
[uquote="HardWareMan",url="/forum/viewtopic.php?p=4657762#p4657762"]А мужики то не в курсе! Вот пример моего говнокодинга на асме под Eclipse для ARM EABI:
Спойлер

Код: Выделить всё

// Запись данных буфера в PRG
__attribute__ ((naked)) void Write_PRG( uint8_t *PBuf, uint32_t Start, uint32_t Size )
{	// Начинаем
	__asm volatile
	(	"PUSH	{R0-R11}\n"
		// R0 = PBuf
		// R1 = Start
		// R2 = Size
		// R3 = GPIOA_IDR (Для чтения F2)
		"MOVW	R3, #0x0010\n"
		"MOVT	R3, #0x4002\n"
		// R4 = GPIOA_BSRR (Для управления R/W)
		"MOVW	R4, #0x0018\n"
		"MOVT	R4, #0x4002\n"
		// R5 = GPIOE_ODR (Для вывода адреса)
		"MOVW	R5, #0x1014\n"
		"MOVT	R5, #0x4002\n"
		// R6 = GPIOD_ODR (Для вывода данных)
		"MOVW	R6, #0x0C14\n"
		"MOVT	R6, #0x4002\n"
		// R7 = Маска $0000FFFF
		"MOVW	R7, 0xFFFF\n"
		"MOVT	R7, 0x0000\n"
		// R8 = Маска $00020000
		"MOVW	R8, 0x0000\n"
		"MOVT	R8, 0x0002\n"
		// R9 = Маска $00000002
		"MOVW	R9, 0x0002\n"
		"MOVT	R9, 0x0000\n"
		// R10 - данные записи
		"LDRB	R10, [R0, #0]\n"
		"AND	R10, R10, 0x00FF\n"
		// Выделим
		"AND	R1, R1, R7, LSL #0\n"
		"AND	R2, R2, R7, LSL #0\n"
		"CPSID	f\n"
		// Синхронизируемся
		"Write_PRG_Syn0:\n"
		"LDR	R11, [R3, #0]\n"
		"ANDS	R11, R11, #1\n"
		"IT		EQ\n"
		"BEQ	Write_PRG_Syn0\n"
		"Write_PRG_Syn1:\n"
		"LDR	R11, [R3, #0]\n"
		"ANDS	R11, R11, #1\n"
		"IT		NE\n"
		"BNE	Write_PRG_Syn1\n"
		// Выставляем запись
		"STR	R8, [R4, #0]\n"
		// Цикл записи
		"Write_PRG_Loop:\n"
		// Выставляем адрес
		"STR	R1, [R5, #0]\n"
		// Выставляем данные
		"STR	R10, [R6, #0]\n"
		// Ждем F2 = 1
		"Write_PRG_LWt0:\n"
		"LDR	R11, [R3, #0]\n"
		"ANDS	R11, R11, #1\n"
		"IT		EQ\n"
		"BEQ	Write_PRG_LWt0\n"
		// Увеличиваем адрес записи
		"ADD	R1, R1, #1\n"
		// Считываем новые данные
		"ADD	R0, R0, #1\n"
		"LDRB	R10, [R0, #0]\n"
		"AND	R10, R10, 0x00FF\n"
		// Ждем F2 = 0
		"Write_PRG_LWt1:\n"
		"LDR	R11, [R3, #0]\n"
		"ANDS	R11, R11, #1\n"
		"IT		NE\n"
		"BNE	Write_PRG_LWt1\n"
		// Счетчик байт
		"SUB	R2, R2, #1\n"
		"ANDS	R2, R2, R7, LSL #0\n"
		"IT		NE\n"
		"BNE	Write_PRG_Loop\n"
		// Убираем запись
		"STR	R9, [R4, #0]\n"
		"CPSIE	f\n"
		// Обнулим адрес
		"MOVW	R7, 0x0000\n"
		"STR	R7, [R5, #0]\n"
		"POP	{R0-R11}\n"
		"BX		LR\n"
	);
}
[/uquote]Если чуток причесать Write_PRG() и перенести её в asm-файл, то получим:
Спойлер

Код: Выделить всё

               SECTION  .text:CODE:NOROOT(2)
               THUMB

IO_GPIOA       EQU    0x40020000
IO_GPIOA_IDR   EQU    0x40020010
IO_GPIOA_BSRR  EQU    0x40020018
IO_GPIOD_ODR   EQU    0x40020C14
IO_GPIOE_ODR   EQU    0x40021014
Write_PRG_2:   PUSH   {R4}
               ;R0 = PBuf
               ;R1 = Start
               ;R2 = Size
               ;R3 = GPIOA_IDR (Для чтения F2)
               LDR    R3, =IO_GPIOA
               ;Выделим
               UXTH   R1, R1
               SUBS   R2, R2, #1
               UXTH   R2, R2
               CPSID  f
               ;Синхронизируемся
p2_Syn0:       LDR    R4, [R3, #IO_GPIOA_IDR - IO_GPIOA]
               LSLS   R4, R4, #31
               BPL    p2_Syn0  ;;;
p2_Syn1:       LDR    R4, [R3, #IO_GPIOA_IDR - IO_GPIOA]
               LSLS   R4, R4, #31
               BMI    p2_Syn1
               ;Выставляем запись
               MOVS   R4, #0x00020000
               STR    R4, [R3, #IO_GPIOA_BSRR - IO_GPIOA]
               ;Цикл записи
p2_Loop:       ;Выставляем адрес
               LDR    R4, =IO_GPIOE_ODR
               STR    R1, [R4]
               ;Выставляем данные
               LDRB   R4, [R0], #1
               STR    R4, [R3, #IO_GPIOD_ODR - IO_GPIOA]
               ;Ждем F2 = 1
p2_LWt0:       LDR    R4, [R3, #IO_GPIOA_IDR - IO_GPIOA]
               LSLS   R4, R4, #31
               BPL    p2_LWt0
               ;Увеличиваем адрес записи
               ADDS   R1, R1, #1
               ;Ждем F2 = 0
p2_LWt1:       LDR    R4, [R3, #IO_GPIOA_IDR - IO_GPIOA]
               LSLS   R4, R4, #31
               BMI    p2_LWt1
               ;Счетчик байт
               SUBS   R2, R2, #1
               BPL    p2_Loop
               ;Убираем запись
               MOVS   R2, #2
               STR    R2, [R3, #IO_GPIOA_BSRR - IO_GPIOA]
               CPSIE  f
               ;Обнулим адрес
               LDR    R2, =IO_GPIOE_ODR
               STR    R4, [R2]
               POP    {R4}
               BX     LR
Итого: размер = 84 байта; вместо исходных 180 байт. Да и быстрее должна быть.
8)
Аватара пользователя
HardWareMan
Мучитель микросхем
Сообщения: 429
Зарегистрирован: Ср сен 02, 2015 07:47:20

Re: stm32 USB host

Сообщение HardWareMan »

jcxz, именно поэтому это и говнокод, была такая проба пера лет 10+ назад. Смысл послания был в том, что асм РУКИ не только никто не запрещает использовать, но и позволяется оформить __NAKED__ процедуры на, собсно, "голом" асме, если вы знаете т.н. "соглашение о вызове" для своего языка программирования.

Добавлено after 2 minutes 22 seconds:
[uquote="jcxz",url="/forum/viewtopic.php?p=4657880#p4657880"][uquote="HardWareMan",url="/forum/viewtopic.php?p=4657762#p4657762"]А мужики то не в курсе! Вот пример моего говнокодинга на асме под Eclipse для ARM EABI:

Код: Выделить всё

...
		"IT		EQ\n"
		"BEQ	Read_PRG_Syn0\n"
...
		"IT		NE\n"
		"BNE	Read_PRG_Syn1\n"
...
		"IT		EQ\n"
		"BEQ	Read_PRG_LWt0\n"
...
[/uquote]Ваш код полон таких пар. А какой смысл в них? Зачем??? :dont_know:[/uquote]
Профдеформация после MCS80, MCS96 и т.д.
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 22 апреля 2026 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.
/!\ Обновлений для STM32PowerMon и STM32PowerMon-UCPD временно не будет.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: stm32 USB host

Сообщение jcxz »

[uquote="HardWareMan",url="/forum/viewtopic.php?p=4657946#p4657946"]если вы знаете т.н. "соглашение о вызове" для своего языка программирования.[/uquote]Именно поэтому PUSH/POP-ить регистры R0...R3 на входе/выходе функции не нужно. :)
danone78
Встал на лапы
Сообщения: 82
Зарегистрирован: Вт фев 15, 2022 21:28:35

Re: stm32 USB host

Сообщение danone78 »

ну да, при входе в прерывания r0-r3 залетают в стек автоматом, такова архитектура ядра. С вложенными прерываниями я пока не разбирался.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: stm32 USB host

Сообщение jcxz »

[uquote="danone78",url="/forum/viewtopic.php?p=4658150#p4658150"]ну да, при входе в прерывания r0-r3 залетают в стек автоматом, такова архитектура ядра. С вложенными прерываниями я пока не разбирался.[/uquote]Причём тут прерывания? Речь шла о функции. Читайте что такое "соглашения вызова функций". Чтобы понимать о чём идёт речь.
danone78
Встал на лапы
Сообщения: 82
Зарегистрирован: Вт фев 15, 2022 21:28:35

Re: stm32 USB host

Сообщение danone78 »

Ладно давайте вернемся к USB. Мышь работает не очень хорошо, то halt то nack ответит, через пень колоду короче. Запросы отправляю в начале кадра и только по одному запросу. Че за фигня, кто останавливает канал?
Аватара пользователя
HardWareMan
Мучитель микросхем
Сообщения: 429
Зарегистрирован: Ср сен 02, 2015 07:47:20

Re: stm32 USB host

Сообщение HardWareMan »

[uquote="danone78",url="/forum/viewtopic.php?p=4658369#p4658369"]Ладно давайте вернемся к USB. Мышь работает не очень хорошо, то halt то nack ответит, через пень колоду короче. Запросы отправляю в начале кадра и только по одному запросу. Че за фигня, кто останавливает канал?[/uquote]
А что за мышка? У меня есть аппаратный USB сниффер, я бы мог записать нормальный обмен как эталон, например. Для примеру записал обмен от беспроводной мышки, файл лога в аттаче. Софт для просмотра можно взять на сайте производителя, он с файлами логов работает и без самого устройства, есть ангельский язык, программа работает без установки. Брал его, кстати, как раз для отладки таких случаев, при реализации USB хоста на STM.
Вложения
Снимок.PNG
Скриншот
(241.6 КБ) 67 скачиваний
WirelessMouse.zip
Wireless Mouse attach log
(42.13 КБ) 64 скачивания
Репозиторий STM32: https://cloud.mail.ru/public/2i19/Y4w8kKEiZ
Актуальность репозитория: 22 апреля 2026 года
Если чего-то не хватает с сайта st.com - пишите, докачаю.
/!\ Обновлений для STM32PowerMon и STM32PowerMon-UCPD временно не будет.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: stm32 USB host

Сообщение COKPOWEHEU »

[uquote="jcxz",url="/forum/viewtopic.php?p=4654832#p4654832"]ваял USB-device в STM32Lxxx. Не Кубом, а самостоятельно. И особенных проблем не встретил. Почти всё работало нормально. Единственный косяк, на который наткнулся - неполная поддержка изохронного режима.[/uquote]
Ну да. Не считая наркоманский EPnR, у которых часть битов read-only, часть read-write, часть можно только стереть, причем нулем, а часть инвертировать, причем единицей.
А что за проблема с изохронными точками? У меня аудио-девайс (микрофон + динамик) вполне запустился.
danone78 писал(а):У меня уже все работает, но вся эта возня с дескрипторами мне кажется не обязательна.
Если я подключаю USB устройство и знаю что это мышь
Так а хосту-то об этом откуда узнать? Как узнать сколько кнопок, какое абсолютное смещение соответствует передаваемым данным?
danone78
Встал на лапы
Сообщения: 82
Зарегистрирован: Вт фев 15, 2022 21:28:35

Re: stm32 USB host

Сообщение danone78 »

Пробовал на двух мышках, одна Genius вторая Zornwee, одинаково. Разобрался что надо PID чередовать, вот только черный нечетный кадр пробовал менять и разницы не увидел. Получается что раз в милисеунду обязательно на SOF прерывание залетать? И.. я не понял где кнопки? Смещения координат я получаю, а кнопки то куда? Жму кнопку, прилетает пакет с нулями.

Добавлено after 6 minutes 57 seconds:
К стати давно хотел спросить, какая разница между периодическими и непериодическими запросами?

Добавлено after 9 minutes 41 second:
Единственное отличие в работе мышек, в том что Zornwee переподключается если ей после остановки канала ничего не послать, а Genius нет, просто молчит.

Добавлено after 22 minutes 59 seconds:
Простите я наврал, кнопки прилетают.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: stm32 USB host

Сообщение jcxz »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4658459#p4658459"]Ну да. Не считая наркоманский EPnR, у которых часть битов read-only, часть read-write, часть можно только стереть, причем нулем, а часть инвертировать, причем единицей.[/uquote]Если все биты описаны в мануале, то нормально.

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4658459#p4658459"]А что за проблема с изохронными точками? У меня аудио-девайс (микрофон + динамик) вполне запустился.[/uquote]Значит у вас размер точек был маленький.

Проблема в том, что размер USB-памяти сильно ограничен. А так как в этой памяти нужно разместить дескрипторы всех точек, а также разместить память для ep0 и по 2 буфера под каждую изохронную точку, то получается, что максимальный размер изохронной точки может быть немного больше 230 байт (если всего одна точка активна).

Для USB-FS размер изохронных точек может быть - до 1023 байт. А значит - и максимальная скорость изохронной передачи ограничена - менее 1/4 от максимально возможной для USB-FS.
Получается - STM32L не соответствует даже требованиям USB-FS. Или не полностью соответствует.
Ответить

Вернуться в «ARM»