You are on page 1of 8


1 I2C Basics | Engscope

1 de 8

An Engineer's Life

10.1 I2C Basics

10.1 I2C Basics

Ive gotten quite a few requests for the I2C bus section of the PIC24 tutorial. This is understandable since most
digital electronics these days, both to reduce design cost and pin count, uses the I2C bus for inter-IC (get it?
IIC = I2C, yeah engineers are smart like that) communications.
Just in case you have no clue what I2C is, it is a communications bus invented by Philips. Although there are
provisions in the I2C standard for multi-master environments, as well as 10 bit addressing, the most simple and
commonly used configuration is the single master, 7 bit addressing. This configuration will be the only one
addressed in this PIC24 tutorial.

Unlike the UART, which is an asynchronous form of communication, the I2C is synchronous. The master device
sends both the data signal, as well as the clock signal, with the exception during data reads. The receiver syncs
up with the clock signal, and samples the data on the rising edge of the clock. Ultimately, this means that the
transmitter and receiver do not need to know the clock rate because a clock signal is sent along with data. If you
remember from the UART tutorial, a predetermined clock speed must be known on both the transmitter and the
receiver. This is great news for engineers, because you dont have to do clock calculations (for the most part).
There are upper limits to how fast you can send the clock signal, but as long as you are below the upper limits,
the bus will work fine. The I2C bus requires two wires to be connected between the master and slaves, as well as
a return (GND) wire. This usually means that at least three wires needs to be connected from the master to the
slave. However, there are several advantages over other forms of buses for communications between chips.
Personally I prefer using the I2C for the ease of use and reliability of communications. The minimal clock
calculations, most of the time as an afterthought is a huge advantage over the UART. In addition, you can also
establish communications between more than just two chips. There are provisions in the I2C standard that
allows for multiple devices, and layers of software and hardware to decode the transmission so that the packet
sent by the master device gets accepted by the intended slave device, and only by the intended slave device. This
is NOT the case in the UART. In the UART communications model, there is a transmitter, and a receiver. If you
have multiple receivers, well, I dont know what would happen. The convention is to name the data line SDA,

01/04/2010 03:22 p.m.

10.1 I2C Basics | Engscope

2 de 8

and the clock line SCL, and as such, I will use this convention in the tutorial.
I will not explain every single section of the I2C standard, but I will provide diagrams for the most basic
Obviously, youll need to have two devices: a master I2C device and a slave I2C device. For most applications, the
master device is obviously the PIC24. We want to use it as a programmable controller, to control one or several
slave devices. Second, the I2C bus is an open drain pull-down bus. What this means is that the bus needs to be
pulled up to a nominal voltage (Vdd) when no devices are occupying the wires. Because it is an open drain bus,
this nominal voltage is not strictly specified. Usually I use 3.3V, but applications such as the DDC in your
monitor use 5V. A set of pull-up resistors need to be tied from the data and clock lines to Vdd. This assures that
when the bus is idle, the voltages on data and clock are always at Vdd. In such a configuration, the devices on the
I2C bus pull DOWN on data and clock. This way the devices dont have to generate the nominal Vdd voltage if it
wants to send a 1, which might be somewhat electrically difficult because it is arbitrarily fixed (i.e. it is very
hard for a 3.3V powered device to generate a 5V signal on a 5V I2C bus). A device only needs to pull the data line
to a GND if it wants to send a 0. Since GND is a reference point that all devices must have, it is technically
possible to have a 5V device communicate with a 3.3V device on the same I2C bus!
Generally speaking, the pull up resistor values must be big enough so that it doesnt overpower the pull down
ability of weakest pull down device (i.e., if I pull up the SDA line to Vdd with a 10 Ohm resistor, can my device
pull the SDA line to GND hard enough to overcome that resister when it wants to send a 0? The device must
overcome the resistor in order to manipulate the SDA and SCL lines). However the pull up resistors must also be
small enough such that they can pull enough current to return the SDA and SCL lines back to Vdd in a very short
amount of time. Small enough such that the rise time of the pull-up is short compared to the clock period.
In technical terms, if you like EE speak, it means that the impedance created by the pull up resistors on the
transmission lines must be such that a clock signal can be sent through with crisp edges. If the resistor is too
large, your rising edges will be damped. If you resistor is too small, your chips gets cant dissipate enough current
to pull down, and your falling edges get damped.
In practical terms, stick with 2.5K Ohms. That should satisfy most situations. Whatever you do, only put ONE set
of pull up resistors for each line. DO NOT put one set of pull up resistors for each device. This would put the
resistors in parallel. And we all remember from circuits 101 what resistors in parallel do.
Basic I2C Communications
On the electrical level, the I2C communications functions as follows:

Image credit goes to Wikipedia. In a hypothetical situation, lets say there is one master device and one slave

01/04/2010 03:22 p.m.

10.1 I2C Basics | Engscope

3 de 8

device on an I2C bus line with pull-up resistors pulling to 3.3V. When the bus is idle, both the SCL and SDA
lines are pulled high by the pull-up resistors. If the master wants to send a byte of data, it must first initiate a
start bit (Label S), where the SDA line is pulled to a logical 0, while maintaining a logical 1 on the SCL line. Next
it starts sending a clock signal. Because the SCL is pulled high at the start bit, the master must pull SCL down for
half a clock cycle, before the first rising edge. Since the data is only sampled on the rising edge, at all other times,
the master is allowed to transition the SDA between a logical 0 and a logical 1. On the first rising edge, the SDA
line must have stabilized. The slave device samples the data (Label B1). This process is repeated until the 8th
rising edge, or the 8th bit. Right after the 8th rising edge, the master device releases control of the SDA line. It
has finished sending its data, and is now awaiting a response from the slave device. The slave device has one
clock cycle to transition the SDA clock to a logical 0 to acknowledge the reception of the data byte. This is
referred to the /ACK bit. The slash in front of the ACK indicates that it is an active low signal. The master then
sends a 9th rising edge on the SCL line, and samples the SDA line. If it is a logical 0, then the slave device has
successfully received the byte. If it is a logical 1, then something wrong has occurred (under most circumstances,
the /ACK is not required during the last byte of a read command). Lastly the SCL is held high, and subsequently
the SDA line is pulled high to signal a stop bit (P).
In the subsequent explanation of I2C packets, I will refer to the ACK bit with these notations: /ACK refers to an
acknowledge bit. Since the signal is an active low signal, when a device wants to communicate an
acknowledgment, it must send a logical 0 (i.e., 0 V). However, when the device wants to indicate that there is
something wrong, or that it did not correctly receive a piece of data, it sends a /NACK as an acknowledgement,
represented by a logical 1 (i.e. 3.3 V or 5 V).
Basic I2C Packet

There are two main types of operations the I2C bus. These are the random write command, and the random read
command. In general, a packet sent by the master for a write command looks something like this:

This picture is taken from the datasheet of the AT24C02B EEPROM chip from Amtel. Three bytes are sent from
the master device, and received by the slave if he is present on the bus. The first byte is the slave address and the
read/write indicator. The first 7 bits is the slave device address. This value is always indicated in the data sheet of
the slave address. In order for the I2C bus to allow for multiple slaves, the master must indicate which device the
message is intended. The slave address, which begins every I2C transaction is the address that corresponds to a
devices on the bus. Obviously there cannot be multiple slaves with the same address. This would create a
collision on the I2C bus. The 8th bit of the first byte is the read/write indicator. If the bit is a 0, the master wants
to write a byte, if it is a 1, the master intends to read. Next, on the 9th bit of the first byte, the master waits for an

01/04/2010 03:22 p.m.

10.1 I2C Basics | Engscope

4 de 8

acknowledge bit from the slave. If the address sent by the master corresponds to the slave address of a slave
device, the slave device MUST acknowledge on the 9th bit. If the /ACK is a 1, a non-acknowledge, then the
master thinks there is no slave with the sent address. It terminates the packet with a STOP bit. However, if a
slave does send back a /ACK with logical 0, then the master device begins sending the second byte. The second
byte is usually the slaves internal address (referred to as the WORD ADDRESS in the above drawing). For
example, on the AT24C02B EEPROM, there are 256 memory locations of 8 bits each. Whenever I want to write
to the device, I must specify which one of the 256 memory locations I wish to write to. This is what the second
byte of the packet is usually used for. On the 9th byte of the second byte the slave device must acknowledge that
the specified address exists as one of the slave devices internal addresses. Lastly, the master device sends the
data it intends to write. This is usually referred to as the data byte. Finally the slave device acknowledges the
received byte, and the communications is terminated by a stop bit.
The second most commonly used command is the random read. It is called a random read because this is the
ability to read any address at will, as opposed to a sequential read, everything must be read, until the correct
piece of data is located. Think of it as a DVD, where you can access anything instantly, versus a VCR, where you
need to wined the tape to the correct spot before watching a particular scene.

A random read must be done in the following manner. The master device must first act like it intends to do a
random write by sending the slave device address with a write command bit (recall that the slave address is 7 bits
long, NOT 8 bits long, the last bit of the first byte is reserved for the read/write command indicator). It then
sends the internal address just as if it intends to do a device write. The slave address must send a /ACK on 9 th
bit of both the bytes to indicate to the master device of its presence. However, at the end of the 2nd byte, the
master device resents a start bit. For the 3rd byte, the master device resends the slave address, but with the read
command bit for the 8th bit of the 3rd byte. At this point, after the slave address sends a /ACK back to the
master, the roles are reversed between the slave and master. On the next byte, the slave device takes over the
SDA line and waits for /ACKs from the master device. After the slave device takes over the SDA line, it starts
transmitting the byte located at the internal address. The slave device starts manipulating the SDA line
according to the clock. On each of the rising edge of the SCL line, sent by the master device, the slave device
must be ready with the bit it intends the master device to read. After the 8th bit is sent, the master device must
indicate a /NACK, the inverse of the inverse-ACK (logical 1) to tell the slave device to stop taking control of the
SDA line. It ends the transmission with a stop bit.
On the Subject of Writing
Be careful when writing to EEPROMS, or devices with permanent memory. It usually takes about 10 ms or so
before the device successfully finishes writing the data to memory. The AT24C02B for example, requires you to
wait a full 5 ms before allowing a subsequent write operation:

01/04/2010 03:22 p.m.

10.1 I2C Basics | Engscope

5 de 8

You must take into account these write cycle times when using a microcontroller. This is why it is important to
take note of the /ACK signals sent by the slave device. When a slave device is NOT READY for a subsequent write
operation, it will reply with a /NACK, logical 1, on every byte sent by the master.
Advanced I2C packets
The two advanced packet formats are the sequential write and the sequential read. As you can see from the two
basic packet formats, there are a lot of overhead data required to write one or two bytes to a device. What I mean
by this is that, if I want to write 8 bytes to an EEPROM device with my PIC24, I will need to actually send 24
bytes of data using random write commands. This is because 8 bytes of the data is used to send the slave
address, 8 bytes of the data is used to send the internal address, and finally 8 bytes of data is the actual data that
I wish to write. In addition, EEPROMs have long write cycles of several milliseconds. To get around these
limitations, most EEPROM have the ability to write 8 or so bytes in one sequential write. In addition, most
EEPROMs allow you to read all its data in one sequential read.
A sequential write is very similar to a random write. The following diagram from the AT24C02B datasheet does a
great job of illustrating the point.

The master device sends the exact same packet as a single write. However, after the /ACK bit of the 3rd byte is
sent, it DOES NOT send a stop bit. It continues to send data, expecting a /ACK from the slave after each byte.
After each transmitted byte, the internal address of the slave device is automatically incremented, and therefore
the master device does not have to manually select the next internal address. Usually sequential writes are
limited to about 8 bytes before the internal buffer of the slave device is full, in which case it will stop sending
/ACKs, indicating that something is wrong. After the last byte that the master wishes to send, and waiting for the
corresponding /ACK signal from the slave device, the master device sends a stop bit to terminate the
A sequential read is also very similar to a random read.

The master device sends the exact same packet as a single read. But whereas in a random read the master sends
a /NACK to stop the transmission, this time it send a /ACK to indicate to the slave device that it wants more
data. The internal address is automatically incremented and the next byte of data is sent by the slave. The slave
will keep on sending data until it receives a /NACK, at which point the master device terminates the

01/04/2010 03:22 p.m.

10.1 I2C Basics | Engscope

6 de 8

transmission with a stop bit. There are usually no limitations on how many bytes the slave is limited to sending.
The slave device just keeps on sending data on the SDA line unit it receives a /NACK from the master.
In the next section of the tutorial, Ill show you the basic functions of the I2C module on the PIC24.
Table of Contents

10 Responses to 10.1 I2C Basics

ED says:
January 7, 2010 at 11:10 am

I cant find your RSS feed i would like to subscribe to your content.

jliu83 says:
January 11, 2010 at 8:25 am
I think thats the standard wordpress address Works for me in firefox, does seem to have some problems with chrome.
Didnt bother checking it with IE.

Danny Cranmer says:

March 5, 2010 at 10:07 am

Hi, I know this isnt I2C but i thought I would let you know anyway.
Have been using the SPI modules on PIC24FJ128GA006 just the SDO and SCK pins to talk to a DAC. I have come to the
conclusion that the flag SPITBF does not work. As follows
Chip_Select = 0;
SPIXBUF = data;
while ( !SPIXSTATbits.SPITBF ); OR while ( SPIXSTATbits.SPITBF );
Chip_Select = 1;
Both of these variations have no effect and viewing on an oscilloscope shows the CS going low then high before the SCK pin
does anything (note the SPI module still operates just a dodgy Flag )
I have overcome this using a small time delay
Chip_Select = 0;
SPIXBUF = data;

01/04/2010 03:22 p.m.

10.1 I2C Basics | Engscope

7 de 8

Chip_Select = 1;
Obviously the time delay relates to the prescalers and Clock Frequency I am using and Where i have used SPIXBUF the X
represents the module number you are using.
Im not sure if this problem is just on my particular chip or I have some buggy header files but hopefully It can stop
someones brain hurting
Let me know if anybody has had the same problem
Danny Cranmer
These tutorials are the best and have helped me so much, thankyou very much !

jliu83 says:
March 5, 2010 at 9:09 pm

Have you checked the most recent errata? Maybe theres some hints on it. Did you eventually figure out the CN0/ CN1

Danny Cranmer says:

March 6, 2010 at 9:05 am

No still havnt got round to them pins yet as have been busy with other parts but I will let you know . Eventually .

Dave Wall says:

May 10, 2012 at 8:45 am

In the 15th paragraph (just above on the subject of writing) you say:
The master device is still in control of the SDA line, but the slave device takes over the SDA line and waits for /ACKs from
the master device.
I think its supposed to be that the slave takes control of the data line.
Thanks for a great website I always use and recommend it!

jliu83 says:
May 17, 2012 at 4:03 am

@Dave Wall. Ive changed the wording to make it more clear. Thank you for pointing that out.

Kruthik says:
July 23, 2012 at 10:15 pm

01/04/2010 03:22 p.m.

10.1 I2C Basics | Engscope

8 de 8

I wanted a detailed information about ,
1. The steps i should follow in SLAVE WRITE operation? and SLAVE READ operation?
2.What is a CURRENT ADDRESS bit?When should i use this bits while programming.
3.What is a MEMORY ADDRESS SELECT BIT (single/two byte address).When can i use this?

jliu83 says:
July 27, 2012 at 7:34 pm

@Kruthik. Unfortunately I dont have a slave I2C driver at the moment. Your on your own for this one, at least for now.
Perhaps in the future I might write a tutorial on it.

Anderson Venturini says:

January 21, 2013 at 11:52 am

Thats a great article! It was very useful. Thank you.

Proudly powered by WordPress.

01/04/2010 03:22 p.m.