A simple working I2C (TWI) level shifter
Recently, I had to interface two hardware platforms via an I2C bus (a.k.a. two-wire interface, TWI) to query temperature and real-time clock information. This task is relatively straightforward on the software side. However, because the power supply of the two platforms were different (one at 3.3V and the other at 5V), the I2C busses could not be connected to one another directly and a level shifter was required between them.
There are commercially available I2C level shifters such as TI’s PCA9515BDGKR that is affordable but what do you do if you do not have such parts available in your drawer? Surely, there must be simpler alternatives to do a basic level shifting that can be implemented with readily available parts such as a few resistors and MOSFETs.
After doing some search I came across this I2C level shifter (courtesy of NXP Semiconductors) which looked simple enough to implement with the parts I had available at the time. Though I did not have much choice regarding the N-channel MOSFETs in that design, I decided to try the BS170 in TO-92 packaging (not as elegant as the SOT-23 package but nothing is perfect, right?). For the pull up resistors, I used 10 KΩ (I also tried 1 KΩ which also works). You just need to check the datasheet of the microcontrollers you are using to make sure the capacitance of the bus and the pull up resistors you choose are suitable. Here is a great article that describes the effect of the pull up resistors on I2C communications. I highly recommend that you have a read through it.
You will see what I ended up building in this photo. The breakout board in the middle is the I2C level shifter. I also suggest that you add some male headers to either side of it (like I have) to simplify interfacing to various development boards. Trust me, it will make life much easier for you! The setup in the photo is able to communicate at speeds of up to 400 kbps (which is the upper limit for the MCUs I was using).
After you build your level shifter, I suggest that you perform the following brief 4 step test with it before connecting it to the microcontrollers. This test helped me identify a couple of missing connections in my build before I started testing it with the target platforms. This test will take under 1 minute and probably save you hours of frustration!
1 – Connect SDA1 to GND and make sure SDA2 is at GND also.
2 - Connect SDA1 to 3.3V and make sure SDA2 is at 5V.
3 – Connect SDA2 to GND and make sure SDA1 is at GND also.
4 - Connect SDA2 to 5V and make sure SDA1 is at 3.3V.
I am sure you cannot wait to build your own I2C level shifter now that you have read my blog so good luck and happy building!
Bus switches are pretty straightforward solutions as you have mentioned. I am using those in most of my designs as well. When I came across this MOSFET solution, I wanted to give it a go and see if it really performed as expected. This is a handy solution when no bus switches are readily available. Electronic component procurement in some parts of the world isn't as easy as that in the USA or Europe where getting hold of bus switches can be a problem.
Thanks for pointing out the additional capacitance issue though. This needs to be considered jointly with the pull up resistor values on the I2C lines to make sure the pulse edges remain sharp during communication.
To post reply to a comment, click on the 'reply' button attached to each comment. To post a new comment (not a reply to a comment) check out the 'Write a Comment' tab at the top of the comments.
Please login (on the right) if you already have an account on this platform.
Otherwise, please use this form to register (free) an join one of the largest online community for Electrical/Embedded/DSP/FPGA/ML engineers: