w5500-rs icon indicating copy to clipboard operation
w5500-rs copied to clipboard

UDP Binding stuck in infinite loop

Open adsnaider opened this issue 2 years ago • 9 comments

Describe the Problem

I'm building an application with the w5500-evb-pico. Upon setting up the SPI and initializing the registers, I used the Udp::udp_bind call to bind Sn0 to some port. However, this often blocks forever (or until the watchdog resets the chip). I've narrowed it down to

while self.sn_sr(sn)? != Ok(SocketStatus::Udp) {}

in udp_bind being the problematic loop and the reason is that the SocketStatus is Closed for some reason. This happens more often than not and I'm not sure what the issue may be here. I've tried with 2 different wiznets and both experience the same problem.

Expected Behaviour

udp_bind doesn't block.

Steps to Reproduce

Setup a w5500-evb-pico, connected over ethernet to a computer. Initialize the w5500 eh0 vdm

I can share some source code as well but it's not much different from what's here: https://github.com/newAM/w5500-issue-252/blob/main/src/main.rs, but I can try running that specifically to see if I have the same issue on that source.

adsnaider avatar Nov 10 '23 23:11 adsnaider

Hmm. A quick fix would be to rebind in the loop, but this shouldn't occur in the first place.

Are you able to try out the code here? If it is intermittent it could be the chip missing the chip-select: https://github.com/newAM/w5500-rs/issues/252#issuecomment-1670593061

newAM avatar Nov 10 '23 23:11 newAM

Oh, that's really odd, that seems to be working :O

Edit: Fyi, that specifically works when I have

            spi_cs.set_high().unwrap();
            w5500_hl::ll::eh0::reset(&mut w5500_reset, &mut delay).unwrap();

when I set the SPI

adsnaider avatar Nov 10 '23 23:11 adsnaider

:/ Your chip probably has a fast clock speed and the default HAL implementation doesn't assert chip select low for long enough. I haven't merged that "fix" yet because I don't have a good solution for embedded-hal 1.0 yet.

newAM avatar Nov 10 '23 23:11 newAM

Interesting find. Do you know if that will cause a problem with networking as well?

adsnaider avatar Nov 10 '23 23:11 adsnaider

We've only seen it in these two locations so far, but it will cause problems with any accesses over the SPI bus given enough time.

newAM avatar Nov 11 '23 00:11 newAM

I'm experiencing something similar. My setup:

Cargo.toml relevant section

panic-halt = "0.2.0"
embedded-hal = "1.0"
ufmt = "0.2.0"
nb = "1.1.0"

w5500-ll = { version = "0.12.0", features = ["eh0"] }
w5500-hl = { version = "0.11.0" }
w5500-dhcp = "0.6.0"
w5500-mqtt = { version = "0.3.0" }

[dependencies.embedded-hal-v0]
version = "0.2.3"
package = "embedded-hal"

[dependencies.arduino-hal]
git = "https://github.com/rahix/avr-hal"
rev = "3e362624547462928a219c40f9ea8e3a64f21e5f"
features = ["arduino-mega2560"]

main.rs

//...

#[arduino_hal::entry]
fn main() -> ! {
    let dp = arduino_hal::Peripherals::take().unwrap_or_else(|| panic!());
    let pins = arduino_hal::pins!(dp);

    let mut serial = arduino_hal::default_serial!(dp, pins, 57600);

    let mut d10 = pins.d10.into_output(); 
    let mut d53 = pins.d53.into_output();
    let mut d4 = pins.d4.into_output();
    d4.set_high();
    d10.set_low();

    let (mut spi, mut cs) = arduino_hal::Spi::new(
        dp.SPI,
        pins.d52.into_output(),
        pins.d51.into_output(),
        pins.d50.into_pull_up_input(),
        d53,
        spi::Settings {mode: embedded_hal::spi::MODE_0, ..spi::Settings::default()}
    );

    cs.set_high().unwrap(); //trying this as a suggestion from GH issue - no effect
    let mut w5500 = W5500::new(spi, cs);

    //below are setup_socket and udp_bind calls

    // dhcp.setup_socket(&mut w5500).unwrap();
    let simr: u8 = w5500.simr().unwrap();
    w5500.set_simr(LOCAL_SOCKET.bitmask() | simr).unwrap();
    const MASK: SocketInterruptMask = SocketInterruptMask::ALL_MASKED.unmask_recv();
    w5500.set_sn_imr(LOCAL_SOCKET, MASK).unwrap();
    w5500.close(LOCAL_SOCKET).unwrap();
    w5500.set_sipr(&Ipv4Addr::UNSPECIFIED).unwrap();

    // w5500.udp_bind(LOCAL_SOCKET, 68).unwrap();
    ufmt::uwriteln!(&mut serial, "W5500 bind1\r").unwrap_infallible();
    w5500.set_sn_cr(LOCAL_SOCKET, SocketCommand::Close).unwrap();
    ufmt::uwriteln!(&mut serial, "W5500 bind2\r").unwrap_infallible();
    while w5500.sn_sr(LOCAL_SOCKET).unwrap() != Ok(SocketStatus::Closed) {
        match w5500.sn_sr(LOCAL_SOCKET).unwrap() {
            Ok(status) => {
                ufmt::uwriteln!(&mut serial, "W5500 waiting1: {}\r", (status as u8)).unwrap_infallible();
            }
            Err(f) => {
                ufmt::uwriteln!(&mut serial, "W5500 waiting1 err: {}\r", f).unwrap_infallible();
            }
        }
        // w5500.write(0x0, 0x0, &[0x80]).unwrap();
        // arduino_hal::delay_ms(1000);
    }
    ufmt::uwriteln!(&mut serial, "W5500 bind3\r").unwrap_infallible();
    w5500.set_sn_port(LOCAL_SOCKET, 68).unwrap();
    ufmt::uwriteln!(&mut serial, "W5500 bind4\r").unwrap_infallible();
    const MODE: SocketMode = SocketMode::DEFAULT.set_protocol(Protocol::Udp);
    ufmt::uwriteln!(&mut serial, "W5500 bind5\r").unwrap_infallible();
    w5500.set_sn_mr(LOCAL_SOCKET, MODE).unwrap();
    ufmt::uwriteln!(&mut serial, "W5500 bind6\r").unwrap_infallible();
    w5500.set_sn_cr(LOCAL_SOCKET, SocketCommand::Open).unwrap();
    // This will not hang, the socket status will always change to Udp
    // after a open command with SN_MR set to UDP.
    // (unless you do somthing silly like holding the W5500 in reset)
    ufmt::uwriteln!(&mut serial, "W5500 bind7\r").unwrap_infallible();
    while w5500.sn_sr(LOCAL_SOCKET).unwrap() != Ok(SocketStatus::Udp) {
        match w5500.sn_sr(LOCAL_SOCKET).unwrap() {
            Ok(status) => {
                ufmt::uwriteln!(&mut serial, "W5500 waiting2: {}\r", (status as u8)).unwrap_infallible();
            }
            Err(f) => {
                ufmt::uwriteln!(&mut serial, "W5500 waiting2 err: {}\r", f).unwrap_infallible();
            }
        }

        // w5500.set_sn_port(LOCAL_SOCKET, 68).unwrap();
        // w5500.set_sn_mr(LOCAL_SOCKET, MODE).unwrap();
        // w5500.set_sn_cr(LOCAL_SOCKET, SocketCommand::Open).unwrap();
        // w5500.write(0x0, 0x0, &[0x80]).unwrap();
        // arduino_hal::delay_ms(1000);
    }     //HANGS

This

while w5500.sn_sr(LOCAL_SOCKET).unwrap() != Ok(SocketStatus::Udp) 

hangs yielding

Starting
W5500 bind1
W5500 bind2
W5500 bind3
W5500 bind4
W5500 bind5
W5500 bind6
W5500 bind7
W5500 waiting2: 0
W5500 waiting2: 0
W5500 waiting2: 0
W5500 waiting2 err: 37   <-------- happens sometimes, rather rarely
W5500 waiting2: 0
W5500 waiting2: 0
W5500 waiting2: 0
...

Is there any chance to get this working?

kiemlicz avatar Jun 05 '24 18:06 kiemlicz

it is "fixed" (read: worked around) for EH0 on the main branch. I have been meaning to make a release, I'll do that today.

For EH1 there's no control for me, so it's up to the HAL authors to keep CS high long enough to meet the hold times. The W5500 base trait can also just be implemented directly if changing the HAL isn't easy.

newAM avatar Jun 09 '24 19:06 newAM

Thanks

I'm pasting updated snippet.

Cargo.toml

[dependencies]
panic-halt = "0.2.0"
embedded-hal = "1.0.0"
ufmt = "0.2.0"
nb = "1.1.0"

w5500-ll = { version = "0.13.0", features = ["eh0"] }
w5500-hl = { version = "0.12.0" }
w5500-dhcp = "0.7.0"
w5500-mqtt = { version = "0.4.0" }
#[arduino_hal::entry]
fn main() -> ! {
    let dp = arduino_hal::Peripherals::take().unwrap_or_else(|| panic!());
    let pins = arduino_hal::pins!(dp);

    let mut serial = arduino_hal::default_serial!(dp, pins, 57600);
    let mut d10 = pins.d10.into_output();
    let seed: u64 = 872398473984;

    d10.set_low();
    let (mut spi, mut cs) = arduino_hal::Spi::new(
        dp.SPI,
        pins.d52.into_output(),
        pins.d51.into_output(),
        pins.d50.into_pull_up_input(),
        pins.d53.into_output(),
        spi::Settings {mode: embedded_hal::spi::MODE_0, ..spi::Settings::default()}
        // spi::Settings::default()
    );

    ufmt::uwriteln!(&mut serial, "Starting\r").unwrap_infallible();
    cs.set_high().unwrap();
    let mut w5500 = W5500::new(spi, cs);
    let mut dhcp: Client = Client::new(LOCAL_SOCKET, seed, LOCAL_MAC, HOSTNAME);

    ufmt::uwriteln!(&mut serial, "W5500 socket_setup\r").unwrap_infallible();
    dhcp.setup_socket(&mut w5500).unwrap();

It is still stuck, should it work?

kiemlicz avatar Jun 11 '24 19:06 kiemlicz

Yeah, that should work. I have been running a DHCP client device for a little over a year now without issues.

What is the system frequency and SPI bus frequency of your device?

newAM avatar Jun 11 '24 23:06 newAM