Кто любит RISC в жизни, заходим, не стесняемся.
Ответить

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

Пн май 02, 2016 19:18:05

Приветствую форумчан!
Наконец-то появилась возможность продолжить свои практические занятия :beer: . Начал разбираться с USB.
Сделал все как в этой статье: http://microtechnics.ru/stm32-peredacha-dannyx-po-usb/ - работает. Только появились вопросы...
Есть две функции:
/*******************************************************************************/
Код:
void Handle_USBAsynchXfer (void)
{
    if (needToSend == 1)
    {
        uint8_t tempData;
 
   tempData = 0x12;
 
   USB_SIL_Write(EP1_IN, &tempData, 1);
   SetEPTxValid(ENDP1);
    }
}
 
/*******************************************************************************/

и
Код:
/*******************************************************************************/
void EP1_IN_Callback (void)
{
    if (needToSend == 1)
    {
   uint8_t tempData;
 
   tempData = 0x34;
 
   USB_SIL_Write(EP1_IN, &tempData, 1);
   SetEPTxValid(ENDP1);
        needToSend = 0;
    }
}
 
/*******************************************************************************/

Обе передают по 8 байт данных. Почему две передачи разнесены по разным функциям?

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

Ср май 04, 2016 12:31:01

Никаких мыслей? :solder:

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

Чт май 05, 2016 10:03:02

да без проблем. Наверняка это callback функции к каким либо событиям. Просто по обеим событиям делается одно и то же. Ну а что это за события - добро пожаловать в документацию на USB и библиотеку, даташит, код библиотеки и т.д.

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

Чт май 05, 2016 12:20:39

Эти два события обычно используются для bulk endpoint. Вероятно, если после начала фрейма на первый IN запрос контроллер ответит NAK, то хост больше не будет слать IN запросы какое-то время. Так что в Handle_USBAsynchXfer заряжается буфер для первого IN запроса.
Кстати, в STM примерах для bulk эндпоинта забыли сделать отсылку пакета нулевой длинны если данных больше нет, а последний пакет был равен размеру буфера. Если не отсылать такой пакет, со стороны хоста это будет выглядеть как подвисание при чтении.

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

Чт май 05, 2016 12:55:03

Galizin писал(а):Наверняка это callback функции к каким либо событиям.

Handle_USBAsynchXfer(); Эта функция вызывается из коллбэка SOF:
Код:
void SOF_Callback(void)
{
  static uint32_t FrameCount = 0;
 
  if(bDeviceState == CONFIGURED)
  {
    if (FrameCount++ == VCOMPORT_IN_FRAME_INTERVAL)
    {
      /* Reset the frame counter */
      FrameCount = 0;
     
      /* Check the data to be sent through IN pipe */
      Handle_USBAsynchXfer();
    }
  } 
}

Я сейчас читаю книги и статьи по USB (учусь), но такое количество информации просто разрывает мозг, поэтому могу написать глупость... :facepalm:
Как я понимаю, то пакет SOF отправляется хостом для того чтоб спросить устройство, хочет ли оно нам что-то передать. Приняв такой пакет устройство либо отвечает пустым пакетом, либо осуществляет передачу данных через EndPoint-ы. Но тогда появляется вопрос - какого фига данные, впихнутые через функцию SOF вообще отправляются? :dont_know:

BorisSPB писал(а): Так что в Handle_USBAsynchXfer заряжается буфер для первого IN запроса.

Если я Вас правильно понял, то только первая партия данных летит через Handle_USBAsynchXfer(), а остальные через EP1_IN_Callback?
Тогда такой вопрос: размер буфера в обоих случаях будет одинаковым (таким каким мы его объявили в дескрипторе)?
И еще вопрос: получается для отправки третьего пакета данных (если мы передаем одну партию данных) нужно только повторно вызвать EP1_IN_Callback (в данном случае) и скормить ему нужные данные?

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

Чт май 05, 2016 14:01:01

isx писал(а):просто разрывает мозг
Согласен, я тоже не нашел легко написанной книги по этому вопросу.
isx писал(а):какого фига данные, впихнутые через функцию SOF вообще отправляются?
Как я понимаю, то пакет SOF отправляется хостом для того чтоб спросить устройство, хочет ли оно нам что-то передать.
SOF - это начало кадра, и не имеет прямого отношения к устройству.
В STM32 много флагов событий от USB и соответственно прерываний. Я тоже потихоньку мучаю USB (т.е. он меня), только я не использую готовых библиотек. Вроде что-то более-менее получается, конечно с кучей подвисших вопросов в воздухе. Так вот, я использую всего два события, это SE0 (событие подключения устройства к компу) и событие успешного трансфера (в любую сторону). В последнем можно определить направравление передачи и для какой точки.
Смысл такой.
-Сначала инициализируется модуль USB. просто вкючаете, подкючаете генератор и т.д.
- По событию SE0 (воткнули девайс в комп) инициализируете нужные регистры, это событие кстати сбросит их в начальное состояние само.
-Затем устанавливаете в регистре EP0 VALID RX, т.е. МК готов принять данные для нулевой точки.
-Возникает прерывание об успешной транзакции. Расшифровываете и понимаете что что то получили.
- читаете что лежит в буфере приема, там будет запрос дескриптора устройства.
-ложите в буфер отправки дескриптор устройства и выставляете в регистре EP0 VALID TX и контроллер сам все отправит.
-после события об успешной отправки опять переводите МК в состояние в готов принять.

После успешной транзакции состояние VALID само сменится на NACK . Т.е. неготовность принятия или отправки данных. Вы же уже поняли что МК сам ничего не отправит и не примет, только по инициативе хоста. И МК может долго отвечать NACK и хост на это никак не обижается.
Я к тому что мне непонятно зачем отлавливать SOF. Ну пропустили начало кадра, ответит МК NACKом сам, и отвечать будет всегда пока не подготовите данные. Хотя мне непонятно может потом, у что мне в USB много чего еще непонятно.

Если интересно, я в ехселе сделал частичный протокол обменамоего МК по USB/
Последний раз редактировалось Z_h_e Чт май 05, 2016 14:04:20, всего редактировалось 1 раз.

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

Чт май 05, 2016 14:04:01

Если отправлять нечего, то аппаратный буфер будет пустой и контроллер при запросе на этот эндпоинт ответит NAKом. Если размер данных в аппаратном буфере меньше максимального, то хост считает что пачка закончилась и приостанавливает IN запросы.
EP1_IN_Callback вызывается в прерывании USB, если есть данные, заряжаем буфер, если нет - посылаем пакет нулевой длинны и далее ждем до следующего SOF.

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

Чт май 05, 2016 15:06:52

Тоже начал разбираться с USB, правда на STMF3. Хочу отправить данные с датчика (1 байт) данных, но получается вот такое:

Отправляют так:


Вложения
Скриншот 2016-05-05 16.10.06.png
(35.44 KiB) Скачиваний: 3042

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

Чт май 05, 2016 16:23:00

Z_h_e писал(а):Согласен, я тоже не нашел легко написанной книги по этому вопросу.

Тут не только книги, а еще куча всяких статей. Пока читаешь - вроде все понятно, как только переходишь к делу - ступор полный :) .
Z_h_e писал(а):SOF - это начало кадра, и не имеет прямого отношения к устройству.

Я просто не могу понять, почему в этой библиотеке SOF связан с передачей данных...
Z_h_e писал(а):Я тоже потихоньку мучаю USB (т.е. он меня), только я не использую готовых библиотек.

Я тоже не сторонник библиотек (до сих пор даже SPL-ом не пользовался), но боюсь не потяну сразу USB на уровне регистров (хотя подумываю об этом)... :solder:
Z_h_e писал(а):Если интересно, я в ехселе сделал частичный протокол обменамоего МК по USB/

У Вас уже реализован полный обмен данными МК с ПК в обе стороны или пока с дескрипторами разбираетесь? В любом случае, буду признателен если скинете кусок кода с инициализацией и работой USB.
Нужно еще подумать что проще, разбирать код чужой библиотеки, или сразу перейти на регистры... :dont_know:
BorisSPB писал(а):EP1_IN_Callback вызывается в прерывании USB, если есть данные, заряжаем буфер,

Пока понять еще не могу, как обновляются данные буфера между отправками? Вот зарядили мы первую партию в EP1, затем отправили их, после этого ждем срабатывание SOF, обновляем данные и отправляем - и так по кругу. Я правильно понимаю?
FireProoF писал(а):правда на STMF3

Я кстати тоже) . В статье (адрес в первом посте) производится отправка на МК 2 байт, с последующим приемом МК 2 байт. Статья из трех частей. Я по ней деле проект - он заработал, но пока не совсем ясно каким образом :) . Посмотрите, может чем поможет....

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

Чт май 05, 2016 16:39:14

Я тоже с неё начал)
С отправкой чисел разобрался.
Теперь встал вопрос частоты отправки данных. У меня отправка происходит по переполнению таймера. Эксперементальным путём установил, что при частоте переполнения свыше 150 Гц stm32 перестаёт определяться компьютером. На 100 Гц всё норм.
Добавил задержку перед включением таймера. Вроде подключилось, открыл терминал, а он повис. Подождал чуток, отсоединил стм. На терминале показались данные. Видимо комп не справляется с потоком? :(
Не могли бы Вы проделать такой же эксперимент, дабы убедиться, что при частой отправке данных, линия зависает?

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

Чт май 05, 2016 17:06:31

isx писал(а):У Вас уже реализован полный обмен данными МК с ПК в обе стороны или пока с дескрипторами разбираетесь?
Вроде как допилить осталось чуток. И в божеский вид привести. Но это вроде. Я сначала через первую точку хотел обмен сделать, даже принял данные через winapi функцией READFILE. Но если данных нет, то там зависнешь. HidD_GetInputReport из библиотеки HID.dll отказалась читать, сейчас уже есть предположение почему.
Решил через Feature репорты обмен делать. Вроде получилось и пока ничего больше не делал, надо пнуть себя и сегодня еще поработать. Вобщем то о своих мытарствах я тут писал, надо будет туда и дописать чем дело кончилось, приведу код в боле менее вид, может и скину. А сама инициализация вот она, она простая. Только радиокот все табуляции кода выкинул, почти все сплошняком.


Мой контроллер STM32F103C8.

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

Чт май 05, 2016 21:37:26

Данные хосту отправляются автоматически по IN запросу если в аппаратном буфере что-то есть, запись в аппаратный буфер происходит с помощью
Код:
USB_SIL_Write(EP1_IN, &tempData, 1);

Обменом управляет хост, насильно хосту данные не скормить, только по IN запросу.
HID устройство удобно тем что не нужен специальный драйвер, но скорость ограничена 64 кб/сек. Если в дескрипторе HID для типа устройства указать нули, обмен можно производить пакетами с помощью ReadFile/WriteFile, за разбор пакета при этом отвечает приложение.

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

Пт май 06, 2016 12:52:52

Очередной раз убедился в том, что ковырять чужие библиотеки - для меня проблема... Даже не смог найти выход к регистрам USB через SPL :dont_know:
Решил идти с нуля, чтоб уж точно знать, как оно там работает. По пути буду снабжать код подробными комментариями (может кому в будущем пригодится) ибо для себя я такого примера так и не нашел.
P.S. За пол года перерыва в практике общения с паяльником и кодом многое подзабылось, поэтому не пинайте сильно.

Итак, начинаем с самого начала:



Делал на основе вскрытия библиотеки USB-FS. Если с GPIO все понятно, то вот докопаться до сути EXTI так и не вышло. С SPL ранее не работал, поэтому так и не нашел на какие регистры воздействуют эти строки:
Код:
  EXTI_InitStructure.EXTI_Line = EXTI_Line18;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;

У себя в коде прописал как самому показалось верным. :dont_know:
Итак, Set_System(); разложена, поехал ковырять Set_USBClock();
Прошу поглядеть на код, может где-то напортачил или поставил не соответствующий комментарий... :)

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

Сб май 07, 2016 12:19:20

Расковырял Set_USBClock();. Добавилось всего 2 строчки. Выносить тактирование USB в отдельный блок не стал, поэтому просто добавил в общий код. Инициализацию переписал немного, заодно уточнил некоторые комментарии:

Добавил:
Код:
RCC->CFGR |= RCC_CFGR_USBPRE; // Настраиваем частоту USB (= частота ядра / 1.5)
RCC->APB2ENR |=   RCC_APB1ENR_USBEN; // Включаем тактирование USB от шины APB1

Идем к USB_Interrupts_Config(); :kill:

Спустя ХХ минут.


Оказалось, отчасти USB_Interrupts_Config(); уже была мной написано в код. Как я понял, эта функция работает с:

Код:
  NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
 // NVIC_SetPriority(USB_LP_CAN1_RX0_IRQn);   
  NVIC_EnableIRQ(USBWakeUp_IRQn);    
 // NVIC_SetPriority(USBWakeUp_IRQn, 3);

однако, сразу поперли вопросы... :solder:
Помимо USB_LP_CAN1_RX0_IRQn, есть USB_HP_CAN1_TX_IRQn. Почему используется именно она, в чем их разница и вообще, за что они отвечают? :dont_know:
И еще, вопрос по приоритетам. Как их выставлять? Запустил рабочий код с USB (про который я говорил в первом посте), там приоритет USB_LP_CAN1_RX0_IRQn стоит 128, а USBWakeUp_IRQn приоритет 1. Можно конечно и просто подставить эти значения, но хочется таки разобраться....
Пока пойду ковырять самую веселую часть инициализации - USB_Init(); :) .

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

Вс май 15, 2016 13:08:19

В общем наковырял всю инициализацию и проверил (проект перенес на Keil 5, так как там оказался полезный файлик - stm32f303xc.h, который заменяет stm32f30x.h и имеет дополнительно прописанные регистры USB).
Вот что получилось:


В отладке все работает правильно. Теперь нужно переходить к самому USB.

Как я понял, раскуривая стандартные библиотеки, начинать нужно с подтяжки D+ к питанию через специальный регистр, но такого я в мануале на свой камень не нашел :dont_know:
Дальше идут следующие действия:

Код:
                                                         
// здесь должна быть подтяжка резистора
USB->CNTR &= ~USB_CNTR_PDWN; //подаем питание
USB->CNTR |= USB_CNTR_FRES; //На всякий случай устанавливаем флаг (хотя он итак должен стоять при включении)
USB->CNTR = 0; // в результате FRES сбрасывается в ноль, происходит ресет и генерируется прерывание USB_LP_IRQHandler.   


В итоге, единственный мост для нашего общения с USB - это прерывание USB_LP_IRQHandler, значит в нем и происходит дальнейшая работа.
С помощью флага определяем - от чего произошло прерывание. Первое прерывание, как я понял, произойдет сразу же, по FRES. Затем, уже в прерывании:

Код:
void USB_LP_IRQHandler(void)
{
 if(USB->ISTR & USB_ISTR_RESET)
    {
USB->ISTR = 0;  // сбрасываем флаги
USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM | USB_CNTR_CTRM; // настраиваем маски и включаем прерывание по завершению передачи
........
}
......
}


Дальнейшее поведение библиотеки отследить не удалось. Скорее всего дальше происходит настройка нулевой контрольной точки, но в какой последовательности все это происходит в камне - не известно. :dont_know:
Перечитываю кучи статей на сайтах, но описания пока не могу найти. Буду признателен, если ткнете на подобную статейку или дадите какую-нибудь подсказку...

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

Вс май 15, 2016 13:32:44

Не знаю как там в библиотеке. Вот моя функция, которая вызывается по прерыванию SE0
USB->CNTR |= USB_CNTR_FRES; //На всякий случай устанавливаем флаг (хотя он итак должен стоять при включении)
Я FRES наоборот сбросил.Вот корявенький перевод REFERENCE, но мне помог.

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

Вс май 15, 2016 15:01:06

Z_h_e писал(а):Я FRES наоборот сбросил

Ну у меня сначала устанавливается, а потом сбрасывается (прочитал где-то, что на всякий случай лучше перед сбросом устанавливить флаг).
Z_h_e писал(а):Вот корявенький перевод REFERENCE, но мне помог

Тоже напал на него час назад. Четвертый раз перечитываю, многое проясняется :) .
Z_h_e писал(а)://Настройка буфера EP0
   DiscrTable->ADR0TX=0x0040;
   DiscrTable->COUNT0TX=0x0000; //макс 0x80
   DiscrTable->ADR0RX=0x0100;
   DiscrTable->COUNT0RX=0b1011000000000000; //размер буфера 0x80 (128)байт

Вот пока главный вопрос - откуда берутся значения этих адресов?

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

Вс май 15, 2016 16:12:21

isx писал(а):Вот пока главный вопрос - откуда берутся значения этих адресов?
Я их сам определил, т.е. сделал такими какие мне нужны. Есть область памяти
0x4000 6000- 0x4000 63FF. Именно с ней работает USB. Есть хитрый момент, 2 и 3ый байты слова в этой области недоступны (т.е. как 16битнай память). Модуль USB работает как 16 битной памятью с адреса 0, ядро как 32ух с адреса 0x4000 6000. Вы определяете область памяти для каждой конечной точки. Например Вы указали адрес
Код:
DiscrTable->ADR0RX=0x0100;
. Это значит что данные, которые придут от компа в МК для конечной точки 0, будут лежать по адресу 0x40006000+0x0100*2. Регистры с адресами (таблица дескрипторов) лежит в этой же памяти. Адрес таблицы указывается в регистре USB_REGISTR->BTABLE=0. Такая запись указывает что таблица находится по адресу 0x4000 6000+0*2.


Это еще что, поглядите как устанавливаются биты регистров конечной точки USB_EPnR. Часть битов обычный доступ, часть только чтение, часть стирание 0, а часть типа togle (инвертирование при записи 1). Так что тут конструкция R|=(n<<m) просто так не сработает.

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

Пт май 20, 2016 20:56:03

Наконец-то вернулся к теме :) .
Z_h_e писал(а):Я их сам определил, т.е. сделал такими какие мне нужны. Есть область памяти
0x4000 6000- 0x4000 63FF. Именно с ней работает USB.

Пока я не могу понять, почему нельзя просто сделать эти адреса друг за другом :dont_know: . Например, указываем адрес для входящих данных EP0 (образно) 0х00, длину - 0х09. Затем указываем для исходящих данных адрес 0х10, длину 0х19 и.т.д. Почему, часто, в дескрипторе эти адреса разбросаны?
Z_h_e писал(а): Адрес таблицы указывается в регистре USB_REGISTR->BTABLE=0. Такая запись указывает что таблица находится по адресу 0x4000 6000+0*2.

И зачем здесь вообще указывать что-то другое, если можно поставить ноль, и плясать от него? :dont_know:
P.S. Уверен, что эти тупые вопросы от непонимания происходящего :dont_know: . Но это только пока не разберусь. Как разберусь, будут другие тупые вопросы :))) .

Z_h_e писал(а):Это еще что, поглядите как устанавливаются биты регистров конечной точки USB_EPnR.

Глядел. Пока все прозрачно вроде, но уверен, как только дойду до практики, грабли дадут о себе знать (да и лето как-никак, пора бы им уже поработать :) )

И вот еще понял, что нифига не понимаю что в этой строке происходит:
Код:
USB->CNTR |= USB_CNTR_RESETM | USB_CNTR_SUSPM | USB_CNTR_WKUPM;

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

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

Сб май 21, 2016 07:55:55

isx писал(а):Пока я не могу понять, почему нельзя просто сделать эти адреса друг за другом
Очень даже можно. Только надо помнить, что там же таблица адресов.
isx писал(а):И зачем здесь вообще указывать что-то другое, если можно поставить ноль, и плясать от него?
Ну можно ж ее в конце памяти разместить, а буфера тогда можно с самого начала или несколько таблиц иметь и переключать их.
isx писал(а):Глядел. Пока все прозрачно вроде, но уверен,...
Предствате что у Вас биты STAT_TX[1:0] устновлены в 10 (NACK). А Вам надо установить в состояние 11 (VALID) . Тогда такая конструкция EP|= STAT_TX1 | STAT_TX0 не прокатит.
isx писал(а):Что за "маски" тут настраиваются?
Дык маски ж прерываний. Но я включил только CTRM и RESETM. Мне хватило этого.
Если нет, то что будет если включить прерывание, а маску нет?
Прошел по USB пакет SOF. Тут же в регистре USB_ISTR устанавливается флаг SOF (он так и будет висеть пока не сбросите), но так как у меня маска SOFM не установлена, то прерывание не возникнет.

Прерывание для всех событий USB одно. Вам надо самому разбираться в нем из-за чего прерывание возникло.
Ответить