реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> STM4 USB CDC. Интересное поведение
drozel
сообщение Oct 19 2015, 10:35
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650



Использую libopencm3. За основу взят вот этот пример CDC.
Размер фрейма для нашего ендпойнта настроен 64.
Написал простеньку логику: МК принимает фрейм, смотрит первый элемент и высылает назад статик массив размером, указанным в принятом байте.
Таким образом, я в терминале посылаю число и в ответ получаю заказанное кол-во байт.
Код:
Код
static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
{
    (void)ep;

    int len = usbd_ep_read_packet(usbd_dev, 0x01, USBio.buffer, 64);
    сdcacm_data_tx((uint8_t *)textBuf, USBio.buffer[0]);
}


Посылаю число 0х20 - получаю 32 байта данных.
Посылаю число 0х3F - gjkexf. 63 байта в ответ.
Посылаю 0x40 - тишина. Еще раз - тишина. Теперь внимание! Посылаю 0х01 - получаю 129 байт.
Т.е. пришли все запрошенные за прошлые 3 раза данные.
Выходит, что если МК посылает кол-во байт, совпадающее с размером фрейма - данные где-то зависают.

Начал копать: посылает ли МК? Поставил коллбек по окончанию передачи, виду, что передача проходит.
Принимает ли ПК? К сообщению прикреплен скриншот USB сниффера.
Данные действительно где-то зависают. Буфер драйвера? Буфер USB контроллера?

Кто сталкивался?

Прикрепленное изображение


UPD: нащел аналогичный вопрос на форуме СТ. Он там остался без ответа)
UPD2: Вот тут пояснили, что передача длиной равной размеру кадра должна дополняться передачей нулевой длины. Однако, такая логика не согласуется с логикой разрабов libopencm3, которые используют следующую логику для проверки занятости ендпойнта в функции отправки:
Код
while(usbd_ep_write_packet(usbd_dev, 0x82, buf, len) == 0);

Функция возвращает 0, если идет передача, таким образом происходит ожидание освобождения ендпойнта. Посылка длиной 0 байт приведет к зависанию и вообще не похоже, что такая вещь предусмотрена разрабами

Сообщение отредактировал drozel - Oct 19 2015, 10:46
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Oct 19 2015, 11:00
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Тем не менее zero length packet нужен.

Сообщение отредактировал Kabdim - Oct 19 2015, 11:00
Go to the top of the page
 
+Quote Post
drozel
сообщение Oct 19 2015, 11:05
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650



Цитата(Kabdim @ Oct 19 2015, 17:00) *
Тем не менее zero length packet нужен.

Я правильно понимаю, что без zero-length данные зависают на стороне приемника? Чем вообще ограничивается кол-во данных, которые можно протолкнуть без zero-packet?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 19 2015, 11:56
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(drozel @ Oct 19 2015, 14:05) *
Я правильно понимаю, что без zero-length данные зависают на стороне приемника?
Да. Окончанием пакета считается посылка с числом байт меньше размера конечной точки (ноль байтов под этот критерий попадает). Так написано в стандарте. К чему приводит несоблюдение стандартов - вы наблюдаете сами.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Oct 19 2015, 13:50
Сообщение #5


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Цитата(drozel @ Oct 19 2015, 14:05) *
Я правильно понимаю, что без zero-length данные зависают на стороне приемника? Чем вообще ограничивается кол-во данных, которые можно протолкнуть без zero-packet?

Да.
Если вопрос про макс размер трансфера, то афаик зависит от операционки, а именно драйвера USB. Для винды так. Если вопрос про то что бы не вставлять ZLP, то тоже довольно очевидно: если передаете байтов картных пакету нужно добавить 1 фейковый байт к передаче. Но решение не лучшее. Лучше использовать/написать более вменяемую библиотеку.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Oct 19 2015, 14:05
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(Kabdim @ Oct 19 2015, 20:50) *
Если вопрос про то что бы не вставлять ZLP, то тоже довольно очевидно: если передаете байтов картных пакету нужно добавить 1 фейковый байт к передаче. Но решение не лучшее. Лучше использовать/написать более вменяемую библиотеку.

Можно и наоборот: никогда не передавать больше 63 байт за раз.
Это сделать значительно проще, не нужно досконально изучать и переписывать всю библиотеку.


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
esaulenka
сообщение Oct 19 2015, 14:49
Сообщение #7


Профессионал
*****

Группа: Свой
Сообщений: 1 032
Регистрация: 13-03-08
Из: Маськва
Пользователь №: 35 877



Цитата(SSerge @ Oct 19 2015, 17:05) *
Это сделать значительно проще, не нужно досконально изучать и переписывать всю библиотеку.

Если "не изучать", можно найти всякие разные грабли. Как правило, ооочень невовремя.

drozel, у меня используется следующая схема:
usbd_poll() вызывается из прерывания, там есть два основных коллбэка:
- out ep складывает принятые данные в буфер. Оттуда основная задача по мере сил и возможностей выгребает данные.
- in ep пытается "достать" данные из буфера. Заполнение буфера и запуск передачи (однократный вызов write_ep()) - из основной задачи.

В эту схему пакет нулевой длины легко приделывается, никаких while (write_ep(...)) {} не нужно. Хотя, конечно, кто ж им мешал возвращать отрицательные значения?..


PS полез рыться на репозитарий libopencm3, обнаружил те же самые грабли, но по обмену control endpoint. Исправили ровно неделю назад.
Вот уроды, я ж в этот код уже несколько месяцев не лазил (все дескрипторы у меня короче)...
До остальных эндпоинтов у них руки пока не дошли.


--------------------
Тут обсуждается творческий порыв, а не соответствие каким-либо стандартам ©
Go to the top of the page
 
+Quote Post
drozel
сообщение Oct 19 2015, 16:20
Сообщение #8


Частый гость
**

Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650



Цитата(esaulenka @ Oct 19 2015, 20:49) *
- out ep складывает принятые данные в буфер. Оттуда основная задача по мере сил и возможностей выгребает данные.
- in ep пытается "достать" данные из буфера. Заполнение буфера и запуск передачи (однократный вызов write_ep()) - из основной задачи.

У Вас там что, циклические буферы? По идее, еще семафоры предусмотреть придется..
У меня в прошлом проекте логика попроще:
приемник получает весь трансфер в массив и вызывает обработчик. Тот, в зависимости от первого байта вызывает нужный кейс, тот отрабатывает данные, затирает тот же буфер данными для передачи и возвращает длину. После вызывается отправка.
Ну это проект зацикленный на управлении с пк, никаких своих процессов.
В том проекте, кстати, использовался USB raw на stdlib. Скорость была просто ужасная. Ну и гемор с драйвером и самопальными PID VID. Решил перескочить на CDC и libopencm3.
Цитата(esaulenka @ Oct 19 2015, 20:49) *
Вот уроды, я ж в этот код уже несколько месяцев не лазил (все дескрипторы у меня короче)...
До остальных эндпоинтов у них руки пока не дошли.

Ха.

Сообщение отредактировал drozel - Oct 19 2015, 16:24
Go to the top of the page
 
+Quote Post
Kabdim
сообщение Oct 19 2015, 23:57
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842



Цитата(SSerge @ Oct 19 2015, 18:05) *
Можно и наоборот: никогда не передавать больше 63 байт за раз.
Это сделать значительно проще, не нужно досконально изучать и переписывать всю библиотеку.

Рано или поздно появится необходимость в чем-то сложнее CDC, лучше к этому моменту иметь правильную библиотеку.
Go to the top of the page
 
+Quote Post
drozel
сообщение Oct 20 2015, 04:35
Сообщение #10


Частый гость
**

Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650



Интересно, что в stdlib контроль трансфера уже прописан в низкоуровневых функциях:
Код
/* Program the transfer size and packet count
      * as follows: xfersize = N * maxpacket +
      * short_packet pktcnt = N + (short_packet
      * exist ? 1 : 0)
      */
      deptsiz.b.xfersize = ep->xfer_len;
      deptsiz.b.pktcnt = (ep->xfer_len - 1 + ep->maxpacket) / ep->maxpacket;
      
      if (ep->type == EP_TYPE_ISOC)
      {
        deptsiz.b.mc = 1;
      }      
    }
    USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPTSIZ, deptsiz.d32);

Какого черта такое творится в libopencm3??
Я над, казалось бы, файлом верхнего уровня USB_cdc.c должен воротить логику протокола?

Сообщение отредактировал drozel - Oct 20 2015, 04:39
Go to the top of the page
 
+Quote Post
drozel
сообщение Oct 22 2015, 10:29
Сообщение #11


Частый гость
**

Группа: Свой
Сообщений: 108
Регистрация: 2-02-11
Пользователь №: 62 650



Еще вопрос: в случае передачи послыки с ПК через CDC кто организует ZLP, когда кол-во байт кратно 64?
Terminal шлет строку по одному символу в кадре, а NI VISA просто отправляет 64 без всяких ZLP.

Не могу составить нормальное представление работы CDC. Я полагал, что пользователь системы работает с портом, как с простым UART, засылая теда что хочет и когда хочет. А драйвер передает это в МК пакетами по 64 байта, трансферами по 1024. Т.е. если я пошлю 256 байт, уйдет 4 пакета и ZLP. Если отправлю 1025, уйдет 16 пакетов, потом МК поставит NACK и ПК будет ждать разрешения для досылки еще одного байта. И пытаюсь создать соответствующую логику на МК, которая будет формировать трансфер (ожидая ZLP или пакета меньше чем 64 байта), после чего выставлять force NAK и вызывать обработчик для данных.

Поправьте, в чем я не прав.

Сообщение отредактировал drozel - Oct 22 2015, 10:59
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 09:26
Рейтинг@Mail.ru


Страница сгенерированна за 0.01461 секунд с 7
ELECTRONIX ©2004-2016