How to Level Shift Bidirectionally with High Impedance Output

high-impedancelevel-shifting

I have communications bus I am trying to reverse engineer. It is based on a 9600 bps UART but inverted so it sits at 0V when idle, and pulses at 5V to send a binary 0. Unlike a normal UART the TX and RX lines are shared so only one wire is used for both transmit and receive. When one side wants to transmit a binary 0 it pulses the line at 5V, otherwise when idle it is weakly pulled towards 0V.

The problem is that I need to interface this bus with a 3.3V microcontroller UART (that is not 5V tolerant), and none of the usual level shifting solutions work. This is because none of them have a high impedance (Hi-Z) output state, rather they are always driving the output high or low, whereas I need a Hi-Z option as well so that another device on the bus can drive it while my transmitter is idle.

I have figured out the receive logic by having the bus feed into the base of an NPN transistor, and with the transistor output pulled high to 3.3V normally, when a 5V pulse arrives on the bus it causes the transistor to conduct, dropping the output from 3.3V down to 0V, and this has allowed me to successfully receive data from the bus.

However I am a bit stuck on how to transmit data. The microcontroller output needs to be both inverted and shifted up from 3.3V to 5V, but instead of the level shifter outputting 5V and 0V, it needs to output 5V and Hi-Z. This is so that when the microcontroller's TX pin is idle, the bus is not affected (and if nobody else is transmitting it will pull itself down to 0V).

Here is a truth table just to be extra clear:

Signal received from uC UART TX pin Output to bus
3.3 V Hi-Z
0 V 5 V

I can't quite see how to achieve this with one transistor, but perhaps it's possible with two. However I am thinking there's probably a trick to this so I thought I would ask before coming up with a my own barely functional solution!

As a side note, here is the truth table of the receiver side in case there's any way it can be built into the same circuit, rather than having two independent TX/RX blocks:

Signal from bus Output to uC UART RX pin
5 V 0 V
0 V 3.3 V

Best Answer

A BJT needs only about 0.7 V to switch on, but you can add diodes to make the threshold higher:

schematic

simulate this circuit – Schematic created using CircuitLab

R1 needs to be able to discharge Q1's base so that it switches off quickly.

Alternatively, use a buffer that has a three-state output and accepts 3.3 V signals at its inputs, with the data input connected to 5 V and the /OE input to TX; one such device is the (SN)74AHCT1G125.