Author Topic: Making a 3V3 to 5V bi-directional level shifter  (Read 485 times)

0 Members and 1 Guest are viewing this topic.

Offline mikeyn6il

  • Newbie
  • Posts: 2
  • Country: us
Making a 3V3 to 5V bi-directional level shifter
« on: June 15, 2021, 07:02:34 pm »
I am trying to make a bluetooth PS2 keyboard using a ESP32.  PS2 keyboards are 5V, ESP32 is 3V3 so I know I need level shifters.

I want to know if I can use the ZVN3306A transistors I have on hand to make my own level shifters. 

The following document describes how to do this using a single MOSFET:

Bi-directional level shifter forIĀ²C-bus and other systems.

The document has a list of transistors that can be used and includes some minimum specs:

Type  :N-channel enhancement mode MOS-FET.
Gate threshold  voltage : VGS(th)min. 0.1V max. 2V
On resistance :RDS(on) max. 100 Ohm  @ ID= 3mA, VGS= 2.5V
Input capacitance :Ciss max. 100 pF @ VDS= 1V,  VGS = 0V
Switching times :ton toffmax. 50 ns.
Allowed drain current :ID 10 mA  or higher.

The transistors I have on hand are ZVN3306A

VGS(th) min: 0.2V max 2.8V
RDS(on) 5 ohms
Ciss 35pf
ton/off 5ns/6ns
ID min 750ma

Seems like this mostly matches up with the specs but some specs are a bit off.  The document makes it pretty clear that VGS(th) is a critical parameter.  They specify up to 2V max and my transistor is 2.8V max. 

So I wonder if I could use the ZVN3306A as a level shifter or whether I should go for something else like 2N7000 which is cheap easy to obtain and closer specs to their examples.

I have tried this using 10k Pull-Up resistors and it sort of works, but sometimes one of the lines gets stuck or not detected properly by the software.  I do have an analog scope but it has some minor issues and barely works well enough to see that the circuit is working, but I can't really judge what the rise/fall looks like. All I can pretty much tell is I when I press a key on the keyboard I can see the clock and data go by on the 3V3 side. and it is in fact 3V3 but harder to tell what the slope is.  I don't see anything getting stuck on the scope....


Offline jpanhalt

  • Super Contributor
  • ***
  • Posts: 1242
  • Country: us
Re: Making a 3V3 to 5V bi-directional level shifter
« Reply #1 on: June 15, 2021, 07:46:10 pm »
With mosfets, Vgs(th) is quoted as the lowest voltage at which a particular current is passed.  That is often 250 uA, but in your case it is quoted at 1mA.  Unfortunately, Philips doesn't specify the current that is used for that specification.  What is does say, is that you need at least 1V head room between the Vgs(th) and the lowest voltage. 

SparkFun makes a level shifter based on the Philips design.  It uses the BSS138 mosfet (Vgs(th) = 1.5V @1 mA).  Your mosfet is potentially a bit above that.  However, its datasheet gives a range of 0.8 to 2.4V.  It is possible a particular device will be 2V or less.

If your are unfortunate, and it is 2.4V, then whether it works will depend on the current drawn by the I2C devices. There is no harm in trying it, except wasted time.  If it doesn't work, then you can order a device that meets that specification or try another device. Be sure to watch pinouts. 

Offline JustMeHere

  • Frequent Contributor
  • **
  • Posts: 432
  • Country: us
« Last Edit: June 17, 2021, 06:42:52 am by JustMeHere »

Offline Peabody

  • Super Contributor
  • ***
  • Posts: 1151
  • Country: us
Re: Making a 3V3 to 5V bi-directional level shifter
« Reply #3 on: June 17, 2021, 01:49:49 pm »
Isn't a PS2 keyboard just unidirectional?  If so, you don't need to complicate your life with bidirectional level shifting.  A simple resistor divider on each line should be enough.  And if memory serves, PS2 sends more like serial data, not I2C.  It's start bit, 8 data bits, parity bit, stop bit, so the same as serial, but with a separate clock line, so not asynchronous.

Edit:  Well it seems my memory is wrong, and it's actually bidirectional.  However, since the lines are open collector with pullups, if you could dedicate four GPIO lines to the keyboard, two for input and two for output, the resistor dividers would still work.

Edit2:  I think I was right the first time.  I looked through the Arduino PS2 Keyboard library, and it has no provision for sending anything to the keyboard, even an ACK.  So it doesn't really need to be bidirectional.  If the pullup resistors for the two lines are to 5V in the keyboard, then you could either use resistor dividers on the two lines, or you could remove the pullups in the keyboard if you can find them, and install pullups to 3.3V on the ESP32 side and connect to the GPIOs directly.  If the keyboard actually drives the lines high at any point, which it shouldn't, then the resistor dividers would still work.

« Last Edit: June 17, 2021, 02:52:01 pm by Peabody »

Online tooki

  • Super Contributor
  • ***
  • Posts: 6940
  • Country: ch

Offline JustMeHere

  • Frequent Contributor
  • **
  • Posts: 432
  • Country: us
Re: Making a 3V3 to 5V bi-directional level shifter
« Reply #5 on: June 17, 2021, 04:05:57 pm »
Isn't a PS2 keyboard just unidirectional?

I don't know exatly, but the CAPS LOCK led is lit based on a flag in the BIOS.
  Thus software can alter and detect the state of the keyboard LEDs.  Therefore, there must be some type of two way communication.   (You can use the cap lock key to troubleshoot a blank display.  If the LED turns on/off the computer is likely working and thei issue is likely the monitor.)
« Last Edit: June 17, 2021, 04:07:33 pm by JustMeHere »

Offline mikeyn6il

  • Newbie
  • Posts: 2
  • Country: us
Re: Making a 3V3 to 5V bi-directional level shifter
« Reply #6 on: June 21, 2021, 07:03:59 pm »
AT/Ps2 keyboard is absolutely bi-directional.  XT keyboard is unidirectional:

The PS/2 Keyboard Interface

The PS/2 Mouse/Keyboard Protocol

Thanks for the suggestions of using various level shifter chips.  I do have TSX0108 chips, but to be honest I have had poor luck using them.  My dad is an old salty EE type with a huge horde of basic electronics parts like I normally use for simple projects, so the ZVN3306A transistors likely came along in the bag with a request for something else. Parts for free beats ordering and waiting. Yes I have to build stuff but that's available off the shelf, but soldering up few transistors and resistors is not a big deal to me.

I would like to bring this thread to closure.  The ZVN3306A level shifter appears to work just fine.  I actually figured out what my problem was.  It is in fact a hardware problem, but it's not my hardware problem.

(1) Hooking the ZVN3306A-based level shifter up to a keyboard and hooking to my scope, I see only clock and data when the keyboard generates clock pulses
(2) Using a Raspberry PI as a logic analzyer (piscipe) which has up to 1us resolution I can see the clock and data just fine and actually decode the data coming from the keyboard.

This leads me to believe that the ZVN3306A-based level shifter is working well enough.

Loading the software on the ESP32 board, either this one or this one, I get good key presses most of the time, but sometimes there are glitches.  Again my test results above suggest there are no glitches coming from the keyboard or the level shifter. 

I went over to my dad's place and grabbed some 2N7000 transistors.  I put those in, repeated all the testing above the result is exactly the same.

So, I spent an evening doing some RTFMing.

Both of those keyboard reading sketches use the same code to read the data.  Ps2 data from device to host is read on the FALLING clock edge.  Both software configure an IRQ to fire on the FALLING edge of the keyboard clock line, and then each time they read(or write) one bit from(to) the keyboard. 

To help diagnose the glitchy behavior I added a bit of code to the sketches so that when the ISR is entered it turns a LED on and when the entire 11-bit packet is read it turns the light off.

The behavior I was observing was that mostly pressing keys the LED blinks as it is supposed to.  Occasionally, it gets stuck.  The LED turns on and stays on. This essentially means that that an IRQ came in when it wasn't expected -- Started reading a packet and never finished it. The code has a 250ms timeout, so if you press another key after that it will reset back to the beginning.

I'm using ESP32 here, so I did some googling and found out that there are some bugs in ESP32 handing edge trigger interrupts --


This is starting to sound like my problem. And further, Espressif themselves acknowleges the problem in their release notes:

ESP32 ECO and Workarounds for Bugs

Given this information, (a) according to my testing the level shifter is working well enough (b) clock in data only on FALLING clock edge (c) ESP32 hardware bugs, I can add 4 lines of code to workaround this problem:

Code: [Select]
#ifdef ESP32

Basically, since I know I only want falling edge, the current value of the IRQ pin when inside of the ISR routine should be low.  If it happens to be high then reject that state.

That's it.  Now the keyboard is being read 100%.  And again in conclusion, both ZVN3306A and 2N7000 seem to work well enough for general purpose bi-directional level shifter for this simple application.
The following users thanked this post: ledtester

Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo