I3C – Improved Inter-Integrated Circuit
I3C is MIPI Alliance's next-generation two-wire serial bus — designed to replace I2C in modern sensor-heavy systems. It reuses the same SDA/SCL pins but delivers up to 125× more bandwidth, adds dynamic addressing, in-band interrupts, hot-join, and power management — all without breaking backward compatibility with existing I2C devices.
Overview
I3C (Improved Inter-Integrated Circuit) was published by the MIPI Alliance in 2016 to address the growing demands of mobile sensors, IoT devices, and automotive electronics. As chips became densely packed with accelerometers, gyroscopes, proximity sensors, and environmental monitors, the old I2C bus hit its limits: 400 kHz was too slow for continuous sensor streams, the interrupt model required extra GPIO pins, and static 7-bit addresses collided across large sensor arrays.
I3C solves all of these by staying on just two wires — SDA and SCL — the same pins as I2C. Legacy I2C devices can coexist on the same bus. The improvements are fundamental: the bus switches from I2C's open-drain topology to a push-pull drive, enabling much higher clock rates; addresses are assigned dynamically at boot rather than hard-wired in hardware; targets can signal the controller without a separate interrupt pin (In-Band Interrupt); and new devices can join the bus at any time (Hot-Join) without resetting the system.
I3C is backward compatible: An I3C bus can host legacy I2C devices alongside I3C targets. The controller identifies legacy devices by their static I2C addresses and uses open-drain communication with them, while using faster push-pull for I3C-native targets.
Signals & Bus Structure
| Signal | Full Name | Direction | Description |
|---|---|---|---|
| SDA | Serial Data | Bidirectional | Carries addresses, data bytes, CCCs, T-bits, and IBI requests. Drive type depends on mode: open-drain during DAA and for I2C devices; push-pull for normal I3C transfers. |
| SCL | Serial Clock | Controller → Target | Push-pull clock generated by the Active Controller. Unlike I2C, targets cannot stretch the clock in SDR mode (no clock stretching in I3C SDR). |
Push-pull vs open-drain
I2C requires open-drain drivers and pull-up resistors because multiple devices share the bus and must not fight each other. This limits speed — the RC time constant of the pull-up limits how fast the line can rise.
I3C replaces open-drain with push-pull for normal transfers: the Active Controller actively drives the line both HIGH and LOW, giving fast edges and eliminating the pull-up bottleneck. Targets also drive push-pull during data phases. Pull-up resistors are still present (typically 1–2 kΩ) but serve only to hold the bus HIGH when idle, not to limit speed.
Exception: During Dynamic Address Assignment (DAA) and arbitration, I3C devices fall back to open-drain drive so that multiple targets can simultaneously respond without bus contention. Legacy I2C devices always communicate in open-drain mode.
Bus Roles
I3C deliberately moved away from "master/slave" language. The four roles on an I3C bus are:
| Role | Description |
|---|---|
| Active Controller | Owns the bus — initiates all transactions, drives SCL, runs DAA, manages the target address table. There is exactly one Active Controller at any time (typically the application processor or MCU). |
| Secondary Controller | An I3C-capable device that can take over as Active Controller if the primary requests a handoff (GETACCMST CCC). Used in multi-controller systems for redundancy or power management. |
| I3C Target | Responds to its dynamic address, sends IBI requests, and can participate in HDR transfers. Most sensors on an I3C bus are I3C Targets. |
| Legacy I2C Target | A pre-existing I2C device on the bus. Uses its static 7-bit I2C address, communicates in open-drain mode only, cannot use IBI, DAA, or any I3C feature. |
Device identification: Every I3C target has a 48-bit Provisional ID (PID) — a factory-programmed unique identifier consisting of a MIPI Manufacturer ID, Part ID, and Instance ID. The controller reads this during ENTDAA to distinguish devices and build the address table.
Dynamic Address Assignment (ENTDAA)
In I2C, every device has a fixed 7-bit address hard-wired in silicon or set by address pins. Address collisions are the designer's problem to solve. I3C eliminates this entirely: devices start with no address. The Active Controller discovers and assigns addresses at startup using the ENTDAA (Enter Dynamic Address Assignment) procedure.
What goes into a Provisional ID (PID)?
Before DAA, each I3C target has a factory-programmed 48-bit PID plus two 8-bit registers:
| Field | Size | Description |
|---|---|---|
| PID[47:33] | 15 bits | MIPI Manufacturer ID — uniquely identifies the chip vendor |
| PID[32] | 1 bit | Part ID type (0 = random, 1 = fixed) |
| PID[31:16] | 16 bits | Part ID — identifies the specific chip model |
| PID[15:12] | 4 bits | Instance ID — distinguishes identical chips on the same bus |
| PID[11:0] | 12 bits | Reserved / vendor defined |
| BCR | 8 bits | Bus Characteristics Register — IBI capable? HDR capable? Controller capable? Max speed. |
| DCR | 8 bits | Device Characteristics Register — device class code (e.g. accelerometer, temperature sensor) |
ENTDAA step-by-step
0x7E + Write + T-bit, followed by the ENTDAA command byte. All unclaimed I3C targets enter DAA mode.SETDASA for legacy I2C devices: The controller uses the SETDASA (Set Dynamic Address from Static Address) CCC to assign a dynamic address to a legacy I2C device. The controller already knows the I2C static address (from the design), so it directly maps it to a dynamic address without the ENTDAA negotiation.
Common Command Codes (CCC)
Common Command Codes are a set of standardized commands the controller sends to configure and query targets. They are the I3C equivalent of I2C "reserved addresses" but far more structured. CCCs can be Broadcast (to all targets at once) or Direct (to a single target).
Broadcast CCC
A Broadcast CCC uses the reserved address 0x7E to reach every I3C target simultaneously. The controller sends a single command byte that all targets execute.
Direct CCC
A Direct CCC first broadcasts the command (using 0x7E), then issues a second frame to a specific target's dynamic address to read or write data associated with that command.
Common CCC examples
| CCC Name | Type | Purpose |
|---|---|---|
| ENTDAA | Broadcast | Enter Dynamic Address Assignment — triggers the DAA procedure |
| SETDASA | Direct | Set Dynamic Address from Static Address (for legacy I2C devices) |
| RSTDAA | Broadcast | Reset Dynamic Addresses — all targets lose their dynamic addresses |
| DISEC | Broadcast | Disable Events — turns off IBI, controller-role requests, or hot-join notifications |
| ENEC | Broadcast | Enable Events — re-enables IBI, hot-join, or controller-role requests |
| GETPID | Direct | Get Provisional ID — reads the 48-bit PID from a specific target |
| GETBCR | Direct | Get Bus Characteristics Register — reads max speed, IBI capability, etc. |
| GETDCR | Direct | Get Device Characteristics Register — reads device class code |
| SETMWL | Direct | Set Max Write Length — tells target the max bytes per private write |
| GETMRL | Direct | Get Max Read Length — queries how many bytes target can send per private read |
| GETACCMST | Direct | Get Accept Controller Role — hands off Active Controller role to a Secondary Controller |
Private Transactions
A Private Transfer is a normal read or write addressed to one specific target by its dynamic address. It is the I3C equivalent of a standard I2C transaction — the payload is application-defined (register data, sensor readings, configuration bytes).
The key difference from I2C is the T-bit (Transition Bit) that follows each data byte. In I2C, the controller acknowledges each data byte during a read. In I3C SDR, the target drives the T-bit after each byte it sends. T=0 means "more data follows", T=1 means "this is the last byte" (analogous to NACK in I2C reads).
Private Write
The controller drives all data bytes. The target drives T-bits to indicate whether it can accept more data (T=0) or if there was an issue / it is done (T=1).
Private Read
The target drives all data bytes and T-bits. T=1 on the final byte signals end of transfer — the controller does not need to send a NACK like it would in I2C.
No repeated START for register reads? In I2C, a combined transaction (write register address, Repeated START, read data) is the standard way to read a register. In I3C, the same two-frame pattern works, but many I3C sensors accept the register address within a single Private Write followed immediately by a Private Read — reducing overhead.
In-Band Interrupt (IBI)
In I2C, a target that wants to notify the controller of an event (data ready, threshold exceeded, fault) needs a dedicated GPIO interrupt pin — a separate wire outside the I2C bus. Multiply this across ten sensors and you've used ten GPIO lines.
I3C eliminates all of these with In-Band Interrupts. A target can signal an interrupt on the SDA line itself without any extra pins.
How IBI works
IBI must be enabled: By default, IBI is disabled on each target after DAA. The controller uses the ENEC (Enable Events) broadcast CCC to enable IBI globally, or a direct ENEC to enable it per target.
Hot-Join
Hot-Join allows an I3C device to connect to — or power up on — an active bus without disrupting ongoing transactions. This is important in systems where peripheral modules are inserted or enabled after system startup (think sensor pods, expansion boards, or dynamically powered sensor islands).
Hot-Join sequence
0x02 to identify itself as a new device, not an interrupt.0x02 as a Hot-Join indicator, acknowledges, and initiates a new ENTDAA procedure to assign the new device a dynamic address.Hot-Join must be enabled: Like IBI, Hot-Join is disabled by default after DAA. The controller uses ENEC to enable it. If disabled, the controller NACKs the Hot-Join request and the new device cannot join until explicitly enabled.
Transfer Modes
I3C defines multiple transfer modes to serve different performance and power trade-offs. All I3C devices must support SDR; HDR modes are optional.
| Mode | Full Name | Max Speed | Key Feature |
|---|---|---|---|
| I2C FM | I2C Fast Mode (legacy) | 400 kHz | Open-drain, backward compatible. Used with legacy I2C devices on I3C bus. |
| I2C FM+ | I2C Fast Mode Plus (legacy) | 1 MHz | Open-drain at higher speed. Requires stronger drivers. |
| SDR | Single Data Rate | 12.5 Mbps | Standard I3C mode. Push-pull, data sampled on one clock edge. All I3C devices support this. |
| HDR-DDR | High Data Rate – Double Data Rate | 25 Mbps | Data sent on both rising and falling clock edges. Optional. Doubles SDR throughput. Indicated via HDR-DDR entry CCC. |
| HDR-TSP | HDR – Ternary Symbol Pure-bus | 37.5 Mbps | Three-symbol encoding on SDA for even higher bandwidth. Rarely used in practice. |
| HDR-TSL | HDR – Ternary Symbol Legacy-inclusive | 37.5 Mbps | Like TSP but maintains I2C legacy device compatibility. |
HDR-DDR: how it doubles throughput
In SDR mode, a data bit is clocked in on the rising edge of SCL only — each clock cycle carries one bit. In HDR-DDR mode, valid data is sampled on both rising and falling edges, effectively doubling the data rate without increasing the clock frequency. At 12.5 MHz SCL, SDR achieves 12.5 Mbps; HDR-DDR achieves 25 Mbps.
The controller signals entry into HDR-DDR using the ENTHDR0 CCC. Only targets whose BCR indicates HDR capability participate. The mode ends when the controller sends a specific HDR Exit Pattern (a sequence of transitions that cannot occur in normal data).
No clock stretching in SDR: Unlike I2C, I3C SDR does not support clock stretching. Targets must respond within a strict timing budget. This is intentional — it makes I3C timing deterministic and enables higher-speed operation. If a target needs more time, it uses the T-bit mechanism instead.
I3C vs I2C vs SPI
| Feature | I3C | I2C | SPI |
|---|---|---|---|
| Wires | 2 (SDA + SCL) | 2 (SDA + SCL) | 4+ (SCLK, MOSI, MISO, CS per device) |
| Max Speed | 25 Mbps (HDR-DDR) | 3.4 MHz (High-speed) | 50–100+ MHz |
| Bus Type | Push-pull (I3C) + open-drain (I2C fallback) | Open-drain with pull-ups | Push-pull (full-duplex) |
| Addressing | 7-bit dynamic (DAA) | 7-bit static (hardware) | No addressing — CS_N per device |
| Multi-drop | Yes (many targets) | Yes (many slaves) | Yes, but needs 1 CS wire per device |
| Interrupts | In-Band (IBI) — no extra pins | Requires separate GPIO per device | Requires separate GPIO per device |
| Hot-plug | Yes (Hot-Join) | No | No |
| Backward compat. | Yes — I2C devices work on I3C bus | N/A | N/A |
| Protocol overhead | Low (DAA pre-assigns, T-bit efficient) | Medium (START + addr + ACK + STOP) | Minimal (CS asserted, continuous data) |
| Duplex | Half-duplex | Half-duplex | Full-duplex |
| Typical use | Modern sensors, mobile (MEMS, IMU, cameras) | Sensors, EEPROMs, RTCs, displays | Flash memory, ADCs, DACs, displays |
Interview Q&A
0x02 to identify the request. The controller then runs a targeted ENTDAA to assign the new device a dynamic address — all without resetting the bus or disturbing other devices.
0x7E to send a command to all I3C targets simultaneously — for example, ENTDAA (start DAA) or DISEC (disable events). All targets execute the same command. A Direct CCC also starts with the 0x7E address and command byte, but then issues a second frame to a specific target's dynamic address to read or write data for that command individually — for example, GETBCR (read BCR from one specific target) or SETMWL (set max write length for one target). Broadcast = all devices, Direct = one device.
SETDASA or SETAASA CCCs). Limitations: legacy devices cannot use IBI (they need a separate GPIO), cannot participate in HDR modes, do not have a PID, and cannot perform Hot-Join. Also, the pull-up resistors must be sized to work with the open-drain legacy devices, which may limit maximum I3C SDR speed slightly. The presence of I2C devices also prevents using reserved I2C addresses as I3C dynamic addresses.