Level Converter with I2C

I recently received a 6DOF IMU

I've come to realize this system operates on 3.3V whereas my robot works on 5V

I am currently working on getting a level converter (as well as a 3.3V regulator to supply power to the IMU and LV pin of the level converter)

While there is a clock signal (SCL) that goes strictly from the Arduino to the IMU (taking up one TXI and TXO pin), there is an SDA pin on the IMU that appears to go both ways (sometimes the IMU drives the line, other times the Arduino drives the line - in accordance with the I2C protocol).

  1. Am I correct in assuming I will need to use both an RXI/RXO and an TXI/TX0 pin to facilitate dual direction communication for the IMU SDA pin to/from the Arduino?
  2. Should I be at all concerned about connecting the RXI to the TX0 on one side of the level converter and doing the mirror (RX0 and TXI) on the flip side, effectively creating a loop?

While there is a clock signal (SCL) that goes strictly from the Arduino to the IMU (taking up one TXI and TXO pin),

Why is that, should you not just have it on one input pin on your system?

For the data yes you need a bi-directional level converter. You can easily make one with two transistors or FETs as shown here:-

1 Like

Mike,
The 3.3V on the gate keeps the 5V on the drain from exceeding 3.3V on the source?

Would this one work?
http://www.fairchildsemi.com/ds/2N/2N7000.pdf

Yes that's basically how it works although it is a common gate (base) amplifier if you want to look it up.
That FET would be ideal for the job.

Why is that, should you not just have it on one input pin on your system?

I'm afraid I don't follow. I was under the impression the Arduino generated the CLK signal, so that would be an output from the Arduino that had to be converted from 5V to 3.3V. I'm not sure how much current the IMU draws from the SCL pin, but I suppose I could use a voltage divider from the 5V to form the 3.3V, bypassing the level converter... if that's what you're implying.

For the data yes you need a bi-directional level converter. You can easily make one with two transistors or FETs as shown here:-

I've already put in the order for the level converter, so I'd prefer to stick with that option. As I understand it, the option you show appears to be doing what the level converter already does, the FETs look similar to the level converter diagram.

I just want to ensure that I can make a "bi-direction level converter" by connecting two of the uni-directional sets of pins on the level converter, and the loop discussed above is not a problem. Having one pin drive another pin which in turns drives the original pin seems like it could possibly pose a problem. The site for the level converter states it can handle I2C, but I want to make sure there aren't any diodes or other components required, if I can accomplish this with just the level converter, that would be desirable.

Since no device on the I2C bus will source power on SDA or SCL, one possibility is to just pull the I2C bus to 3V3 with two appropriately sized external resistors. A mix of 5V and 3V3 devices can then coexist on the same bus without active level conversion. 5V devices will only see 3V3, but this is within specifications for logic high.

An issue with this approach however is that the Arduino wire library will by default enable internal pull-up to 5V for SDA and SCL. Modifying the wire library to leave pull-up disabled however is quite simple (comment out pull-up enable in the twi.c, twi_init function) and so for a specific design this is a low cost simple approach.

I just want to ensure that I can make a "bi-direction level converter" by connecting two of the uni-directional sets of pins on the level converter

The level converter is bi-directional, there is no need to use two.

As a follow up to this post, I have managed to communicate with both the ADXL345 Accel and ITG3200 Gyro on the breakout board.

An important side note about the level converter: The TXI and TXO pins on the level converter use the MOSFETs as described in an earlier post. The RXI and RXO pins however are simple voltage dividers, meaning whatever voltage you supply on the high side, half the voltage comes out of the low side (supply 5V in, get 2.5V out, not 3.3V). Therefore to properly operate the I2C interface which is sensitive to changes below 3.3V, only the TXI and TXO pins should be used for the SDA and SCL conversion, this will ensure the IMU receives the full range from 0V to 3.3V when supplied with 0V or 5V from the Arduino, respectively.

/******************************************************************************
 *  Parallel Logic
 *  August 2, 2011
 *
 *  Program to read either the ID# stored on the Gyro or the Accel
 *  Choose which by changing the XXXX_ADDRESS in the two locations in the loop() method
 *
 *  Connection diagram for Arduino Mega 2560:
 *  3.3V --> LV of level converter & 3.3V input to 6DOF IMU
 *  5V --> HV of level converter
 *  GND of Arduino --> 2 GNDs of level converter & GND of 6DOF IMU
 *  pin 20 SDA --> 5V TXO of level converter __ 3.3V TXI of level converter --> SDA pin of 6DOF IMU breakout board
 *  pin 21 SCL --> other 5V TXO of level converter __ other 3.3V TXI of level converter --> SCL pin of 6DOF IMU breakout board
 *
 *  Note: I2C uses pins 20 and 21.  I2C library kills Analog pins 4 and 5
 ******************************************************************************/
#include <Wire.h>
#define ACC_ADDRESS (0x53) //7-bit address from Accel docs p10
#define GYRO_ADDRESS (0x68) //7-bit address from Gyro docs p18
int iteration=0;

void setup(){
  Wire.begin();
  Serial.begin(4800);
}

void loop()
{
  iteration++;
  delay(1000*10);
  Serial.print("Begin Transmission #");
  Serial.println(iteration);
  Wire.beginTransmission(GYRO_ADDRESS);
  Wire.send(0x00);
  int resp=Wire.endTransmission();
  Serial.print("Sent resp: ");
  Serial.println(resp);
  Wire.requestFrom(GYRO_ADDRESS,1);
  int avail=0;
  while(avail==0)
  {
    avail=Wire.available();
  }
  int rec=Wire.receive();
  Serial.print("ID #: ");
  Serial.println(rec);
  //returns Dx229 or Bx11100101 for Accel
  //returns Dx105 or Bx01101001 for Gyro
}

Hi everyone.

Great thread on the topic of i2c level conversion. I especially like the use of trough hole components :slight_smile:

What value would be appropriate for the pull up resistors? I found this website where 2k2 resistors are use in a similar design. http://www.rocketnumbernine.com/2009/04/10/5v-33v-bidirectional-level-converter

Would that be the right value?

Thanks in advance!
Rob.

I use 4K7 on a 5V system and 2K2 on a 3V3 system.

Hey Mike,

Thank you very much!

Rob.