Trung Do

Embedded knowledge:
Basic communication protocol - I2C

Share on facebook
Share on twitter
Share on linkedin


Let’s continue with the “Embedded knowledge: Basic communication” series. Today, we will look into another popular protocol: Inter-Integrated Circuit or I2C.

Here are 3 blogs in “Embedded knowledge: Basic communications” series in case you’ve missed any of them:

1. Embedded knowledge: Basic communication protocol – UART.

2. Embedded knowledge: Basic communication protocol – SPI.

3. Embedded knowledge: Basic communication protocol – I2C.

In this series, I also share my working experience with these protocols.

Now, let’s get started!


Let’s get back to Ted and Marshall who are in a conversation.

Figure 01: Ted and Marshall are in a conversation

With I2C, we still have the same principle as shown in figure 02.

Figure 02: The most basic I2C connection

Only 2 wires are required in I2C bus, which is equal with UART. However, I2C works in a totally different way in comparison with UART. Let’s go to find out what I2C protocol can do and why over 1000 ICs manufactured have used I2C in their product so far.



Let’s again take a look at the most basic cases

Figure 03: The most basic I2C connection

There is something we should notice about this figure:

Only 2 wires are used: SDA (aka. Serial Data Line) and SCL (aka. Serial Clock Line)

SCL – Marked as “1” in figure 03:
Only goes from Master to Slave -> Device generating clock and initiating the communication is Master

SDA – Marked as “2” in figure 03:
Data is transferred between master and slave on this line.
This is a bi-directional bus. As a result, at one time, it is either Master or Slave transfers data. For this reason, I2C is a half-duplex protocol.

Pull-up resistor to VDD – Marked as “3” in figure 03:
How to choose the correct value for that pull-up resistor will be discussed later of this post.

Last but not least, each device connected to the I2C line is required to have a unique address, which is normally addressed by software.


Basic operation

We will go through some basic cases between master and slave before deep diving into details:

Figure 04-1: Read 1 byte from slave

Figure 04-2: Read several bytes from slave

Figure 04-3: Write 1 byte to slave

Figure 04-4: Write multiple bytes to slave

Figure 04-5: Read right after write to slave


SDA and SCL signal and logic levels

Let’s consider to a more complex case as the picture below

Figure 05: Multi masters and multi slaves 

As you can notice in the figure, we have multiple devices drive the SDA and SCL lines. If master and slaves use the normal configuration for the output pin, voltage conflict will happen in some cases (Master drives SDA to 5V while slave 1’s SDA is still 0V) 

In order to avoid this issue, both SDA and SCL must have an open-drain (for CMOS) or open-collector (for BJT). I will tell you why but first take a look at an example of SDA open-drain output in figure 06:

Figure 06: SDA open-drain output

There are only 2 cases here in figure 07:

Figure 07-1: Different output to SDA open-drain

When ever we apply “1” to G (gate), D (Drain) and S (Source) are shorted. SDA line is now connected to GND.
When ever we apply “0” to G, D and S are disconnected. SDA line is disconnected from GND.

For example, if master drives SDA to 5V, there are 2 cases:
1. Slave outputs “0” to its Gate -> its SDA pin passively goes HIGH through pulled up resistor Rd (SDA = 5V) -> No voltage conflict. 
2. Slave outputs “1” to its Gate -> its SDA pin is connected to GND (SDA = 0V) -> No voltage conflict.


Figure 07-2: Logic levels

Data validity

Data is sampled on SDA line everytime clock pulse goes HIGH. Therefore, the data on SDA line must be kept unchanged during that high period of clock.

On the other hands, the data on SDA line is only allowed to change during the low period of clock.

Figure 08: Data validity

Start and Stop condition

Both start and stop conditions are created by the master.

Master will generate either Stop (if it wants to stop the transferring session) or Start repeat (if it wants to continue the transferring session) after the Start condition.

We use Start repeat instead of Stop then Start again when the master wants to start a new communication without let the bus go idle in between, in which it can lose control to another master (in multimaster case).

Figure 09 shows the start and stop condition in a frame:

Figure 09: Start, start repeat and stop condition

In short:

Figure 10: Start, start repeat and stop condition definition

Byte format

One data bit is transfer in each clock pulse and I2C requires to use 8-bit long per bytes.

Figure 11: Bits and Byte


Acknowledge (ACK) and Not Acknowledge (NACK)

Slave sends an ACK if the data is received correctly.

Slave sends an NACK when:
• The receiver is not ready to start communication with the master because it’s busy doing other tasks.
• Not understand data from master during transmission.
• Cannot receive any more bytes from master during transmission

When master receives data from slave, it will send ACK if it’s still waiting for another byte.
Also in this case, master will send NACK to slave to terminate the transmission. Remember that NACK from master to slave does not mean that the last byte from slave has error.

The transmitter must release the SDA line before receiving any response from the receiver.

Figure 12: ACK and NACK

Clock stretching

When the slave able to receive all data but it needs time to store and prepare for the new bytes, it can hold the SCL line (extending clock LOW period) after receiving all 8 bits to put the master into wait state. After finishing all tasks, slave will response ACK to master. This procedure is called clock stretching.

The I2C slave is allowed to hold down the clock if it needs to reduce the bus speed.

The master is required to read back and wait until it is actually reach the high state after releasing it.

Figure 13: Clock stretching

  1. Before clock stretching: After finish sending 8 bits, master releases SDA and SCL. The master is required to keep reading back SCL until it goes HIGH.
  2. During clock stretching: Slave does clock stretching by driving SDA to LOW (for ACK) but keep holding the SCL.
  3. Finish clock stretching: Slave releases SCL. SCL now passively goes HIGH.
  4. After clock stretching: master detect 9th clock pulse while SDA is LOW. This is the ACK signal. 


Slave address (7 bits) and Read/Write bit

After the START, master firstly needs to send a byte to inform slave which command (READ or WRITE) master is going to do at which address. The format of this frame is shown on figure 14:

Figure 14: Slave address (7 bits) and Read/Write bit

10-bit slave addressing

10-bit addressing is born to extend the number of address on I2C bus. However, it is not widely used nowadays.

10-bit address format will be created after receiving the first 2 bytes after Start or Start repeat. Note that the first 5 bits of the first bytes is fixed at 1-1-1-1-0.

Figure 15: 10-bit address format

We can use 7-bit addresses and 10-bit addresses device on the same I2C bus. Due to the first byte address with format 1-1-1-1-0-x-x is reserved for 10-bit device only, we can distinguish between 2 type of different addresses. 

Let’s take a look at “Reserved address” section below for more details.


Reserved address

Figure 16: Reserved address

General call address

The general call address is used if master would like to execute something on several slave devices at the same time. It is required that the slave devices are configured to receive the general call address previously.

If a device does not required any data from a general call address, it responses nothing. Otherwise, it will ACK this address and turn into a slave-receiver.

The master cannot detect how many devices are using the message.

The general command will be sent in the second bytes with the following format:

Figure 17: General call address bytes format

In the second byte, if B = 0:
0000 011 0 (0x06): Reset and write programmable part of slave address by hardware.
0000 0100 (0x04): Write programmable part of slave address by hardware.

If B = 1: this is a “hardware general call”


Device ID

This is an optional 3-byte read-only with the following format:

Figure 18: Device ID

Multi-master bus: clock synchronization and arbitration

Let’s consider the case that we have multi masters on the same bus and two of them start transferring on the free bus at the same time.
For this reason, there must be a way to determine which master takes control the bus and finish its transmission. This problem is solved by using clock synchronization and arbitration.


Because SCL pin is configured as an open-drain output, the SCL will be 0 if at least 1 master drives it to 0. Therefore, this is called “the wired-AND” connection of I2C interfaces.

Figure 19: Multi-master bus

Here is how clock synchronization works

Figure 20: Clock synchronization

When Master-1 release SCL1, the shared SCL is still driven low by SCL2. Therefore, Master-1 will enter the wait state until Master-2 completes its low-state and releasing SCL2. Master-1 will be informed by the Shared SCL goes high event and starts counting its high state.

By doing this, the clock synchronization is done in every clock period.


We use arbitration to determine which master will complete its transmission while other must stop (in multi master bus with several START conditions are sent out at almost the same time)

Figure 21: Arbitration

Master-1 and Master-2 start the transmission almost at the same time.
Both Master-1 data and Master-2 data are sent out. 
Just like the shared SCL, the shared SDA is also a wired-AND, thus, Shared SDA will be equal to (SDA1 AND SDA2).
After sending every bit, each master will check the shared SDA to see if it’s matched.
The first time the mismatch happens, the master knows that it loses the arbitration to other master and therefore, turning off its SDA. 

Bus speed

The I2C speed relies on the pull-up resistor value as well as the bus capacitance. 

The maximum speed is the largest clock speed at which, our MCU can sample the correct logic level. 

The way we choose the value for the pull-up resistor and number of devices connected to I2C (bus capacitance) are directly related to the rise-time of clock. As a result, the sampling process is affected.

According to User Guide UM10204 page 35, we have 5 operating speed categories:

Figure 22: Bus speed

Electrical specification

Logic level voltage, rising time and bus capacitance

Pull-up resistor

How does pull-up resistor affect clock pulse?
R is high → long rise time.
R is low  → short rise time but the power consumption is high.
⇒ Need to find Rp_max and Rp_min value of Rp to meet the signal timing specification.
If your system is sensitive to power, should choose Rp around Rpmax to minimize the current consumption.

Calculate Rp_max and Rp_min

Rp_max = t_r/(0.8473 x C_b) 

Rp_min = (VDD – VOLmax)/IOL

t_r: SDA and SCL maximum rising time allowed
C_b: estimated bus capacitance
VOLmax: maximum LOW-level output voltage
IOL: sink current (3mA for standard mode and fast mode, 20mA for fast mode plus) 

More information about this please refer in the UM10204.

After having Rp_max and Rp_min, we can choose our R_p within this range.

What is bus capacitance?
The bus capacitance is the total capacitance of wire, connections and pins.
⇒ That’s why when sniff with a logic analyzer, the I2C signal might be affected.
⇒ Should choose probe with as low capacitance as possible to make sure we still meet the I2C signal timing specification.


Operating above the maximum allowable bus capacitance

Decrease the clock speed: as the bus capacitance will slow down the rise-time of clock, decreasing the clock speed to make sure it reaches the correct logic level might help.

Increase drive-strength output: higher drive strength on SCL can help decrease the rising time dramatically.

There are other ways such as bus buffers or switched pull-up circuit also helps in this situation.


Coming up next!

We have just finished the last article in the Embedded knowledge: Basic communication series. I hope you find it helpful and don’t forget to subscribe for more exciting articles is coming out real soon.


Trung Do

Firmware engineer, blogger and a makerholic 

Related Articles

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>