diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index d9f51c677e..10f9a73863 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -123,6 +123,8 @@ ETHERNET_TYPES = { "DM9051": EthernetType.ETHERNET_TYPE_DM9051, "LAN8670": EthernetType.ETHERNET_TYPE_LAN8670, "ENC28J60": EthernetType.ETHERNET_TYPE_ENC28J60, + "W6100": EthernetType.ETHERNET_TYPE_W6100, + "W6300": EthernetType.ETHERNET_TYPE_W6300, } # PHY types that need compile-time defines for conditional compilation @@ -140,6 +142,8 @@ _PHY_TYPE_TO_DEFINE = { "DM9051": "USE_ETHERNET_DM9051", "LAN8670": "USE_ETHERNET_LAN8670", "ENC28J60": "USE_ETHERNET_ENC28J60", + "W6100": "USE_ETHERNET_W6100", + "W6300": "USE_ETHERNET_W6300", } @@ -170,12 +174,14 @@ _ALWAYS_EXTERNAL_IDF_COMPONENTS = {"LAN8670", "ENC28J60"} # ESP32-only SPI ethernet types (W5100 is RP2040-only, no ESP-IDF driver) SPI_ETHERNET_TYPES = {"W5500", "DM9051", "ENC28J60"} -# RP2040-supported SPI ethernet types -RP2040_SPI_ETHERNET_TYPES = {"W5100", "W5500", "ENC28J60"} +# RP2040-supported ethernet types (SPI and PIO QSPI) +RP2040_ETHERNET_TYPES = {"W5100", "W5500", "W6100", "W6300", "ENC28J60"} _RP2040_SPI_LIBRARIES = { "W5100": "lwIP_w5100", "W5500": "lwIP_w5500", "ENC28J60": "lwIP_enc28j60", + "W6100": "lwIP_w6100", + "W6300": "lwIP_w6300", } SPI_ETHERNET_DEFAULT_POLLING_INTERVAL = TimePeriodMilliseconds(milliseconds=10) @@ -328,9 +334,9 @@ def _validate(config): f"{config[CONF_TYPE]} PHY requires RMII interface and is only supported " f"on ESP32 classic and ESP32-P4, not {variant}" ) - elif CORE.is_rp2040 and config[CONF_TYPE] not in RP2040_SPI_ETHERNET_TYPES: + elif CORE.is_rp2040 and config[CONF_TYPE] not in RP2040_ETHERNET_TYPES: raise cv.Invalid( - f"Only {', '.join(sorted(RP2040_SPI_ETHERNET_TYPES))} are supported on RP2040, " + f"Only {', '.join(sorted(RP2040_ETHERNET_TYPES))} are supported on RP2040, " f"not {config[CONF_TYPE]}" ) return config @@ -427,6 +433,8 @@ CONFIG_SCHEMA = cv.All( "OPENETH": cv.All(BASE_SCHEMA, cv.only_on([Platform.ESP32])), "DM9051": SPI_SCHEMA, "ENC28J60": SPI_SCHEMA, + "W6100": cv.All(SPI_SCHEMA, cv.only_on([Platform.RP2040])), + "W6300": cv.All(SPI_SCHEMA, cv.only_on([Platform.RP2040])), "LAN8670": RMII_SCHEMA, }, upper=True, diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index b760ba2af7..3a87842315 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -30,6 +30,20 @@ extern "C" eth_esp32_emac_config_t eth_esp32_emac_default_config(void); #include #elif defined(USE_ETHERNET_W5100) #include +#elif defined(USE_ETHERNET_W6100) +#include +#elif defined(USE_ETHERNET_W6300) +#include +// W6300 uses PIO QSPI, not Arduino SPI. The upstream Wiznet6300 class +// incorrectly returns needsSPI()=true, causing LwipIntfDev::begin() to +// call SPI.begin() which claims GPIOs that PIO QSPI needs. +// This wrapper hides needsSPI() with a version returning false. +class Wiznet6300NoSPI : public Wiznet6300 { + public: + using Wiznet6300::Wiznet6300; + constexpr bool needsSPI() const { return false; } +}; +using Wiznet6300lwIPFixed = LwipIntfDev; #elif defined(USE_ETHERNET_ENC28J60) #include #else @@ -70,6 +84,8 @@ enum EthernetType : uint8_t { ETHERNET_TYPE_DM9051, ETHERNET_TYPE_LAN8670, ETHERNET_TYPE_ENC28J60, + ETHERNET_TYPE_W6100, + ETHERNET_TYPE_W6300, }; struct ManualIP { @@ -232,6 +248,8 @@ class EthernetComponent final : public Component { static constexpr uint32_t LINK_CHECK_INTERVAL = 500; // ms between link/IP polls #if defined(USE_ETHERNET_W5100) static constexpr uint32_t RESET_DELAY_MS = 150; // W5100S PLL lock time +#elif defined(USE_ETHERNET_W6300) + static constexpr uint32_t RESET_DELAY_MS = 100; // W6300 needs 100ms after hardware reset #else static constexpr uint32_t RESET_DELAY_MS = 10; #endif @@ -239,6 +257,10 @@ class EthernetComponent final : public Component { Wiznet5500lwIP *eth_{nullptr}; #elif defined(USE_ETHERNET_W5100) Wiznet5100lwIP *eth_{nullptr}; +#elif defined(USE_ETHERNET_W6100) + Wiznet6100lwIP *eth_{nullptr}; +#elif defined(USE_ETHERNET_W6300) + Wiznet6300lwIPFixed *eth_{nullptr}; #elif defined(USE_ETHERNET_ENC28J60) ENC28J60lwIP *eth_{nullptr}; #else diff --git a/esphome/components/ethernet/ethernet_component_rp2040.cpp b/esphome/components/ethernet/ethernet_component_rp2040.cpp index 9771bc59d5..ef7bd46332 100644 --- a/esphome/components/ethernet/ethernet_component_rp2040.cpp +++ b/esphome/components/ethernet/ethernet_component_rp2040.cpp @@ -18,9 +18,14 @@ static const char *const TAG = "ethernet"; void EthernetComponent::setup() { // Configure SPI pins +#if !defined(USE_ETHERNET_W6300) SPI.setRX(this->miso_pin_); SPI.setTX(this->mosi_pin_); SPI.setSCK(this->clk_pin_); +#endif + // W6300 uses PIO QSPI with hardcoded pins, not Arduino SPI. + // SPI pin config is skipped; Wiznet6300lwIPFixed (needsSPI()=false) + // prevents LwipIntfDev::begin() from calling SPI.begin(). // Toggle reset pin if configured if (this->reset_pin_ >= 0) { @@ -40,6 +45,10 @@ void EthernetComponent::setup() { this->eth_ = new Wiznet5500lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT #elif defined(USE_ETHERNET_W5100) this->eth_ = new Wiznet5100lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT +#elif defined(USE_ETHERNET_W6100) + this->eth_ = new Wiznet6100lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT +#elif defined(USE_ETHERNET_W6300) + this->eth_ = new Wiznet6300lwIPFixed(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT #elif defined(USE_ETHERNET_ENC28J60) this->eth_ = new ENC28J60lwIP(this->cs_pin_, SPI, this->interrupt_pin_); // NOLINT #endif @@ -183,9 +192,23 @@ void EthernetComponent::dump_config() { type_str = "W5500"; #elif defined(USE_ETHERNET_W5100) type_str = "W5100"; +#elif defined(USE_ETHERNET_W6100) + type_str = "W6100"; +#elif defined(USE_ETHERNET_W6300) + type_str = "W6300"; #elif defined(USE_ETHERNET_ENC28J60) type_str = "ENC28J60"; #endif +#if defined(USE_ETHERNET_W6300) + // W6300 uses PIO QSPI with hardcoded pins — SPI pin fields are not used + ESP_LOGCONFIG(TAG, + "Ethernet:\n" + " Type: %s (PIO QSPI)\n" + " Connected: %s\n" + " IRQ Pin: %d\n" + " Reset Pin: %d", + type_str, YESNO(this->is_connected()), this->interrupt_pin_, this->reset_pin_); +#else ESP_LOGCONFIG(TAG, "Ethernet:\n" " Type: %s\n" @@ -198,6 +221,7 @@ void EthernetComponent::dump_config() { " Reset Pin: %d", type_str, YESNO(this->is_connected()), this->clk_pin_, this->miso_pin_, this->mosi_pin_, this->cs_pin_, this->interrupt_pin_, this->reset_pin_); +#endif this->dump_connect_params_(); } diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 4939c194e3..d8b4faced9 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -300,6 +300,8 @@ #define USE_ETHERNET_OPENETH #define USE_ETHERNET_W5100 #define USE_ETHERNET_W5500 +#define USE_ETHERNET_W6100 +#define USE_ETHERNET_W6300 #define USE_ETHERNET_DM9051 #define CONFIG_ETH_SPI_ETHERNET_W5500 1 #define CONFIG_ETH_SPI_ETHERNET_DM9051 1 diff --git a/tests/components/ethernet/common-w6100-rp2040.yaml b/tests/components/ethernet/common-w6100-rp2040.yaml new file mode 100644 index 0000000000..8afbd2d7cd --- /dev/null +++ b/tests/components/ethernet/common-w6100-rp2040.yaml @@ -0,0 +1,18 @@ +ethernet: + type: W6100 + clk_pin: 18 + mosi_pin: 19 + miso_pin: 16 + cs_pin: 17 + interrupt_pin: 21 + reset_pin: 20 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local + mac_address: "02:AA:BB:CC:DD:01" + on_connect: + - logger.log: "Ethernet connected!" + on_disconnect: + - logger.log: "Ethernet disconnected!" diff --git a/tests/components/ethernet/common-w6300-rp2040.yaml b/tests/components/ethernet/common-w6300-rp2040.yaml new file mode 100644 index 0000000000..c248bc9810 --- /dev/null +++ b/tests/components/ethernet/common-w6300-rp2040.yaml @@ -0,0 +1,18 @@ +ethernet: + type: W6300 + clk_pin: 18 + mosi_pin: 19 + miso_pin: 16 + cs_pin: 17 + interrupt_pin: 21 + reset_pin: 20 + manual_ip: + static_ip: 192.168.178.56 + gateway: 192.168.178.1 + subnet: 255.255.255.0 + domain: .local + mac_address: "02:AA:BB:CC:DD:01" + on_connect: + - logger.log: "Ethernet connected!" + on_disconnect: + - logger.log: "Ethernet disconnected!" diff --git a/tests/components/ethernet/test-w6100.rp2040-ard.yaml b/tests/components/ethernet/test-w6100.rp2040-ard.yaml new file mode 100644 index 0000000000..bf119e97c4 --- /dev/null +++ b/tests/components/ethernet/test-w6100.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common-w6100-rp2040.yaml diff --git a/tests/components/ethernet/test-w6300.rp2040-ard.yaml b/tests/components/ethernet/test-w6300.rp2040-ard.yaml new file mode 100644 index 0000000000..4fa1bb76f4 --- /dev/null +++ b/tests/components/ethernet/test-w6300.rp2040-ard.yaml @@ -0,0 +1 @@ +<<: !include common-w6300-rp2040.yaml