Pocket SNES

by Arnov Sharma in Circuits > Remote Control

452 Views, 3 Favorites, 0 Comments

Pocket SNES

Pocket SNES
24.gif
26.gif
33.gif
35.gif
THUMBb.JPG

Greetings everyone, and welcome back! Today, I’ve got something fun and tiny to share—the Pocket SNES, a miniaturized version of the classic SNES controller, built entirely from scratch using Custom PCBs and 3D Printed Enclosure.

This project has come a long way. I originally created an extra-large version powered by an XIAO SAMD21 Microcontroller encased in an extra-large Enclosure. I had to print the enclosure in three separate parts and then assemble them together to form a single controller unit that was huge. For version 2, I intend to reduce its size to something less than the palm of a hand while maintaining functionality.

For the smaller version, I intend to use the RP2040-Tiny mini development board, which is an SMD or Module version of the Raspberry Pi PICO. This RP2040 Tiny Module was mounted on a controller-shaped PCB with Small SMD tactile buttons on one side and the RP2040 controller on the other. To improve the controller's grip, I added an enclosure attached to the bottom side of the PCB, making it comfortable to hold.

Despite its small size, the Pocket SNES works fairly well. We initially used the controller to play Broforce, we had to map its buttons to control our avatar or character. Basically, we can use this controller in any game; we simply need to map the keys.

Next, we tried this controller with our MAC Pi setup, and I played a few games on the PPSSPP emulator, including Moto GP 3 and Dead or Alive Paradise. In this case, we also had to map the controller in the PPSSPP Emulator settings.

Overall, this tiny controller works similarly to a standard-sized SNES controller, with 12 buttons. The best part about this project is that we can finish it in a few simple steps because it is just a PICO connected with 12 buttons.

In this Instructables, we will go over the entire process of developing this tiny and simple console, so let's get started.

Supplies

These are the materials used in this project:

  1. Custom PCB (Provided by PCBWAY)
  2. RP2040 Tiny Dev Board with USB Adapter Board
  3. SMD Tactile Buttons
  4. 3D printed enclosure
  5. THT Right Angle Tactile Switch
  6. M2 Screws

DESIGN

untitled.24.png
untitled.26.png
Screenshot 2025-05-27 153142.png
Screenshot 2025-05-27 153207.png
Screenshot 2025-05-27 153339.png
Screenshot 2025-05-27 153351.png
Screenshot 2025-05-27 153405.png
untitled.25.png

We begin by creating the project's model, which was a major challenge.

We created an XL version before developing the Tiny version. The XL version has an unrestricted area, allowing for unrestricted component layout without regard for space.

In our Tiny version, the initial idea of assembling an enclosure and placing components inside proved impractical. Instead, I designed a PCB that accommodates all components on both sides, with a frame-like part attached to the bottom. This frame provides protection for the adapter board and improves user grip.

The SMD buttons are positioned on the top side of the PCB, while the right-angle tactile switch and the RP2040 Tiny Dev board are placed on the bottom. The USB adapter board is mounted on the back, secured by screw bosses integrated into the frame.

Once the model was finalized, we exported the mesh file for 3D printing using transparent PLA, allowing the onboard RGB LED to illuminate through the material. Additionally, the board’s DWG file was exported for use in the PCB editing process.

RP2040-Tiny Micro Development Board

800px-RP2040-Tiny-Kit-details-11.png
rp2040-tiny-1.jpg
rp2040-tiny-3.jpg

We are using the RP2040-Tiny mini development board, which is based on Raspberry Pi's RP2040 core. It includes a separate programming adapter board that keeps the type C USB port separate from the circuit, reducing overall thickness and size, making it easier for users to integrate into their projects.

In terms of technical specifications, it's essentially a Pico with an RP2040 microcontroller chip and a few modifications, such as the Onboard FPC 8PIN connector, which connects the module to the Type C adapter board, and the addition of Castellated holes or pads, which allow soldering directly to carrier boards.

We also have a WS2812B 2020 Package LED added on the board, which is connected to GPIO16.

Overall, this board shares its technical parameters with PICO 1, which includes the RP2040 Dual-core Arm Cortex M0+ processor, flexible clock running up to 133 MHz, 264KB of SRAM, and 2MB of onboard Flash memory.

For in-depth details about this Dev Board, you can check out its Wiki Page from the link below.

https://www.waveshare.com/wiki/RP2040-Tiny

As for where I got it, we got it from PCBWAY's Gift Shop, which is an online marketplace for getting electronics modules and dev board sensors at their genuine pricing, or you can get them through PCBWAY's Reward system known as beans.

Checkout PCBWAY's Giftshop from here

https://www.pcbway.com/project/gifts.html

PCB DESIGN

SCH_page-0001.jpg
Screenshot 2025-05-27 234221.png
Screenshot 2025-05-27 234247.png

As previously stated, the PCB design for the Game Controller was truly simple; it is essentially an RP2040 Tiny Dev Board connected to 12 SMD Push buttons, each of which is attached to an RP2040 GPIO Pin. All SMD Button Terminals are linked to GND. When a button is pressed, the GPIO attached to it is connected to GND, and our microcontroller registers the change in button state.

After setting up the schematic, we exported the netlist and used the DWG file from the 3D model to create the shape of the board. All SMD buttons, including the two trigger buttons, were placed according to the 3D model. Four mounting holes were also added to the PCB, which will be used to connect the frame to the board.

The RP2040 Dev board is put on the bottom side of the board.

PCBWAY SERVICE

01.gif
IMG_5553.JPG

Following the completion of the board design, we ordered a white solder mask with black silkscreen and submitted the PCB's Gerber data on the PCBWAY quote page.

PCBs were received within a week, and the PCB quality was outstanding. Here, we added a few design elements on the board's silkscreen layer to increase the aesthetic appeal of the project. PCBWAY made the custom layer properly, which shows their great PCB manufacturing capabilities.

Over the past ten years, PCBWay has distinguished themselves by providing outstanding PCB manufacturing and assembly services, becoming a trusted partner for countless engineers and designers worldwide.

You guys can check out PCBWAY if you want great PCB service at an affordable rate.

PCB ASSEMBLY-SMD SWITCH ASSEMBLY

02.gif
03.gif
04.gif
05.gif
  1. We begin the PCB Assembly process by placing SMD switches on the top layer of the PCB. This is carried out by applying solder paste to each component pad one by one with a solder paste dispensing needle, in this case using normal Sn/PB 63/37 Solder paste.
  2. We use an ESD Tweezer to pick and install all SMD tactile switches.
  3. We next pick up the circuit and place it on our Miniware Reflow hotplate, which heats the PCB from below up to the solder paste melting temperature, allowing us to solder all of the components in their proper locations.

PCB ASSEMBLY—RP2040 Tiny Assembly

06.gif
07.gif
08.gif
09.gif
10.gif

The RP2040 Tiny Assembly process differs slightly from the previous reflow process in that we cannot use a hotplate to heat the surface of the PCB since it contains SMD components on the top side, preventing us from using a hotplate to solder components on the bottom.

  1. We use our soldering iron here; first, we dip the solder wire in flux before melting it on the first pad on the RP2040 tiny's footprint.
  2. We use tweezers to pick and place the RP2040 in its location, then use a soldering iron to heat up the previously soldered pad. This will melt the solder and attach the RP2040 to its footprint.
  3. We then solder the opposing terminals of the RP2040 Tiny, securing the module with its PCB Footprint. All that remains is to solder all pads with a soldering iron.

PCB ASSEMBLY—THT Switch Assembly

11.gif
12.gif
13.gif
  1. We install the THT switches from the bottom side of the circuit.
  2. next we solder their pads from the top side of the board with a soldering iron.
  3. Finally, we use a wire cutter to trim the THT Vertical Switch Pads that are visible from the top side.

Adapter Board & Controller Connection

14.gif
15.gif
16.gif

Now that the board assembly is complete, we begin the assembly process of connecting the USB Adapter Board to our Main Switch Board. For this link, we utilize the provided Flexible cable, which we first attach to the Type C board.

Next, we connected the flex cable to the connector found on the RP2040 Tiny board. The connection order of the flex cable is crucial; the blue side should likewise be on the top side, and the cable should be routed all the way through the inner connector.

Also, the cable that came with the RP2040 was rather long, so we bent it to make it shorter.

FRAME ASSEMBLY

17.gif
18.gif
19.gif
20.gif
21.gif
  1. The frame assembly process begins with passing the USB Adapter board through the Frame part, followed by aligning the circuit's mounting holes with the Frame part's.
  2. We then use four M2 screws to secure the frame part to the circuit.
  3. Next, place the adaptor board over the screw bosses added to the back side of the frame and fasten it in place with two M2 screws.

The Pocket SNES Assembly has been completed; let us take a look at the code for this project.

CODE

This was the code used in this project and it's a simple one.

#include "Adafruit_TinyUSB.h"
#include <Adafruit_NeoPixel.h>

// === WS2812 Setup ===
#define LED_PIN 16 // GPIO16
#define NUM_LEDS 1
Adafruit_NeoPixel pixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

// === Gamepad Setup ===
#define NUM_BUTTONS 12
const uint8_t buttonPins[NUM_BUTTONS] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
};

// Gamepad HID Descriptor (12 buttons)
uint8_t const hid_report_descriptor[] = {
0x05, 0x01, 0x09, 0x05, 0xA1, 0x01, 0x15, 0x00,
0x25, 0x01, 0x35, 0x00, 0x45, 0x01, 0x75, 0x01,
0x95, 0x0C, 0x05, 0x09, 0x19, 0x01, 0x29, 0x0C,
0x81, 0x02, 0x75, 0x01, 0x95, 0x04, 0x81, 0x03,
0xC0
};

Adafruit_USBD_HID usb_hid;
uint8_t report[2] = {0};

void setup() {
for (int i = 0; i < NUM_BUTTONS; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}

// Setup NeoPixel
pixel.begin();
pixel.setBrightness(50);
pixel.show(); // Initialize to off

// Setup USB HID
usb_hid.setReportDescriptor(hid_report_descriptor, sizeof(hid_report_descriptor));
usb_hid.setPollInterval(2);
usb_hid.begin();

while (!USBDevice.mounted()) delay(10);
}

void loop() {
static uint32_t last = 0;
if (millis() - last < 10) return;
last = millis();

// Clear report
report[0] = 0;
report[1] = 0;
bool anyPressed = false;

for (int i = 0; i < NUM_BUTTONS; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
report[i / 8] |= (1 << (i % 8));
anyPressed = true;
}
}

// Update LED: Purple if any button is pressed
if (anyPressed) {
pixel.setPixelColor(0, pixel.Color(255, 0, 255)); // Purple
} else {
pixel.setPixelColor(0, 0); // Off
}
pixel.show();

usb_hid.sendReport(0, report, sizeof(report));
}

Our code. We basically set up the RP2040 as an HID gamepad using the Adafruit TinyUSB Library, and we also included a WS2812B LED for visual feedback when buttons are pressed.

#include "Adafruit_TinyUSB.h"
#include <Adafruit_NeoPixel.h>

The code begins by including the necessary libraries, which in our instance are the Adafruit Tiny USB, which handles USB communication, and the Adafruit Neopixel Library, which controls the WS2812B LED.

#define LED_PIN 16 // GPIO16
#define NUM_LEDS 1
Adafruit_NeoPixel pixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

Next, we define a single WS2812 LED connected to GPIO16, then set up an Adafruit NeoPixel object to handle RGB color control.

#define NUM_BUTTONS 12
const uint8_t buttonPins[NUM_BUTTONS] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
};

In this part of the code, we define 12 buttons connected to GPIO pins 0 to 11. These buttons will be read to determine user input.

uint8_t const hid_report_descriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x05, // Usage (Gamepad)
0xA1, 0x01, // Collection (Application)
...
0xC0 // End Collection
};

This section defines the USB HID report descriptor for a 12-button gamepad. basicallt This instructs the computer on how to interpret incoming data, including which buttons are being pressed.

Adafruit_USBD_HID usb_hid;
uint8_t report[2] = {0};

Here the usb_hid Initializes the USB HID object for communication.

The report[2] Stores the pressed button states.

void setup() {
// **1. Configure buttons** (INPUT_PULLUP)
for (int i = 0; i < NUM_BUTTONS; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}

// **2. Initialize NeoPixel LED**
pixel.begin();
pixel.setBrightness(50);
pixel.show(); // Turn off initially

// **3. Configure USB HID (Gamepad)**
usb_hid.setReportDescriptor(hid_report_descriptor, sizeof(hid_report_descriptor));
usb_hid.setPollInterval(2);
usb_hid.begin();

// **4. Wait until USB is connected**
while (!USBDevice.mounted()) delay(10);
}

In the setup, we have four things that are happening: First, the buttons are initialized; each button is configured as an input pullup, ensuring that the buttons default to high when not touched and low when pressed.

The WS2812B LED is then initialized, and the brightness is set to 50, which can be increased up to 255.

then The HID report descriptor defines how button data is sent to the computer.

The program then waits until the USB device is mounted, ensuring proper communication with the computer.

void loop() {
// **1. Limit execution to every 10ms**
static uint32_t last = 0;
if (millis() - last < 10) return;
last = millis();

// **2. Clear button report**
report[0] = 0;
report[1] = 0;
bool anyPressed = false;

// **3. Read button states**
for (int i = 0; i < NUM_BUTTONS; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
report[i / 8] |= (1 << (i % 8));
anyPressed = true;
}
}

// **4. Update LED (Purple if any button is pressed)**
if (anyPressed) {
pixel.setPixelColor(0, pixel.Color(255, 0, 255)); // Purple
} else {
pixel.setPixelColor(0, 0); // Off
}
pixel.show();

// **5. Send button report via USB HID**
usb_hid.sendReport(0, report, sizeof(report));
}

In the loop function, first we have added the Limit Execution Rate that Runs every 10ms to prevent unnecessary rapid updates.

then the code Resets the report array, which holds the button states.

Check Button States Loops through each button to check if it's pressed.

If any button is pressed, the NeoPixel turns Lite Blue.

At last, the updated button data is sent to the computer, acting as a gamepad input.

RESULT

Pocket SNES
27.gif
30.gif
31.gif
33.gif
34.gif

Here's the end result of this simple and tiny build: the Pocket SNES game Controller, an extremely portable gaming controller designed for playing old retro games with a layout similar to the SNES. It can also be used to run select modern titles that don't require left and right thumbsticks.

This device has dimensions of 74.5mm x 33.8mm x 11.5mm, making it one of the tiniest DIY game controllers.

For testing, we first played Broforce, an action-packed, side-scrolling run 'n' gun game with a campaign, bonus levels, unlocked characters, and violent enemy clashes. Broforce is a group of hyper-masculine action heroes inspired by renowned characters from old movies and TV shows. They fight terrorists and free their fellow Brothers from captivity. Each Bro has distinct talents, weaponry, and special attacks, making them handy in a variety of circumstances. This game is pretty awesome and fun to play in multiplayer.

The controller is an ideal match for a side-scrolling game; the controls were first mapped in the game settings, allowing us to manage our player.

We installed Broforce on Windows, but what if we want to utilize this controller on another operating system, such as Raspberry Pi or another game emulation OS? Testing was critical since it would allow us to use this controller with our past Raspberry Pi-based game console projects.

Using our previous build MAC Pi, we installed the PPSSPP emulator using Pi applications and then played a few PSP games, including Dead or Alive Paradise and Moto GP 3. We first had to map the button in the settings, and then both games ran quite smoothly with our Mini Controller.

The Small SMD Buttons were not particularly soft to use, but they functioned properly overall.

WHAT'S NEXT

32.gif

The one thing I'd like to change in the next version is to replace the RP2040 Tiny with the Raspberry Pi PICO W or 2W, due to the WiFi/Bluetooth connectivity, which eliminates the need for a USB cable entirely. This will allow the device to be truly portable.

For the time being, this project has been completed, and all of the necessary details, including PCB files, code, and other information, are all attached.

In addition, we appreciate PCBWAY's support of this project. Visit them for a variety of PCB-related services, such as stencil and PCB assembly services, as well as 3D printing services

Thanks for reaching this far, and I will be back with a new project pretty soon.

Peace.