[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 logging
|
||||||
|
|
||||||
import esphome.config_validation as cv
|
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
|
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 = {
|
_ESP32C5_SPI_PSRAM_PINS = {
|
||||||
16: "SPICS0",
|
16: "SPICS0",
|
||||||
17: "SPIQ",
|
17: "SPIQ",
|
||||||
@@ -43,3 +46,13 @@ def esp32_c5_validate_supports(value):
|
|||||||
|
|
||||||
check_strapping_pin(value, _ESP32C5_STRAPPING_PINS, _LOGGER)
|
check_strapping_pin(value, _ESP32C5_STRAPPING_PINS, _LOGGER)
|
||||||
return value
|
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 logging
|
||||||
|
|
||||||
import esphome.config_validation as cv
|
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
|
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 = {
|
_ESP32C6_SPI_PSRAM_PINS = {
|
||||||
24: "SPICS0",
|
24: "SPICS0",
|
||||||
25: "SPIQ",
|
25: "SPIQ",
|
||||||
@@ -43,3 +46,13 @@ def esp32_c6_validate_supports(value):
|
|||||||
|
|
||||||
check_strapping_pin(value, _ESP32C6_STRAPPING_PINS, _LOGGER)
|
check_strapping_pin(value, _ESP32C6_STRAPPING_PINS, _LOGGER)
|
||||||
return value
|
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 logging
|
||||||
|
|
||||||
import esphome.config_validation as cv
|
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
|
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_USB_JTAG_PINS = {24, 25}
|
||||||
|
|
||||||
_ESP32P4_STRAPPING_PINS = {34, 35, 36, 37, 38}
|
_ESP32P4_STRAPPING_PINS = {34, 35, 36, 37, 38}
|
||||||
@@ -36,3 +39,14 @@ def esp32_p4_validate_supports(value):
|
|||||||
pass
|
pass
|
||||||
check_strapping_pin(value, _ESP32P4_STRAPPING_PINS, _LOGGER)
|
check_strapping_pin(value, _ESP32P4_STRAPPING_PINS, _LOGGER)
|
||||||
return value
|
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
|
from esphome import pins
|
||||||
import esphome.codegen as cg
|
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 (
|
from esphome.components.zephyr import (
|
||||||
zephyr_add_overlay,
|
zephyr_add_overlay,
|
||||||
zephyr_add_prj_conf,
|
zephyr_add_prj_conf,
|
||||||
@@ -16,6 +33,7 @@ from esphome.const import (
|
|||||||
CONF_I2C,
|
CONF_I2C,
|
||||||
CONF_I2C_ID,
|
CONF_I2C_ID,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
|
CONF_LOW_POWER_MODE,
|
||||||
CONF_SCAN,
|
CONF_SCAN,
|
||||||
CONF_SCL,
|
CONF_SCL,
|
||||||
CONF_SDA,
|
CONF_SDA,
|
||||||
@@ -40,6 +58,25 @@ IDFI2CBus = i2c_ns.class_("IDFI2CBus", InternalI2CBus, cg.Component)
|
|||||||
ZephyrI2CBus = i2c_ns.class_("ZephyrI2CBus", I2CBus, cg.Component)
|
ZephyrI2CBus = i2c_ns.class_("ZephyrI2CBus", I2CBus, cg.Component)
|
||||||
I2CDevice = i2c_ns.class_("I2CDevice")
|
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_SDA_PULLUP_ENABLED = "sda_pullup_enabled"
|
||||||
CONF_SCL_PULLUP_ENABLED = "scl_pullup_enabled"
|
CONF_SCL_PULLUP_ENABLED = "scl_pullup_enabled"
|
||||||
@@ -91,6 +128,13 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
cv.positive_time_period,
|
cv.positive_time_period,
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_SCAN, default=True): cv.boolean,
|
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),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040, PLATFORM_NRF52]),
|
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]
|
full_config = fv.full_config.get()[CONF_I2C]
|
||||||
if CORE.using_zephyr and len(full_config) > 1:
|
if CORE.using_zephyr and len(full_config) > 1:
|
||||||
raise cv.Invalid("Second i2c is not implemented on Zephyr yet")
|
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
|
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)))
|
cg.add(var.set_timeout(int(config[CONF_TIMEOUT].total_microseconds)))
|
||||||
if CORE.using_arduino and not CORE.is_esp32:
|
if CORE.using_arduino and not CORE.is_esp32:
|
||||||
cg.add_library("Wire", None)
|
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):
|
def i2c_device_schema(default_address):
|
||||||
|
|||||||
@@ -16,13 +16,10 @@ namespace i2c {
|
|||||||
static const char *const TAG = "i2c.idf";
|
static const char *const TAG = "i2c.idf";
|
||||||
|
|
||||||
void IDFI2CBus::setup() {
|
void IDFI2CBus::setup() {
|
||||||
static i2c_port_t next_port = I2C_NUM_0;
|
static i2c_port_t next_hp_port = I2C_NUM_0;
|
||||||
this->port_ = next_port;
|
#if SOC_LP_I2C_SUPPORTED
|
||||||
if (this->port_ == I2C_NUM_MAX) {
|
static i2c_port_t next_lp_port = LP_I2C_NUM_0;
|
||||||
ESP_LOGE(TAG, "No more than %u buses supported", I2C_NUM_MAX);
|
#endif
|
||||||
this->mark_failed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->timeout_ > 13000) {
|
if (this->timeout_ > 13000) {
|
||||||
ESP_LOGW(TAG, "Using max allowed timeout: 13 ms");
|
ESP_LOGW(TAG, "Using max allowed timeout: 13 ms");
|
||||||
@@ -31,23 +28,35 @@ void IDFI2CBus::setup() {
|
|||||||
|
|
||||||
this->recover_();
|
this->recover_();
|
||||||
|
|
||||||
next_port = (i2c_port_t) (next_port + 1);
|
|
||||||
|
|
||||||
i2c_master_bus_config_t bus_conf{};
|
i2c_master_bus_config_t bus_conf{};
|
||||||
memset(&bus_conf, 0, sizeof(bus_conf));
|
memset(&bus_conf, 0, sizeof(bus_conf));
|
||||||
bus_conf.sda_io_num = gpio_num_t(sda_pin_);
|
bus_conf.sda_io_num = gpio_num_t(sda_pin_);
|
||||||
bus_conf.scl_io_num = gpio_num_t(scl_pin_);
|
bus_conf.scl_io_num = gpio_num_t(scl_pin_);
|
||||||
bus_conf.i2c_port = this->port_;
|
|
||||||
bus_conf.glitch_ignore_cnt = 7;
|
bus_conf.glitch_ignore_cnt = 7;
|
||||||
#if SOC_LP_I2C_SUPPORTED
|
#if SOC_LP_I2C_SUPPORTED
|
||||||
if (this->port_ < SOC_HP_I2C_NUM) {
|
if (this->lp_mode_) {
|
||||||
bus_conf.clk_source = I2C_CLK_SRC_DEFAULT;
|
if ((next_lp_port - LP_I2C_NUM_0) == SOC_LP_I2C_NUM) {
|
||||||
} else {
|
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;
|
bus_conf.lp_source_clk = LP_I2C_SCLK_DEFAULT;
|
||||||
}
|
} else {
|
||||||
#else
|
|
||||||
bus_conf.clk_source = I2C_CLK_SRC_DEFAULT;
|
|
||||||
#endif
|
#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_;
|
bus_conf.flags.enable_internal_pullup = sda_pullup_enabled_ || scl_pullup_enabled_;
|
||||||
esp_err_t err = i2c_new_master_bus(&bus_conf, &this->bus_);
|
esp_err_t err = i2c_new_master_bus(&bus_conf, &this->bus_);
|
||||||
if (err != ESP_OK) {
|
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_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_frequency(uint32_t frequency) { this->frequency_ = frequency; }
|
||||||
void set_timeout(uint32_t timeout) { this->timeout_ = timeout; }
|
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_; }
|
int get_port() const override { return this->port_; }
|
||||||
|
|
||||||
@@ -48,6 +51,9 @@ class IDFI2CBus : public InternalI2CBus, public Component {
|
|||||||
uint32_t frequency_{};
|
uint32_t frequency_{};
|
||||||
uint32_t timeout_ = 0;
|
uint32_t timeout_ = 0;
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
|
#if SOC_LP_I2C_SUPPORTED
|
||||||
|
bool lp_mode_ = false;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace i2c
|
} // namespace i2c
|
||||||
|
|||||||
@@ -559,6 +559,7 @@ CONF_LOGS = "logs"
|
|||||||
CONF_LONGITUDE = "longitude"
|
CONF_LONGITUDE = "longitude"
|
||||||
CONF_LOOP_TIME = "loop_time"
|
CONF_LOOP_TIME = "loop_time"
|
||||||
CONF_LOW = "low"
|
CONF_LOW = "low"
|
||||||
|
CONF_LOW_POWER_MODE = "low_power_mode"
|
||||||
CONF_LOW_VOLTAGE_REFERENCE = "low_voltage_reference"
|
CONF_LOW_VOLTAGE_REFERENCE = "low_voltage_reference"
|
||||||
CONF_MAC_ADDRESS = "mac_address"
|
CONF_MAC_ADDRESS = "mac_address"
|
||||||
CONF_MAGNITUDE = "magnitude"
|
CONF_MAGNITUDE = "magnitude"
|
||||||
|
|||||||
Reference in New Issue
Block a user