First of all: I read through some of the suggested topics (i.e. connecting a 5V relay to an ESP), but to my (limited) understanding, this seems not to be the problem I'm trying to solve. If it is, please accept my apologies.

What I'm trying to do: I want to emulate an Atari-style joystick (which runs on 5V) with an ESP32 (3.3V). To do that, the direction pins of the joystick port need to be connected to the GND pin.

First I was thinking of using optocouplers because they provide galvanic isolation. However, since the ESP will be powered by the joystick port's 5V pin eventually, this might not be really necessary. So I thought about using transistors and supply the base of the transistor with the current from one of the ESP's GPIO. Collector and emitter would then be connected to GND and the respective direction pin of the joystick port.

Would that work as well and as reliable/fast as an optocoupler? I read about leakage current that can occur on transistors even if the GPIO connected to the transistor's base is off? And could I use BC547 (NPN) transistors for that purpose, as I have lots of them laying around here? Or would a different type be better? And last question: In some of the examples using a transistor as a switch, I saw that GND would be connected to the collector and the load to the emitter. I thought that current flows from the collector to the emitter via the base, so I would have expected GND to be connected to the collector?

Thanks in advance for any suggestions/explanations!

  • \$\begingroup\$ Hi, can you share more details about how the Atari-style joystick signal looks? sounds like a simple BJT can do it \$\endgroup\$ – Umar Aug 30 at 21:59
  • \$\begingroup\$ What device(s) (with a joystick port) might it be plugged into? \$\endgroup\$ – Bruce Abbott Aug 30 at 23:30
  • \$\begingroup\$ @Umar: An Atari (or C64 or Amiga..) joystick signal is nothing else than 5V on each direction pin that a joystick connects to the GND pin of the joystick port when moved to that direction. \$\endgroup\$ – fredlcore Aug 31 at 6:28
  • \$\begingroup\$ @BruceAbbott: It will be plugged into an Atari or C64 homecomputer. BTW: The solution from my other question where you helped so much worked in theory and generally also in practice, but you were right that synchronicity became a problem after a few minutes. So I'm trying it now this way where the joystick is read by the ESP and then the ESP switches the pins on the Atari joystick port. The same is done during "replay" later, so I hope that then timing/synchronicity will be less of an issue or hopefully not at all. \$\endgroup\$ – fredlcore Aug 31 at 6:29
  • \$\begingroup\$ "The same is done during "replay" later.." - You want to record joystick movements, then play them back later to 'replay' the game? \$\endgroup\$ – Bruce Abbott Aug 31 at 6:47

You only need a single transistor on each output, and it doesn't need (or want) a pullup. Like this:-


simulate this circuit – Schematic created using CircuitLab

If you are reading the joystick switches directly then the signal will have to be inverted, but that is easily done in software. A small signal switching transistor like the BC547 or 2N3904 has negligible leakage current and is much faster than an optocoupler, as well as requiring a lot less drive current.

If the problem you are trying to solve is what I think it is, you will need to synchronize joystick movements to the game running on the computer. Most games only read the joystick port once during each vertical blank (or close to it), so if you latch the joystick input before this time, then update and hold the output until after the computer has read the port, you should be able to achieve perfect 'playback' of movements (provided the game's timing is consistent).

At 50 or 60Hz frame rate the switching speed isn't critical, so long as you are producing a stable output during the time that the joystick is being being read by the computer. If the game is running at a lower update rate (eg. 25Hz) you still need to provide a new output on every frame because you don't know which frames are 'active'.

To summarize:- detect the vertical blanking pulse and wait for some time afterwards (after the game has finished reading the joystick port), then sample the joystick state and transfer it to the output, latching the output until the next sample time.

  • \$\begingroup\$ Thanks a lot! And you are of course right about the timing issues, but I have no means to detect when a vertical blank occurs if I just want to use a device plugged into the joystick port. Some homecomputers have ports that provide the system clock etc., but that would require extra cabling and make the device fixed to one system. But if you can think of any other means, I'd be happy to listen! \$\endgroup\$ – fredlcore Aug 31 at 8:24
  • \$\begingroup\$ With the previous solution you provided in my other question, a game would either run fine for five minutes or get out of sync after a few seconds already. However, this was not a timing issue but due to the fact that the ESP detected some movements (or maybe bouncing contacts) that the Atari did not, and vice versa. So by running everything through the ESP, I hope to eliminate this issue. Most games will allow for some leeway in joystick movements anyway, so I hope it wouldn't have to be cycle exact. Else, I would have to bury this project ;)... \$\endgroup\$ – fredlcore Aug 31 at 8:28
  • \$\begingroup\$ And is there any reason you used 2N3904 compared to the BC547s I have in dozens laying around here from a different project? \$\endgroup\$ – fredlcore Aug 31 at 8:29
  • \$\begingroup\$ 2N3904 is just the default in CircuitLab. They are equivalent. The C64 has composite and luminance output on the A/V connector. Ataris have composite video output on a din connector or a/v sockets. You could feed the composite/luminance signal into a sync stripper such as the LM1881. Just one little cable with a passthrough plug/socket is all you need, and then you should get perfect sync. \$\endgroup\$ – Bruce Abbott Aug 31 at 8:57
  • \$\begingroup\$ Wow, thanks, I'll give that a try! \$\endgroup\$ – fredlcore Aug 31 at 9:30

could I use BC547 (NPN) transistors for that purpose


These are not meant to be for really high speed switching (greater than a few 100 KHz) but will work assuming the joystick signal rate will be slower.


simulate this circuit – Schematic created using CircuitLab

  • \$\begingroup\$ Great, thanks a lot, I will try that! One further question: From my limited understanding, two transistors are necessary because one transistor would invert the signal, correct? Could I save one transistor by sending an inverted signal from the ESP (i.e. low instead of high and vice versa)? Also, normally one shouldn't connect the joystick pins to 5V because they COULD be configured as inputs when the computer boots up. As the joystick pin already carries 5V, could I simply omit the connection from 5V to the right transistor (and the 10k resistor) or is this then not going to work? \$\endgroup\$ – fredlcore Aug 31 at 6:33
  • \$\begingroup\$ By the way: Most games back then polled the joystick port once every TV frame, i.e. every 1/50 or 1/60 seconds, so around every 20ms. Would that be too fast (and would optocouplers be (significantly) faster)? \$\endgroup\$ – fredlcore Aug 31 at 6:38
  • \$\begingroup\$ 1. You can definitely omit one section if inverting is possible in software. 2. Optocouplers will be costlier solution, they are slower than BJT solution. You can omit 5 V if you are sure that they have pull-up internally. Needed to know more about the pin to decide on the 5 V omitting part.3. I would suggest to place a 1kohm resistor between the transistor collector and joystick input pin just in case \$\endgroup\$ – Umar Aug 31 at 6:58
  • \$\begingroup\$ Thanks! Yes, the joystick port has pull-ups internally, giving a high signal when no movement takes place and a low signal when the joystick connects the pin to GND. That would mean if inverting can be done in software, I can omit V1, Q2 and R2-R4, correct? \$\endgroup\$ – fredlcore Aug 31 at 7:41
  • \$\begingroup\$ Yes. Just R1 and Q1 are needed in that case \$\endgroup\$ – Umar Aug 31 at 10:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.