Wire library enables internal pull-ups -> bad for 3.3V I2C devices.

The function twi_init() in twi.c enables the two internal pull-up resistors.

If a 3.3V I2C device is connected to the 3.3V, and the Wire library is used, the SDA and SCL lines have the internal pull-resistors to 5V.
Some low power I2C devices might have problems with that.
Allthough it should have open-drain or open-collector, according to some datasheets, the SDA and SCL may not exceed the 3.3 or 3.6V.

I have mentioned this also here: Arduino Playground - I2CBi-directionalLevelShifter (search for the word "violate").

This forum question is about the internal pull-ups: http://arduino.cc/forum/index.php/topic,105196.0.html

Are there any 3V I2C chips that are actually confirmed to be unable to handle this very tiny current through their ESD protection diodes?

I'm not asking for what the datasheets specs say. I'm not asking for a theoretical argument. I want to know if ANYONE has even one confirmed case where this causes actual problems.

[quote author=Paul Stoffregen link=topic=105291.msg790057#msg790057 date=1336669941]
Are there any 3V I2C chips that are actually confirmed to be unable to handle this very tiny current through their ESD protection diodes?[/quote]

No, I have never read about this actually causing a problem.
Some datasheets say for example 3.6V maximum, and don't say how much current is the maximum.
If 4k7 pull-up resistors are used to the 3.3V, and the internal resistor is 20k (it is 20k ... 50k), then the result is 3.7 V

Is this just an FYI, or are you proposing that it be changed? I haven't really used I2C, so I haven't studied the specifics, but I imagine you kinda need pull-ups, don't you? Unless you assume the user is going to provide them...

Normally the pull-ups are 4k7 or 10k. So the weak internal resistors are not very good.

I read about a different library that has an option for the init function to select the internal resistors or not. That seems the best way to handle this.

I don't understand the question. Why would you be connecting a 3.3V device to a 5V processor without some kind of level shifter?

Because many people connect a 3.3V I2C device to the 3.3V of the Arduino, and the SDA and SCL directly to the Arduino.
The Wire library activates the internal pull-ups to +5V, so that could be too much for the I2C device.

I have updated my story about level shifters: Arduino Playground - I2CBi-directionalLevelShifter
So far, no one knows about a chip that got damaged.

Krodal:
So far, no one knows about a chip that got damaged.

How about any confirmed case where a chip merely didn't work properly (but no actual damage to the chip once connected properly), or even a confirmed case where a chip worked but with reduced performance or some other undesirable effect?

Really, if this is such a big deal, one which merits a page with such strong warnings and which proposes numerous "solutions", where is the actual problem?

Did you understand what that page is for?
It is about a bi-directional level shifter for I2C: Arduino Playground - I2CBi-directionalLevelShifter
A level shifter is a very often used way. There were questions on the forum, so I decided to collect all of that in a page.

The problem with the internal pull-ups is that it could be outside the specs. So I mentioned that to.
Where are the strong warnings and the numerous solutions ? I can't see them.

Because one of the advantages of I2C being open-drain is that, you can just use a pull-up resistor to 3.3V instead of 5V, thus you don't need the level shifter

frank26080115:
Because one of the advantages of I2C being open-drain is that, you can just use a pull-up resistor to 3.3V instead of 5V, thus you don't need the level shifter

But not according to many datasheet.
It is not just open-drain, it is also an input. And that input is not tolerant for higher voltages on many components.

Or is this about using a 5V i2c component on the same bus as the 3.3V components, with pull-up resistors of 4k7 to the 3.3V ?

open drain means the bus can either be grounded or floating

now if all devices use open drain pins on the I2C bus, how can the bus be anything except one of either grounded or floating?

where can 5V possibly come from, if there is literally no physical connection, no semiconductor, no conductor, not even any resistors, that connects the bus to 5V? (note, this is the "ideal" case, but the non-idealities does not matter here)

oh wait, "Wire.h" enables the pull-up resistors to 5V, this is where the original problem comes from. Solution? Disable them and add external pull up resistors to 3.3V instead

The only situation where you would actually need a level converter is when the logic high threshold voltage of a device is above 3.3V, but this situation is VERY rare, that's why you read the datasheet first and look for input logic threshold voltage specifications

obviously if you have a device that uses a voltage lower than 3.3V, then you use another appropriate voltage instead and the same issue with logic threshold applies

I edited the playground page, to add a "Outside specs, (usually) works anyway" section.

Language like "level shifting to be able to use 3.3V I2C components" implies that level shifting is required. It certainly is required to meet all the specifications, but it is not usually necessary to simply get a chip to work.

Many Arduino users are very casual hobbyists. Vast numbers of them have indeed connected I2C parts directly with success. Advising them of the official specs is great. I just don't like directing novices to add extra (error-prone) complexity without mentioning a direct non-compliant connection usually works just fine.

I see the problem.. When you initialize the Arduino TWI library, you get a no-choice pull-up to +5 during idle.

If I understand the counter-argument: In practicality, the overvoltage will be shunted by the input driver protection circuitry on the i2c component, and is current-limited by the weak pull-up resistors, so it does no harm.

I think, as a user, I would appreciate knowing the risks. I would probably opt for either using a different library, hacking the header file to disable pull-ups, or using a level shifter. Even if it's "probably" OK to go ahead and internally pull up to 5v, that just doesn't sit well with me as a general practice.

I have changed a lot in the page about level shifting: Arduino Playground - I2CBi-directionalLevelShifter

Everyone should be happy with it now, it is informative and practical and compleet. I think there's no need to make big changes anymore.

I still think that the Wire library should have an option for the internal pull-up resistors though.....

There would be a bit of a danger if a 3.3V I2C device lets the line go high (by going high impedance) the line will only reach 3.3V if you pull-up to 3.3V and not 5V. Thus, although the Atmega running at 5V will read that as a high, it is only just (it registers high at above 2.7V) - page 412 of datasheet. You would need a reasonably powerful (ie. low) pull-up resistor to make sure it reached that level quickly enough.

Hello,

I am a student (but 48 yo!) just beginning to work with Arduinos. I am in this situation, too: a 5 V Arduino to connect to a 3.3 V device through I2C, so I designed a circuit with 3.3 V pull-up resistors.

The "easy" solution to disable internal pull-up, as reported, was to comment out disable Arduino internal pull-ups enable in twi_init().

What I have done is adding a new parameter in Wire.begin() wich allows enabling (default) and disabling pull-up resistors in the way that begin function is back-compatible.
I've had to modify Wire.h, Wire.cpp, utility/twi.h, utility/twi.c:

Example:

#include <Wire.h>
//...
void setup()
{
//...
// new parameter: WIRE_DISABLE_PULLUPS WIRE_ENABLE_PULLUPS

Wire.begin(WIRE_DISABLE_PULLUPS); //start Wire with pullups disabled

// Previous library version works as usual:
// Wire.begin(); //start Wire with pullups enabled (default case)
// and can be called this way, too:
// Wire.begin(WIRE_ENABLE_PULLUPS);
//...
// The 'begin' implementation makes Wire.begin(address) works as usual
// but it can be called too as: Wire.begin(address, WIRE_DISABLE_PULLUPS)
// ...
}

Attached you will find Wire library with this new specification/proposal.

Regards,
Josep

Wire.zip (14.2 KB)