Connecting an Arduino to a Raspberry PI using I2C

Some time ago I created a weather station using a Raspberry PI and an off the shelf weather station, connecting the two via USB.

However, for some time not I’ve been meaning to create a weather station from scratch – i.e. one or more Raspberry PI’s which connect to the network (via Ethernet or WiFi) and directly monitor the sensors directly.

Now the problem here is that some sensors are analog – for example the leaf, soil and UV sensors I have generate an analog signal so we need an ADC (Analogue to Digital Converter) which the Raspberry PI doesn’t have.

So we have two possible solutions:

  1. Add a Raspberry PI compatible ADC
  2. Use an Arduino

With the parts I have available, the Arduino won, not just on available ADC channels but also with the additional digital ports available.

Now how to connect it to the PI? Well the easiest way is to use USB, however the PI only has two USB ports (one for the Model A) and as I’m intending to use Model A’s for the final station I need that for WiFi (there won’t be room or power for hubs) so USB is out.

There’s RS232 which both support, however the PI runs on 3v3 whilst the Arduino (UNO) is 5v so I need to add a level converter between the two. It also limits me to just one arduino and I might need to use more than one so another solution is needed.

Enter I2C

Both the PI and Arduino support two additional types of communication for talking to peripheral devices. There’s SPI which is a high speed serial protocol and I2C. Like RS232, SPI needs level shifters, but not exactly so for I2C.

I2C is a 2 wire protocol allowing for 127 devices to be connected to a single bus. One device is the master (The PI in our case) and then the peripherals.

An example I2C network (From Wikipedia)
An example I2C network (From Wikipedia)

In the above diagram you can see that there’s two connections between devices (other than ground), SDA (Serial Data Line) which is where the data is carried, and SCL (Serial Clock Line). There’s also a pair of resistors which pull up the signals to Vdd.

Now the trick, Vdd is only there to pull those signals up and in I2C a 1 is when the signal is pulled down to 0V. It’s not there to power the devices so, as long as we keep Vdd at 3v3 and no device has a pull up resistor on them (i.e. to 5V) then we are save to connect it to the PI. There’s only a problem if any device on the I2C bus also has a pull up resistor.

Now do the Arduino’s have pullup resisitors? Well they actually don’t, they actually cannot as the I2C interface is shared by two of the analogue inputs (4 & 5 to be precise) so there cannot be a resistor there else it would affect those pins when not being used for I2C.

So, we have a solution as long as the Raspberry PI is the I2C Master which is what we want. Also, of the available GPIO pins, only SDA and SCL have pull up resistors, so we are set.

First the obligitory warning

If you are uncertain of anything, like blowing up your PI etc then don’t follow this any further. You do this at your own risk.

Configuring the PI for I2C

First we need to enable the I2C module on the PI.

Remove I2C from the module blacklist

As root edit /etc/modprobe.d/raspi-blacklist.conf and comment out the line blacklisting i2c-bcm2708

$ 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

Next add i2c-dev to the /etc/modules file so it’s loaded on boot:

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
# Parameters can be specified after the module name.

snd-bcm2835
ipv6
i2c-dev

Finally install i2c-tools:

$ sudo apt-get install i2c-tools
$ sudo adduser pi i2c

Now reboot the PI.

Configuring the Arduino

The following sketch implements a simple I2C slave with two commands:

Command 1 will toggle the onboard led on the Arduino.

Command 2 will return the arduino’s temperature in Celsius.

#include <Wire.h>

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

double temp;

void setup() {
 pinMode(13, OUTPUT);

 // initialize i2c as slave
 Wire.begin(SLAVE_ADDRESS);

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

void loop() {
 delay(100);
 temp = GetTemp();
}

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

 while(Wire.available()) {
  number = Wire.read();

  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;
   }
  }

  if(number==2) {
   number = (int)temp;
  }
 }
}

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

// Get the internal temperature of the arduino
double GetTemp(void)
{
 unsigned int wADC;
 double t;
 ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
 ADCSRA |= _BV(ADEN); // enable the ADC
 delay(20); // wait for voltages to become stable.
 ADCSRA |= _BV(ADSC); // Start the ADC
 while (bit_is_set(ADCSRA,ADSC));
 wADC = ADCW;
 t = (wADC - 324.31 ) / 1.22;
 return (t);
}

The Raspberry PI client

Here’s a simple C application which will now talk to the Arduino over I2C:

#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

// The PiWeather board i2c address
#define ADDRESS 0x04

// The I2C bus: This is for V2 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-1";

int main(int argc, char** argv) {

  if (argc == 1) {
    printf("Supply one or more commands to send to the Arduino\n");
    exit(1);
  }

  printf("I2C: Connecting\n");
  int file;

  if ((file = open(devName, O_RDWR)) < 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
  }

  printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

  if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
  }

  int arg;

  for (arg = 1; arg < argc; arg++) {
    int val;
    unsigned char cmd[16];

    if (0 == sscanf(argv[arg], "%d", &val)) {
      fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
      exit(1);
    }

    printf("Sending %d\n", val);

    cmd[0] = val;
    if (write(file, cmd, 1) == 1) {

      // As we are not talking to direct hardware but a microcontroller we
      // need to wait a short while so that it can respond.
      //
      // 1ms seems to be enough but it depends on what workload it has
      usleep(10000);

      char buf[1];
      if (read(file, buf, 1) == 1) {
	int temp = (int) buf[0];

	printf("Received %d\n", temp);
      }
    }

    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
  }

  close(file);
  return (EXIT_SUCCESS);
}

Save that as main.c and compile it:

pi@mimas ~ $ gcc main.c -o main

Now you’ll notice there’s a couple of usleep() waits in this code, once between sending the command and again after reading the response. I’ve found that this is necessary for two reasons.

  1. The arduino is emulating an I2C device, so it won’t respond immediately unlike a dedicated device so you need to wait a short while before reading it otherwise you won’t get a response.
  2. Without the second delay you can confuse the arduino by requesting another command too quickly, necessitating the arduino to be reset before it can be used again.

I found that 10000 (10ms) is enough here.

Wiring the two together

Now this is simple: First power down both the Arduino and the Raspberry PI – never connect things whilst they are powered up!

Next simply connect the two with 3 wires using the following table:

Raspberry PI Arduino
GPIO 0 (SDA) <–> Pin 4 (SDA)
GPIO 1 (SCL) <–> Pin 5 (SCL)
Ground <–> Ground

Testing

Power up both the Arduino and Raspberry PI.  Once it’s up and running log in and run i2cdetect:

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

What you are now seeing is a list of all I2C devices connected. The one you are interested in is 04 which happens to be your arduino.

Lets toggle the led:

pi@mimas ~ $ ./main 1
I2C: Connecting
I2C: acquiring buss to 0x4
Sending 1
Received 1

You should now see the onboard led turn on. Run it again and the led goes out.

How about the temperature?

pi@mimas ~ $ ./main 2
I2C: Connecting
I2C: acquiring buss to 0x4
Sending 2
Received 35

35 just happens to be the Arduino’s internal temperature in Celsius (in this example we’ve just returned the integer temperature).

That’s about it. The next thing I now need to do is to get those additional sensors working with the arduino and wrap them in an I2C slave.

Oh, one last thing, as I said earlier and in that diagram, you can have many devices on the one I2C bus, so to add another arduino all you need to do is to connect the three wires to that arduino as well and make certain it is using a different address.

Author: petermount1

Prolific Open Source developer who also works in the online gaming industry during the day. Develops in Java, Go, Python & any other language as necessary. Still develops on retro machines like BBC Micro & Amiga A1200

62 thoughts on “Connecting an Arduino to a Raspberry PI using I2C”

    1. Normally you would be right but here we are driving the i2c bus at the pi’s voltage not that of the arduino, hence the retirements of the pi being the master & no pull up resistors on the slaves as the Pi’s resistors run the bus at 3V3

  1. The Arduino sketch does delay the I2C slave communication of the Arduino accidentially in it’s loop() method.
    If you would only read the temperature when really needed or by breaking up the “delay(100);” into a more sophisticated non-blocking delay (shorter delay or only read temperatures every 100 milliseconds by using the “millis()” method) the responsiveness of the Arduino as the I2C slave should greatly improve.

    1. Yes, the sketch is there as an example to show it actually working whilst keeping things as simple as possible, although thanks for pointing this out. I had based this on several other articles so I’m not the only one to get caught out on that snag.

      That said, it’s the first time I’ve done I2C on the arduino side, so easily done.

  2. Thank you Peter…very beautiful post!
    It’s a very good start for my project on a weather station!!!

  3. Thanks for the post. It all works as flawlessly, except I get a ‘Segmentation fault’ when I try and close ‘file’ just before the return. Do you have any idea why that would be?

    Thanks.

    1. Never mind, I see the problem. It should be closing the file with a ‘close’ not ‘fclose’.

      Thanks again.

  4. There are now some html problems getting into the RasPI C++ source code. If you get problems with & lt; (no spaces) this should be the < less than symbol. & amp; should be replaced with the & ampersand symbol.

    on line 73 change:
    fclose(file);
    close(file);
    since the file was opened with open and not fopen. This will fix the warning during compilation and the Segmentation fault echoed after the temperature reading when running.

    Thanks for the code Pete, this really helped me get started connecting Arduino and RasPI

    1. Thanks for spotting that, not sure how fclose() got in there as I had copied it from my working copy at the time.

      As for lt & <, it's a problem I've had with wordpress, sometimes it breaks code whilst writing, can be a real problem when trying to put xml into an article.

  5. pi@raspberrypi ~ $ gcc main.c -o main
    main.c: In function ‘main’:
    main.c:27:39: error: ‘lt’ undeclared (first use in this function)
    main.c:27:39: note: each undeclared identifier is reported only once for each function it appears in
    main.c:27:41: error: expected ‘)’ before ‘;’ token
    main.c:34:42: error: expected ‘)’ before ‘;’ token
    main.c:41:30: error: expected ‘)’ before ‘;’ token
    main.c:45:39: error: ‘amp’ undeclared (first use in this function)
    main.c:45:42: error: expected ‘)’ before ‘;’ token
    main.c:73:3: warning: passing argument 1 of ‘fclose’ makes pointer from integer without a cast [enabled by default]
    /usr/include/stdio.h:234:12: note: expected ‘struct FILE *’ but argument is of type ‘int’

    i create main.c and try 2 gcc it…
    whats wrong?

    1. In the 2 if statements theres < which should actually be < – I've fixed it in the article now.

      It's an old problem with wordpress reformatting code examples when it shouldn't do.

      1. you got most of them. Line 41 and 45 still has that html code for the characters sneaking in on you.

      2. pi@raspberrypi ~ $ gcc main.c -o main
        main.c: In function ‘main’:
        main.c:41:22: error: ‘lt’ undeclared (first use in this function)
        main.c:41:22: note: each undeclared identifier is reported only once for each function it appears in
        main.c:41:30: error: expected ‘)’ before ‘;’ token
        main.c:45:39: error: ‘amp’ undeclared (first use in this function)
        main.c:45:42: error: expected ‘)’ before ‘;’ token

        I am a loser 🙂

      3. No the wordpress editor occasionally substitutes html entities in source code. I’ve fixed the example for the second time now, so it should work now.

  6. I’ve been struggling to get reliable communication between my raspberry pi and an arduino micro. It works 99% of the time and fails 1% of the time.

    I attached a logic analyzer. When the address of a slave is sent over the bus, there is a short acknowledge step. When communication fails, for the first bit after this step, the clock consistently looks weird. Either there’s a long clock cycle, or a super-short one. I’ve tested many times now. After searching on the web I found that it is known that some Atmel devices “stretch” the clock at this point. This is legal, but the current raspberry pi drivers don’t know how to handle this correctly and the communication fails. If you write your code defensively you can deal with this but you may need to watch out for this. I’m going to try SPI instead…

    Slowing the clock makes it fail less often. Haven’t checked this case with the logic analyzer.

    1. Sorry for the late reply. As you point out This is a known issue with the current I2C kernel drivers and clock stretching.

      What I’ve been doing to get around this problem is I manually add delays to my code – one after sending the command and before reading the response and another after the response.

      The delay size doesn’t have to be much but it varies per device, so having an Arduino on it usually has a longer delay depending on the code it’s got to run.

      The other trick I use in the weatherstation project is that I ensure that all I2C calls are run sequentially by using a dedicated thread. I found that if I tried to run concurrent commands on the I2C bus it always caused problems.

      SPI is an option – the problem I have is that I have multiple devices that are I2C only (the UV Index sensor is one) but the solution I now have works pretty well.

      For info to anyone else reading this:

      1. The problem is, the issue happens within the space of a single call to the wire library and I don’t see how delays around those calls can change anything and I’m finding delays don’t help. (Delays make the system run for longer, but that’s only because it does less!) But the Arduino is surely a fairly a deterministic device so there must be *something* that makes the Arduino delay sometimes and not other times.

  7. WORKS FINE !!!! Thanks a lot.
    I have replaced the line 28 with this one:
    fprintf(stderr, “I2C: Failed to access %s : %s\n”, devName, strerror (errno));

  8. Would you have a schematic or fritzing diagram of the whole project. Curious on what and how you used the pull-up resistors or if you didn’t have to, what the connections between the raspberry pi & arduino looks like

  9. Wow I lost my post. I was just wondering if there is a full wiring schematic or better yet a fritzing for this project? You lost me when you were talking about the pullup resistors and if they were even needed and what value. Would be nice to see the actual final photo of the finished product. Thanks for the article.

    1. I’ve only just got around to approving your last post 🙂

      As for fritzing, no I haven’t but I will have something in the next week as I’m finally finishing off the build for the projects this article was the precursor to. The cabling is pretty straight forward however, its just connect GND, SCL & SDA directly between both boards.

      For the pullup resistors, they aren’t needed as the PI has them already on the I2C lines, & thats the trick here, as the arduino is the slave, it relies on the resistors on the PI to pull up those lines.

  10. Cool!!! I have three devices connected to my PI. One Aduino Uno, one Arduino mini pro and a PCF8574. This make it necessary to select a address. How can I change the main.c in that way that the first parameter is the Bus address? Can any one help me with this?

    1. Has anyone got a solution to this? I have multiple ATMegas (Arduino Uno chips on breadboard) – and while I can get one to communicate effectively (Great tutorial!!) – when I add a second chip and try to modify the programs, it does not work. No failure message, just “unknown command” when I enter a number.
      Ideas? Sample code for solution? Any help is appreciated!!!

      1. I did get the two chips working, but only with 2 separate programs on the pi. I call one for the first arduino, and call the second program for the second chip. Each ATMega chip has its own address – and each ATmega (arduino) has unique commands (1 and 2 for chip 1, 3 and 4 for chip 2).
        So to get it to work, I call:
        ./main1 1 (turns on/off LED on chip 1)
        ./main1 2 (returns temp from chip 1)
        ./main2 3 (turns on/off LED on chip 2)
        ./main2 4 (returns temp from chip 2)

        My question is – can I get all this into one pi program?

      2. I’m not certain why that’s happening. The only thing I can think of is that you are running both ATMega’s with the same I2C address? As they are separate devices then they should have individual addresses.

        Since writing this article I’ve been using code that’s evolved from this to talk to multiple devices on the one I2C bus. In the instance thats been running since April there’s no ATMega’s in there but it’s got a Light meter, UV sensor and a temp/pressure board all communicating with a single process on the PI & have not seen any problems like this. Each of these devices are physically separate units each with their own address (defined by the manufacturer).

    1. Other than having the relevant build tools installed (gcc etc), i actually use Netbeans on the desktop with a pi as a build slave to the ide.

      That said you can use any ide you wish on the pi, that’s just my setup.

  11. Thank you so much. It worked perfectly, of course. But there was one GOTCHA / WARNING. Maybe obvious to others, but not me, I connected to Arduino Uno pins 4 and 5. When it needs to be Arduino Uno pins A4 and A5.

  12. I now have 4 ATMegas and one magnetometer as slaves on my I2C bus, with a raspberry Pi as the master.
    Everything seems to be running great – EXCEPT – any time I call my stepper function (nothing is actually hooked up to the ATMega chip – simply a test call), my Pi loses the I2C bus (can’t see any device) and ends the program with a segmentation fault.

    If I unplug the chip from the bus that the stepper function was called on, the Pi can see the devices on the bus again. If I reset the chip, I can plug it back into the bus again, and the Pi can see it and interact with it again.

    I am at my wits end trying to figure out what is happening here! I have verified this only happens when I call this stepper library function. It doesn’t pertain to the chip, any other calls to all other functions read/write fine with no problems.

    I am using the standard arduino stepper library to call myStepper.step(rotations) – there is nothing fancy going on here so far as I can see.

    Any ideas? Help, please!!

    1. Double check that you are not pulling the i2c bus up to 5v – that could damage your PI as that runs at 3V3.

      It sounds to me that your stepper chip might be doing that. It might be as simple as the board the chip is on has pull-up resistors, you you may be able to get around this by removing them. If not then you will most likely need to put a level converter between the bus and that particular chip.

      This is a common problem where vendors put the resistors in when they are not needed.

      1. The Arduino chips are just on a breadboard, with only a resonator (clock) and 10k resistor (reset to 5V) for each chip. They are currently not plugged into anything except the i2c bus (plus obviously the resonator, resistor, 5V and ground).
        In other words – no chips, pull-up resistors or any sort of peripheral is involved here.

        The pi is being powered from a 5V breadboard rail, through a micro usb power port.
        The pi functions without any problems like this – and it can complete dozens of any other type of i2c call – read and write – as long as it is not to a stepper.step() function on the arduino!

        When I run the test from the pi – it is only to send commands to each arduino (on breadboard – just an ATMega chip) so the arduino will run its own functions. With nothing plugged in – this test was only meant to confirm i2c communication back and forth through all chips, and that the function calls are all set correctly.

        It was a real surprise then that the mere action of calling the function step() from the Arduino Stepper library causes such a problem! With no stepper, chip, or even an LED plugged in – the action was simply expected to give a confirmation. Instead – segfault. Bus stops working. Chip reset required. Unexpected chaos!!!

        It’s as if when calling the stepper step function, it starts filling the bus with so much junk it (the bus) no longer functions. That is my best hypothesis – but I can not find any documentation anywhere that could support such a conclusion. The closest I found is that the step function call causes blocking – and the chip should not be called to do anything else until the action completes. There is a formula to determine how much time to wait, based on the speed the rotation is set to (in my case, 90) – but even if I wait 5 seconds for a single rotation, the result is the same.

        Any ideas?

    1. Ah, at first I thought it was const int brakeB3 = 4; but then remembered you said are using Megas?

      So on those you’re connected to pins 20 & 21 for I2C (looking at the wire docs as not used Megas myself). The reason I thought that line was on the Uno’s it’s pins 4 & 5 so thought it was a pin clash so trying to control the stepper caused the bus to crash. As the uno has those pins exposed in 2 locations on the boards I was thinking that was a possibility but, if the megas do have separate pins then that’s not it.

      Other than that I can’t see anything obvious in the source. Timings seem ok and you aren’t using threading – I did find there was a bug in the Linux i2c kernel code when writing to two devices on two threads could cause the bus to get confused but you have everything in a single thread so can’t be it.

      Perhaps you could take a look at https://github.com/peter-mount/piweather.center/tree/master/sensors/i2c which evolved from this article & definitely works – one PI running this code has just celebrated sitting out doors with i2c sensors on it for a year this week. Bit more complex (& part of a bigger project) but might give you a few more pointers.

  13. It was an awesome post. I managed to connect the raspberry pi with one arduino. However, I tried to connect 2 Arduinos but for some reason just one works. What am I doing wrong? I am using 2 different address and it still doesn’t work. I detect both addresses with the i2cdetect. I connect both arduinos with the same ground, same 3v3, SDA and SCL. What else should I do.

    Thank you

    1. The fact that you have different addresses & i2cdetect sees both of them means the wiring is correct.

      If one is working, what happens if you disconnect the one that’s working leaving the other one there. Does the other one then start to work?

      1. I just tried it and it did not work. Could you show me exactly what I should change on my script and sketch ? maybe I missed a few lines during the process.

  14. I honestly made only a feel changes. I guess that was mainly because I did not get exactly what which line is doing.
    On my Arduino Sketch I just changed the address for each Arduino and for the Rpi I just did the following:

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    // The PiWeather board i2c address
    #define ADDRESS 0x04
    #define ADDRESS2 0x06

    // The I2C bus: This is for V2 pi’s. For V1 Model B you need i2c-0
    static const char *devName = “/dev/i2c-1”;

    int main(int argc, char** argv) {

    if (argc == 1) {
    printf(“Supply one or more commands to send to the Arduino\n”);
    exit(1);
    }

    printf(“I2C: Connecting\n”);
    int file;

    if ((file = open(devName, O_RDWR)) < 0) {
    fprintf(stderr, "I2C: Failed to access %d\n", devName);
    exit(1);
    }

    printf("I2C: acquiring buss to 0x%x\n", ADDRESS);

    if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS);
    exit(1);
    }

    printf("I2C: acquiring buss to 0x%x\n", ADDRESS2);

    if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    fprintf(stderr, "I2C: Failed to acquire bus access/talk to slave 0x%x\n", ADDRESS2);
    exit(1);
    }

    int arg;

    for (arg = 1; arg < argc; arg++) {
    int val;
    unsigned char cmd[16];

    if (0 == sscanf(argv[arg], "%d", &val)) {
    fprintf(stderr, "Invalid parameter %d \"%s\"\n", arg, argv[arg]);
    exit(1);
    }

    printf("Sending %d\n", val);

    cmd[0] = val;
    if (write(file, cmd, 1) == 1) {

    // As we are not talking to direct hardware but a microcontroller we
    // need to wait a short while so that it can respond.
    //
    // 1ms seems to be enough but it depends on what workload it has
    usleep(10000);

    char buf[1];
    if (read(file, buf, 1) == 1) {
    int temp = (int) buf[0];

    printf("Received %d\n", temp);
    }
    }

    // Now wait else you could crash the arduino by sending requests too fast
    usleep(10000);
    }

    close(file);
    return (EXIT_SUCCESS);
    }

    I am new on the Raspberry Pi, so that's why I am having a hard time. lol

    1. Ah ok I can see whats wrong.

      You’ve got ADDRESS as 0x04 and ADDRESS2 as 0x06. Thats fine.

      However when you are acquiring the buss for ADDRESS2, you are logging it but the ioctl() call is using ADDRESS. It’s also storing the file handle into the same variable as that for ADDRESS.

      So, you need to:
      1: on the line where it says int file; replace it with int file1, file2.
      2: on the ioctl() call for ADDRESS change the variable to file1.
      3: on the ioctl() call for ADDRESS2, after you change it to use that address, change file to file2.
      4: in the write() call change it to file1.
      5: duplicate that if block but have the second write() to use file2.
      6: close(file) becomes close(file1); close(file2);

      In theory that should then send to both arduinos.

      What was happening was the PI was opening a filehandle twice to the first one but not the second, and you were making just a single command, so the second arduino never got the command.

      Hope that helps.

      Peter

      1. Hey Peter.

        Before you told me that, I sat for a hour straight and understood mostly what was going on and made it work. But thank you anyway for using your time to help me. I really appreciate it.

        What I really want to do with the Rpi and the Arduino is to constantly send a string to the arduino that contains the time and a set point for a water tank temperature. I need the time from the Pi because I will have more than 5 arduinos working together and they must be synchronized. So if the pi send this info, that helps a lot. I want to send the temp because I do not want to upload the sketch all the time if I want to change the set point. So my question is, how can I make it an infinite loop so the time changes constantly? Do you have any idea?

        Pedro

  15. Hi, thanks for the awesome article. Can I use the same connection between a 5v Adafruit Trinket and a Pi? The Trinket also shares i2c pins as analog, should I assume there are no pullups?

  16. Hello Peter, when I run main.c I get the following lines and error: “I2c: Connecting” followed by “I2C: Failed to access 34900”. Running I2Cdetect shows a ’04’ in the correct place according to you diagram so as far as I know i2c has been configured on my rpi properly. Do you have any other explanations for my problem? Would be appreciated, thanks.

  17. Hello Peter, I used this solution for a while now to switch on and off some switches. It all works fine, but I like to get some analogue values. The values from the analogue port are larger than 255 (one byte) how can I send and receive values to and from a Arduino and a Pi. I am a noop at C so could you help me with that? Would appreciate it very much.

    1. Sorry for the late reply, I’m a bit behind with the blog.

      The way I’ve done it is to send the analogue values as 2 bytes, eg on the arduino:
      output[0] = (val>>8) & 0xff;
      output[1] = val & 0xff;

      Then in C:
      int t = (cmd[0]<<8) | cmd[1];

      Example sources:
      arduino: https://github.com/peter-mount/piweather.center/blob/master/arduino/arduino_weather_slave/arduino_weather_slave.ino
      C: https://github.com/peter-mount/piweather.center/blob/master/sensors/adc/adcpi_v1.c

      peter

      1. Hi Peter;
        Thanks so much for sharing your code with everyone. I too, am looking to poll the arduino’s analogue ports and use that information in the Raspberry Pi. I am also a C noob, so can you please direct me where in your github that you’ve shown that . I’ve done a simple modification to your C program to ask the arduino for the data, but need to work on the arduino side now.
        Thanks again,
        Robin (Canada)

  18. I’m currently using an arduino connected to my RPi by USB, to serve as a keyboard. Basically, it takes outside info and sends key strikes to the Pi (using the keyboard library). Works great through USB, but I was wondering whether it would also work it I were to hook it through I2C (to liberate the USB port). Any thought?

  19. I really don’t understand how this happened, but when I shut down my Raspberry connected to an Arduino Uno over I2c, there was power being backfed somehow to the RPi as the power led was still dimly lit … Fastforward today, my RPi is completely fried now… Is it possible the Arduino sometimes leak power over the I2C pins?

    I’m really annoyed because otherwise, I always use diodes and resistors to make sure this doesn’t happen… but dropped my guard with the I2C connection.

  20. hi, we want Pi with PIC (18F67K22) comm. by I2C but not working… example we add address inside PIC 0x04 ID, after pi we enter “sudo i2cdetect -y 1” read first time half address! like this 0x02, then we again enter “sudo i2cdetect -y 1” then no any seen address… what will we do for this… since 2 week we cant do it… 😦

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: