8000 W5500-EVB-PICO - Unexplained TCP & UDP Transfer Speed Delays and Variations...Very Slow · Issue #15645 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

W5500-EVB-PICO - Unexplained TCP & UDP Transfer Speed Delays and Variations...Very Slow #15645

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
BB486999 opened this issue Aug 12, 2024 · 8 comments
Labels

Comments

@BB486999
Copy link

Port, board and/or hardware

W5500-EVB-PICO

MicroPython version

MicroPython v1.23.0 on 2024-06-02; W5500-EVB-Pico with RP2040

Reproduction

Master Code running on a PC:

import socket
import time
import os
import math


MCAST_GROUP = '224.1.1.1'
MCAST_PORT = 5007
MASTER_PORT = 5008
CAST_ADDR = '255.255.255.255'


def create_master():
    #?Create a UDP socket for broadcasting
    sock_broadcast = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    sock_broadcast.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock_broadcast.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    #sock_broadcast.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 8)
    #sock_broadcast.bind(('', 5007))

    #?Create a UDP socket for receiving responses
    sock_receive = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock_receive.bind(('', MASTER_PORT))
    sock_receive.setblocking(0)

    return sock_broadcast, sock_receive



def run_master(sock_broadcast, sock_receive):

    while True:

        sock_receive.settimeout(2)
        start_time = time.time()

        for i in range(100):
            sock_broadcast.sendto("SPEED TEST.........................................................................................".encode(), (CAST_ADDR, 5007))
            data, addr = sock_receive.recvfrom(1024)
            print("Iteration: ", i, " - ", round(((time.time() - start_time) / (i + 1)), 5), " s")
        end_time = time.time()


        if data:
            print(f"Master received: {data.decode()} from {addr}")
            print("Elapsed time: ", ((end_time - start_time)))
            print("Average round trip per message: ", ((end_time - start_time) / 100))

        break


sock_broadcast_master, sock_receive_master = create_master()
run_master(sock_broadcast_master, sock_receive_master)

Slave Code on the W5500-EVB-PICO

#pylint: skip-file
import wiznet_w5500.w5500 as w5500
import usocket as socket
from machine import Pin
import utime as time
import gc

led = Pin(25, Pin.OUT)

gc.collect()

#Note, switched to static
w5500.w5500_init_dhcp()


led.value(1)

#Create the listener socket
listener_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
#listener_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

listener_socket.bind(('224.1.1.1', 5007))


#Create the responder

send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

start_time = time.time()

while True:
    data, addr = listener_socket.recvfrom(1024)
    print("Data: ", data, " from addr: ", addr)
    listener_socket.sendto("SPEED TEST RETURN".encode(), ('255.255.255.255', 5008))

print("Finished")

And corresponding w5500 library for reference:

#SPI SETUP for onboard WizNET chip
MOSI = Pin(19)
MISO = Pin(16)
SCK = Pin(18)
CS = Pin(17)
RST = Pin(20)


#W5500 onboard chip initialization
def w5500_init_dhcp():
    spi=SPI(0,60_000_000, mosi=MOSI,miso=MISO,sck=SCK)
    print(spi)

    nic = network.WIZNET5K(spi,CS,RST) # type: ignore #spi,cs,reset pin


    nic.active(True)

    #It looks like we have a mac address...
    mac = nic.config('mac')
    print("''''''''''''''''''''''''''")
    print("MAC ADDR: -> ", ':'.join('{:02x}'.format(mac[i]) for i in range(6)))



    #nic.ifconfig('dhcp')
    nic.ifconfig(('168.5.0.12', '255.255.0.0', '0.0.0.0', '0.0.0.0'))
    print('\nAssigned IP address: -> ', nic.ifconfig()[0], "\nSubnet Mask: -> ", nic.ifconfig()[1], "\nGateway: -> ", nic.ifconfig()[2], "\nDNS: -> ", nic.ifconfig()[3])
    print("''''''''''''''''''''''''''\n\n")

    #while not nic.isconnected():
        #time.sleep(1)
        #print("Waiting...")
        #print(nic.regs())

When running the following code (round trip UDP messages, one down to slave, one back up to master) with MicroPython official release 1.23.0, I get about 65 ms round trip per message.

When running with WizNet's own v2.0.0 release on their website (https://github.com/Wiznet/RP2040-HAT-MicroPython/releases), I am looking at around 2-5ms per message. Note that this is roughly in the same range if I ran the master and slave code on two separate PCs with the same setup (2-5 ms per message).

I don't want to have to use the WizNet micropython build because it is incredibly unstable (print statements are delayed, misses keyboard interrupts when stopping, lacking many features/functions, etc.), but I really need the speed for my application. Why is the MicroPython build so much slower, is this a bug that can be addressed? Thanks

Expected behaviour

Micropython Official 1.23.0 build UDP back and forth: ~ 65 ms
WizNet v2.0.0 Micropython build UDP back and forth: ~ 2-5 ms
PC to PC UDP back and forth: ~ 2 ms

Expected is micropython official build to be ~ 2-5 ms

Observed behaviour

Micropython build is significantly slower sending UDP messages (tens of milliseconds slower) than using WizNet's v2.0.0 build or compared to PC to PC UDP messaging.

PC to PC: ~2 ms
PC to Wiznet v2.0.0 micropython w5500-EVB-PICO: ~2-5 ms
PC to Micropython v1.23.0 build W5500-EVB-PICO: ~65 ms +

Additional Information

No, I've provided everything above.

Code of Conduct

Yes, I agree

@BB486999 BB486999 added the bug label Aug 12, 2024
@andrewleech
Copy link
Contributor

There were a lot of speed tests done during the original development for this board, though more to do with TCP throughout than latency.

Would you be able to try re-running some of the tests described in #8540 (comment) it would be helpful to know if the support has regressed since then, or if your use case wasn't tested originally?

Separately, I'm not sure if it still works this way but I think if you change the LWIP setting to 0 in https://github.com/andrewleech/micropython/blob/6f27e1c9681de46e0c6ef859dd8be4fc6fd7cf1d/ports/rp2/boards/W5100S_EVB_PICO/mpconfigboard.cmake#L4 it'll build in the mode where it uses the external stack on the chip rather than LWIP software stack in micropython. The chip stack was often quicker, but has less features.

@dpgeorge
Copy link
Member

If you are explicitly constructing the network.WIZNET5K instance then I think you need to pass in the interrupt pin. That will get the latency down to almost zero between when a packet arrives to the Wiznet and the RP2040 polls the Wiznet.

Without an interrupt pin there is a 64ms latency between polls of the Wiznet, see ports/rp2/mpnetworkport.c:

// Poll lwIP every 64ms by default                                      
#define LWIP_TICK_RATE_MS 64

(If you construct the Wiznet without any arguments then it uses default SPI and pins and enables the interrupt pin.)

@dpgeorge dpgeorge added port-rp2 and removed bug labels Aug 14, 2024
@dpgeorge
Copy link
Member

Hmmm, it looks like we need to document the interrupt pin in the network.WIZNET5K docs.

@BB486999
Copy link
Author

That was it!

nic = network.WIZNET5K(spi,CS,RST, INT)

Added the INT pin as specified by the W5500-EVB-PICO pinout, now I'm seeing 6-10ms round trips (still a little slower than than the wiznet build or PC to PC, but much more reasonable). Yes, please add that to the docs, I'm not sure I would have found it otherwise. Thank you guys for the quick support, hopefully this helps someone else in the future

@MilhouseVH
Copy link

Hmmm, it looks like we need to document the interrupt pin in the network.WIZNET5K docs.

Yes, documenting the INT pin would be fantastic! 😄

I just added the INT pin to a project using micropython 1.24.1 and W5500-EVB-PICO and saw an increase in TCP throughput from 100KB/s to more-or-less 1MB/s (using buffers of 32768 bytes) just with the addition of , Pin(21)! 😃

I used the following initialisation code to hopefully remain compatible with any potential non-LWIP firmware build:

    try:
        nic = network.WIZNET5K(spi, Pin(17), Pin(20), Pin(21))
    except:
        nic = network.WIZNET5K(spi, Pin(17), Pin(20))

nic = network.WIZNET5K() is certainly a simpler approach but obviously less configurable - for the first time, the SPI baudrate now has an impact on performance following the addition of the INT pin whereas before - without the INT pin - the baudrate setting had no discernible impact at all - 2Mbps, 20Mbps, 32Mbps all result in the same ~100KB/s TCP throughput result without the INT pin.

Q: Is there any better way at runtime to detect if LWIP is enabled?

@BB486999
Copy link
Author

Yeah just want to follow up on this, if this could be documented (it looks like it hasn’t been updated), I think this would be super useful for both those using the W550-EVB-Pico, or even just the w5500 chip. I spent quite a bit of time searching into this (weeks) before I was able to figure it out.

@MilhouseVH
Copy link
MilhouseVH commented Jan 20, 2025

@BB486999 in case you haven't already seen it, have a look at #13718 - I now include the following early in my initialisation code to ensure the SPI is running at full speed otherwise the baudrate can be limited to 24MHz due to the PERI clock running at only 48MHz:

from machine import freq

#Ensure peripheral clock (second param) is same as core clock (first param).
# Peripheral clock can default to 48MHz after a soft-reboot, which would limit SPI baudrate to 24MHz
freq(freq(), freq())

The above code should ensure the CPU and PERI clocks are always both set to 125MHz on an RP2040... in theory it would be 250MHz on an RP2350 (I think...)

@andrewleech
Copy link
Contributor

Another potential cause for intermittent speed / dropout issues has been found and addressed in #16664

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants
0