Страница 5 из 30
Re: STM32 и USB (практика)
Добавлено: Пн июн 13, 2016 20:59:50
Serg1987
Если не ошибаюсь, то момент соединения с шиной обозначается прерыванием по РЕСЕТ.
У меня в STM32F303 тоже нет бита подтяжки. На плате резистор тупо припаян.
Собрал схему, для проверки достал где-то ещё завалявшуюся плату STM32 H-103.
По поводу событий при подключении..
прерывание по РЕСЕТ.?
Нет, мне кажется, не совсем так. Подробнее. Первое событие RESET - это сброс FRES. Тут мы включаем тактирование, настраиваем флаги и т.д. По первому РЕСЕТу мы только конфигурируем и настраиваем девайс. Но на данном этапе данный RESET никак не свидетельствует о подключении шины.
Об подключении к шине непосредственно свидетельствует второй РЕСЕТ (флаг в ISTR первого РЕСЕТа не забываем очистить), о котором и упомянул Z_h_e, и который отправляется уже хостом. Но до этого хаб определяет наличие подтяжки D+. Тут я и стал.(Схему собрал, но не работает). Какое событие отвечает за обнаружение подтяжки D+. ?
Весь процесс я понимаю, идет так:
- после включения девайса (только девайса, без подключения к шине) (и после конфигурирования модуля)устанавливается событие SUSP (более 3мс отсутствия активности на шине). Контроллер успешно уводит девайс в данный режим. Выставляется флаг. Флаг от первого РЕСЕТа (который по сбросу FRES) очищаем. Ждем второго РЕСЕТа от компа.
- в это время (после установления SUSP) при подключении к шине должно произойти событие WKUP

(пробуждение устройства и сброс бита low-power mode). Т.е. тут девайс должен определить наличие подтяжки и дать компу информацию о своем присутствии на шине.
Но последнее (именно событие
WKUP) почему-то не проходит. Втыкаю девайс в комп - прерывание по WKUP молчит. Такое на двух платах. И на своей и на заводской от Olimex.
Re: STM32 и USB (практика)
Добавлено: Ср июн 15, 2016 09:45:36
Serg1987
Уже совсем замучился. Девайс стабильно уходит в режим приостановки SUSPEND. Именно это прерывание и срабатывает.

Re: STM32 и USB (практика)
Добавлено: Ср июн 15, 2016 11:11:15
Serg1987

В общем вот. Всё перепроверил. Вроде всё верно. Но при подключении шнура USB комп ожидаемый Reset не отдает ну никак. При включении прерывания SUSP (пока закомментил) устройство уходит в приостановленный режим. РЕСЕТа нет.
Код: Выделить всё
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "defusb.h"
void UsbInit();
//Инициализация USB
void UsbInit()
{
//делитель USB равен 1
RCC->CFGR |= RCC_CFGR_USBPRE;
//Разрешаем USB
RCC->APB1ENR |= RCC_APB1ENR_USBEN;
//Включаем USB
USB->CNTR &= ~USB_CNTR_PDWN;
//Тактируем
USB->CNTR &= ~USB_CNTR_FRES;
//Очистка флагов событий USB
USB->ISTR = 0;
//Разрешаем прерывания
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
NVIC_SetPriority (USB_LP_CAN1_RX0_IRQn, 2);
NVIC_EnableIRQ(USBWakeUp_IRQn);
EXTI->RTSR |= EXTI_RTSR_TR18; // прерывание №18
EXTI->IMR |= EXTI_IMR_MR18; // прерывание по выводам
EXTI->EMR |= EXTI_EMR_MR18; // прерывание по WU
//Настройка масок прерываний
USB->CNTR |=USB_CNTR_RESETM;
//| USB_CNTR_CTRM
//| USB_CNTR_WKUPM
//| USB_CNTR_PMAOVRM
//| USB_CNTR_ERRM
//| USB_CNTR_WKUPM
//| USB_CNTR_SUSPM
//| USB_CNTR_RESETM
//| USB_CNTR_SOFM
//| USB_CNTR_ESOFM;
}
int main(void)
{
__enable_irq ();
//*****Настройка тактирования
//сброс системы тактирования
RCC_DeInit();
//Включаем HSE
RCC->CR |= RCC_CR_HSEON;
//Ждем готовности HSE
while((RCC->CR & RCC_CR_HSERDY) == 0) {}
//Предделитель AHB
RCC->CFGR |= RCC_CFGR_HPRE_0;
//Очистка регистра умножителя PLL
RCC->CFGR &= ~RCC_CFGR_PLLMULL;
//источник PLL от внешнего кварца
RCC->CFGR |= RCC_CFGR_PLLSRC_HSE;
//умножитель PLL x6
RCC->CFGR |= RCC_CFGR_PLLMULL6;
//Включаем PLL
RCC->CR |= RCC_CR_PLLON;
//Ждем готовности PLL
while((RCC->CR & RCC_CR_PLLRDY) == 0) {}
//очистка регистра SW
RCC->CFGR &= ~RCC_CFGR_SW;
//выбор источника тактирования PLL
RCC->CFGR |= RCC_CFGR_SW_1;
//Ожидание включения PLL
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_1) {}
//Включим тактирование - порт A, B,C и альтернативного режима
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN|RCC_APB2ENR_AFIOEN;
//Очищаем регистр альтернативных функций
//AFIO->MAPR &= 0xFFFFFFFE;
// НОЖКА C9
GPIOC->CRH &= ~GPIO_CRH_CNF12_0 & ~GPIO_CRH_CNF12_1;
GPIOC->CRH |= GPIO_CRH_MODE12;
GPIOC->ODR |= GPIO_ODR_ODR12;
UsbInit();
while(1)
{
}
}
void USB_LP_CAN1_RX0_IRQHandler(void)
{
USB->BTABLE=0;
//Втыкаем и ждем сброса от хоста
if ((USB->ISTR & USB_ISTR_RESET))
{
USB->ISTR &= ~USB_ISTR_RESET;
USB_Reset();
return; //выходим из обработчика прерываний
}
}
Есть мысли? Резистор стоит. Подтяжка внешняя. При выставлении SUSP в CNTR уходит в Suspend (т.е. спячку)
Re: STM32 и USB (практика)
Добавлено: Ср июн 15, 2016 15:52:27
Radist_M
А может ну его нафиг эти SUSP и WKUP?
На первых порах мне хватало 2-х событий - RESET и CTR (correct transfer).
Код: Выделить всё
void USB_INIT(void)
{
RCC->CFGR |=RCC_CFGR_USBPRE;//выставляю делитель на 1 (работаю сразу на 48МГЦ)
RCC->APB1ENR |= RCC_APB1ENR_USBEN;//USB clock enabled
USB->CNTR &= ~USB_CNTR_PDWN;// включаю USB
delay(8);//ждем примерно 1 мкс пока не запустится внутренний ИОН
//
USB->CNTR = 0;//и очищаю FRES
delay(1);//ждем немного, чтобы установился флаг резета
USB->ISTR = 0;//и сбрасываю этот флаг, т.к. всю настройку буду производить уже пофакту резета от компа
USB->CNTR = USB_CNTR_RESETM|USB_CNTR_CTRM;//enable reset interrupt, correct transfer
descr_init();//тут инициализирую таблицу дескрипторов
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);// включаю нужное прерывание
}
Вот задержка на всякий случай
Код: Выделить всё
void delay(uint32_t val)
{
for(;val!=0;val--)
{__nop();}
}
Re: STM32 и USB (практика)
Добавлено: Ср июн 15, 2016 19:50:02
isx
Z_h_e
Скиньте пожалуйста обработчик CTR. Я что-то совсем замучался, не идет второй запрос и все

Re: STM32 и USB (практика)
Добавлено: Чт июн 16, 2016 16:18:14
Serg1987
Продолжу о своих приключениях. Всё разрешилось. На отладочной плате всего-то сгорел буферный транзистор, из-за чего не было подтяжки к D+, и соответственно поэтому не приходил долгожданный RESET. Идем дальше. Сейчас вожусь с контрольными точками и дескрипторами. С первыми вроде всё ясно, но не до конца. Так и не понял, как их настраивать. Перечитал всю ветку. Но так и не понял.
Значения скопипастил из постов.

Re: STM32 и USB (практика)
Добавлено: Чт июн 16, 2016 17:04:18
isx
Спрашивайте конкретнее что не понятно. У меня уже появилось некоторое представление, может чем и помогу

Re: STM32 и USB (практика)
Добавлено: Чт июн 16, 2016 23:02:21
Serg1987
С таблице контрольных точек вроде как разобрался немного. Итак.
Вот.

Итак. С адресами всё вроде понятно.
Вопрос тут следующий:
Код: Выделить всё
//Настройка буфера 0
Table->ADR0TX=0x0000;
//количество данных для передачи хосту (32 байт)
Table->COUNT0TX=0x0020;
Table->ADR0RX=0x0100;
//количество принимаемых данных от хоста(32 байт)
Table->COUNT0RX=0x00004000;
Значение COUNT0RX взял из вашего примера. Но непонятно до конца.
Как именно хекс 0x00004000 соответствует 32-м байтам?
Следующий вопрос. Не до конца понятно, как получить доступ к принятым данным в буфере.
А именно как его прочесть.
Я правильно понимаю, что в USB_ADDRn_RX хранится адрес буфера.
Это значит что данные, которые придут от компа в МК для конечной точки 0, будут лежать по адресу 0x40006000+0x0100*2.
В данном случае данные будут лежать по адресу 0x40006200?!
Но то адрес!.. Туплю. А как с него данные то толком извлечь? Определяю, что мне приходит SETUP пакет. Как вскрыть его содержимое - пока не дошел.
isx, посмотрел ваш код. Меня тут смущает, что адрес приемного буфера у вас нечетный. (выделил) -
0x400060C1. Как такое получилось?
Спойлер
switch (*(__IO uint32_t*)(0x400060C1))
{
case 0x6:
for (i = 0; i < 18; i+=2)
{
TXBuff = Virtual_Com_Port_DeviceDescriptor + (Virtual_Com_Port_DeviceDescriptor[i+1] <<
;
*(__IO uint16_t*)(0x40006080 + i*2) = TXBuff;
}
*(__IO uint32_t*)(0x40006004) = 0x0012;
USB->EP0R |= USB_EP_TX_VALID;
test1 = USB->EP0R |= USB_EP_TX_VALID;
USB->EP0R |= USB_EP_RX_VALID;
break;
}
Z_h_e. Поясните, пожалуйста, участок кода при заполнении передающего буфера.
Почему здесь идет умножение на 2.?
Re: STM32 и USB (практика)
Добавлено: Пт июн 17, 2016 13:15:13
Serg1987
А, всё. Кажись въехал.!
Так понимаю, нечетный адрес получается, т.к. мы считываем поле Request из пакета SETUP, а у байта Request собственное смещение = 1?
Правильно?
Re: STM32 и USB (практика)
Добавлено: Пт июн 17, 2016 13:33:40
isx
Serg1987 писал(а):Почему здесь идет умножение на 2.?

Мы берем адреса, которые использует USB, а их значение в два раза меньше.
Serg1987 писал(а):Значение COUNT0RX взял из вашего примера. Но непонятно до конца.
Как именно хекс 0x00004000 соответствует 32-м байтам?
Это значение имеет только одну единицу (в бинарном представлении) в бите номер 14. Посмотрить, что это значит в регистре COUNT0RX, а затем загляните в таблицу, которая под этим регистром в даташите.
Serg1987 писал(а):В данном случае данные будут лежать по адресу 0x40006200?!
Но то адрес!.. Туплю. А как с него данные то толком извлечь?
*(__IO uint16_t*)(0x40006080) = TXBuff;
По каждому значению адреса в памяти хранится 4 байта информации, но 3-й и 4-й байты недоступны. Соответственно в моем примере TXBuff получит два байта из адреса. Делаем цикл и читаем данные как из массива в массив.
Вроде так

.
P.S. А вообще, значение адреса онлайн можно посмотреть в отладчике в KEIL ) .
Re: STM32 и USB (практика)
Добавлено: Пт июн 17, 2016 14:14:29
Serg1987
разбираю его - все четко:
Код: Выделить всё
0x80
0x06 - вот оно - Запрос дескриптора устройства
0x00
0x01
0x00
0x00
0x40
0x00
Да. Но вообще, если делать грамотно, то первый байт нужно также учитывать. Вообще по спецификации бывает 3 запроса на дескриптор (в основном):
GET_DESC_DEVICE:
0x8006
GET_DESC_INTERFACE:
0x8106
GET_DESC_ENDPOINT:
0x8206
Так что учитывать необходимо 2 байта. Я думаю, до этого сам дойду. Пока для отладки использую мониторинг на 0x06, будучи уверенным, что придет именно GET_DESC_DEVICE.
Re: STM32 и USB (практика)
Добавлено: Пт июн 17, 2016 14:21:51
Serg1987
Код: Выделить всё
Мы берем адреса, которые использует USB, а их значение в два раза меньше.
Спасибо, вроде начал вьезжать.
А, понял. Объем памяти в блоке у нас 2 байта (15 бит равен 0). А в поле NUM_BLOCK записано количество блоков. В данном случае в десятичном представлении - это 0d16. 16*2=32.
Поле COUNTn_RX[9:0] заполняется после прихода данных и содержит информацию о кол-ве принятых байт.
Вроде стало на свои места всё.

Re: STM32 и USB (практика)
Добавлено: Пт июн 17, 2016 15:28:29
Serg1987
Все равно где-то что-то не то..
Итак. По участку кода всё проходит отлично:
На сей раз заодно решил светодиодом поиграть
Код: Выделить всё
switch (*(__IO uint32_t*)(0x40006081))
{
case 0x06:
GPIOC->BRR |= GPIO_ODR_ODR12;
break;
}
Request 0x06 читается.
Но при попытке прочитать значение из адреса 0x40006080 (самый первый байт. ожидаю там 0x80), то этого значения там нет.
Может чего не так делаю.??
Вот, подрисовал рисунок в файле во вложении.
Если у меня читается второй байт по адресу 0x40006081 (значение 0x06. как и должно быть), то почему не читается первый по адресу 0x40006080??
Re: STM32 и USB (практика)
Добавлено: Пт июн 17, 2016 17:16:16
isx
Посмотрите в отладчике, какие там у вас значения по адресам.

Здесь в строке адреса указано C0, так как в регистр прописано 60 (в два раза меньше, помним

). Так можно посмотреть что на самом деле пришло нам в буфер.
P.S. Проглядел. Посмотрите внимательно, что у вас в CASE записано

.
Вообще не понятно. У вас по адресу .....81 читается 0x06, хотя должно быть 0x60. Возможно вам приходит что-то не то....

Re: STM32 и USB (практика)
Добавлено: Сб июн 18, 2016 00:04:13
Radist_M
Serg1987, а напишите как считываете значение из 0x40006080 и как узнали что не то?
Мне всю дорогу приходит 0x80 0x06 и т.д. 0x81 не встречал.
Re: STM32 и USB (практика)
Добавлено: Сб июн 18, 2016 09:49:01
isx
Все испробовал. Понятия не имею почему второй запрос не идет. Как только регистры и адреса уже не вертел, но в приемник залетает только дескриптор устройства.
Спойлер
Код: Выделить всё
void USB_LP_CAN_RX0_IRQHandler(void)
{
if (USB->ISTR & USB_ISTR_CTR)
{
while ((USB->ISTR & USB_ISTR_CTR) != 0)
{
if ((USB->EP0R & USB_EP_CTR_RX) != 0)
{
USB->EP0R &= ~USB_EP_CTR_RX;
switch (*(__IO uint32_t*)(0x40006101))
{
case 0x6:
for (i = 0; i < 18; i+=2)
{
TXBuff = Virtual_Com_Port_DeviceDescriptor[i] + (Virtual_Com_Port_DeviceDescriptor[i+1] << 8);
*(__IO uint16_t*)(0x40006080 + i*2) = TXBuff;
}
*(__IO uint32_t*)(0x40006004) = 0x0012;
USB->EP0R |= USB_EP_RX_NAK;
USB->EP0R |= USB_EP_TX_VALID;
test1 = USB->EP0R |= USB_EP_TX_VALID;
USB->EP0R |= USB_EP_RX_VALID;
break;
}
}
}
if ((USB->EP0R & USB_EP_CTR_TX) != 0)
{
USB->EP0R |= USB_EP_RX_VALID;
}
i = 0;
}
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; // размер исходящих данных - 32 байта USB_COUNT0TX
*(__IO uint32_t*)(0x40006008) = (uint16_t) 0x80; // начальный адрес USB_ADDR0_RX
*(__IO uint32_t*)(0x4000600C) = (uint16_t) 0x8400; // 32 байта входящих данных USB_ USB_COUNT0RX_BL_SIZE
USB->EP0R |= USB_EP_CONTROL; // режим - CONTROL
USB->EP0R |= USB_EP_TX_NAK; // Готовы к передаче, но данных для передачи нет
USB->EP0R |= USB_EP_RX_VALID; // К приему готов
test1 = *(__IO uint32_t*)(0x40006100);
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, // протокол
0x40, // USB_MAX_PACKET0, // max размер пакета для нулевой конечной точки
0x83, 0x04, // 2 байта - VID
0x40, 0x57,// 2 байта - PID
0x00, 0x02,// 2 байта - версия (ревизия) устройства
0x01, // индекс строки с названием производителя
0x02, // индекс строки с названием устройства
0x03, // индекс строки с серийным номером устройства
0x01 // количество поддерживаемых конфигураций
};
Подскажите пожалуйста, что делать. Я уже перепробовал все, что в голову пришло....

Re: STM32 и USB (практика)
Добавлено: Вс июн 19, 2016 07:44:47
Z_h_e
Некогда пока мне не в форуме участвовать, ни самому с USB ковыряться. После 21 должно время появится, так как я буду на работе

.
isx писал(а): USB->EP0R |= USB_EP_RX_NAK;
USB->EP0R |= USB_EP_TX_VALID;
test1 = USB->EP0R |= USB_EP_TX_VALID;
USB->EP0R |= USB_EP_RX_VALID;
Четвертый раз говорю, пройдите по шагам все эти строки чудо кода и мониторьте регистр EP0R (с отключенным МК от USB).
Проверьте флаг успешной отправки, которого я думаю нет и соответственно нет в ответ на него (от хоста к МК) пакета ZLP.
Да, я разрешал прием и передачу поочередно, но возможно это неважно.
Serg1987 писал(а):Да. Но вообще, если делать грамотно, то первый байт нужно также учитывать.
Правильно учитывать все поля запроса и обрабатывать неизвестный запрос тоже.
Serg1987 писал(а):switch (*(__IO uint32_t*)(0x40006081))
{
case 0x06:
GPIOC->BRR |= GPIO_ODR_ODR12;
break;
}
Если Вы считываете один байт, то и указатель тоже должен быть на байт, но не на 32 бита.
isx писал(а):У вас по адресу .....81 читается 0x06, хотя должно быть 0x60. Возможно вам приходит что-то не то....

Нет, 0x06.
Radist_M писал(а):Мне всю дорогу приходит 0x80 0x06 и т.д. 0x81 не встречал.
Вот запрос дескриптора репорта HID, видимо у Вас не HID
Код: Выделить всё
bmRequestType 0x81
bRequest 0x6
wValue 0x2200
wIndex 0x0
wLength 0x94
Re: STM32 и USB (практика)
Добавлено: Вс июн 19, 2016 08:17:29
isx
Z_h_e писал(а):После 21 должно время появится, так как я буду на работе
Что у Вас за работа такая, на которой есть время сидеть на форумах?
Z_h_e писал(а):Проверьте флаг успешной отправки, которого я думаю нет
Его и нет - прерывание по CTR не возникает. Только вот не ясно почему... Последнее, что удается отследить в отладке - это как USB_EP_TX становится в VALID, а потом в 0. При этом флаг ошибки тоже не срабатывает (тоже включал прерывание по ERR для диагностики).
Буду ждать следующей недели, а пока попробую еще куда-нибудь ковырнуть

.
Re: STM32 и USB (практика)
Добавлено: Вс июн 19, 2016 08:28:51
Z_h_e
Да ёлки-палки,
isx 
. Пускай есть упрощенный 4х битный регистр EP (r1 r0 t1 t0), начальное состояние 0. Все биты типа тогл. Вы хотите установить прием и передачу в VALID, т.е. 0b1111. Что Вы делаете
Результат:
Код: Выделить всё
EP==0//начальное состояние
EP==0b1100
EP==0b0011
Так понятно или написать как работает конструкция
|= ??? Ах, да, я же уже писал и это. И не верю я, что в отладке этого не видно.
Re: STM32 и USB (практика)
Добавлено: Вс июн 19, 2016 11:15:40
isx
Это понятно, только вот после отработки установленного значения TX/RX они автоматически обнуляются.
Вот скрин. После каждого шага значение регистра EP0 заносится в отдельную переменную. Как видим, все, по какой-то причине, отрабатывается правильно, но тугл так работать не должен

.
