Ethernet shield hangs

I have funny problem with ethernet shield. I am using version 21 software. Duemillanove and official ethernet shield with W5100.

My Arduino controls my remote station electric energy production and usage. And it sends data as statistics to pachube (www.pachube.com/feeds/7458) and from webserver it checks if there are configuration changes, and adjusts its RTC time with NTP.
It is designed to work without internet. If ethernet is disconnected it is no problem. But now problem comes. If there are problems with internet further away from local router, that causes no response from webserver or other services, connection making hangs for too long before shield returns "no connection". This again causes Watchdog to reset the whole system, which again causes loss of power in the whole system. So every time lights go out I know there is no internet again :slight_smile:
So, question is how to make timeout happen faster?

Of the working principle and saving power, ethernet shield is switched off if not used. Every time it is powered up, waited until it resets properly and then initialised for every usege. So there can not be multiple connection problem. And it hangs on connect();

Any hints?

I've seen that there was a problem with too lenghty delay before recognizing connection fail. It was possible to make that time out shorter by modifying library only I can't find it anymore. Could anyone give some hints?

The timeout is controlled by the W5100 chip. I discovered you can change that timeout retry count and cut the timeout delay in half. You might want to play with that number. I have not tried a value less than 4.

This is in
/arduino-022/libraries/Ethernet/utility/w5100.cpp

I added a line in the init() function to shorten the timeout delay. The default retry count is 8. This sets that to 4.
Look for the "//Tim added" comment.

void W5100Class::init(void)
{
  delay(300);

  SPI.begin();
  initSS();
  
  writeMR(1<<RST);
  writeTMSR(0x55);
  writeRMSR(0x55);

// Tim added
  writeRCR(0x04);
  
  for (int i=0; i<MAX_SOCK_NUM; i++) {
    SBASE[i] = TXBUF_BASE + SSIZE * i;
    RBASE[i] = RXBUF_BASE + RSIZE * i;
  }
}

If you try a number smaller than 4, please let me know how it worked.

Thanx! It seems it worked. I set the retry count to 1. In that system it is not reasonable to frantically try to connect at any cost. Nothing serious happen if connection fails.

I will monitor how it works and if there are something interesting to report, I'll let you know.

Thanks, peep rada! :slight_smile:

I am about to need that in a few days, and it is good to know it works with 1. That is what I will need. One try, then back. I'll determine when it tries again.

Edit: I might be incorrect about the count. That register is a "retry" count. So setting that to '1' may try the connection twice. Maybe when I try the code in a few days, I will try setting that to '0'. :astonished:

I think i have the same problem. I use a server control a relay board via arduino uno R3 + Ethernet Shield W5100. After a short time, maybe 15 min, if there are not any command to control relay i can't control anymore. My power and router are good. So i think Ethernet Shield go to Watchdog.

Should i use this code?

void W5100Class::init(void)
{
delay(300);

SPI.begin();
initSS();

writeMR(1<<RST);
writeTMSR(0x55);
writeRMSR(0x55);

// Tim added
writeRCR(0x04);

for (int i=0; i<MAX_SOCK_NUM; i++) {
SBASE = TXBUF_BASE + SSIZE * i;
RBASE = RXBUF_BASE + RSIZE * i;
}
}
Thank you!

@PhamDinh: Then the solution above does not apply to you. Post your code.

I'm sorry. Here my code:

#include <SPI.h>
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <EthernetUdp.h>

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xED};
String code = "";
String doc = "";
String data;
int lencode;


IPAddress server(192,168,1,15);

EthernetClient client;


void setup() {
  //set pinmode to control 10 relay
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  // turn - off 10 realy
  digitalWrite(0, LOW); 
  digitalWrite(1, LOW); 
  digitalWrite(2, LOW); 
  digitalWrite(3, LOW); 
  digitalWrite(4, LOW); 
  digitalWrite(5, LOW);
  digitalWrite(6, LOW); 
  digitalWrite(7, LOW); 
  digitalWrite(8, LOW); 
  digitalWrite(9, LOW);
   
 // Ethernet.begin(mac, ip, mydns, gateway, subnet);
  Ethernet.begin(mac);
  if (Ethernet.begin(mac) == 0 )
       {
           Ethernet.maintain();          
       }
  delay(50);
  client.connect(server,1000);
  delay(200);
  while(!client.connected()){
    delay(50);
    client.stop();
    delay(50);
    client.connect(server, 1000);
    delay(200);
  }
  if (client.connected()) {
    client.print("relay already");
  }
}

void(*resetFunc) (void) = 0;

void loop()
{ 
  //get string command from server
  if (client.available()) {
    code = "";
    while (client.available() > 0) {
      char c = client.read();
      code += c;
    }
  }

 if ( code.startsWith("relay")) {
    command();
  }    

 //auto re-connect when internet problem
  while(!client.connected()){
      client.stop();
      delay(50);
      //try 10 times
      for(int i = 0; i<10;i++){
        delay(3000);
     
       client.connect(server, 1000);
        delay(50);
        if(client.connected()){         
          client.print("re-connect control relay");    
          return;
        }      
      }
      //after 10 times still not re-connect. Call resetFunc goto void(setup)
      digitalWrite(0, LOW); 
      digitalWrite(1, LOW); 
      digitalWrite(2, LOW); 
      digitalWrite(3, LOW); 
      digitalWrite(4, LOW); 
      digitalWrite(5, LOW);
      digitalWrite(6, LOW); 
      digitalWrite(7, LOW); 
      digitalWrite(8, LOW); 
      digitalWrite(9, LOW);
      resetFunc();
     }
}

void command()
{
  //PIN 0 :
  if( code.endsWith("OUT00")){
    digitalWrite(0,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT01")){
    digitalWrite(0,HIGH);
    delay(20);
    code = "";
  }
  //PIN 1 :
  if( code.endsWith("OUT10")){
    digitalWrite(1,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT11")){
    digitalWrite(1,HIGH);
    delay(20);
    code = "";
  }
  //PIN 2:
  if( code.endsWith("OUT20")){
    digitalWrite(2,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT21")){
    digitalWrite(2,HIGH);
    delay(20);
    code = "";
  }
 //PIN 3:
  if( code.endsWith("OUT30")){
    digitalWrite(3,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT31")){
    digitalWrite(3,HIGH);
    delay(20);
    code = "";
  }
  //PIN 4:
  if( code.endsWith("OUT40")){
    digitalWrite(4,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT41")){
    digitalWrite(4,HIGH);
    delay(20);
    code = "";
  }
  //PIN 5:
  if( code.endsWith("OUT50")){
    digitalWrite(5,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT51")){
    digitalWrite(5,HIGH);
    delay(20);
    code = "";
  }
  //PIN 6:
  if( code.endsWith("OUT60")){
    digitalWrite(6,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT61")){
    digitalWrite(6,HIGH);
    delay(20);
    code = "";
  }
  //PIN 7:
  if( code.endsWith("OUT70")){
    digitalWrite(7,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT71")){
    digitalWrite(7,HIGH);
    delay(20);
    code = "";
  }
  //PIN 8:
  if( code.endsWith("OUT80")){
    digitalWrite(8,LOW);
    delay(20);
    code = "";
  }
  if( code.endsWith("OUT81")){
    digitalWrite(8,HIGH);
    delay(20);
    code = "";
  }
  //PIN 9:
  if( code.endsWith("OUT90")){
    digitalWrite(9,LOW);
    code = "";
  }
  if( code.endsWith("OUT91")){
    digitalWrite(9,HIGH);
    delay(20);
    code = "";
  }
}

My code is fine. It is working.
Ex: I send string command from virtual TCPserver to Arduino, I will turn on/off relay

  • relayOUT00 : turn - off relay 1
  • relayOUT01 : turn - on relay 1
    and so on.

The problem is Ethernet Shield go to Watchdog or timeout/hang. I can not control after 15min.
I modified follow your code in library w5100.cpp. I set 0 and 1. But it did not work.

void W5100Class::init(void)
{
  delay(300);

#if !defined(SPI_HAS_EXTENDED_CS_PIN_HANDLING)
  SPI.begin();
  initSS();
#else
  SPI.begin(SPI_CS);
  // Set clock to 4Mhz (W5100 should support up to about 14Mhz)
  SPI.setClockDivider(SPI_CS, 21);
  SPI.setDataMode(SPI_CS, SPI_MODE0);
#endif
  SPI.beginTransaction(SPI_ETHERNET_SETTINGS);
  writeMR(1<<RST);
  writeTMSR(0x55);
  writeRMSR(0x55);
  SPI.endTransaction();

  [b]writeRCR(0x00);[/b]
 
  for (int i=0; i<MAX_SOCK_NUM; i++) {
    SBASE[i] = TXBUF_BASE + SSIZE * i;
    RBASE[i] = RXBUF_BASE + RSIZE * i;
  }
}

Thank SurferTim for your consider

After 15min, its mean I am not send any data from server to Arduino during 15min. just idle

PhamDinh:
My code is fine. It is working.

No, it's not. If it was working, it wouldn't lock up.

Take a look at this client code. It has a timeout that prevents lockups if the server stalls or the connection breaks. I've tested it extensively. Pay attention to the connectLoop variable.
http://playground.arduino.cc/Code/WebClient

Thank you very much, SurferTim. I wil try it and come back for few day.

Dear Mr.SurferTim,

Your is code is very good. I wrote a code approximate your code 3 month ago.

 void loop()
{
  if (client.available()) {
    code = "";
    while (client.available() > 0) {
      char c = client.read();
      code += c;
    }
  }
  lencode = code.length();

  if (lencode > 18 && code.startsWith("0001")) {
    SentUID();
  }

//keep connection alive 24/24
// send any character to server after 30s
   if (millis() - lastConnectionTime > postingInterval) {
    client.print("@");
    lastConnectionTime = millis();
  } 
   
  while (!client.connected()) {
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Ethernet Failed");
    delay(50);
    client.stop();
    Ethernet.maintain();
    pinMode(4, OUTPUT);
    digitalWrite(4, HIGH);
    delay(50);
    client.connect(server, 1000);
    
    delay(50);
    if (client.connected()) {
      code = "";
      client.print("0000RF#00100000002@");
      lcd.clear();
      lcd.setCursor(0,1);
      lcd.print("Connected"); 
      mfrc522.PCD_Init();
      delay(50);    
      return;
    }
  }
}

The code was about read UID of mifare card and send to server. I tested my device run full time 24h/day in a week. I keep connection alive full time by send character "@" (maybe another, anything) every 30s to avoid lock up. It was ok. But the problem is if we have a lot of devices send many different character as the same time. Server will receive data confusion and consumptive bandwidth of server.
Your code are really better. Thank you very much. Thank you for your consider.