Understanding I2C Communication
I2C (Inter-Integrated Circuit, also written as I²C) is one of the most popular communication protocols used by microcontrollers to talk to sensors, displays, and other chips. It's a serial, half-duplex, and synchronous interface.
What Makes I2C Special?
The I2C Bus
The I2C bus uses just two wires shared by all connected devices:
- SCL (Serial Clock Line): Carries the clock signal from the controller
- SDA (Serial Data Line): Transfers data in both directions
Controller and Target Model
I2C uses a controller-target model (formerly master-slave). The controller initiates communication and provides the clock signal. The target responds to the controller's commands. In typical embedded projects, the microcontroller (Pico) acts as the controller, and connected devices like displays or sensors act as targets.
I2C Addresses
Each I2C target device has a 7-bit or 10-bit address (7-bit is most common). This allows up to 128 possible addresses. Many devices have a fixed address defined by the manufacturer, but others allow configuring the lower bits using pins or jumpers.
Speed Modes
| Mode | Speed |
|---|---|
| Standard | Up to 100 kbps |
| Fast | Up to 400 kbps |
| Fast Mode Plus | Up to 1 Mbps |
| High-Speed | Up to 3.4 Mbps |
I2C on the Raspberry Pi Pico 2
The RP2350 has two separate I2C controllers (I2C0 and I2C1) that can operate simultaneously. Both controllers support multiple pin options for SDA and SCL:
| Controller | GPIO Pins |
|---|---|
| I2C0 - SDA | GP0, GP4, GP8, GP12, GP16, GP20 |
| I2C0 - SCL | GP1, GP5, GP9, GP13, GP17, GP21 |
| I2C1 - SDA | GP2, GP6, GP10, GP14, GP18, GP26 |
| I2C1 - SCL | GP3, GP7, GP11, GP15, GP19, GP27 |
Using I2C with Embassy
Setting up I2C in Embassy is straightforward. Here's a basic example:
// Bind I2C interrupt
bind_interrupts!(struct Irqs {
I2C0_IRQ => i2c::InterruptHandler<I2C0>;
});
// Initialize I2C
let sda = p.PIN_16;
let scl = p.PIN_17;
let mut config = I2cConfig::default();
config.frequency = 400_000; // 400kHz
let i2c = I2c::new_async(
p.I2C0,
scl,
sda,
Irqs,
config,
);Why Use I2C?
I2C is ideal when you want to connect multiple devices using just two wires. It's well-suited for applications where speed is not critical but wiring simplicity is important. The embedded-hal crate provides standard I2C traits, and platform HALs handle the low-level details.