enhance ethernet component for spi interface choice on esp-idf

This commit is contained in:
Ross Tyler
2025-10-09 10:17:20 -07:00
parent d006008539
commit 1804face26
3 changed files with 69 additions and 10 deletions
+32 -8
View File
@@ -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)
@@ -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<char const *const, SPI_HOST_MAX> 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
@@ -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