arduino-libraries / Ethernet

Ethernet Library for Arduino
http://arduino.cc/
259 stars 264 forks source link

Some common register addresses in W5100.h are incorrect for W5500 #84

Open SapientHetero opened 5 years ago

SapientHetero commented 5 years ago

The W5500 data sheet (https://wizwiki.net/wiki/lib/exe/fetch.php?media=products:w5500:w5500_ds_v106e_141230.pdf) shows certain W5500 registers to be at different addresses than those used by the driver (W5100.h).

Current W5100.h values: GP_REGISTER16(RTR, 0x0017); // Timeout address __GP_REGISTER8 (RCR, 0x0019); // Retry count GP_REGISTER8 (RMSR, 0x001A); // Receive memory size (W5100 only) GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size (W5100 only) __GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer __GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode (W5100 only) GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode (W5100 only)

Updated W5100.h definitions per Wiznet W5500 version 1.0.6 data sheet values (see page 30, Section 3.1 Common Register Block): GP_REGISTER16(RTR, 0x0019); // Timeout address __GP_REGISTER8 (RCR, 0x001B); // Retry count GP_REGISTER8 (PTIMER, 0x001C); // PPP LCP Request Timer GP_REGISTER8 (PMAGIC, 0x001D); // PPP LCP Magic Number GP_REGISTER_N(PHAR, 0x001E, 6); // PPP Destination MAC address GP_REGISTER16(PSID, 0x0024); // PPP Session ID GP_REGISTER16(PMRU, 0x0026); // PPP Maximum Segment Size GP_REGISTER_N(UIPR, 0x0028, 4); // Unreachable IP address in UDP mode (W5500 only) GP_REGISTER16(UPORT, 0x002C); // Unreachable Port address in UDP mode (W5500 only) __GP_REGISTER8 (PHYCFGR_W5500, 0x002E); // PHY Configuration register, default: 10111xxx

I discovered this while tweaking RTR values in the hope of resolving the client-mode TCP connection problems others have reported. Setting RTR to 4000 (400ms) seems to have eliminated the connection timeout I was seeing, but I still have the problem in which socketConnect reports SnSR::CLOSED while waiting for SnSR::ESTABLISHED.

Update: Further testing revealed that the device I'm connecting to, a Linksys WRTGS running DD-WRT, routinely takes over 202 - 237 ms to connect (though it sometimes connects in as little as 100 ms). This is longer than the W5500's default of 200ms (W5500 datasheet, page 39), which caused constant failures to connect.

Setting the W5500 timeout (RTR) with the current driver was fruitless because W5100.h contains the wrong address for this register. After I fixed that, I was able to set RTR to 3000 by adding W5100.setRetransmissionTime(3000); to EthernetClient::connect (see code below).

I made two other minor mods while investigating this. I changed execCmdSn so the Arduino isn't constantly hammering the W5500's I/O while waiting for the command register to be zeroed by commenting out "while (readSnCR(s)) ;" and adding a loop with a modest delay between reads. After resolving the connection timeout issue I restored the original code and got an occasional failure to connect, while I got none with the new code.

{
    // Send command to socket
    writeSnCR(s, _cmd);
    // Wait for command to complete
    //while (readSnCR(s)) ;
    do {
        delayMicroseconds(100);
    } while (readSnCR(s));
}

The other minor mod was the increase of the delay in the loop in EthernetClient::connect that watches for the socket to enter ESTABLISHED status from 1 ms to 5 ms. I had persistent failures to connect with the 1 ms delay that vanished when I increased it to 5 ms. YMMV. Incidentally, my target platform is an Adafruit Metro M4 Express.

One last note; the W5500 datasheet (page 63, 5.5.4 SPI Timing) specifies a maximum guaranteed SPI bus clock rate of 33.3 MHz. I ran my tests with a SPI clock of 25 MHz. If your performance is flaky, consider reducing your SPI bus clock.


{
    if (sockindex < MAX_SOCK_NUM) {
        if (Ethernet.socketStatus(sockindex) != SnSR::CLOSED) {
            Ethernet.socketDisconnect(sockindex); // TODO: should we call stop()?
        }
        sockindex = MAX_SOCK_NUM;
    }
#if defined(ESP8266) || defined(ESP32)
    if (ip == IPAddress((uint32_t)0) || ip == IPAddress(0xFFFFFFFFul)) return 0;
#else
    if (ip == IPAddress(0ul) || ip == IPAddress(0xFFFFFFFFul)) return 0;
#endif

    **W5100.setRetransmissionTime(3000);**

    sockindex = Ethernet.socketBegin(SnMR::TCP, 0);
    if (sockindex >= MAX_SOCK_NUM) return 0;
    Ethernet.socketConnect(sockindex, rawIPAddress(ip), port);
    uint32_t start = millis();

    while (1) {
        uint8_t stat = Ethernet.socketStatus(sockindex);
        //iStats[i++] = stat;
        if (stat == SnSR::ESTABLISHED) return 1;
        if (stat == SnSR::CLOSE_WAIT) return 1;
        if (stat == SnSR::CLOSED) {
            return 0;
        }
        if ((uint16_t)(millis() - start) > _timeout) break;
        **delay(5);**
    }

    Ethernet.socketClose(sockindex);
    sockindex = MAX_SOCK_NUM;
    return 0;
}