I2C between 5V Uno and 3.3V Pro Mini


I've got an Uno running at 5V and a 3.3V Pro Mini (328P). I'm trying to get I2C working between the two. I can see stuff coming from the Uno and into the Mini, but not stuff going from the Mini into the Uno (the I2C addresses are right).

My first thought was, well that's because the 328P used on both boards is a CMOS process based chip and the minimum high logic level is 0.7x5V, which is 3.5V... and the Pro mini can only put out 3.3V which wouldn't register as a high on the uno.

Well, I've got some pull up resistors (2.2k) on the SDA and SCL lines pulling them up to 5V. Shouldn't that automatically make the line voltage 5V when the pro mini sends 3.3V (since the 5V coming from the pullups is not being pulled down any by the pro mini) and then the pro mini will pull the lines down to ground when it sends 0v?


Okay, so I removed the 2.2k pullups from the circuit altogether and then the devices can talk both ways. What in the world? Shouldn't the resistors help since they're pulling up to 5v? I added them back but as soon as I did nothing can talk again. Remove them? Talks again.

Btw - if this helps any I'm running at 400KHz. I did try using stronger pullups (470 ohm) in case the line wasn't transitioning from 0v to 5v fast enough at the high frequency, but that stopped any communications on the bus.

Any ideas?

I don't suppose I should trust the I2C lines to not float without the pull ups?

The Wire library enables the internal pull-up resistors. But that is not very reliable, certainly not at 400kHz.

You can not connect a 3.3V Arduino to a 5V I2C bus.
The Arduino pins are never a real open-collector output. If 5V is connected to an 3.3V arduino pin (via a resistor) the internal protection diodes will pass it on to the 3.3V power supply. You should avoid that.
Connecting a 3.3V I2C device to a 5V I2C device (with pull-ups to 3.3V) is okay, but it is not always working.

I have a mix of 5V and 3.3V devices and an Arduino master and an Arduino slave, and I can't do 400kHz. But 100kHz works fine.

The Arduino Leonardo has different input circuits. It detects a '1' at a lower voltage. So the Arduino Leonardo is compatible with 3.3V signals. But the Arduino Uno is not.

For a good communication, you should use a level shifter.

You might try using using Adafruit's '4-channel I2C-safe Bi-directional Logic Level Converter - BSS138'.

It's only $4: 4-channel I2C-safe Bi-directional Logic Level Converter [BSS138] : ID 757 : $3.95 : Adafruit Industries, Unique & fun DIY electronics and kits