mirror of
https://github.com/esphome/esphome.git
synced 2026-03-23 22:14:50 +08:00
[i2c] Fix RP2040 I2C bus selection based on pin assignment (#14745)
This commit is contained in:
committed by
Jesse Hills
parent
b0447dc521
commit
039efdb02a
@@ -93,11 +93,31 @@ def _bus_declare_type(value):
|
||||
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):
|
||||
if CORE.is_esp32:
|
||||
return cv.require_framework_version(
|
||||
esp_idf=cv.Version(5, 4, 2), esp32_arduino=cv.Version(3, 2, 1)
|
||||
)(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
|
||||
|
||||
|
||||
@@ -146,6 +166,23 @@ 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.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:
|
||||
variant = get_esp32_variant()
|
||||
max_num = ESP32_I2C_CAPABILITIES[variant]["NUM"]
|
||||
|
||||
@@ -20,12 +20,14 @@ void ArduinoI2CBus::setup() {
|
||||
#if defined(USE_ESP8266)
|
||||
wire_ = new TwoWire(); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
#elif defined(USE_RP2040)
|
||||
static bool first = true;
|
||||
if (first) {
|
||||
// Select Wire instance based on pin assignment, not definition order.
|
||||
// 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;
|
||||
first = false;
|
||||
} else {
|
||||
wire_ = &Wire1; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
wire_ = &Wire1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user