diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index 7384bb26d3..5d6af4490e 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -68,6 +68,8 @@ CONF_CLK_MODE = "clk_mode" CONF_POWER_PIN = "power_pin" CONF_PHY_REGISTERS = "phy_registers" +CONF_INTERFACE = "interface" + CONF_CLOCK_SPEED = "clock_speed" EthernetType = ethernet_ns.enum("EthernetType") @@ -110,6 +112,12 @@ CLK_MODES_DEPRECATED = { "GPIO17_OUT": ("CLK_OUT", 17), } +SPI_INTERFACE_MAP = { + "spi1": "SPI1_HOST", + "spi2": "SPI2_HOST", + "spi3": "SPI3_HOST", +} + MANUAL_IP_SCHEMA = cv.Schema( { cv.Required(CONF_STATIC_IP): cv.ipv4address, @@ -243,6 +251,10 @@ SPI_SCHEMA = BASE_SCHEMA.extend( cv.Optional(CONF_CLOCK_SPEED, default="26.67MHz"): cv.All( cv.frequency, cv.int_range(int(8e6), int(80e6)) ), + cv.Optional(CONF_INTERFACE): cv.All( + cv.only_with_framework("esp-idf"), + cv.one_of(*SPI_INTERFACE_MAP.keys()), + ), # Set default value (SPI_ETHERNET_DEFAULT_POLLING_INTERVAL) at _validate() cv.Optional(CONF_POLLING_INTERVAL): cv.All( cv.positive_time_period_milliseconds, @@ -277,18 +289,21 @@ def _final_validate(config): if config[CONF_TYPE] not in SPI_ETHERNET_TYPES: return if spi_configs := fv.full_config.get().get(CONF_SPI): - variant = get_esp32_variant() - if variant in (VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3): - spi_host = "SPI2_HOST" + if CORE.using_esp_idf and CONF_INTERFACE in config: + spi_host = SPI_INTERFACE_MAP[config[CONF_INTERFACE]] else: - spi_host = "SPI3_HOST" + variant = get_esp32_variant() + if variant in (VARIANT_ESP32C3, VARIANT_ESP32S2, VARIANT_ESP32S3): + spi_host = "SPI2_HOST" + else: + spi_host = "SPI3_HOST" for spi_conf in spi_configs: if (index := spi_conf.get(CONF_INTERFACE_INDEX)) is not None: interface = get_spi_interface(index) if interface == spi_host: raise cv.Invalid( - f"`spi` component is using interface '{interface}'. " - f"To use {config[CONF_TYPE]}, you must change the `interface` on the `spi` component.", + f"this and an `spi` component are both using interface '{interface}'. " + f"To use {config[CONF_TYPE]}, you must change the `interface` on one of these." ) @@ -336,8 +351,17 @@ async def to_code(config): cg.add(var.set_clock_speed(config[CONF_CLOCK_SPEED])) cg.add_define("USE_ETHERNET_SPI") - add_idf_sdkconfig_option("CONFIG_ETH_USE_SPI_ETHERNET", True) - add_idf_sdkconfig_option(f"CONFIG_ETH_SPI_ETHERNET_{config[CONF_TYPE]}", True) + if CORE.using_esp_idf: + if CONF_INTERFACE in config: + cg.add( + var.set_interface( + cg.RawExpression(SPI_INTERFACE_MAP[config[CONF_INTERFACE]]) + ) + ) + add_idf_sdkconfig_option("CONFIG_ETH_USE_SPI_ETHERNET", True) + add_idf_sdkconfig_option( + f"CONFIG_ETH_SPI_ETHERNET_{config[CONF_TYPE]}", True + ) elif config[CONF_TYPE] == "OPENETH": cg.add_define("USE_ETHERNET_OPENETH") add_idf_sdkconfig_option("CONFIG_ETH_USE_OPENETH", True) diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 28043dd969..818aec9d7e 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -87,11 +87,20 @@ void EthernetComponent::setup() { .intr_flags = 0, }; + spi_host_device_t host; +#ifdef USE_ESP_IDF + if (this->interface_ != SPI_HOST_MAX) { + host = this->interface_; + } else { +#endif #if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \ defined(USE_ESP32_VARIANT_ESP32C6) - auto host = SPI2_HOST; + host = SPI2_HOST; #else - auto host = SPI3_HOST; + host = SPI3_HOST; +#endif +#if USE_ESP_IDF + } #endif err = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO); @@ -390,6 +399,15 @@ void EthernetComponent::dump_config() { " MOSI Pin: %u\n" " CS Pin: %u", this->clk_pin_, this->miso_pin_, this->mosi_pin_, this->cs_pin_); +#ifdef USE_ESP_IDF + { + constexpr std::array values{"spi1", "spi2", "spi3"}; + char const *const value{this->interface_ < values.size() ? values[this->interface_] : nullptr}; + if (value) { + ESP_LOGCONFIG(TAG, " Interface: %s", value); + } + } +#endif #ifdef USE_ETHERNET_SPI_POLLING_SUPPORT if (this->polling_interval_ != 0) { ESP_LOGCONFIG(TAG, " Polling Interval: %lu ms", this->polling_interval_); @@ -674,6 +692,9 @@ void EthernetComponent::set_cs_pin(uint8_t cs_pin) { this->cs_pin_ = cs_pin; } void EthernetComponent::set_interrupt_pin(uint8_t interrupt_pin) { this->interrupt_pin_ = interrupt_pin; } void EthernetComponent::set_reset_pin(uint8_t reset_pin) { this->reset_pin_ = reset_pin; } void EthernetComponent::set_clock_speed(int clock_speed) { this->clock_speed_ = clock_speed; } +#ifdef USE_ESP_IDF +void EthernetComponent::set_interface(SPIInterface interface) { this->interface_ = interface; } +#endif #ifdef USE_ETHERNET_SPI_POLLING_SUPPORT void EthernetComponent::set_polling_interval(uint32_t polling_interval) { this->polling_interval_ = polling_interval; } #endif diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index 6b4e342df5..2d4353b782 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -5,6 +5,14 @@ #include "esphome/core/hal.h" #include "esphome/components/network/ip_address.h" +#ifdef USE_ESP_IDF + +#include "driver/spi_master.h" + +using SPIInterface = spi_host_device_t; + +#endif // USE_ESP_IDF + #ifdef USE_ESP32 #include "esp_eth.h" @@ -70,6 +78,9 @@ class EthernetComponent : public Component { void set_interrupt_pin(uint8_t interrupt_pin); void set_reset_pin(uint8_t reset_pin); void set_clock_speed(int clock_speed); +#ifdef USE_ESP_IDF + void set_interface(SPIInterface interface); +#endif #ifdef USE_ETHERNET_SPI_POLLING_SUPPORT void set_polling_interval(uint32_t polling_interval); #endif @@ -124,6 +135,9 @@ class EthernetComponent : public Component { int reset_pin_{-1}; int phy_addr_spi_{-1}; int clock_speed_; +#ifdef USE_ESP_IDF + SPIInterface interface_{SPI_HOST_MAX}; // Default to invalid, will be set based on ESP32 variant +#endif #ifdef USE_ETHERNET_SPI_POLLING_SUPPORT uint32_t polling_interval_{0}; #endif