Off-Chip Protocol

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.

Wires — 2 (SDA + SCL)
Type — Synchronous, half-duplex (push-pull)
Speed (SDR) — up to 12.5 Mbps
Speed (HDR-DDR) — up to 25 Mbps
Addressing — 7-bit dynamic (DAA)
Standard — MIPI I3C v1.0 (2016)

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

SignalFull NameDirectionDescription
SDASerial DataBidirectionalCarries 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.
SCLSerial ClockController → TargetPush-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.

VCC VCC 1kΩ 1kΩ SDA SCL Controller (push-pull) I3C Target 0x0A I3C Target 0x0B Legacy I2C (open-drain) 0x48 Push-pull I3C targets and legacy open-drain I2C devices coexist on the same two wires.

Bus Roles

I3C deliberately moved away from "master/slave" language. The four roles on an I3C bus are:

RoleDescription
Active ControllerOwns 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 ControllerAn 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 TargetResponds to its dynamic address, sends IBI requests, and can participate in HDR transfers. Most sensors on an I3C bus are I3C Targets.
Legacy I2C TargetA 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:

FieldSizeDescription
PID[47:33]15 bitsMIPI Manufacturer ID — uniquely identifies the chip vendor
PID[32]1 bitPart ID type (0 = random, 1 = fixed)
PID[31:16]16 bitsPart ID — identifies the specific chip model
PID[15:12]4 bitsInstance ID — distinguishes identical chips on the same bus
PID[11:0]12 bitsReserved / vendor defined
BCR8 bitsBus Characteristics Register — IBI capable? HDR capable? Controller capable? Max speed.
DCR8 bitsDevice Characteristics Register — device class code (e.g. accelerometer, temperature sensor)

ENTDAA step-by-step

1
Controller broadcasts ENTDAA CCC — Sends a START + broadcast address 0x7E + Write + T-bit, followed by the ENTDAA command byte. All unclaimed I3C targets enter DAA mode.
2
Targets arbitrate on SDA — Each unclaimed target begins driving its PID MSB onto SDA. Devices with a 0 on that bit override devices with a 1 (open-drain wired-AND). Losing targets detect the mismatch and go silent. This continues bit by bit until only one target's bits dominate.
3
Winning target sends its full 64-bit identity — Transmits its 48-bit PID + 8-bit BCR + 8-bit DCR. No other target is driving the bus at this point.
4
Controller assigns a 7-bit dynamic address — Picks an address from the available pool (avoids reserved and I2C addresses) and sends it with a parity bit.
5
Target acknowledges and claims its address — The winning target drives T=0 to confirm receipt. It now has a valid dynamic address and exits DAA mode.
6
Loop repeats — Steps 2–5 repeat until all unclaimed targets have addresses (no target pulls SDA LOW = no more unclaimed devices). Controller sends STOP.

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.

S
0x7E
Broadcast
W
ACK
CCC Byte
e.g. DISEC
T
P
Controller drives
Target drives
Bus condition

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.

S
0x7E
W
ACK
CCC Byte
e.g. GETMRL
T
Sr
DA+R
ACK
Data Byte
target → ctrl
T
P

Common CCC examples

CCC NameTypePurpose
ENTDAABroadcastEnter Dynamic Address Assignment — triggers the DAA procedure
SETDASADirectSet Dynamic Address from Static Address (for legacy I2C devices)
RSTDAABroadcastReset Dynamic Addresses — all targets lose their dynamic addresses
DISECBroadcastDisable Events — turns off IBI, controller-role requests, or hot-join notifications
ENECBroadcastEnable Events — re-enables IBI, hot-join, or controller-role requests
GETPIDDirectGet Provisional ID — reads the 48-bit PID from a specific target
GETBCRDirectGet Bus Characteristics Register — reads max speed, IBI capability, etc.
GETDCRDirectGet Device Characteristics Register — reads device class code
SETMWLDirectSet Max Write Length — tells target the max bytes per private write
GETMRLDirectGet Max Read Length — queries how many bytes target can send per private read
GETACCMSTDirectGet 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

S
DA
7-bit
W
ACK
Byte 0
T=0
continue
Byte 1
T=0
Byte N
T=1
last
P

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

S
DA
7-bit
R
ACK
Byte 0
T=0
more data
Byte 1
T=0
Byte N
T=1
last byte
P

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

1
Bus is idle — SCL and SDA are HIGH. The controller is not currently driving a transaction.
2
Target pulls SDA LOW — During a defined arbitration window after a STOP, the IBI-capable target pulls SDA LOW before the controller issues a new START. This looks like a START condition initiated by the target.
3
Controller detects IBI — The controller sees SDA go LOW before it initiated a START, recognizing it as an IBI request. It then generates SCL clocks to arbitrate.
4
Target sends its dynamic address — The requesting target drives its 7-bit dynamic address + RnW=1 onto SDA. If multiple targets request IBI simultaneously, open-drain arbitration determines the winner (lower address wins).
5
Controller ACKs or NACKs — If ACK: the target may send an optional IBI payload (up to 64 bytes of interrupt data). If NACK: the IBI is deferred. The controller handles the interrupt at its convenience.
SCL SDA Idle IBI Request Controller ACKs IBI payload Target pulls SDA LOW addr+R=1 ACK payload

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

1
New device powers up — It has no dynamic address. It watches the bus for an idle state (both SDA and SCL HIGH for long enough).
2
Device signals Hot-Join request — Pulls SDA LOW while SCL is HIGH (similar to IBI mechanism). It uses the reserved Hot-Join address 0x02 to identify itself as a new device, not an interrupt.
3
Controller ACKs the Hot-Join — Recognizes the address 0x02 as a Hot-Join indicator, acknowledges, and initiates a new ENTDAA procedure to assign the new device a dynamic address.
4
DAA runs for the new device — Normal ENTDAA cycle. The new device gets its dynamic address and joins the bus without any system reset.

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.

ModeFull NameMax SpeedKey Feature
I2C FMI2C Fast Mode (legacy)400 kHzOpen-drain, backward compatible. Used with legacy I2C devices on I3C bus.
I2C FM+I2C Fast Mode Plus (legacy)1 MHzOpen-drain at higher speed. Requires stronger drivers.
SDRSingle Data Rate12.5 MbpsStandard I3C mode. Push-pull, data sampled on one clock edge. All I3C devices support this.
HDR-DDRHigh Data Rate – Double Data Rate25 MbpsData sent on both rising and falling clock edges. Optional. Doubles SDR throughput. Indicated via HDR-DDR entry CCC.
HDR-TSPHDR – Ternary Symbol Pure-bus37.5 MbpsThree-symbol encoding on SDA for even higher bandwidth. Rarely used in practice.
HDR-TSLHDR – Ternary Symbol Legacy-inclusive37.5 MbpsLike 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

What is the key difference between I3C and I2C at the electrical level?
I2C uses an open-drain bus where devices can only pull the line LOW — a pull-up resistor restores the HIGH state, limiting rise time and speed. I3C uses a push-pull bus for normal transfers: the Active Controller actively drives both HIGH and LOW, eliminating the RC rise-time bottleneck. This enables speeds up to 12.5 Mbps (SDR) vs I2C's 3.4 MHz maximum. Pull-up resistors still exist in I3C but only to hold the bus idle; they do not limit performance.
How does Dynamic Address Assignment (DAA) work in I3C?
I3C targets have no addresses at power-up. The controller sends the ENTDAA broadcast CCC to start DAA. All unclaimed targets enter open-drain arbitration, driving their 48-bit Provisional ID (PID) bit by bit — lower bits win. The surviving target sends its full PID, BCR (Bus Characteristics Register), and DCR (Device Characteristics Register). The controller then assigns a 7-bit dynamic address. This repeats until all targets have addresses. DAA eliminates address collisions because each device's PID is globally unique.
What is an In-Band Interrupt (IBI) and why is it important?
An IBI allows an I3C target to signal an interrupt to the controller over the SDA line itself, with no extra GPIO pin required. The target pulls SDA LOW after a STOP condition. The controller detects this, clocks the target's dynamic address (with RnW=1), and ACKs or NACKs the interrupt. If ACKed, the target can send an optional payload (up to 64 bytes) with event data. This is critical in mobile SoCs where GPIO pins are scarce and tens of sensors must report events without polling.
What is the Provisional ID (PID) and what does it contain?
The PID is a 48-bit factory-programmed unique identifier in every I3C target. It consists of: a 15-bit MIPI Manufacturer ID (vendor-specific, assigned by MIPI), a 1-bit type flag, a 16-bit Part ID (chip model), a 4-bit Instance ID (to distinguish identical chips on the same bus), and 12 reserved bits. The controller reads the PID during ENTDAA to build its address table, identify device types, and detect duplicates. Because the PID is globally unique, address collisions across vendors are impossible.
What is the T-bit in I3C and how does it differ from I2C's ACK/NACK?
In I2C, after each data byte, the receiver pulls SDA LOW for ACK or releases it for NACK. In a read, the controller is the receiver and it sends NACK on the last byte. In I3C SDR, the T-bit (Transition Bit) replaces this mechanism. The target always drives the T-bit after each byte it sends (during read) or receives (during write). T=0 means "continue" (more data) and T=1 means "last byte / end." This shifts the termination signal to the target, making the protocol more symmetric and avoiding the need for the controller to predict the last byte in advance.
How does Hot-Join differ from a normal device connecting to an I2C bus?
In I2C, there is no mechanism for a device to announce its arrival — the controller must either poll for new devices or the system must be designed such that all devices are present at startup. In I3C, Hot-Join lets a device that powers up or connects after bus initialization signal its presence by pulling SDA LOW during an idle window. It uses reserved address 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.
What is the difference between a Broadcast CCC and a Direct CCC?
A Broadcast CCC uses the reserved I3C address 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.
Can I mix I2C and I3C devices on the same bus? What are the limitations?
Yes. I3C is designed to be backward compatible with I2C. Legacy I2C devices can coexist on an I3C bus as Legacy I2C Targets. The controller communicates with them using open-drain mode and their static I2C addresses (assigned via 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.