W5100 does not work, TCP client mode

Много времени потратил. W5100 в режиме сервера работает, в режиме клиента нет.

W5100, SPI. На компьютере поднял сервер TCP и ожидаю соединения на порту 10301. ip адрес компьютера 169.254.194.110

Код инициализации w5100 и открытие сокета

[code] //делаем сброс аппаратный W5100
GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_7, 0);
Task_sleep(100);
GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_7, GPIO_PIN_7);
Task_sleep(500);

//софтварный сброс;
writeW5100(W5100, (uint8_t)W51_MR_RST, W51_MR);
Task_sleep(3000);

// writeByte(spi, 0, 0x10); //запретить пинг

writeW5100(W5100, (uint32_t)0x01020304, W51_GAR); //
writeW5100(W5100, (uint16_t)0x2710, W51_RTR); //пишим Retry Time-value Register 1 секунда
writeW5100(W5100, (uint8_t)10, W51_RCR); //пишим Retry Count Register 10 попыток

uint8_t array[100] =
{ 0x00, 0x22, 0x20, 0x13, 0xd9, 0x7b };
writeW5100(W5100, array, 6, W51_SHAR); //запишим MAC адрес
writeW5100(W5100, (uint32_t)0xffffff00, W51_SUBR); //пишим маску сети 255, 255, 255, 0
writeW5100(W5100, 0xc0fec205, W51_SIPR); //пишим ip свой 169.254.194.5
//
writeW5100(W5100, (uint16_t)0x5555, W51_RMSR); //инициализация памяти, всем по 2 кб

writeW5100(W5100, (uint8_t)W51_PROTOKOL_TCP, W51_S1_MR); //S1_MR set TCP
writeW5100(W5100, (uint16_t)0x283d, W51_S1_DPORT); //порт 10301 на сокете 1 для датчика скорости вращения антенны
writeW5100(W5100, (uint16_t)48000, W51_S1_PORT); //порт 48000
uint8_t array4[4] = { 169, 254, 194, 110 };
writeW5100(W5100, array4, 4, W51_S1_DIPR);
uint8_t byte;

writeW5100(W5100, (uint8_t)W51_CR_OPEN, W51_S1_CR);
for(int i = 0; i < 10; i++)
{
	readW5100(W5100, array, 1, W51_S1_SR);
	Task_sleep(1000);
	if(array[0] == W51_SR_SOCK_INIT)
		break;
}
writeW5100(W5100, (uint32_t)0, W51_SUBR);//сброс маски сети в 0
readW5100(W5100, &byte, 1, W51_S1_SR);
writeW5100(W5100, (uint8_t)W51_CR_CONNECT, W51_S1_CR);
while(1)
{
	readW5100(W5100, &byte, 1, W51_S1_CR);
	if(byte == 0)
		break;
}
writeW5100(W5100, (uint32_t)0xffffff00, W51_SUBR);//восстановление маски 255.255.255.0
readW5100(W5100, array, 1, W51_S1_IR);
readW5100(W5100, &byte, 1, W51_S1_SR);[/code]

С таким кодом не могу соединиться с сервером. Запустил на компьютере wireshark и смотрю лог. Снимок 1.
после подачи команды connect, регистр S1_CR сбрасывается в 0, а регистр статуса S1_SR становитсья 0х15. Через какое-то время регистр S1_SR становиться 0, а регистр прерывания S1_IR становиться 0х08 (таймаут)

Может что с сервером не так? Вместо w5100 подключил ноутбук и с помощью программы TCP Port Toolkit подключаюсь к серверу. Соединение нормально устанавливается. Посмотрел лог в wireshark - Снимок 2

Почему w5100 не может установить соединение с сервером?



На первой картинке, как видно, всё работает? Пятый сто десятому, а тот отвечает, и делее обмен пустыми пакетами, чтобы поддерживать связь. Однако мне не понятно значение размера буфера - 8К.
На второй удаленный интерфейс просто ничего не отвечает. Маски сети совпадают? Напомню, что ru.wikipedia.org/wiki/Link-local_address

То есть маска должна быть 255.255.0.0, а не как тут

   writeW5100(W5100, (uint32_t)0xffffff00, W51_SUBR); //пишим маску сети 255, 255, 255, 0

Далее

   writeW5100(W5100, (uint16_t)48000, W51_S1_PORT); //порт 48000

Номер порта не совпадает с первой картинкой.
Далее, код

for(int i = 0; i < 10; i++) { readW5100(W5100, array, 1, W51_S1_SR); Task_sleep(1000); if(array[0] == W51_SR_SOCK_INIT) break; }
подразумевает, что независимо от того, открылся ли сокет через 10 секунд, происходит выполнение последующего кода. Читайте раздел 5 даташита, а также диаграмму состояний на стр. 28.

Далее,

writeW5100(W5100, (uint32_t)0, W51_SUBR);//сброс маски сети в 0 readW5100(W5100, &byte, 1, W51_S1_SR);
это зачем? Зачем сбрасывать сетку так, чтобы выпасть из сетки 169.254.1.0 по 169.254.254.255? И зачем читать статус, если он не используется?

Далее,

while(1) { readW5100(W5100, &byte, 1, W51_S1_CR); if(byte == 0) break; }
таким образом проверяется завершение команды, но совсем не факт, что она завершилась соединением.

И последнее,

   writeW5100(W5100, (uint32_t)0xffffff00, W51_SUBR);//восстановление маски 255.255.255.0

тоже не понятно (и маска, сорее всего, неправильная).

Как надо делать -

  1. инициализировать чип правильными данными. Инициализировать надо как общие регистры, так и сокет. У вас вроде всё сделано, однако маска, скорее всего, неправильная.
  2. открывать сокет, ждать, пока команда не выполнилась (CR==0). Если ошибка, то есть статус после этого не 0x13 - пытаться переоткрыть (алгоритм есть в даташите).
  3. коннектиться к удаленному интерфейсу, по завершении команды (CR==0) проверять результат команды в SR, при успехе он должен быть 0x17, иначе сокет закрыть и всё начать с шага 2 заново (или закончить, по необходимости).

Добрый день, спасибо за быстрый ответ и рекомендации.

нашел у себя ошибку.

writeW5100(W5100, 0xc0fec205, W51_SIPR); //пишим ip свой 169.254.194.5

только вот 0xc0fec205 - это 192.254.194.5. Это и wireshark показал, просмотрел. Сорри за беспокойство.

Однако… остался вопрос по поводу сброса маски подсети. В еррате пишется, что есть аппаратный глюк w5100 и рекомендации по обходу его.
Глюк в следующем: при коннекте w5100 посылает ARP запрос не на дистанейшин ip а на gateway ip. Чтобы обойти этот глюк нужно маску сбросить в 0,0,0,0. Перед коннектом установить валидную маску, а после коннекта опять сбросить в 0.

На ЭФО есть библиотека W5100_driver_v1_6. В ней тоже этот сброс маски в 0 используется.

Хотелось бы от первого лица узнать об этом. Действительно ли есть этот глюк и нужно ли делать подобные финты с маской?

ps Отдельное СПАСИБО за поддержку на русском языке!!!

Я до этого не читал эту эррату, наверное был не прав. Рассмотрим каждый случай -

  1. К счастью, я не использовал RAW mode, так как режимы TCP и UDP работают вполне удовлетворительно, и являются большими плюсами чипа.
  2. “The W5100 replies with gateway IP address for the ARP request from network node which has “0.0.0.0” IP address” я думаю, что мне все равно, что получит утсройство с таким IP адресом, только если W5100 не DHCP сервер, тогда W5100 должен обрабатывать запросы от 0.0.0.0 корректно.
  3. “Assuming that the IP address of W5100 is “0.0.0.0” and the gateway, subnet mask is valid (not “0.0.0.0”)” то есть программа знает GW, но не может установить свой IP адрес, что довольно странно. Обычно вся данная информацию появляется через DHCP.
    Думаю, что все эти случаи исключительные, на грабли которых мне не удалось наступить :slight_smile:
    Но я вам благодарен за то, что я о них узнал.

Теперь по тексту, как обычно написанному на коренглише.

Данное значение, FF.FF.FF.xx, это не то значение, которое надо установить. Надо установить значение, соответствующее подсетке. Ответ находится в коде

/* Save the right subnet mask value if the subnet is 255.255.255.0 */

то есть “установите правильную маску подсети ЕСЛИ подсеть 255.255.255.0”. В вашем случае подсетка 255.255.0.0, и ее значение нужно вернуть в то же состояние.

Добрый день.
Перестал работать Client mode. Не конектиться к серверу. Сделал в коде loop в которо в дебаге смотрю все регистры чипа.

static uint8_t array2[10];
	uint16_t adrReg = 0x0500;
	while(1)
	{
		writeW5100(W5100, array2, 1, adrReg);
		Task_sleep(50);
		readW5100(W5100, &array2[3], 1, adrReg);
		Task_sleep(50);
	} 

Дебагом останавливаюсь в while и правлю адрес регистра и данные. Общие регитры прописываються нормально. Сокетные регистры… Socket n Mode Register - для сокета 0 и 1 пишеться и читается. Регситры Destination IP Address и Destination Port для 0 и 1 сокетов не пишется.
Пишу в регистр с адресом 0x0510 значение 0х55, читаю 0х00. Проверил на двух платах - картина одинаковая. Не могу прописать адрес и порт удаленного узла в регистры сокета. Почему? Может они прописываются, но не читаются?

Значения некоторых регистров “появляются” только после определенных действий. 0x510 это Sn_DPORT, попробуйте подконнектиться к какому-нибудь ресурсу, а потом прочитать.

А что говорит Wireshark? Может проблема в сети или в сервере?

Решил проблему. Sn_DPORT также как и Sn_DiP будет изменяться только после того, как порт откроется. Для клиента сначала нужно открыть порт, потом задать задать Sn_DPORT и Sn_DiP - тольк опотом эти регистры будут меняться. А потом нужно делать коннект.

Я что-то поправил стал делать сначала запсь Sn_DPORT и Sn_DiP, а потом опен и коннект, поэтому перестало работать.