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

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
Z_h_e
Собутыльник Кота
Сообщения: 2708
Зарегистрирован: Сб май 14, 2011 21:16:04
Откуда: г. Чайковский

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

Сообщение Z_h_e »

Kellya, Вам пришли данные для для 1ой точки типа OUT и Вы их дешифровали как запрос дескриптора или для конечно точки 1 типа IN приходят фреймы с запросом данных?
Что-то я боюсь вопрос не совсем корректно сформулировал.
Изображение
Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Все дескрипторы через 0-ю точку отправляются. Тут очень важно правильно HIDReportDescriptor составить. Без этого ничего работать дальше не будет.

Весь обмен HID состоит из SetReport и GetReport. Первый передаёт данные от хоста к устройству и может приходить как в 0-ю точку, так и в 1-ю. Второй только через 1-ю interrupt точку работает. Отправлять репорты устройство может когда захочет. Обычно это происходит, если изменяется состояние устройства. Естественно, чаще чем хост опрашивает отправлять смысла не имеет.

Сама отправка репортов ни чем не отличается от отправки дескрипторов при энумерации, только производится в 1-ю точку. Для этого должна быть правильно заполнена таблица описания буферов приёма/передачи и писать правильно в буфер.

Одно из "заподлянских" мест в USB от STM (тот что не OTG) это правильно выставлять статусы с регистре конфигурации точки. Там непривычные для новичков toggle-биты есть.

Добавлено after 16 minutes 21 second:
Ещё насчёт дескрипторов. Я на прошлой странице выкладывал дескрипторы, которые правильно работают с STM-овской утилитой для тестирования HID. Там установка и считывание светодиодов реализовано. Для отладки за глаза.
Реклама
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

"Kellya, Вам пришли данные для для 1ой точки типа OUT и Вы их дешифровали как запрос дескриптора"
Сначала эти данные пришли для 0ой точки, я их дешифровал как запрос дескриптора, обработал и отправил. Потом проделал тоже самое для остальных дескрипторов (конфигурации, интерфейса, строк, отчета и к.т.1). Все это через нулевую точку. На этом этапе у меня проблем не возникает. Устройство определилось в системе.
После всего этого, как только я передал дескриптор репорта мне начинают сыпаться фреймы с запросом данных для конечно точки 1 типа IN, на которые у меня не получается ответить, после парты попыток от хоста получить ответ, он начинает сыпать различными запросами на ресет пайпов (это успешно выполняется контроллером самостоятельно), а потом снова начинает сыпать запросы данных для конечно точки 1 типа IN

Добавлено after 5 minutes 40 seconds:
"Все дескрипторы через 0-ю точку отправляются. Тут очень важно правильно HIDReportDescriptor составить. Без этого ничего работать дальше не будет."
Все верно, хост съедает все дескрипторы, которые я ему шлю.
"Весь обмен HID состоит из SetReport и GetReport".
Когда хост хочет получить репорт он отправляет GetReport? Хм, у меня такого вроде бы нет. Я думал, что он отправляет URB_INTERRUPT in, когда хочет получить данные из точки
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

[uquote="Kellya",url="/forum/viewtopic.php?p=3898704#p3898704"]Когда хост хочет получить репорт он отправляет GetReport? Хм, у меня такого вроде бы нет.[/uquote]Нет, это я так вольно процесс передачи данных описал. Что репорты туда-сюда бегают. Реально такого запроса конечно же нет.

[uquote="Kellya",url="/forum/viewtopic.php?p=3898704#p3898704"]Я думал, что он отправляет URB_INTERRUPT in, когда хочет получить данные из точки[/uquote]Всё верно. Только не когда хочет получить данные, а когда придёт время опроса. И если вы к этому моменту положили данные, то они их сам заберёт. Устройству не надо реагировать на эти запросы, как вы не поймёте. Просто положите репорт в ep-1 и хост сам их заберёт.

Добавлено after 14 minutes 6 seconds:
Если дескрипторы составлены правильно, то там реально всё примитивно.

Вот кусочек реализации HID. Тут ClassSpecificSetup это Setup-запросы в EP0, характерные только для HID. И обработка SetReport через EP0 и EP1.
Спойлер

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

class USB_HID : public USB_DEVICE
{
  public:
    USB_HID(){}
    
    void Enumerate_Reset()
    {
      EPInit<1,EP_TYPE::Interrupt>();
    }
     
    inline void EP0_RX() { SetReport(0); }
    inline void EP1_RX() { SetReport(1); }
    inline void EP1_TX() {}      
        
    virtual bool ClassSpecificSetup(USB_SETUP_REQ *uSetReq, uint8_t *len, uint8_t **pbuf)
    {
      switch(HID_REQUEST(uSetReq->wRequest))
      {
        case HID_REQUEST::GET_DESCRIPTOR:
          switch(DescriptorType(uSetReq->descType))
          {      
            case DescriptorType::HID:
              DEBUG_Print("HID_GET_Descriptor HID %d \r\n",uSetReq->wLength);
              *len = sizeof(USB_CUSTOM_HID_DESCRIPTOR);
              *pbuf = (uint8_t *)&ConfigDescriptor.HID_Descriptor;
              break;          
            case DescriptorType::REPORT:
              DEBUG_Print("HID_GET_Descriptor REPORT %d\r\n",uSetReq->wLength);
              *len = sizeof(ReportDescriptor);
              *pbuf = (uint8_t *)ReportDescriptor;
              break;
            default:
              DEBUG_Print("HID_GET_Descriptor 0x%X not supported\r\n",uSetReq->wValue);
              return false;          
          }
          break;
        case HID_REQUEST::SET_REPORT:
          DEBUG_Print("HID_SET_REPORT %d\r\n",uSetReq->wLength);
          break;
        case HID_REQUEST::SET_IDLE:
          DEBUG_Print("HID_Set_Idle 0x%X\r\n",uSetReq->wValue);
          break;
        default:
          DEBUG_Print("HID_Request 0x%X\r\n not supported",uSetReq->wRequest);
          return false;
      }
      return true;
    }

  private:
  
      void SetReport(uint32_t ep)
    {  
      DEBUG_Print("EP%d DATA:",ep);
      for(uint32_t i=0; i<rx_len; i++) DEBUG_Print(" 0x%X",rx_buf[i]);
      DEBUG_Print("\r\n");   
      switch(rx_buf[0])
      {
        case 1:  // Report 1
          if(rx_buf[1]) LED1::On(); else LED1::Off();
          break;
        case 2:  // Report 2
          if(rx_buf[1]) LED2::On(); else LED2::Off();       
          break;
        case 3:  // Report 3
          if(rx_buf[1]) LED3::On(); else LED3::Off();
          break;        
        case 4:  // Report 4
          if(rx_buf[1]) LED4::On(); else LED4::Off();      
          break;        
      }  
    }
};
А вот кусочек отправки репорта, я его уже приводил.
Спойлер

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

  uint8_t report[2]={5,0};  // Report ID 5
  
  for(;;)
  {    
    if(key.pressed()) 
    { 
      report[1]=!report[1];
      if(report[1]) LED0::On(); else LED0::Off();
      usb.WriteEP<1>(report,sizeof(report));
    }
  };
Это весь код HID, не считая дескрипторов (их я тоже чуть выше выкладывал), где тут можно запутаться?
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

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

Сообщение Eddy_Em »

[uquote="VladislavS",url="/forum/viewtopic.php?p=3898689#p3898689"]Весь обмен HID состоит из SetReport и GetReport. Первый передаёт данные от хоста к устройству и может приходить как в 0-ю точку, так и в 1-ю. Второй только через 1-ю interrupt точку работает. Отправлять репорты устройство может когда захочет. Обычно это происходит, если изменяется состояние устройства. Естественно, чаще чем хост опрашивает отправлять смысла не имеет.[/uquote]
Что у вас за HID такой, который с interrupt работает? Я сколько ни ловил их - пусто... И wireshark не показывал, чтобы что-то в них происходило.
Единственное, когда в interrupt были какие-то данные - когда я подумывал ch340 сэмулировать. Но там оказалось, что по сути вообще никакой не CDC, даже обмен данными не так происходит, как у CDC. Поэтому забил (плюс к тому же, в ядре поддержка ch340 сделана реверсом и очень многие вещи не учитываются, ХЗ, как оно себя поведет в той же мастдайке).
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Реклама
Аватара пользователя
Мурик
Друг Кота
Сообщения: 3383
Зарегистрирован: Пн окт 11, 2010 19:00:08

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

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

VladislavS писал(а):Весь обмен HID состоит из SetReport и GetReport. Первый передаёт данные от хоста к устройству и может приходить как в 0-ю точку, так и в 1-ю. Второй только через 1-ю interrupt точку работает.
SetReport и GetReport нормально работают через 0-ю.
VladislavS писал(а):Отправлять репорты устройство может когда захочет.
Не совсем так. Инициатором обмена всегда выступает хост, а значит отправлять можно только если в конечной точке нет данных которые еще не запросил хост. То есть перед копированием в USB буфер нужно проверить состояние точки.
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

Eddy_Em, иди читай спецификацию HID, потом обсудим, если останутся вопросы.

Для ленивых.
СпойлерИзображение
hid_interfaces.png
(76.56 КБ) 331 скачивание
Добавлено after 15 minutes 55 seconds:
[uquote="Мурик",url="/forum/viewtopic.php?p=3898872#p3898872"]SetReport и GetReport нормально работают через 0-ю.[/uquote]Ну это же легко проверятеся. Вот приведённый выше код меняет состояние отображения кнопки
СпойлерИзображение
button.png
(61.8 КБ) 323 скачивания
А если отправлять через 0-ю точку

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

usb.WriteEP<0>(report,sizeof(report));
То уже ничего не приходит.

Добавлено after 17 minutes 17 seconds:
Я тут сам ещё раз спецификацию почитал. Пожалуй, через нулевую точку тоже будет работать. Надо просто Get_Report с хоста слать и на него отвечать. STM-овская USB HID Demonstrator просто так не умеет. Но в код обработку GET_REPORT, конечно, обязательно добавить.
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

В общем удалось собрать рабочий проект для мышки в CubeMX, значит железо работает нормально. Но с их дескрипторами свой код мне все равно так и не удалось запустить. Видимо неправильно пытаюсь инициализировать первую точку. Можно ли как-то вообще её не инициализировать, и, например, чтобы она на каждый опрос от хоста просто отвечала STALLом? Или для обмена пакетами в любом случае необходимо инициализировать буферы приема/передачи?
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

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

Сообщение VladislavS »

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

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

Сообщение Kellya »

В общем ошибка была только в том, что я не указал для первой точки её адрес :oops: . Для нулевой точки там все автоматически стояло, поэтому этот момент как-то вылетел из головы. Всем большое спасибо за помощь
Kellya
Первый раз сказал Мяу!
Сообщения: 21
Зарегистрирован: Пн авг 24, 2020 19:13:24

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

Сообщение Kellya »

Столкнулся с ещё одной проблемой. После того как отправляю репорт, который описывает нажатие клавиши на клавиатуре, почему-то эта клавиша печатается не один раз, а много (не ждал пока остановятся), будто клавишу зажали и держат. Причем, как вызов функции отправки, так и прерывание о корректной передаче происходят только один раз. Wireshark тоже фиксирует только один ответ от устройства. Но клавиша почему-то остается нажатой. Не встречалась ни у кого такая проблема? Репорт состоит из 8 байт - [bModifier, bReserved, bKey1, bKey2, bKey3, bKey4, bKey5, bKey6]
Аватара пользователя
Мурик
Друг Кота
Сообщения: 3383
Зарегистрирован: Пн окт 11, 2010 19:00:08

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

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

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

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

Сообщение Kellya »

[uquote="Мурик",url="/forum/viewtopic.php?p=3922154#p3922154"]
Kellya писал(а):Но клавиша почему-то остается нажатой.
А вы проинформировали хост что она была отпущена? Нужно отправить пакет не содержащий код этой клавиши, иначе она считается нажатой.[/uquote]
Точно. Спасибо. Теперь вспомнил, что когда-то попадалось на глаза такое.
Аватара пользователя
azhel12
Встал на лапы
Сообщения: 145
Зарегистрирован: Пн апр 02, 2012 15:56:23

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

Сообщение azhel12 »

Всех приветствую, надеюсь, ветка еще жива. Разбираюсь в USB на Stm32, пытаюсь приладить шаблоны C++ к USB (кому интересно, ВОТ пост про это). Без особых проблем (пятикратного перечитывания этой ветки, в общем-то, почти хватило. Отдельная благодарность @Z_h_e за предоставленные исходники) добился определения устройства в ОС. Далее перешел к реализации HID, девайс тоже определяется (хотя через раз, иногда ошибка "Код 10 Запуск этого устройства невозможен". Грешу или на питание, нет под рукой большого конденсатора, или частота гуляет).

Собственно, моя проблема в следующем: данные на конечную точку 1 (она типа Interrupt) прилетают (содержимое памяти правильное + бит CTR_RX взведен), но биты EP_ID в регистра ISTR всегда 0, соответственно, управление не заходит в обработчик прерывания конечной точки 1. Из RM я понял, что EP_ID заполняется номером конечной точки с наибольшим приоритетом, однако вроде как компьютер не должен настолько плотно обмениваться управляющими пакетами.

Мое предположение такое: я не сбрасываю бит CTR в регистре ISTR (как его сбросить, так и не понял, в некоторых МК он помечен read-only, в некторых - clear-only) и из-за этого постоянно срабатывает прерывание на 0 конечную точку.

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

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

Сообщение VladislavS »

[uquote="azhel12",url="/forum/viewtopic.php?p=4003881#p4003881"]Мое предположение такое: я не сбрасываю бит CTR в регистре ISTR (как его сбросить, так и не понял, в некоторых МК он помечен read-only, в некторых - clear-only) и из-за этого постоянно срабатывает прерывание на 0 конечную точку.[/uquote]Не надо его сбрасывать, он RO. Все делается в EPnR. Сбрасываются флаги CTR_RX и CTR_TX, устанавливаются статусы TX_STAT и RX_STAT. Большинство проблем с конечными точками - неправильная работа с EPnR, проверяйте.
Аватара пользователя
azhel12
Встал на лапы
Сообщения: 145
Зарегистрирован: Пн апр 02, 2012 15:56:23

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

Сообщение azhel12 »

[uquote="VladislavS",url="/forum/viewtopic.php?p=4003961#p4003961"][uquote="azhel12",url="/forum/viewtopic.php?p=4003881#p4003881"]Мое предположение такое: я не сбрасываю бит CTR в регистре ISTR (как его сбросить, так и не понял, в некоторых МК он помечен read-only, в некторых - clear-only) и из-за этого постоянно срабатывает прерывание на 0 конечную точку.[/uquote]Не надо его сбрасывать, он RO. Все делается в EPnR. Сбрасываются флаги CTR_RX и CTR_TX, устанавливаются статусы TX_STAT и RX_STAT. Большинство проблем с конечными точками - неправильная работа с EPnR, проверяйте.[/uquote]

Спасибо за быстрый ответ, вечером перепроверю сброс CTR_RX/TX в EP0 и отпишу. Буду надеяться, что я действительно просто забыл это сделать и поэтому словил такую ситуацию.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

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

Сообщение COKPOWEHEU »

Можете сравнить с моим вариантом (HID клава + мышь) https://github.com/COKPOWEHEU/usb/tree/main/3.HID_L1 Вроде работает и не отваливается. Но у меня тактирование от кварца и с конденсаторами.
Вы, наверное, видели мою статью по ядру библиотеки https://habr.com/ru/post/548150/
данные на конечную точку 1 (она типа Interrupt) прилетают (содержимое памяти правильное + бит CTR_RX взведен)
Для передачи пакета его надо записать в буфер endpoint'а, потом выставить в EPnR биты USB_EPTX_DTOG1 и USB_EPTX_DTOG2 в значение USB_EP_TX_VALID. И наконец сбросить флаг прерывания USB_EP_CTR_TX в том же EPnR. Осторожно, биты в EPnR наркоманские, их надо очень осторожно менять чтобы не задеть остальные.
девайс тоже определяется (хотя через раз, иногда ошибка "Код 10 Запуск этого устройства невозможен"
Проверьте размер репорта, он должен быть ровно такой, как указан в HID-дескрипторе. На 1 байт ошибетесь и винда вас пошлет далеко и надолго. (Линуксу, естественно, пофиг - они и не с таким работать умеет).
данные на конечную точку 1 (она типа Interrupt) прилетают
А Wireshark что говорит? Отправляет ли хост вообще interrupt запросы или нет?
Аватара пользователя
azhel12
Встал на лапы
Сообщения: 145
Зарегистрирован: Пн апр 02, 2012 15:56:23

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

Сообщение azhel12 »

Вы, наверное, видели мою статью по ядру библиотеки https://habr.com/ru/post/548150/
Нет, честно говоря, на неделе некогда было заходить, но пробежался глазами сейчас, интересно. Очень рад, что появляются материалы по работе с USB (да и не только) на регистрах. Пытался обратиться за помощью "оффлайн" к коллегам, которые связаны с железом, в т.ч. микроконтроллерами, они отвечают "Мне хватает куба, ничем помочь не могу".
Для передачи пакета его надо записать в буфер endpoint'а, потом выставить в EPnR биты USB_EPTX_DTOG1 и USB_EPTX_DTOG2 в значение USB_EP_TX_VALID
Тут не понял, USB_EP_TX_VALID - это же другое поле, а именно STAT_TX(STAT_RX)? с DTOG так и не разобрался, он, как я понял, работает в случае Bulk с двойной буферизацией. Или я что-то не понимаю?
А USB_EP_TX(RX)_VALID я записываю, собственно, нумерацию девайс проходит нормально (если бы накосячил, наверно, данные бы не улетали).
Проверьте размер репорта, он должен быть ровно такой, как указан в HID-дескрипторе.
Спасибо за подсказку, проверю. Однако странно, в 3 случаях из 5 все-таки нормально определяется. Более склоняюсь к частотам, потому что сначала все эксперименты ставил на Disco-F072RB, там на самом МК вообще кварца нет, и было большой удачей "поймать" нумерацию. Сейчас перешел на BluePill, уже гораздо лучше.
А Wireshark что говорит? Отправляет ли хост вообще interrupt запросы или нет?
Wireshark-ом так и не смог начать пользоваться, не могу нормально фильтры выставить. Но пока мне даже это рано, потому что у меня только OUT конечная точка в HID, соответственно, когда пытаюсь через HID-Demonstrator отправить команду через REPORT, то она 100% доходит, потому что у конечной точки взводится CTR_RX, в буфере тоже данные лежат. Проблема лишь в том, что в прилетающем прерывании всегда конечная точка 0, хотя я ожидаю, что будет 1, и в обработчике я обработаю.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

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

Сообщение COKPOWEHEU »

Тут не понял, USB_EP_TX_VALID - это же другое поле, а именно STAT_TX(STAT_RX)?
Возможно, перепутал. Смотрел бегло по заголовочнику. Скорее всего, вы правы.
Насколько я понимаю, поле DTOG это переключение между DATA0 / DATA1 / DATA2 / MDATA, то есть скорее для каких-то внутренних целей. Хотя с ST станется...
Очень рад, что появляются материалы по работе с USB (да и не только) на регистрах.
Я бы предложил моей библиотекой и воспользоваться :) но догадываюсь, что свой велосипед всегда ближе. Но хотя бы на макросы для дескрипторов посмотрите: рано или поздно считать длинны надоест.
Wireshark-ом так и не смог начать пользоваться, не могу нормально фильтры выставить. Но пока мне даже это рано
Я им начал пользоваться когда одну endpoint0 мучил чтобы хоть энумерацию пройти.
Запускаете, выбираете захват usbmon0 (или какой там у вас) и запрещаете все лишнее по адресам на шине. Удобно для этого lsusb использовать, но можно и самые надоедливые адреса из самого wireshark'а прибить:

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

$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 051: ID 0458:003a KYE Systems Corp. (Mouse Systems) NetScroll+ Mini Traveler / Genius NetScroll 120
Bus 001 Device 004: ID 13d3:56a8 IMC Networks USB2.0 HD UVC WebCam
Из перечисленного будет активно мешаться мышка со своими прерываниями. Она висит на 1.51, конечная точка с прерываниями 1-я. Еще я всегда блокирую программатор stlink. Допустим, он висит на 1.52 и спамит с точек 1 и 2. Тогда строка фильтра будет такой:

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

!((usb.addr=="1.51.1")||(usb.addr=="1.52.1")||(usb.addr=="1.52.2"))
Проблема лишь в том, что в прилетающем прерывании всегда конечная точка 0, хотя я ожидаю, что будет 1, и в обработчике я обработаю.
Покажите ConfigurationDescriptor, функцию настройки endpoint'ов (если она читаемая, конечно: в шаблонах С++ я все равно не разберусь) и обработчик прерывания где вы накладываете маску USB_ISTR_EP_ID.
Ну и тот же wireshark поможет хотя бы понять шлет вам хост запросы вообще или нет. И если шлет, то куда.
Аватара пользователя
azhel12
Встал на лапы
Сообщения: 145
Зарегистрирован: Пн апр 02, 2012 15:56:23

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

Сообщение azhel12 »

Покажите ConfigurationDescriptor, функцию настройки endpoint'ов (если она читаемая, конечно: в шаблонах С++ я все равно не разберусь) и обработчик прерывания где вы накладываете маску USB_ISTR_EP_ID
Дескриптор скину вечером (формируется он путем развертывания variadic template), просто из памяти выдерну в виде байтов, буду рад, если глянете и мб что-то найдете.
Обработчик вот такой:

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

if(_Regs()->ISTR & USB_ISTR_RESET)
{
	Reset();
}
if(_Regs()->ISTR & USB_ISTR_CTR)
{
	uint8_t endpoint = _Regs()->ISTR & USB_ISTR_EP_ID;
	EpHandlers::Handle(endpoint, ((_Regs()->ISTR & USB_ISTR_DIR) != 0 ? EndpointDirection::In : EndpointDirection::Out));
}

NVIC_ClearPendingIRQ(_IRQNumber);
Обработчик EP0 (мне кажется, проблема в нем, потому что при наличии только 0 точки все работает. Ну как работает, определяется, SET_FEATURE тоже корректно записывает данные в буфер, просто не обрабатываю) вот такой:

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

if(_Ep0::Reg::Get() & USB_EP_CTR_RX)
{
	_Ep0::ClearCtrRx();
	if(_Ep0::Reg::Get() & USB_EP_SETUP)
	{
		SetupPacket* setup = reinterpret_cast<SetupPacket*>(_Ep0::RxBuffer);
		switch (setup->Request) {
		case StandartRequestCode::GetStatus: {
			// Dummy answer. Remote wakeup and self-powered now not supported.
			uint16_t status = 0;
			_Ep0::Writer::SendData(&status, sizeof(status));
			break;
		}
		case StandartRequestCode::SetAddress: {
			TempAddressStorage = setup->Value;
			_Ep0::Writer::SendData(0);
			break;
		}
		case StandartRequestCode::GetDescriptor: {
			switch (static_cast<GetDescriptorParameter>(setup->Value)) {
			case GetDescriptorParameter::DeviceDescriptor: {
				DeviceDescriptor tempDeviceDescriptor;
				FillDescriptor(reinterpret_cast<DeviceDescriptor*>(&tempDeviceDescriptor));
				_Ep0::Writer::SendData(&tempDeviceDescriptor, setup->Length < sizeof(DeviceDescriptor) ? setup->Length : sizeof(DeviceDescriptor));
				break;
			}
			case GetDescriptorParameter::ConfigurationDescriptor: {
				uint8_t temp[64];
				uint16_t size = GetType<0, Configurations>::type::FillDescriptor(reinterpret_cast<ConfigurationDescriptor*>(&temp[0]));
				_Ep0::Writer::SendData(reinterpret_cast<ConfigurationDescriptor*>(&temp[0]), setup->Length < size ? setup->Length : size);
				break;
			}
			case GetDescriptorParameter::HidReportDescriptor: {
				IO::Pc7::Clear();
				uint16_t size = sizeof(GetType_t<0, Configurations>::HidReport::Data);
				_Ep0::Writer::SendData(GetType_t<0, Configurations>::HidReport::Data, setup->Length < size ? setup->Length : size);    
				break;
			}
			default:
				_Ep0::SetTxStatus(EndpointStatus::Stall);
				break;
			}
			break;
		}
		case StandartRequestCode::SetConfiguration: {
			_Ep0::Writer::SendData(0);
		}
		default:
			_Ep0::SetTxStatus(EndpointStatus::Stall);
			break;
		}
	}
	_Ep0::SetRxStatus(EndpointStatus::Valid);
}
if(_Ep0::Reg::Get() & USB_EP_CTR_TX)
{
	_Ep0::ClearCtrTx();
	if(TempAddressStorage != 0)
	{
		_Regs()->DADDR = USB_DADDR_EF | (TempAddressStorage & USB_DADDR_ADD);
		TempAddressStorage = 0;
	}
	_Ep0::SetRxStatus(EndpointStatus::Valid);
}
}
_Ep0::ClearCtrRx(); как раз сбрасывает CTR_RX у нулевой точки, _Ep0::ClearCtrTx();, соответственно, CTR_TX.
Ответить

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