Raspberry Pi and Arduino Connected Using I2C

by Oscar

With Raspberry Pi and I2C communication, we can connect the Pi with single or multiple Arduino boards. The Raspberry Pi has only 8 GPIO’s, so it would be really useful to have additional Inputs and outputs by combining the Raspberry Pi and Arduino.

Some of the links on this page are affiliate links. I receive a commission (at no extra cost to you) if you make a purchase after clicking on one of these affiliate links. This helps support the free content for the community on this website. Please read our Affiliate Link Policy for more information.

There are many ways of Linking them such as using USB cable and Serial Connection. Why do we choose to use I2C? One reason could be it does not use your serial, USB on the Pi. Given the fact that there are only 2 USB ports, this is definitely a big advantage. Secondly, flexibility. You can easily connect up to 128 slaves with the Pi. Also we can just link them directly without a Logic Level Converter.

In this article I will describe how to configure the devices and setup Raspberry Pi as master and Arduino as slave for I2C communication.

In the next article I will be doing some Voice Recognition, if you are interested see here Raspberry Pi Voice Recognition Works Like Siri

How Does It Work? Is It Safe?

The Raspberry Pi is running at 3.3 Volts while the Arduino is running at 5 Volts. There are tutorials suggest using a level converter for the I2C communication. This is NOT needed if the Raspberry Pi is running as “master” and the Arduino is running as “slave”.

The reason it works is because the Arduino does not have any pull-ups resistors installed, but the P1 header on the Raspberry Pi has 1k8 ohms resistors to the 3.3 volts power rail. Data is transmitted by pulling the lines to 0v, for a “high” logic signal. For “low” logic signal, it’s pulled up to the supply rail voltage level. Because there is no pull-up resistors in the Arduino and because 3.3 volts is within the “low” logic level range for the Arduino everything works as it should.

Raspberry-PI-I2c-Arduino-connected

Remember though that if other I2C devices are added to the bus they must have their pull-up resistors removed. For more information, see here.

These are the images showing where the I2C pins are on the Raspberry Pi and Arduino.

Note that the built-in pull-up resistors are only available on the Pi’s I2C pins (Pins 3 (SDA) and 5 (SCL), i.e. the GPIO0 and GPIO1 on a Rev. 1 board, GPIO2 and GPIOP3 on a Rev. 2 board:

I2C Raspberry Pi and Arduino Connect Link

On the Arduino Uno, the I2C pins are pins A4 (SDA) and A5 (SCL), On the Arduino Mega, they are 20 (SDA), 21 (SCL)

I2C Raspberry Pi and Arduino Connect Link

For information about the Arduino I2C Configuration and for other models of Arduino, check out this documentation Wire library.

Setup Environment on Raspberry Pi for I2C Communication

I will describe the process briefly here, if you are in doubt please refer to a more detailed process here and here.

Remove I2C from Blacklist:

$ cat /etc/modprobe.d/raspi-blacklist.conf
# blacklist spi and i2c by default (many users don't need them)
blacklist spi-bcm2708
#blacklist i2c-bcm2708

Load i2c.dev in Module File

Add this to the end of /etc/modules

i2c-dev

Install I2C Tools

$ sudo apt-get install i2c-tools

Allow Pi User to Access I2C Devices

$ sudo adduser pi i2c

Now reboot the RPI. After that you should see the i2c devices:

pi@raspberrypi ~ $ ll /dev/i2c*
crw-rw---T 1 root i2c 89, 0 May 25 11:56 /dev/i2c-0
crw-rw---T 1 root i2c 89, 1 May 25 11:56 /dev/i2c-1

Now we run a simple test, scan the i2c bus:

pi@raspberrypi ~ $ i2cdetect -y 1 
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Hint: if you’re using the first revision of the RPI board, use “-y 0″ as parameter. The I2C bus address changed between those two revisions.

Install Python-SMBus

This provides I2C support for Python, documentation can be found here. Alternatively, Quck2Wire is also available.

sudo apt-get install python-smbus

Configure Arduino As Slave Device For I2C

Load this sketch on the Arduino. We basically define an address for the slave (in this case, 4) and callback functions for sending data, and receiving data. When we receive a digit, we acknowledge by sending it back. If the digit happens to be ‘1’, we switch on the LED.

This program has only been tested with Arduino IDE 1.0.

[sourcecode language=”cpp”]

#include <Wire.h>

#define SLAVE_ADDRESS 0x04
int number = 0;
int state = 0;

void setup() {
pinMode(13, OUTPUT);
Serial.begin(9600); // start serial for output
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);

// define callbacks for i2c communication
Wire.onReceive(receiveData);
Wire.onRequest(sendData);

Serial.println(“Ready!”);
}

void loop() {
delay(100);
}

// callback for received data
void receiveData(int byteCount){

while(Wire.available()) {
number = Wire.read();
Serial.print(“data received: “);
Serial.println(number);

if (number == 1){

if (state == 0){
digitalWrite(13, HIGH); // set the LED on
state = 1;
}
else{
digitalWrite(13, LOW); // set the LED off
state = 0;
}
}
}
}

// callback for sending data
void sendData(){
Wire.write(number);
}

[/sourcecode]

Configure Raspberry Pi As Master Device

Since we have a listening Arduino slave, we now need a I2C master.

I have written this testing program in Python. This is what it does: the Raspberry Pi asks you to enter a digit and sends it to the Arduino, the Arduino acknowledges the received data by send the exact same number back.

In the video, I used a built-in programming tool called “IDLE” in Raspberry Pi for compiling.

[sourcecode language=”python”]

import smbus
import time
# for RPI version 1, use “bus = smbus.SMBus(0)”
bus = smbus.SMBus(1)

# This is the address we setup in the Arduino Program
address = 0x04

def writeNumber(value):
bus.write_byte(address, value)
# bus.write_byte_data(address, 0, value)
return -1

def readNumber():
number = bus.read_byte(address)
# number = bus.read_byte_data(address, 1)
return number

while True:
var = input(“Enter 1 – 9: “)
if not var:
continue

writeNumber(var)
print “RPI: Hi Arduino, I sent you “, var
# sleep one second
time.sleep(1)

number = readNumber()
print “Arduino: Hey RPI, I received a digit “, number
print
[/sourcecode]

For more read/write functions, check out this useful look up table for the functions.

Connect Your Arduino With Raspberry Pi

Finally, we need to connect the Raspberry Pi and Arduino on the I2C bus. Connection is easy:

RaspberryPI-I2c-Arduino

RPI               Arduino (Uno/Duemillanove)
--------------------------------------------
GPIO 0 (SDA) <--> Pin 4 (SDA)
GPIO 1 (SCL) <--> Pin 5 (SCL)
Ground       <--> Ground

To make sure this is working, run i2cdetect -y 1 again in the terminal, you should get something like this. 04 is the address we defined in the Arduino sketch.

pi@raspberrypi ~ $ i2cdetect -y 1 
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- 04 -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

That’s the end of this article, for results, please see video on top. From here, you can add sensors to the Arduino, to send data back to the Raspberry. Or have servos and motors on the Arduino that can be controlled from the Raspberry Pi. It’s just Fun.

Updates: 07/07/2013

Someone messaged me asking how to use logic level converter for i2c connection between Raspberry Pi an d Arduino. I happen to have a spare Logic Level converter, so I gave it a go.

This is how I connect them.

GPIO0 (SDA) -- | TX1  -- TX0 | -- A4 (SDA)
GPIO1 (SCL) -- | RX0  -- RX1 | -- A5 (SCL)
3.3V        -- | LV   -- HV  | -- 5V
GND         -- | GND  -- GND | -- GND

08745-04-L

But the result was a little weird. The data successfully sent to the Arduino, and the data was also received successfully from the Arduino on the Pi, but the data was wrong at the raspberry pi side.

  • When I sent number 1 to the Arduino, I got 0 back.
  • When I sent 2, I got 1 back.
  • sent 3 and got 1 back
  • sent 4 and got 2 back… etc…

I don’t know why this is happening, something to do with the converter? or maybe the connection is wrong? I don’t have time to figure this out. Since I can get it working without a logic level converter, i will leave it for now, if you do know why, please let me know.

Leave a Comment

By using this form, you agree with the storage and handling of your data by this website. Note that all comments are held for moderation before appearing.

112 comments

Zea 18th March 2020 - 1:29 pm

Just a heads up your code will only work up until 127 from that point arduino will still recive the correct number from the python program however what it gives back will overflow eg 128 will become 0, 129 will become 1 …

forum.dexterindustries.com/t/problem-if-i-send-a-value-greater-than-127-using-the-i2c-block/748

“The problem is that the values are interpreted as signed int8 and not unsigned Byte. ”
Although not a fault of your code but the underlying Wire() libraries.

You can easily test it with:

#I2C master
import smbus
import time
# for RPI version 1, use ?bus = smbus.SMBus(0)?
bus = smbus.SMBus(1)

# This is the address we setup in the Arduino Program
address = 0x04

def writeNumber(value):
bus.write_byte(address, value)
# bus.write_byte_data(address, 0, value)
return -1

def readNumber():
number = bus.read_byte(address)
# number = bus.read_byte_data(address, 1)
return number

for x in range(120, 256):
writeNumber(x)
print “RPI: Hi Arduino, I sent you “, x
time.sleep(1)
number = readNumber()
print “Arduino: Hey RPI, I received a digit “, number

Reply
Fahad 17th April 2019 - 11:18 pm

Can you please re-upload the python script in correct format?
Or use some editor so that we can copy the raw code without any syntax mistake please?

Reply
saket kumar 30th November 2018 - 12:15 pm

i got error
Enter 1-9:1
(‘RPI: HI MSP,I sent you’, 1)
Traceback (most recent call last):
File “i2cmsp.py”, line 24, in
number= readNumber()
File “i2cmsp.py”, line 12, in readNumber
number=bus.read_byte(address)
IOError: [Errno 5] Input/output error

Reply
zaenal 21st November 2018 - 2:38 am

thanks..
from indonesian

Reply
DODDA VINEELA CHANDRA 9th November 2018 - 6:50 am

hi,
can we use pi as slave and arduino as master using level shifter….
tanks a lot for your help

Reply
Raza 10th May 2018 - 4:28 am

Can I do this in java? I want to read an analog input using arduino and send the values to RPi. The application on RPi will be written in java. A reply will be highly appreciated and keep up the good work. People like you are really a beacon in the dark for newcomers like me.

Reply
Roni Segoly 11th April 2018 - 12:25 pm

Hi
Can you give an example of sending string from Arduino to raspberry using i2c?

Reply
Muhammad Tanzeel Khalid 16th March 2018 - 5:10 pm

Thanks Man…you helped me alot

Reply
jeenu 6th December 2017 - 8:47 am

how to connect ardupilot mega 2.8 to raspberypi:?

Reply
Wobex 31st October 2017 - 1:42 pm

On the contrary:
A level shifter is needet. Just take a look at the I2C-specs. Minimal hi input voltage = 0.7Vdd. The Arduino’s Atmega (which btw. has internal pullups – 20k to 40k – which will be activated by the wire library) needs 0.7 * 5V input level = 3.5V. The RPI can not provide this voltage level. The i2c transmission without levelshifter is faulty. In my application I had about 20% faulty i2c telegrams, which was quite bad. Using a levelshifter (two nMos & two pullup resitors on the 5V side) lead to an error free transmission.
Cheers Wobex!

Reply
Michael 21st April 2017 - 11:13 pm

Hey I think I know the reason for your wrong data.
The last bit is not arriving. Look at it in binary:
1 -> [00]1 -> 0
2 -> [01]0 -> 1
3 -> [01]1 -> 1
4 -> [10]0 -> 2

Reply
Robson 12th March 2017 - 12:56 am

Hello,

On the voltage level converter, I believe it is not necessary because I2C works with open collector (drain), and only Raspberry Pi would have pullup resistors enabled. So the bus will work at 3.3V correctly.

See this image:
i1.wp.com/maxembedded.files.wordpress.com/2014/02/i2c-bus-interface-a-closer-look1.png

Reply
Robson 11th March 2017 - 1:37 pm

Nice, but you can use USB (serial) instead

Reply
sridhar 17th February 2017 - 12:24 pm

i connected every thing according to your tutorial. but data is not transferring, i am using raspi3 model b, arduino uno.
i didnot get any errors while compiling. pl somebody help me to tell what type of erros may be.

Reply
Vince 13th November 2017 - 8:25 pm

I have exactly the same setup as you do, and I finaly achieve to make it work.(without logic lvl convert)

Please read carefully theses post, ( and others post)

first post: raspberry-wise
Rodrigo
7th February 2016 at 12:21 am

also this link from :
Kostas Maragos
31st July 2013 at 10:39 am

may help you too, give you some ideas :
github.com/kmaragos/raspi2cino

second post : arduino-wise

Daniel Eriksson
29th April 2014 at 10:01 pm

Reply
Roger Ram Jet 16th February 2017 - 11:49 pm

Firstly thank you for writing this blog. I have taken your code and made it work between a Raspberry Pi zero and Arduino type (DFRobot bluno beetle). Press ‘1’ and get ‘1’ back. I then modified your Python code so that it missed out the manual input and ‘1’ was programmed to ‘var’ all the time. So it just looped round. I added a delay of time.sleep(0.5) after the writeNumber command. After reducing the delay down to roughly 0.01 or there abouts I hit the, what I believe to be, the clock stretching bug of the Raspberry Pi which I have been struggling with. Apparently the Raspberry Pi doesn’t do clock stretching but the Arduino does and there lies the bug. Some I2C sensors don’t do clock stretching so they are fine with the Raspberry Pi. Again what I believe from research on the internet.
Again thank you for your code that confirmed that I hadn’t done something wrong with my code.

These statements are made in good faith but please do your own research.

Reply
Mirko Hessel-von Molo 6th July 2016 - 3:46 pm

Hi Oscar,

thanks for your tutorial. However, I’m a bit puzzled about your statement that the Arduino does not have pull up resistors installed. Quite to the contrary, from the Arduino documentation I gather that the ATMega microcontrollers do have pull up resistors on the I2C lines, albeit very weak ones (20k Ohms to 70 kOhms, see e. g. http://playground.arduino.cc/Main/I2CBi-directionalLevelShifter) which are enabled by the Arduino Wire library.

So as far as I can see, the hardware setup you’re proposing (using the Raspberry Pi pullup to 3.3 Volts) is a bit risky: When the I2C bus is idle, you have 3.3 Volts on the Raspberry Pi connected via the raspberry pullups and the arduino pullups to 5 Volts on the Arduino. Assuming the total resistance to be around 20 kOhms (the 1k8 resistors on the Raspberry don’t influence this much) this should lead to a continuous current of 85 micro-Ampere _into_ the 3.3 Volts port on the Raspberry. Can we be sure this is small enough not to mess things up on the Raspberry side?

Reply
Pavel 2nd July 2016 - 12:28 pm

Hi, Oscar, tell me pls, how i can connect more than 1 arduino? Maybe you have a article about it? Ore examples? I afraid try it myself. :-(

Reply
Oscar 9th July 2016 - 11:05 pm

no sorry i don’t, with I2C you should be able to connect more than 1 Arduino, you just need to set an unique address ID on each one… Google Arduino I2C you should be able to find a tutorial

Reply
Marco Tarantino 30th June 2016 - 11:04 am

Hi Oscar,

Thanks for your post. I’ve used the examples of code you posted here in a project of mine. Recently, I’ve put that code on github and only later it occurred to me that your code is, well, yours.

So, I would like to ask for your permission to share this code (you can find it here https://github.com/metis-vela/raspmetis/blob/master/data_fetch.py). Admittedly, the present version contains what I believe are 13 lines in common with yours, but I still think you’re the author of those lines and, moreover, in the history there is a verbatim copy of your code.

Reply
Linus 3rd June 2016 - 11:17 am

Just a quick correction while using that logic lever shifter the conection that you tried is wrong should be

GPIO0 (SDA) — | TX1 — TX0 | — A4 (SDA)
NC — |RXO — RX1 | NC
3.3V — | LV — HV | — 5V
GND — | GND — GND | — GND
NC ————–|RX1 — RX0 | —– NC
GPIO1 (SCL) — | TX1 — TX0 | — A5 (SCL)

also made de order more as it is on the pdb.

Reply
Verlene 17th February 2016 - 11:10 am

When some one searches for his necessary thing,
therefore he/she wants to be available that in detail,
thus that thing is maintained over here. ironsteelcenter

Reply
jep 22nd February 2016 - 3:23 pm

Hi Oscar,

The C++ code posted by Milliways2 didn’t compile for me, here’s a version that does.

Compile with g++ -o i2ctest i2ctest.c -l wiringPi

// I2cTest
//
// Based on https://oscarliang.com/raspberry-pi-arduino-connected-i2c/
// Requires WiringPi http://wiringpi.com/

#include
#include
#include

const int address = 0x04; // This is the address we setup in the Arduino Program
int fd;

int writeNumber(unsigned value) {
return wiringPiI2CWrite(fd, value);
}

int readNumber(void) {
return wiringPiI2CRead(fd);
}

int main(int argc, const char * argv[]) {
unsigned int var;
int number;

fd = wiringPiI2CSetup(address); // Automatically selects i2c on GPIO

while(true) {
std::cout <> var;
writeNumber(var);
std::cout << "Sent: " << var << std::endl;
number = readNumber();
std::cout << "Received: " << number << "\n\n";
}
return 0;
}

Reply
Rodrigo 7th February 2016 - 12:21 am

Hey Oscar,
great tutorial, thanks a lot!
It took me a while to make the code work in python3 but I finally made it!
You need to install python3-smbus and change a couple of things in the python script (linke fix indentation, cast value to an int in writeNumber , put parentheses in print functions, etc.)
I’m new to python but this code worked fine for me:

import smbus
import time
# for RPI version 1, use “bus = smbus.SMBus(0)”
bus = smbus.SMBus(1)

# This is the address we setup in the Arduino Program
address = 0x04

def writeNumber(value):
bus.write_byte(address, int(value))
# bus.write_byte_data(address, 0, value)
return -1

def readNumber():
number = bus.read_byte(address)
# number = bus.read_byte_data(address, 1)
return number

while True:
var = input(“Enter 1 – 9: “)
if not var:
continue
writeNumber(var)
print(“RPI: Hi Arduino, I sent you “, var)
# sleep one second
time.sleep(1)

number = readNumber()
print(“Arduino: Hey RPI, I received a digit “, number)

Reply
DeltaSL 29th October 2017 - 11:35 pm

Works=1
Great=1
Thanks for the int cast fix, works fine in Python shell. good starting point for my RGB proj.

thumbsUp=100

Reply
4ntoine 12th January 2016 - 12:55 pm

Check out ArduinoCode – Arduino IDE that runs on iOS but is able to compile and upload using Raspberry Pi: http://www.arduinocode.info/2016/01/raspberry-pi.html

Reply
BombDoc 22nd December 2015 - 12:35 am

Hi Oscar,

I am trying to send sketches from my rpi to arduino using a i2c connection.
I have a grove pi+ board on my pi 2 and a grove base shield on my arduino mega.
I have there neat cable that plugs into the i2c connectors on the bord. I cut the red wire from the cable. I can not get it to work, now is this a software problem or should I cross the yellow and white wires to get them talking. I am very new to this but I think it should work.

Reply
DeltaSL 30th October 2017 - 4:47 am

Future reference: you cannot PROGRAM an Arduino with i2c, only communicate with it.

Reply
Nicolas 20th December 2015 - 12:18 pm

File “i2cTest.py”, line 3
SyntaxError: Non-ASCII character ‘\xe2’ in file i2cTest.py on line 3, but no encoding declared; see python.org/peps/pep-0263.html for details / your script

Reply
Rob 23rd November 2015 - 7:43 pm

Hi Oscar, cheers for the small example! Quick and simple starting point for my setup :)

Reply
Paresh 18th November 2015 - 8:46 am

Hi Oscar,
I’m getting error “bus=smbus.SMBus(1) IOError[Error 2] No suh file or directory ” what should i do?

Reply
Vinay 10th November 2015 - 6:05 pm

Hi Oscar, Thanks a lot. Works like a charm.

Reply
dona 23rd October 2015 - 2:19 am

Hi Oscar,

I have a project that send data from arduino to raspberry via i2c.
I have tried your code and its work. Thanks!
The problem is, i want to reset the data that arduino sent to raspberry.
For now, i just do it with push the button in arduino to reset data.
But, i want now raspberry give a command to reset data in arduino.
How i could do this? its a bit confusing.

Reply
Kassus 12th December 2015 - 10:35 am

Hi Dona,

Maybe you should connect one of GPIOs to Arduino’s reset pin?

Reply
Ronda 14th July 2015 - 1:48 am

Hi Oscar,

Great information in this blog post! Thanks for sharing. I wanted to let you know about a kickstarter we have going for an I2C 8 GPIO Extneder board for the Arduino & Raspberry Pi. It will add 8 GPIO pins and will cost a lot less than another Arduino or RP board. The kickstarter is called “Really, Really Useful Breakout Boards for Your Raspberry Pi and Arduino”. Here’s a link if you’re interested; I’d love to hear your thoughts! http:// kck.st/ 1HYLam1

Reply
Bill Harvey 26th June 2015 - 4:12 pm

Hi;

This is a great guide that I desparately need to work however following some updates to Raspbian there are some errors in this guide such as setting up i2c and the sketch test code to set the Arduino to listen.
I know it says Arduino IDE 1.0 but is there an updated version of the guide anywhere??

The errors in Sketch are not many:

sketch_jun26a:17: error: stray ‘\’ in program
sketch_jun26a:17: error: stray ‘\’ in program
sketch_jun26a:29: error: stray ‘\’ in program
sketch_jun26a:29: error: stray ‘\’ in program
sketch_jun26a.ino: In function ‘void setup()’:
sketch_jun26a:17: error: ‘u201cReady’ was not declared in this scope
sketch_jun26a.ino: In function ‘void receiveData(int)’:
sketch_jun26a:29: error: ‘u201cdata’ was not declared in this scope

May be a copy and paste issue??

Reply
Jan 28th June 2015 - 9:12 am

Hi Bill,
i’ve had the same error.

You have to replace the “ with this one ” quotation marks.

I hope this will fix your error!

Jan

Reply
Bill Harvey 13th September 2015 - 10:20 pm

Sorry forgot to say thanks – yes it was a problem with the way the code copied from this web page :-)

Reply
Manju Hubli 14th August 2015 - 4:34 am

hey just delete whatever you have written in print or println statement and rewrite again ,you should get comment inside printf or println in green or skyblue(or other than black). now save and compile..
now your program is ready to upload….

Reply
Georg 4th February 2015 - 11:08 pm

re logic level converter:
I found a comment on watterott.com/en/4-channel-I2C-safe-Bi-directional-Logic-Level-Converter-BSS138
that hints that the problem with your trial might have been due to ‘I2C, which uses a funky pull-up system to transfer data back and forth’ and this particular converter (as shown in picture).
I am thinking about ordering the converter linked above and will report back if I succeed ;)

Reply
Drac 31st December 2014 - 5:18 pm

Your post has been very helpful for newcomers like myself.
I’ve been trying to control an led on arduino using a push button… And it worked. Then I attached a Raspberry pi and controlled the led on the arduino via i2c… It was fun!!!

But when I try to connect them both together( to be able to control via i2c and also using a push button on the arduino to on and off the same led) I run in to many troubles.
I would really appreciate it if you could show me a way to make it work!

Reply
nvw 27th December 2014 - 11:08 am

I’ve been digging a bit on this statement: “The reason it works is because the Arduino does not have any pull-ups resistors installed”

The ATmega328P chip datasheet shows SDA and SCL are bits of Port C, described as follows:
“Port C is a 7-bit bi-directional I/O port with internal pull-up resistors (selected for each bit)”

And the section specifically describing SDA/SCL says:
“Note that the internal pull-ups in the AVR pads can be enabled by setting the PORT bits corresponding to the SCL and SDA pins, as explained in the I/O Port section.”

Looking up the Arduino Wire library code I see the following:

The Wire.begin() & Wire.begin(int address) functions both call twi_init() which contains the following code:

// activate internal pullups for twi.
digitalWrite(SDA, 1);
digitalWrite(SCL, 1);

I understand from the above that ATmega328P based Arduinos do have pull-up resistors enabled when using the Arduino Wire library for the SDA/SCL pins and thus should not be used on a 3.3V i2c bus without a logical level converter.

What am I missing?

Reply
Bill Harvey 26th June 2015 - 10:50 am

I am about to connect a Rapsberry Pi Model B to an Arduino Nano ATMega-328P to control motors connected to the Arduino via a Web Page using Apache on the RPi.

Reading you post can I do this with or without a Logic Level Converter and if so which type? What about Serial connection via USB?

Reply
sandeep 20th November 2014 - 7:34 am

hi oscar,
i did all you posted and everything is ok, but whenever i run python code it gives error like these
——————————————————————————————————
root@raspberrypi:/home/pi# python test19.py
enter 1-9: 1
Traceback (most recent call last):
File “test19.py”, line 21, in
writeNumber(var)
File “test19.py”, line 9, in writeNumber
bus.write_byte(address, value)
IOError: [Errno 5] Input/output error
root@raspberrypi:/home/pi#
————————————————————

Reply
Oscar 21st November 2014 - 4:57 pm

because the device of that address you are sending the data to is not there. please google the error before asking.

Reply
Milliways2 8th November 2014 - 4:41 am

A c++ version of the test program

// I2cTest
//
// Based on https://oscarliang.com/raspberry-pi-arduino-connected-i2c/
// Requires WiringPi http://wiringpi.com/

#include
#include “wiringPi.h”
#include “wiringPiI2C.h”

const int address = 0x04; // This is the address we setup in the Arduino Program
int fd;

int writeNumber(unsigned value) {
return wiringPiI2CWrite(fd, value);
}

int readNumber(void) {
return wiringPiI2CRead(fd);
}

int main(int argc, const char * argv[]) {
unsigned int var;
int number;

fd = wiringPiI2CSetup(address); // Automatically selects i2c on GPIO

std::cout <> var;
while(var) {
writeNumber(var);
std::cout << "Arduino, I sent you " << var << std::endl;
number = readNumber();
std::cout << "Arduino, I received a digit " << number << std::endl;
std::cout <> var;
}
return 0;
}

Reply
Lin 17th September 2014 - 4:18 am

Hi, im new bie with raspberry.
I want to connect it to my arduino uno using i2c.
my question is:
1. ” 04 is the address we defined in the Arduino sketch. ” —> so couldn’t we change the address to 01 or 02 or ?
2. I send data from arduino to raspberry.
So i make counter in arduino then i send that counter to raspberry.
So far is it running well, my counter is 1,2,3,50,90,110,255 is it fine and raspberry can show data correctly.
But when it takes 256, raspberry turn into 0.
What happen with that? is it raspberry just can show my counter till 255? what causes it?
Thanks

Reply
Oscar 17th September 2014 - 12:16 pm

1. yes you can, from 0x00 to 0xFF I believe
2. because you are sending a byte (8 bits), which can only be 0 to 255, when you send 256, it overflows, and it will go back to 0.

Reply
chichara 15th September 2014 - 4:29 am

Hi, is it possible if 1 raspberry as a master connected to 5 arduino as a slave using i2c communication?

Reply
Oscar 15th September 2014 - 10:18 am

yes it is possible.

Reply
chichara 17th September 2014 - 4:56 am

Hi, so where i can connect pin SDA SCL? coz in raspberry just have one SDA and SCL.
Or GPIO can set as SDA SCL?
*sorry im beginner with this.

Reply
Oscar 17th September 2014 - 12:21 pm

same SDA SCL pins.
the RPI can identify each slave by their unique address.

Reply
Brian92127 7th August 2014 - 3:07 am

Excellent tutorial!
As a tip for anyone else trying this one: if you “copy/paste” the python code make sure you delete all of the “spaces” and replace them with “tabs”. For every 4 spaces I deleted I replaced them with 1 tab. Eight spaces deleted equals two tabs, and so on. Also, there are a couple of blank lines that are not actually blank. Python recognizes a “space” and will choke on it so make sure to delete/remove the “spaces” from the blank lines as well. Thanks again Oscar!

Reply
Oscar 7th August 2014 - 12:20 pm

yes, it is a problem with python source code on my blog, it somehow changes the indentation of the code… and python relies on it…
Thank you for the tip!

Reply
eco_bach 18th July 2014 - 7:57 pm

Hey Oscar. Great post!
But 2 problems.

1- Sending values larger than 255!

2- Sending a continuous stream of data . My goal is to send MouseXY data in realtime.

Since I am a novice arduino hacker, haven’t made much progress.

Reply
Oscar 21st July 2014 - 10:03 am

Hi eco_bach,

depends on what the possible maximum number you would send, then you should work out how many bytes of data needs to be sent, in order to represent that max number. For example if you send 2 bytes of data, it represents a number between 0-65536.
And now, modify the receiving side code, as you will expect to receive 2 bytes of data every time.

Reply
Dimas 10th April 2018 - 8:21 pm

hi oscar, i want to send 2 bytes of data, so what i have to change in the code of raspberry?

Reply
Guillaume L. 5th July 2014 - 10:47 am

Thanks!

Perfect tutorial!

Two reamarks :
“ll /dev/i2c*” required the uncommented alias ll in file “.bashrc” (or using ls -la)

If you use a Arduino Leonardo pins are :
Pin 2 (SDA)
Pin 3 (SCL)

Reply
Oscar 5th July 2014 - 11:44 am

Cheers Mate! :)

Reply
Mike W 23rd February 2015 - 2:15 pm

Further, I was just following this on 2015-02-16 of Rasbian and had to use sudo to see anything under /dev/i2c.

Reply
Daniel Eriksson 29th April 2014 - 10:01 pm

Hi.

I would like to share some important info regarding Wire library on Arduino. I spent many hours debugging communication on the Raspberry Pi when I randomly got “IOError: [Errno 5] Input/output error”.

Don’t put heavy code in receiveData() function on you Arduino. This code is called from an interrupt and to execute code here will disrupt communication. I suggest you to put received data in your own buffer and close the function as soon as you can.

Like this:

unsigned char tmpBuffer[120];
unsigned char currentPos = 0;

void receiveData(int byteCount){
unsigned int number = 0;
currentPos = 0;
while(Wire.available()) {
number = Wire.read();
tmpBuffer[currentPos] = number;
currentPos++;
}
}

Good luck!

/Daniel

Reply
kay 29th April 2014 - 2:20 pm

Not sure if anyone said this already but that particular logic level converter is not suitable for I2C, that is why you are getting errors. Try this one adafruit.com/product/757 from adafruit or look for I2C converters that are I2C compatible

Reply
Bobbie 20th February 2014 - 9:13 pm

Magnificent web site. Plenty of helpful info here.
I am sending it to a few pals ans additionally sharing in delicious.
And naturally, thanks on your sweat!

Reply
Moises 28th January 2014 - 12:28 am

There’s definately a great deal to find out about this topic.
I really like all the points you’ve made.

Reply
laviritel 7th January 2014 - 11:39 pm

Hello.
Thanks for this great tutorial. Everething works fine.
I have one question, maybe You can help me. For example, I’m going to send a byte array from arduino to RPi, my array looks like this:
sysState[0]=00000001
sysState[1]=11111111
I send it this way:
Wire.write(sysState,sizeof(sysState))
And the question is, it is possible to read this two values in Python on RPi? At moment I receive only first value. Thank you again.

Reply
Oscar 8th January 2014 - 11:30 am

I actually tried to do that as well, but because I am not familiar with Python, and there isn’t much information about i2c communication with Python on the internet, I couldn’t find a way to do it. I would suggest reading it byte by byte if you are not getting the answer from anyway.

Reply
Lenard 29th December 2013 - 11:36 pm

Hi, its nice post concerning media print, we all be aware of media is a wonderful source of data.

Reply
Ramonita 14th December 2013 - 3:15 am

Hello, I enjoy reading all of your post. I like to write a little comment to support you.

Reply
Avinash Babu 5th December 2013 - 2:18 am

hi
can we connect multiple Arduino Uno boards to Rapberry pi ? can you provide any link or explain procedure for connecting multiple Arduino uno boards to Raspberry pi ?
thanks for your help in advance………………………………..

Reply
Oscar 5th December 2013 - 9:17 am

yes, like I said in the post you can link up to 128 devices. You just need to assign each on with a different address. sorry i can’t give you more explanation right now, hope that helps.

Reply
panic 30th November 2013 - 5:06 pm

Hi i have absolutely the same issue here i don’t get it. did you find a way to manage multibyte send from arduino ??
thanks

Reply
Balazs 12th November 2013 - 5:03 pm

Hi!
I would like to transfer multiply bytes at once. With the python method “bus.write_block_data()” I was able to do this in direction to Arduino.
But I cannot transfer more bytes from the Arduino. I guess I should use the Wire.write(resultBuffer, resultLen); on the Arduino side, but “bus.read_block_data()” does not make the Arduino to enter the sendData() callback.
Anyone has a hint on this?
Thx,
Balazs

Reply
Javier 26th January 2018 - 11:45 pm

Same here! Did you find any solution after all this time?

Reply
boy 17th October 2013 - 8:56 am

I have a bit of a trouble here.

I did all the instruction until i2cdetect -y 1 in the terminal
and it shows the address 04.

The problem is when I tried the program above no matter what I wrote the arduino would not response . I have no idea what is wrong. I tried update and upgrade the Rpi the result is still the same. Is it possible that the pi is broken?

Thanks in advance for the answer

Reply
boy 22nd October 2013 - 7:24 am

I managed to solve the problem, seems like the psition of variable print in the code needs to be parallel with number. Thanks a bunch for the code

Reply
shivam 16th February 2016 - 5:56 pm

Hi boy,

I am facing the same issue

Can you please let me know the exact code to which you are referring?
where is this variable print?

Thanks in advance for your help

Reply
shivam 16th February 2016 - 6:22 pm

Hi boy,

I made it worked

Few indention mistakes.

Reply
Brian 6th October 2013 - 3:53 pm

Absolutely AWESOME article. I was able to get my Rpi rev2 talking to my arduino micro in no time and your sample code and instructions were spot on!
One problem I encountered was a sequence issue resulting in Rpi not booting up.
When physically wired between Rpi GPIO and Arduino you MUST have Ardiuno code running and it be available for communication. If not, my Rpi would lock up in boot. Took me a little while to figure out and was a bit alarming at first but quickly figured it out.

Thank you for this AWESOME tutorial on i2c with Rpi and Arduino!

Reply
John 6th October 2013 - 12:28 am

I don’t know how the Sparkfun converter is made, but the circuit in the Philips AN97055 document works perfectly using your code between the Pi and Arduino.

http://www.nxp.com/documents/application_note/an97055.pdf

Reply
Oscar 10th October 2013 - 11:24 am

great to hear that, but it works without one anyway… (it’s been a while and it’s still running…)

Reply
Frans Merrild 26th August 2013 - 7:41 pm

Hi,

I am doing a new project with the Raspberry PI, and we are doing a sensor board consisting of PIR, IR, temperature, humidity, air quality sensor, siren, andcamera.

What do you think would be the best way to integrate these sensors to the Raspberry PI. Do we need to have an external processor board, or might we just as well connect all of these directly to the Raspberry PI?

Reply
Oscar 27th August 2013 - 11:09 am

is it like a weather station kind of thing? :-)
I think you can get those sensors with I2C communications, and connect them directly to the raspberry pi!

this sounds very interesting I might do a separate post for it!

thanks for sharing the idea.

Reply
Marcelo 20th August 2013 - 12:43 am

Try to use only the TX of the Logic Level converter from Sparkfun.
TX are bi-directional.
RX are uni-directional.
GPIO0 (SDA) — | TX1 — TX0 | — A4 (SDA)
— | RX0 — RX1 | —
3.3V — | LV — HV | — 5V
GND — | GND — GND | — GND
GPIO1 (SCL) — | TX1 — TX0 | — A5 (SCL)

Reply
udelunar 19th August 2013 - 6:00 pm

Hi!!
i try send string, but i cant :(…. how i send??

Thx!!!

Reply
Kostas Maragos 31st July 2013 - 10:39 am

Hey Oscar, thank you for this great post.

I finally got to trying it out myself and I had trouble getting it to work on my Raspberry Pi running Arch Linux. The package python-smbus does not seem to be available for Arch Linux.

After some research, I decided to give Quick2Wire a try. After modifying the code, it worked like a charm. I have created a repository on github (https://github.com/kmaragos/raspi2cino) hoping it might help others. FYI, I have tested this with an Arduino Pro Mini, Nano and Uno.

I have included the URL to your post. I hope it is ok with you. Let me know if there is any other specific attribution method I should use. Thanks again for an amazing tutorial!

Reply
Oscar 31st July 2013 - 10:44 am

Hi Kostas

Absolutely fine, that’s very kind of you created a open source project for this! :-)

Cheers
O.

Reply
Pablo Torres 30th July 2013 - 11:28 am

Hi, sorry to disturb you, I have a very important question, I have a project in my house where I use an arduino board in each room to control everything that is on that room. I want to command this arduinos (8) from a tablet running android, how can i do it? Using wifi on each one? Using Bluetooth on each one? Using one as a master and connecting this one to the rest and to the tablet? Doing the same but using a raspberry pi? Can you help me? Just point me the direction you think it’s better. Thanks so much

Reply
Oscar 30th July 2013 - 11:47 am

You are limited to 2 choices by the Androoid Tablet, Bluetooth (BT) or Wifi.

BT is quite easy to use on Arduino, but it’s very range limited. Not to mention you have 8! I am not sure if Bluetooth can support that many connections at the same time on the Arduino (i have not looked into this)

Another option would be wifi. It’s not common to use wifi on Arduino (have not seen people implemented this) what are you controlling in each room?

I personally would use Raspberry Pi to replace the Arduinos for what you described, because it supports wifi (which has longer range than BT), and all clients can connect to the network at the same time. If you are short of GPIO or need Analogue I/O, you can always extend it by adding new components.

Reply
tweety 22nd July 2013 - 2:41 pm

Hello Oscar,

Very good tuto. Tested and … working. But is it really safe AND reliable ? Reading on internet, some says yes some say no ! I’m quite lost.

And what do you mean by “Remember though that if other I2C devices are added to the bus they must have their pull-up resistors removed”. I have a ds18b20+ sensor. You mean that I dont have to use the 4.7k resistor ?
Do you have a sample schema for connecting those other i2c devices.

@Dantheman2865 : you mean the spakfun module is not working for linking raspberry and arduino ?

Reply
Oscar 22nd July 2013 - 2:49 pm

hey~ thanks for the comment.
It is very controversial whether we should connect both devices directly.

Like I explained there are pullup resistors on the Pi, so in theory it should be okay (I have been using this configuration since I wrote this tutorial, I have not had any problem with it yet.)
But if you are not confident and doesn’t want to take the risk, USE a level converter. They are so cheap (~$1) so there is no reason why you shouldn’t do more to protect your pi.

Reply
Dantheman2865 18th July 2013 - 8:55 pm

I think the reason your Level Shifter doesn’t work is because it’s uni-directional. If that’s the Sparkfun Level Shifter, you need to use Transmit and Receive properly based on the circuitry involved. I2C has one uni-directional signal (Clock) and one *Bi*-directional signal (Data). There is some circuit theory behind this, but here is a product that will work for you: https://www.adafruit.com/products/757

Reply
Oscar 18th July 2013 - 11:47 pm

that could be the reason, I didn’t really look at the specification when I was using it, so you might be right!
Thanks for the pointing that out! :-)

Reply
merill 6th August 2013 - 1:11 pm

For me, the line with resistor is uni-directional but the line with the transistor is bi-directional.
When i’m using it, i let the two resistor-line alone and i use the two other (extreme Right, extreme left).
Less hassle.

Reply
Gus Smith 16th July 2013 - 4:59 am

Just tested it and the code works fine!

Cheers,
Gus

Reply
Jason 15th July 2013 - 5:42 pm

Hello!
I really appreciate your entry and the help it provides!

One note, though – in Python, the Print command requires a value set by print(value).

You leave out these parentheses, which will trigger syntax errors if left.

Thanks again!

Reply
Jason 15th July 2013 - 7:52 pm

Actually, it looks like I was wrong. In this case, it can work without the parentheses, although I do think it is more “hardy” if you leave them in. This will allow the code to function even if there is a mistype somewhere along the way.

That said, the code printed above DOES WORK (woo!) and the only reason you would need the parentheses is if you did something differently.

Reply
Oscar 15th July 2013 - 8:29 pm

thank you for the comment, I am not familiar with Python, so I don’t really know if leaving the parentheses would cause any problem potentially, but it did work like you said. Anyway, what I was trying to achieve with “print” without any argument is to create a newline, so if any problem occur because of this, we can just add “” to it as argument i guess…

Reply
Piero 14th July 2013 - 10:23 pm

Hello,
thanks for this nice tutorial.

I’m trying to make it work, with Rpi REV1 and Arduino 2009/Arduino UNO. Connections are ok (I think), because when I run i2detect -y 0 I see this (Ihave two MCP23017 also connected to i2c):

$ i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: — 04 — — — — — — — — — — —
10: — — — — — — — — — — — — — — — —
20: 20 21 — — — — — — — — — — — — — —
30: — — — — — — — — — — — — — — — —
40: — — — — — — — — — — — — — — — —
50: — — — — — — — — — — — — — — — —
60: — — — — — — — — — — — — — — — —

but when I run the python script, I see:

python i2c_arduino.py
Enter 1 – 9: 1
Traceback (most recent call last):
File “i2c_arduino.py”, line 24, in
writeNumber(var)
File “i2c_arduino.py”, line 10, in writeNumber
bus.write_byte(address, value)
IOError: [Errno 5] Input/output error

any suggestion? I missed something?
Thank in advance for you help

Reply
Oscar 14th July 2013 - 10:41 pm

sorry I don’t have a Rev1 Rpi, so I can’t replicate your problem. have you tried the commented out function:
bus.write_byte_data(address, 0, value)

Also, make sure the cabling is correct, because the pin arrangement has changed from Rev1 to Rev2.

Reply
Piero 20th July 2013 - 11:14 pm

Hello,
thanks for your answer and sorry for my late reply

It was my NEWBIE and distraction error… I have REV 1 Pi, so
bus = smbus.SMBus(0)
and not
bus = smbus.SMBus(1)

:-)

now all seems to be working fine, thanks again

Reply
Oscar 21st July 2013 - 2:35 am

oops~ :-D
That’s so nice of you letting me know!
Grazie tanto!

Reply
Clayton Lambert 1st July 2013 - 8:22 pm

Hey, thanks for the great walkthrough! I got it working no problems with continuous servos and leds for a robot. I’m looking for another guide to help me make a web gui which can interface with this setup (and can also do video) any suggestions?

Reply
Oscar 1st July 2013 - 9:03 pm

Hi, I think that’s a very interesting idea to create a web GUI to enhance this project! I might actually do some work and write a post on this (just a thought)

If I was going to do it
1. I will setup a web server on my laptop/PC, maybe using Apache.
2. Build the web GUI in HTML/PHP/Javascript, you will be using this GUI on your client (laptop/PC)
3. We can send data from the Pi to the web server using GET or POST in Python, which can be interpreted in PHP on the server.
4. That data will be sent to the web GUI client from the web server.

does that make sense? Any better idea?

Reply
Clayton Lambert 15th July 2013 - 2:17 pm

That makes perfect sense. I’m just a bit of a novice when it comes to programming especially when it comes down to multiplatform interfacing. If you could create a guide I would greatly appreciate it. Using your modified code I was able to remotely drive a arduino-pi robot around my room over wifi from the inputs into python while my laptop was vnc’d into the raspberry pi. It works fine but a web based gui would be much slicker. Thanks in advance!

Reply
Jon 30th June 2013 - 3:04 pm

Thanks for the tutorial. I’m having a bit of trouble, though. My pi is recognizing my arduino when I type i2cdetect -y 1, but when I run the python script, nothing seems to be sent or returned. In order to get the py script to work properly, I had to tab over lines 25 – 33. I don’t know python, but I don’t see how that could have affected the I2C… the script ran and asked for a digit, but the Arduino doesn’t show anything. I’d appreciate any help. Thanks!

Reply
Oscar 1st July 2013 - 9:09 pm

by “tab over” you mean create indentation? I don’t know Python very well either, but I do know that Python is very strict about line indentation. Because it doesn’t use the semi colon ; like C or C++, wrong indentation could make your code get executed completely differently.

Reply
fm3391 3rd June 2013 - 5:05 pm

I followed this tutorial but I have a problem where no matter what integer I put in, I get the integer 9 back.
Example:
RPI: Hi Arduino, I sent you 1
Arduino: Hey RPI, I received a digit 9
or
RPI: Hi Arduino, I sent you 7
Arduino: Hey RPI, I received a digit 9

Reply
Oscar 3rd June 2013 - 5:28 pm

really? did you check on your arduino terminal? what number do you get there?

Reply
Goe 3rd June 2013 - 9:19 pm

I have the same exact problem. No matter what integer I put in, I get integer 9 back. I’m on Rev. 1 of Rasperry Pi, and I’m using I2C Bus 0.

Reply
Goe 3rd June 2013 - 9:33 pm

On the Arduino Serial terminal, this is what I see if I send a ‘6’:
Ready!
data received: 0
data received: 6
data received: 1

For some reason, 2 additional bytes are always sent… a ‘0’ in front, and a ‘1’ behind the byte that I select.

Reply
Goe 3rd June 2013 - 9:46 pm

Figured it out… for some reason, the python code was not working properly.

Had to replace the write_byte_data() with write_byte() and the read_byte_data() with a read_byte() for things to finally work. Not sure why… I’m new to i2c

Reply
Oscar 4th June 2013 - 1:21 am

you are absolutely right, the write_byte_data() has a ‘cmd’ parameter, it’s part of the data transferred, that’s why you are getting the extra byte zero.

This is entirely my fault, I made a change in the codes, updated this post a couple of days after it was posted. I think I must have forgotten to update the Python code. I will do so now. The reason for the change is that I am still not confident with the write_byte_data() function (couldn’t find any good documentation about it), that’s why I used write_byte() as well at the end.

Thank you very much for pointing that out!