[ethernet] Add RMII GPIO pin conflict validation

This commit is contained in:
J. Nick Koston
2025-10-22 14:57:32 -10:00
parent 7f567bdfbe
commit 6a2b305eb2

View File

@@ -32,6 +32,7 @@ from esphome.const import (
CONF_MISO_PIN,
CONF_MODE,
CONF_MOSI_PIN,
CONF_NUMBER,
CONF_PAGE_ID,
CONF_PIN,
CONF_POLLING_INTERVAL,
@@ -52,12 +53,24 @@ from esphome.core import (
coroutine_with_priority,
)
import esphome.final_validate as fv
from esphome.types import ConfigType
CONFLICTS_WITH = ["wifi"]
DEPENDENCIES = ["esp32"]
AUTO_LOAD = ["network"]
LOGGER = logging.getLogger(__name__)
# RMII pins that are hardcoded on ESP32 and cannot be changed
# These pins are used by the internal Ethernet MAC when using RMII PHYs
ESP32_RMII_FIXED_PINS = {
19: "EMAC_TXD0",
21: "EMAC_TX_EN",
22: "EMAC_TXD1",
25: "EMAC_RXD0",
26: "EMAC_RXD1",
27: "EMAC_RX_CRS_DV",
}
ethernet_ns = cg.esphome_ns.namespace("ethernet")
PHYRegister = ethernet_ns.struct("PHYRegister")
CONF_PHY_ADDR = "phy_addr"
@@ -383,3 +396,38 @@ async def to_code(config):
if CORE.using_arduino:
cg.add_library("WiFi", None)
def _final_validate_rmii_pins(config: ConfigType) -> None:
"""Validate that RMII pins are not used by other components."""
# Only validate for RMII-based PHYs on ESP32/ESP32P4
if config[CONF_TYPE] in SPI_ETHERNET_TYPES or config[CONF_TYPE] == "OPENETH":
return # SPI and OPENETH don't use RMII
variant = get_esp32_variant()
if variant not in (VARIANT_ESP32, VARIANT_ESP32P4):
return # Only ESP32 classic and P4 have RMII
# Check each RMII pin against the pin registry
for pin_num, pin_function in ESP32_RMII_FIXED_PINS.items():
# Check if this pin is used by any component
for pin_list in pins.PIN_SCHEMA_REGISTRY.pins_used.values():
for pin_path, _, pin_config in pin_list:
if pin_config.get(CONF_NUMBER) == pin_num:
# Found a conflict - show helpful error message
component_path = ".".join(str(p) for p in pin_path)
raise cv.Invalid(
f"GPIO{pin_num} is reserved for Ethernet RMII ({pin_function}) and cannot be used. "
f"This pin is hardcoded by ESP-IDF and cannot be changed when using RMII Ethernet PHYs. "
f"Please choose a different GPIO pin for '{component_path}'.",
path=pin_path,
)
def _final_validate(config: ConfigType) -> ConfigType:
"""Final validation for Ethernet component."""
_final_validate_rmii_pins(config)
return config
FINAL_VALIDATE_SCHEMA = _final_validate