Skip to content


Introduction to I2C

design_i2c_bus_interface_circuit4In this article Grinan Barrett introduces us to I2C. Grinan explains how I2C works, provides many useful links to information related to I2C and example Arduino code for a robot project where multiple Arduino boards are used for sensing and control. Grinan submitted this article to uCHobby as part of the uCHobby Giveaway program.

What is I2C?

I²C uses only two bidirectional open-drain lines, Serial Data (SDA) and Serial Clock (SCL), pulled up with resistors. Typical voltages used are +5 V or +3.3 V although systems with other, higher or lower, voltages are permitted.

The I²C reference design has a 7-bit address space with 16 reserved addresses, so a maximum of 112 nodes can communicate on the same bus. The most common I²C bus modes are the 100 kbit/S standard mode and the 10 kbit/S low-speed mode, but clock frequencies down to DC are also allowed. Recent revisions of I²C can host more nodes and run faster (400 kbit/S Fast mode, 1 Mbit/S Fast mode plus or Fm+, and 3.4 Mbit/S High Speed mode), and also support other extended features, such as 10-bit addressing.

The maximum number of nodes is limited by the address space, and also by the total bus capacitance of 400 pF, which restricts practical communication distances to a few meters.

Wikipedia Definition

What exactly does the I2C protocol and usage mean to the average robot builder? Well, it can mean a lot of different things,such as easily accessible devices like temperature sensors, accelerometers, and even setting up a small on board network on a robot.

 

 A simple I2C network setup

Using I2C I can connect more than one Arduino to my robot, and establish a  network of sensors, or other devices, and have more than enough controller pins to make life easy. Sure, there are other solutions, like port expanders, and such as that, but when you already have multiple Arduino boards, and no electronics shop anywhere near you, it is more than adequate.

 

Setting up and using i2c

For demonstrating the i2c protocol with Arduino, you will need some basic things:

· Two or more Arduino

· The latest Arduino IDE

· hookup wires – just a couple of pieces

· 2 – 1.5k pull up resistors

· Arduino Wire library – already installed

The Arduino Wire library is installed by default with all of the Arduino IDE’s that I am aware of. You can see this by starting the environment and looking in the sketchbook at the example programs for your installed libraries.

The Wiring – hardware not software!

i2csmall1The wiring diagram isn’t much, because there’s not much needed to make these connections.

In the circuit above you will see we are dealing with three Arduino here, one master, two slaves. The entire network is shown. There are a total of 2 pins in addition to the power and ground on each Arduino that we will use.

It is important to remember when you use two power supplies is to install a common ground between the two. You can still have individual power, you just have to have that common ground, without it, the I2C protocol will probably fail. In my testing, I noticed that my communication failed each time I unplugged either of my USB cables from the Arduino I finally figured out that if I put that common ground in there, I won’t lose communication when I disconnect from the PC.

Another important point is the actual pins used for communication. Analog pins 4 and 5 are your SDA and SCL pins respectively. You will connect these two pins to the same two pins on the other Arduino, with a 1.5k pull-up resistor on the SDA and a 1.5k pull-up resistor SCL lines tying them to the 5 volt positive supply on one of the Arduino I usually connect them to a breadboard that my master Arduino sits on. Be sure you connect pin 4 on the master to pin 4 on the slave, and pin 5 on the master to pin 5 on the slave.

The Wire Examples

The Wire examples that are included with the library are basic, but will show you the actual proof that your i2c network is up and running. You can access the example sketches by going to file>sketchbook>examples>Wire.

Load up the example sketch "Master Writer" if you look at the code you will see that this code is well commented, and just about every line tells you what it does. One of the main points is the fact that the "Master" Arduino does not have to have an address specified, but all slave devices do.

Lets connect one Arduino up, and load the sketch "Master Writer" from the Wire examples library. Looking at the sketch you will see the following:

#include <Wire.h>
  void setup()  {     Wire.begin(); // join i2c bus (address optional for master)  }

Wire.beginTransmission(4); // transmit to device #4  Wire.send("x is "); // sends five bytes  Wire.send(x); // sends one byte   Wire.endTransmission(); // stop transmitting
  x++;  delay(500);

That’s pretty much the entire program.

The very first line includes the wire.h library. Which is necessary if you will be using it.

The setup loop in any sketch that you want to use the wire library in must also have the “wire begin” function in it to join the I2C bus. If you don’t specify a device address in this setup step, it is assumed that device is the master. The master device does not have to have a device address, although all of the slave devices will.

The next couple of lines are to actually send whatever information you want to the slaves. Oddly enough, you start a transmission by calling the “wire.beginTransmission” function. You should also note that the device id that you want to transmit to is listed in the parenthesis next to the begin function. “wire.beginTransmission(4);” Where 4 is the device id that we want to transmit to.

In this example we are simply setting up a variable and loop to increment a basic looping count. When the counter reaches 255 it will reset to 0. Pretty basic, but it will show if communication is working or not for us.

After we have sent to data to the slave device we must close the transmission. Ending the transmission is as easy as “wire.endTransmission()”. That’s pretty much how you send data to a slave over I2C with an Arduino.

If you haven’t changed anything in the sketch, press the key to upload the sketch to the master Arduino. You don’t have to leave your connection cable connected, but be sure that you have all of your hardware wiring connected and the Arduino is on.

Connect your other Arduino and load the sketch "Slave Receiver" from the Wire examples library.

void setup()
{       Wire.begin(4); // join I2C bus with address #4       Wire.onReceive(receiveEvent); // register event      Serial.begin(9600); // start serial for output   }

Again, we see that the wire.begin function starts the wire library, and prepares us to receive data transmissions from the master.

Something new in this sketch that is different from the master code, that’s the “Wire.onReceive” function. Here we are setting an actual interrupt. When you send data, it will interrupt whatever is going on in the loop and execute the code associated with that interrupt.

Also, we are starting the serial communication so that we see what is being received in the serial monitor for this Arduino.

void loop()  {
    delay(100);   }

that loop is just to keep us running.. we aren’t doing anything but receiving data and relaying it via the serial monitor with this sketch.

void receiveEvent(int howMany)
{
    while(1 < Wire.available()) // loop through all but the last      {
        char c = Wire.receive(); // receive byte as a character
        Serial.print(c); // print the character       }

    int x = Wire.receive(); // receive byte as an integer
    Serial.println(x); // print the integer
}

The rest of our code here is receiving our data and formatting it to be displayed via the serial monitor. Pretty basic stuff in actuality.

Upload this sketch to your second Arduino. It is now your slave device with a device id of 4. Be sure to leave the cable connected to this device after uploading, and start the "serial monitor" to see what data if any is being broadcast by the master Arduino and what data is actually being received by the slave.

If your connections are right, you have placed the 1.5k pull up resistors on both data and clock and power is good, and you didn’t change any code, you should see something like this in the serial monitor:

x=1

x=2

x=3

x=4

etc.

It should continue to count up until it reaches 255 and then reset. This is a simple program only to show that the communication is working.

 

Next Steps

Now that you have the I2C network working, you should be able to adapt it to your own uses. I worked off the basic code supplied with the wire library, and at this point have my robot up and running with an Arduino diecimila and a Bare Bones Board from Modern Device Company.

 

picture-020 Yes, that’s a ROBOQUAD head on there… with the brains taken out, and a Parallax Ping ))) ultrasonic sensor installed along with one Panasonic IR detector which was salvaged from one eye. I was surprised the head fit.. perfectly, and the ping sensor went right into the existent eye holes.. almost like someone was planning my liberating it and doing just what I did with it.

Here is an over all picture of the I2C network.. one BBB on top controls the LCD at this point, will control the ping sensor when I get around to coding it.. and it also will control all of my IR sensor stuff in the end.

The other board, an Arduino Diecimila with Ladyada’s outstanding Motor Shield. I love the motor shield, it made my life as a robot experimenter much easier.

The way I have this I2C network setup is that the lower board is the master. It controls the motor shield, and also catches the IR signals from the universal remote. The master board also is sending out the directional indicators to the LCD that is attached to the BBB. Here are a couple of pictures of it with the LCD displaying info.

 

Conclusions

I think in the end, the I2C protocol used as I have used it, is a pretty painless thing. After I figured out a couple of key things:

· make sure you have a common ground when using two power supplies

· make sure you have a minimum of a 1K pull-up resistor on each line pulling it to 5 volts. I personally used 1.5K for all my testing, and in my current robot setup.

Using the wire library with Arduino is simple to do as you can see from my code that I have attached. This code was the original examples that I modified to connect to the motor shield and the LCD It took my two days to learn all that I did on I2C and actually get an I2C network up and running on my robot.

I hope that maybe I have opened your eyes to I2C a little, and if you want to you can learn a lot more about I2C from the Arduino forums. .There are also a couple of great sites around that have some interesting projects using I2C and I2C enabled sensors.

Here are a couple of things to keep you going:

· Here is an excellent FAQ about I2C. Includes a lot of valuable information.

· Here is a forum post that i made discussing the I2C while I was chasing problems with it.

· The Wii Nunchuk is I2CuCHobby tells us about it.

· Keith’s blog tells about expanding ports on the Arduino using I2C

· Here is video of an I2C clock and LCD on You Tube

Here is the code that I am currently working on for my I2C robot. Feel free to use it at will.

Robot Network Arduino Code

Posted in Arduino, Development Tools, Discovering, Electronics Links, Ideas, Microcontroller.

12 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Cool article! Are there any special considerations when setting up a peer-to-peer I2C network, as opposed to a master/slave configuration as you’ve outlined here?

    The image at the start of the article shows a pair of resistors labeled Rs between the SDA and SCL lines and each Arduino. What is this for? It’s not mentioned in the text.

  2. Daniel said

    Very nice, im implementing the Wii Nunchuck and i2c in my next project. I bought a couple of those breakout adapters from

    http://store.fungizmos.com/index.php?main_page=product_info&cPath=69&products_id=212

    so that breaks out 3 accelerometers, an xy-stick and two buttons.

  3. grinan said

    the two resistors are necessary, those are 10k pullup resistors. You need one pullup on both the sda and scl from 5+.

    I have read in several places that you can enable the internal pullup resistors on the atmega, but it failed miserably for me each time i tried.. i could never establish clear communication.. it was intermittent at best.

    Hope that helps, thanks for the kind comment.

  4. grinan said

    Plese disreguard the last comment, i re-read your comment and missed your question totally.

    the i2c bus is just two wires, called SCL and SDA. SCL is the clock line. It is used to synchronize all data transfers over the I2C bus. SDA is the data line. The SCL & SDA lines are connected to all devices on the I2C bus. There needs to be a third wire which is just the ground or 0 volts. There may also be a 5volt wire is power is being distributed to the devices. Both SCL and SDA lines are “open drain” drivers. What this means is that the chip can drive its output low, but it cannot drive it high. For the line to be able to go high you must provide pull-up resistors to the 5v supply. There should be a resistor from the SCL line to the 5v line and another from the SDA line to the 5v line. You only need one set of pull-up resistors for the whole I2C bus, not for each device.

    Also, I used 1.5k resistors, but any resistor should work from 1k up.

    Hope that helps.

  5. Very good article, Simple and direct to the point .
    Jeronimo
    http://www.blogdoje.com.br
    Avr,Arduino & ARM

  6. Daniel said

    Is there an article somewhere that explains setting up addresses for i2c devices, and what to do about conflicting device addresses?

  7. grinan said

    well, the best i can tell you about is arduino, and most devices that arduino connect to are configurable as to addressing. You will need to check the manufacturers data sheet for other arduino devices.

    You are allowed, i believe, up to 255 devices connected on the i2c bus. As you can see in the code above, it’s as simple as just giving it a number in arduino, with the master being 0 or undefined.

    Check out this forum post, it touches briefly on addressing, http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1221415715/6 If that doesn’t help you, try searching the arduino forums via google or their built in search.

    Most of my information came from the forums to begin with.

    Hope that helps.

  8. Seb said

    Hi,

    I’ve set up a I2C with 2 arduino. Seems to be OK, messages are received but they are read with strange characters. Instead of reeiving ‘hello ‘ i receive 6 characters looking like a quare. my grounds are connected each other diretly.

    Any idea where the pb comes from ?

    once this will be solve, if I have 20 arduino sending messages all together, will there be any trouble to get them ALL on the master receiver ?

    Thanks

    Seb

  9. grinan said

    I believe you will find I answered your question on the arduino forum, check here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1220103333/20#20

    This problem happens to me when I try to power both arduinos from usb at the same time. To avoid this, I usually only use usb on one, the master, and the other i am running off of a separate power supply with no connection to the computer.

  10. Berni said

    Well you could be running I2C at a too high speed, your line between them may be too long (I2C is only ment for a meter or two)Or a too big / too small pull up resistor

    When you have 20 on the line you have to always wait while the line is busy so you don’t transmit when someone else is already transmitting.

    Also for this thing it may be better to use something called a CAN network.It works with a 2 wire twisted pair cable and goes up to 1Mbit and up to 300m.(So if you renovate your house remember to put a twisted pair cable over the whole house and do some really cool house automatisation)

  11. Sushi said

    Now, if I want to setup an I2C network between my Arduino and an ATTiny13A, how would I do that? I don’t think there is any type of wire library for the ATTiny. Is there?

  12. grinan said

    well at first glance i would say that there is not a wire library for the attiny. I don’t think that the 13a will do i2c, although the data sheet says that you can use SPI to communicate with it. That may be worth investigating.