Например TDA7294

Форум РадиоКот • Просмотр темы - Низкоуровневая работа с USB на STM32
Форум РадиоКот
Здесь можно немножко помяукать :)

Текущее время: Вс июл 27, 2025 21:40:25

Часовой пояс: UTC + 3 часа


ПРЯМО СЕЙЧАС:



Начать новую тему Ответить на тему  [ Сообщений: 22 ]  1,  
Автор Сообщение
Не в сети
 Заголовок сообщения: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Вт ноя 17, 2015 11:35:24 
Встал на лапы

Карма: 3
Рейтинг сообщений: 1
Зарегистрирован: Вс янв 27, 2013 19:02:19
Сообщений: 126
Рейтинг сообщения: 0
Пытаюсь разобраться с USB у STM32F103 на низком уровне (т.е. без сторонних библиотек) и столкнулся с проблемой.

Мои действия:
1) У меня внешний кварц на 8 МГц. Запускаю PLL на 72 МГц (коэффициент умножения 9, делитель для USB 3). Разумеется, этот процесс состоит из нескольких этапов, однако в результате в регистре RCC->CFGR оказывается значение 0x001DC40A (что помимо прочего обозначает, что PLL успешно выбран как системный источник частоты). Работа USART и SysTick адекватна (частота точно верная).
2) Включаю тактирование USB. Убираю бит PWDN из USB->CNTR. Жду 1 микросекунду (по даташиту нужно для стабилизации источника опорного напряжения), пишу нули в CNTR, BTABLE и ISTR. Разрешаю прерывания USB_FS_WKUP и CAN1_RX0. Пишу в CNTR значение USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_CTRM.
3) На этом инициализация окончена. Далее приходит прерывание от USB. Причина, определённая из ISTR - RESET. Да, именно это и должно случиться, всё логично. Обнуляю соответствующий флаг прерывания.
4) Настраиваю нулевую конечную точку. В итоге в USB->EP0R оказывается значение 0x3220. По адресу USB_PMA_BASE + 0 оказывается значение 64 (TXADDR для EP0 == 64), по адресу USB_PMA_BASE + 8 оказывается значение 128 (RXADDR для EP0 == 128), по адресу USB_PMA_BASE + 12 оказывается значение 0x8400 (размер буфера приёма для EP0 - 64 байта).
5) Разрешаю работу USB - пишу в USB->DADDR значение 0x80.
6) Выхожу из прерывания.
7) Ожидаю, что мне придёт первый SETUP-пакет, о чём мне скажет прерывание с флагом CTR в регистре ISTR. А оно не приходит. Зато приходит куча прерываний по причине WKUP (я сбрасываю этот флаг, а оно снова приходит). Иногда приходит RESET (у хоста срабатывает таймаут назначения адреса устройству и он устраивает новый сброс), но после него опять куча WKUP. В конце-концов хост забивает на устройство и события прекращаются. Помимо WKUP ещё приходит ESOF.
Моя теория: USB-модуль не запускается должным образом и не способен разобрать, что приходит по шине кроме RESET. Передача данных видится им как событие WKUP (которое по сути вызывается любой активностью на линии).
Возможно, я забыл что-то инициализировать или же я что-то неправильно настроил и машину состояний USB клинит.

В чём может быть проблема? Аппаратная часть исправна - прошивки с использованием готовых библиотек на этой плате работают нормально.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Вт ноя 17, 2015 12:26:41 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
USB prescaller нужно включить делитель на полтора, чтобы получить частоту 48МГц.
Код:
#define RCC_USBCLKSource_PLLCLK_1Div5   ((uint8_t)0x00)
RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);


Я тоже бьюсь головой об USB, сейчас уже хоть какая-то картинка в голове, иногда хотелось психануть и все бросить. И тоже пробую на этом же камне. Дошел до того что хост назначает мне адрес, засылаю его в DADDR и потом жду что дальше хост скажет. А дальше тишина и затем сброс. Может на команду установки адреса надо что-то ответить ? Кто знает?

Заодно подскажите, тоже пока не разобрался. Зачем нужны младшие четыре бита регистра конечной точки EPnR.
Код:
Bits 3:0EA[3:0]: Endpoint address
Software must write in this field the 4-bit address used to identify the transactions directed to
this endpoint. A value must be written before enabling the corresponding endpoint.
Что за адреса конечных точек, или их может быть больше чем 8, но реально работающих одновременно только 8, но номера точек можно перезначачть. Допустим сначала работают точки 0, 1-7. А потом, по некоторой задаче, работают 0 ,8-14. Т.е. регистр EP7R может работать с любой точкой, а не только с седьмой?

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Вт ноя 17, 2015 20:05:52 
Встал на лапы

Карма: 3
Рейтинг сообщений: 1
Зарегистрирован: Вс янв 27, 2013 19:02:19
Сообщений: 126
Рейтинг сообщения: 0
После назначения адреса, тебе следует отправить в ответ пакет нулевой длины с точки EP0 IN. Этим ты сообщишь хосту успешность операции. Во всяком случае на MSP430 я так делал. Я для MSP430 вообще смог разобраться и реализовать полностью стек USB (и запилить виртуальный COM-порт), поэтому с теорией про саму шину у меня проблем нет, могу подсказать. Проблемы в реализации работы с железом самой STM32.

Не мог бы поделиться своим исходником? В библиотеках всё разбросано по куче файлов и я могу упускать из вида что-то важное. А если бы я увидел минимальную инициализацию USB, это могло бы помочь.

Насчёт EPnR думаю вы правы - можно назначить каждой точке свой адрес и таким образом получить доступ к номерам больше 8. Однако нулевая точка STM32 должна совпадать с нулевой точкой USB, по остальным такого требования нет.

Что касается делителя на 1.5.

Вот значение регистра RCC->CFGR на момент начала инициализации USB - 0x001DC40A. 22-ой битик этого регистра отвечает за частоту USB. На 135-ой странице STM32F1xx Reference Manual указано, что в сброшенном состоянии он включает деление на три, а в установленном на два. При этом делится частота в два раза выше выходной частоты PLL. Таким образом если в итоге получается деление на полтора или на один. Смотрим на моё значение - 0x001DC40A & (1 << 22) == 0, это можно проверить на калькуляторе. Если это единственное место, где настраивается делитель USB, то я всё сделал верно.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Вт ноя 17, 2015 21:18:23 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 1
Медали: 1
Получил миской по аватаре (1)
Исходник я Вам не дам. Ибо он страшен, по разным причинам, но в основном потому что еще на разобрался толком ни с ЮСБ, не с камнем да и к С не привычен. Закончу хотя бы с энумерацией, начну причесывать. Правда боюсь если с ближайшее время не получится что-нибудь, то дальнейшие изыскания придется прекратить где-то на месяц.

Прогаю в Кокосе. Тактовая частота контроллера задается стартапом. Раз работает, пока туда особо не лез. Но там наверняка множитель стоит на 9 от кварца 8МГц. То что от кварца работает проверял, пальцем, частота сразу плывет.

Какие подводные камни, навскидку. Буферная память USB для отладки не видна, копирую ее в RAM. Адресуется для ядра и блока перефирии ЮСБ по разному(как 32 и 16 битная соответственно). В одном регистре EPnR, биты имеют разные методы изменения, стирание нулем, обычный, тогл и только чтение. Пошаговая отладка тоже трудна, ибо в режиме паузы периферия USB продолжает работать и меняет состояния регистров. Стараюсь успеть выдернуть разъем из компа или закинуть данные регистров в RAM на лету.
Вот код инициализации USB
Код:
#define  bit0                           ((uint32_t)0x00000001)
#define  bit1                          ((uint32_t)0x00000002)
#define  bit2                           ((uint32_t)0x00000004)
и т.д.

RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE);

pUSB_REGISTR->USB_CNTR&=!bit1; //сбросим PWDN.  питает usb передатчик.

    Delay(100000);

   pUSB_REGISTR->USB_CNTR&=!bit0; //сбросим FRES

//сброс флагов
   pUSB_REGISTR->USB_ISTR=0;

//Настройка прерываний
   pUSB_REGISTR->USB_CNTR|=
         bit15| //CTRM:Correct transfer interrupt mask
         bit14 | //PMAOVRM:Packet memory area over / underrun interrupt mask
         //bit13 | //ERRM:Error interrupt mask
         //bit12 | //WKUPM:Wakeup interrupt mask
         //bit11 | //SUSPM:Suspend mode interrupt mask
         bit10 |//разрешение прерывание по резету
         bit9 | //SOFM:Start of frame interrupt mask
         //bit8 | //ESOFM:Expected start of frame interrupt mask
            0;

   NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);



Вот и вся инициализация USB.

Хотя в маске прерываний разрешены несколько событий, реально обрабатываю (пока) лишь резет и успешную передачу.


В обработчике прерывания Резет.
Код:
pUSB_REGISTR->USB_BTABLE=0;
DiscrTable->ADR0TX=(uint16_t)0x30;//тут записывается что буфер IN расположен по адресу 0x40006060. ОБРАТИТЕ НА ЭТО ВНИМАНИЕ. Именно 60

DiscrTable->ADR0RX=(uint16_t)0x10; // это буфер для приема нулевой конечной точки
DiscrTable->COUNT0RX=(uint16_t)(bit14+bit13+bit12+bit11+bit10);//выделено 0x40  байт

pUSB_REGISTR->USB_EP0R=bit13|bit12|bit9;

pUSB_REGISTR->USB_DADDR=bit7;//EF:Enable function

После этого возникает прерывание успешная передача. В EP0R выставлен флаг что именно прием произошел. В регистре длины буфера приема в младших битах число 8, т.е. принято 8 байт. По адресу 00x40006020 лежит запрос на выдачу дескриптора устройства.
Цитата:
В библиотеках всё разбросано по куче файлов
Я там вообще ничего не понял. Может когда USB сам скурю пойму :)
Цитата:
После назначения адреса, тебе следует отправить в ответ пакет нулевой длины с точки EP0 IN.
Ага, я уже нашел инфу об этом. Так называемый Zero Length Packet, ZLP. Но все равно Вам за это спасибо. Устанавливаю в буфере длину 0, в EP0R бит DTOG_TX в 1 (вроде ZLP должен быть как DATA1) и вроде как отвечаю. Но пока безрезультатно. Пока ищу ошибки на предмет рукожопости.

----------
Цитата:
STM32F1xx Reference Manual указано, что в сброшенном состоянии он включает деление на три, а в установленном на два...
У меня CFGR==001d040a

----------
С утра мозги лучше работают оказывается :)
Получилось у меня адресоваться. Ошибка была в том, адрес в DADDR не надо сразу устанавливать после получения SET_ADDRESS, а только после успешной отправки пустого пакета ZLP. Т.е. хост его запрашивает еще как у без адресного устройства, что в общем то логично. Затем хост опять запрашивает дескриптор, но уже у девайса с адресом.

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Чт ноя 19, 2015 16:24:07 
Встал на лапы

Карма: 3
Рейтинг сообщений: 1
Зарегистрирован: Вс янв 27, 2013 19:02:19
Сообщений: 126
Рейтинг сообщения: 0
Тоже с этим сегодня разбирался (адрес не получался) и тоже продвинулся до запроса дескриптора. Проблема с прерываниями WKUP заключалась в том, что их просто не нужно разрешать, если мы не спим. Сейчас такой алгоритм - по умолчанию разрешаю только RESET. При приходе RESET разрешаю RESET, CTR и SUSP. При приходе SUSP разрешаю WKUP и запрещаю SUSP. При приходе WKUP разрешаю SUSP и запрещаю WKUP. Всё отлично работает. Судя по всему WKUP приходит вне зависимости от состояния модуля USB при любой активности, а чрезмерная генерация прерываний приводит к глюкам.

Теперь у меня проблема вернуть дескриптор.

Код:
struct STM32USBBufferDesc {
   uint32_t txAddr;
   uint32_t txCount;
   uint32_t rxAddr;
   uint32_t rxCount;
};

volatile STM32USBBufferDesc *bufferTable() {
   return (volatile STM32USBBufferDesc*)(USB_PMA_BASE + USB->BTABLE * 2);
}

void epSetTxStatus(uint8_t i, STM32USBEpStatus status) {
   uint32_t epr = USB->EPR[i];
   epr &= ~(USB_EP0R_STAT_RX_MASK | USB_EP0R_DTOG_RX | USB_EP0R_STAT_TX_MASK | USB_EP0R_DTOG_TX);
   epr |= USB_EP0R_CTR_RX | USB_EP0R_CTR_TX;
   epr |= (USB->EPR[i] & USB_EP0R_STAT_TX_MASK) ^ (status << USB_EP0R_STAT_TX_OFFSET);
   USB->EPR[i] = epr;
}
      
STM32USBEpStatus epTxStatus(uint8_t i) {
   return (STM32USBEpStatus)((USB->EPR[i] & USB_EP0R_STAT_TX_MASK) >> USB_EP0R_STAT_TX_OFFSET);
}      

void copyToBufferArea(uint32_t offset, const void *data, int count) {
   count = (count + 1) / 2;
   uint32_t *dst = (uint32_t*)(USB_PMA_BASE + offset * 2);
   const uint16_t *src = (const uint16_t*)data;
   while(count--) {
      *(dst++) = *(src++);
   }
}

int epWrite(int ep, const void *data, int dataLen) {
   if ((ep & USB_ENDPOINT_IN) == 0) return -1;
   ep &= 0x7F;
   if (epTxStatus(ep) == STM32USB_EP_VALID) return 0;
   if (dataLen > epInfo[ep].txBufSize) dataLen = epInfo[ep].txBufSize;
   volatile STM32USBBufferDesc *bufferDesc = bufferTable() + ep;
   copyToBufferArea(bufferDesc->txAddr, data, dataLen);
   bufferDesc->txCount = dataLen;
   epSetTxStatus(ep, STM32USB_EP_VALID);
   return dataLen;
}


У меня epWrite отлично отрабатывает, если dataLen == 0 (адрес назначается нормально). А если я отсылаю дескриптор (в ответ на следующий SETUP-пакет, после установки адреса), то он типа отсылается (даже приходит событие CTR), но хост ничего не получает (в лог ядра Linux сыпятся ошибки таймаута запроса дескриптора), в итоге спустя какое-то время происходит сброс шины и новая попытка.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Чт ноя 19, 2015 19:40:26 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
KIVi писал(а):
то он типа отсылается (даже приходит событие CTR),
Абсолютно идентичная ситуация, а я то думал что сегодня буду уже слать следующие дескрипторы, наивный дурачок блин. После данного события CTR_TX, сразу же "сфотографировал" регистр EP0R в RAM, в полях EP_TYPE значения битов 00 вместо 01. Т.е. bulk вместо control. Фигня какая-то. Попробовал тупо их восстановить на control, без выяснения причины произошедшего, конечно ничего не помогло. Завтра днем попробую покопаться еще, потом наверное времени не будет до декабря.

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Распродажа паяльного оборудования ATTEN!
Паяльные станции, паяльники и аксессуары по самой выгодной цене.

По промокоду radiokot скидка 10%
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Пт ноя 20, 2015 01:04:54 
Встал на лапы

Карма: 3
Рейтинг сообщений: 1
Зарегистрирован: Вс янв 27, 2013 19:02:19
Сообщений: 126
Рейтинг сообщения: 0
Хм... а у меня заработало. Учти, что хост не обязательно сначала назначает адрес, а потом просит дескриптор. У меня наоборот (пробовал тыкать в виндовой комп - там так же как на Linux, только повторов в случае ошибок меньше).
Код:
RESET                                                                                           
SETUP(len=8)
SETUP(type=80, req=06)
DEVICE DESCR requested
NEXT CHUNK (8, 18, EP0R=7270)
SETUP(len=0)
EP0IN complete (EP0R=0x0080)
NEXT CHUNK (8, 10, EP0R=0000)
RESET
SETUP(len=8)
SETUP(type=00, req=05)
SET ADDRESS(0, 14, EP0R = 7270)
EP0IN complete (EP0R=0x72A0)
SETUP(len=8)
SETUP(type=80, req=06)
DEVICE DESCR requested
NEXT CHUNK (8, 18, EP0R=7270)
EP0IN complete (EP0R=0x72A0)
NEXT CHUNK (8, 10, EP0R=7230)
EP0IN complete (EP0R=0x72E0)
NEXT CHUNK (2, 2, EP0R=7270)
SETUP(len=0)
EP0IN complete (EP0R=0x32A0)

У меня при каждом событии USB на USART1 выводится сообщение. Сначала хост запрашивает первые 8 байт дескриптора устройства (я думаю это ради того, чтобы узнать размер пакетов для нулевой конечной точки, чтобы настроить все буферы со своей стороны). Затем устраивает повторный сброс. Затем уже назначает адрес и запрашивает дескриптор устройства целиком.
Код:
[46538.780765] usb 2-1.4: new full-speed USB device number 5 using xhci_hcd
[46538.897523] usb 2-1.4: unable to read config index 0 descriptor/start: -32
[46538.897534] usb 2-1.4: chopping to 0 config(s)
[46538.898162] usb 2-1.4: string descriptor 0 read error: -32
[46538.898275] usb 2-1.4: no configuration chosen from 0 choices

Вот такие сообщения у меня в dmesg. Пришло время готовить дескриптор конфигурации. Хотя не понимаю, почему он у меня его не запрашивает (у меня уже есть заглушка на этот случай, возвращающая пакет нулевой длины).
UPD: У меня всё работает. Важно перевести EP0 OUT в NAK при отправке последней части ответа. Теперь всё отлично. Сейчас дозаполняю дескрипторы и буду пытаться сделать USB CDC.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Чт дек 03, 2015 21:36:36 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
KIVi, получилось у Вас?
Я когда ехал в поезде, читал Агурова. На рис. 3.14 указано что нужно подтверждение транзакций. Типа ZLP чтоли, как то не четко написано. Пару недель назад пробовал отвечать ZLP, на запрос дискриптора, а уж потом отправлять дискриптр. Не знаю на сколько корректно, но не получилось. Пока к этой теме больше не возвращался.
Может Вы решили проблему?

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Вт дек 29, 2015 13:45:23 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
Вернулся я сегодня к ковырянию USB. Тяжело конечно возвращаться к проекту после такого перерыва, ваще ничего не помню :).
Ошибку, почему хост не запрашивал дескриптор конфигурации, я нашел. Дело в том что размер пакета для нулевой точки в дескрипторе устройства должен выбираться из ряда 8, 16, 32, 64 байт. А для HS USB (2.0) - только 64. Я в дескрипторе устройства указал 16 байт и версию по какой-то хер 2.0 (если быть честным просто скопипастил с какого то сайта). Сейчас в дескр. устройств версия 1.1 и размер пакета нулевой точки 16 байт и хост теперь просит конфигурацию. Буду пробовать отправлять ее.

Кто-нить может дать ссылку или кинуть мне на мыло книгу Агурова по USB в нормальном PDF, а то у меня скан.

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Ср дек 30, 2015 03:23:32 
Встал на лапы

Карма: 3
Рейтинг сообщений: 1
Зарегистрирован: Вс янв 27, 2013 19:02:19
Сообщений: 126
Рейтинг сообщения: 0
У меня всё полностью заработало. В смысле вообще всё. Я смог реализовать протокол USB CDC и запилить полноценный виртуальный COM-порт. А ещё я успел переписать весь проект с С++ на С и всё опять заработало. Могу поделиться кодом, если интересно. Сейчас я мучаю плату STM32F4DISCOVERY и пытаюсь завести USB на ней. USB на STM32F4 гораздо более фичастый, но и разбираться с ним труднее. Пока не могу получить ни одного пакета, только RESET и SUSPEND.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Ср дек 30, 2015 05:14:22 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
Я сейчас пробую создать свое HID устройство. Медленно и со скрипом продвигаюсь. Код давайте, спасибо, может и пригодится.

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Ср дек 30, 2015 20:08:19 
Встал на лапы

Карма: 3
Рейтинг сообщений: 1
Зарегистрирован: Вс янв 27, 2013 19:02:19
Сообщений: 126
Рейтинг сообщения: 1
https://github.com/KivApple/controllerF ... stm32usb.c
https://github.com/KivApple/controllerF ... stm32usb.h
https://github.com/KivApple/controllerF ... eric/usb.c
https://github.com/KivApple/controllerF ... eric/usb.h
https://github.com/KivApple/controllerF ... standard.h
Это основные файлы поддержки USB (я разделил платформоспецифичную часть и общую). А вот весь мой проект целиком - https://github.com/KivApple/controllerFramework


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Ср фев 03, 2016 21:15:11 
Родился
Аватар пользователя

Зарегистрирован: Пн фев 01, 2016 17:52:27
Сообщений: 2
Рейтинг сообщения: 1
На STM32F302R8 я освоил периферию USB без CMSIS за неделю (только USB). Всё что я хочу сказать - это было сложно, но можно. Я был суроф и юзал только ARM-компиллер для ассемблера в Keil (вообще не Си). Накодил я 2К прошивки с функциями: ШИМ-пульсогенератор со счётчиком и направлением для драйвера сервы (http://www.adtechen.com/products/QS7AA020M-AC-Servo-Drives.html), квадратурный энкодер (A,B,Z) того же мотора, USB связь между им и демоном UNIX, и ещё пару приятностей. Общее впечатление от игрушки - хорошее, полёт нормальный.

Я тактировал систему так: HSE->PLL=72Mhz, APB1=AHB/2=36Mhz. В моём случае (даже без внешнего кварца на платке) частота USB стала верной сразу, без бита USBPRE. Это зависит от чипа. Ноги PA11/PA12 в альтернативной функции AF0(???). Программную подтяжку DP к питанию искал, но не нашёл, воткнул 1,5Ком от шины.

Я споткнулся на:

- Поймав событие RESET и войдя в обработчик USB_LP_IRQ, я точно ловил токен-пакет SETUP и следующий за ним пакет данных типа DATA0. Всё говорило о том, что контрольная транзакция началась и приняты 8 байт запроса от хоста. Но в Keil MemoryWatch пакетная память (0x40006000) не отображала старшие байты 3 и 4 в каждом слове, и это сильно смущало. Оказалось, что если сдвинуть стартовый адрес MemoryWatch на 1 или 2 байта, всё проявлялось. Особенность эта - невозможность получить из пакетной памяти USB более, чем 2 байта. Прошу учесть схему адресации пакетной памяти: для моего чипа она была [2 полуслова в слове], и, как я понял, есть вторая схема - [одно полуслово с слове], где и адрес надо умножать на 2, и другие доступы надо реализовывать по другому. Таки я вписал в таблицу описаний буферов свои данные для нулевой конечной точки - адреса буферов для приёма и отправки и их размеры.

- Токен SETUP с его данными обработан, моим первым пакетом был SET_ADDRESS от хоста UNIXFreeBSD 10.2. В спецификациях и разных доках самый возможный первый пакет - GET_DEVICE_DISCRIPTOR, но мне повезло. Но не сразу. Получив SET_ADDRESS и сам будущий адрес устройства в пакете, его нельзя сразу применить на деле - транзакция требует завершения пакетом нулевой длины от изначально адресуемого устройства. Изменив адрес сразу, ответный пакет нулевой длины выйдет из устройства с другим адресом. Решением оказалось обработка события SOF: получив пакет SET_ADDRESS, я сделал снимок адреса в память; отвечая пакетом нулевой длины на SET_ADDRESS, я записал в переменную этот факт; ставить бит SOFM в USB_CNTR оказалось не надо - этот флаг USB_ISTR[SOF] будет установлен при следующем событии получения/отправки данных для конечной точки 0 (CTR_RX/CTR_TX), где его (SOF и факт) надо отловить, установить адрес, очистить факт и флаг прерывания SOF в USB_ISTR и покинуть обработчик. Обработчик будет вызван снова, т.к. есть установленные биты в USB_ISTR (например CTR или RESET), но адрес устройства будет новым.

- Адрес установлен. Пошли запросы от OS хоста. GET_DESCRIPTOR_то, _то, и _это. На всё надо ответить корректными данными. Я подглядывал утилитой usbdump во FreeBSD, что откуда и куда. Подглядывал за подопытным - Prolific USBtoCOMtoUART-устройством, которое до этого момента было единственным способом общения с MCU. Как минимум наблюдательность привела меня к правильным ответам моего девайса хосту.

В итоге я иметь подключенный и подруженный с системой UNIX девайс, но без драйверов для оного. Для дальнейшего диалога с чипом пришлось запилить микродрайвер на сишке для писишки на основе libusb - это просто! Там вам и bulk и interrupt и всё такое. Но, как я понял, libusb - это довольно высокого уровня коды и есть возможность понизить задержки от вызова до результата. Но это уже другая тема.

Не скажу, что у меня не осталось вопросов. Код мне не жалко, но выкладывать его сюда - расточительство в плане количества строк. Я не пользуюсь Си для MCU. Но если есть кому необходимость - обращайтесь.


Последний раз редактировалось radiokonb Чт фев 04, 2016 21:05:54, всего редактировалось 1 раз.

Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Чт фев 04, 2016 20:03:53 
Родился
Аватар пользователя

Зарегистрирован: Пн фев 01, 2016 17:52:27
Сообщений: 2
Рейтинг сообщения: 0
Добавлю текста типа наблюдение_t:

- Обрабатывая событие CTR(Correct Transfer) в любом направлении, ждать сервисного пакета ACK/NAK/STALL/DIS от получателя/отправителя стоит только после выхода из обработчика прерывания, т.е. установки его бита ACTIVE=0 в NVIC. Если надолго задержаться в обработке USB_LP_IRQ, возможно потерять доверие хоста (TIMEOUT) и получить пинок или RESET на шине. Естественно, приоритет прерывания должен установить ты, чтобы не потерять ход важных событий.

- Регистры конечных точек USB_EPnR уж сильно извращены: одни биты(CTR_RX/CTR_TX) только чистятся записью только нуля, другие RW, один реадонли, а четвёртые ваще инвертируются записью только единицы. Я пробовал bit-banding, пробовал ORR, но в одном случае (OUT) только обоими способами удалось привести точку в готовность к следующим передачам данных, в другом (IN) справилась ORR. Не стал погружаться, возможно я согрешил лишними тремя инструкциями. Обрабатывая нулевую конечную точку, ни в коем случае нельзя трогать биты DTOG_RX/DTOG_TX, их переключает периферия для правильной последовательности типов передаваемых данных в пределах контрольной транзакции (DATA0 -> DATA1 -> DATA0 и т.д.).

- Сначала написал задержу в 10мс на основе свободного таймера для вроде как каких-то гарантий, но из обработчика RESET задержку эту я убрал за ненадобностью. Возможно в моём чипе приёмопередатчик USB вовсе не ложится спать, или я не всё обрабатываю, конечно же для случая самопитания.

- Сильно огорчён отсутствием DMA-передачи из пакетной памяти USB в SRAM. В мануалах для DMA нет каналов для USB, или есть (stream from APB1), но я чего-то недоузнал. В отчаянии, я вписывал адрес-источник 0x40006000 в DMA_PMAR в другие каналы и активировал их фиктивно, но что толку от переданных двух байт? Пакет USB может содержать сотни, вопрошаю помощи!

- Структура DEVICE_DESCRIPTOR может быть окружена чем угодно. Структура CONFIGURATION_DESCRIPTOR должна соприкосаться с последующими INTERFACE_DESCIPTOR и всеми следующими ENDPOINTn_DESCIPTORs без вставок и паддингов, для каждой конфигурации. Либо придётся скакать, ибо на запрос конфигурации устройство должно отдать всю ветку конфигурации, включая интерфейс и все его конечные точки. Хост запрашивает сначала 8 первых байт дескриптора, берёт из них общую длину всей ветки, и вторым запросом забирает всю структуру. Структура STRING должна начинаться с 0x03xx, где 03 - запрос на неё, xx - длина строки из двухбайтных (unicode) символов +2. Особым строковым дескриптором является поддерживаемый язык, куда я вписал 0x09040403 (03 - строковый дескриптор, 04 - длина, 0x0409 - поддержка ENG).

Ну и напоследок. Ждать от отладчика каких-то актуальных значений USB_EPnR в брейкпойнте совсем не стоит. Периферия она на своей волне. Очищая флаг CTR_RX/CTR_TX, моя железка вела себя не всегда так, как я хотел. Я практиковал смещённый дамп регистров периферии USB в SRAM при каждом входе в обработчик. Труд геркулесов, но только так и понялось, что как и почему.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Пт мар 04, 2016 20:19:06 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
Ну вот, вернулся я к USB. Если я так же будут его изучать по 2 дня в месяц, то видимо к пенсии что-нибудь получится. :)

До запроса репортов я так и не дошел.

Хост у меня запрашивает дескриптор устройства, а затем дескриптор конфигурации. Они у меня такие как тут. После этого у меня приходит запрос строки вот такой
Код:
bmRequestType:  0x80
 bRequest     :  0x06   
 wValue       :  0x03EE 
 wIndex       :  0x0000 
 wLength      :  0x0012

Ладно нашел в просторах инета, что на это отвечают тут и тут. Ответил этой строкой, не поняв зачем.
Код:
const U8 MS_OS_String[] = {
  0x12,   // bLength
  0x03,   // bDescriptorType (STRING)
          // qwSignature
  'M’, 0x00, ’S’, 0x00, 'F’, 0x00, ’T’, 0x00, '1’, 0x00, ’0’, 0x00, '0', 0x00,
  0x01,   // bMS_VendorCode
  0x00    // bPad
};


Тут же приходит новый запрос
Код:
bmRequestType:  0xC0    (Device-to-Host, Vendor, Device)
 bRequest     :  0x01    (bMS_VendorCode, given by MS OS String Descriptor)
 wValue       :  0x0000  (0x00 / interface)
 wIndex       :  0x0004  (Extended compat ID)
 wLength      :  0x0010
wLength именно 0x0010 (в инете 0x0028).
Отвечать на это уже не стал, считая что куда то в дебри лезу с протоколом MTP, откуда он вообще взялся?

Если на запрос строки 0x03EE не отвечать или ответить STALL, то запросов больше никаких не приходит.

Кто может чего подсказать? И еще вопрос, правильно ли я понял, что если хочу ответить STALL, в ответ на запрос данной строки то достаточно выставить биты STAT_TX[1:0] в состояние STALL регистра конечной точки?

Вот еще что, запрос строки 0x03EE приходит только один раз. Чтобы еще раз его получить надо сменить vid или pid.

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Сб мар 19, 2016 15:33:16 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
Написал некую прошивку для STM. Винда приняла устройство HID. Сделал лог для конфигурационных пакетов точки 0, а что отвечал в ответ не логгировал. Очень сильно помогает для понимания обмена. Лог в формате excel, приложу, может кому пригодится. Если в конфиг. пакете поля bmRequestType и bRequest равны нулю - это значит что хост прислал ZLP (пакет нулевой длины) -подтверждение что хост данные успешно принял. Я так понял что stm эти поля сбрасывает при приеме ZLP, иначе чего бы они обнулились. На запрос строки 0xEE я ответил STALL. Еще одной из многих моих ошибок была отправка дескриптора длиннее, чем просит хост, но наоборот можно (хотя во всех книгах об этом было написано).

Правда с репортами я еще пока не разобрался. Использую вот такой дескриптор репорта.
Спойлер
Код:
const uint8_t HID_ReportDesc[]  =

   {

                               0x06, 0x00, 0xff,            // USAGE_PAGE (Vendor Defined Page)
                               0x09, 0x01,                    // USAGE (Vendor Usage 1)
                               0xa1, 0x01,                    // COLLECTION (Application)

                               0x19, 0x01,               //USAGE MINIMUM
                               0x29, 0x01,               //USAGE Maximum

                               0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
                               0x26, 0xff, 0x00,           //   LOGICAL_MAXIMUM (255)
                               0x75, 0x08,                    //   REPORT_SIZE (8)
                               0x95, 10,                       //   REPORT_COUNT (10)
                               0x85, 0x01,                    //   REPORT_ID (1)

                               0xc0                               // END_COLLECTION

   };
Как я понимаю, у меня один репорт IN c id 1. Хост постоянно запрашивает данные от EP1, но ничего не предлагает отправлять в сторону МК. Вроде как логично. МК на каждый запрос отправляет массив из 11 байт, первый и последний (на всякий случай) элементы массивы равны 1 - id1.
Спойлер
Код:
uint8_t In_Pack[]={          //пакет для отправки на комп
    1,1,2,3,4,5,6,7,8,9,1};


Пробую компом что-нибудь получить. Вот таким способом
Спойлер
Код:
   
   char flag=1,buffer[]={1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
   
   HANDLE h=NULL;
   h = CreateFile(m_ConnectedDevice.c_str(),GENERIC_READ,0,0,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0);
   flag=HidD_GetInputReport(h,&buffer[0],11);
   CloseHandle(h);
Функция HidD_GetInputReport (из hid.dll) всегда возвращает false, массив buffer не меняется. Вот собственно и вопрос, как получить пакет данных? Функция CreateFile успешно работает, по хэндолу h, например, успешно получал имя устройства.


Вложения:
Лог USB.rar [14.49 KiB]
Скачиваний: 700

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Вт май 03, 2016 09:24:56 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
Прошли очередные два месяца, вернулся ко своей игрушке.
Ошибка была в неправильном открытии файла со стороны приложения виндовс, надо было так.

Спойлер
Код:
   HANDLE h=NULL;
    h = CreateFile(m_ConnectedDevice.c_str(),
                  GENERIC_READ|GENERIC_WRITE,
                  0,
                  0,
                  OPEN_EXISTING,
                  FILE_FLAG_OVERLAPPED,
                  0);

Затем если пытаюсь считать репорт вот так
Код:
flag=HidD_GetInputReport(h,&buffer[0],11);
, то возращает фальш и буфер неизменен. Код ошибки
СпойлерERROR_GEN_FAILURE
31 (0x1F)
A device attached to the system is not functioning.

А если вот так, то считывает
Цитата:
flag=ReadFile(h,&buffer[0],11,&count,0);


Ладно. Буду дальше мучить.

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Пн май 16, 2016 17:32:51 
Открыл глаза
Аватар пользователя

Зарегистрирован: Пн июн 14, 2010 17:09:55
Сообщений: 45
Откуда: Москва
Рейтинг сообщения: 0
Ух, это я удачно зашел. Тоже начал недавно раскуривать USB на STM32F103C8. И что-то как-то не заладилось. Пробовал CubeMX - тихий ужас. Понятного мало, зато код в половину флеша. Не хочется использовать готовые библиотеки с кучей классов, непонятных функций и пр., нужно простое понимание что и как. В даташите местами мутно написано и от этого еще сложней.
На данный момент контроллер сваливается в прерывание по сигналу Reset от USB. дальше пока туго. Вопросов масса.
1. Почему значение в регистре USB_BTABLE должно быть кратно 8? Как я понял -
Цитата:
Каждая запись таблицы связана с регистром конечной точки и состоит из четырех 16-битных слов ( 8 байт), поэтому начальный адрес должен всегда быть выровнен по границе 8 байт (нижние 3 бита регистра USB_BTABLE всегда “000”)

А контроллер в данном случае наверное "шагает" именно с таким шагом в 8 байт, чтобы попасть в "ширину" этих четырех 16-битных регистров?

2. Или вот - Shared USB/CAN SRAM имеет размер 512 bytes и расположена в диапазоне 0x4000 6000 - 0x4000 63FF – а это 1024 байта. Наверное поэтому значение в USB_ADDRn_TX кратно 2. Тут где-то говорили про умножение адреса на 2, но никак это не пойму. Припоминаю, что это что-то по аналогии dwв AVR, когда в памяти 16-битными словами размещали переменные, а потом обращались побайтно.

Хочу обратиться к Z_h_e - есть ли успехи? Или может где затык - давайте вместе думать.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Пн май 16, 2016 18:03:19 
Собутыльник Кота
Аватар пользователя

Карма: 29
Рейтинг сообщений: 651
Зарегистрирован: Сб май 14, 2011 21:16:04
Сообщений: 2708
Откуда: г. Чайковский
Рейтинг сообщения: 0
Медали: 1
Получил миской по аватаре (1)
Победил я вроде USB. Работает через репорты фьючи, мне этого дастаточно
Radist_M писал(а):
Почему значение в регистре USB_BTABLE должно быть кратно 8? Как я понял
Наверное так модуль USB работает. Для каждой конечной точки есть четыре шестнацибитных регистров, указывающих откуда отправлять данные и куда ложить. Только имейте ввиду, что память 0x40006000-0x400063FF модуль USB видит в своем формате, как 16 битную с адреса 0 (для него не существуют 2 и 3 байта 32х разрядного слова). Тут почитайте, я как раз там мяукал про эту хитрую память.
Понимать тяжело это все и как USB работает и как МК с ней. Но как оказалось возможно :).

_________________
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Низкоуровневая работа с USB на STM32
СообщениеДобавлено: Сб июн 25, 2016 01:16:25 
Грызет канифоль
Аватар пользователя

Карма: 2
Рейтинг сообщений: 27
Зарегистрирован: Вт авг 09, 2011 15:01:44
Сообщений: 271
Откуда: Харьков
Рейтинг сообщения: 0
KIVi, у Вас сейчас есть драйвер USB на STM32F103?
Можете поделится?


Вернуться наверх
 
Показать сообщения за:  Сортировать по:  Вернуться наверх
Начать новую тему Ответить на тему  [ Сообщений: 22 ]  1,  

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 12


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y