w5300 hold interrupt pin asserted low

Hello! I am using w5300 as server in TCP mode. W5300 connected to DSP. I have a w5300 driver and it work fine in some task. Now I have a new task, where data flow increase, and after some second of interconection with PC client, w5300 drop interrupt pin, and I can’t acknowledge it in ISR for inerrupt complete.

W5300 can be dropped some interrupt when you are processing a interrupt and another interrupt is occured at that time.

Specially RX interrupt can be often lost. So If you received the RX interrupt, you should be checked the overraped RX interrupt before your ISR returned.
It is possible that you can check the remained RX data to Sn_RX_RSR.

For example

void ISR()
{
      setIMR(0x00);
      while((ir = getIR())
     {
         for(i = 0; i < 8 ; i ++)
         {
              if(ir & (0x0100 << i))  
              {
                  snir[i] = getSn_IR(i);
                  if(rx interrupt)
                  {
                     // rx flag set, or rx data receive process
                   }
                  if(others interrupt)
                  {
                     // interrupt flags set or others interrupt process
                   }
                  setSn_IR(i, snir[i]);
              }
        }
   }
   setIMR(0xFF);
}

The example maybe also lost rx interrupt.
so, We recommend the preodic checking Sn_RX_RSR.

Thank you.

Ok, thank you! Add this to my ISR.
Now I have interest conditionof wiznet chip, when RSR value is 0. And SSR value is 0x11.
I assume, that rx fifo is full at this time. Is it so?

SSR value 0x11 is temporary value. it can not be monitored continueously.

If SSR value is still 0x11, you should check the errata of W5300.
Refer to Erratum 1 in here

and
“RSR = 0” means rx memory is empty.

Thank you.

Thank you!
First phenomenon from errata seems like to my problem. But I not execute close/disconnect.
DSP just send data and freezes at waiting for SENDOK acknowledgment:
WIZnetSendOk[n]=false;
wrWIZnetReg(Sn_CR(n))=CMD_SEND;
while(!WIZnetSendOk[n]);
////(WIZnetSendOk[n] set in ISR)

Could you share the process to send data?

void WIZnetWrite(BYTE *Buf,long Length,long n)
{	
	long LocLen,i,j,k,ind,FreeSpace;
	WORD dataWrite;
	WORD* wp = (WORD*)Buf;
	if(WIZnetSocketState[n] != CONNECTED)	return;

	if(((DWORD)Buf)&0x01)
	{	WritingCycle(oddCopy,Buf,Length,n);
	}
	else
	{	WritingCycle(evenCopy,Buf,Length,n);
	}
}

void WritingCycle(DataOperation f,BYTE *Buf,long Length,long n)
{
	long LocLen,ind,j,FreeSpace;
	WORD dataWrite;
	
	FreeSpace=getFreeSpace(n);
	for(ind=0;ind<Length && WIZnetSocketState[n] == CONNECTED;)
	{	if(FreeSpace == 0)
		{	for(j=1000/5;j>0;j--)	// ~1000 нс
				asm("nop;");
			FreeSpace=getFreeSpace(n);
			if(FreeSpace == 0)	continue;				
		}
		LocLen=min((Length-ind),FreeSpace);
		f(LocLen,Buf,ind,n);			
		setSizeTxData(n,LocLen);
		ssync();
		WIZnetSendOk[n]=false;
		wrWIZnetReg(Sn_CR(n))=CMD_SEND;
		DWORD guard=1000000;
		while(!WIZnetSendOk[n])
		{   asm("nop;");
		}
		dataWrite=rdWIZnetReg(Sn_MR(n));
		ssync();
		ind+=LocLen;
	}
	return;	
}
inline void oddCopy(long WrLen, BYTE* Buf,long ind,long n)
{	long i=0,k=0;
	WORD dataWrite;
	for (i=0;i<WrLen/2;i++)
	{	dataWrite = (Buf[ind+k])|(Buf[ind+k+1]<<8);	
		wrWIZnetReg(Sn_TX_FIFOR(n))=dataWrite;;
		k+=2;
	}
	if (WrLen&0x01)
	{	wrWIZnetReg(Sn_TX_FIFOR(n))=(WORD)(Buf[ind+k]);
		k++;
	}
}

Hi,

Your code maybe worked well.
But, I wonder what’s roll of ssync() and why read Sn_MR.

I recommend to modify your code as following.

==>

wrWIZnetReg(Sn_CR(n)) = CMD_SEND;
while(rdWIZnetReg(Sn_CR(n)) != 0); // wait until command is cleard.
DWORD guard=1000000;
while(!WIZnetSendOk[n]) {asm{"nop"); }
// Add to barrier code for proctection : disable_interrupt();
WIZnetSendOk[n] = false;
// Add to barride code for proctection : enable_interrupt();

Thank you.

Thank you!
I add your modification, but still has 0x11 at SSR.
I add guard counter and sending CMD_DISCON for case where counter decrement to 0. This so rough, but reconnect reset 0x11 state. And…not always.
Have you idea how to avoid this state?

As expained in erratum #1,
If a socket is still at 0x11, Socket operation becomes abnormal.
This problem happens often when socket is disconnected by command before send is not process completely.

In your case, If gurad==0, you forced to disconnect a socket.
In the case, you can follow as the erratum #1 guide.

if(guard == 0) 
{
        socket(sn, Sn_MR_UDP, 3000, 0x00);
        sendto(sn, "1", 1, (char*)0x0000001,3000);
        while(Ssn_SSR != SOCK_CLOSED);
}

The correct guide shoud be reffered to Erratum#1.

Thank you.

}

So this udp sending didn’t break current tcp connection?

Hear are full code…

      uint8_t destip[4] = {0, 0, 0, 1};

      // TODO

      // You can wait for completing to sending data;

      // wait about 1 second;

      // if you have completed to send data, skip the code of erratum 1

      // ex> wait_1s();

      //     if (getSn_TX_FSR(s) == getSn_TxMAX(s)) continue;

      // 

      //M20160503 : The socket() of close() calls close() itself again. It occures a infinite loop - close()->socket()->close()->socket()-> ~

      //socket(s,Sn_MR_UDP,0x3000,0);

      //sendto(s,destip,1,destip,0x3000); // send the dummy data to an unknown destination(0.0.0.1).

      setSn_MR(sn,Sn_MR_UDP);

      setSn_PORTR(sn, 0x3000);

      setSn_CR(sn,Sn_CR_OPEN);

      while(getSn_CR(sn) != 0);

      while(getSn_SR(sn) != SOCK_UDP);

      sendto(sn,destip,1,destip,0x3000); // send the dummy data to an unknown destination(0.0.0.1).

This code can exit the abnormal TCP state by using udp arp timeout.

Thank you.

Please, explain, whether the current connection will be preserved?

This erratum occures when the TCP socket is disconnected by owner or peer normally when the sending data is still remained.

So, The socket need to be disconnected but the socket is not disconnected normally, stays still established state.

The above code force to disconnect the socket normally. so the TCP socket cannot be preserved.