Skip to content
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

UDP Binding stuck in infinite loop #280

Open
adsnaider opened this issue Nov 10, 2023 · 9 comments
Open

UDP Binding stuck in infinite loop #280

adsnaider opened this issue Nov 10, 2023 · 9 comments
Labels
bug Something isn't working

Comments

@adsnaider
Copy link

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.

@newAM
Copy link
Owner

newAM commented Nov 10, 2023

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: #252 (comment)

@newAM newAM added the bug Something isn't working label Nov 10, 2023
@adsnaider
Copy link
Author

adsnaider commented Nov 10, 2023

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

@newAM
Copy link
Owner

newAM commented Nov 10, 2023

:/ 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.

@adsnaider
Copy link
Author

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

@newAM
Copy link
Owner

newAM commented Nov 11, 2023

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.

@kiemlicz
Copy link

kiemlicz commented Jun 5, 2024

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?

@newAM
Copy link
Owner

newAM commented Jun 9, 2024

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.

@kiemlicz
Copy link

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?

@newAM
Copy link
Owner

newAM commented Jun 11, 2024

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants