STM32 и USB (практика)

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

Z_h_e писал(а):Только надо помнить, что там же таблица адресов.
А можете немного рассказать про таблицу адресов, что это вообще?
Как я понимаю, там хранятся адреса, которые мы задаем для начала и размера контрольных точек. Если это так, то размер таблицы для одной контрольной точки строго фиксированный, и общей размер таблицы будет зависеть только от количества использованных контрольных точек?
Z_h_e писал(а):Ну можно ж ее в конце памяти разместить, а буфера тогда можно с самого начала
А какой в этом практический смысл?
Z_h_e писал(а):или несколько таблиц иметь и переключать их.
А это для чего?
Z_h_e писал(а):Представьте что у Вас биты STAT_TX[1:0] установлены в 10 (NACK). А Вам надо установить в состояние 11 (VALID) . Тогда такая конструкция EP|= STAT_TX1 | STAT_TX0 не прокатит.
Если я правильно помню, то это биты типа переключателя. Тогда (если я еще и правильно понимаю :) ) для изменения битов с 10 в 11 нужно вставить строку EP|= STAT_TX0; (значение нулевого бита должно инвертироваться).
Z_h_e писал(а):Дык маски ж прерываний
Вопрос снимается :) . Я почему-то думал, что помимо битов масок (типа CTRM) есть еще и биты включения прерываний (типа CTR), но оказалось, что биты типа CTR есть только в регистре с флагами :)
За расписанные прерывания с комментариями отдельное Спасибо, поправил кое-что у себя в голове :) .
Реклама
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

isx писал(а):А какой в этом практический смысл?
isx писал(а):А это для чего?
Может для каких-то сложных USB устройств. :dont_know: Мне это не надо и я ж написал можно, а не нужно.
А можете немного рассказать про таблицу адресов, что это вообще?
Могу. Как видите я настраиваю только буфер для конечной точки 0. В RM0008 Reference manual таблица расписана в абзаце "Structure and usage of packet buffers" раздела 23.4.2 System and power-on reset, стр. 617.

Говорите МКру, что пора бы уже что-нибудь принять (STAT_RX[1:0] VALID ). Приходящий пакет (OUT) мк положит в буфер по адресу ADRnRX для соответствующей точки и автоматом переведется в NACK, если Вы конечно достаточно памяти выделили , указывается в старших битах COUNTnRX, а младших будет реальный размер полученных данных.

Пакет исходящий на хост (IN): Кладете данные по адресу ADRnTX,в COUNTnTX указываете сколько положили, переводите NACK в VALID STAT_TX[1:0] и все, когда хост из запросит, МК сам отправит и сам же переведет обратно в NACK.

Я еще функцию написал для переключения битов DTOG регистра конечной точки, но оказалось лишнее. МК сам его переключает как надо.
isx писал(а):с 10 в 11 нужно вставить строку EP|= STAT_TX0;
Можно. Если знаете что у Вас регистр в состоянии NACK. Я сначала хотел использовать атомарный доступ, вроде так проще, но одновременно так все биты не изменишь же. И не знал, что МК в состояние nack сам переходит, так что можно и по одному биту менять было.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

Блиин.. Чет все-равно ниче не понятно :solder: . Попробую пойти по порядку.
Вот, к примеру, Начинаем мы работать с адресами. Определяем, что будет у нас 3 конечные точки - 0, 1 и 2. Все три точки будут типа Control, нулевая будет системная, 1-я на исходящие от МК данные, 2-я на входящие (или можно нулевую тоже использовать в обычном режиме после отправки дескрипторов?)
Отправлять и принимать данные мы планируем по 64 байта.
Теперь необходимо настроить BTABLE. Допустим, мы оставили начальный адрес по умолчанию - 0x40006000 (адрес начала буфера в памяти), т.е. BTABLE = 0.
Далее нужно определить начальный адрес исходящих данных для нулевой конечной точки - USB_ADDR0_TX. Поскольку у нас таблица расположена в начале памяти, значит и начальный адрес равен нулю. Далее, бегу по даташиту:
Спойлер

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

Transmission buffer address n (USB_ADDRn_TX)
Address offset: [USB_BTABLE] + n*16

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

Transmission byte count n (USB_COUNTn_TX)
Address offset: [USB_BTABLE] + n*16 + 4

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

Reception buffer address n (USB_ADDRn_RX)
Address offset: [USB_BTABLE] + n*16 + 8

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

Reception byte count n (USB_COUNTn_RX)
Address offset: [USB_BTABLE] + n*16 + 12
Итого получается, что выделенная для нулевой конечной точки память будет занимать пространство от 0x40006000 до 0x40006012. Тогда USB_ADDR0_TX занимает пространство в памяти от 0x40006000 до 0x40006003. Если я правильно понимаю, то по каждому конкретному адресу (например 0x40006000) содержится 16 бит информации. Тогда напрашивается вопрос: регистр USB_ADDR0_TX содержит 16 бит информации, зачем под него выделено 64 бита?
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

isx писал(а):Теперь необходимо настроить BTABLE. Допустим, мы оставили начальный адрес по умолчанию - 0x40006000 (адрес начала буфера в памяти), т.е. BTABLE = 0.
По-моему Вы крайне невнимательно прочитали про буфер, в том числе что я несколько раз писал. Перечитайте весь пост. Да и название регистра BTABLE разве Вам ни о чем не говорит? Это адрес таблицы в которой лежат адреса буферов, я же писал об этом несколько раз и указал страницу даже референса.
isx писал(а):Далее нужно определить начальный адрес исходящих данных для нулевой конечной точки - USB_ADDR0_TX.Поскольку у нас таблица расположена в начале памяти, значит и начальный адрес равен нулю
Сами подумайте что написали. Поскольку таблица адресов там лежит, будем затирать ее данными для отправки.
isx писал(а):Определяем, что будет у нас 3 конечные точки - 0, 1 и 2. Все три точки будут типа Control, нулевая будет системная, 1-я на исходящие от МК данные, 2-я на входящие (или можно нулевую тоже использовать в обычном режиме после отправки дескрипторов?)
Я же писал и коды выкладывал. Я работаю только с 0 конечной точкой. Хотя я тоже изначально приблизительно так и хотел сделать, только точки 1 и 2 типа interupt. Собственно сделал, но с одной точкой проще. Любая точка может работать на прием и передачу одновременно. Я не уверен, что точек типа контрол может быть больше чем одна. Для нулевой можно использовать репорты типа Future.
isx писал(а):то по каждому конкретному адресу (например 0x40006000) содержится 16 бит информации
Не 16, а 8. Если Вы пишите в память 32 х разрядные слова, Вы же шагаете адрес +4. Адресация побайтовая у ARM.
ИзображениеРисуйте дамп буферной памяти USB снизу вверх, каждая ячейка - слово по 4 байта. Закрасьте 2 и 3 байты слова, они недоступны. Слева каждой ячейке-слову пишите адреса по-порядку 0x40006000, 0x40006004, 0x40006008... и так до 0x4000 63FC :tea: . Так видит эту память ядро, это логично, адресное пространство едино. Справа пишите адреса 0x000,0x002,0x004...0x1FE :sleep: . Так видит эту память периферия USB.

Картинку можете выложить сюдой, может кому пригодится, если начертите конечно. Да, все-таки откройте ту 617 страницу. Там есть картинка про буфер USB и как в ней лежит таблица.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

:kill:
Голова кипит уже, а я даже до дескрипторов не добрался :facepalm:
Посты перечитал уже раз 20, только вот толкование получается двоякое...
Прикладываю таблицу из даташита (STM32F30X):
Изображение
Получается. если ставим BTABLE = 0, то локальный адрес таблицы начинается с 0, а глобальный с 0x40006000. Далее, если используем только одну - нулевую контрольную точку, то таблица будет занимать пространство от 0x00 до 0x06 (см. таблицу). Дальше (с 0x07) располагаем USB_ADDR0_TX, который имеет размер, указанный в USB_COUNTn_TX (к примеру 32 байта) и ,соответственно, данный буфер будет занимать память от 0x07 до 0x39. За ним идет (с 0x40) USB_ADDR0_RX, который имеет размер, указанный в USB_COUNTn_RX (к примеру тоже 32 байта), соответственно, данный буфер будет занимать память от 0x40 до 0x72.
Теперь я правильно понимаю?
Z_h_e писал(а):Не 16, а 8. Адресация побайтовая у ARM.
Не знал. Теперь стало понятнее. Спасибо :)
И еще один вопрос возник из:
Z_h_e писал(а):Закрасьте 2 и 3 байты слова, они недоступны.
Регистр USB_COUNTn_TX:
Изображение
Видим, что используются все 32 бита. Но как с ним работать, если 2 и 3 байты не доступны?

P.S. Большое спасибо за терпение. Я просто раньше так к близко к железу не копал никогда, а гуманитарное образование здесь помочь ни чем не может... Не знаю как бы без Вас разбирался в этих дебрях :) .
Реклама
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

isx писал(а):Дальше (с 0x07) располагаем USB_ADDR0_TX
С 0x08. Начертите дамп буфера что я предложил, будет понятнее.
который имеет размер, указанный в USB_COUNTn_TX
В этом регистре не надо указывать полную длину буфера. В него указывается количество данных для отправки на хост. Хотите отправить один байт, указываете USB_COUNTn_TX=1, 64 значит USB_COUNTn_TX=64. Да я ж писал про них, вчера вроде.
isx писал(а): указанный в USB_COUNTn_RX (к примеру тоже 32 байта)
И про него писал, размер указывается в страшных старших битах, в младших МК сам установит значение, по факту принятых данных.
isx писал(а):Регистр USB_COUNTn_TX:
Я не вижу что на картинке, а документа этого у меня нет. Я с другим МК работаю. Приложите нормального размера и спрячьте под споллейр.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

А, все увидел про что Вы. Это для двойной буферизации, два регистра спариваются в один. Над ним же буржуйским по белому написано. Это для изохроной передачи, я даже не пробовал туда читать :).
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

Z_h_e писал(а):С 0x08
Точно... Невнимательно посмотрел.
Z_h_e писал(а):В этом регистре не надо указывать полную длину буфера. В него указывается количество данных для отправки на хост.
Я имел ввиду буфер для передаваемых данных. Надо было понятнее написать, виноват :) .
Z_h_e писал(а):размер указывается в страшных старших битах
То есть устанавливается только один, самый старший бит регистра (если передавать будем максимум по 2 байта - то бит 1, если по 32 байта - то бит 5)?
Рисуйте дамп буферной памяти USB
Таблица по такому типу?
Изображение
Z_h_e писал(а):Это для двойной буферизации, два регистра спариваются в один. Над ним же буржуйским по белому написано.
Это понятно. Не понятно что это значит - "два регистра спариваются в один" :dont_know: . Ну, впрочем до этого дело еще дойдет :)) .
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

isx писал(а):Точно... Невнимательно посмотрел.
Кстати Вы число 7 и не смогли бы записать туда, получилось бы 6. Младший бит не доступен, выравнивание по 2 байта. Я только не понимаю зачем Вы так рветесь расположить буфер по адресу 8. Оставьте место для всей таблицы, пускай будет незаполненной, зато потом если ее добавлять ничего остального двигать не надо будет.
isx писал(а):То есть устанавливается только один, самый старший бит регистра (если передавать будем максимум по 2 байта - то бит 1, если по 32 байта - то бит 5)?
USB_COUNTn_RX для приема, а не для передачи. Мне не трудно помочь, но Вы все-таки почитайте про этот регистр в референсе и то что я уже написал. А то все одно и тоже повторяю. Там 6 старших бит задают размер области приема, и целая таблица есть Table 177. Definition ofallocated buffer memory.
isx писал(а):Таблица по такому типу?
Ну как то так. Только компактнее все 4 байта в одну строчку нарисовать, но это дело вкуса. Ну и справа такой разрядности адреса не требуется, 512 байт же всего.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

Z_h_e писал(а):Я только не понимаю зачем Вы так рветесь расположить буфер по адресу 8.
Не знаю. Возможно сказывается привычка все минимизировать :) .
Z_h_e писал(а):USB_COUNTn_RX для приема, а не для передачи.
Прочитал еще несколько раз, вроде разобрался немного.

Раз уж мы затронули адресацию, то прошу помочь еще вот с чем. Нужно правильно прописать мои данные в регистр USB_COUNT0_TX в IDE на Си. Таблица начинается с 0х40006000, значит USB_COUNT0_TX находится в диапазоне 0х40006004 - 0х40006007. Правильная ли будет запись:

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

Count0TXAdr = 0х40006004;
*Count0TXAdr=0x0020;
P.S. Повторюсь, с адресами памяти не работал ранее и приходится изучать все на лету, поэтому не пинайте сильно... :)
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

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

uint32_t *Count0TXAdr = 0х40006004;
         *Count0TXAdr=0x0020;
Только это как-то ненаглядно. Возвращаю Вас на первую страницу созданного Вами же топика.
Вот тут под споллером объявлена структура. А здесь пример ее использования, тоже под споллером.

Вы меня по Си сильно то не спрашивайте, сам его только с осени прошлой использую.

Вот еще, http://radiokot.ru/forum/viewtopic.php? ... 0#p2541335, может пригодится.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

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

void USB_LP_IRQHandler(void)
{

if (USB->ISTR & USB_ISTR_RESET)
{
	
  USB->ISTR &= ~USB_ISTR_RESET; // сбрасываем флаг прерывания по Reset
  USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_CTRM;

	uint32_t *BTableOffset = 0x00000000; // указываем значение BTABLE
	
	uint32_t *ADR0TXAdr=0x40006000;           
	         *ADR0TXAdr=0x0008;               // начальный адрес USB_ADDRn_TX
	uint32_t *Count0TXAdr=0x40006004;
	         *Count0TXAdr=0x0028;             // размер исходящих данных - 32 байта
	uint32_t *ADR0RXAdr=0x40006008;           
	         *ADR0RXAdr=0x0028;               // начальный адрес USB_ADDRn_RX
	uint32_t *Count0RXAdr=0x4000600C;
	         *Count0RXAdr=0b0100000000000000; // 32 байта входящих данных

  USB->BTABLE = BTableOffset; // таблица начинается с 0x0000
	
  USB->EP0R	|= USB_EP_CONTROL; // режим - CONTROL
	USB->EP0R	|= USB_EP_TX_VALID; // не совсем понятно. Разрешаем передачу данных
  USB->EP0R	|= USB_EP_RX_VALID; // не совсем понятно. Разрешаем прием данных

..............

}
	
}
Правильно?
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

Нашел ошибку, поправил:

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

 *Count0TXAdr=0x0020;             // размер исходящих данных - 32 байта
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

Поправил работу с адресами. И еще такой вопрос: Когда я записываю данные по адресу в память они записываются нормально, но в соседних ячейках записана тоже какая-то фигня. Может нужно как-то стирать участок памяти перед использованием, или и так нормально работать будет?
Вот что в итоге получилось:
Спойлер

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

void MyUSBinit(void)
{
	
/*Тактируем ядро*/	
	//RCC->CR |= RCC_CR_HSION; //Включить генератор HSI
	//RCC->CR &= ~RCC_CR_HSEON; 
	RCC->CFGR &= ~RCC_CFGR_SW; //Очистка битов выбора источника тактового сигнала
	RCC->CR |= RCC_CR_HSEON;
	
//	FLASH->ACR |= FLASH_ACR_HLFCYA; 
  FLASH->ACR |= FLASH_ACR_LATENCY_1;
  FLASH->ACR |= FLASH_ACR_PRFTBE; 
	while((FLASH->ACR & FLASH_ACR_PRFTBS)==0) {}
	
  while((RCC->CR & RCC_CR_HSERDY)==0) {} //Ожидание готовности HSE
  
	RCC->CFGR |= RCC_CFGR_PLLSRC; //Источником сигнала для PLL выбран HSE (внешний - кварц на 8 МГц)
  RCC->CR &= ~RCC_CR_PLLON; //Отключить генератор PLL
  RCC->CFGR &= ~RCC_CFGR_PLLMUL; //Очистить PLLMULL
  RCC->CFGR |= RCC_CFGR_PLLMUL_0 | RCC_CFGR_PLLMUL_1 | RCC_CFGR_PLLMUL_2; //Коефициент умножения 9  (будет 72 МГЦ)
  RCC->CFGR |= RCC_CFGR_PPRE1_2;
	RCC->CR |= RCC_CR_PLLON; //Включить генератор PLL
  while((RCC->CR & RCC_CR_PLLRDY)==0) {} //Ожидание готовности PLL
	

		
 
  //Переключиться на тактирование от PLL
 	//
	RCC->CFGR |= RCC_CFGR_SW_1 ; //Выбрать источником тактового сигнала PLL
		
  while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_1) {} //Ожидание переключения на PLL
	
/*Тактируем периферию*/		
	RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOEEN; // Включаем тактирование портов А и Е
	RCC->CFGR &= ~RCC_CFGR_USBPRE; // Настраиваем частоту USB (= частота ядра / 1.5)
	RCC->APB1ENR |=	RCC_APB1ENR_USBEN; // Включаем тактирование USB от шины APB1
	RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; // Включаем тактирование SYSCFG (хз что это, но так надо :) )

      /*----------------------------------------------------------------*/
	
/*Настраиваем Порт А*/		
  GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12; // Скорость 50 МГц
	GPIOA->MODER |= GPIO_MODER_MODER11_1 | GPIO_MODER_MODER12_1; // Режим альтернативной функции (для USB)
	//GPIOA->OTYPER = 0x00000000;
	//GPIOA->PUPDR |= GPIO_PUPDR_PUPDR12_0;
	GPIOA->AFR[1] |= 0x000EE000; // Номер и пины альтернативной фунции (у нас пины 11 и 12 для альтернативной функции номер 14 - USB)
	
/*Настраиваем Порт Е*/			
  GPIOE->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR8 | GPIO_OSPEEDER_OSPEEDR9 | GPIO_OSPEEDER_OSPEEDR10 | 
	                  GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12 | GPIO_OSPEEDER_OSPEEDR13 | 
		                GPIO_OSPEEDER_OSPEEDR14 | GPIO_OSPEEDER_OSPEEDR15; // Скорость для указанных пинов 50 МГц
	GPIOE->MODER |= GPIO_MODER_MODER8_0 | GPIO_MODER_MODER9_0 | GPIO_MODER_MODER10_0 | 
	                GPIO_MODER_MODER11_0 | GPIO_MODER_MODER12_0 | GPIO_MODER_MODER13_0 | 
	                GPIO_MODER_MODER14_0 | GPIO_MODER_MODER15_0; // Указанные пины на выход
	//GPIOE->OTYPER = 0x00000000;
	//GPIOE->PUPDR = 0x00000000;
	//GPIOE->AFR[1] |= 0x00000000;
	
      /*----------------------------------------------------------------*/
											
  EXTI->RTSR |= EXTI_RTSR_TR18; // внешнее прерывание №18 (USBWakeUp) по возрастающему фронту
  EXTI->IMR |= EXTI_IMR_MR18; // Включаем прерывание по пинам
  //EXTI->EMR |= EXTI_EMR_MR18; // Включаем прерывание по событию (USBWakeUp - по обнаружению устройства)
		 
      /*----------------------------------------------------------------*/
			
	NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn);
  NVIC_SetPriority(USB_LP_CAN_RX0_IRQn, 8);	
	NVIC_EnableIRQ(USBWakeUp_IRQn); //	Разрешаем глобально прерывание USBWakeUp
  //NVIC_SetPriority(USBWakeUp_IRQn, 3);	// Приоритет прерывания (не могу определится для USB)
		 
      /*----------------------------------------------------------------*/																		 
//подтяжка резистора
USB->CNTR &= ~USB_CNTR_PDWN; 
USB->CNTR |= USB_CNTR_FRES; 
USB->CNTR = 0; 	
USB->ISTR = 0;

USB->CNTR |= USB_CNTR_RESETM;

}

void USB_LP_CAN_RX0_IRQHandler(void)
{
	
uint32_t BTableOffset = 0x00000000; // указываем значение BTABLE
	
if (USB->ISTR & USB_ISTR_RESET)
{
	
  USB->ISTR &= ~USB_ISTR_RESET; // сбрасываем флаг прерывания по Reset
  USB->CNTR |= USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_CTRM;

		
	*(__IO uint32_t*)(0x40006000) = 0x0008; // начальный адрес USB_ADDR0_TX
	*(__IO uint32_t*)(0x40006004) = 0x0020; // размер исходящих данных - 32 байта USB_COUNT0TX
	*(__IO uint32_t*)(0x40006008) = 0x0028; // начальный адрес USB_ADDR0_RX
	*(__IO uint32_t*)(0x4000600C) = 0x00004000; // 32 байта входящих данных USB_ USB_COUNT0RX_


	USB->BTABLE = BTableOffset; // таблица начинается с 0x0000
	
  USB->EP0R	|= USB_EP_CONTROL; // режим - CONTROL
	USB->EP0R	|= USB_EP_TX_VALID; // не совсем понятно. Разрешаем передачу данных
  USB->EP0R	|= USB_EP_RX_VALID; // не совсем понятно. Разрешаем прием данных


  USB->DADDR |= USB_DADDR_EF; 

}
	
	
}
Я так понимаю, дальше с дескриптором работать нужно? Или я что-то упустил?

Есть спертый с какого-то сайта дескриптор(писать свой, думаю, пока не стоит):
Спойлер

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

const uint8_t Virtual_Com_Port_DeviceDescriptor[] =
{
    0x12, // размер данного дескриптора
    0x01, // тип данного дескриптора - device descriptor 
    0x00, 0x02, // 2 байта - версия usb 2.0
    0x02, // класс устройства cdc
    0x00, // подкласс
    0x00, // протокол
    USB_MAX_PACKET0, // max размер пакета для нулевой конечной точки
    0x83, 0x04, // 2 байта - VID
    0x40,   0x57,// 2 байта - PID
    0x00, 0x02,// 2 байта - версия (ревизия) устройства
    0x01, // индекс строки с названием производителя
    0x02, // индекс строки с названием устройства
    0x03, // индекс строки с серийным номером устройства
    0x01 // количество поддерживаемых конфигураций
};

// configuration descriptor
const uint8_t Virtual_Com_Port_ConfigDescriptor[] =
{
    /* ============== CONFIGURATION 1 =========== */
    /* Configuration 1 descriptor */
    0x09, // размер дескриптора конфигурации
    0x02, // тип дескриптора - configuration
    0x43, // 2 байта - полный размер дескриптора, включая др. дескрипторы 
    0x00, // (CwTotalLength 2 EP + Control)
    0x02, // количество интерфейсов (2 интерфейса для CDC - data и config)
    0x01, // номер данной конфигурации (SET_CONFIGURATION)
    0x00, // индекс строки описывающий данную конфигурацию
    0xC0, // битовое поле, характеризующее конфигурацию
        /*
        Распределение бит:
        D7 – зарезервировано (установлено в 1);
        D6 – признак наличия собственного источника питания;
        D5 – признак разрешения сообщения хосту о выходе
        устройства из режима «сна»;
        D4...D0 – зарезервированы (сброшены в 0)
        */
    0x00, // max потребляемый ток от шины (половина от реального (50 = 100мА))

        /* Communication Class Interface Descriptor Requirement */
        0x09, // длина дескриптора
        0x04, // тип дескриптора - интерфейс
        0x00, // номер данного интерфейса
        0x00, // номер альтернативной установки для интерфейса
        0x01, // количество точек для данной альтернативной установки в данном интерфейсе
        0x02, // код класса(USB-IF)
        0x02, // код подкласса(USB-IF)
        0x00, // код протокола(USB-IF)
        0x01, // индекс строки, описывающей данную альтернативную установку данного интерфейса

    /* Header Functional Descriptor */
    0x05, // bFunction Length
    0x24, // bDescriptor type: CS_INTERFACE
    0x00, // bDescriptor subtype: Header Func Desc
    0x10, // bcdCDC:1.1
    0x01,

    /*Call Management Functional Descriptor */
    0x05, /* bFunctionLength */
    0x24, /* bDescriptorType: CS_INTERFACE */
    0x01, /* bDescriptorSubtype: Call Management Func Desc */
    0x00, /* bmCapabilities: device handles call management */ //!!!!!!!!!!!!!!!!!!1
    0x01, /* bDataInterface: CDC data IF ID */

        /* ACM Functional Descriptor */
        0x04, // bFunctionLength
        0x24, // bDescriptor Type: CS_INTERFACE
        0x02, // bDescriptor Subtype: ACM Func Desc
        0x02, // bmCapabilities

    /* Union Functional Descriptor */
    0x05, // bFunctionLength
    0x24, // bDescriptorType: CS_INTERFACE
    0x06, // bDescriptor Subtype: Union Func Desc
    0x00, // bMasterInterface: Communication Class Interface
    0x01, // bSlaveInterface0: Data Class Interface

        /* Endpoint 1 descriptor */
        0x07, // размер дескриптора
        0x05, // тип дескриптора - endpoint
        0x81, // битовое поле адреса точки // IN
            /*
            D7 – направление передачи данных точкой (1 – IN, 0 – OUT);
            D6...D4 – зарезервированы (сброшены в 0);
            D3...D0 – адрес точки
            */
            0x03, // битовое поле, характеризующее точку
            /*
            D7, D6 – зарезервированы (сброшены в 0);
            D5, D4 – функция, выполняемая точкой:
            00 – точка данных;
            01 – точка обратной связи;
            10 – точка данных с неявной обратной связью;
            11 – зарезервировано
            D3, D2 – тип синхронизации хоста и точки:
            00 – без синхронизации;
            01 – асинхронный;
            10 – адаптивный;
            11 – синхронный
            D1, D0 – тип обмена данными:
            00 – контрольный;
            01 – изохронный;
            10 – bulk;
            11 – interrupt
            */

        64, // 2 байта - битовое поле  
            // характеризующее размер пакета передаваемых данных

        0x00,   /*
            D15…D13 – зарезервированы (сброшены в 0);
            D12, D11 – количество дополнительных передач:
            00 – нет дополнительных передач;
            01 – 1 дополнительная передача (всего 2 передачи),
            10 – 2 дополнительные передачи (всего 3 передачи);
            11 – зарезервировано.
            D10...D0 – размер пакета в байтах
            */
        0xFF, // интервал готовности точки к обмену данными

    /* Data Class Interface Descriptor Requirement */
    0x09, // bLength
    0x04, // bDescriptorType
    0x01, // bInterfaceNumber
    0x00, // bAlternateSetting
    0x02, // bNumEndpoints
    0x0A, // bInterfaceClass
    0x00, // bInterfaceSubclass
    0x00, // bInterfaceProtocol
    0x04, // iInterface


    /* Endpoint 2 descriptor */
    0x07, // bLength
    0x05, // bDescriptorType
    0x02, // bEndpointAddress, Endpoint 01 - OUT
    0x02, // bmAttributes BULK
    64, // wMaxPacketSize
    0x00,
    0x00, // bInterval

    /* Endpoint 3 descriptor */
    0x07, // bLength
    0x05, // bDescriptorType
    0x83, // bEndpointAddress, Endpoint 02 - IN
    0x02, // bmAttributes BULK
    64, // wMaxPacketSize
    0x00,
    0x00 // bInterval
};

/* USB String Descriptors */
const uint8_t Virtual_Com_Port_StringLangID[] =
{
    0x04, // длина дескриптора
    0x03, // тип дескриптора - string desc
    0x09, // N байт индетификатор языка
    0x04 /* LangID = 0x0409: U.S. English */
};

const uint8_t Virtual_Com_Port_StringVendor[] =
{
    10, // длина дескриптра
    0x03, // тип дескриптора - string desc
    /* имя */
    'T', 0, 
    'E', 0, 
    'S', 0, 
    'T', 0
};

const uint8_t Virtual_Com_Port_StringProduct[] =
{
    10, // длина дескриптра
    0x03, // тип дескриптора - string desc
    /* имя */
    'T', 0, 
    'E', 0, 
    'S', 0, 
    'T', 0
};

const uint8_t Virtual_Com_Port_StringSerial[] =
{
    10, // длина дескриптра
    0x03, // тип дескриптора - string desc
    /* имя */
    'T', 0, 
    'E', 0, 
    'S', 0, 
    'T', 0
};
Если можно, вкратце, как его использовать (на примере первой функции)?

*Добавлено позже*

Добавил обработчик прерывания по CTR. Если у платы отключен пользовательский USB, то прерывание не появляется, как только подключаем пользовательский USB к компу, то происходит прерывание по CTR.
Кстати, устройство в таком случае определяется компьютером как: "Неопознанное устройство", поэтому USB монитор подключить не получается. На данном этапе так и должно быть?
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

isx писал(а): USB->EP0R   |= USB_EP_TX_VALID; // не совсем понятно. Разрешаем передачу данных
  USB->EP0R   |= USB_EP_RX_VALID; // не совсем понятно. Разрешаем прием данных
Вы видимо совсем не читаете, то что я уже Вам писал.
isx писал(а):Если можно, вкратце, как его использовать (на примере первой функции)?
Ваши вопросы указывают на то, что Вы совсем не читали как работает USB, бесполезно писать программу, если нет даже приблизительного понимания. В частности почитайте про запросы к USB устройствам.
isx писал(а):Добавил обработчик прерывания по CTR
Ну дык почитайте про это прерывание, когда оно случается.
isx писал(а):На данном этапе так и должно быть?
Если Ваше устройство не рассказывает хосту ничего, то как его он опознает?
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

Z_h_e писал(а):Вы видимо совсем не читаете, то что я уже Вам писал.
Тогда может так:

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

USB->EP0R	|= USB_EP_TX_NAK; // Готовы к передаче, но данных для передачи нет
USB->EP0R	|= USB_EP_RX_VALID; // К приему готов
Z_h_e писал(а):Если Ваше устройство не рассказывает хосту ничего, то как его он опознает?
Просто читал про диагностику USB поделок посредством мониторов. Я так понял, что пока мы дескриптор не передадим, мониторить ничего не получится? :dont_know:
Z_h_e писал(а):Ваши вопросы указывают на то, что Вы совсем не читали как работает USB, бесполезно писать программу, если нет даже приблизительного понимания. В частности почитайте про запросы к USB устройствам.
Z_h_e писал(а):Ну дык почитайте про это прерывание, когда оно случается.
Про USB читал Агурова, правда только один раз. И про запросы представление имею, а вот как переслать правильно данные именно с STM32 - не очень понятно....
Я знаю что это за прерывание, но не пойму как мне на него реагировать...
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

isx писал(а):Про USB читал Агурова, правда только один раз. И про запросы представление имею, а вот как переслать правильно данные именно с STM32 - не очень понятно....
Я знаю что это за прерывание, но не пойму как мне на него реагировать...
Вы заметили всю иронию второй страницы данного топика? Она наполовину состоит из ссылок на предыдущие посты. Вот Вам очередная, по которой найдете пост, там написано что делают с дескрипторами. Удачи.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Аватара пользователя
isx
Поставщик валерьянки для Кота
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Re: STM32 и USB (практика)

Сообщение isx »

Может так мой вопрос станет понятнее: :dont_know:
-Затем устанавливаете в регистре EP0 VALID RX, т.е. МК готов принять данные для нулевой точки.
-Возникает прерывание об успешной транзакции. Расшифровываете и понимаете что что то получили.
Вот возникло прерывание CTR после RESET. Как я понимаю, это значит что к нам поступил SETUP пакет. Нам нужно просто выполнить последующие действия?:
просто скопировать данные с указанных адресов - прочитать посылку - выяснить, что за дескриптор от нас просят - тупо копируем наш массив с описанием соответствующего дескриптора в соответствующую область памяти - выставляем USB_EP_TX_VALID, сообщая, что данные для отправки готовы и находятся в буфере, выставляем USB_EP_RX_VALID, сообщая о готовности принять данные. Снова ждем прерывание по CTR и едем по кругу...
По-любому все не так просто - должны быть какие-то грабли... :dont_know:
Аватара пользователя
Radist_M
Открыл глаза
Сообщения: 45
Зарегистрирован: Пн июн 14, 2010 17:09:55
Откуда: Москва

Re: STM32 и USB (практика)

Сообщение Radist_M »

Ага, вот на эти самые грабли я и напоролся. До выходных все было хорошо, потом что-то сломал и понеслось. Не работает и все тут

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

использую вот такой дескриптор девайса(откопал на хабре вроде):

#define USB_DEVICE_DESCRIPTOR_TYPE 1
#define DEVICE_VER_L 0
#define DEVICE_VER_H 2
#define RHID_SIZ_DEVICE_DESC 18



const uint8_t RHID_DeviceDescriptor[RHID_SIZ_DEVICE_DESC] =   {
		    RHID_SIZ_DEVICE_DESC,         // overall descriptor length
		    USB_DEVICE_DESCRIPTOR_TYPE, // bDescriptorType -  Device descriptor
		    0x00, 0x02,                 // bcdUSB USB 2.0

			// class, subclass
		    0x00,                       //bDeviceClass
		    0x00,                       //bDeviceSubClass
		    0x00,                       //bDeviceProtocol

		    0x40,                       //bMaxPacketSize - max size of packets

			// vid pid
		    0x83, 0x04,                 //idVendor (0x0483)
		    0x11, 0x57,                 //idProduct (0x5711)

		    DEVICE_VER_L, DEVICE_VER_H,                 // bcdDevice rel. DEVICE_VER_H.DEVICE_VER_L  			
		    1,                          //Index of string descriptor describing manufacturer
		    2,                          //Index of string descriptor describing product
		    3,                          //Index of string descriptor describing the device serial number
		    0x01                        // bNumConfigurations - kol-vo vozmozhnih configurations.
  }  ; /* CustomHID_DeviceDescriptor */

Коды событий, которые желаю поймать

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

#define GET_DESCRIPTOR 6
#define SET_ADDRESS	5
Обработчик прерывания USB

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

void USB_LP_CAN1_RX0_IRQHandler(void)//обработчик прерывания USB
{//if DIR==1 OUT transaction;	
	if (((USB->ISTR)&USB_ISTR_RESET)!=0) // if reset
		{				
			//Если пришел резет конфигурируем КТ
			USB->EP0R = USB_EP0R_EP_TYPE_0|USB_EP0R_STAT_RX|USB_EP0R_STAT_TX_1;//EP address 0, type - control, EP enable (stat_rx - valid), STAT_TX -NAK		
			USB->DADDR = USB_EF;//EF enable function				
			USB->ISTR = 0;		//clear reset.
		}	
	
	else if (((USB->ISTR)&USB_ISTR_CTR)!=0)// if correct transfer
	{				
		
		if (((USB->EP0R)&USB_EP0R_SETUP)!=0)//if setup packet
		{		//STAT_TX = NAK
			//int swcase = byte_from_PMA2(1,0x80);
			int swcase = (*(int*)0x40006081)&0xf;//беру байт из пакетной памяти, тот самый где лежит байт под именем bRequest (ну по спецификации USB). Это второй принятый байт
			
			switch(swcase){
				case SET_ADDRESS:
					/*
						Сюда вообще не попадаю
					*/
				USART2->DR = SET_ADDRESS;				
				USB->EP0R = USB_EP0R_EP_TYPE_0|USB_EP0R_STAT_TX_0;//STAT_TX - valid; разрешаю передачу				
				break;
				
				case GET_DESCRIPTOR://ага ,запрос дескриптора. дескриптор у меня уже лежит в нужном месте
					//USART2->DR= GET_DESCRIPTOR;//действительно получаю 0x06
					//while (((USART2->SR)&USART_SR_TXE)==0) {} ждем пока буфер не освободится ,чтобы быстро не молотил
					//ниже менял количество отправляемых байт. Да это именно счетчик количества байт, которые надо отправить
					//DiscrTable->COUNT0TX = 0;//если так, то иногда получается попасть в обработку события USB_EP0R_CTR_TX
					//DiscrTable->COUNT0TX = 0x8;// нет
					//DiscrTable->COUNT0TX = RHID_SIZ_DEVICE_DESC;//				и так нет

					USB->EP0R = USB_EP0R_EP_TYPE_0|USB_EP0R_STAT_TX_0;//EP type will be not changed (control EP); STaT_TX -> valid; bit CTR_RX will be clear. Разрешаю передачу						
					break;
				default:				
				USART2->DR= swcase;	//если другой запрос, то поглядим в UART что пришло		
			}		
		}		
	}
	if (((USB->EP0R)&USB_EP0R_CTR_TX)!=0) //Если удачно передадим дескриптор, то должны попасть вот сюда. STAT_TX-NAK; сюда попадаю иногда
				{					
					USART2->DR = 0xFC;//mark of event
					//while (((USART2->SR)&USART_SR_TXE)==0) {}					
				USB->EP0R = USB_EP0R_EP_TYPE_0|USB_EP0R_STAT_RX_0;//EP address 0, type - control, stat_rx from NAK to VALID, clear CTR_TX разрешаю прием след. команды								
				}	
	
	USB->ISTR = 0;
}
По идее должно быть вот что (ИМХО):
1. Первый Reset
2. Запрос дескриптора устройства
3. Второй Reset
4. Пакет Set address


USB настроено на 2 прерывания.

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

USB->CNTR = USB_CNTR_RESETM|USB_CNTR_CTRM;//enable reset interrupt, correct transfer,

Прерывание USB_LP_CAN1_RX0_IRQ разрешено

Reset приходит. Срабатывает прерывание. Настраиваюсь и выхожу из прерывания
Потом хост присылает SETUP пакет. Срабатывает прерывание. И в буфере уже лежит принятый пакет.

разбираю его - все четко:

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

0x80
0x06 - вот оно - Запрос дескриптора устройства
0x00
0x01
0x00
0x00
0x40
0x00
Вот тут вопрос: логика протокола USB
/Token Packet / data packet / handshake /
А вот этот handshake это не ZLP? раньше я не парился над этим.

В Буфере передатчика лежит заготовленный дескриптор (заранее положил туда), тогда я выставляю

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

DiscrTable->COUNT0TX = RHID_SIZ_DEVICE_DESC;//т.е. говорю ,что передать надо весь буфер
далее разрешаю передачу

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

USB->EP0R = USB_EP0R_EP_TYPE_0|USB_EP0R_STAT_TX_0;
т.е. STAT_TX из NAK в VALID. Да, периферия USB сама выставляет NAK для приема и передачи и приложение должно само решить что делать дальше

теперь должен дескриптор улететь и сработать прерывание

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

USB_EP0R_CTR_TX
Типа "данные отправлены, что дальше шеф?"
Я бы в этом прерывании разрешил прием следующей команды но нет. Не работает. Где накосячил - хз.
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

Re: STM32 и USB (практика)

Сообщение Z_h_e »

Radist_M писал(а):А вот этот handshake это не ZLP?
Нет, это разные вещи.
Radist_M писал(а):По идее должно быть вот что (ИМХО):...
Все что приходило от хоста к stm32 я залогировал и выложил. Данная операция мне очень помогла.
Radist_M писал(а):т.е. говорю ,что передать надо весь буфер
Передавать надо ровно столько данных, сколько просит хост, по крайней мере не длиннее. И уж всяко не длиннее самого дескриптора. Если у Вас дескриптор 18 байт, 18 и передавайте, зачем слать к нему в догонку мусор буфера. А если хост запросил только 9 байт, 9 и передавайте.
Radist_M писал(а):Где накосячил - хз.
На любой косяк хост "обижается". Вы должны четко соблюдать протокол. Описание дескрипторов, их длина. Очередность передачи и т.д. Если хост требует что-то сделать, но не требуются данные. Вы должны помахать в ответ ZLP. Например пришла команда установить адрес. Вы отвечаете ZLP, как от безадресного устройства, затем дальше все должно работать по адресу. Отправили дескриптор хосту, если хост его съест , то он отправит zlp.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Ответить

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