Делаю вывод, Bit Banding это аппаратный |= и по факту нет доступа к конкретному биту
А на картинках-то так все красиво расписано . Спойлер Вашу функцию пока не пробовал - хотел докопаться до правды. Как появится время обязательно попробую...
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:0 Медали: 1
isx писал(а):
А на картинках-то так все красиво расписано .
В целом то все верно, регистров с битами тогл врядли много, или даже только в USB. С Bit Banding не надо переживать за соблюдение атомарности. Быстродействие опять, Сишное |= будем скомпилированно как минимум в три команды, Bit Banding в одну.
Весьма вероятно, что в какой-то документации указан этот нюанс работы Bit Banding. Скорее всего не в STM, а в ARM.
Цитата:
Вашу функцию пока не пробовал - хотел докопаться до правды
Думаете она у меня какая-то не правдивая ?
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:0 Медали: 1
isx писал(а):
Уууу... Так глубоко я еще не копаю .
Так то с него бы и надо начинать, основа, это ж ядро проца, единое для всех, а вот перефирия это уже от марки контроллера. Но не буду врать, я много чего забыл уже сам. Сразу в голове не все откладывается, особенно когда работаешь с контроллером иногда.
isx писал(а):
Я правильно понимаю, что bit15 и bit7 это: Код: const uint16_t bit15 = 0x8000; const uint16_t bit7 = 0x0080;
Когда я начал изучать STM, начал с самого легкого, с USB . И не знал, что не только для каждого регистра уже есть определения, но и для каждого бита тоже. Я собственно и для регистров USB сам сделал определения. Кстати, тоже хорошо помогает для понимания. По большому счету и СИ то тоже начал одновременно с STM изучать. Вы значения правильно определили, только у меня это не константы, а макроопределения.
Так то с него бы и надо начинать, основа, это ж ядро проца, единое для всех
Это я понимаю. Врать не буду, начинал несколько раз читать про ядра, но не осилял такой поток информации . Наверное, пока рано.
Z_h_e писал(а):
Когда я начал изучать STM, начал с самого легкого, с USB
Я к нему постепенно шел, да вот только не чувствую особого различия. Все с ним наизнанку выворачивается
Z_h_e писал(а):
Я собственно и для регистров USB сам сделал определения
Я тоже сам начинал, но потом в 5-ом кейле встретил готовые определения... Эх, жаль тогда мне никто не сказал, что STAT-дефайны оттуда можно только для чтения использовать. Сколько я из-за этого времени убил Не знаю почему, но кейл у меня напрочь отвергает case-ы со значениями Valid и Stall. Просит значения Int. Параллельно пробую свою функцию городить. Это уже просто дело принципа, завести этот чертов USB со своим кодом
Сделал функцию, прям вот по-топорному, чтоб все перед глазами было. Прогнал на тесте - вроде все правильно пашет. Только вот чертов второй запрос так и не приходит... Кину код. Он кошмарный, вряд ли кто-то захочет читать, но вдруг. А я ушел глубокие думы думать Спойлер
uint32_t buff; uint32_t stat; buff=((uint32_t*)0x40005C00)[EPNum]; //0x40005C00 базовый адрес регистров юсб
if (RXTX == 1)////////////////////////////////RXTX = 1 = TX { stat = (buff>>4) & 3; switch (stat) { case 0: //DISABLE switch (EPStatus) { case 0: break; case 1: buff^=0x0010; buff&=0x8FBF; break; //TX case 2: buff^=0x0020; buff&=0x8FBF; break; //TX case 3: buff^=0x0030; buff&=0x8FBF; break; //TX } break;
case 1: //STALL switch (EPStatus) { case 0: buff^=0x0010; buff&=0x8FBF; break; //TX case 1: break; case 2: buff^=0x0030; buff&=0x8FBF; break; //TX case 3: buff^=0x0020; buff&=0x8FBF; break; //TX } break;
case 2: //NAK switch (EPStatus) { case 0: buff^=0x0020; buff&=0x8FBF; break; //TX case 1: buff^=0x0030; buff&=0x8FBF; break; //TX case 2: break; case 3: buff^=0x0010; buff&=0x8FBF; break; //TX } break;
case 3: //VALID switch (EPStatus) { case 0: buff^=0x0030; buff&=0x8FBF; break; //TX case 1: buff^=0x0020; buff&=0x8FBF; break; //TX case 2: buff^=0x0010; buff&=0x8FBF; break; //TX case 3: break; } break;
default: break; } }
else //////////////////////////////////////// RXTX = 0 = RX { stat = (buff>>12) & 3; switch (stat) { case 0: //DISABLE switch (EPStatus) { case 0: break; case 1: buff^=0x1000; buff&=0xBF8F; break; //RX case 2: buff^=0x2000; buff&=0xBF8F; break; //RX case 3: buff^=0x3000; buff&=0xBF8F; break; //RX } break;
case 1: //STALL switch (EPStatus) { case 0: buff^=0x1000; buff&=0xBF8F; break; //RX case 1: break; case 2: buff^=0x3000; buff&=0xBF8F; break; //RX case 3: buff^=0x2000; buff&=0xBF8F; break; //RX } break;
case 2: //NAK switch (EPStatus) { case 0: buff^=0x2000; buff&=0xBF8F; break; //RX case 1: buff^=0x3000; buff&=0xBF8F; break; //RX case 2: break; case 3: buff^=0x1000; buff&=0xBF8F; break; //RX } break;
case 3: //VALID switch (EPStatus) { case 0: buff^=0x3000; buff&=0xBF8F; break; //RX case 1: buff^=0x2000; buff&=0xBF8F; break; //RX case 2: buff^=0x1000; buff&=0xBF8F; break; //RX case 3: break; } break;
} }
((uint32_t*)0x40005C00)[EPNum]=buff;
}
const uint8_t Virtual_Com_Port_DeviceDescriptor[] = { 0x12, // размер данного дескриптора 0x01, // тип данного дескриптора - device descriptor 0x00, 0x02, // 2 байта - версия usb 2.0 0x02, // класс устройства cdc 0x00, // подкласс 0x00, // протокол 0x40, // USB_MAX_PACKET0, // max размер пакета для нулевой конечной точки 0x83, 0x04, // 2 байта - VID 0x40, 0x57,// 2 байта - PID 0x00, 0x02,// 2 байта - версия (ревизия) устройства 0x01, // индекс строки с названием производителя 0x02, // индекс строки с названием устройства 0x03, // индекс строки с серийным номером устройства 0x01 // количество поддерживаемых конфигураций };
//Переключиться на тактирование от 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)
if (USB->ISTR & USB_ISTR_RESET) { USB->ISTR = 0; USB->CNTR |= USB_CNTR_CTRM | USB_CNTR_RESETM; // | USB_CNTR_ESOFM | USB_CNTR_SOFM; USB->BTABLE = BTableOffset; // таблица начинается с 0x0000
*(__IO uint32_t*)(0x40006000) = (uint16_t) 0x40; // начальный адрес USB_ADDR0_TX (такой адрес позволяет в дальнейшем добавить все 8 возможных контрольных точек, каждая имеет размер 1 байт) *(__IO uint32_t*)(0x40006004) = (uint16_t) 0x40; // размер исходящих данных - 64 байта USB_COUNT0TX *(__IO uint32_t*)(0x40006008) = (uint16_t) 0x80; // начальный адрес USB_ADDR0_RX *(__IO uint32_t*)(0x4000600C) = (uint16_t) 0x8400; // 64 байта входящих данных USB_ USB_COUNT0RX_BL_SIZE
USB->EP0R |= USB_EP_CONTROL; // режим - CONTROL
USB->EP0R |= USB_EP_TX_NAK; // Готовы к передаче, но данных для передачи нет USB->EP0R |= USB_EP_RX_VALID; // К приему готов test4 = *(__IO uint32_t*)(0x40006100);
// 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, // интервал готовности точки к обмену данными
Хост отправляет токен Setup, говорящий функции, что следующий пакет будет пакет Setup. Поле адреса будет содержать адрес устройства, от которого главный компьютер просит дескриптор. Номер конечной точки должен быть 0, что указывает канал по умолчанию (default pipe). Затем хост отправит пакет DATA0. Он будет содержать 8 байт полезной нагрузки, которая будет являться запросом Device Descriptor Request. Функция USB подтверждает пакет setup, что он был прочитан корректно, без ошибок.
Не значит ли это, что после принятия дескриптора устройства мне нужно как-то сказать хосту о том, что я его получил (типа - отправкой пакета нулевой длины)? Или это подтверждение выполняется на железном уровне самостоятельно? А еще и вот:
Цитата:
Хост отправляет токен IN, чем говорит устройству, что он может теперь отправить данные для этой конечной точки. Поскольку максимальный размер пакета 8 байт, мы должны для отправки разделить 12 байт дескриптора устройства на кусочки. Каждый кусочек должен быть размером по 8 байт, за исключением последней транзакции. Хост подтверждает каждый пакет, который мы посылаем ему.
Однако, я где-то читал, что для STM32 делить control пакет не нужно. Где всё-таки правда?
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:0 Медали: 1
isx писал(а):
Не значит ли это, что после принятия дескриптора устройства мне нужно как-то сказать хосту о том, что я его получил
По-моему это значит Вам пора отдохнуть и потом начать все заново. Как устройство может получить дескриптор устройства и зачем это знать хосту?
isx писал(а):
Однако, я где-то читал, что для STM32 делить control пакет не нужно. Где всё-таки правда?
Все управляющие пакеты будут для нулевой точки. Т.е. выделять как-то отдельно обрабатывать управляющие пакеты нет смысла.
Я так понимаю, Вы собрались сделать USB UART. Как я понимаю у Вас два пути. Это сделать полную копию какого-то устройства которое знает Винда, т.е. не только дескрипторы повторить, но и протокол обмена. Или же сделать свое и написать драйвер. Какое у Вас решение?
Можно сделать свое HID устройство. Для этого уже в этом топике все есть. Да я Вам весь код выложил своего устройства, хорош он или плох, но работает.
Читаете теорию снова и на этот раз не один раз, а перечитываете(до меня, например, такие вещи не доходят с первого раза). Читаете данный топик сначала, Вами же созданный и все у Вас получится. С виртуальным COM портом не помогу, не знаю.
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Как устройство может получить дескриптор устройства и зачем это знать хосту?
Прошу прощения, имел ввиду запрос дескриптора устройства.
Z_h_e писал(а):
Все управляющие пакеты будут для нулевой точки. Т.е. выделять как-то отдельно обрабатывать управляющие пакеты нет смысла.
Не то, чтобы выделять. Просто, как я понял смысл этих строк - пока хост полностью не получит дескриптор устройства, он за раз принимает данные не более 8 байт.
Цитата:
Поскольку максимальный размер пакета 8 байт, мы должны для отправки разделить 12 байт дескриптора устройства на кусочки. Каждый кусочек должен быть размером по 8 байт, за исключением последней транзакции.
Вообще хочу виртуальный COM порт сделать для начала. Только вот пока не удается даже запрос на второй дескриптор получить, а может и скормить первый. Единственная причина, по которой сейчас запрос на второй дескриптор может не приходить - это неверный порядок действий после получения первого запроса. Данные в буфер записываются нормально, но вот что происходит дальше - передались ли они или же передача не состоялась - загадка . Ни на каком ресурсе не могу найти простое описание действий (без SPL, HAL и самопальных библиотек), а я нормально читать чужие огороды загадочных для меня функций пока не получается, хоть тресни
Не то, чтобы выделять. Просто, как я понял смысл этих строк - пока хост полностью не получит дескриптор устройства, он за раз принимает данные не более 8 байт.
Похоже нашел правду :
Цитата:
The USB driver stack issues a request for the USB Device Descriptor (GET_DESCRIPTOR for Descriptor Type DEVICE), using the default USB address of 0, and a maximum packet size of 8 bytes for low-speed devices and 64 bytes for full and high-speed devices.
Сделал что-то типа лога срабатывающих прерываний. У меня используются 4 флага прерывания: RESET (тут понятное дело, настройки контрольной точки) SETUP (просто так, в нем ничего не происходит) CTR_RX (отправка 18-ти байт дескриптора устройства) CTR_TX (установка STAT_RX в VALID) Внутри каждого прерывания поместил строки:
Код:
TestBuff[CountTestBuff] = Х; CountTestBuff++;
Изначально CountTestBuff = 0. Значение Х зависит от того, по какому флагу произошло прерывание. Так для:
Цитата:
RESET = 9 SETUP = 5 CTR_RX = 8 CTR_TX = 7
В итоге массив заполняется такими значениями:
Цитата:
9,5,8,7, 9,5,8,7, 9,5,8,7, 9,5,8,7, 0.0.0......
а затем вылетает окошко в Windows "Неопознанное устройство" Почему-то после прерывания по CTR_TX я опять вылетаю в ресет и все шаги повторяются. Во входящем буфере при этом после первого ресета постоянно висит первый запрос дескриптора устройства.
Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04 Сообщений: 2708 Откуда: г. Чайковский
Рейтинг сообщения:0 Медали: 1
Сдался вам этот сетап. У меня сейчас нет возможности проверить, но наверняка флаги сетап и rx устанавливпются одновременно, а вы их поди как два разных события обрабатываете. В этом топике мой код полностью выложен, только в разных постах. Соберите,не поленитесь. Дескрипторы не могу выложить физически, только их и не выкладывал, я на телефоне и долго компа не увижу .
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
но наверняка флаги сетап и rx устанавливаются одновременно, а вы их поди как два разных события обрабатываете
Я SUTUP сегодня только поставил, чисто для проверки. В нем кроме заполнения массива нет ничего.
Z_h_e писал(а):
Дескрипторы не могу выложить физически, только их и не выкладывал, я на телефоне и долго компа не увижу .
В дескрипторах нет необходимости - у меня второй запрос все-равно не приходит, а дескриптор устройства я нашел в статье в интернете, потом сверил с другими форумами и с книгой Агурова. Там все сходится... Пытаюсь сверяться, с Вашим кодом. Пока вроде все сходится, но не уверен что все правильно трактую. В выходные попробую выкроить время и свести все в одну кучу, может что и прояснится...
P.S. Если у меня происходит прерывание по CTR_TX после CTR_RX (в котором мы отправляли дескриптор устройства), то это значит, что МК осуществил передачу дескриптора хосту, и дальнейшая судьба пакета ему не известна? Или это говорит о том, что дескриптор дошел до хоста и хост сообщил о его принятии?
//Регистры конечных точек 0 USB_REGISTR->EP0R=0x0| //номер точки bit13|bit12| //STAT_RX - VALID // bit8 |//какой то статус аут bit5|//bit4| //STAT_TX - NAK /*bit10|*/ bit9 ; /*00 BULK //10-9 тип точки. в данном случае Контрол 01 CONTROL 10 ISO 11 INTERRUPT*/
USB_REGISTR->DADDR=bit7;//EF:Enable function, Включение ЮСБ с нулевым адресом
FlagAddress=0; //устройство не пришла команда установки адреса // FlagZLP=0;
}
Имеются две проблемы. 1. Если USB_REGISTR->DADDR=bit7; ставить в конце (после настройки точки 0), то регистр EP0 не меняется и остается не настроенным (EP0 = 0). 2. USB_REGISTR->EP0R у Вас использует какую-то функцию установки битов или просто работает с дефайнами из CMSIS (доступ к битам через |=)? Если второй случай, то происходит вот что: При первом резете, (когда ещё EP0 = 0) STAT биты ставятся как положено (VALID и NAK), но после второго ресета регистр EP0 не сбрасывается и при повторной обработке через |= происходит сброс STAT битов. Что я опять не так делаю?
Сделал что-то типа лога срабатывающих прерываний. ..... SETUP (просто так, в нем ничего не происходит) ..... В итоге массив заполняется такими значениями:
Цитата:
9,5,8,7, 9,5,8,7, 9,5,8,7, 9,5,8,7, 0.0.0......
а затем вылетает окошко в Windows "Неопознанное устройство" Почему-то после прерывания по CTR_TX я опять вылетаю в ресет и все шаги повторяются. Во входящем буфере при этом после первого ресета постоянно висит первый запрос дескриптора устройства.
Э, а как это в SETUP ничего не происходит? Ясен пень "ресет и все шаги повторяются". Я ж уже скидывал ссылку где расписан процесс энумерации устройства. Давайте по порядку: 1. Reset. Поймали сброс, контроллер готов к приему следующих команд по адресу 0 в нулевую КТ. 2. Получаем пакет типа Setup. Смотрим что это за пакет в полях bRequest wValue - должен быть запрос дескриптора устройства. 2.1 После этого Хост долбит контроллер запросами типа IN. Если мне не изменяет память - тут надо по-моему отправить пакет нулевой длинны, чтоб комп понял, что мы приняли пакет. 3. Загружаем дескриптор в пакетную память и разрешаем отправку установкой соответствующих значений (что отправлять и в каком количестве). Об этом уже говорилось. 4. Получаем от компа пакет нулевой длинны - это значит что комп распознал наш пакет. 5. Должен прийти Setup пакет но с запросом Set address. После этого Хост долбит контроллер запросами типа IN. Контроллер должен отправить пакет нулевой длинны. 6. Отвечаем пакетом нулевой длинны. 7. Устанавливаем полученный адрес от хоста в соотв. региср. 8. Хост опять запрашивает дескриптор.. и так далее. Вот эти шаги должны быть у вас 100%. Мой контроллер STM32C8T6 с кварцем на 12 МГц. Если уж сможете в коде разобраться - смогу выслать свою прошивку. Но предупреждаю - я не дошел до логического конца. Завалился на запросе дескриптора конфигурации. Я об этом писал. Да, выслать смогу не сразу, сейчас нет доступа к прошивке.
2.1 После этого Хост долбит контроллер запросами типа IN. Если мне не изменяет память - тут надо по-моему отправить пакет нулевой длинны, чтоб комп понял, что мы приняли пакет.
Вот про это хотелось бы по точнее. Я как-то спрашивал на форуме про ZLP после приема запроса дескриптора, но мне сказали, что делать этого не нужно . Сегодня может время появится, попробую с ZLP - вариантов все-равно пока других нет....
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения