drozel 0 19 октября, 2015 Опубликовано 19 октября, 2015 (изменено) · Жалоба Использую 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 байт приведет к зависанию и вообще не похоже, что такая вещь предусмотрена разрабами Изменено 19 октября, 2015 пользователем drozel Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 19 октября, 2015 Опубликовано 19 октября, 2015 (изменено) · Жалоба Тем не менее zero length packet нужен. Изменено 19 октября, 2015 пользователем Kabdim Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
drozel 0 19 октября, 2015 Опубликовано 19 октября, 2015 · Жалоба Тем не менее zero length packet нужен. Я правильно понимаю, что без zero-length данные зависают на стороне приемника? Чем вообще ограничивается кол-во данных, которые можно протолкнуть без zero-packet? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 19 октября, 2015 Опубликовано 19 октября, 2015 · Жалоба Я правильно понимаю, что без zero-length данные зависают на стороне приемника?Да. Окончанием пакета считается посылка с числом байт меньше размера конечной точки (ноль байтов под этот критерий попадает). Так написано в стандарте. К чему приводит несоблюдение стандартов - вы наблюдаете сами. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 19 октября, 2015 Опубликовано 19 октября, 2015 · Жалоба Я правильно понимаю, что без zero-length данные зависают на стороне приемника? Чем вообще ограничивается кол-во данных, которые можно протолкнуть без zero-packet? Да. Если вопрос про макс размер трансфера, то афаик зависит от операционки, а именно драйвера USB. Для винды так. Если вопрос про то что бы не вставлять ZLP, то тоже довольно очевидно: если передаете байтов картных пакету нужно добавить 1 фейковый байт к передаче. Но решение не лучшее. Лучше использовать/написать более вменяемую библиотеку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SSerge 6 19 октября, 2015 Опубликовано 19 октября, 2015 · Жалоба Если вопрос про то что бы не вставлять ZLP, то тоже довольно очевидно: если передаете байтов картных пакету нужно добавить 1 фейковый байт к передаче. Но решение не лучшее. Лучше использовать/написать более вменяемую библиотеку. Можно и наоборот: никогда не передавать больше 63 байт за раз. Это сделать значительно проще, не нужно досконально изучать и переписывать всю библиотеку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 19 октября, 2015 Опубликовано 19 октября, 2015 · Жалоба Это сделать значительно проще, не нужно досконально изучать и переписывать всю библиотеку. Если "не изучать", можно найти всякие разные грабли. Как правило, ооочень невовремя. drozel, у меня используется следующая схема: usbd_poll() вызывается из прерывания, там есть два основных коллбэка: - out ep складывает принятые данные в буфер. Оттуда основная задача по мере сил и возможностей выгребает данные. - in ep пытается "достать" данные из буфера. Заполнение буфера и запуск передачи (однократный вызов write_ep()) - из основной задачи. В эту схему пакет нулевой длины легко приделывается, никаких while (write_ep(...)) {} не нужно. Хотя, конечно, кто ж им мешал возвращать отрицательные значения?.. PS полез рыться на репозитарий libopencm3, обнаружил те же самые грабли, но по обмену control endpoint. Исправили ровно неделю назад. Вот уроды, я ж в этот код уже несколько месяцев не лазил (все дескрипторы у меня короче)... До остальных эндпоинтов у них руки пока не дошли. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
drozel 0 19 октября, 2015 Опубликовано 19 октября, 2015 (изменено) · Жалоба - out ep складывает принятые данные в буфер. Оттуда основная задача по мере сил и возможностей выгребает данные. - in ep пытается "достать" данные из буфера. Заполнение буфера и запуск передачи (однократный вызов write_ep()) - из основной задачи. У Вас там что, циклические буферы? По идее, еще семафоры предусмотреть придется.. У меня в прошлом проекте логика попроще: приемник получает весь трансфер в массив и вызывает обработчик. Тот, в зависимости от первого байта вызывает нужный кейс, тот отрабатывает данные, затирает тот же буфер данными для передачи и возвращает длину. После вызывается отправка. Ну это проект зацикленный на управлении с пк, никаких своих процессов. В том проекте, кстати, использовался USB raw на stdlib. Скорость была просто ужасная. Ну и гемор с драйвером и самопальными PID VID. Решил перескочить на CDC и libopencm3. Вот уроды, я ж в этот код уже несколько месяцев не лазил (все дескрипторы у меня короче)... До остальных эндпоинтов у них руки пока не дошли. Ха. Изменено 19 октября, 2015 пользователем drozel Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Kabdim 0 19 октября, 2015 Опубликовано 19 октября, 2015 · Жалоба Можно и наоборот: никогда не передавать больше 63 байт за раз. Это сделать значительно проще, не нужно досконально изучать и переписывать всю библиотеку. Рано или поздно появится необходимость в чем-то сложнее CDC, лучше к этому моменту иметь правильную библиотеку. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
drozel 0 20 октября, 2015 Опубликовано 20 октября, 2015 (изменено) · Жалоба Интересно, что в 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 должен воротить логику протокола? Изменено 20 октября, 2015 пользователем drozel Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
drozel 0 22 октября, 2015 Опубликовано 22 октября, 2015 (изменено) · Жалоба Еще вопрос: в случае передачи послыки с ПК через CDC кто организует ZLP, когда кол-во байт кратно 64? Terminal шлет строку по одному символу в кадре, а NI VISA просто отправляет 64 без всяких ZLP. Не могу составить нормальное представление работы CDC. Я полагал, что пользователь системы работает с портом, как с простым UART, засылая теда что хочет и когда хочет. А драйвер передает это в МК пакетами по 64 байта, трансферами по 1024. Т.е. если я пошлю 256 байт, уйдет 4 пакета и ZLP. Если отправлю 1025, уйдет 16 пакетов, потом МК поставит NACK и ПК будет ждать разрешения для досылки еще одного байта. И пытаюсь создать соответствующую логику на МК, которая будет формировать трансфер (ожидая ZLP или пакета меньше чем 64 байта), после чего выставлять force NAK и вызывать обработчик для данных. Поправьте, в чем я не прав. Изменено 22 октября, 2015 пользователем drozel Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться