Tip
A summary of everything shown below is available further down this page:
This post describes how the I2C (Inter-Integrated Circuit, or "Two-Wire") interface works, with particular reference to the Arduino Uno which is based on the ATmega328P microprocessor chip. A lot of the details however will be of more general interest.
The Two-Wire interface is extremely useful for connecting multiple devices, as they can all share the same two pins (plus a ground return). This is because the devices are "addressable". Each device needs to have a unique address in the range 8 to 119. Address 0 is reserved as a "broadcast" address, addresses 1 to 7 are reserved for other purposes, and addresses 120 to 127 are reserved for future use.
Because of this you could have an LCD screen (say) at address 10, a keyboard at address 11, and so on.
More information about I2C at:
http://en.wikipedia.org/wiki/I2c
More information about the Arduino Two-Wire interface at:
http://www.arduino.cc/en/Reference/Wire
Other protocols
Pinouts
On the Arduino Uno the pins you need are:
- Analog port 4 (A4) = SDA (serial data)
- Analog port 5 (A5) = SCL (serial clock)
On the Arduino Mega, SDA is digital pin 20 and SCL is digital pin 21 (they are marked SDA and SCL on the board itself).
On the Arduino Leonardo, the SDA and SCL pins are separate pins, so marked, on the board (next to AREF). They are also connected to D2 (SDA) and D3 (SCL).
These pins may require pull-up resistors (that is, connect them to +5v via something like a 4.7K resistor each).
The Atmega328 is configured to use internal pull-up resistors which may be adequate for short cable runs. Warning: for multiple I2C devices, or longer cable runs, the 4.7K pull-up resistor (for each line) is recommended.
Also see further down in this thread for some screen-shots of the effect of using different pull-up resistors.
Of course, you also need to connect the GND (ground) pins to complete the circuit.
The pins should be connected together (that is, pin 4 to pin 4, and pin 5 to pin 5, if you are connecting Arduino Unos together). This is because the pull-up resistors keep the lines high until one of the devices wants to use it by pulling a line low. In other words, you don't swap pins (like you do with serial communications, where you connect Tx to Rx and vice-versa).
Note also that the Atmega specifies a maximum bus capacitance of 400 pf, so that would rule out long cable runs.
Sending data
Let's start with an image - this is a screenshot taken with a logic analyser. It shows the character "S" (0x53) being sent from the Arduino to the device at address 42.
From the above graphic note the following points of interest:
- The transmission starts with the "Start condition" (labelled Start). This is when SDA (serial data) is pulled low while SCL (serial clock) stays high.
- The 7-bit address of the required slave is then transmitted, most significant bit first. In this case it was 42 (0x2A or 0b0101010). The logic analyser reports the address as being 0x54 but that is really 0x2A (this is, 42) shifted left one bit, so that the "write" bit (0) is in the least-significant bit place.
- Then the read/write bit is transmitted. 0 means write (master to slave) and 1 means read (slave to master).
- The master then waits for the slave to pull the SDA line low which is an ACK (acknowledge) that a slave of that address exists and is ready to receive data. If there is no slave connected and powered on, or it does not have the required address, then it will ignore the address, leaving the SDA line high (by the pull-up resistor). This counts as a NAK (negative acknowledgement). This can be tested for in the software.
- Then the data byte (0x53 in this case) is transmitted, most significant bit first.
- Again, after the 8 bits of data, the master checks that the slave acknowledges by pulling the SDA line low. Thus, each byte is acknowledged.
- More data bytes could be transmitted, but are not shown here.
- The transmission is ended by the "Stop condition" (labelled Stop) which is sent by releasing the SDA line to allow it to be pulled up while SCL stays high.
The code to produce this (in Arduino's C++ language) was:
// Written by Nick Gammon
// February 2012
#include <Wire.h>
const byte SLAVE_ADDRESS = 42;
const byte LED = 13;
void setup ()
{
Wire.begin ();
pinMode (LED, OUTPUT);
} // end of setup
void loop ()
{
for (byte x = 2; x <= 7; x++)
{
Wire.beginTransmission (SLAVE_ADDRESS);
Wire.write (x);
if (Wire.endTransmission () == 0)
digitalWrite (LED, HIGH);
else
digitalWrite (LED, LOW);
delay (200);
} // end of for loop
} // end of loop
[EDIT] Updated February 2012 to allow for version 1.0 of the Arduino IDE. This uses Wire.write rather Wire.send.
Tip:
Wire.endTransmission returns zero if the transmission was a success. It is a good idea to check that you got zero, otherwise you are sending "blind". If you do not get zero maybe you have the wrong slave address. Try running the "I2C scanner" described later in this thread.
The code above uses address 42 for the slave, and also uses the LED on pin 13 (which is standard on the Arduino Uno) to confirm visually that the transmission took place. If it succeeded then the LED is turned on, otherwise off. You can see this in operation by noting that the LED is only on if a slave of address 42 is connected and responding.
The code for the slave in my case was:
// Written by Nick Gammon
// February 2012
#include <Wire.h>
const byte MY_ADDRESS = 42;
void setup ()
{
Wire.begin (MY_ADDRESS);
for (byte i = 2; i <= 7; i++)
pinMode (i, OUTPUT);
// set up receive handler
Wire.onReceive (receiveEvent);
} // end of setup
void loop()
{
// nothing in main loop
}
// called by interrupt service routine when incoming data arrives
void receiveEvent (int howMany)
{
for (int i = 0; i < howMany; i++)
{
byte c = Wire.read ();
// toggle requested LED
if (digitalRead (c) == LOW)
digitalWrite (c, HIGH);
else
digitalWrite (c, LOW);
} // end of for loop
} // end of receiveEvent
The slave code has nothing in the main loop, because the two-wire interface generates an interrupt when data arrives. This was displayed on LEDs plugged into pins D2 through to D7 using an appropriate resistor in series with each one (eg. 470 ohms).
[EDIT] Updated February 2012 to allow for version 1.0 of the Arduino IDE. This uses Wire.read rather Wire.receive.
Example of connecting two Unos together to communicate via I2C
ACK or NAK
The above graphic shows what happens if the slave device responds. Below is what happens if it doesn't. In this case I changed the address from 42 to 43, so that the slave would ignore the attempt to communicate with it.
This condition can be tested for in Wire.endTransmission(). That returns zero on success and various error codes on failure.
Timing
The timing for the entire transaction above (address byte and data byte) was that from the start condition to the stop condition took 0.2125417 milliseconds. Thus at that rate you could send around 4705 bytes per second. However that is a bit inefficient because half of it was the address. The time taken to send one byte was 96.3333 microseconds, which translates to 10,380 bytes per second. This is reasonable enough if you are just driving a LCD display or similar.
You can increase the clock speed by adding this line after "Wire.begin ();", like this:
Wire.begin ();
TWBR = 12;
With that in place, the speeds are 4 times as fast. So a single byte then takes around 28 microseconds.
Sample TWBR values
The formula for converting TWBR into frequency is:
freq = clock / (16 + (2 * TWBR * prescaler))
The default prescaler is 1, and the default value for TWBR (on the Uno etc.) is 72. Thus:
freq = 16000000 / (16 + 144) = 100000
TWBR prescaler Frequency
12 1 400 kHz (the maximum supported frequency)
32 1 200 kHz
72 1 100 kHz (the default)
152 1 50 kHz
78 4 25 kHz
158 4 12.5 kHz
To set the prescaler to 4 you need to set the bit TWPS0 in TWSR, so for example to have a clock of 12.5 kHz:
Wire.begin ();
TWBR = 158;
TWSR |= bit (TWPS0);
[EDIT] Updated 17 June 2012 to add the table of TWBR values and related frequencies.
Buffer Length
It isn't currently mentioned in the documentation, but the internal buffer used for I2C communications is 32 bytes. That means you can transfer a maximum of 32 bytes in one transaction.
It also isn't particularly clear, but the functions Wire.beginTransmission and Wire.write don't actually send anything. They simply prepare an internal buffer (with a maximum length of 32 bytes) for the transmission. This is so that the hardware can then clock out the data at a high rate. For example:
Wire.beginTransmission (SLAVE_ADDRESS); // prepare internal buffer
Wire.write ("hello world"); // put data into buffer
byte result = Wire.endTransmission (); // transmission occurs here
After calling Wire.endTransmission, if zero was returned, you know the call was a success.
Communicating with other devices
So all this I2C stuff is great, you can use just two wires (plus ground) to talk to up to 119 devices. But what if you have a device (like a keypad) that doesn't support I2C? Well, the simple answer is that you can use something that does as an interface. For example, a second Arduino. My examples above do just that, using one as the master and second one to display text on LEDs.
In fact, the "master" can also act as a slave, since you can have multiple masters on one wire. The example below shows how you can send data from one Arduino to another, whilst waiting for information to be sent from the second back to the first.
Master
// Written by Nick Gammon
// February 2012
#include <Wire.h>
const byte MY_ADDRESS = 25;
const byte SLAVE_ADDRESS = 42;
const byte LED = 13;
void setup()
{
Wire.begin (MY_ADDRESS);
Wire.onReceive (receiveEvent);
pinMode (LED, OUTPUT);
} // end of setup
void loop()
{
for (int x = 2; x <= 7; x++)
{
Wire.beginTransmission (SLAVE_ADDRESS);
Wire.write (x);
Wire.endTransmission ();
delay (200);
} // end of for
} // end of loop
void receiveEvent (int howMany)
{
for (int i = 0; i < howMany; i++)
{
byte b = Wire.read ();
digitalWrite (LED, b);
} // end of for loop
} // end of receiveEvent
[EDIT] Updated February 2012 to allow for version 1.0 of the Arduino IDE. This uses Wire.read rather Wire.receive, and Wire.write rather than Wire.send.
Slave
// Written by Nick Gammon
// February 2012
#include <Wire.h>
const byte MY_ADDRESS = 42;
const byte OTHER_ADDRESS = 25;
void setup ()
{
Wire.begin (MY_ADDRESS);
for (byte i = 2; i <= 7; i++)
pinMode (i, OUTPUT);
Wire.onReceive (receiveEvent);
} // end of setup
void loop()
{
int v = analogRead (0);
Wire.beginTransmission (OTHER_ADDRESS);
Wire.write (v < 512);
Wire.endTransmission ();
delay (20);
} // end of loop
// called by interrupt service routine when incoming data arrives
void receiveEvent (int howMany)
{
for (int i = 0; i < howMany; i++)
{
byte c = Wire.read ();
// toggle requested LED
if (digitalRead (c) == LOW)
digitalWrite (c, HIGH);
else
digitalWrite (c, LOW);
} // end of for loop
} // end of receiveEvent
[EDIT] Updated February 2012 to allow for version 1.0 of the Arduino IDE. This uses Wire.read rather Wire.receive, and Wire.write rather than Wire.send.
The examples above use addresses 25 and 42. Each device "registers" its own address with:
It also registers an interrupt handler to be called when the other end wants to send some data:
Wire.onReceive(receiveEvent);
Now one can send a stream of data to the second, while the second sends back a message if the value on analog port 0 drops below 512. Thus we have two-way communication.
Dedicated I2C expanders
Another (cheaper) approach is to simply use "16-port I/O expander" chips (such as the MCP23017). These connect to an I2C bus and provides 16 digital ports which can be configured as inputs or outputs depending on the chip. Most of these allow you to set some address bits (eg. via jumpers) so you might use 8 of the expanders (if you needed to!) connected to a single I2C line, with addresses like 000, 001, 010 etc.
I have seen these for sale at around $US 1.20, which is pretty cheap.
See this post for an example of driving an LCD screen with an I/O expander chip:
http://www.gammon.com.au/forum/?id=10940
Alternatively, the Atmega328 chip on its own is only $6, so the suggested approach above of using another microprocessor isn't all that expensive an option.
Here is an example of an expander board (the "Centipede"). This uses 4 x MCP23017 chips to give a whopping 64 I/O ports, at the expense of only two pins on the Arduino. This board comes with headers that let you connect cables and run to other boards where you might have measuring devices, or output devices.
Arduino Library
Pinouts on the Arduino Uno
Note that more recent Arduino Unos (R3 boards and above) have dedicated (extra) I2C pins (near the USB connector) as shown on the photo on this page: http://www.gammon.com.au/uno
That is in addition to being able to use A4/A5 (they are connected together).
[EDIT] Updated on 1 February 2013 to mention more reserved I2C addresses (1 to 7). |