WIZnet Developer Forum

Cannot reset INT pin on W5500 after interrupt

I developed my own W5500 driver for 20+ commercial applications. Up to this point, I have utilized a polling approach to execute all functions and the driver has performed flawlessly in this mode. I have a new client who wants me to use the Free RTOS operating system for an application which means I need to use the interrupt capabilities of the W5500. At first, this seemed like an easy task because I only needed to add some initialization code and an interrupt handler to my existing driver. However, after 40+ hours of hardware and software debugging, I have determined that the behavior of the W5500 interrupts do not match the data sheet in any way!! Specifically, once an interrupt occurs (i.e. the INT pin goes low), there is no way to clear the interrupts to allow the INT pin to go high again. (If the INT pin does not go high, no more interrupts will be triggered!!)

The initialization code is shown below:

void ConfigureW5500
(UCHAR * pDeviceIP, // pointer to ip address
UCHAR * pGatewayIP, // pointer to gateway ip address
UCHAR * pMacAddrs, // pointer to mac address
int nBuffSizes [2]) // buffer size table
//-----------------------------------------------------------------------
// Configure the registers in the W5500:
W5500_RESET_LO; // set reset low to assert
delay_us (100); // delay for 100 microseconds
W5500_RESET_HI; // set reset high to clear
WriteCommMR (MR_RST); // reset the W5500 registers
delay_ms (100); // delay while the W5500 resets
WriteCommIMR (0x00); // disable common interrupts
WriteCommSIMR (0x00); // disable socket interrupts
WriteCommSIPR (pDeviceIP); // write the device IP address
WriteCommGAR (pGatewayIP); // write the gateway IP address
WriteCommSUBR (_uSubMaskW5500); // write the subnet mask
WriteCommSHAR (pMacAddrs); // write the MAC address
WriteCommRTR (12000); // write the retry time-out period
WriteCommRCR (3); // write the retry count
//-----------------------------------------------------------------------
// Set the receive and transmit buffer sizes:
BYTE bySockt=0; // socket number
BYTE bySizeInK=0;
for (bySockt=SOCKT_0;
bySockt <= SOCKT_7;
bySockt++)
{
_nRxBuffSizeW5500 [bySockt]= // set the RX buffer size
nBuffSizes [bySockt][0];
bySizeInK= // determine the RX buffer size in
nBuffSizes [bySockt][0]/1024; // kilobytes
WriteSocktRxBuffSize
(bySockt, bySizeInK); // set the socket RX buffer size
_nTxBuffSizeW5500 [bySockt]= // set the TX buffer size
nBuffSizes [bySockt][1];
bySizeInK= // determine the TX buffer size in
nBuffSizes [bySockt][1]/1024; // kilobytes
WriteSocktTxBuffSize
(bySockt, bySizeInK); // set the socket TX buffer size
}
//-----------------------------------------------------------------------
// If interrupts enabled, configure the W5500 interrupt registers:
WriteCommSIMR (0x0f); // enable socket interrupts
//-----------------------------------------------------------------------
// If interrupts enabled, configure the PIO driver:
icPIOA_W5500.uIntruptMask= // W5500 interrupt enable bit
NEC_INT_MASK;
icPIOA_W5500.uAIM_Mode=
FALLING_EDGE_AIM; // falling edge AIM mode
icPIOA_W5500.uAIM_IntruptMask= // AIM interrupt enable bit
NEC_INT_MASK;
icPIOA_W5500.uIntruptPriority=0; // interrupt priority
icPIOA_W5500.pHandler=ISR_W5500; // pointer to interrupt handler
ConfigIntruptsPIO // configure the W5500 interrupts
(PIO_A, ID_PIOA, icPIOA_W5500);
#endif
}

The interrupt handler code is shown below:

void ISR_W5500
(int nPIO_ID, // PIO interrupt ID
UINT uIntStatus) // interrupt (I\N\T) pin level
{
UCHAR uSockt; // socket number
for (uSockt=SOCKT_0;
uSockt < SOCKT_7; // set to process all 8 sockets
uSockt++)
//-----------------------------------------------------------------------
// Get the socket interrupt bits, save them in the status array and reset
// the interrupt bits in the socket interrupt registers (IR):
{
SOCKT_STATUS= // get socket interrupt bits and
(ReadSocktIR (uSockt) & 0x1f); // save them in status array
WriteSocktIR (uSockt, 0x1f); // reset the interrupt bits
}
//-----------------------------------------------------------------------
// Reset the common interrupt bits in the common interrupt register (IR):
WriteCommIR (0xf0); // reset common interrupts
//-----------------------------------------------------------------------
// Verify that the interrupt pin on the W5500 is high indicating that all
// interrupt conditions have been cleared:
int nIntPinLevel= // get the level of the interrupt
GetPinsPIO (PIO_A, NEC_INT_MASK); // pin on the W5500
if (!nIntPinLevel) // if the pin is still low, turn the
{ // Error LED on
ErrorOnLED ();
}
}

When the code above executes, the Error LED ALWAYS comes on because the INT pin remains low even after 1’s are written to all of the common and socket interrupt status registers.

I would like to find anyone who has ever successfully implemented interrupt operation using the W5500.

What interrupt registers read at this time - before abd after their reset?

Let’s consider the possibilities why flags do not reset:

  1. you write reset flags to wrong location, or write does not happen;
  2. there’s some condition causing flag to be continuously set.

After some debugging, I determined that the problem was caused by writing to the W5500 registers while in the interrupt routine. I discovered that, if the code that was executing was accessing the registers in the W5500 when an interrupt occurred, then it is possible for a conflict to occur. I changed the code in the interrupt routine to set a flag indicating that an interrupt occurred. The interrupt routine does not access any of the registers in the W5500. When the program that is executing sees the interrupt flag is set, it will read the interrupt status registers to determine the cause if the interrupt and reset the interrupt status bits. I am working on another approach which is to disable interrupts from the W5500 whenever the program that is executing accesses the W5500 registers. This too will prevent any conflicts.

The interrupt condition must be cleared in the ISR, otherwise after exiting the ISR, it will be (immediately) called again.

I’ve found a precaution regarding the interrupt in the application note of W5100S which maybe applicable to W5500.

It says that the interrupt may happen in the middle of SPI signaling and if there are any code to control
SPI signal in the Interrupt Handler like writing or reading from a register, the SPI frame will be damaged.

So, @BitBanger46 you are right regarding this. However, after some trials and error in my code I concluded that if the interrupt happens periodically and fast about every <= 1s, the SPI will break and code stopped working. If the interrupt happens to be for example every 1 min like my case it will be ok but still it is a bad practice and your suggestion by setting a flag is the best way.

Thank you for the additional information about the problem with interrupts. It should be helpful to developers who are writing interrupt driven code.

Copyright © 2017 WIZnet Co., Ltd. All Rights Reserved.