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.



Extremely helpful
I had lots of trouble to communicate through I2C with my Arduino Mega2560. The documentation is so patchy. Turn out the pull-up resistors' value, both internal and external, was the main issue. Thank you so much for the information.
very helpful~~thks~~:)
very helpful~~thks~~:)
Post new comment