The Inter-Integrated Circuit, or I2C, bus is an interface found on most microprocessors and is heavily used in embedded systems design.   The I2C bus is used to communicate with peripheral devices in much the same way as the SPI and UART interfaces.

The key feature that differentiates I2C from UART and SPI  is that the I2C bus can support multiple monarch and subordinate devices on the same bus.  The ability to support multiple devices on a single bus allows us to reduce the number of external pins on a microprocessor, reducing the cost and size of the device.


Source: TM4C123GH6PM Data Sheet, section 16.3

Pin Construction

The I2C bus consists of two signals: the data  (SDA) and clock (SCL) lines.  These pins are configured as open-drain (or open-collector) pins.  An open-drain pin is constructed using a single transistor that connects the output pin to ground when the transistor is turned on.  When the transistor is turned off, the output pin is left unconnected and a pull-up resistor pulls the line up to VCC (logic 1).


An open-drain pin make it a good choice for a bidirectional data bus where multiple devices many initiate a data transfer.   If one device attempts to place logic 1 on the line while another device attempts to drive logic 0, the pull-up resistor acts to limit the current and prevents a short circuit.

Standard (totem pole) GPIO pins would not prevent a short circuit.  Standard GPIO pins actively drive logic 1 and 0 on a signal without the use of a pull-up resistor.  If two different devices were to drive opposite logic values on the signal, this would result in a short circuit that could damage both devices.  This is the reason that standard GPIO pins are not used for bi-directional data transmissions.

I2C bus typologies can be very complex.  A single I2C bus can have multiple subordinate sand multiple monarchs.  We will only deal with most basic bus topology:  a single monarch and multiple subordinate devices.

Signal Descriptions

“The I2C bus uses only two signals: SDA and SCL, named I2CSDA and I2CSCL on  microcontrollers. SDA is the bi-directional serial data line and SCL is the bi-directional serial clock line. The bus is considered idle when both lines are High.

Every transaction on the I2C bus is nine bits long, consisting of eight data bits and a single acknowledge bit. The number of bytes per transfer is unrestricted, but each data byte has to be followed by an acknowledge bit, and data must be transferred MSB first. When a receiver cannot receive another complete byte, it can hold the clock line SCL Low and force the transmitter into a wait state. The data transfer continues when the receiver releases the clock SCL”

Source: TM4C123GH6PM Data Sheet, section 16.3.1

SDA is allowed to change only when SCL is low.  When SCL is high, the SDA must not change.

Data Format

Data transmitted over the I2C interface uses many of the same concepts used in SPI and UART interfaces.  Data is transmitted most significant bit first.  Data sent over I2c is framed by start and stop conditions.  Data can be read and written from an external device by specifying the internal addresses of registers in the peripheral device.

A key difference with the I2C interface is that each byte of data has to be acknowledged, or ACKed, by the receiving device in order for the data transaction to complete.  The ACK is necessary when many devices are present on the same I2C bus.  The ACK indicates to the transmitter that it is successfully communicating with another device and can maintain ownership of the bus until the data transaction completes.

Start Condition

Both the SDA and SCL lines are pulled high when there is no activity on the bus.  In order to signal the beginning of a data transaction, the device initiating the data transfer will pull the SDA line low while the SCL is still high.



All bus transactions have a required acknowledge clock cycle that is generated by the monarch . During the acknowledge cycle, the transmitter (which can be the monarch or subordinate ) releases the SDA line. To acknowledge the transaction, the receiver must pull down SDA during the acknowledge clock cycle.

When a subordinate receiver does not acknowledge the subordinate address, SDA must be left High by the subordinate so that the monarch can generate a STOP condition and abort the current transfer.

If the monarch device is acting as a receiver during a transfer, it is responsible for acknowledging each transfer made by the subordinate . Because the monarch controls the number of bytes in the transfer, it signals the end of data to the subordinate transmitter by not generating an acknowledge on the last data byte. The subordinate transmitter must then release SDA to allow the monarch to generate the STOP or a repeated START condition.

Source: TM4C123GH6PM Data Sheet, section

The image below shows an ACK.  An ACK is generated when the data line is released on the 9th clock cycle by the transmitter.  An ACK occurs if the receiver pulls SDA low before the next positive edge of SCL.  If the SDA is not pulled low by the next clock cycle, the data transmission is aborted.


Stop Condition

The monarch indicates that a transaction will end by generating a stop condition.  A stop condition occurs when SCL is high and SDA makes a low to high transition.


I2C Device Addresses

Because the I2C bus is not a point-to-point connection, there needs to be a mechanism to differentiate which pair of devices are currently transmitting data.  To solve this problem, each device is assigned an address on the I2C bus.   When the monarch device wants to send/receive data from a specific device, the first byte transmitted is the address of the subordinate device being accessed.

The address of the subordinate device consists of a device ID found in the data sheet of the device.  In addition to the device ID, many devices have one or more hardware address pins that allow you to support multiple of the same subordinate device on the same I2C bus.  Each hardware address pin will be set to an address using pull-up/down resistors to set a unique address for each device.deviceAddress

We will use the schematic snippet above to determine the I2C address of the MCP23017 IO expander.  Chapter 5 of the MCP23017 data sheet gives us the following information about how to determine the address.


Source: MCP23017

Using this figure, we see that the upper 4 bits of the address are 01002.  Bits 3-1 are set using the values supplied on the hardware address pins.  Using the schematic, these bits will be set to 0002.  Bit 0 always indicates if the device is being  read or written.   In order to write to the MCP23017 above,  the monarch would start a transaction with a byte equal to 0x40.  In order to read from the MCP23017 above, the monarch device would transmit  0x41.  When multiple devices are placed on the I2C bus, the hardware designer must ensure that two devices do not have conflicting addresses.

7-bit Vs. 8-bit Addresses

One common mistake that embedded software developers encounter when using I2C is specifying an incorrect address for a device on the I2C bus. The confusion arises because some data sheets list a 7-bit address and others list an 8-bit address.  So what is the difference between the two?

An 8-bit address includes the read/write bit.  Using the 8th bit to specifying an address results in one logical address  for writing to the device and a different address to read from the device.  The addresses shown above for the MCP23017 above are 8-bit address.

A 7-bit address omits the  read/write bit.  When specifying the 7-bit address, we only use bits 7-1 of the 8-bit address.  If we use bits 7-1 from the example above, the 7-bit address becomes 0x20.  It is understood that the 7-bit address is shifted left by 1 position and the read/write bit is set appropriately.

In the end, both representations of the I2C address will result in the same I2C address being placed on SDA.

Leave a Reply