Fix gpio validation for esp32 variants (#2609)

Co-authored-by: Otto Winter <otto@otto-winter.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Martin 2021-11-08 19:29:28 +01:00 committed by GitHub
parent a17a6d5346
commit add484a2ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 348 additions and 43 deletions

View File

@ -1,4 +1,5 @@
import logging from dataclasses import dataclass
from typing import Any
from esphome.const import ( from esphome.const import (
CONF_ID, CONF_ID,
@ -17,10 +18,24 @@ import esphome.config_validation as cv
import esphome.codegen as cg import esphome.codegen as cg
from . import boards from . import boards
from .const import KEY_BOARD, KEY_ESP32, esp32_ns from .const import (
KEY_BOARD,
KEY_ESP32,
KEY_VARIANT,
VARIANT_ESP32,
VARIANT_ESP32C3,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
VARIANT_ESP32H2,
esp32_ns,
)
_LOGGER = logging.getLogger(__name__) from .gpio_esp32 import esp32_validate_gpio_pin, esp32_validate_supports
from .gpio_esp32_s2 import esp32_s2_validate_gpio_pin, esp32_s2_validate_supports
from .gpio_esp32_c3 import esp32_c3_validate_gpio_pin, esp32_c3_validate_supports
from .gpio_esp32_s3 import esp32_s3_validate_gpio_pin, esp32_s3_validate_supports
from .gpio_esp32_h2 import esp32_h2_validate_gpio_pin, esp32_h2_validate_supports
IDFInternalGPIOPin = esp32_ns.class_("IDFInternalGPIOPin", cg.InternalGPIOPin) IDFInternalGPIOPin = esp32_ns.class_("IDFInternalGPIOPin", cg.InternalGPIOPin)
@ -59,65 +74,61 @@ def _translate_pin(value):
return _lookup_pin(value) return _lookup_pin(value)
_ESP_SDIO_PINS = { @dataclass
6: "Flash Clock", class ESP32ValidationFunctions:
7: "Flash Data 0", pin_validation: Any
8: "Flash Data 1", usage_validation: Any
11: "Flash Command",
_esp32_validations = {
VARIANT_ESP32: ESP32ValidationFunctions(
pin_validation=esp32_validate_gpio_pin, usage_validation=esp32_validate_supports
),
VARIANT_ESP32S2: ESP32ValidationFunctions(
pin_validation=esp32_s2_validate_gpio_pin,
usage_validation=esp32_s2_validate_supports,
),
VARIANT_ESP32C3: ESP32ValidationFunctions(
pin_validation=esp32_c3_validate_gpio_pin,
usage_validation=esp32_c3_validate_supports,
),
VARIANT_ESP32S3: ESP32ValidationFunctions(
pin_validation=esp32_s3_validate_gpio_pin,
usage_validation=esp32_s3_validate_supports,
),
VARIANT_ESP32H2: ESP32ValidationFunctions(
pin_validation=esp32_h2_validate_gpio_pin,
usage_validation=esp32_h2_validate_supports,
),
} }
def validate_gpio_pin(value): def validate_gpio_pin(value):
value = _translate_pin(value) value = _translate_pin(value)
if value < 0 or value > 39: variant = CORE.data[KEY_ESP32][KEY_VARIANT]
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-39)") if variant not in _esp32_validations:
if value in _ESP_SDIO_PINS: raise cv.Invalid("Unsupported ESP32 variant {variant}")
raise cv.Invalid(
f"This pin cannot be used on ESP32s and is already used by the flash interface (function: {_ESP_SDIO_PINS[value]})" return _esp32_validations[variant].pin_validation(value)
)
if 9 <= value <= 10:
_LOGGER.warning(
"Pin %s (9-10) might already be used by the "
"flash interface in QUAD IO flash mode.",
value,
)
if value in (20, 24, 28, 29, 30, 31):
# These pins are not exposed in GPIO mux (reason unknown)
# but they're missing from IO_MUX list in datasheet
raise cv.Invalid(f"The pin GPIO{value} is not usable on ESP32s.")
return value
def validate_supports(value): def validate_supports(value):
num = value[CONF_NUMBER]
mode = value[CONF_MODE] mode = value[CONF_MODE]
is_input = mode[CONF_INPUT] is_input = mode[CONF_INPUT]
is_output = mode[CONF_OUTPUT] is_output = mode[CONF_OUTPUT]
is_open_drain = mode[CONF_OPEN_DRAIN] is_open_drain = mode[CONF_OPEN_DRAIN]
is_pullup = mode[CONF_PULLUP] is_pullup = mode[CONF_PULLUP]
is_pulldown = mode[CONF_PULLDOWN] is_pulldown = mode[CONF_PULLDOWN]
variant = CORE.data[KEY_ESP32][KEY_VARIANT]
if variant not in _esp32_validations:
raise cv.Invalid("Unsupported ESP32 variant {variant}")
if is_input:
# All ESP32 pins support input mode
pass
if is_output and 34 <= num <= 39:
raise cv.Invalid(
f"GPIO{num} (34-39) does not support output pin mode.",
[CONF_MODE, CONF_OUTPUT],
)
if is_open_drain and not is_output: if is_open_drain and not is_output:
raise cv.Invalid( raise cv.Invalid(
"Open-drain only works with output mode", [CONF_MODE, CONF_OPEN_DRAIN] "Open-drain only works with output mode", [CONF_MODE, CONF_OPEN_DRAIN]
) )
if is_pullup and 34 <= num <= 39:
raise cv.Invalid(
f"GPIO{num} (34-39) does not support pullups.", [CONF_MODE, CONF_PULLUP]
)
if is_pulldown and 34 <= num <= 39:
raise cv.Invalid(
f"GPIO{num} (34-39) does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN]
)
value = _esp32_validations[variant].usage_validation(value)
if CORE.using_arduino: if CORE.using_arduino:
# (input, output, open_drain, pullup, pulldown) # (input, output, open_drain, pullup, pulldown)
supported_modes = { supported_modes = {
@ -138,7 +149,6 @@ def validate_supports(value):
"This pin mode is not supported on ESP32 for arduino frameworks", "This pin mode is not supported on ESP32 for arduino frameworks",
[CONF_MODE], [CONF_MODE],
) )
return value return value

View File

@ -0,0 +1,77 @@
import logging
from esphome.const import (
CONF_INPUT,
CONF_MODE,
CONF_NUMBER,
CONF_OUTPUT,
CONF_PULLDOWN,
CONF_PULLUP,
)
import esphome.config_validation as cv
_ESP_SDIO_PINS = {
6: "Flash Clock",
7: "Flash Data 0",
8: "Flash Data 1",
11: "Flash Command",
}
_ESP32_STRAPPING_PINS = {0, 2, 4, 15}
_LOGGER = logging.getLogger(__name__)
def esp32_validate_gpio_pin(value):
if value < 0 or value > 39:
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-39)")
if value in _ESP_SDIO_PINS:
raise cv.Invalid(
f"This pin cannot be used on ESP32s and is already used by the flash interface (function: {_ESP_SDIO_PINS[value]})"
)
if 9 <= value <= 10:
_LOGGER.warning(
"Pin %s (9-10) might already be used by the "
"flash interface in QUAD IO flash mode.",
value,
)
if value in _ESP32_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
if value in (20, 24, 28, 29, 30, 31):
# These pins are not exposed in GPIO mux (reason unknown)
# but they're missing from IO_MUX list in datasheet
raise cv.Invalid(f"The pin GPIO{value} is not usable on ESP32s.")
return value
def esp32_validate_supports(value):
num = value[CONF_NUMBER]
mode = value[CONF_MODE]
is_input = mode[CONF_INPUT]
is_output = mode[CONF_OUTPUT]
is_pullup = mode[CONF_PULLUP]
is_pulldown = mode[CONF_PULLDOWN]
if is_input:
# All ESP32 pins support input mode
pass
if is_output and 34 <= num <= 39:
raise cv.Invalid(
f"GPIO{num} (34-39) does not support output pin mode.",
[CONF_MODE, CONF_OUTPUT],
)
if is_pullup and 34 <= num <= 39:
raise cv.Invalid(
f"GPIO{num} (34-39) does not support pullups.", [CONF_MODE, CONF_PULLUP]
)
if is_pulldown and 34 <= num <= 39:
raise cv.Invalid(
f"GPIO{num} (34-39) does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN]
)
return value

View File

@ -0,0 +1,53 @@
import logging
from esphome.const import (
CONF_INPUT,
CONF_MODE,
CONF_NUMBER,
)
import esphome.config_validation as cv
_ESP32C3_SPI_PSRAM_PINS = {
12: "SPIHD",
13: "SPIWP",
14: "SPICS0",
15: "SPICLK",
16: "SPID",
17: "SPIQ",
}
_ESP32C3_STRAPPING_PINS = {2, 8, 9}
_LOGGER = logging.getLogger(__name__)
def esp32_c3_validate_gpio_pin(value):
if value < 0 or value > 21:
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-21)")
if value in _ESP32C3_SPI_PSRAM_PINS:
raise cv.Invalid(
f"This pin cannot be used on ESP32-C3s and is already used by the SPI/PSRAM interface (function: {_ESP32C3_SPI_PSRAM_PINS[value]})"
)
if value in _ESP32C3_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
return value
def esp32_c3_validate_supports(value):
num = value[CONF_NUMBER]
mode = value[CONF_MODE]
is_input = mode[CONF_INPUT]
if num < 0 or num > 21:
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-21)")
if is_input:
# All ESP32 pins support input mode
pass
return value

View File

@ -0,0 +1,11 @@
import esphome.config_validation as cv
def esp32_h2_validate_gpio_pin(value):
# ESP32-H2 not yet supported
raise cv.Invalid("ESP32-H2 isn't supported yet")
def esp32_h2_validate_supports(value):
# ESP32-H2 not yet supported
raise cv.Invalid("ESP32-H2 isn't supported yet")

View File

@ -0,0 +1,80 @@
import logging
from esphome.const import (
CONF_INPUT,
CONF_MODE,
CONF_NUMBER,
CONF_OUTPUT,
CONF_PULLDOWN,
CONF_PULLUP,
)
import esphome.config_validation as cv
_ESP32S2_SPI_PSRAM_PINS = {
26: "SPICS1",
27: "SPIHD",
28: "SPIWP",
29: "SPICS0",
30: "SPICLK",
31: "SPIQ",
32: "SPID",
}
_ESP32S2_STRAPPING_PINS = {0, 45, 46}
_LOGGER = logging.getLogger(__name__)
def esp32_s2_validate_gpio_pin(value):
if value < 0 or value > 46:
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-46)")
if value in _ESP32S2_SPI_PSRAM_PINS:
raise cv.Invalid(
f"This pin cannot be used on ESP32-S2s and is already used by the SPI/PSRAM interface (function: {_ESP32S2_SPI_PSRAM_PINS[value]})"
)
if value in _ESP32S2_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
if value in (22, 23, 24, 25):
# These pins are not exposed in GPIO mux (reason unknown)
# but they're missing from IO_MUX list in datasheet
raise cv.Invalid(f"The pin GPIO{value} is not usable on ESP32-S2s.")
return value
def esp32_s2_validate_supports(value):
num = value[CONF_NUMBER]
mode = value[CONF_MODE]
is_input = mode[CONF_INPUT]
is_output = mode[CONF_OUTPUT]
is_pullup = mode[CONF_PULLUP]
is_pulldown = mode[CONF_PULLDOWN]
if num < 0 or num > 46:
raise cv.Invalid(f"Invalid pin number: {num} (must be 0-46)")
if is_input:
# All ESP32 pins support input mode
pass
if is_output and num == 46:
raise cv.Invalid(
f"GPIO{num} does not support output pin mode.",
[CONF_MODE, CONF_OUTPUT],
)
if is_pullup and num == 46:
raise cv.Invalid(
f"GPIO{num} does not support pullups.", [CONF_MODE, CONF_PULLUP]
)
if is_pulldown and num == 46:
raise cv.Invalid(
f"GPIO{num} does not support pulldowns.", [CONF_MODE, CONF_PULLDOWN]
)
return value

View File

@ -0,0 +1,74 @@
import logging
from esphome.const import (
CONF_INPUT,
CONF_MODE,
CONF_NUMBER,
)
import esphome.config_validation as cv
_ESP_32S3_SPI_PSRAM_PINS = {
26: "SPICS1",
27: "SPIHD",
28: "SPIWP",
29: "SPICS0",
30: "SPICLK",
31: "SPIQ",
32: "SPID",
}
_ESP_32_ESP32_S3R8_PSRAM_PINS = {
33: "SPIIO4",
34: "SPIIO5",
35: "SPIIO6",
36: "SPIIO7",
37: "SPIDQS",
}
_ESP_32S3_STRAPPING_PINS = {0, 3, 45, 46}
_LOGGER = logging.getLogger(__name__)
def esp32_s3_validate_gpio_pin(value):
if value < 0 or value > 48:
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-46)")
if value in _ESP_32S3_SPI_PSRAM_PINS:
raise cv.Invalid(
f"This pin cannot be used on ESP32-S3s and is already used by the SPI/PSRAM interface(function: {_ESP_32S3_SPI_PSRAM_PINS[value]})"
)
if value in _ESP_32_ESP32_S3R8_PSRAM_PINS:
_LOGGER.warning(
"GPIO%d is used by the PSRAM interface on ESP32-S3R8 / ESP32-S3R8V and should be avoided on these models",
value,
)
if value in _ESP_32S3_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
if value in (22, 23, 24, 25):
# These pins are not exposed in GPIO mux (reason unknown)
# but they're missing from IO_MUX list in datasheet
raise cv.Invalid(f"The pin GPIO{value} is not usable on ESP32-S3s.")
return value
def esp32_s3_validate_supports(value):
num = value[CONF_NUMBER]
mode = value[CONF_MODE]
is_input = mode[CONF_INPUT]
if num < 0 or num > 48:
raise cv.Invalid(f"Invalid pin number: {num} (must be 0-46)")
if is_input:
# All ESP32 pins support input mode
pass
return value