W5500, RX-Interrupt not working

Hello, may kindly ask for help. I’m using w5500, running a TCP connection on socket 1, typically gettting a message, calculating the answer and sending it. System is working for couple of minutes, but randomly gets broken. I traced it down to an issue in receiving data - interrupt not set …

In Receive, I do:
Look at interrupt line (by polling from my processor), if the line is low, I read SIR, then read SnIR and if RECV bit is set, do all the stuff for receiving the data: read from fifo, update sock_rd and send the command for received.

When the flow on socket 1 stops (rare event), I made a dump of the registers:

w5500:Int=idle (line is high)
w5500:SIR=00;SIMR=C3 (socket 1 is enabled)
w5500:MODE=00
w5500:PHYCFGR=BF
lnk:up,100,FD,auto
w5500:1:SnIR=00;SnIMR=1F (this is socket 1, SnIR is 0, mask is ‘enabled all’.)
w5500:rx:rsr=0013:rd=0050:wr=0063 (tells me: 13 bytes received)

What I don’t understand: why is SnIR equal 0 in this case? There are data in the receive fifo …

best regards Wolfgang

Where’s the action to clear interrupt flag? I ask WHERE it is in this workflow?

Workflow:
read(IR)
read(snIR)
read(RX_RSR)
if RX_RSR > 0: read the bytes from sock_rx_rd following
sock_rx_rd + RX_RSR
write(sock_rx_rd)
write(RECV-command)
write(snIR, RECV-bit)

Your mistake is clearing the interrupt bit at the exit of the ISR. You must do it as soon as you enter the ISR and then process all the data in the buffer to date. With your current workflow, while you are working on the buffer, it gets gradually filled and the process gets stuck when buffer gets full between last read and interrupt bit clear. That’s why it works for minutes and then stops. You simply clear interrupt bit before processing it.

Hello, thanks for the answer. What happens, if I clear the interrupt bit at start, and not reading the complete data (ie. my further processing can not take all data at this point)? The Interrupt bit will be gone, right? I’ll have keep a flag ‘not fully processed’?

Then you solve this problem. Or before processing data check if you can process all the data and decide if you are going to clear the flag or not. Anyway if you do not clear the flag your ISR should be invoked immediately again after you exit it.

Edit: alternatively, you can do the following - after you took all the data you can take, check if there’s more data pending. If not, clear the flag AND check again if there’s still no data pending. If there’s still data, do not clear the flag. Note that after you clear the flag you must check if there’s no data, because data may arrive between your checking buffer before resetting flag and performing resetting flag effectively resetting the condition. But this is an ugly hack because again, ISR will be invoked immediately after you exit it, and there’s no sense in all this unless you add even more complexity by managing interrupts.

One more alternative - instead of using interrupts, use polling. This way you can take data any time you can do it, and there’s no issue managing interrupt bits at all.

Hello,
I started with polling of RSR and when there is something, I read the data. However, this costs me too much processing time. So I changed code to use the interrupt line - in polling mode. Asking just an input is a little bit faster then doing SPI transmits. So I’ll have to minimize SPI accesses.

I think of caching both RSR and SnIR in my processor and do processing as follows:
Testing the interrupt line.
If active, then look at cached SnIR. If Zero, read and update cached SnIR.
Test cached SnIR. If REC-Bit, check cached RSR.
case a) if cached RSR > 0, read the data, update cached RSR. Then do the RECD, do not not clear cached snIR nor chip snIR and exit.
case b) if cached RSR is == 0, read RSR; if still 0, clear chip snIR. Again read RSR.
if RSR == 0, clear cached snIR and exit.
if RSR > 0, do not clear cache snIR and exit. (This will result in a renext entry)

What do think about it?

Why not, but I have suspicion that all these tests and decision making will take more time than just read RSR. Or connect interrupt line to MCU interrupt line and set up ISR properly. In general, if you are forced to do this way there’s something wrong with selected hardware, hardware or software architecture.

there’s something wrong with selected hardware

Agreed. I wouldn’t use this chip again. The w5500 is in some points not really optimal. Ie I’ll have to read RX_RSR twice to overcome potential bytewise race conditions in the hardware - other hardware use some kind of race free mirror registers for such accesses. And the interrupt handling is cumbersome, too. On other hardware, if I clear the root cause for an interrupt, the corresponding interrupt bit gets cleared automatically. On w5500 I need to clear it manually, again with some ugly actions to counteract possible race conditions.

best regards Wolfgang

These chips are tools which must be used properly, otherwise (as any tools) they lose their innate value. These chips have embedded network stack acceleration, and are very useful and simple in programming, at the same time you should not expect intel PCIe networking chip performance from them.
Most anxiety you get may be a cause of being unclear how to employ the chip properly. You can do int in different way, and therefore level of complexity will differ.
Interrupt pin must be connected to interrupt pin of MCU to get best performance. All other ways are polling, which are slower. I can’t advise anything material because do not know the purpose for the device and why you have set those limitations.

It is enough to read once (high then low) and the value read will always be less than or equal to current value, which is ok for TCP, but you may really need to re-read for UDP to ensure whole the packed had been received.

It is designed for interrupt, not polling.

Here if you write specific bit(s) into interrupt register the interrupt clears automatically. What’s wrong here?

Because you kind of misuse the virtues of the chip.

Hello, I changed the handling as written above and things seem to work.

Sorry, it really makes no difference (in terms of handling the chip), if I look at the interrupt pin with polling or with an interrupt handler - there may be a longer reaction time when using polling, but then processing will be equal. In any case there will be a timing gap between clearing the interrupt and araival of new data, the handling of this interrupt bit is not atomic.
I run all the data transfer to and from wizchip with DMA, so the cpu is doing other tasks in the meantime. And with DMA, there are already some interrupts around, however DMA brings me seamless transfers at max. SPI speed.

Here if you write specific bit(s) into interrupt register the interrupt clears automatically. What’s wrong here?
IMHO, the easiest way is: as long as there are data inside the receive fifo, RX interrupt is active. If all data is processed, RX interrupts clears automatically - and rises again, if there are new data. No need to manually clear it, no risk of races. Every multipurpose IO like USART/SPI/FLEXCOMM handles things in such a way. May be it is possible to improve this in a future version of such chips.
Because you kind of misuse the virtues of the chip.
Is streaming a misuse? I didn’t expect QSFP 200DD performance, but going a little bit ahead in speed compared to the simple arduino stuff should be possible. As said, now seamless transfers (when it comes to payload data) are running at max setting of SPI speed. Thanks for your support and explanations!

1 Like