Teensy 4.1 - W5500 using SPI DMA

Interesting. Thanks for having a go at that. I think I was seeing upwards of ~11-14.7Mbps with the Teensy->Wiznet->eero->wifi setup, and about the same speeds as you’re seeing when using the wired adapter. Both tests with 30MHz SPI. Something’s up with the Wiznet module and wired Ethernet adapters.

I’m perplexed. Also befuddled.
 
Last edited:
For posterity, here were my results from yesterday with the Teensy->W5500 (WIZ850io)->eero node->wireless->Mac laptop:
Code:
------------------------------------------------------------
Client connecting to 10.0.0.21, TCP port 5001
TCP window size:  128 KByte (default)
------------------------------------------------------------
[  1] local 10.0.0.71 port 53899 connected with 10.0.0.21 port 5001
[ ID] Interval       Transfer     Bandwidth
[  1] 0.00-1.00 sec  1.75 MBytes  14.7 Mbits/sec
[  1] 1.00-2.00 sec  1.75 MBytes  14.7 Mbits/sec
[  1] 2.00-3.00 sec  1.50 MBytes  12.6 Mbits/sec
[  1] 3.00-4.00 sec  1.50 MBytes  12.6 Mbits/sec
[  1] 4.00-5.00 sec  1.38 MBytes  11.5 Mbits/sec
[  1] 5.00-6.00 sec  1.50 MBytes  12.6 Mbits/sec
[  1] 6.00-7.00 sec  1.62 MBytes  13.6 Mbits/sec
[  1] 7.00-8.00 sec  1.25 MBytes  10.5 Mbits/sec
[  1] 8.00-9.00 sec  1.38 MBytes  11.5 Mbits/sec
[  1] 9.00-10.00 sec  1.50 MBytes  12.6 Mbits/sec
[  1] 10.00-10.27 sec   128 KBytes  3.95 Mbits/sec
[  1] 0.00-10.27 sec  15.3 MBytes  12.5 Mbits/sec

Maybe the moon is in a slightly different orbital plane or my network topology changed, or maybe there's just more wireless noise (yesterday's test was done at night), but here's some results from just now:
Code:
------------------------------------------------------------
Client connecting to 10.0.0.21, TCP port 5001
TCP window size:  128 KByte (default)
------------------------------------------------------------
[  1] local 10.0.0.71 port 54901 connected with 10.0.0.21 port 5001
[ ID] Interval       Transfer     Bandwidth
[  1] 0.00-1.00 sec  1.00 MBytes  8.39 Mbits/sec
[  1] 1.00-2.00 sec   896 KBytes  7.34 Mbits/sec
[  1] 2.00-3.00 sec   896 KBytes  7.34 Mbits/sec
[  1] 3.00-4.00 sec   896 KBytes  7.34 Mbits/sec
[  1] 4.00-5.00 sec   768 KBytes  6.29 Mbits/sec
[  1] 5.00-6.00 sec   896 KBytes  7.34 Mbits/sec
[  1] 6.00-7.00 sec   896 KBytes  7.34 Mbits/sec
[  1] 7.00-8.00 sec   768 KBytes  6.29 Mbits/sec
[  1] 8.00-9.00 sec   896 KBytes  7.34 Mbits/sec
[  1] 9.00-10.00 sec   768 KBytes  6.29 Mbits/sec
[  1] 10.00-10.33 sec   128 KBytes  3.20 Mbits/sec
[  1] 0.00-10.33 sec  8.63 MBytes  7.01 Mbits/sec

Exact same code, except a different IP address and this topology: Teensy->WIZ850io->Belkin Ethernet USB-C adapter->Mac laptop (verified 100Mbps and full duplex):
Code:
------------------------------------------------------------
Client connecting to 192.168.1.3, TCP port 5001
TCP window size:  128 KByte (default)
------------------------------------------------------------
[  1] local 192.168.1.2 port 55308 connected with 192.168.1.3 port 5001
[ ID] Interval       Transfer     Bandwidth
[  1] 0.00-1.00 sec   128 KBytes  1.05 Mbits/sec
[  1] 1.00-2.00 sec   128 KBytes  1.05 Mbits/sec
[  1] 2.00-3.00 sec   128 KBytes  1.05 Mbits/sec
[  1] 3.00-4.00 sec  0.000 Bytes  0.000 bits/sec
[  1] 4.00-5.00 sec   128 KBytes  1.05 Mbits/sec
[  1] 5.00-6.00 sec  0.000 Bytes  0.000 bits/sec
[  1] 6.00-7.00 sec  0.000 Bytes  0.000 bits/sec
[  1] 7.00-8.00 sec   128 KBytes  1.05 Mbits/sec
[  1] 8.00-9.00 sec   128 KBytes  1.05 Mbits/sec
[  1] 9.00-10.00 sec  0.000 Bytes  0.000 bits/sec
[  1] 10.00-11.00 sec   128 KBytes  1.05 Mbits/sec
[  1] 0.00-12.31 sec   896 KBytes   596 Kbits/sec

Weird. Well, at least I know that my driver is written reasonably well. I'm baffled as to why the "hard link" is so much slower.
 
Another issue I'm experiencing is that ping doesn't work. I haven't dived too deeply using Wireshark or anything, but I'm just not seeing ICMP Echo Reply packets after sending multiple pings out the Teensy/W5500.
 
Was this W5500 measurement with the latest on github?

If I run "git log", the latest commit it prints is:

Code:
commit c11e8bb2c6819f40d9739c833baf24f3bf646387 (HEAD -> master, origin/master, origin/HEAD)
Author: Shawn Silverman <email redacted>
Date:   Thu Feb 12 20:56:14 2026 -0800

    w5500: Remove some socket-state-checking commented-out code
 
@PaulStoffregen I changed the MTU for the network the Teensy is attached to (Belkin adapter) to 1280 and then to 1400, down from 1500. The speeds are dramatically improved, like by a factor of 10. Would you be willing to try that?

I also tried some other experiments where I lowered the MTU on the Teensy side to 1400, keeping the max-frame-length the same, etc. And a few combinations. It turns out the MTU on the laptop side definitely needs to be less than the MTU on the Teensy side. I haven't played with too many combinations of max-frame-length, etc. But I do know that an MTU of 1280 or 1400 on the laptop side, with the 1500 MTU on the Teensy side, drastically increased throughput.

I might need to do more clever buffering. Currently, I drain as much data as possible from the W5500, then process everything in that buffer, then, when that buffer's empty, I get more data from the W5500. Maybe I need to check the W5500 again after each packet I process. I'll experiment with a circular buffer...
 
With a Wiznet W5500 and src/qnethernet_opts.h edited to uncomment #define QNETHERNET_DRIVER_W5500

Code:
iperf -c 192.168.195.236 -i 1
------------------------------------------------------------
Client connecting to 192.168.195.236, TCP port 5001
TCP window size: 16.0 KByte (default)
------------------------------------------------------------
[  1] local 192.168.194.2 port 55168 connected with 192.168.195.236 port 5001
[ ID] Interval       Transfer     Bandwidth
[  1] 0.00-1.00 sec  91.2 KBytes   748 Kbits/sec
[  1] 1.00-2.00 sec  48.5 KBytes   397 Kbits/sec
[  1] 2.00-3.00 sec  51.3 KBytes   420 Kbits/sec
[  1] 3.00-4.00 sec  51.3 KBytes   420 Kbits/sec
[  1] 4.00-5.00 sec  51.3 KBytes   420 Kbits/sec
[  1] 5.00-6.00 sec  51.3 KBytes   420 Kbits/sec
[  1] 6.00-7.00 sec  51.3 KBytes   420 Kbits/sec
[  1] 7.00-8.00 sec  51.3 KBytes   420 Kbits/sec
[  1] 8.00-9.00 sec  51.3 KBytes   420 Kbits/sec
[  1] 9.00-10.00 sec  51.3 KBytes   420 Kbits/sec
[  1] 10.00-11.08 sec  25.7 KBytes   194 Kbits/sec
[  1] 0.00-11.08 sec   576 KBytes   426 Kbits/sec

Code:
Starting program...
MAC = 04:e9:e5:1a:34:11
Starting Ethernet with DHCP...
[Ethernet] Link ON, 100 Mbps, Full duplex
[Ethernet] Address changed:
    Local IP = 192.168.195.236
    Subnet   = 255.255.254.0
    Gateway  = 192.168.194.1
    DNS      = 192.168.194.1
Accepted connection: 192.168.194.2:55168
Processing input...
Rate = 425.839 kbps
I confirm these outputs also :)
I used a SFP based ethernet media converter (this is my "direct ethernet access" to the PC) and Wiznet still struggles as far as this scenario is concerned.
 
I confirm these outputs also :)
I used a SFP based ethernet media converter (this is my "direct ethernet access" to the PC) and Wiznet still struggles as far as this scenario is concerned.
Could you try setting your Ethernet port’s MTU to 1400 and see what happens? And then 1280.
 
[...two days later...] [again, in a French accent]

I believe I've solved it this time. I'm now seeing speeds greater than 19Mbps over the "direct" link (Belkin Ethernet USB-C adapter). I'm using much more aggressive buffering. Also, I'm leaving the interface's MTU at 1500. The text below is with this command: iperf -c 192.168.1.3 (no -i 1 option means it just uses the whole 10 seconds)

Code:
------------------------------------------------------------
Client connecting to 192.168.1.3, TCP port 5001
TCP window size:  128 KByte (default)
------------------------------------------------------------
[  1] local 192.168.1.2 port 59733 connected with 192.168.1.3 port 5001
[ ID] Interval       Transfer     Bandwidth
[  1] 0.00-10.08 sec  23.3 MBytes  19.4 Mbits/sec

@PaulStoffregen @istrateandrei26 would you mind testing one more time with the latest code on GitHub? (https://github.com/ssilverman/QNEthernet)

1. Don't forget to uncomment "#define QNETHERNET_DRIVER_W5500" in src/qnethernet_opts.h
2. Please run the SimpleIPerfServer example and optionally set the static IP (if you need to, and whatever addresses you need) like so:
C++:
const IPAddress kStaticIP{192, 168, 1, 3};
const IPAddress kSubnet{255, 255, 255, 0};
const IPAddress kGateway{192, 168, 1, 1};
Leave kStaticIP as-is (i.e. nothing) if you want to use DHCP.

One more note: I'm still trying to figure out why I can't receive Echo Reply ICMP packets, needed for sending pings.
 
Last edited:
Sorry for this late response...I am really busy these days but I promise I will return with results as far as the latest commit on GitHub repo is concerned :)
 
Another issue I'm experiencing is that ping doesn't work. I haven't dived too deeply using Wireshark or anything, but I'm just not seeing ICMP Echo Reply packets after sending multiple pings out the Teensy/W5500.
I finally fixed the ping issue. I wasn't calculating the ICMP checksum in some cases.
 
Last edited:
I finally fixed the ping issue. I wasn't calculating the ICMP checksum in some cases.
Thank you a lot for addressing that. I tested and I can confirm that it works.
But now I have encountered another issue.
I am trying to capture packets on W5500 interface and process and then send them on the native interface and vice-versa. The problem is that I observed retransmissions during iperf tests.
Is it because one interface is faster than the other?
I mention that if I modify the SPI clock frequency to a higher value, the number of retransmissions gets lower, but they still exist.
 
Thank you a lot for addressing that. I tested and I can confirm that it works.
But now I have encountered another issue.
I am trying to capture packets on W5500 interface and process and then send them on the native interface and vice-versa. The problem is that I observed retransmissions during iperf tests.
Is it because one interface is faster than the other?
I mention that if I modify the SPI clock frequency to a higher value, the number of retransmissions gets lower, but they still exist.
Do you mean that you want to receive packets on the W5500 interface and then send them out the Teensy 4.1 PHY?
 
Tell me more about your use case?
Well, I have a university project where I want to achieve something similar with a packet sniffer / proxy etc. For the moment I have a setup with 2 PCs and the teensy between them. The goal is to filter the packets which go to one of the PCs. So I managed to receive frames on the native interface and forward them on the w5500 interface accordingly, by updating source and destination mac addresses in the packet. But the problem I mentioned is related to the packet retransmissions. I think it is because the native interface is faster than w5500 and sometimes it receives faster than w5500 can send and drops some packets.
If I transfer files, for example, using tcp client and server on the PCs, the file transmission is fine, regarding the integrity, but it encounters packet retransmissions and it impacts throughput.
 
If I had to guess, I'd say the native interface is maybe 4 to 5 times faster than the W5500 interface.
 
Well, I tested the both interfaces with a PC host and native managed to achieve 90mbps while w5500 around 30mbps.
What do you suggest with 2 Teensy boards and what you refer by “some fast interface”?
 
For the 30Mbps, two questions:
1. What was the SPI rate?
2. Which driver or code did you use to talk to the W5500?
(I think it's possible you answered or described these, but please refresh my memory.)

Well, you could receive a packet on one Teensy, and when you need to relay it somewhere else, communicate over a fast link to the other Teensy, then spits out the packet on its own Ethernet interface. This is instead of receiving it on one interface and spitting it out on the other, on the same Teensy. That sounds equivalent to me.
 
If I remember correctly, SPI rate was around 45-55 Mhz, while I used ioLibrary to talk to the w5500, and also used spi burst read and write functions.
I understand your suggestion, but I would like make it work like a standalone device, to be more relevant for my university project.
Suppose that I have 2 Teensys, and each of them has native and w5500 interfaces, then I can also build a vpn between those.
 
What about using two Teensys? They could talk to each other over some fast interface or something.
I am sorry, I think I didn’t get yet this matter. Do you know some sort of methods in order to communicate with fast throughput between 2 Teensys, so that is worth using 2 to “create/simulate” a single platform which receives packets and process them and sends to the other similar node?
 
Back
Top