mirror of
https://github.com/esphome/esphome.git
synced 2026-06-05 01:52:47 +08:00
[i2c] Fix RP2040 I2C bus selection based on pin assignment (#14745)
This commit is contained in:
@@ -93,11 +93,31 @@ def _bus_declare_type(value):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
def _rp2040_i2c_controller(pin):
|
||||||
|
"""Return the I2C controller number (0 or 1) for a given RP2040/RP2350 GPIO pin.
|
||||||
|
|
||||||
|
See RP2040 datasheet Table 2 (section 1.4.3, "GPIO Functions"):
|
||||||
|
https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
|
||||||
|
See RP2350 datasheet Table 7 (section 9.4, "Function Select"):
|
||||||
|
https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf
|
||||||
|
"""
|
||||||
|
return (pin // 2) % 2
|
||||||
|
|
||||||
|
|
||||||
def validate_config(config):
|
def validate_config(config):
|
||||||
if CORE.is_esp32:
|
if CORE.is_esp32:
|
||||||
return cv.require_framework_version(
|
return cv.require_framework_version(
|
||||||
esp_idf=cv.Version(5, 4, 2), esp32_arduino=cv.Version(3, 2, 1)
|
esp_idf=cv.Version(5, 4, 2), esp32_arduino=cv.Version(3, 2, 1)
|
||||||
)(config)
|
)(config)
|
||||||
|
if CORE.is_rp2040:
|
||||||
|
sda_controller = _rp2040_i2c_controller(config[CONF_SDA])
|
||||||
|
scl_controller = _rp2040_i2c_controller(config[CONF_SCL])
|
||||||
|
if sda_controller != scl_controller:
|
||||||
|
raise cv.Invalid(
|
||||||
|
f"SDA pin GPIO{config[CONF_SDA]} is on I2C{sda_controller} but "
|
||||||
|
f"SCL pin GPIO{config[CONF_SCL]} is on I2C{scl_controller}. "
|
||||||
|
f"Both pins must be on the same I2C controller."
|
||||||
|
)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
@@ -146,6 +166,23 @@ 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.is_rp2040:
|
||||||
|
if len(full_config) > 2:
|
||||||
|
raise cv.Invalid(
|
||||||
|
"The maximum number of I2C interfaces for RP2040/RP2350 is 2"
|
||||||
|
)
|
||||||
|
if len(full_config) > 1:
|
||||||
|
controllers = [
|
||||||
|
_rp2040_i2c_controller(conf[CONF_SDA]) for conf in full_config
|
||||||
|
]
|
||||||
|
if len(set(controllers)) != len(controllers):
|
||||||
|
raise cv.Invalid(
|
||||||
|
"Multiple I2C buses are configured to use the same I2C controller. "
|
||||||
|
"Each bus must use pins on a different controller. "
|
||||||
|
"The I2C controller is determined by (gpio / 2) % 2: "
|
||||||
|
"even pin pairs (0-1, 4-5, 8-9, ...) use I2C0, "
|
||||||
|
"odd pin pairs (2-3, 6-7, 10-11, ...) use I2C1."
|
||||||
|
)
|
||||||
if CORE.is_esp32 and get_esp32_variant() in ESP32_I2C_CAPABILITIES:
|
if CORE.is_esp32 and get_esp32_variant() in ESP32_I2C_CAPABILITIES:
|
||||||
variant = get_esp32_variant()
|
variant = get_esp32_variant()
|
||||||
max_num = ESP32_I2C_CAPABILITIES[variant]["NUM"]
|
max_num = ESP32_I2C_CAPABILITIES[variant]["NUM"]
|
||||||
|
|||||||
@@ -20,12 +20,14 @@ void ArduinoI2CBus::setup() {
|
|||||||
#if defined(USE_ESP8266)
|
#if defined(USE_ESP8266)
|
||||||
wire_ = new TwoWire(); // NOLINT(cppcoreguidelines-owning-memory)
|
wire_ = new TwoWire(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||||
#elif defined(USE_RP2040)
|
#elif defined(USE_RP2040)
|
||||||
static bool first = true;
|
// Select Wire instance based on pin assignment, not definition order.
|
||||||
if (first) {
|
// I2C controller = (gpio / 2) % 2: even pairs (0-1,4-5,...) → I2C0, odd pairs (2-3,6-7,...) → I2C1
|
||||||
|
// RP2040 datasheet Table 2 (section 1.4.3): https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf
|
||||||
|
// RP2350 datasheet Table 7 (section 9.4): https://datasheets.raspberrypi.com/rp2350/rp2350-datasheet.pdf
|
||||||
|
if ((this->sda_pin_ / 2) % 2 == 0) {
|
||||||
wire_ = &Wire;
|
wire_ = &Wire;
|
||||||
first = false;
|
|
||||||
} else {
|
} else {
|
||||||
wire_ = &Wire1; // NOLINT(cppcoreguidelines-owning-memory)
|
wire_ = &Wire1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user