[i2c] Fix port logic with ESP-IDF (#12063)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
9f60aed9b0
commit
7a20c85eec
@@ -1,9 +1,12 @@
|
||||
import logging
|
||||
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER, CONF_SCL, CONF_SDA
|
||||
from esphome.pins import check_strapping_pin
|
||||
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/esp_hal_i2c/esp32c5/include/hal/i2c_ll.h
|
||||
_ESP32C5_I2C_LP_PINS = {"SDA": 2, "SCL": 3}
|
||||
|
||||
_ESP32C5_SPI_PSRAM_PINS = {
|
||||
16: "SPICS0",
|
||||
17: "SPIQ",
|
||||
@@ -43,3 +46,13 @@ def esp32_c5_validate_supports(value):
|
||||
|
||||
check_strapping_pin(value, _ESP32C5_STRAPPING_PINS, _LOGGER)
|
||||
return value
|
||||
|
||||
|
||||
def esp32_c5_validate_lp_i2c(value):
|
||||
lp_sda_pin = _ESP32C5_I2C_LP_PINS["SDA"]
|
||||
lp_scl_pin = _ESP32C5_I2C_LP_PINS["SCL"]
|
||||
if int(value[CONF_SDA]) != lp_sda_pin or int(value[CONF_SCL]) != lp_scl_pin:
|
||||
raise cv.Invalid(
|
||||
f"Low power i2c interface is only supported on GPIO{lp_sda_pin} SDA and GPIO{lp_scl_pin} SCL for ESP32-C5"
|
||||
)
|
||||
return value
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import logging
|
||||
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER, CONF_SCL, CONF_SDA
|
||||
from esphome.pins import check_strapping_pin
|
||||
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/esp_hal_i2c/esp32c6/include/hal/i2c_ll.h
|
||||
_ESP32C6_I2C_LP_PINS = {"SDA": 6, "SCL": 7}
|
||||
|
||||
_ESP32C6_SPI_PSRAM_PINS = {
|
||||
24: "SPICS0",
|
||||
25: "SPIQ",
|
||||
@@ -43,3 +46,13 @@ def esp32_c6_validate_supports(value):
|
||||
|
||||
check_strapping_pin(value, _ESP32C6_STRAPPING_PINS, _LOGGER)
|
||||
return value
|
||||
|
||||
|
||||
def esp32_c6_validate_lp_i2c(value):
|
||||
lp_sda_pin = _ESP32C6_I2C_LP_PINS["SDA"]
|
||||
lp_scl_pin = _ESP32C6_I2C_LP_PINS["SCL"]
|
||||
if int(value[CONF_SDA]) != lp_sda_pin or int(value[CONF_SCL]) != lp_scl_pin:
|
||||
raise cv.Invalid(
|
||||
f"Low power i2c interface is only supported on GPIO{lp_sda_pin} SDA and GPIO{lp_scl_pin} SCL for ESP32-C6"
|
||||
)
|
||||
return value
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import logging
|
||||
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
|
||||
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER, CONF_SCL, CONF_SDA
|
||||
from esphome.pins import check_strapping_pin
|
||||
|
||||
# https://documentation.espressif.com/esp32-p4-chip-revision-v1.3_datasheet_en.pdf
|
||||
_ESP32P4_LP_PINS = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
|
||||
|
||||
_ESP32P4_USB_JTAG_PINS = {24, 25}
|
||||
|
||||
_ESP32P4_STRAPPING_PINS = {34, 35, 36, 37, 38}
|
||||
@@ -36,3 +39,14 @@ def esp32_p4_validate_supports(value):
|
||||
pass
|
||||
check_strapping_pin(value, _ESP32P4_STRAPPING_PINS, _LOGGER)
|
||||
return value
|
||||
|
||||
|
||||
def esp32_p4_validate_lp_i2c(value):
|
||||
if (
|
||||
int(value[CONF_SDA]) not in _ESP32P4_LP_PINS
|
||||
or int(value[CONF_SCL]) not in _ESP32P4_LP_PINS
|
||||
):
|
||||
raise cv.Invalid(
|
||||
f"Low power i2c interface for ESP32-P4 is only supported on low power interface GPIO{min(_ESP32P4_LP_PINS)} - GPIO{max(_ESP32P4_LP_PINS)}"
|
||||
)
|
||||
return value
|
||||
|
||||
@@ -2,6 +2,23 @@ import logging
|
||||
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import esp32
|
||||
from esphome.components.esp32 import (
|
||||
VARIANT_ESP32,
|
||||
VARIANT_ESP32C2,
|
||||
VARIANT_ESP32C3,
|
||||
VARIANT_ESP32C5,
|
||||
VARIANT_ESP32C6,
|
||||
VARIANT_ESP32C61,
|
||||
VARIANT_ESP32H2,
|
||||
VARIANT_ESP32P4,
|
||||
VARIANT_ESP32S2,
|
||||
VARIANT_ESP32S3,
|
||||
get_esp32_variant,
|
||||
)
|
||||
from esphome.components.esp32.gpio_esp32_c5 import esp32_c5_validate_lp_i2c
|
||||
from esphome.components.esp32.gpio_esp32_c6 import esp32_c6_validate_lp_i2c
|
||||
from esphome.components.esp32.gpio_esp32_p4 import esp32_p4_validate_lp_i2c
|
||||
from esphome.components.zephyr import (
|
||||
zephyr_add_overlay,
|
||||
zephyr_add_prj_conf,
|
||||
@@ -16,6 +33,7 @@ from esphome.const import (
|
||||
CONF_I2C,
|
||||
CONF_I2C_ID,
|
||||
CONF_ID,
|
||||
CONF_LOW_POWER_MODE,
|
||||
CONF_SCAN,
|
||||
CONF_SCL,
|
||||
CONF_SDA,
|
||||
@@ -40,6 +58,25 @@ IDFI2CBus = i2c_ns.class_("IDFI2CBus", InternalI2CBus, cg.Component)
|
||||
ZephyrI2CBus = i2c_ns.class_("ZephyrI2CBus", I2CBus, cg.Component)
|
||||
I2CDevice = i2c_ns.class_("I2CDevice")
|
||||
|
||||
ESP32_I2C_CAPABILITIES = {
|
||||
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/soc_caps.h
|
||||
VARIANT_ESP32: {"NUM": 2, "HP": 2},
|
||||
VARIANT_ESP32C2: {"NUM": 1, "HP": 1},
|
||||
VARIANT_ESP32C3: {"NUM": 1, "HP": 1},
|
||||
VARIANT_ESP32C5: {"NUM": 2, "HP": 1, "LP": 1},
|
||||
VARIANT_ESP32C6: {"NUM": 2, "HP": 1, "LP": 1},
|
||||
VARIANT_ESP32C61: {"NUM": 1, "HP": 1},
|
||||
VARIANT_ESP32H2: {"NUM": 2, "HP": 2},
|
||||
VARIANT_ESP32P4: {"NUM": 3, "HP": 2, "LP": 1},
|
||||
VARIANT_ESP32S2: {"NUM": 2, "HP": 2},
|
||||
VARIANT_ESP32S3: {"NUM": 2, "HP": 2},
|
||||
}
|
||||
VALIDATE_LP_I2C = {
|
||||
VARIANT_ESP32C5: esp32_c5_validate_lp_i2c,
|
||||
VARIANT_ESP32C6: esp32_c6_validate_lp_i2c,
|
||||
VARIANT_ESP32P4: esp32_p4_validate_lp_i2c,
|
||||
}
|
||||
LP_I2C_VARIANT = list(VALIDATE_LP_I2C.keys())
|
||||
|
||||
CONF_SDA_PULLUP_ENABLED = "sda_pullup_enabled"
|
||||
CONF_SCL_PULLUP_ENABLED = "scl_pullup_enabled"
|
||||
@@ -91,6 +128,13 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.positive_time_period,
|
||||
),
|
||||
cv.Optional(CONF_SCAN, default=True): cv.boolean,
|
||||
cv.Optional(CONF_LOW_POWER_MODE): cv.All(
|
||||
cv.only_on_esp32,
|
||||
esp32.only_on_variant(
|
||||
supported=LP_I2C_VARIANT, msg_prefix="Low power i2c"
|
||||
),
|
||||
cv.boolean,
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, PLATFORM_NRF52]),
|
||||
@@ -102,6 +146,31 @@ def _final_validate(config):
|
||||
full_config = fv.full_config.get()[CONF_I2C]
|
||||
if CORE.using_zephyr and len(full_config) > 1:
|
||||
raise cv.Invalid("Second i2c is not implemented on Zephyr yet")
|
||||
if CORE.using_esp_idf and get_esp32_variant() in ESP32_I2C_CAPABILITIES:
|
||||
variant = get_esp32_variant()
|
||||
max_num = ESP32_I2C_CAPABILITIES[variant]["NUM"]
|
||||
if len(full_config) > max_num:
|
||||
raise cv.Invalid(
|
||||
f"The maximum number of i2c interfaces for {variant} is {max_num}"
|
||||
)
|
||||
if variant in LP_I2C_VARIANT:
|
||||
max_lp_num = ESP32_I2C_CAPABILITIES[variant]["LP"]
|
||||
max_hp_num = ESP32_I2C_CAPABILITIES[variant]["HP"]
|
||||
lp_num = sum(
|
||||
CONF_LOW_POWER_MODE in conf and conf[CONF_LOW_POWER_MODE]
|
||||
for conf in full_config
|
||||
)
|
||||
hp_num = len(full_config) - lp_num
|
||||
if CONF_LOW_POWER_MODE in config and config[CONF_LOW_POWER_MODE]:
|
||||
VALIDATE_LP_I2C[variant](config)
|
||||
if lp_num > max_lp_num:
|
||||
raise cv.Invalid(
|
||||
f"The maximum number of low power i2c interfaces for {variant} is {max_lp_num}"
|
||||
)
|
||||
if hp_num > max_hp_num:
|
||||
raise cv.Invalid(
|
||||
f"The maximum number of high power i2c interfaces for {variant} is {max_hp_num}"
|
||||
)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||
@@ -155,6 +224,8 @@ async def to_code(config):
|
||||
cg.add(var.set_timeout(int(config[CONF_TIMEOUT].total_microseconds)))
|
||||
if CORE.using_arduino and not CORE.is_esp32:
|
||||
cg.add_library("Wire", None)
|
||||
if CONF_LOW_POWER_MODE in config:
|
||||
cg.add(var.set_lp_mode(bool(config[CONF_LOW_POWER_MODE])))
|
||||
|
||||
|
||||
def i2c_device_schema(default_address):
|
||||
|
||||
@@ -16,13 +16,10 @@ namespace i2c {
|
||||
static const char *const TAG = "i2c.idf";
|
||||
|
||||
void IDFI2CBus::setup() {
|
||||
static i2c_port_t next_port = I2C_NUM_0;
|
||||
this->port_ = next_port;
|
||||
if (this->port_ == I2C_NUM_MAX) {
|
||||
ESP_LOGE(TAG, "No more than %u buses supported", I2C_NUM_MAX);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
static i2c_port_t next_hp_port = I2C_NUM_0;
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
static i2c_port_t next_lp_port = LP_I2C_NUM_0;
|
||||
#endif
|
||||
|
||||
if (this->timeout_ > 13000) {
|
||||
ESP_LOGW(TAG, "Using max allowed timeout: 13 ms");
|
||||
@@ -31,23 +28,35 @@ void IDFI2CBus::setup() {
|
||||
|
||||
this->recover_();
|
||||
|
||||
next_port = (i2c_port_t) (next_port + 1);
|
||||
|
||||
i2c_master_bus_config_t bus_conf{};
|
||||
memset(&bus_conf, 0, sizeof(bus_conf));
|
||||
bus_conf.sda_io_num = gpio_num_t(sda_pin_);
|
||||
bus_conf.scl_io_num = gpio_num_t(scl_pin_);
|
||||
bus_conf.i2c_port = this->port_;
|
||||
bus_conf.glitch_ignore_cnt = 7;
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
if (this->port_ < SOC_HP_I2C_NUM) {
|
||||
bus_conf.clk_source = I2C_CLK_SRC_DEFAULT;
|
||||
} else {
|
||||
if (this->lp_mode_) {
|
||||
if ((next_lp_port - LP_I2C_NUM_0) == SOC_LP_I2C_NUM) {
|
||||
ESP_LOGE(TAG, "No more than %u LP buses supported", SOC_LP_I2C_NUM);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
this->port_ = next_lp_port;
|
||||
next_lp_port = (i2c_port_t) (next_lp_port + 1);
|
||||
bus_conf.lp_source_clk = LP_I2C_SCLK_DEFAULT;
|
||||
}
|
||||
#else
|
||||
bus_conf.clk_source = I2C_CLK_SRC_DEFAULT;
|
||||
} else {
|
||||
#endif
|
||||
if (next_hp_port == SOC_HP_I2C_NUM) {
|
||||
ESP_LOGE(TAG, "No more than %u HP buses supported", SOC_HP_I2C_NUM);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
this->port_ = next_hp_port;
|
||||
next_hp_port = (i2c_port_t) (next_hp_port + 1);
|
||||
bus_conf.clk_source = I2C_CLK_SRC_DEFAULT;
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
}
|
||||
#endif
|
||||
bus_conf.i2c_port = this->port_;
|
||||
bus_conf.flags.enable_internal_pullup = sda_pullup_enabled_ || scl_pullup_enabled_;
|
||||
esp_err_t err = i2c_new_master_bus(&bus_conf, &this->bus_);
|
||||
if (err != ESP_OK) {
|
||||
|
||||
@@ -30,6 +30,9 @@ class IDFI2CBus : public InternalI2CBus, public Component {
|
||||
void set_scl_pullup_enabled(bool scl_pullup_enabled) { this->scl_pullup_enabled_ = scl_pullup_enabled; }
|
||||
void set_frequency(uint32_t frequency) { this->frequency_ = frequency; }
|
||||
void set_timeout(uint32_t timeout) { this->timeout_ = timeout; }
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
void set_lp_mode(bool lp_mode) { this->lp_mode_ = lp_mode; }
|
||||
#endif
|
||||
|
||||
int get_port() const override { return this->port_; }
|
||||
|
||||
@@ -48,6 +51,9 @@ class IDFI2CBus : public InternalI2CBus, public Component {
|
||||
uint32_t frequency_{};
|
||||
uint32_t timeout_ = 0;
|
||||
bool initialized_ = false;
|
||||
#if SOC_LP_I2C_SUPPORTED
|
||||
bool lp_mode_ = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace i2c
|
||||
|
||||
@@ -559,6 +559,7 @@ CONF_LOGS = "logs"
|
||||
CONF_LONGITUDE = "longitude"
|
||||
CONF_LOOP_TIME = "loop_time"
|
||||
CONF_LOW = "low"
|
||||
CONF_LOW_POWER_MODE = "low_power_mode"
|
||||
CONF_LOW_VOLTAGE_REFERENCE = "low_voltage_reference"
|
||||
CONF_MAC_ADDRESS = "mac_address"
|
||||
CONF_MAGNITUDE = "magnitude"
|
||||
|
||||
Reference in New Issue
Block a user