Arduino – I2C Pull-Up Resistors and Voltage

arduinoi2cmagnetometerpullup

I have a sensor that I'm trying to read via I2C, but I have some issues with the pull-up resistors and what voltage they would be set to.

My host computer is the Arduino Nano Every while my sensor is the HMC5883L magnetometer.

Below is a block diagram showing my wiring scheme.

I did some research on the Nano Every's processor. The I2C pins are connected to the ATMEGA4809, and it is powered at +5V. Thus, the I2C lines are referenced to a voltage of 5 volts. The HMC5883L module has pull-up resistors on it already for both 5V and 3.3V, but if I wanted to add my own external pull-up resistors, then I would have to reference it to 5V as shown in my block diagram, correct? If I decide to reference it to 3.3 volts (and connecting 3.3 volts from the Nano to the corresponding pin on the sensor,) since the microcontroller is running at 5 volts, what voltage should I connect the pull-up resistors to?

schematic

simulate this circuit – Schematic created using CircuitLab

Best Answer

Thus, the I2C lines are referenced to a voltage of 5 volts

Nope. They are referenced to a GND.

connecting 3.3 volts from the Nano to the corresponding pin on the sensor

Don't do this! The 3.3V on the sensor is an output.

The HMC5883L module has pull-up resistors on it already for both 5V and 3.3V

While they are indeed pull-up resistors, they are also parts of the built-in level shifter, which allows 3.3V sensor to work with 5V I2C bus.

if I wanted to add my own external pull-up resistors, then I would have to reference it to 5V as shown in my block diagram, correct?

There is no reason whatsoever to add anything externally. However if you do want to do it then yes, you can add pull-up resistors to 5V, but then you have to either remove R3, R4 from sensor board or make sure your additional resistors in parallel with them do not go under a minimum allowed resistance (i.e. your combined pull-up is not too strong). For example additional 10k resistors will result in 5k pull-up, which should be OK for 400kHz bus.

If I decide to reference it to 3.3 volts

Again, there is no reason for this, as sensor side of the level shifter is already pulled-up to 3.3V. The MCU side of the shifters is pulled up to 5V. If you have used any 3.3V MCU then you could have removed all 4 resistors (R1-R4) and two MOSFETs, short the SDA and SCL lines for pass-trough, and finally add external pull-up resistors to 3.3V. But since you are using Nano, its MCU is incompatible with 3.3V I2C bus.

UPDATE:

what you connect to VIN will depend on the MCU's I2C logic level?

YES for Adafruit boards, NO in general. The Adafruit boards are designed to be powered from 5V (VIN), using internal regulator to step down to 3.3V, as you mentioned yourself. So, the board is powered by 5V, however the sensor chip on it is powered by 3.3V.

Now, the VIN_min for HMC5883L chip is 2.16V, for LSM9DS1 it is 1.9V. Theoretically, you can power the boards from these voltages + voltage drop on LDO. Does not mean you have to do it. If you want stable predictable behavior I'd recommend powering the boards from 5V where possible. But keep reading...

Thus, 5V from Nano to VIN and my pull-ups.

Your mistake is to think that VIN has anything to do with pull-ups. The I2C bus voltage (where pull-ups should be connected) is often called VDDIO on the schematics. Many chips have separate input pin for VDDIO (e.g. pin 13 of HMC5883L, pins 1 and 3 of LSM9DS1). It is just so happens that Adafruit connected those pins to VDD from LDO on their boards.

Since they connected VDDIO to internal 3.3V regulator, they could not let you apply higher voltage to sensor I2C pins. So they added level shifters to their boards, with pull-ups to 3.3V on sensor side and pull-ups to VIN on the connector side. This in turn fixed external I2C bus voltage to VIN. So, in this case the VIN does define the bus voltage, but only because Adafruit engineers wired the boards this way.

To summarize:

  • If you are not prepared to hack sensor boards to bypass level shifters you are stuck with their pull-ups, which means external (i.e. connected to MCU) I2C bus voltage will be always equal to VIN.
  • Therefore you should supply VIN with I/O logic level of your MCU. Or 5V in case of Nano, 3.3V in case of Portenta.
  • There is no reason to add any external pull-ups, unless you experience communication errors at 400kHz. Then you can connect external pull-ups to VIN, but try not to go below 10k.