| Форум РадиоКот https://radiokot.ru/forum/ |
|
| W5500 переполнение выходного буфера https://radiokot.ru/forum/viewtopic.php?f=61&t=161252 |
Страница 1 из 1 |
| Автор: | Scaarj [ Пн мар 04, 2019 05:24:35 ] | ||
| Заголовок сообщения: | W5500 переполнение выходного буфера | ||
Здравствуйте. Проверяю данную плату на предельных скоростях на своём протоколе, в качестве МК взят Arduino. Начал наблюдать следующие поведение. Выходной буфер сокета TX переполняется и соответственно мк подвисает, пока буфер не очистится. Очищение всего буфера происходит через определенное время, видимо, по какому-то внутреннему таймеру чипа (~200 мс). При этом такое поведение наблюдается только тогда, когда работают два микроконтроллера в режиме запись-чтение. При работе мк с компьютером выходной буфер сокета освобождается сразу как сообщение будет послано. Какое условие должно быть выполнено, чтобы буфер TX освободился? Запись в буфер->запись указателя буфера->отправка сообщения->ожидания подтверждения? Write в сокет я использую полностью как в родной Wiznet библиотеке. Read маленько модифицировал - читает в два приёма, правда в один приём тоже самое выходит. Код: int16_t recv = w5500.getRXReceivedSize(_sock); uint16_t ptr = w5500.readSnRX_RD(_sock); uint8_t sz_msg = 0; if(recv >= 2) { uint8_t head[2]; w5500.read_data(_sock, ptr, head, 2); ptr += 2; sz_msg = head[1]; message = new char[sz_msg + 1]; w5500.read_data(_sock, ptr, (uint8_t*)message, sz_msg); ptr += sz_msg; message[sz_msg] = 0; w5500.writeSnRX_RD(_sock, ptr); w5500.execCmdSn(_sock, Sock_RECV); } //else // здесь пока ничего не сделал, но все сообщения более 2 б, это точно return sz_msg; Картинку приложил. 1-ый канал блокирующие чтение сокета, 2-ой канал отправка сообщений, блокируется соотвественно пока ждёт while (freesize < ret);.
|
|||
| Автор: | roman.com [ Пн мар 04, 2019 21:54:15 ] |
| Заголовок сообщения: | Re: W5500 переполнение выходного буфера |
Какое условие должно быть выполнено, чтобы буфер TX освободился? Это кольцевой буфер... он никогда не освободится)) https://ru.wikipedia.org/wiki/Кольцевой_буфер Если значение приращения счётчика буфера превышает максимальное значение 0xFFFF, то есть больше 0x10000, счётчик буфера обнуляется... И так по кругу)) Просто надо отправить W5500 команду передачи пакета (SEND) и немного подождать...)) пока закончится передача пакета... После передачи пакета установится соответствующий флаг (см. регистр флагов) и статус команды (SEND) Sn_CR = 0x20 меняется на (SEND) Sn_CR = 0x00. (команда выполнена). Вообще режим TX в W5500 такой: 1-Прочитайте начальный адрес буфера TX (регистр указателя Sn_TX_WR ) для записи передаваемых данных. 2-Сохраните передаваемые данные с начального адреса буфера TX (регистр указателя Sn_TX_WR). 3-После сохранения передаваемых данных обновите адрес буфера TX (регистр указателя Sn_TX_WR ) до увеличенного значения. 4-Запись команды передачи SEND. 5-Дождитесь окончания передачи (по окончанию передачи статус Sn_CR = 0x20 меняется на Sn_CR = 0x00). (команда выполнена). (из даташита): Если записать новые данные в буфер TX раньше, чем закончится текущая передача, то это может привести к ошибке передачи. Очищение всего буфера происходит через определенное время, видимо, по какому-то внутреннему таймеру чипа (~200 мс). это RTR (Retry Time-value Register) - период повторной передачи W5500. W5500 ожидает подтверждение (ACK) на отправленный пакет. Если запрашиваемый узел не отвечает в течении RTR (200 мс), то W5500 ретранслирует пакет повторно. ещё есть RCR - количество повторных ретрансляций. если нет подтверждения (ACK) в течении RTR (200 мс) х (RCR + 1), то происходит таймаут. таймаут для ARP = 2000 X 0.1ms X 9 = 1800ms =1.8s (по умолчанию) таймаут для TCP = (0x07D0+0x0FA0+0x1F40+0x3E80+0x7D00+0xFA00+0xFA00+0xFA00+0xFA00) X 0.1ms = (2000 + 4000 + 8000 + 16000 + 32000 + ((8 - 4) X 64000)) X 0.1ms = 318000 X 0.1ms = 31.8s (по умолчанию) и т.д. )) |
|
| Автор: | Scaarj [ Вт мар 05, 2019 08:41:07 ] |
| Заголовок сообщения: | Re: W5500 переполнение выходного буфера |
Цитата: Это кольцевой буфер... он никогда не освободится)) https://ru.wikipedia.org/wiki/Кольцевой_буфер Здесь подразумевается свободный участок для записи. Размер свободного буфера можно прочитать в регистре Sn_TX_FSR. Считается как разница Sn_TX_WR и Sn_TX_RD. В случае TCP маленько подругому. Есть внутрений ACK указатель, который сдвигается на место Sn_TX_WR в случае подтверждения и вот он видимо не двигается. При этом в связке с компьютером-подписчиком всё прекрасно работает - размер буфера уменьшается не более чем на 1-2 размеров сообщений (выводил Sn_TX_FSR в последовательный порт). При работе в паре с микроконтроллером-подписчиком видимо не долетают/не успевают обрабатываться пакеты с ACK. Я поэтому и выложил код чтения подписчиком, так как для записи код выглядит рабочим. Я посмотрел алгоритм записи в сокет - всё как в мануале и даже более - ожидание прерывания SEND_OK. Вот так выглядит алгоритм 1) Чтение Sn_TX_FSR 2) Ждём пока Sn_TX_FSR < len размер нашего пакета и параллельно проверяем соединение. 3) Считываем Sn_TX_WR в ptr 4) Записываем в буфер по адресу ptr длинной len данные data 5) Записываем новое положение указателя Sn_TX_WR ptr + len 6) Шлём команду Sock_SEND (0x20) и ждём 0x00 7) Ждём пока SnIR != SEND_OK (0x10) и параллельно проверяем соединение. зы уменьшил RTR и убедился, что этот провал обусловлен временем ожидания ACK. |
|
| Автор: | roman.com [ Вт мар 05, 2019 09:30:19 ] |
| Заголовок сообщения: | Re: W5500 переполнение выходного буфера |
Размер свободного буфера Sn_TX_FSR меня не интересует)) Т.к. размер буфера TX по умолчанию 2000 байт, а кадр максимум 1500 байт. https://ru.wikipedia.org/wiki/Ethernet#Формат_кадра Не знаю... я на своём W5500 делаю проще)) 1) - 2) - 3) Считываем Sn_TX_WR в add 4) Записываем в буфер W5500 по адресу Sn_TX_WR данные data и считает len (len = add + data). 5) Записываем новое положение указателя Sn_TX_WR + len 6) Шлём команду Sock_SEND (0x20) и ничего не ждём..)) Пока идёт передача в это время мой МК готовит новые данные для передачи... тайминги так расчитаны... )) Если данных больше нет: 7 -закрывает соединение DISCON 8 -ждём FIN... 9 -закрываем сокет CLOSE. Всё)) Scaarj писал(а): При работе в паре с микроконтроллером-подписчиком видимо не долетают/не успевают обрабатываться пакеты с ACK. Я вывожу на экран все регистры W5500 и смотрю анализатор трафика. Scaarj писал(а): Есть внутрений ACK указатель, который сдвигается на место Sn_TX_WR в случае подтверждения и вот он видимо не двигается. подтверждение чего? SYN ACK (подтверждение нового соединения), TCP ACK (подтверждение передачи пакета - окно TCP), FIN ACK (подтверждение разрыва соединения). у меня W5500 может после каждого пакета получать ACK: SYN... W5500 1500 байт -> перадача -1. <- ACK -1 W5500 1500 байт -> перадача -2. <- ACK -2 W5500 1500 байт -> перадача -3. <- ACK -3 ... FIN... а может после пачки пакетов получить один ACK: SYN... W5500 1500 байт -> перадача -1. W5500 1500 байт -> перадача -2. W5500 1500 байт -> перадача -3. <- ACK -3 ... FIN... И так и так у меня работает. Из чего я сделал вывод, что W5500 не ждёт подтверждение (ACK) на каждый отдельный пакет. Я отправляю сразу пачку пакетов и при этмом у меня буфер TX не переполняется... Главное дождаться окончания передачи перед отправкой нового пакета.)) Короче как-то так.)) |
|
| Автор: | Scaarj [ Вт мар 05, 2019 12:34:51 ] |
| Заголовок сообщения: | Re: W5500 переполнение выходного буфера |
В общем стало более менее понятно. w5500 довольно таки умный и когда пакеты прилетают слишком быстро он не отвечает на каждый пакет ACKом. Как выглядит в моём случае. Паблишер шлёт с макс скоростью сообщения - упирается в участок буфера, который ещё не был подтверждён и подвисает в ожидание ACK. Подписчик читает постоянно прилетающие сообщения, но не шлёт ACK, а аккумулирует все подтверждения для отправки одного ACK, но этот момент всё никак не может наступить И вот проходит 200 мс (по умолчанию) с момента отправки первого сообщения пабом. Чип видит, что данные не были доставлены и делает ретрансмиссию. Если RCR = 0 - получим разрыв соединения по таймауту. Если RCR > 0, то заново посылаем весь буфер (как его разбивает на фреймы по 1500 понятия не имею) и получает ACK от подписчика. Если уменьшить RTR со стороны издателя, то соответственно ретрансмиссия будет раньше, чем заполнится буфер, но на осциллограмме её даже не увидеть (дёргаю ногами перед/после write/read). А вот если уменьшить RTR со стороны подписчика, то этот интервал магическим образом станет уменьшаться. То есть грубо говоря у меня в одном цикле(200 мсек) ~130 мсек это приём-передача данных, 70 мсек ожидания ACK. Если RTR для подписчика указать меньше 70 (< 700*0.1), то этот интервал станет уменьшаться и будет в точности равен времени RTR
|
|
| Автор: | roman.com [ Вт мар 05, 2019 13:44:25 ] |
| Заголовок сообщения: | Re: W5500 переполнение выходного буфера |
Ясно)) я так подробно W5500 не разбирал... Надо будет поковырять)) Да, по даташиту там есть внутренний указатель... "difference between Sn_TX_WR and the internal ACK pointer which indicates the point of data is received already by the connected peer " Как он там работает.. без понятия)) Я не понимаю зачем он вообще нужен, если буфер 2000 байт. Это надо сначала буфер увеличивать до 16000 байт... Затем грузить в буфер кучу данных... Затем там (по идеи) должен работать автоматических фрагментатор, который нарезает фреймы по 1500 байт... и следит за их правильной отравкой)) И т.д. Вот тут тоже пытались оптимизировать работу TCP - http://we.easyelectronics.ru/electro-an ... henie.html А вообще для связи МК <> МК по интернету я обычно использую UDP. Он быстрее... А для всяких автоматических PING запросов использую MACRAW. |
|
| Автор: | Scaarj [ Вт мар 26, 2019 04:30:06 ] |
| Заголовок сообщения: | Re: W5500 переполнение выходного буфера |
В общем пришёл мне управляемый коммутатор, отзеркалил порт и увидел, что читающий МК не отсылает ACK, точнее отсылает, но не вовремя. Выглядит это как посылка N сообщений, потом те же N сообщений одним пакетом. А всего то надо было сделать, это прочитать полностью и внимательно документацию. У регистра Sn_MR, есть настройка в 5 бите - использование ACK без/с задержкой. Соответственно, задержка выставляется регистром RTR. Это я уже опытным путём выяснил Поэтому, если RTR рассылающего = RTR принимающего МК, а по умолчанию они равны 200 мс, то у нас будут постоянно ретрансмиссии и подвисания.. |
|
| Автор: | vinni_puh [ Пт фев 21, 2020 13:08:24 ] |
| Заголовок сообщения: | Re: W5500 переполнение выходного буфера |
Прпробовал конотрлировать регистр CR после отправки SEND - сбрасывается СРАЗУ ЖЕ. В ДШ на стр. 47 сказано: "After W5500 accepts the command, the Sn_CR register is automatically cleared to 0x00. Even though Sn_CR is cleared to 0x00, the command is still being processed. To check whether the command is completed or not, please check the Sn_IR or Sn_SR." Короче у меня проблема похожая, на большой нагрузке есть симптомы что происходит "перехлест" ТХ.. воюю дальше. (STM32F103VET6). Есть регистр Sn_TX_FSR - Tx-free-space-register - при передаче он увеличивается. Поставил заплатку, ожидание момента когда считываемые показания из этого регистра перестанут меняться. Это довольно немало - точно не считал.. но примерно с 20-50мкс. |
|
| Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
| Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |
|


