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

Can't acquire static IP when using W5500 ethernet chip #492

Open
rdeterre opened this issue Sep 25, 2024 · 5 comments
Open

Can't acquire static IP when using W5500 ethernet chip #492

rdeterre opened this issue Sep 25, 2024 · 5 comments

Comments

@rdeterre
Copy link

Hello,

I'm running into an issue where configuring a static IP for a W5500 SPI ethernet chip does not work, but using DHCP works fine.

To test, I am using a recently generated esp-rs/esp-idf-template project with the code below, adapted from the wifi_static_ip.rs example in this repo.

main.rs
use std::net::Ipv4Addr;
use std::str::FromStr;

use esp_idf_hal::gpio::AnyOutputPin;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::spi;
use esp_idf_hal::spi::config::DriverConfig;

use esp_idf_svc::eth::{BlockingEth, EspEth, EthDriver, SpiEth, SpiEthChipset};
use esp_idf_svc::eventloop::EspSystemEventLoop;
use esp_idf_svc::ipv4::{
    ClientConfiguration as IpClientConfiguration, ClientSettings as IpClientSettings,
    Configuration as IpConfiguration, Mask, Subnet, DHCPClientSettings
};
use esp_idf_svc::netif::{EspNetif, NetifConfiguration};

// Expects IPv4 address
const DEVICE_IP: Option<&str> = option_env!("DEVICE_IP");
// Expects IPv4 address
const GATEWAY_IP: Option<&str> = option_env!("GATEWAY_IP");
// Expects a number between 0 and 32, defaults to 24
const GATEWAY_NETMASK: Option<&str> = option_env!("GATEWAY_NETMASK");

fn main() -> anyhow::Result<()> {
    esp_idf_svc::sys::link_patches();
    esp_idf_svc::log::EspLogger::initialize_default();

    let peripherals = Peripherals::take()?;
    let pins = peripherals.pins;
    let sys_loop = EspSystemEventLoop::take()?;

    let spi_driver = spi::SpiDriver::new(
        peripherals.spi3,
        pins.gpio27,
        pins.gpio21,
        Some(pins.gpio22),
        &DriverConfig {
            dma: spi::Dma::Auto(4096),
            ..Default::default()
        },
    )?;
    let mut eth_driver = EthDriver::new_spi(
        spi_driver,
        pins.gpio23,
        Some(pins.gpio26),
        None::<AnyOutputPin>,
        SpiEthChipset::W5500,
        esp_idf_hal::units::Hertz(20 * 1000 * 1000),
        Some(&[0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED]),
        None,
        sys_loop.clone(),
    )?;

    let netmask = GATEWAY_NETMASK.unwrap_or("24");
    let netmask = u8::from_str(netmask)?;
    let gateway_addr = Ipv4Addr::from_str(GATEWAY_IP.unwrap())?;

    let static_ip = Ipv4Addr::from_str(DEVICE_IP.unwrap())?;
    log::info!("Using static IP {}", DEVICE_IP.unwrap());
    let ip_client_configuration = IpClientConfiguration::Fixed(IpClientSettings {
        ip: static_ip,
        subnet: Subnet {
            gateway: gateway_addr,
            mask: Mask(netmask),
        },
        // Can also be set to Ipv4Addrs if you need DNS
        dns: None,
        secondary_dns: None,
    });


    // log::info!("Using DHCP");
    // let ip_client_configuration = IpClientConfiguration::DHCP(DHCPClientSettings {
    //     hostname: Some(
    //         heapless::String::try_from("croquette")
    //             .map_err(|_| anyhow!("Could not create static string"))?,
    //     ),
    // });

    eth_driver.start()?;

    log::info!("EspEth");

    let eth = EspEth::wrap_all(
        eth_driver,
        EspNetif::new_with_conf(&NetifConfiguration {
            ip_configuration: IpConfiguration::Client(ip_client_configuration),
            ..NetifConfiguration::eth_default_client()
        })?,
    )?;

    log::info!("BlockingEth");
    let mut eth = BlockingEth::wrap(eth, sys_loop)?;
    eth.start()?;

    log::info!("Waiting for up...");
    eth.wait_netif_up()?;

    let ip_info = eth.eth().netif().get_ip_info()?;

    log::info!(
        "Eth info: {} {} {:?}",
        eth.is_started()?,
        eth.is_up()?,
        ip_info
    );

    core::mem::forget(eth);
    Ok(())
}

The application stalls after printing "Waiting for up..." for about ten seconds and then terminates. Here is the output log:

Output log
I (31) boot: ESP-IDF v5.1-beta1-378-gea5e0ff298-dirt 2nd stage bootloader
I (31) boot: compile time Jun  7 2023 07:48:23
I (33) boot: Multicore bootloader
I (37) boot: chip revision: v1.1
I (41) boot.esp32: SPI Speed      : 40MHz
I (46) boot.esp32: SPI Mode       : DIO
I (50) boot.esp32: SPI Flash Size : 4MB
I (55) boot: Enabling RNG early entropy source...
I (60) boot: Partition Table:
I (64) boot: ## Label            Usage          Type ST Offset   Length
I (71) boot:  0 nvs              WiFi data        01 02 00009000 00006000
I (78) boot:  1 phy_init         RF data          01 01 0000f000 00001000
I (86) boot:  2 factory          factory app      00 00 00010000 003f0000
I (93) boot: End of partition table
I (98) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=2be3ch (179772) map
I (171) esp_image: segment 1: paddr=0003be64 vaddr=3ffb0000 size=0236ch (  9068) load
I (175) esp_image: segment 2: paddr=0003e1d8 vaddr=40080000 size=01e40h (  7744) load
I (180) esp_image: segment 3: paddr=00040020 vaddr=400d0020 size=69810h (432144) map
I (341) esp_image: segment 4: paddr=000a9838 vaddr=40081e40 size=0bcb0h ( 48304) load
I (368) boot: Loaded app from partition at offset 0x10000
I (368) boot: Disabling RNG early entropy source...
I (380) cpu_start: Multicore app
I (389) cpu_start: Pro cpu start user code
I (389) cpu_start: cpu freq: 160000000 Hz
I (389) cpu_start: Application information:
I (392) cpu_start: Project name:     libespidf
I (397) cpu_start: App version:      1
I (401) cpu_start: Compile time:     Sep 23 2024 23:00:51
I (407) cpu_start: ELF file SHA256:  000000000...
I (413) cpu_start: ESP-IDF:          v5.2.2
I (418) cpu_start: Min chip rev:     v0.0
I (422) cpu_start: Max chip rev:     v3.99 
I (427) cpu_start: Chip rev:         v1.1
I (432) heap_init: Initializing. RAM available for dynamic allocation:
I (439) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (445) heap_init: At 3FFB36E8 len 0002C918 (178 KiB): DRAM
I (451) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (458) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (464) heap_init: At 4008DAF0 len 00012510 (73 KiB): IRAM
I (472) spi_flash: detected chip: generic
I (475) spi_flash: flash io: dio
W (479) pcnt(legacy): legacy driver is deprecated, please migrate to `driver/pulse_cnt.h`
W (488) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`
W (498) timer_group: legacy driver is deprecated, please migrate to `driver/gptimer.h`
I (508) main_task: Started on CPU0
I (518) main_task: Calling app_main()
I (528) esp_idf_svc::eth: Driver initialized
I (528) esp_idf_svc::eth: Attached MAC address: [222, 173, 190, 239, 254, 237]
I (528) esp_idf_svc::eth: Initialization complete
I (528) esp_static_eth: Using static IP 192.168.2.8
I (548) esp_idf_svc::eth: Start requested
I (548) esp_static_eth: EspEth
I (548) esp_idf_svc::eth: Stopping
I (548) esp_idf_svc::eth: Stop requested
I (558) esp_eth.netif.netif_glue: de:ad:be:ef:fe:ed
I (558) esp_eth.netif.netif_glue: ethernet attached to netif
I (568) esp_static_eth: BlockingEth
I (578) esp_idf_svc::eth: Start requested
I (578) esp_static_eth: Waiting for up...
I (15588) esp_idf_svc::eth: Stopping
I (15588) esp_idf_svc::eth: Stop requested
I (15588) esp_idf_svc::eth: EspEth dropped
I (15588) esp_idf_svc::netif: Dropped
I (15588) esp_idf_svc::eth: Stopping
E (15598) esp_eth: esp_eth_stop(310): driver not started yet
I (15598) esp_idf_svc::eth: Stop requested
I (15608) gpio: GPIO[23]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 
I (15618) esp_idf_svc::eth: Driver deinitialized
I (15618) esp_idf_svc::eth: EthDriver dropped
E (15628) spi_master: spi_master_deinit_driver(309): not all CSses freed
I (15638) gpio: GPIO[21]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 
I (15648) gpio: GPIO[22]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 
I (15658) gpio: GPIO[27]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 

I have also tested the static_ip example from esp-idf on the same hardware and the module manages to establish a connection without any issues.

@ivmarkov
Copy link
Collaborator

  • What ESP-IDF versions and crates' version?
  • Does it work if you comment out wait_netif_up and then just try to ping the gateway?

@rdeterre
Copy link
Author

Thanks! Removing the wait_netif_up works, I can ping the device no problem with this change 👍

For information, the dependencies in this test project are:

  • log = { version = "0.4", default-features = false }
  • esp-idf-svc = { version = "0.49", default-features = false }
  • anyhow = "1.0.89"
  • esp-idf-hal = "0.44.1"
  • heapless = "0.8.0"

@ivmarkov
Copy link
Collaborator

ivmarkov commented Sep 25, 2024

I think that might explain it.... We don't receive the ETH_IP_UP event so the waiting (which is driven by the system event loop) waits until timeout.

I suggest we keep this open, as ideally - the "wait" should work even for static IP addresses.

@ivmarkov
Copy link
Collaborator

In svc "0.49" we still have this buggy code. In other words, we might be waiting on the wrong event ID.

In latest master, the code is correctly waiting on the ETH_GOT_IP.

Perhaps you can try master by patching all esp-idf-* crates to their master versions in [patch.crates-io]?

@rdeterre
Copy link
Author

rdeterre commented Oct 2, 2024

After patching esp-idf-sys, esp-idf-hal and esp-idf-svc to master and making a small change to make the code build (see full main.rs and Cargo.toml below), it looks like the situation is the same: eth.wait_netif_up() still hangs.

Removing the call to wait_netif_up() still works though, the workaround is good 👍

Cargo.toml
[package]
name = "esp-static-eth"
version = "0.1.0"
authors = ["Romain Deterre <[email protected]>"]
edition = "2021"
resolver = "2"
rust-version = "1.77"

[[bin]]
name = "esp-static-eth"
harness = false # do not use the built in cargo test harness -> resolve rust-analyzer errors

[profile.release]
opt-level = "s"

[profile.dev]
debug = true    # Symbols are nice and they don't increase the size on Flash
opt-level = "z"

[features]
default = ["std", "embassy", "esp-idf-svc/native"]

pio = ["esp-idf-svc/pio"]
std = ["alloc", "esp-idf-svc/binstart", "esp-idf-svc/std"]
alloc = ["esp-idf-svc/alloc"]
nightly = ["esp-idf-svc/nightly"]
experimental = ["esp-idf-svc/experimental"]
embassy = ["esp-idf-svc/embassy-sync", "esp-idf-svc/critical-section", "esp-idf-svc/embassy-time-driver"]

[dependencies]
log = { version = "0.4", default-features = false }
esp-idf-svc = { version = "0.49", default-features = false }
anyhow = "1.0.89"
esp-idf-hal = "0.44.1"
heapless = "0.8.0"

[build-dependencies]
embuild = "0.32.0"

[patch.crates-io]
esp-idf-hal = { git = "https://github.com/esp-rs/esp-idf-hal" }
esp-idf-sys = { git = "https://github.com/esp-rs/esp-idf-sys" }
esp-idf-svc = { git = "https://github.com/esp-rs/esp-idf-svc" }
main.rs
use std::net::Ipv4Addr;
use std::str::FromStr;

use esp_idf_hal::gpio::AnyOutputPin;
use esp_idf_hal::peripherals::Peripherals;
use esp_idf_hal::spi;
use esp_idf_hal::spi::config::DriverConfig;

use esp_idf_svc::eth::{BlockingEth, EspEth, EthDriver, SpiEth, SpiEthChipset};
use esp_idf_svc::eventloop::EspSystemEventLoop;
use esp_idf_svc::ipv4::{
    ClientConfiguration as IpClientConfiguration, ClientSettings as IpClientSettings,
    Configuration as IpConfiguration, Mask, Subnet, DHCPClientSettings
};
use esp_idf_svc::netif::{EspNetif, NetifConfiguration};

// Expects IPv4 address
const DEVICE_IP: Option<&str> = option_env!("DEVICE_IP");
// Expects IPv4 address
const GATEWAY_IP: Option<&str> = option_env!("GATEWAY_IP");
// Expects a number between 0 and 32, defaults to 24
const GATEWAY_NETMASK: Option<&str> = option_env!("GATEWAY_NETMASK");

fn main() -> anyhow::Result<()> {
    esp_idf_svc::sys::link_patches();
    esp_idf_svc::log::EspLogger::initialize_default();

    let peripherals = Peripherals::take()?;
    let pins = peripherals.pins;
    let sys_loop = EspSystemEventLoop::take()?;

    let spi_driver = spi::SpiDriver::new(
        peripherals.spi3,
        pins.gpio27,
        pins.gpio21,
        Some(pins.gpio22),
        &DriverConfig {
            dma: spi::Dma::Auto(4096),
            ..Default::default()
        },
    )?;
    let mut eth_driver = EthDriver::new_spi(
        spi_driver,
        pins.gpio23,
        Some(pins.gpio26),
        None::<AnyOutputPin>,
        SpiEthChipset::W5500,
        esp_idf_hal::units::Hertz(20 * 1000 * 1000),
        Some(&[0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED]),
        None,
        sys_loop.clone(),
    )?;

    let netmask = GATEWAY_NETMASK.unwrap_or("24");
    let netmask = u8::from_str(netmask)?;
    let gateway_addr = Ipv4Addr::from_str(GATEWAY_IP.unwrap())?;

    let static_ip = Ipv4Addr::from_str(DEVICE_IP.unwrap())?;
    log::info!("Using static IP {}", DEVICE_IP.unwrap());
    let ip_client_configuration = IpClientConfiguration::Fixed(IpClientSettings {
        ip: static_ip,
        subnet: Subnet {
            gateway: gateway_addr,
            mask: Mask(netmask),
        },
        // Can also be set to Ipv4Addrs if you need DNS
        dns: None,
        secondary_dns: None,
    });


    // log::info!("Using DHCP");
    // let ip_client_configuration = IpClientConfiguration::DHCP(DHCPClientSettings {
    //     hostname: Some(
    //         heapless::String::try_from("croquette")
    //             .map_err(|_| anyhow!("Could not create static string"))?,
    //     ),
    // });

    eth_driver.start()?;

    log::info!("EspEth");

    let eth = EspEth::wrap_all(
        eth_driver,
        EspNetif::new_with_conf(&NetifConfiguration {
            ip_configuration: Some(IpConfiguration::Client(ip_client_configuration)),
            ..NetifConfiguration::eth_default_client()
        })?,
    )?;

    log::info!("BlockingEth");
    let mut eth = BlockingEth::wrap(eth, sys_loop)?;
    eth.start()?;

    log::info!("Waiting for up...");
    eth.wait_netif_up()?;

    let ip_info = eth.eth().netif().get_ip_info()?;

    log::info!(
        "Eth info: {} {} {:?}",
        eth.is_started()?,
        eth.is_up()?,
        ip_info
    );

    core::mem::forget(eth);
    Ok(())
}

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

No branches or pull requests

2 participants