Introduction: USB Paddle Game Controller

My son was having a retro video games night for his birthday, and on the morning of the day I decided to see if I could make a pair of USB paddle game controllers for Pong with the help of a 3D printer and electronics from my stash. While I did manage to get them basically working in time, people were too busy with other games for Pong in the end.

The controllers can be used for Pong with the DICE circuit-level emulator or with my fairly accurate pygame version, for Atari 2600 games with an emulator, and for Etch-a-Sketch-like functionality with a painting program like Tux Paint.

There are three switchable modes:

  • Stelladaptor paddle emulation: they should work with all Atari 2600 emulation software that supports the Stelladaptor; in Stelladaptor mode, the paddles function as two-axis two-button joystick, each paddle controlling one axis and one button
  • dual joystick emulation: each paddle functions as a joystick with one button (with the paddle movement translating to movement on both joystick axes)
  • mouse: each paddle controls one direction of motion for an absolute mouse, and the buttons are mouse buttons; together with a painting program you can get a high-tech device similar to an Etch-a-Sketch.


You will need:

  • stm32f103c8t6 blue pill
  • 2x linear potentiometer (I'd recommend 20K-100K)
  • 2x 12mm-width microswitch with button
  • 3D printer
  • miscelleanous (filament, wires, solder, soldering iron, hot glue)

Step 1: Prepare Board and Arduino Environment

  1. Solder the six header pins in the middle of your stm32f103c8t6 board.
  2. Check the resistance between A12 and 3.3V. It should be 1.5K for fuller USB compatibility. Many boards have 10K instead. If your is one of those, ideally solder in a 1.8K resistor from A12 to 3.3V, though you might be lucky and have your computers work with the 10K.
  3. Install a bootloader. There are instructions in Step 2 of this Instructable. One thing to make note of is what the flash size reported by the STM Demonstrator is. If it's 32K, you have a fake stm32f103c8 which is probably a relabeled stm32f103c6. This project should still work with that, but make a note that you have the fake board for a future step.
  4. Install Arduino, Arduino Zero and Roger's libmaple-based core following the instructions in Step 3 of the Instructable you used in the previous step. Ignore the library instructions in that step.
  5. Download the latest release of my USB Composite library and unzip it in your Arduino/Libraries folder.
  6. Download my paddlecontrollers sketch and unzip it in your Arduino folder.
  7. In Arduino, go to Tools | Board | Generic STM32F103C Series, unless you have the fake c6 board, in which case choose Generic STM32F103C6/fake STM32F103C8 instead. If you're not sure which you have, choosing the fake option is actually safer.

Step 2: Upload

Plug board into your computer's USB adapter, load the paddlecontroller sketch, and click the Upload button (right pointing arrow). If all goes well, the sketch should upload, and the board should show up on your computer as a two-axis two-button joystick called "Stelladaptor". In Windows, you can verify this with Windows-R, joy.cpl[enter].

Of course, this won't do anything until you have the rest of the hardware assembled.

Step 3: Print

  1. Download the stl and/or scad files from my Thingiverse page for this project. Please note that the paddle knob is modified from here.
  2. If your microswitch housing width is different from 12mm, you will need to adjust the button width parameter in the paddlemain-standalone.scad file. You can do that in OpenSCAD or in the Thingiverse Customizer.
  3. You may need to tweak the measurements in the paddleknob.scad file to fit your potentiometer.
  4. Print these files (do only one copy of the "2x" files if you just want one paddle). I used PLA, but ABS should work well, too.
    • 2x paddlemain.stl
    • 2x paddleknob.stl
    • 1x paddleconverter.stl
    • 1x pcbholdernarrower.stl
    • 2x buttoncap110.stl (optional)
    • 1x 12.stl (optional; print in a different color and glue on to label the two paddles)

Step 4: Wiring

You will need to run four wires from the stm32f103c board to each paddle controller. You could use old USB cords for these wires. I happened to have nice standalone wires from an ethernet cable which I bound together with shrink wrap.

Each paddle has one microswitch and one potentiometer. Use a multimeter to identify a pair of adjacent (not diagonal) pins on the microswitch that are connected/disconnected by pressing the button. I will label these pins S1 and S2 in the diagram. The three pins on the potentiometer I've labeled P1, P2 and P3 from top to bottom, looking from the underside of the potentiometer, with pins pointing right.

Push the four wires from the board through the hole on the side of the paddle housing (paddlemain.stl).

When connecting wires to the microswitch, first push the wires through the holes in the side of the paddle housing and solder to the switch while the switch lies on the outside of the housing. Then pull the switch to the housing, making the pins and attached wires fit in the holes. I cut off the unnecessary pins.

Both paddles:

  • P1 to S1
  • P1 to board 3.3V (3.3)
  • P3 to board GND (G)

Paddle 1:

  • P2 to board A1
  • S2 to board A2

Paddle 2:

  • P2 to board A3
  • S2 to board A4

Now test the connections by connecting to your computer and using a joystick test program. On windows, Windows-R, joy.cpl[enter], select Stelladaptor, click on Properties. Paddle 1 should control the X-axis and the first button; paddle 2 should control the Y-axis and the second button.

Step 5: Final Assembly

The microswitches can be glued (hot glue did the job for me) in their locations on the side of the paddle box. Button caps can be snapped on, with a bit of hot glue for stability.

The potentiometer attaches to the big hole in the top of the paddle box. The knob should slide on and stick on. Enlarge holes with a drill as needed. Push the bottom cover on, adding a bit of hot glue if you like.

The blue pill board fits inside the PCB slide, which then screws to the bottom of the converter box, which also has a lid that can cover it up.

I added a bit of Shoe Goo where wires meet the housing to protect the wires. And I glued on "1" and "2" labels on the paddles.

Step 6: Modes of Operation

The paddles have three modes of operation. You can switch the mode of operation by pressing a particular combination of buttons while plugging them into a USB port, releasing once the board LEDs stop flashing. Once you switch the mode of operation, it will be saved to flash memory, and will stay until you next change it. (So, if you don't want to change the mode, don't press any button while plugging the paddles into a USB port.) Here are the options:

  • Left paddle button only: One two-axis two-button joystick, with each axis and button controlled by one paddle. Moreover, the paddles identify as a Stelladaptor, a discontinued USB adapter for Atari 2600 controllers, and so Atari 2600 emulators like Stella and Z26 that are Stelladapter compatible should work perfectly.
  • Both paddle buttons: Each paddle shows up a separate joystick. The joystick has one operational button, and turning the paddle moves the joystick diagonally, so either the X or the Y axis works for the paddle.
  • Right paddle button only: The paddles show up as a two-button absolute mouse. You can now use this similarly to an Etch-a-Sketch with a drawing program.

Step 7: Pong

Pong was the great original paddle game. I recommend the original version, because clones often fail to include all the lovely subtle functionality, like the changes in speed with repeat hits, the angle changes depending on the part of the paddle that hits the ball, or the subtly but not easily predictable position of the serve after a miss. For a careful analysis of the original, see here.

One of the best way to play Pong is with the DICE circuit-level emulator if your computer is fast enough to use it at full speed. (My Windows laptop is, but the Raspberry PI 3+ is much too slow.) I recommend version 0.8.

If you use the Stelladaptor mode in the paddles, go to Settings | Configure Inputs... in DICE and choose Joystick 1 and Absolute for Player 1 Paddle, and set both Horizontal and Vertical to Joy 1 X-Axis. Then do the same for Player 2 Paddle, except with Y-Axis.

If your computer is too slow for DICE, I made a Python3+pygame version whose timings and functionality are meant to be very close to the original Pong (I am grateful for help from Dr. Hugo Holden in this regard).

3D Printed Contest

Participated in the
3D Printed Contest