esp-rs / esp-idf-svc

Type-Safe Rust Wrappers for various ESP-IDF services (WiFi, Network, Httpd, Logging, etc.)
https://docs.esp-rs.org/esp-idf-svc/
Apache License 2.0
330 stars 183 forks source link

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

Open rdeterre opened 2 months ago

rdeterre commented 2 months ago

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 ``` rust 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::, 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 commented 2 months ago
rdeterre commented 2 months ago

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:

ivmarkov commented 2 months ago

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 commented 2 months ago

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 commented 1 month ago

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 :+1:

Cargo.toml ```toml [package] name = "esp-static-eth" version = "0.1.0" authors = ["Romain Deterre "] 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 ```rust 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::, 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(()) } ```