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

Кто любит RISC в жизни, заходим, не стесняемся.
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

Спасибо за помощь. Оказалось, что проблема и правда в юарте: у меня почему-то не отправляются (или не принимаются в консоль) байты 0x11, 0x12, 0x13. Буду сейчас для начала с этим пытаться разобраться
Реклама
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

Здравствуйте.
Теперь столкнулся с такой проблемой - получаю URB_interrupt in запросы от хоста на первую оконечную точку после того, как передал дескриптор репорта, но все ответы (девайс -> хост) имеют статус USBD_STATUS_XACT_ERROR (смотрю через WIRESHARK), хотя я даже не могу получить прерывание по ней. Все дескрипторы для клавиатуры брал вот отсюда https://www.usb.org/sites/default/files/hid1_11.pdf стр. 66 с небольшими изменениями, чтобы убрать один интерфейс под мышь. В системе устройство определяется корректно. В прикрепленном файле - скрин логов wireshark. Пробовал использовать разные оконечные точки для прерываний, двигать btable, но ничего не изменилось. Есть ли какой совет, что в такой ситуации делать?
Спасибо
Вложения
Захват из USBPcap2.png
(82.67 КБ) 175 скачиваний
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Продолжать курить как работает USB. Хост САМ забирает данные из конечных точек.

Вот код от простенького HID. По нажатию кнопки на плате переключается состояние светодиода. Состояние светодиода отображается на хосте.

Код: Выделить всё

Key key;

int main()
{
  uint8_t report[2]={5,0};  // Report ID 5
  
  for(;;)
  {    
    if(key.pressed()) 
    { 
      report[1]=report[1]?0:1;
      if(report[1]) LED::On(); else LED::Off();
      usb.WriteEP<1>(report,sizeof(report));
    }
  }
}
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

Я понимаю, что хост сам забирает данные, но чтобы микроконтроллер передал их, мне же все равно нужно разрешить передачу. На данный момент - после того как я передал дескриптор репорта и обработал сет репорт - я заполняю буффер данных передачи для первой точки репортом, в btable указываю размер передаваемых данных и устанавливаю тип точки - interrupt. Затем разрешаю передачу данных для этой точки. Как я понимаю, теперь когда хост пошлет interrupt запрос, то устройство должно будет отправить данные из буфера. Но в итоге передать данные у меня не получается. Что касательного Вашего примера, то что делает функция WriteEP? Просто заполняет PMA?
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

WriteEP делает всё то же самое что и при отправке дескрипторов, только в 1-ю точку. Пишет в буфер, указывает длину и ставит статус TX_VALID. После этого хост сам всё заберёт.
Реклама
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

Видимо где-то из-за невнимательности не могу найти ошибку, потому что сделал все как и при отправке дескрипторов, но почему-то данные из первой точки не уходят.
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Показывай инициализацию ep1 и функцию отправки.
Аватара пользователя
Мурик
Друг Кота
Сообщения: 3383
Зарегистрирован: Пн окт 11, 2010 19:00:08

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

Сообщение Мурик »

И дескриптор интерфейса.
Может в нем нет данных о точке или они некорректные.
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

В общем вот весь код. Немного изменил, чтобы основную часть перенести в main файл. Инициализация первой оконечной точки после ресета происходит на 298 и 301 строках.

Добавлено after 2 hours 53 minutes 18 seconds:
Забыл в коде указать COUNT_TX для первой точки, но если указать, то все равно не работает
Вложения
main.txt
(11.52 КБ) 216 скачиваний
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Хорошо, даже отлично, нет, просто замечательно! Что всё это не у меня :)

Я продираться через такое количество мэджикнамберсов не буду. Сравните как можно даже дескрипторы понятно описать.
Спойлер

Код: Выделить всё

#pragma once

#include "usb_descriptors_types.h"

STRING_DESCRIPTOR(0, StringLangID,    u"\x0409"                );
STRING_DESCRIPTOR(1, StringVendor,    u"STMicroelectronics"    );
STRING_DESCRIPTOR(2, StringProduct,   u"STM32 Custom HID"      );
STRING_DESCRIPTOR(3, StringSerial,    u"00000000001B"          );

inline const uint8_t * const descr_table[] =
{
  (uint8_t *)&StringLangID,
  (uint8_t *)&StringVendor,
  (uint8_t *)&StringProduct,
  (uint8_t *)&StringSerial
};

//========================
// HID Device Descriptor
//========================
inline constexpr USB_DEVICE_DESCRIPTOR DeviceDescriptor =
{
  .bLength = sizeof(DeviceDescriptor),  // размер дескриптора
  .bDescriptorType    = DescriptorType::DEVICE,
  .bcdUSB             = 0x0200,         // usb 2.0
  .bDeviceClass       = 0x00,           // Class is specified in the interface descriptor
  .bDeviceSubClass    = 0x00,           // Subclass is specified in the interface descriptor
  .bDeviceProtocol    = 0x00,           // Protocol is specified in the interface descriptor
  .bMaxPacketSize0    = 0x40,           // 64
  .idVendor           = 0x0483,         // VID
  .idProduct          = 0x572A,         // PID
  .bcdDevice          = 0x0200,         // 
  .iManufacturer      = 0x01,           // индекс строки с названием производителя 
  .iProduct           = 0x02,           // индекс строки с названием устройства 
  .iSerialNumber      = 0x03,           // индекс строки с серийным номером устройства 
  .bNumConfigurations = 0x01            // количество поддерживаемых конфигураций
};

//========================
// HID Device Qualifier Descriptor
//========================
inline constexpr USB_DEVICE_QUALIFIER_DESCRIPTOR Device_Qualifier =
{
  .bLength = sizeof(Device_Qualifier),
  .bDescriptorType      = DescriptorType::DEVICE_QUALIFIER,
  .bcdUSB               = 0x0200,       // usb 2.0
  .bDeviceClass         = 0x00,         // Class is specified in the interface descriptor
  .bDeviceSubClass      = 0x00,         // Subclass is specified in the interface descriptor
  .bDeviceProtocol      = 0x00,         // Protocol is specified in the interface descriptor
  .bMaxPacketSize0      = 0x40,         // 64
  .bNumConfigurations   = 0x01,         // 
  .bReserved            = 0x00          // 
};

//========================
// HID Report Descriptor
//========================
inline constexpr uint8_t ReportDescriptor[100] =
{  
    0x06, 0x00, 0xFF,              // USAGE_PAGE (Vendor Difined Page 1)    
    0x09, 0x01,                    // USAGE (Vendor Usage 1)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x01,                    //   REPORT_ID(1)    
    0x09, 0x01,                    //   USAGE (Vendor Usage 1)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x08,                    //   REPORT_SIZE(8)
    0x95, 0x01,                    //   REPORT_COUNT(1)
    0xb1, 0x82,                    //   FEATURE (Data,Var,Abs,Vol)
    0x85, 0x01,                    //   REPORT_ID(1)
    0x09, 0x01,                    //   USAGE (Vendor Usage 1)
    0x91, 0x82,                    //   OUTPUT (Data,Var,Abs,Vol)

    0x85, 0x02,                    //   REPORT_ID(2)
    0x09, 0x02,                    //   USAGE (Vendor Usage 2)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x08,                    //   REPORT_SIZE(8)
    0x95, 0x01,                    //   REPORT_COUNT(1)
    0xb1, 0x82,                    //   FEATURE (Data,Var,Abs,Vol)
    0x85, 0x02,                    //   REPORT_ID(2)
    0x09, 0x02,                    //   USAGE (Vendor Usage 2)
    0x91, 0x82,                    //   OUTPUT (Data,Var,Abs,Vol)

    0x85, 0x03,                    //   REPORT_ID(3)
    0x09, 0x03,                    //   USAGE (Vendor Usage 3)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE(8)
    0x95, 0x01,                    //   REPORT_COUNT(1)
    0xb1, 0x82,                    //   FEATURE (Data,Var,Abs,Vol)
    0x85, 0x03,                    //   REPORT_ID(3)
    0x09, 0x03,                    //   USAGE (Vendor Usage 3)
    0x91, 0x82,                    //   OUTPUT (Data,Var,Abs,Vol)

    0x85, 0x04,                    //   REPORT_ID(4)
    0x09, 0x03,                    //   USAGE (Vendor Usage 3)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                    //   REPORT_SIZE(8)
    0x95, 0x01,                    //   REPORT_COUNT(1)
    0xb1, 0x82,                    //   FEATURE (Data,Var,Abs,Vol)
    0x85, 0x04,                    //   REPORT_ID(4)
    0x09, 0x03,                    //   USAGE (Vendor Usage 3)
    0x91, 0x82,                    //   OUTPUT (Data,Var,Abs,Vol)
        
    0x85, 0x05,                    //   REPORT_ID(5)
    0x09, 0x04,                    //   USAGE (Vendor Usage 4)
    0x75, 0x08,                    //   REPORT_SIZE(8)
    0x95, 0x01,                    //   REPORT_COUNT(1)
    0x81, 0x82,                    //   INPUT (Data,Var,Abs,Vol)
    0xC0                           //  END_COLLECTION
};

//========================
// HID Configuration Descriptor
//========================
inline constexpr USB_HID_CONFIGURATION_DESCRIPTOR ConfigDescriptor =
{
  .Config_1 = { // Configuration 1
    .bLength = sizeof(USB_CONFIGURATION_DESCRIPTOR),
    .bDescriptorType     = DescriptorType::CONFIGURATION,
    .wTotalLength        = sizeof(USB_HID_CONFIGURATION_DESCRIPTOR),
    .bNumInterfaces      = 0x01,         // 1 интерфейс Data 
    .bConfigurationValue = 0x01,         // конфигурация 1
    .iConfiguration      = 0x00,         // No String Descriptor
    .bmAttributes        = 0xC0,         // Собственное питание
    .MaxPower            = 0x32          // 100 мА    
  },  
  .Interface_0 = { // Interface 0 CUSTOM HID
    .bLength = sizeof(USB_INTERFACE_DESCRIPTOR),
    .bDescriptorType    = DescriptorType::INTERFACE,
    .bInterfaceNumber   = 0x00,                  // Interface 0
    .bAlternateSetting  = 0x00,                  //
    .bNumEndpoints      = 0x02,                  //
    .bInterfaceClass    = 0x03,                  // Custom HID
    .bInterfaceSubClass = 0x00,                  // 1=BOOT, 0=no boot
    .bInterfaceProtocol = 0x00,                  // 0=none, 1=keyboard, 2=mouse
    .iInterface         = 0x00                   // No String Descriptor
  },
  .HID_Descriptor = { // Custom HID Descriptor
    .bLength             = sizeof(USB_CUSTOM_HID_DESCRIPTOR),
    .bDescriptorType     = DescriptorType::HID,
    .bcdHID              = 0x0111,      // HID Version ( 1.11 )
    .bCountryCode        = HID_Localization::Not_Localized,
    .bNumDescriptors     = 1,          // Количество дескрипторов в классе
    .bDescriptorType_0   = DescriptorType::REPORT,
    .wDescriptorLength_0 = sizeof(ReportDescriptor) // Длина Report Descriptor
  },
  .EndPoint_1 = { // Interrupt IN EndPoint
    .bLength = sizeof(USB_ENDPOINT_DESCRIPTOR),
    .bDescriptorType  = DescriptorType::ENDPOINT,
    .bEndpointAddress = 0x81,                    // Direction=IN, EndpointID=1
    .bmAttributes     = 0x03,                    // TransferType = Interrupt
    .wMaxPacketSize   = 0x0002,                  // 2 bytes
    .bInterval        = 0x20                     // 20 ms
  },
  .EndPoint_2 = { // Interrupt OUT EndPoint
    .bLength = sizeof(USB_ENDPOINT_DESCRIPTOR),
    .bDescriptorType  = DescriptorType::ENDPOINT,
    .bEndpointAddress = 0x01,                    // Direction=OUT, EndpointID=1
    .bmAttributes     = 0x03,                    // TransferType = Interrupt
    .wMaxPacketSize   = 0x0002,                  // 2 bytes
    .bInterval        = 0x00                     // 20 ms
  }
};
А за такое вообще увольнять без выходного пособия. Что записано в регистр? Какой бит ожидается?

Код: Выделить всё

usb.ep0r.write(0x0210);
while usb.ep0r.get_bit(7) == 0 {};
Я в RM не полезу выяснять.

И собственно главный вопрос. В какой строке вы репорт отправляете?
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

"Я продираться через такое количество мэджикнамберсов не буду. Сравните как можно даже дескрипторы понятно описать."
Опыта программирования у меня не так уж и много. Век живи - век учись, как говорится.

"А за такое вообще увольнять без выходного пособия. Что записано в регистр? Какой бит ожидается?"
В регистре прием и передача находятся в состоянии nak, когда я записываю единицу, то перевожу передачу в состояние valid. Поскольку в мануале не рекомендуют чтение + запись, то я методом подбора нашел такое значение, чтобы корректно передавать данные. Далее жду пока устройство не переключит флаг в состояние корректной передачи.

"И собственно главный вопрос. В какой строке вы репорт отправляете?"
Я пытаюсь его отправить только один раз. В строке 298 ( write_pma(&[0xc0, 0x00, report_size, 0x00, 0x00, 0x01, 0x00, 0x84], 8); ), где я указываю размер репорта и в строке 301, когда я разрешаю передачу данных. Если я правильно понимаю, то в следующий раз, когда хост запросит данные из первой точки, устройство уже будет готово их отдать (поскольку я не записал в буфер отправки никакие значения, то отправятся все нули), но ничего не отправляется.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

[uquote="Kellya",url="/forum/viewtopic.php?p=3895204#p3895204"]Я пытаюсь его отправить только один раз.[/uquote]В обработчике ресета? До прохождения энумерации?
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

"В обработчике ресета? До прохождения энумерации?"
Получается, что да. Я думал, что можно в самом начале настроить контрольную точку, а когда хосту понадобится данные, то она уже будет готова их отдать. Просто по control sequence я достаточно много источников информации нашел, а вот что делать после пытался уже сам догадаться.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Что делать дальше зависит от реализуемого класса. Тут творчески надо подойти. В случае с HID самое сложное правильный Report Descriptor сделать и формат репортов чтобы соответсвовал дескриптору. А так то передавать данные легко.
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

Перенес код инициализации первой точки в место перед отправкой дескриптора отчета. Вот что получилось

Код: Выделить всё

write_pma(&[0xc0], 8); // Пишу по адресу 0x4000_6000 + 8 * 2 значение 0xc0 - оффсет буфера передачи для первой оконечной точки
write_pma(&report, 192); // Заполняю буфер передачи репортом
write_pma(&[report.len() as u8], 10); // Пишу по адресу 0x4000_6000 + 10 * 2 размер передаваемых данных
usb.ep1r.write(0x0630); // Разрешаю передачу данных для первой оконечной точки, устанавливая STAT_TX в valid
Но отправить данные из этой точки все равно не получается. Всё та же XACT ERROR. Если инициализировать точку после отправки репорта, то ничего не меняется.
И еще такой вопрос: через некоторое время после того, как устройству не удалось отправить ответ на interrupt, host начинает снова запрашивать дескриптор устройства. Так и должно быть, или это связано с неправильной энумерацией?
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

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

Сообщение Z_h_e »

Если хост видит, что девайс общается не по этикету, он пошлет его сбросом и начнет все заново (до трех раз).
Если все нормально, дескриптор устройства запрашивается два раза, сначала только его кусок, потом полностью.
Да, когда приходит команда установить адрес девайса, надо ответить ZLP как от безадресного устройства и только потом установить адрес.
Это я сходу что вспомнил, надеюсь правильно.
С 107 МК я чето пока подзавязал разбираться,а со 103 давно делал. Кстати, в этой же теме разбирались как у 103 USB робит , Kellya, Вы читали этот топик полностью? Тут вроде все про 103 и USB разжёвано и как раз на любительском уровне, по мере появления времени и желания ковырялись с коллегами.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

"Вы читали этот топик полностью?"
Да, с этого и начинал, мне очень помогло - получилось сделать так, чтобы устройство корректно отображалось в диспетчере устройств. Но для этого достаточно работы с нулевой точкой, а вот что делать с точкой interrupt in, я так и не разобрался, может быть невнимательно все прочитал. Хотя вроде бы настраиваю её аналогично нулевой точке
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

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

Сообщение Z_h_e »

Я помню, что interrupt у меня что-то получилось, но потом понял что мне хватает для общения устройства типа HID через "фьючи" более чем. ISX себе CDC забубекал.
Что у меня с interrupt было, точно не помню, но хост регулярно запросы слал (т.е. работало). Вроде с конфигурировать не сложно было, может есть тут в теме? И еще где-то есть ссылка (наверное в начале топика) на параллельную тему, может там что есть А я стал общаться с девайсом через фьючи, потому что мне так проще оказалось приложение под винду написать для обмена.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

"Что у меня с interrupt было, точно не помню, но хост регулярно запросы слал"
Вот, у меня тоже хост шлет регулярно запросы к первой точке, но корректно ответить на них у меня почему-то (не разобрался) не получается. Пробую клавиатуру написать, если это как-то важно
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Неужели в сети рабочий пример HID для f103 не ищется? Да хоть тем же кубом сгенерить и разбираться.
Ответить

Вернуться в «ARM»