SimpleSoft 0 4 августа, 2019 Опубликовано 4 августа, 2019 · Жалоба Добрый день, реализуем YModem поверх USB CDC. Тестируем под Win7 с помощью TeraTerm. Как только начинается передача пакетов данных от ПК (TeraTerm) в STM32, пакеты данных (по 512) прилетают с такой скоростью, что забивают кольцевой буфер под завязку. Посмотрели более детально, TeraTerm (Ymodem TX) повторяет пакеты до тех пор, пока STM32 не пришлёт ACK (тогда шлёт следующий кусок данных). Возник вопрос - как "притормозить" приходящие пакеты? Мы рассматривали вариант отключать прерывания USB: hpcd_USB_OTG_HS.Instance->GAHBCFG &= ~USB_OTG_GAHBCFG_GINT; Но это как-то жестоко, хоть и работает. Второй вариант который мы рассматривали - это Flow Control, но отбросили - не всегда его конечный клиент использует, да и потом без него тоже система должна корректно отрабатывать. Обработчик который сейчас реализован: static int8_t CDC_Receive_HS(uint8_t* Buf, uint32_t *Len) { /* USER CODE BEGIN 11 */ USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceHS.pClassData; if (hcdc) { USBD_CDC_SetRxBuffer(&hUsbDeviceHS, Buf); USBD_CDC_ReceivePacket(&hUsbDeviceHS); if (bs_usb_rx_command(Buf, hcdc->RxLength) == 0) { return (USBD_BUSY); } } return (USBD_OK); /* USER CODE END 11 */ } Если функция bs_usb_rx_command не может записать в кольцевой буфер (он полон) данные - возвращаем USBD_BUSY (по сути теряем данные). Но следующие тут же прилетают. Поделитесь, пожалуйста, опытом, как вы решали подобную задачу. Спасибо! MCU: STM32H743XIH STM32CubeIDE Version: 1.0.2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 4 августа, 2019 Опубликовано 4 августа, 2019 · Жалоба 9 минут назад, SimpleSoft сказал: Поделитесь, пожалуйста, опытом, как вы решали подобную задачу. Спасибо! Написать парсер выделяющий границы кадров прям в этом обработчике приёма (CDC_Receive_HS()). Выделил кадр - записал его в буфер (послал на обработку задаче обработчика) и взвёл флаг - "занято". Когда задача-обработчик полностью вычитает кадр из буфера - она снимет флаг. Пока флаг стоит - обработчик приёма должен кадры пропускать (но всё равно сначала выделять их границы! - и только целиком пропускать). Т.е. - говоря грамотным языком: Вам надо процесс приёма потока кадров разбить на уровни (канальный, прикладной, ...). Канальный выполнять в обработчике приёма, прикладной - в фоновой задаче. PS: Я не читал описание протокола YModem - ACK там является признаком чего? Просто признаком приёма кадра (вне зависимости от его содержимого) или признаком что удалённая сторона обработала данные из этого кадра и готова принять ещё? Если первое - то ACK должен генерить обработчик приёма сразу по завершении обнаружения границ кадра (ну или если там есть CRC - после обнаружения границ и проверки CRC). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 4 августа, 2019 Опубликовано 4 августа, 2019 (изменено) · Жалоба 52 минуты назад, SimpleSoft сказал: Возник вопрос - как "притормозить" приходящие пакеты? Мы рассматривали вариант отключать прерывания USB: Почему? Вот почему вы не прочитали хотя бы какую-нибудь статью вроде "USB на пальцах"? Там, ближе к началу, обязательно должно быть сказано, что если конечная точка не готова принимать данные, она должна отвечать NAK. Все остальное будет решаться на уровне контроллера. Изменено 4 августа, 2019 пользователем Сергей Борщ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 64 4 августа, 2019 Опубликовано 4 августа, 2019 · Жалоба 51 minutes ago, SimpleSoft said: Возник вопрос - как "притормозить" приходящие пакеты? Просто не читать, чтобы USB device возвращал хосту NAK. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 4 августа, 2019 Опубликовано 4 августа, 2019 · Жалоба 11 минут назад, Сергей Борщ сказал: Почему? Вот почему вы не прочитали хотя бы какую-нибудь статью вроде "USB на пальцах"? Там, ближе к началу, обязательно должно быть сказано, что если конечная точка не готова принимать данные, она должна отвечать NAK. Все остальное будет решаться на уровне контроллера. А если кадры YModema-а не будут совпадать с USB-кадрами? Т.е. - комп пошлёт 2 кадра YModem-а "впритык" друг к другу не дожидаясь ACK. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 64 5 августа, 2019 Опубликовано 5 августа, 2019 · Жалоба 1 hour ago, jcxz said: А если кадры YModema-а не будут совпадать с USB-кадрами? Т.е. - комп пошлёт 2 кадра YModem-а "впритык" друг к другу не дожидаясь ACK. И каким боком это помешает управлению потоком на уровне USB? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 5 августа, 2019 Опубликовано 5 августа, 2019 · Жалоба 11 часов назад, jcxz сказал: А если кадры YModema-а не будут совпадать с USB-кадрами? А если YModem передается через RS232, где вообще кадров нет? А если этот RS232 с "железным" управлением потоком и приемная сторона дернет RTS? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 5 августа, 2019 Опубликовано 5 августа, 2019 · Жалоба 9 часов назад, aaarrr сказал: И каким боком это помешает управлению потоком на уровне USB? Управлению потоком - никак, но вот парсингу на кадры - запросто может помешать. Так как будут приходить обрывки кадров. 36 минут назад, Сергей Борщ сказал: А если YModem передается через RS232, где вообще кадров нет? А если этот RS232 с "железным" управлением потоком и приемная сторона дернет RTS? Т.е. Вы хотите сказать, что по NAK-у USB-хост будет просто повторять данные позже? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 64 5 августа, 2019 Опубликовано 5 августа, 2019 · Жалоба 3 minutes ago, jcxz said: Т.е. Вы хотите сказать, что по NAK-у USB-хост будет просто повторять данные позже? Разумеется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 5 августа, 2019 Опубликовано 5 августа, 2019 · Жалоба 8 минут назад, jcxz сказал: Т.е. Вы хотите сказать, что по NAK-у USB-хост будет просто повторять данные позже? Если мне не изменяет память, вы хвастались тут самописным стеком USB. Неужели с момента его написания все забылось напрочь? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 186 5 августа, 2019 Опубликовано 5 августа, 2019 · Жалоба 54 минуты назад, Сергей Борщ сказал: Если мне не изменяет память, вы хвастались тут самописным стеком USB. Неужели с момента его написания все забылось напрочь? Причём тут? Я его не использовал для CDC. Да и не хвастался я самописным. Брал его из примеров IAR. Память точно изменяет... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 64 5 августа, 2019 Опубликовано 5 августа, 2019 · Жалоба 14 minutes ago, jcxz said: Причём тут? Я его не использовал для CDC. Так это общий механизм USB, причем тут CDC? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SimpleSoft 0 5 августа, 2019 Опубликовано 5 августа, 2019 (изменено) · Жалоба Спасибо всем за ответы. 18 hours ago, Сергей Борщ said: Почему? Вот почему вы не прочитали хотя бы какую-нибудь статью вроде "USB на пальцах"? Мы хорошо разбираемся в USB, мой вопрос был про опыт решения на STM32. По поводу не читать USB RX - мы не пробовали, но возник вопрос - а не будет ли STM32 дергать постоянно прерывание о приёме данных? (в Tech Ref не копались) Может кто-то знает как OTG в STM32H7 обрабатывает RX data interrupt? Изменено 5 августа, 2019 пользователем SimpleSoft Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 5 9 августа, 2019 Опубликовано 9 августа, 2019 · Жалоба On 8/5/2019 at 6:59 PM, SimpleSoft said: Мы хорошо разбираемся в USB Не похоже, извините. On 8/5/2019 at 6:59 PM, SimpleSoft said: мой вопрос был про опыт решения на STM32 Контроллер позволяет отправлять и ACK, и NAK. То, что это не позволяет сделать кубохал (кажется. Детально не исследовал) - не проблема контроллера. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 9 августа, 2019 Опубликовано 9 августа, 2019 (изменено) · Жалоба On 8/4/2019 at 11:55 PM, SimpleSoft said: Поделитесь, пожалуйста, опытом, как вы решали подобную задачу. Спасибо! Это делается созданием дополнительной задачи. Она только читает из USB и отправляет указатели на полученные пакеты в очередь. Просто запомните на будущее - все зависимые друг от друга процессы обрабатывающие данные с разной скоростью используют для обмена между собой очереди. Если у вас нет вытесняющей RTOS, то такую очередь делать довольно хлопотно. А если есть RTOS то все проще. Вместе с задачей Ymodem надо создать параллельную задачу чтения из USB. Вот как такая задача выглядит в RTOS ThreadX: Spoiler static void Mb_usbfs_rcv_task(ULONG ptr) { UINT res; ULONG actual_length; ULONG actual_flags; T_usbfs_drv_cbl * p = (T_usbfs_drv_cbl *)ptr; uint32_t n; do { if (p->active) { n = p->head_n; res = ux_device_class_cdc_acm_read(p->cdc, p->rd_pack[n].buff,USBDRV_BUFFER_MAX_LENGTH, &actual_length); // Чтение пакета из USB p->rd_pack[n].len = actual_length; if (res == UX_SUCCESS) { // Перемещаем указатель головы очереди n++; if (n >= IN_BUF_QUANTITY) n = 0; p->head_n = n; // Выставляем флаг выполненного чтения if (tx_event_flags_set(&(p->evt), MB_USBFS_READ_DONE, TX_OR) != TX_SUCCESS) { tx_thread_sleep(2); // Задержка после ошибки } // Если все буферы на прием заполнены, то значит системе не требуются данные if (p->tail_n == n) { // Перестаем принимать данные из USB и ждем когда система обработает уже принятые данные и подаст сигнал к началу приема по USB p->no_space = 1; if (tx_event_flags_get(&(p->evt), MB_USBFS_READ_REQUEST, TX_AND_CLEAR,&actual_flags, TX_WAIT_FOREVER) != TX_SUCCESS) { tx_thread_sleep(2); // Задержка после ошибки } } } else { tx_thread_sleep(2); // Задержка после ошибки } } else { tx_thread_sleep(2); // Задержки после ошибки нужны для того чтобы задача не захватила все ресурсы в случает постоянного появления ошибки } } while (1); } Т.е. здесь задача чтения из USB при заполненной очереди перестает вызывать функцию получения пакетов, а зависает на ожидании флага от задачи Ymodem-а Заполненность очереди определяется просто по равенству указателей на хвост (p->tail_n) и на голову очереди (p->head_n). И очередь здесь не очередь байт, а очередь буферов. В простейшем случае очередь состоит из двух буферов. Контроллеры USB не реагируют прерываниями на запросы хоста к пустым точкам доступа, тут можно быть спокойным. Изменено 9 августа, 2019 пользователем AlexandrY Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться