We can use a single FET transistor with two resistors to make a two way logic level converter to interface e.g. Arduino Uno and a micro:bit.
I need to interface a micro:bit to an Arduino Uno, connecting the RX and TX pins of the Arduino to tabs on the edge connector of the micro:bit. The Arduino Uno has 5V logic levels. The micro:bit has 3V logic levels. The 5V signals from the Arduino Uno may damage the micro:bit.
The setup may well work without the logic level converter. However, the input pins on the micro:bit are not rated for more than 3.9V. So, applying the 5V signal levels from the Arduino is out of spec, meaning that the micro:bit could fail at any time. Or fail a little bit, just enough to corrupt your data occassionally, leaving you chasing Heisenbugs.
I need a logic level converter. This sits inbetween the Arduino Uno and the micro:bit boards and converts the signal levels so that each board receives the logic levels it works at.
How a logic level converter works
I learned about how logic level converters work from an excellent article in Circuit Cellar by Robert Lacoste. You can read this article for free by opening a free account on the website here. The simplest bi-directional logic level converter in the Lacoste article uses a single field-effect transistor with two 2.2K Ohm resistors. This circuit is simulated below.
Simulation of the FET based logic level converter using Falstad
I use the free online circuit simulation tool Falstad to simulate the device. Go to the site, then click on File, Import from Text. Copy and paste this text in to the text box and click OK.
$ 1 2e-8 21.593987231061412 50 5 50 5e-11 r 256 272 256 352 0 2200 r 464 272 464 352 0 2200 f 368 320 368 368 32 1.5 0.02 w 256 352 256 368 0 w 256 368 352 368 0 w 464 352 464 368 0 w 464 368 384 368 0 w 256 272 256 256 0 w 256 256 368 256 0 w 368 256 368 320 0 R 160 368 96 368 0 2 10000 2.5 2.5 0 0.5 w 160 368 256 368 0 R 256 256 176 256 0 0 40 3 0 0 0.5 R 464 256 560 256 0 0 40 5 0 0 0.5 w 464 256 464 272 0 403 640 352 768 416 0 6_64_0_4099_5_0.003125_-1_2_6_3 w 464 624 464 640 0 R 464 624 560 624 0 0 40 5 0 0 0.5 R 256 624 176 624 0 0 40 3 0 0 0.5 R 496 736 544 736 0 2 10000 2.5 2.5 0 0.5 w 368 624 368 688 0 w 256 624 368 624 0 w 256 640 256 624 0 w 464 736 384 736 0 w 464 720 464 736 0 w 256 736 352 736 0 w 256 720 256 736 0 f 368 688 368 736 32 1.5 0.02 r 464 640 464 720 0 2200 r 256 640 256 720 0 2200 w 496 736 464 736 0 403 32 672 160 736 0 26_64_0_4099_5_0.0015625_-1_2_26_3 207 464 368 528 368 4 High\slevel\slogic 207 256 736 176 736 4 Low\slevel\slogic 403 32 288 160 352 0 11_64_0_4099_5_0.00625_-1_2_11_3 403 512 656 640 720 0 30_64_0_4099_5_0.00625_-1_2_30_3 x 157 222 687 225 4 24 Low-level\slogic\sinput,\shigh-level\slogic\soutput x 131 587 658 590 4 24 High-level\slogic\sinput,\slow-level\slogic\soutput
You should see this circuit:
One note about Falstad - the app can suck up a lot of the CPU and ramp up the CPU temperature.
The 'scopes shows voltage in green and current in brown at the same time. We are interested in the green voltage levels.
There are two circuits shown. These show the same logic level converter circuit but with the inputs and outputs reversed.
The top circuit shows a 3V signal, simulated by a 10kHz square wave, from the simulated low-level logic device converted to a 5V signal.
The bottom circuit shows a 5V signal input to the right side of the circuit and a 3V signal output from the left.
So the logic level converter simulates correctly for an input signal to either side.
I use 2.2K resistors in the simulated circuit as this is what the boards I received use. Lacoste uses 2.2K resistors in his example.
Explanation of the simulated FET circuit
The FET is called an n-type FET as it uses an n-type semiconductor channel to transmit charge through the component. This channel is incomplete unless the gate has a positive bias compared with the source. Then current can flow along the completed channel. This current flow is shown as animated dots in Falstad. If you hover your cursor over the FET symbol, the gate, drain and source terminals show up as G, D and S. This gate-source bias needs to be above a threshold level for the semiconductor channel to complete and for current to flow. This is a pretty sketchy summary. There are lots of good YouTube videos explaining how a FET works with great animations I wish I'd had access to in the Chibanian when I studied this.
The FET gate is permanently held high by the low level side of the logic converter, in this case 3V. The source and drain of the FET are both weakly held high by 2.2K resistors.
If we slow down the simulation, we see that current flows when the source is held low by the low-level logic driver in the top simulation. Similarly, in the bottom simulation, current flows when the drain is held low by the high-level logic simulation. In both cases, a path to ground is created when the FET starts to conduct. This means that the output level also sees ground.
Have a play with the simulation to get your head around how the device works.
I bought a logic level converter board from eBay. The board has four logic level converter channels. A photo of the board with four converter channels can be seen below. The top pins are labelled HV1..HV4 - these are the connections for the high logic values. In my use case, these connect to the RX and TX pins on the Arduino Uno. So I only need two of the four channles. The pin labelled HV is connected to the high logic level voltage rail (5V in the case of the Arduino Uno). There is a ground pin connection on both the top and bottom rows, labelled GND. Similarly, the bottom row of connections has LV1..LV4 for each of the four low voltage signals. In my use case, the low level logic channels connect with pads 0 and 1 of the micro:bit's edge connector. I only need two channels. The unused channels are left unconnected.
I set the logic level converter up on some breadboard. I hooked a micro:bit to one side and an Arduino Uno to the other. The TX pin from the Arduino goes into the high-level logic side on HV1. Pad 0 of a micro:bit is connected to the low-level logic side on LV1. I connect to pad 0 on the micro:bit using a pin on a Kitronix edge connector that the micro:bit slots into.
A photo showing this arrangement can be seen below.
I set up the Arduino Uno to send a signal from the TX pin and scoped the input to the micro:bit on my pocket oscilloscope, a DS213. This may not be a high-spec oscilloscope, but it is good enough for this application. One advantage of the DSO213 'scope is that it is battery powered, so there is no danger of creating ground loops. A close up of the oscilloscope display showing input and output serial data can be seen below:
The green trace is the low level logic, the yellow the high level trace. I can see that the signal going to the micro:bit is shifted to the expected 3V logic level. The time axis is set to 10us per square. The square waves can be seen to occupy about one 'scope square for each high and low, which gives a baud rate of approximately 1/(10*10^-6) = 100kHz. I set the baud to be 115200, so this all looks about right.
The screen shot shows that the output signals are not the crisp square waves shown on the simulation. This is due to the capacitance in the circuit which was not part of the simulation There is also some ripple and noise on the signals. This is from other real-world artefacts of building circuitry, such as inductance. As the input frequency increases, the capacitance will have an increasing effect on the output signal, causing the edges to become more rounded. We can add capacitors and inductors to our simulated circuits to get more accurate outputs. That is a topic to deal with in another blog one day.
Once I was happy that the setup worked to convert from a high level voltage to a low level voltage, I tested the opposite signal direction. I connected pin 1 from the micro:bit edge connector to a second channel on the low logic level side of the converter board (LV4) and the RX pin of the Arduino Uno to the same channel on the high voltage side (HV4). I generated 3V signals with the micro:bit as the input to the logic level converter. The output was at the 5V logic level of the Arduino Uno. The output signals showed a similar rounding of the signal edges due to capacitance as the high level to low level conversion did.
Difference between the converter board and the simulated circuit
The transistors on my boards have 'J1Y' marked on the backs. The only transistor I can find with this marking on the back is the KSA1298Y, which is a bipolar transistor, not a FET. I don't see how the circuit will work with a single bipolar transistor per channel, but I'm open to suggestions. My conclusion is that the transistor is an unidentified FET. The converter board I bought uses 10K Ohm resistors, but this is a minor difference with the 2.2K Ohm resistors used in the simulation. A wide range of resistance values can be used for the resistors in the circuit.
The logic level converter works as expected. The real world implementation has effects from the inherent capacitance present in the circuitry. I'm not sure what model of transistor is used in the circuit boards that I purchased. Using a printed circuit board may reduce the rounding of the signal corners. I'm not sure how well the converter board would work in the MHz range - the rounding may become so severe that the output signals don't reach the necessary logic voltage levels. However, for passing data between serial ports at 115200 baud, the board is adequate.