W5100 stop working after 6 min


#1

Hi all,

I am using the Ethernet Arduino board.
I am sending and receiving packets of 128 bits size every 11 ms. After approximately 6 minuets the W5100 stops sending packets, and don’t get out from the while loop:

int sendUDP(SOCKET s)
{
[color=#FF0000] W5100.execCmdSn(s, Sock_SEND);

/* +2008.01 bj /
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
{
if (W5100.readSnIR(s) & SnIR::TIMEOUT)
{
/
+2008.01 [bj]: clear interrupt */
W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT));
return 0;
}
}[/color]

/* +2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK);

/* Sent ok */
return 1;
}

I will be happy to receive some help debugging it.

Thanks
Yoav


#2

Hi,

sendUDP() is only processing send command.
Plz, Post all data processing code such as data copy and pointer regsiters control.

Thank you.


#3

Hi,

I quote a part of code from the socket.cpp file of Arduino ethernet library.

The entire code is:

#include “w5100.h”
#include “socket.h”

static uint16_t local_port;

/**

  • @brief This Socket function initialize the channel in perticular mode, and set the port and wait for W5100 done it.

  • @return 1 for success else 0.
    */
    uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
    {
    if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE))
    {
    close(s);
    W5100.writeSnMR(s, protocol | flag);
    if (port != 0) {
    W5100.writeSnPORT(s, port);
    }
    else {
    local_port++; // if don’t set the source port, set local_port number.
    W5100.writeSnPORT(s, local_port);
    }

    W5100.execCmdSn(s, Sock_OPEN);

    return 1;
    }

return 0;
}

/**

  • @brief This function close the socket and parameter is “s” which represent the socket number
    */
    void close(SOCKET s)
    {
    W5100.execCmdSn(s, Sock_CLOSE);
    W5100.writeSnIR(s, 0xFF);
    }

/**

  • @brief This function established the connection for the channel in passive (server) mode. This function waits for the request from the peer.
  • @return 1 for success else 0.
    */
    uint8_t listen(SOCKET s)
    {
    if (W5100.readSnSR(s) != SnSR::INIT)
    return 0;
    W5100.execCmdSn(s, Sock_LISTEN);
    return 1;
    }

/**

  • @brief This function established the connection for the channel in Active (client) mode.
  •  This function waits for the untill the connection is established.
    
  • @return 1 for success else 0.
    */
    uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port)
    {
    if
    (
    ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
    ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
    (port == 0x00)
    )
    return 0;

// set destination IP
W5100.writeSnDIPR(s, addr);
W5100.writeSnDPORT(s, port);
W5100.execCmdSn(s, Sock_CONNECT);

return 1;
}

/**

  • @brief This function used for disconnect the socket and parameter is “s” which represent the socket number
  • @return 1 for success else 0.
    */
    void disconnect(SOCKET s)
    {
    W5100.execCmdSn(s, Sock_DISCON);
    }

/**

  • @brief This function used to send the data in TCP mode
  • @return 1 for success else 0.
    */
    uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len)
    {
    uint8_t status=0;
    uint16_t ret=0;
    uint16_t freesize=0;

if (len > W5100.SSIZE)
ret = W5100.SSIZE; // check size not to exceed MAX size.
else
ret = len;

// if freebuf is available, start.
do
{
freesize = W5100.getTXFreeSize(s);
status = W5100.readSnSR(s);
if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT))
{
ret = 0;
break;
}
}
while (freesize < ret);

// copy data
W5100.send_data_processing(s, (uint8_t *)buf, ret);
W5100.execCmdSn(s, Sock_SEND);

/* +2008.01 bj /
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
{
/
m2008.01 [bj] : reduce code /
if ( W5100.readSnSR(s) == SnSR::CLOSED )
{
close(s);
return 0;
}
}
/
+2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK);
return ret;
}

/**

  • @brief This function is an application I/F function which is used to receive the data in TCP mode.
  •  It continues to wait for data as much as the application wants to receive.
    
  • @return received data size for success else -1.
    */
    int16_t recv(SOCKET s, uint8_t *buf, int16_t len)
    {
    // Check how much data is available
    int16_t ret = W5100.getRXReceivedSize(s);
    if ( ret == 0 )
    {
    // No data available.
    uint8_t status = W5100.readSnSR(s);
    if ( status == SnSR::LISTEN || status == SnSR::CLOSED || status == SnSR::CLOSE_WAIT )
    {
    // The remote end has closed its side of the connection, so this is the eof state
    ret = 0;
    }
    else
    {
    // The connection is still up, but there’s no data waiting to be read
    ret = -1;
    }
    }
    else if (ret > len)
    {
    ret = len;
    }

if ( ret > 0 )
{
W5100.recv_data_processing(s, buf, ret);
W5100.execCmdSn(s, Sock_RECV);
}
return ret;
}

/**

  • @brief Returns the first byte in the receive queue (no checking)
  • @return
    */
    uint16_t peek(SOCKET s, uint8_t *buf)
    {
    W5100.recv_data_processing(s, buf, 1, 1);

return 1;
}

/**

  • @brief This function is an application I/F function which is used to send the data for other then TCP mode.
  •  Unlike TCP transmission, The peer's destination address and the port is needed.
    
  • @return This function return send data size for success else -1.
    */
    uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port)
    {
    uint16_t ret=0;

if (len > W5100.SSIZE) ret = W5100.SSIZE; // check size not to exceed MAX size.
else ret = len;

if
(
((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
((port == 0x00)) ||(ret == 0)
)
{
/* +2008.01 [bj] : added return value */
ret = 0;
}
else
{
W5100.writeSnDIPR(s, addr);
W5100.writeSnDPORT(s, port);

// copy data
W5100.send_data_processing(s, (uint8_t *)buf, ret);
W5100.execCmdSn(s, Sock_SEND);

/* +2008.01 bj */
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK ) 
{
  if (W5100.readSnIR(s) & SnIR::TIMEOUT)
  {
    /* +2008.01 [bj]: clear interrupt */
    W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */
    return 0;
  }
}

/* +2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK);

}
return ret;
}

/**

  • @brief This function is an application I/F function which is used to receive the data in other then
  • TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well.
  • @return This function return received data size for success else -1.
    */
    uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port)
    {
    uint8_t head[8];
    uint16_t data_len=0;
    uint16_t ptr=0;

if ( len > 0 )
{
ptr = W5100.readSnRX_RD(s);
switch (W5100.readSnMR(s) & 0x07)
{
case SnMR::UDP :
W5100.read_data(s, (uint8_t *)ptr, head, 0x08);
ptr += 8;
// read peer’s IP address, port number.
addr[0] = head[0];
addr[1] = head[1];
addr[2] = head[2];
addr[3] = head[3];
*port = head[4];
*port = (*port << 8) + head[5];
data_len = head[6];
data_len = (data_len << 8) + head[7];

  W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy.
  ptr += data_len;

  W5100.writeSnRX_RD(s, ptr);
  break;

case SnMR::IPRAW :
  W5100.read_data(s, (uint8_t *)ptr, head, 0x06);
  ptr += 6;

  addr[0] = head[0];
  addr[1] = head[1];
  addr[2] = head[2];
  addr[3] = head[3];
  data_len = head[4];
  data_len = (data_len << 8) + head[5];

  W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy.
  ptr += data_len;

  W5100.writeSnRX_RD(s, ptr);
  break;

case SnMR::MACRAW:
  W5100.read_data(s,(uint8_t*)ptr,head,2);
  ptr+=2;
  data_len = head[0];
  data_len = (data_len<<8) + head[1] - 2;

  W5100.read_data(s,(uint8_t*) ptr,buf,data_len);
  ptr += data_len;
  W5100.writeSnRX_RD(s, ptr);
  break;

default :
  break;
}
W5100.execCmdSn(s, Sock_RECV);

}
return data_len;
}

uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len)
{
uint8_t status=0;
uint16_t ret=0;

if (len > W5100.SSIZE)
ret = W5100.SSIZE; // check size not to exceed MAX size.
else
ret = len;

if (ret == 0)
return 0;

W5100.send_data_processing(s, (uint8_t *)buf, ret);
W5100.execCmdSn(s, Sock_SEND);

while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
{
status = W5100.readSnSR(s);
if (W5100.readSnIR(s) & SnIR::TIMEOUT)
{
/* in case of igmp, if send fails, then socket closed /
/
if you want change, remove this code. */
close(s);
return 0;
}
}

W5100.writeSnIR(s, SnIR::SEND_OK);
return ret;
}

uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len)
{
uint16_t ret =0;
if (len > W5100.getTXFreeSize(s))
{
ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size.
}
else
{
ret = len;
}
W5100.send_data_processing_offset(s, offset, buf, ret);
return ret;
}

int startUDP(SOCKET s, uint8_t* addr, uint16_t port)
{
if
(
((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
((port == 0x00))
)
{
return 0;
}
else
{
W5100.writeSnDIPR(s, addr);
W5100.writeSnDPORT(s, port);
return 1;
}
}

int sendUDP(SOCKET s)
{
W5100.execCmdSn(s, Sock_SEND);

/* +2008.01 bj /
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
{
if (W5100.readSnIR(s) & SnIR::TIMEOUT)
{
/
+2008.01 [bj]: clear interrupt */
W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT));
return 0;
}
}

/* +2008.01 bj */
W5100.writeSnIR(s, SnIR::SEND_OK);

/* Sent ok */
return 1;
}


#4

Hi,
Did you used with Arduino ethernet library without modifying?
I have already ardunion ethernet library and it works fine as I known.

But, You have a problem of no occurrence Sn_IR_SENDOK.
Have you test the another udp example provied by arduino?

Check the Sn_SR register value in infinite loop.

Thank you.


#5

Hi midnightcow,

Thanks for the replay.

I didn’t change the original Ethernet library. I don’t get SEND_OK, and it happens when the data rate is as I mention above, with slower data rate it works fine.

I also tried modifying the Ethernet library and my own time out, it also didn’t help (in the sendUDP):

while ((W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK) {

	if (W5100.readSnIR(s) & SnIR::TIMEOUT) {			
		/* +2008.01 [bj]: clear interrupt */
		W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT));
		return 0;
	}

	if (ii > 1000) {		
		W5100.writeSnIR(s, SnIR::SEND_OK | SnIR::TIMEOUT);
		return 0;
	}
	ii++;

}

Thnaks
Yoav


#6

Hi,
I’m sorry I have little experience of auduino library.

How do you apply the auduino library to udp processing ?

Can you show me the code? I need main code of udp data send.

I will expect your code to like as following.

EthernetUDP udpsock;
//
udpsock.begin();
while(1)
{
  if(btimeout == 1)
  {
    if(udpsock.beginPacket()==0) goto error;
    if(udpsock.write() == 0) goto error;
    if(udpsock.endPacket()==0) goto error;  //<-- You maybe blocked here.
    udpsock.parsePacket();
    if(udpsock.available())
    {
       if(udpsock.read() == 0)  goto error;
    }   
  }
}
error:
udpsock.stop();
while(1);
}

For better solution, You’d better ask the problem to Arduino communitiy.

Thank you.