You’ve got several devices which communicate via the I2C protocol, but some of them can only operate at 3.3V while the rest are hungry for a 5V connection. What to do? [Linux-works] built this I2C level converter to solve the problem.
The circuit comes from an NXP app note (PDF) on the issue. You can take a quick peek at the suggested schematic from that document. The design uses two MOSFETS for each side of the adaptor. Perhaps a better way to explain this is that you need one for the higher voltage and one for the lower voltage on each of the two data lines for a total of four parts. This allows for both of the buses to communicate as one, while still having their own 3.3V and 5V pull-up resistors.
[Linux-works] concedes that there are chips designed to do this for you, but he was able to source the BSS138 MOSFETs locally and for about ten cents a piece. Not a bad alternative to putting in a parts order.
Haha, I mentioned this trick in my upcoming EEWeb interview. Pretty handy, and I haven’t seen it in many places around the web.
3.3v ttl and 5v ttl use the same switching levels, so no conversion needing for “5v tolerant” 3.3v logic. The PDF mentioned is for level conversion with power down isolation…
but if you have a 3v3 and 5V part talking then at some point you could be shooting 5V into a 3v3 part… that’s bad
Not if the I/O is 5V tolerant as the parent post referred to…..
A useful scenario might occur if you’re trying to interface a 3.3v only part on a board you’re unwilling or unable to modify that’s running at 5v. perhaps it doesn’t even have a 3.3v supply or something? I think that’s where this circuit really shines. because now the supplies don’t even have to come up at the same time.
If the 5V side is never powered down while the 3.3V side is powered, then you only need one transistor per I2C line, so two transistors total. That’s how I’ve used this circuit.
The second transistor is to prevent the body diode passing current from the powered 3.3v side into an unpowered 5v side.
This is explained in the app note.
SMD components have notoriously fragile leads. If there is any chance they should be soldered to the PCB. I’d use #32 AWG enameled wire rather than anything with PVC insulation.
Simply place your pull-ups on 3,3V
All 5V logic should switch with 3,3V and given that I2C is an open-collector topology, no 5V will travel on lines.
That doesn’t always work…like if you have one i2c device that is rated for 1.8-3.3V and another that is rated for 4.0v-6.0v, and they are running from the same i2c bus.
some (all?) chinese/hk products have this crudely levelshifter for 5V TTL output/input. But if you need another level you cant use this “levelshifter” on your side. You have to use a real levelshifterchip.
Be careful using this circuit when the higher voltage right hand side can be in a situation where its power rail is removed. I used this circuit on a project wherein the higher voltage right side was not necessarily always powered and in this situation the body diodes of the MOSFETs allow the lower voltage side to sink current into an unpowered higher voltage side.
SparkFun has been selling this for years. It’s their Logic Level Converter board.
the sparkfun unit still uses a resistor voltage divider for one side (receive side, I think). many people have had problems with that.
I used the NXP dual transistor method since it allowed hot-swap and that seemed like a useful enough thing to have for only 2 extra discretes.
fwiw, this was not meant to be production; it was a midnight hack that I put together since I did not want to wait for a proper (and easier) chip and needed to get some i2c comms going that day.
comments regarding ‘yeah, but a chip could do it’ entirely miss the point.
I’ve done this with regular UART serial, I built my own for an arduino to iPod converter based on the sparkfun level shifter boards. I ordered a bunch of those BSS138 and use them for everything.
I think NXP have a dedicated chip that does just this. Why mess with discretes when the problem has been solved already?
@slincolne: simple mosfets are easier to get, may be cheaper and do not consume any power when the bus is high.
You do not need two mosfets! See figure 2 in the NXP application note. This works fine as long as you use pullups on both sides and make sure the diode in the mosfet points the right way.
Just got home and checked – I can get a PCA9306DCUR Dual Bidirectional I2C and SMBus voltage level translator from Element14 for $1.50. It covers all the ranges, and is just 1 package to deal with. Sorry, but I’d rather work with a purpose built chip than faff around with all those discretes.
I use an SN74LVC244. It’s a logic buffer that runs on 3.3v and has 5v tolerant inputs. Works great, and it’s only $0.48 in single quantities at digikey. It comes in both DIP and SOIC packages, which is great for moving from prototype to a real product.
However, I do agree that this hack works in a pinch.
Very nice, but won’t work with I2C, as the data bus is bidirectional.
actually it works great for I2C. 3.3V is considered high on 5V devices. Make that ‘most’ 5V devices :) I’m sure there are exceptions to the rule, but it works great for an arduino.
I made this one about a year ago.
http://www.instructables.com/id/A-bidirectional-logic-level-converter-for-I2C/
And this is mine: http://www.varesano.net/blog/fabio/i2c-logic-level-convertertranslator-integrated-voltage-regulator
Can anyone explain to me why you need the pull ups on the lower voltage level? It seems that its working for me even when there is no pull up and the devices on the lower levels are all on High impedance (ie: all inputs, no internal pull-ups).
b.t.w. the origional Philips (who invented i2c) document for this exact thing is: AN97055