should I be using a pullup resistor?

I’ll start by stating that my background isn’t in electronics. I’ve been learning a lot as I go, but it’s still absolutely an area that I’m lacking on.

With that being said, I’m working on a project with a 9-axis imu that communicates over i2c. I’m connecting this to an ESP32. I am using the adafruit libraries and wire.h to facilitate everything.

I’m running into an issue where the IMU seems to stop generating new values. I THINK what is happening is the device is crashing, and the libraries are just returning the last values it received, but regardless, something is wrong and I’m hoping to get some help in diagnosing it.

Here are the exact libraries I’m using:

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_L3GD20_U.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_9DOF.h>

These allow me to get the accelerometer, magnometer, gyro, and dof data (pitch and roll).

The IMU seems to work fine at first, so it has me fairly stumped. I have it connected to the 3.3v pin on the device and the esp32. I’ve seen a few other posts that recommend pullup resistors. I won’t lie, I don’t even know what those are or do. I’m hoping someone can help me figure out the issue and if it do need a pullup resistor, help me understand why and what kind?

I want to get this figured out because thought I haven’t done it yet, I’m also planning to add an additional i2c device (SSD 1306 OLED) and I don’t expect that to make my issues go away. So far I’ve gotten the oled to work great independantly, and I’d like to be able to say the same for the imu before I try to use them both at the same time.

I’m hoping you guys might be able to help me diagnose this issue and find a way to resolve it!

You will have to post your complete code and the complete wiring schematic, otherwise it will just be guess work for anyone.

That device doesn't seem to have pullup resistors. There's a pair of resistors adjacent to the SCL and SDA pins but they don't seem to be connected to those pins or even the right value for pullups. Without a schematic, it's hard to be certain.

Yes, you need external pullup resistors.

I don’t have anything to make a pretty illustration, but it’s just four wires: https://www.aliexpress.com/item/9-Axis-IMU-L3GD20-LSM303D-Module-9DOF-Compass-Acceleration-Gyroscope-for-Arduino/32834750188.html?spm=a2g0s.9042311.0.0.1d404c4dHkts8w

esp32  -  imu
3.3v    -  3vo
grnd    - grnd
scl      -  p22
sda     - p21

and the code is pretty straight forward, just getting readouts and pausing half a second and repeating

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_L3GD20_U.h>
#include <Adafruit_LSM303_U.h>
#include <Adafruit_9DOF.h>

/* Assign a unique ID to these sensors at the same time */
Adafruit_L3GD20_Unified            gyro      =      Adafruit_L3GD20_Unified(10001);
Adafruit_LSM303_Accel_Unified      accel     =      Adafruit_LSM303_Accel_Unified(10002);
Adafruit_LSM303_Mag_Unified        mag       =      Adafruit_LSM303_Mag_Unified(10003);
Adafruit_9DOF                      dof       =      Adafruit_9DOF();

void setup(void){
  Serial.begin(9600);
  
  /* Enable auto-ranging */
  gyro.enableAutoRange(true);
  
  /* Initialise the sensor */
  if(!gyro.begin())
  {
    /* There was a problem detecting the L3GD20 ... check your connections */
    Serial.println("Ooops, no L3GD20 detected ... Check your wiring!");
    while(1);
  }
  
   /* Initialise the sensor */
  if(!accel.begin()){
    /* There was a problem detecting the ADXL345 ... check your connections */
    Serial.println("Ooops1, no LSM303 detected ... Check your wiring!");
    while(1);
  }
  
  /* Enable auto-gain */
  mag.enableAutoRange(true);

  /* Initialise the sensor */
  if(!mag.begin())
  {
    /* There was a problem detecting the LSM303 ... check your connections */
    Serial.println("Ooops2, no LSM303 detected ... Check your wiring!");
    while(1);
  }
  
}

void loop(void){
  
  /* Get a new sensor event */ 
  sensors_event_t event; 
  gyro.getEvent(&event);
  accel.getEvent(&event);
  mag.getEvent(&event);
  
  sensors_vec_t   orientation;
  
  /* Display the results (acceleration is measured in m/s^2) */
  Serial.print("X: "); Serial.print(event.acceleration.x); Serial.print("  ");
  Serial.print("Y: "); Serial.print(event.acceleration.y); Serial.print("  ");
  Serial.print("Z: "); Serial.print(event.acceleration.z); Serial.print("  ");Serial.println("m/s^2 ");
  
  /* Display the results (speed is measured in rad/s) */
  Serial.print("X: "); Serial.print(event.gyro.x); Serial.print("  ");
  Serial.print("Y: "); Serial.print(event.gyro.y); Serial.print("  ");
  Serial.print("Z: "); Serial.print(event.gyro.z); Serial.print("  ");
  Serial.println("rad/s ");
  
  /* Display the results (magnetic vector values are in micro-Tesla (uT)) */
  Serial.print("X: "); Serial.print(event.magnetic.x); Serial.print("  ");
  Serial.print("Y: "); Serial.print(event.magnetic.y); Serial.print("  ");
  Serial.print("Z: "); Serial.print(event.magnetic.z); Serial.print("  ");Serial.println("uT");
  
  float Pi = 3.14159;
  
  // Calculate the angle of the vector y,x
  float heading = (atan2(event.magnetic.y,event.magnetic.x) * 180) / Pi;
  
  // Normalize to 0-360
  if(heading < 0){
    heading = 360 + heading;
  }
  Serial.print("Compass Heading: ");
  Serial.println(heading);
  
  /* Calculate pitch and roll from the raw accelerometer data */
  if (dof.accelGetOrientation(&event, &orientation)){
    Serial.print(F("Roll: "));
    Serial.print(orientation.roll);
    Serial.print(F("; "));
    Serial.print(F("Pitch: "));
    Serial.print(orientation.pitch);
    Serial.print(F("; "));
  }
  
  delay(500);
}

Pretty is not required. The scruffiest pencil schematic on the back of a receipt badly photographed with a phone is better than 90% of all "pretty" drawings.

Do you have resistors? Pretty much any value between 2K and 10K should work unless the wires are excessively long or something. ("Excessive" here is 20cm)

thanks, that's really good to have. I've seen other posts mention 10k pullups, but didn't go into much detail beyond stating they might try them. So at this point, I think I might do the same, lol. The length is extremely short.. right now, probably 6 inches, but the final product will be even shorter.

I'm still very new, is a 10k 1/2 watt resistor like these look right?

Thanks again for the help!

unless the wires are excessively long or something. ("Excessive" here is 20cm)

and

The length is extremely short.. right now, probably 6 inches,

jsut shows how close these things can be 6" = +-15.2cm 10K
1/2 watt is fine (1/4 watt is fine as well)

Those resistors are exorbitantly priced... 7 cents a pop for el-cheapo carbon comp resistors....

If you don't have a selection of resistors, search for a "resistor pack" on ebay (or amazon for faster shipping and much higher prices).

Or aliexpress, if you have time and want change back from a buck :slight_smile:

About six bits for a hundred pack . . .

I've seen other posts mention 10k pullups, but didn't go into much detail beyond stating they might try them.

The resistors are supposed to be able to source between one and two mA. So for 3V3 supply that will be 3K3 for one mA or 1K8 for two mA.

On a 5V bus you should use 4K7 or 2K4.

Some devices like the controllers used in the Wii specify higher values but these are exceptions and it should say in the data sheets.

I’m getting a variety pack of resistors in the mail today. I’m glad you guys suggested shopping around. I’ll be trying this out and updating this thread with my results. Hopefully it can help someone else in the future too.

For whatever reason, when I research resistors, I really struggle.

In the mean time, looking ahead, I want to eventually have two i2c devices. I’ve seen this shouldn’t be a big deal, but so far I’ve struggled with just one, lol and I’ve got a couple questions on that topic that I might break out into another thread just to keep it clearly posted.

My two i2c devices are the imu and an oled.

I’ve tested them both independently , and pending adding the pullup resistors for the imu, they should both work out well. When I combine them, I want to make sure I can keep them working. One device runs on 5v and the other runs on 3.3v will that create any issues?

Would I wire that up something like this?

esp32[p22] → pullup resistor → imu[scl] → oled[scl]
esp32[p21] → pullup resistor → imu[sda] → oled[sda]

or should I branch them so that the oled isn’t on the same line as the resistor? even though it still kind of is. This is where I get myself lost easily. Something like this…

esp32[p22] → pullup resistor → imu[scl] → oled[scl]
esp32[p22] → oled[scl]

esp32[p21] → pullup resistor → imu[sda] → oled[sda]
esp32[p21] → oled[sda]

I hope those typed out illustrations make sense. Like I said, the hardware is always really challenging for me. I get the general concept of what a resistor is and what it does, but I definitely don’t have the level of understanding that I’d like to have about them.

One device runs on 5v and the other runs on 3.3v will that create any issues?

Yes.

None of those solutions work you will need a bidirectional level shifter and hang the 5V device on the 5V side and the 3V3 device on the 3V3 side.

So my resistors are now saying they'll be arriving tonight instead of last night. I'm glad they're behind a day because I just read "bidirectional level shifter" lol. The more you know, the less you know, right? I'm now reading up on this and my take on it is... a bidirectional level shifter will manage the different voltages to the two devices and give a common communication line? I'm not 100% sure I get it just yet, but that's my crude take away.

Now maybe there's hope for a simple design still, my IMU says it can run on 5v or 3.3v, and if I run it on 5v, that'll place both of my i2c devices on a 5v line now. So this leads me back to my initial question, if both of my i2c devices are on a 5v line, and my imu needs the pullup resistors, how should I go about wiring them up? I've googled wiring multiple i2c devices, but I haven't found anything that was clear to me yet.

You guys have been a boat load of help, I really appreciate you guys helping out a n00b on this stuff!

Grumpy_Mike:

faceless105:
One device runs on 5v and the other runs on 3.3v will that create any issues?

Yes.

None of those solutions work you will need a bidirectional level shifter and hang the 5V device on the 5V side and the 3V3 device on the 3V3 side.

I believe your 9-DOF sensor has level shifters on board for the I2C signals. The apparently identical Adafruit board does. The Adafruit board shows 10k pullup resistors to Vin on the MCU side so you’d want 3.3V into the 9-DOF board.

No idea about the OLED. The challenge with using stuff from AliExpress is that there is little to no documentation, but the link claims that it works down to 3.3V, so you could probably operate it there and skip the level shifters.

This has me a bit confused. And that's just because all of this is a bit out of my depth, lol. From the sounds of it, i wouldn't be having an issue with my IMU if I were running it on 5v to the VIN as opposed to running 3v to the 3v pin?

Now the second part has me a little more confused, are you recommending that I run them both on the 5v line or on the 3v line? It seems the more important part is that they're both at the same voltage since I want to use both i2c devices, but would one voltage likely be better than the other?

Once I have them on the same power, and start taking advantage of the builtin pullup resistors on the IMU, should I be able to wire them both up to the esp32 like so?

esp32[p22] -> imu[scl] -> oled[scl]
esp32[p21] -> imu[sda] -> oled[sda]

Per the Adafruit guidance you should be able to hook together the SCL from all boards and the SDA from all boards directly.

For power to the IMU you may either apply regulated 3.3 V directly to the IMU 3Vo pin or to the IMU Vin pin.

Using 3Vo means all boards would be running at 3.3 V and there is 10k pullup to 3.3V on the IMU side of the level shift transistors.

Using Vin means the IMU board would be running at a somewhat lower voltage (dropout voltage of regulator) and the external boards would see the 10k pullup resistors on the external side of the IMU board to 3.3V.

For higher I2C speeds (Wire.setClock()) you might want lower value pullup resistors but at the default 100kHz and short wire runs the 10k should be sufficient.

reading this makes my brain feel like it might start melting out though my ears, lol, but I believe I understand. I really appreciate all the help from you and everyone else. Needless to say, this stuff is outside my typical understanding.

I'll be wiring all of this up tonight or tomorrow. Once I do, I'll be back with some results. Like I said, hopefully this can help the next guy who doesn't know what he's doing, lol.