mirror of
https://github.com/esphome/esphome.git
synced 2026-09-03 19:46:02 +00:00
[esp32] Fix S31 reserved pins (#18915)
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
Copilot Autofix powered by AI
parent
5e58b312e2
commit
2890afe0e5
@@ -5,11 +5,10 @@ import esphome.config_validation as cv
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER, CONF_SCL, CONF_SDA
|
||||
from esphome.pins import check_strapping_pin
|
||||
|
||||
# Per the ESP32-S31 datasheet, the SPI flash and PSRAM interfaces use
|
||||
# dedicated package pins (SPICS/SPIQ/SPIWP/SPIHD/SPICLK/SPID) outside the
|
||||
# GPIO matrix, so no GPIOs are reserved for them. GPIO29 and GPIO41 do not
|
||||
# exist on this chip (SOC_GPIO_VALID_GPIO_MASK excludes them).
|
||||
# https://documentation.espressif.com/esp32-s31_datasheet_en.html
|
||||
# Per the ESP32-S31 IDF DOCS and datasheet:
|
||||
# https://docs.espressif.com/projects/esp-idf/en/v6.1/esp32s31/api-reference/peripherals/gpio.html
|
||||
# https://documentation.espressif.com/esp32-s31_datasheet_en.pdf
|
||||
_ESP32S31_SPI_FLASH_PINS: set[int] = {26, 27, 28, 30, 31, 32}
|
||||
_ESP32S31_INVALID_PINS: set[int] = {29, 41}
|
||||
# GPIO60/GPIO61 set the boot mode; GPIO37 selects the JTAG signal source;
|
||||
# GPIO36 sets the VDD_SPI voltage.
|
||||
@@ -25,6 +24,10 @@ def esp32_s31_validate_gpio_pin(value: int) -> int:
|
||||
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-61)")
|
||||
if value in _ESP32S31_INVALID_PINS:
|
||||
raise cv.Invalid(f"GPIO{value} does not exist on ESP32-S31.")
|
||||
if value in _ESP32S31_SPI_FLASH_PINS:
|
||||
raise cv.Invalid(
|
||||
f"GPIO{value} is reserved for the SPI flash interface on ESP32-S31 and cannot be used."
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
|
||||
@@ -1274,8 +1274,9 @@ def test_esp32_s31_gpio_validation(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""S31: flash uses dedicated pins so GPIO27-33 are normal pins, GPIO29 and
|
||||
GPIO41 do not exist, and GPIO36 is a strapping pin."""
|
||||
"""S31: GPIO26-28/30-32 are reserved for the SPI flash interface, GPIO29
|
||||
and GPIO41 do not exist, GPIO33 is a normal pin, and GPIO36 is a
|
||||
strapping pin."""
|
||||
from esphome.components.esp32.const import VARIANT_ESP32S31
|
||||
from esphome.components.esp32.gpio import validate_supports
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_OPEN_DRAIN, CONF_OUTPUT
|
||||
@@ -1286,9 +1287,18 @@ def test_esp32_s31_gpio_validation(
|
||||
|
||||
input_mode = {CONF_INPUT: True, CONF_OUTPUT: False, CONF_OPEN_DRAIN: False}
|
||||
|
||||
# Previously reserved for the flash interface, which uses dedicated pins
|
||||
for num in (27, 28, 31, 32, 33):
|
||||
pin = {CONF_NUMBER: num, CONF_IGNORE_PIN_VALIDATION_ERROR: False}
|
||||
# Not reserved; a normal GPIO
|
||||
pin = {CONF_NUMBER: 33, CONF_IGNORE_PIN_VALIDATION_ERROR: False}
|
||||
assert validate_gpio_pin(pin)[CONF_NUMBER] == 33
|
||||
|
||||
# Reserved for the SPI flash interface, but can be bypassed with
|
||||
# ignore_pin_validation_error
|
||||
for num in (26, 27, 28, 30, 31, 32):
|
||||
with pytest.raises(cv.Invalid, match=f"GPIO{num} is reserved"):
|
||||
validate_gpio_pin(
|
||||
{CONF_NUMBER: num, CONF_IGNORE_PIN_VALIDATION_ERROR: False}
|
||||
)
|
||||
pin = {CONF_NUMBER: num, CONF_IGNORE_PIN_VALIDATION_ERROR: True}
|
||||
assert validate_gpio_pin(pin)[CONF_NUMBER] == num
|
||||
|
||||
for num in (29, 41):
|
||||
|
||||
@@ -144,17 +144,22 @@ def test_metadata_records_rotation(
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("variant", "board"),
|
||||
("variant", "board", "model"),
|
||||
[
|
||||
(VARIANT_ESP32S3, "esp32-s3-devkitc-1"),
|
||||
(VARIANT_ESP32P4, "esp32-p4-evboard"),
|
||||
# ESP32-8048S070 is a real Sunton board wired for ESP32-S3 (e.g. its
|
||||
# default de_pin is GPIO41, which doesn't exist on S31), so it is
|
||||
# only meaningful as a config on that variant.
|
||||
(VARIANT_ESP32S3, "esp32-s3-devkitc-1", "ESP32-8048S070"),
|
||||
# P4 and S31 use the pin-agnostic CUSTOM model so this only checks
|
||||
# that the chip itself is accepted, independent of board wiring.
|
||||
(VARIANT_ESP32P4, "esp32-p4-evboard", "CUSTOM"),
|
||||
# No dedicated board is registered for ESP32-S31 yet; an unknown board
|
||||
# name simply skips per-board pin validation.
|
||||
(VARIANT_ESP32S31, "esp32-s31-devkitc"),
|
||||
(VARIANT_ESP32S31, "esp32-s31-devkitc", "CUSTOM"),
|
||||
],
|
||||
)
|
||||
def test_configuration_succeeds_on_supported_variants(
|
||||
variant: str, board: str, set_core_config: SetCoreConfigCallable
|
||||
variant: str, board: str, model: str, set_core_config: SetCoreConfigCallable
|
||||
) -> None:
|
||||
"""mipi_rgb requires a chip with an RGB LCD peripheral: S3, P4 or S31."""
|
||||
set_core_config(
|
||||
@@ -164,7 +169,11 @@ def test_configuration_succeeds_on_supported_variants(
|
||||
|
||||
from esphome.components.mipi_rgb.display import CONFIG_SCHEMA
|
||||
|
||||
CONFIG_SCHEMA({"model": "ESP32-8048S070", "data_pins": DATA_PINS, "pclk_pin": 21})
|
||||
config = {"model": model, "data_pins": DATA_PINS, "pclk_pin": 21}
|
||||
if model == "CUSTOM":
|
||||
config[CONF_INIT_SEQUENCE] = [[0xA0, 0x01]]
|
||||
config[CONF_DIMENSIONS] = {CONF_WIDTH: 480, CONF_HEIGHT: 480}
|
||||
CONFIG_SCHEMA(config)
|
||||
|
||||
|
||||
def test_only_on_variant_rejects_unsupported_variant(
|
||||
|
||||
Reference in New Issue
Block a user