I2C communication between Arduino and Raspberry

Hi everybody and Merry Christmas to you all.
I've a question regarding the I2C communication between Arduino and RaspberryPi 3 Model B.

In the installation I'm working on, I need to connect 8 of them and I must do this using the I2C protocol.
I'm using the I2C port 0 actually (pin 27 and 28, called ID_SD and ID_SC respectively) since I cannot use the other one.

I've tried to read as much documentation as I could about the topic and I know that these pins are not meant to be used this way:

(see attachments)

Nevertheless it (almost) seems to work and now I have the PIs acting as masters, pulling information from a single Arduino UNO board, which is their slave (poor guy :stuck_out_tongue: )!

(see attachments)

My question is about the pullup resistors.

I know that the I2C bus drivers are “open drain”, so I must take care for the signal to return high when not in use.
The problem here is that Arduino and the PIs are operating at two different voltages (isn't it?).

As suggested by the same tutorial, in cases like this I can use the "trick" of putting the pullups on the lower voltage device (the RaspberryPi in my case).

The question is:

1. Do these (I2C 0) RaspberryPi pins already have their own internal pullup resistors? Just in case, can these resistors be enabled/disabled?


On the Arduino side, I know pins A4 (SDA) and A5 (SCL) already have their own internal pullups, or at least that's what I can say after reading the source code of the Wire library I'm using for the Arduino code.
See the begin and the end functions (inside the Wire.cpp file) which in turns call the twi_init() and twi_disable() functions (see utility/twi.c file).

Here the interested lines of code for twi_init():

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

and for twi_disable():

  // deactivate internal pullups for twi.
  digitalWrite(SDA, 0);
  digitalWrite(SCL, 0);

If I will explicitly disabled the Arduino internal pullups via code (using the digitalWrite(SDA, 0) and digitalWrite(SCL, 0)), is this hardware configuration going to work (pullpus to 3.3V the Arduino side)?

(see attachments)

I'm mean, I've already tried it and it works but I'm not perfectly sure it is the right way to approach the problem. I don't know if I'm damaging my I2C Pi pins and consequently I don't know if this configuration will be sufficiently robust to last for hours/days/months;

The second question which naturally came out is:

2. Am I damaging my pins? Are these pins protected in some way? Do I risk to permanently damage them, maybe with some incorrect voltage on the I2C bus? ( I hope not but actually I think I've already damaged one of my pi using external pullups to 5V the Arduino side).

Sorry for my wall of text. I will highly appreciate any support!
Thank you so much and again
...Merry Xmas.

pullups.jpg

Do these (I2C 0) RaspberryPi pins already have their own internal pullup resistors? Just in case, can these resistors be enabled/disabled?

Yes the Pi has its own pull up resistor but it is built into the board and can not be disabled with software, only a soldering iron. The thing is that this resistor is rather low at 1K8. So putting 8 Pis in parallel on the same bus is going to require the active Pi to sink just under 15mA which is just on the limit of what the GPIO pins can take. Do not add any more pull up resistors on the Arduino.

Disable the internal pull up resistors on the Arduino. This is best done by using a library that does not enable them in the first place like the I2C library or at a fudge using the pin mode call to set the two lines to inputs with no pullups just after the I2C begin call.

Hi Grumpy_Mike and thank you very much for your quick reply.

Grumpy_Mike:
Yes the Pi has its own pull up resistor but it is built into the board and can not be disabled with software, only a soldering iron. The thing is that this resistor is rather low at 1K8.

Are you talking about the the GPIO2 and GPIO3 which are used for the I2C port 1? If this is the case, yes: you are correct.
Indeed, as I can see from the board schematics there are two 1K8 pullup resistors to 3.3V.

The fact is that I'm not using this port for my I2C bus communication but I'm using the I2C port 0 whose pins are named ID_SD and ID_SC (I see they are also called GPIO0 and GPIO1). According to the schematics they shouldn't have a similar pullup configuration so I need to work it out.

Grumpy_Mike:
Disable the internal pull up resistors on the Arduino. This is best done by using a library that does not enable them in the first place like the I2C library or at a fudge using the pin mode call to set the two lines to inputs with no pullups just after the I2C begin call.

I'm working on this using the Wire library:

Since the begin and end of the Wire library automatically manage the Arduino A4 and A5 pullup resistors, in order to set the pullups resistors properly (disable them), I have to manually set the proper configuration after the methods of the library are called in my code.

[...]
 // initialize the Arduino as a SLAVE on the i2c bus
 Wire.begin( SLAVE_ADDRESS );
 
 // deactivate the internal pullup resistors.
 digitalWrite( SDA, 0 );
 digitalWrite( SCL, 0 );
[...]

Does it make sense to you?
Thank you very much.

Since the begin and end of the Wire library automatically manage the Arduino A4 and A5 pullup resistors, in order to set the pullups resistors properly (disable them),

It is only the wire begin that activates them, wire end. You only call wire begin at the very start of your code not inbetween writes. Just set the actual PIN numbers you use with a pinMode call.

If you are using GPIO 0&1 you might have problems because the OS uses these for the HAT interrogation on boot up. It is recommended that this is not used as an extra I2C bus.