How to disable internal Arduino ATMEGA pullups on SDA and SCL with I2C bus
Wire, the library available in the Arduino apis to communicate with devices on the I2C bus, as of the 022 version of the Arduino IDE, by default enable the internal pullups of the ATMEGA microcontroller.
As all 16MHz ATMEGA runs at 5V this means that with pullups enabled signals will have a 5 volt as logic level. Unfortunately, as many I2C devices runs at 3 Volts and aren't 5Volts tolerant, sending 5V signals to them is clearly a very bad idea. You may shorten your device life or even damage them irreparably.
As Wayne demonstrated with practical scope tests, internal pullups performs extremely bad in terms of signal quality and bus speed.
I personally don't understand why the guys who wrote Wire enabled the internal pullups by default, that's why I opened an issue on Arduino bug tracking website.
Unfortunately, it looks that not many people care about this issue so we probably will have this issue for some time more.. meanwhile you have two possibilities.
In sketch program code disabling
Just use the following code to disable the internal pullups in any code after you initialized Wire (using Wire.begin()). This is a good solution to implement in your Arduino library code.
#ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) #endif
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) // deactivate internal pull-ups for twi // as per note from atmega8 manual pg167 cbi(PORTC, 4); cbi(PORTC, 5); #else // deactivate internal pull-ups for twi // as per note from atmega128 manual pg204 cbi(PORTD, 0); cbi(PORTD, 1); #endif
In Wire library disabling
Another possibility is to modify the Wire library of your Arduino environment install so that it won't enable the pullups by default anymore.
If you are using Arduino-023 or previous, just find the Arduino IDE files and open the file twi.c under libraries/Wire/utility/. Locate and comment out or delete the following lines:
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) // activate internal pull-ups for twi // as per note from atmega8 manual pg167 sbi(PORTC, 4); sbi(PORTC, 5); #else // activate internal pull-ups for twi // as per note from atmega128 manual pg204 sbi(PORTD, 0); sbi(PORTD, 1); #endif
Instead, if you are using Arduino 1.0 IDE or later, search for the following lines and comment them out:
// activate internal pullups for twi. digitalWrite(SDA, 1); digitalWrite(SCL, 1);
Your pullups will be disabled by default now.