А можете немного рассказать про таблицу адресов, что это вообще? Как я понимаю, там хранятся адреса, которые мы задаем для начала и размера контрольных точек. Если это так, то размер таблицы для одной контрольной точки строго фиксированный, и общей размер таблицы будет зависеть только от количества использованных контрольных точек?
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 есть только в регистре с флагами За расписанные прерывания с комментариями отдельное Спасибо, поправил кое-что у себя в голове .
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:1 Медали: 1
isx писал(а):
А какой в этом практический смысл?
isx писал(а):
А это для чего?
Может для каких-то сложных USB устройств. Мне это не надо и я ж написал можно, а не нужно.
Цитата:
А можете немного рассказать про таблицу адресов, что это вообще?
Могу. Как видите я настраиваю только буфер для конечной точки 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 сам переходит, так что можно и по одному биту менять было.
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Блиин.. Чет все-равно ниче не понятно . Попробую пойти по порядку. Вот, к примеру, Начинаем мы работать с адресами. Определяем, что будет у нас 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
Итого получается, что выделенная для нулевой конечной точки память будет занимать пространство от 0x40006000 до 0x40006012. Тогда USB_ADDR0_TX занимает пространство в памяти от 0x40006000 до 0x40006003. Если я правильно понимаю, то по каждому конкретному адресу (например 0x40006000) содержится 16 бит информации. Тогда напрашивается вопрос: регистр USB_ADDR0_TX содержит 16 бит информации, зачем под него выделено 64 бита?
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:1 Медали: 1
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 . Так видит эту память ядро, это логично, адресное пространство едино. Справа пишите адреса 0x000,0x002,0x004...0x1FE . Так видит эту память периферия USB.
Картинку можете выложить сюдой, может кому пригодится, если начертите конечно. Да, все-таки откройте ту 617 страницу. Там есть картинка про буфер USB и как в ней лежит таблица.
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Голова кипит уже, а я даже до дескрипторов не добрался Посты перечитал уже раз 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. Большое спасибо за терпение. Я просто раньше так к близко к железу не копал никогда, а гуманитарное образование здесь помочь ни чем не может... Не знаю как бы без Вас разбирался в этих дебрях .
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:1 Медали: 1
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:
Я не вижу что на картинке, а документа этого у меня нет. Я с другим МК работаю. Приложите нормального размера и спрячьте под споллейр.
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:0 Медали: 1
А, все увидел про что Вы. Это для двойной буферизации, два регистра спариваются в один. Над ним же буржуйским по белому написано. Это для изохроной передачи, я даже не пробовал туда читать .
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:1 Медали: 1
isx писал(а):
Точно... Невнимательно посмотрел.
Кстати Вы число 7 и не смогли бы записать туда, получилось бы 6. Младший бит не доступен, выравнивание по 2 байта. Я только не понимаю зачем Вы так рветесь расположить буфер по адресу 8. Оставьте место для всей таблицы, пускай будет незаполненной, зато потом если ее добавлять ничего остального двигать не надо будет.
isx писал(а):
То есть устанавливается только один, самый старший бит регистра (если передавать будем максимум по 2 байта - то бит 1, если по 32 байта - то бит 5)?
USB_COUNTn_RX для приема, а не для передачи. Мне не трудно помочь, но Вы все-таки почитайте про этот регистр в референсе и то что я уже написал. А то все одно и тоже повторяю. Там 6 старших бит задают размер области приема, и целая таблица есть Table 177. Definition ofallocated buffer memory.
isx писал(а):
Таблица по такому типу?
Ну как то так. Только компактнее все 4 байта в одну строчку нарисовать, но это дело вкуса. Ну и справа такой разрядности адреса не требуется, 512 байт же всего.
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Я только не понимаю зачем Вы так рветесь расположить буфер по адресу 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. Повторюсь, с адресами памяти не работал ранее и приходится изучать все на лету, поэтому не пинайте сильно...
Только это как-то ненаглядно. Возвращаю Вас на первую страницу созданного Вами же топика. Вот тут под споллером объявлена структура. А здесь пример ее использования, тоже под споллером.
Вы меня по Си сильно то не спрашивайте, сам его только с осени прошлой использую.
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; // не совсем понятно. Разрешаем прием данных
Поправил работу с адресами. И еще такой вопрос: Когда я записываю данные по адресу в память они записываются нормально, но в соседних ячейках записана тоже какая-то фигня. Может нужно как-то стирать участок памяти перед использованием, или и так нормально работать будет? Вот что в итоге получилось: Спойлер
//Переключиться на тактирование от 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)
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, // индекс строки, описывающей данную альтернативную установку данного интерфейса
/* 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, // интервал готовности точки к обмену данными
/* 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 монитор подключить не получается. На данном этапе так и должно быть?
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:0 Медали: 1
isx писал(а):
USB->EP0R |= USB_EP_TX_VALID; // не совсем понятно. Разрешаем передачу данных USB->EP0R |= USB_EP_RX_VALID; // не совсем понятно. Разрешаем прием данных
Вы видимо совсем не читаете, то что я уже Вам писал.
isx писал(а):
Если можно, вкратце, как его использовать (на примере первой функции)?
Ваши вопросы указывают на то, что Вы совсем не читали как работает USB, бесполезно писать программу, если нет даже приблизительного понимания. В частности почитайте про запросы к USB устройствам.
isx писал(а):
Добавил обработчик прерывания по CTR
Ну дык почитайте про это прерывание, когда оно случается.
isx писал(а):
На данном этапе так и должно быть?
Если Ваше устройство не рассказывает хосту ничего, то как его он опознает?
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Вы видимо совсем не читаете, то что я уже Вам писал.
Тогда может так:
Код:
USB->EP0R |= USB_EP_TX_NAK; // Готовы к передаче, но данных для передачи нет USB->EP0R |= USB_EP_RX_VALID; // К приему готов
Z_h_e писал(а):
Если Ваше устройство не рассказывает хосту ничего, то как его он опознает?
Просто читал про диагностику USB поделок посредством мониторов. Я так понял, что пока мы дескриптор не передадим, мониторить ничего не получится?
Z_h_e писал(а):
Ваши вопросы указывают на то, что Вы совсем не читали как работает USB, бесполезно писать программу, если нет даже приблизительного понимания. В частности почитайте про запросы к USB устройствам.
Z_h_e писал(а):
Ну дык почитайте про это прерывание, когда оно случается.
Про USB читал Агурова, правда только один раз. И про запросы представление имею, а вот как переслать правильно данные именно с STM32 - не очень понятно.... Я знаю что это за прерывание, но не пойму как мне на него реагировать...
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:0 Медали: 1
isx писал(а):
Про USB читал Агурова, правда только один раз. И про запросы представление имею, а вот как переслать правильно данные именно с STM32 - не очень понятно.... Я знаю что это за прерывание, но не пойму как мне на него реагировать...
Вы заметили всю иронию второй страницы данного топика? Она наполовину состоит из ссылок на предыдущие посты. Вот Вам очередная, по которой найдете пост, там написано что делают с дескрипторами. Удачи.
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
-Затем устанавливаете в регистре EP0 VALID RX, т.е. МК готов принять данные для нулевой точки. -Возникает прерывание об успешной транзакции. Расшифровываете и понимаете что что то получили.
Вот возникло прерывание CTR после RESET. Как я понимаю, это значит что к нам поступил SETUP пакет. Нам нужно просто выполнить последующие действия?: просто скопировать данные с указанных адресов - прочитать посылку - выяснить, что за дескриптор от нас просят - тупо копируем наш массив с описанием соответствующего дескриптора в соответствующую область памяти - выставляем USB_EP_TX_VALID, сообщая, что данные для отправки готовы и находятся в буфере, выставляем USB_EP_RX_VALID, сообщая о готовности принять данные. Снова ждем прерывание по CTR и едем по кругу... По-любому все не так просто - должны быть какие-то грабли...
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
Reset приходит. Срабатывает прерывание. Настраиваюсь и выхожу из прерывания Потом хост присылает SETUP пакет. Срабатывает прерывание. И в буфере уже лежит принятый пакет.
разбираю его - все четко:
Код:
0x80 0x06 - вот оно - Запрос дескриптора устройства 0x00 0x01 0x00 0x00 0x40 0x00
Вот тут вопрос: логика протокола USB /Token Packet / data packet / handshake / А вот этот handshake это не ZLP? раньше я не парился над этим.
В Буфере передатчика лежит заготовленный дескриптор (заранее положил туда), тогда я выставляю
Код:
DiscrTable->COUNT0TX = RHID_SIZ_DEVICE_DESC;//т.е. говорю ,что передать надо весь буфер
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:0 Медали: 1
Radist_M писал(а):
А вот этот handshake это не ZLP?
Нет, это разные вещи.
Radist_M писал(а):
По идее должно быть вот что (ИМХО):...
Все что приходило от хоста к stm32 я залогировал и выложил. Данная операция мне очень помогла.
Radist_M писал(а):
т.е. говорю ,что передать надо весь буфер
Передавать надо ровно столько данных, сколько просит хост, по крайней мере не длиннее. И уж всяко не длиннее самого дескриптора. Если у Вас дескриптор 18 байт, 18 и передавайте, зачем слать к нему в догонку мусор буфера. А если хост запросил только 9 байт, 9 и передавайте.
Radist_M писал(а):
Где накосячил - хз.
На любой косяк хост "обижается". Вы должны четко соблюдать протокол. Описание дескрипторов, их длина. Очередность передачи и т.д. Если хост требует что-то сделать, но не требуются данные. Вы должны помахать в ответ ZLP. Например пришла команда установить адрес. Вы отвечаете ZLP, как от безадресного устройства, затем дальше все должно работать по адресу. Отправили дескриптор хосту, если хост его съест , то он отправит zlp.
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 25
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения