W500 INTn pin does't reset (stays low) after interrupt

Hello. I’m trying to use INTn pin to check interrupts. After module hard reset pin is in a high state. When i send UDP packet to module, pin goes low. Then i’m trying to reset interrupts with wizchip_clrinterrupt() but nothing happend - pin is stil low. Here goes main parts of code:
//-----------------------------------------------------------------------------------------------------------------------
volatile intr_kind IntKind = 0;
//-----------------------------------------------------------------------------------------------------------------------
ISR( INT0_vect )
{
IntKind = wizchip_getinterrupt();
}
//-----------------------------------------------------------------------------------------------------------------------
int main(void)
{
reg_wizchip_spi_cbfunc(W5500ReadByte, W5500WriteByte);
reg_wizchip_cs_cbfunc(W5500Select, W5500DeSelect);
reg_wizchip_cris_cbfunc(IR_Enter, IR_Exit);
wizchip_init(txsize, rxsize);
wizchip_setnetinfo(&gWIZNETINFO);
wizchip_setinterruptmask(IK_SOCK_0);

int8_t sR = socket(0, Sn_MR_UDP, 55555, 0);

while (1)
{
if (IntKind)
{
switch (IntKind)
{
case IK_SOCK_0:

recivedSize = getSn_RX_RSR(0);

if (recivedSize>0)
{
if (recivedSize > 128) recivedSize = 128;
int32_t ret = recvfrom(0, buffer, recivedSize, destIp, (uint16_t*)&destPort);
}
break;

default:
break;
}
wizchip_clrinterrupt(IntKind);
}
}
}

Few weeks of pain and suffering but no results. Please help.

I suspect you must clear interrupt condition in ISR, otherwise, with INTn pin always active, MCU will loop calling ISR.

I’m sorry, what is ISR (don’t see in datasheet)? You mean ctlsocket(0, CS_CLR_INTERRUPT, (void*)SIK_ALL)? MCU INT0 must check low level or falling edge?

Asking this question means that you did not take an effort to analyze how code your posted is designed and how it works. Here it is:

ISR( INT0_vect )
{
    IntKind = wizchip_getinterrupt();
}

ISR = interrupt service routine.

Ok, but i’m used multimetr and pin INTn on w5500 is low (0 V) after wizchip_clrinterrupt(). It does not reset to high. I’m using standart ioLibrary_Driver from gitgub.

Are you sure this code is being executed at all? Did you put break point or diagnostic output for that?

I’m using breakpoints. AVR Dragon and debugWire. If i use wizchip_clrinterrupt() and after that check interrupt status with wizchip_getinterrupt(), it stils IK_SOCK_0. SPI seems to be ok - after initialization module answers on PING command. getSn_RX_RSR() returns length (18 bytes of test message) if send a packet to module. recvfrom() successfully write packet to buffer. But then i can’t reset IK_SOCK_0 and no packets recieving anymore. INT0 on atmega configured on falling edge (so, i get one iterrupt and breakpoint in ISR never works again because INTn pin on w5500 is low).

Ok, I see. Then raised interrupt means that there’s something else causing it. Read and display interrupt registers (common and socket) to see what else they have set.

I had a similar problem of not being able to clear the interrupt condition. I am using a library adapted from the Wiznet git repository under the Arduino IDE.

The problem was manifold. First is that in the Arduino libraries the SIR [0x0017], SIMR [0x0018] and Sn_IR [0x0002] are not supported. I enabled these registers and wrote functions in the library to write to these registers using the “enableInterrupt” standard of arduino.h. The functions work really well and I have full access to the registers. These even allow the chip to actually cause an interrupt and my ISR executes just fine.

void EthernetUDP::enableInterrupt() {
  if (_sock >= MAX_SOCK_NUM)
    return;
  EthernetUDP::clearInterrupt();
  uint8_t val = w5500.readSIMR();
  w5500.writeSIMR(val | (1 << _sock));
}

void EthernetUDP::disableInterrupt(){
  if (_sock >= MAX_SOCK_NUM)
    return;
  uint8_t val = w5500.readSIMR();
  w5500.writeSIMR(val & ~(1 << _sock));
}

void EthernetUDP::clearInterrupt(){
  w5500.writeSnIR(_sock, 0xff);
}

uint8_t EthernetUDP::readInterrupt() {
  if (_sock >= MAX_SOCK_NUM)
    return;
  return w5500.readSnIR(_sock);
}

Why am I writing to these registers, great question, the datasheet has the following for the Sn_IR:
“Sn_IR indicates the status of Socket Interrupt such as establishment, termination, receiving data, timeout). When an interrupt occurs and the corresponding bit of Sn_IMR is ‘1’, the corresponding bit of Sn_IR becomes ‘1’. In order to clear the Sn_IR bit, the host should write the bit to ‘1’.” pp 49
for the INTLEVEL register:
“a. When Timeout Interrupt of Socket 0 is occurred, S0_IR[3] & SIR[0] bit set as ‘1’ and then INTn PIN is asserted to low.
b. When the connection interrupt of Socket 1 is occurred before the previous interrupt processing is not completed, S1_IR[0] & SIR[1] bits set as ‘1’ and INTn PIN is still low.
c. If the host processed the previous interrupt completely by clearing the S0_IR[3] bit, INTn PIN is deasserted to high but S1_IR[0] & SIR[1] is still set as ‘1’.
d. Although S1_IR[0] & SIR[1] bit is set as ‘1’, the INTn can’t be asserted to low during INTLEVEL time. After the INTLEVEL time expires, the INTn will be asserted to low.” page 35

for the IR:
“IR indicates the interrupt status. Each bit of IR can be cleared when the host writes ‘1’ value to each bit. If IR is not equal to ‘0x00’, INTn PIN is asserted low until it is ‘0x00’.” page 36

and for SIR:
" SIR indicates the interrupt status of Socket. Each bit of SIR be still ‘1’ until Sn_IR is cleared by the host. If Sn_IR is not equal to ‘0x00’, the n-th bit of SIR is ‘1’ and INTn PIN is asserted until SIR is ‘0x00’." page 38

The datasheet is as clear as mud. So what I figured out is that to clear the interrupt all that is needed is to write ‘0xff’ into the appropriate register, IR or Sn_IR. I’m more interested in the Sn_IR because I’m waiting for a reply packet and am using a task scheduler in my code so my loop{} is empty.

Note, the IR register has to be separately configured with a similar code as to what I had above, and an additional class in the w5500 library class IR needs to be uncommented.

void EthernetClass::enableInterrupt(uint8_t type) {
  EthernetClass::clearInterrupt();
  uint8_t val = w5500.readIMR();
  switch (type) {
    case IR::MP: // Magic Packet
      w5500.writeIMR(val | IR::MP);
    break;
    case IR::PPPoE: // PPPoE Connection Close
      w5500.writeIMR(val | IR::PPPoE);
    break;
    case IR::UNREACH: // Destination unreachable
      w5500.writeIMR(val | IR::UNREACH);
    break;
    case IR::CONFLICT: // IP Conflict
      w5500.writeIMR(val | IR::CONFLICT);
    break;
  }
}

void EthernetClass::disableInterrupt(uint8_t type) {
  uint8_t val = w5500.readIMR();
  switch (type) {
    case IR::MP: // Magic Packet
      w5500.writeIMR(val & ~IR::MP);
    break;
    case IR::PPPoE: // PPPoE Connection Close
      w5500.writeIMR(val & ~IR::PPPoE);
    break;
    case IR::UNREACH: // Destination unreachable
      w5500.writeIMR(val & ~IR::UNREACH);
    break;
    case IR::CONFLICT: // IP Conflict
      w5500.writeIMR(val & ~IR::CONFLICT);
    break;
  }
}

void EthernetClass::clearInterrupt() {
  w5500.writeIR(0xff);
}

uint8_t EthernetClass::readInterrupt() {
  return w5500.readIR() & w5500.readIMR();
}

Also note, I have these files in the library files and had to modify the public section of the headers to be

  virtual void clearInterrupt();
  virtual void enableInterrupt();
  virtual void disableInterrupt();
  virtual uint8_t readInterrupt();

and

  void clearInterrupt();
  void enableInterrupt(uint8_t type);
  void disableInterrupt(uint8_t type);
  uint8_t readInterrupt();

It is important to declare the clearInterrupt prior to the enableInterupt as the latter uses the former.

It seems it is a bug in the Library.

Please see this topic: