From 90c10103b81fd705b5581b4491e853137d2d914b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 14 Mar 2026 17:08:42 -1000 Subject: [PATCH] [ethernet] Throttle RP2040 link polling, fix defines.h warnings - Throttle linkStatus()/connected() polling to 500ms intervals to avoid excessive SPI transactions on every loop iteration - Guard USE_ETHERNET/USE_ETHERNET_SPI in RP2040 defines.h block with #ifndef to prevent macro redefinition warnings --- esphome/components/ethernet/ethernet_component.h | 2 ++ .../ethernet/ethernet_component_rp2040.cpp | 12 +++++++----- esphome/core/defines.h | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index ad2368e03fe..7c139bb19c1 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -214,7 +214,9 @@ class EthernetComponent : public Component { #endif // USE_ESP32 #ifdef USE_RP2040 + static constexpr uint32_t LINK_CHECK_INTERVAL = 500; // ms between link/IP polls Wiznet5500lwIP *eth_{nullptr}; + uint32_t last_link_check_{0}; uint8_t clk_pin_; uint8_t miso_pin_; uint8_t mosi_pin_; diff --git a/esphome/components/ethernet/ethernet_component_rp2040.cpp b/esphome/components/ethernet/ethernet_component_rp2040.cpp index fd2ff4a6473..c4f7aceac8e 100644 --- a/esphome/components/ethernet/ethernet_component_rp2040.cpp +++ b/esphome/components/ethernet/ethernet_component_rp2040.cpp @@ -81,11 +81,15 @@ void EthernetComponent::setup() { void EthernetComponent::loop() { // On RP2040, we need to poll connection state since there are no events. - // linkStatus() reads the W5500 PHY register via SPI — no lwip state involved. + const uint32_t now = App.get_loop_component_start_time(); + + // Throttle link/IP polling to avoid excessive SPI transactions from linkStatus() + // which reads the W5500 PHY register via SPI on every call. // connected() reads netif->ip_addr without LwIPLock, but this is a single // 32-bit aligned read (atomic on ARM) — worst case is a one-iteration-stale // value, which is benign for polling. - if (this->eth_ != nullptr) { + if (this->eth_ != nullptr && now - this->last_link_check_ >= LINK_CHECK_INTERVAL) { + this->last_link_check_ = now; bool link_up = this->eth_->linkStatus() == LinkON; bool has_ip = this->eth_->connected(); @@ -108,9 +112,7 @@ void EthernetComponent::loop() { } } - // Call common state machine - const uint32_t now = App.get_loop_component_start_time(); - + // State machine switch (this->state_) { case EthernetComponentState::STOPPED: if (this->started_) { diff --git a/esphome/core/defines.h b/esphome/core/defines.h index b7a298eab6d..7b234be2c4c 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -351,9 +351,13 @@ #define USE_SOCKET_IMPL_LWIP_TCP #define USE_RP2040_BLE #define USE_SPI +#ifndef USE_ETHERNET #define USE_ETHERNET +#endif +#ifndef USE_ETHERNET_SPI #define USE_ETHERNET_SPI #endif +#endif #ifdef USE_LIBRETINY #define USE_CAPTIVE_PORTAL