juanrgar

Juan García Blanco's Personal Page

Github | Twitter | LinkedIn
11 February 2022

I2C Protocol

by juanrgar

I2C is a synchronous, serial communication bus designed for connecting devices at short distance, i.e., intra-board. It was invented by Philips in 1982, and it’s still widely used in simple peripherals. SMBus is derived from I2C and specifically designed for peripherals typically found on a motherboard.

Physical Layer

I2C consists of various nodes that can either be controllers or peripherals. It allows multiple controllers in the same network, and the specification describes an arbitration mechanism. Nodes are connected using 2 lines, SCL and SDA: SCL carries the clock signal (as previously stated, it’s synchronous), while SDA carries the data bits (i.e., half-duplex).

The bus design supports various maximum speeds:

Mode Maximum speed
Standard mode (Sm) 100 kbit/s
Fast mode (Fm) 400 kbit/s
Fast mode plus (Fm+) 1 Mbit/s
High-speed mode (Hs) 1.7 Mbit/s
High-speed mode (Hs) 3.4 Mbit/s

Please note that the actual amount of transferred data varies depending on the messages flow, as there’s some overhead in the protocol.

Protocol

First of all, I2C defines a 7-bit address space, where each peripheral has a unique address. The full 7-bit space is not usable, though, because there are some addresses reserved to extend the address space to 10 bits.

A controller initiates a data transfer using a START condition, and can terminate it using a STOP condition. A START condition is indicated by a high-to-low transition of SDA with SCL high; a STOP condition, on the other hand, is indicated by a low-to-high transition of SDA with SCL high.

After the START condition, it comes the device selector or address byte, which consists a 7-bit address followed by a R/W bit. The addressed peripheral, if any, responds with a ACK/NACK bit.

The R/W bit determines what comes next. If the controller signaled a read operation, then the peripheral begins sending data bytes; each byte is followed by an ACK/NACK bit from the controller. This ACK/NACK bit indicates whether the controller will keep accepting data bytes or not, i.e., the controller sends NACK after receiving the last data byte.

Conversely, if the controller signaled a write operation, it begins sending data bytes to the peripheral, which responds with a ACK/NACK bit indicating the status of the operation.

Finally, the controller sends a STOP condition to finish the data transfer. And that’s all, pretty simple so far.

Repeated START

The bus supports a so-called repeated START condition, which means sending a START condition following an address or data byte, i.e., without sending a STOP condition. A new address byte comes after the repeated START.

10-bit Addressing

Although rarely used, the specification foresees a 10-bit addressing mode. In this mode, 2 address bytes are sent before data transmission can start. The first address byte embeds a pattern in its 5 most significant bits, which is followed by the 2 most significant address bits, and the R/W bit: 11110XXY. The second address byte contains the 8 least significant address bits. Please note that the type of operation is encoded in the first byte.

Address Space

The specification reserves 2 sets of 7-bit addresses: 0000XXX and 1111XXX. The first group is devoted entirely to special pre-defined functions; the second group comprises 10-bit addresses and other addresses reserved for future use.

This means that the maximum number of peripherals that can be connected to the same I2C network is (2^7 - 1) - 2 * (2^3 - 1) = 113.

Overhead

As previously stated, there’s some overhead in the protocol, mainly derived from the need to transmit an address byte to select a peripheral, and also from the need to send again a full address byte when the operation type changes.

tags: