Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Cory Parsnipson
Nov 15, 2015
I’m doing an electronics project. I hope this fits in with all the building DIY projects. I want to make this accessible to people not familiar with electronics or electrical engineering. I like video games and making video game related hardware makes me excited and I hope you get excited reading this too. :)



“Making” a gameboy? What does that mean? Like, you’re making a mock-up for design school or something? Drawing pictures of one you’d like to exist??

No I mean, like, physically making a game console you can hold in your hands and walk around with. Not completely from scratch, of course. I don’t exactly know all the work that goes into something like this, but it’s going to be a lot of electronics work and some software development. There’s a lot of guides out on the internet about making your own game system but for some reason they stop halfway (in my opinion) by skimping on features, polish, or capabilities. I want to make something that I would actually use myself and not just a short lived toy that looks good in a tutorial.

Why are you doing this

Let’s rewind back to March. The year is 20XX. poo poo hit the fan everywhere at the same time and it wasn’t clear whether or not people would be allowed to go outside anymore. Nobody was able to wipe their rear end for 6 weeks. Nintendo Switch sales went through the roof and, because of manufacturing slowdowns, the supply absolutely dried up. This meant it was sold out from every store you could imagine, and the units you could buy online were being sold by scalpers for ridiculous prices. Seeing as how I also wanted to buy a switch, I decided to do the crappy immigrant parent thing and buy a lovely knock-off that wasn’t as good.

Enter: the Raspberry Pi.






If you don’t know, a Raspberry Pi is a cutely named portable computer. It runs a variant of the Linux operating system and people like using them in hobby projects because they’re cheap and the entire system comes in one piece, meaning you only need the peripherals you would normally attach to a regular desktop computer like a keyboard, LCD, and mouse. This computer isn’t very powerful, but you can use them when you need a high end microcontroller for projects like uh…

  • Making drones
  • Automated sprinkler management system
  • Home media server
  • etc

Ok, so what is this project?

I’m stuck in my room without a Nintendo Switch and I just want to play games while lying down on the couch. Without having to look at the TV. Also I want all my games in one box.

I’m a big fan of the Nintendo 3ds and I have one that I play regularly. I think it’s almost perfect except that there’s two screens and it folds. I think my ideal handheld would be the lower half of a Nintendo 3ds with some elements taken from the Nintendo Switch. So that’s what I’m attempting to make.

Here’s a child’s drawing that I made:


I always feel a little crazy when explaining what I’m doing to other people. If it sounds insane and a whole lot of work, that’s because it is. On the other hand, I’ve been pleasantly surprised at the capabilities available to hobbyists in the modern DIY electronics space. Kids these days have all the Raspberry Pi’s and the Arduinos and the widely accessible youtube guides for repairing gaming hardware. When I was in school, you had to search for microcontrollers by name (e.g. STM32F103C8T6) and if you had questions, people would just call you a nerd and laugh. :corsair:

Project Goals

I feel like I’m spoiling things by writing this out, but seeing as I’m unlikely to actually get that far, here goes:

Phase 1 - COMPLETE

Just make something, anything. This is where I’m at now. Take a Raspberry Pi, add an LCD, add speakers, add controller buttons, and add a battery. Then put it all in a cardboard box. Maybe it'll be a pizza box who knows.

Phase 2

Next I’d figure out how to make a plastic casing (3d printing, anyone?) and put all my circuitry on a green circuit board (this is called a PCB for those in the know). This would also involve moving away from the Raspberry Pi 3A+ model shown above and using the more portable Raspberry Pi Compute Module 3.

Create a compact version of a portable raspberry pi somehow, using custom PCB's if necessary. Upgrade the power supply to be able to supply the 5V 3A power envelope and increase battery capacity for acceptable battery life. Also make sure this has undervoltage protection to solve range anxiety issues. Use smaller audio circuitry with louder and more power efficient speakers. Add meta buttons, fix shoulder buttons. Use a cheaper LCD screen that doesn't come in an all-in-one package.

If possible design the RPI attachment to be modular so that the RPi 3A+ can be swapped out for the Compute Module 3 or an RPi4 or some other SBC of similar size.

I’d consider “the Gameboy” to be complete at this point.

Phase 3

Dockify this poo poo, yo! The Raspberry Pi already expects people to hook this up to an external screen like a traditional PC. So I’d really like to copy the Nintendo Switch and make a docking station for my console so I can play it on a big TV or in handheld mode. This might involve moving some components around on the PCB and fiddling with different (USB/HDMI/etc) port configurations to get it to work well with a docking station.

Phase 4

:filez:??? What :filez:? From here on out, this will start to sound like some kind of pipe dream. Modify the previous hardware to expose the 40 GPIO pins. This may require moving the existing connections to the higher pin numbers that are only available via the Compute Module. This would be really cool because then you could interface with the lowest 40 GPIO pins as if you were still carrying around a vanilla Raspberry Pi with you. Then this turns into a hybrid gaming console and regular Raspberry Pi (with buttons attached) if you wanted to continue developing random Raspberry Pi projects on it. Also replace the Retropie image with a regular Raspbian image for more of a linux desktop experience. I don't know if this would work since Raspbian might have too much overhead to play games on. This could probably be worked around with some creative use of scripts.

Some software mods might come in handy to write code using a game controller instead of a keyboard and mouse. I might attempt to use this as a daily dev computer.

Phase 5

I'm thinking about adding a cartridge slot to it. This would just be a hardware wrapper around an SD card (that you already need to insert into the raspberry pi anyway). I got some cool ideas for a 3d printed case that might also use a microcontroller to show box-art on an e-ink display depending on what files you have loaded in the card. There's some logistics to figure out here because the Raspberry Pi only has a limited number of SD card interfaces you can bolt on to it and the wireless module also uses one of these slots.

Phase 6

Since I started the project, the Raspberry Pi foundation has released the next version of hardware creatively dubbed, the Raspberry Pi 4. This is a much, much more powerful computer that’s slightly more expensive than the RPi3 but it is also approaching netbook/tablet levels of compute power. I hear that you can play PSP and playstation games on it. Switching to using an RPi4 would really make it feel like a portable linux computer.

Phase 7+

Swap out the Raspberry Pi for a custom CPU and maybe use an FPGA to create custom hardware accelerators in the hope to support even more powerful software applications. And write custom software to act as an alternative to RetroPie. Pshhh yeah, like this would be some Tony Stark level poo poo.

Cory Parsnipson fucked around with this message at 06:14 on Jan 20, 2022

Adbot
ADBOT LOVES YOU

Cory Parsnipson
Nov 15, 2015
Table of Contents

Part 1: Young, dumb, and full of crazy half baked ideas
  1. The OP

  2. 1.8" TFT Screen

  3. Sound Breadboarding (Part 1, Overview)
  4. Sound Breadboarding (Part 2, About Amplifiers)
  5. Sound Breadboarding (Part 3, I2S and Stereo Decoder)
  6. Sound Breadboarding (Part 4, Protoboard Time)

  7. Input Breadboarding (Part 1, Cory Decides to Use an Arduino)
  8. Input Breadboarding (Part 2, Pushbutton Prototype)
  9. Input Breadboarding (Part 3, Thumbstick Research and Shopping)
  10. Input Breadboarding (Part 4, Thumbstick Pinout and Breakout Board)
  11. Input Breadboarding (Part 5, Thumbstick Software Calibration)

  12. 5" OSOYOO LCD Screen

  13. Input Breadboarding (Part 6, Extending 10 Buttons to 20)
  14. Input Breadboarding (Part 7, Cory Does Charlieplexing)
  15. Input Breadboarding (Part 8, Charlieplexing Implementation With Switches)
  16. Input Breadboarding (Part 9, Shopping for "Real Buttons")
  17. Input Breadboarding (Part 10, Membrane Testing with Conductive Ink)
  18. Input Breadboarding (Part 11, Steve-O Pays a Visit)
  19. Input Breadboarding (Part 12, Re-hooking Thumbstick to Charlieplexed Setup)

  20. Exploring the Inside of My 3DS and Joycons
  21. Ooooh yeah
Part 2: The Great Cardboard Debacle
  1. Cardboard Enclosure (Part 1, VISUALIZATION)
  2. Cardboard Enclosure (Part 2, CAD: Cardboard Aided Design)
  3. Cardboard Enclosure (Part 3, Trouble with Z height of Left Controller Pieces)
  4. Cardboard Enclosure (Part 4, Origin of the Cardboard Backplane)

  5. Device Review (Also I Got A 3D Printer)

  6. Cardboard Enclosure (Part 5, Copper Tape Testing)
  7. Cardboard Enclosure (Part 6, Designing a Charlieplexing Paper Circuit)
  8. Cardboard Enclosure (Part 7, Finalized Charlieplexing Circuit)
  9. Cardboard Enclosure (Part 8, I Shouldn't Have Used Charlieplexing! Motherf*cker!)
  10. Cardboard Enclosure (Part 9, Charlieplexing Post Mortem)
  11. Cardboard Enclosure (Part 10, Key Matrix Research)
  12. Cardboard Enclosure (Part 11, Key Matrix is Now My New Friend)
  13. Cardboard Enclosure (Part 12, Right Controller is Cut Out)
  14. Cardboard Enclosure (Part 13, Controller Cables Made out of Paper)
  15. Cardboard Enclosure (Part 14, Cutting out Shoulder Buttons)

  16. Prusa's Here

  17. Cardboard Enclosure (Part 15, Laid Down Copper Tape on Paper Cable)
  18. Cardboard Enclosure (Part 16, Should I Give Up?)

  19. Building the Prusa (Part 1)
  20. Building the Prusa (Part 2)
  21. Building the Prusa (Part 3)
  22. The First Print
  23. The, uh..., First Print

  24. Cardboard Enclosure (Part 15, PSYCH! Never Gonna Give You Up)
  25. CardBoard Enclosure (Part 16, Clutch cakesmith)
  26. Cardboard Enclosure (Part 17, Sturdy Cable)

  27. Printing Benchys and First Foray into KiCAD

  28. Cardboard Enclosure (Part 18, More Benchys and Another Cable)

  29. There and Back Again: Adventures in 3D Printing
  30. Variable Layer Height

  31. Cardboard Enclosure (Part 19, Testing Metal Dome Switch Membrane with Copper Tape)
  32. Cardboard Enclosure (Part 20, DOUBLE PSYCH! I Gave Up)
Part 3: Up to My Eyeballs in CAD
  1. FreeCAD Modeling (Part 1, Tutorials)
  2. FreeCAD Modeling (Part 2, Useful 3D poo poo)
  3. FreeCAD Modeling (Part 3, Legend of Cory)
  4. FreeCAD Modeling (Part 4, Useless 3D poo poo)

  5. KiCAD (Part 1, Controller Schematic)
  6. KiCAD (Part 2, Why Did They Use Separate PCB's????)
  7. KiCAD (Part 3, Audio Amplifier Schematic)
  8. KiCAD (Part 4, PWR_FLAG)
  9. KiCAD (Part 5, Cory Makes a Footprint :can:)
  10. KiCAD (Part 6, Cory Sings a Stupid, Cringey KiCAD Song)
  11. KiCAD (Part 7, Laying Out Footprints)

  12. Ahhh, Whoops...

  13. KiCAD (Part 8, Starting to Make a Metal Dome Switch Membrane Footprint)

  14. Cory Discovers the Raspberry Pi Fusion

  15. Cory Loses His poo poo Over Making a PCB (Part 1)
  16. Cory Loses His poo poo Over Making a PCB (Part 2)
Part 4: Third Time's the Charm
  1. PLA Enclosure (Part 1, Putting the Printer to Use)
  2. PLA Enclosure (Part 2, Thumbstick holder v1)
  3. PLA Enclosure (Part 3, Thumbstick holder v2)
  4. PLA Enclosure (Part 4, Shoulder Buttons)
  5. PLA Enclosure (Part 5, Fused Controller Frame)
  6. PLA Enclosure (Part 6, Left Controller Pieces in Place)
  7. PLA Enclosure (Part 7, Turning on Ironing for Shoulder Buttons)
  8. PLA Enclosure (Part 8, Enter: the Chassis)
  9. PLA Enclosure (Part 9, ABXY Button Jig)

  10. Help, My Baby Boy is Addicted to CAD!

  11. PLA Enclosure (Part 10, Both Controllers Mounted)

  12. Fun Ideas with Cakesmith

  13. PLA Enclosure (Part 11, Wiring Left Side)
  14. PLA Enclosure (Part 12, Switched to Higher Gauge)
  15. PLA Enclosure (Part 13, Weird Behavior Seen During Wiring)
  16. PLA Enclosure (Part 14, Booting up Linux With Half a Controller)
  17. PLA Enclosure (Part 15, Wiring Explained)
  18. PLA Enclosure (Part 16, USB Connector on Arduino Broke Off)
  19. PLA Enclosure (Part 17, Reinforced and Rebuilt)
  20. PLA Enclosure (Part 18, The Future of Gaming)
  21. PLA Enclosure (Part 19, Chassis Version 2)

  22. Need to Revisit Power Dissipation in Thumbstick Module
  23. Should be Okay I Guess?? Also Links to Batteries

  24. PLA Enclosure (Part 20, Chassis V2 and Second Tier Fit Check)
  25. PLA Enclosure (Part 21, Add Sound Back In)
  26. PLA Enclosure (Part 22, Sound's Working Again)

  27. Batteries, USB hubs, BitBuilt Projects, oh my!
  28. Batteries (Part 2, Looking Far and Wide)
  29. Batteries (Part 3, 18650's Arrive. Messing around with Godot Engine)

  30. USB Hub PCB Design Experiment (Part 1, Be the Leaf)
  31. USB Hub PCB Design Experiment (Part 2, Draft 1)

  32. Batteries (Part 4, Batteries are Kicking My rear end)
  33. Batteries (Part 5, SPICY ELECTRONICS)
  34. Batteries (Part 6, Step down or Step Up?)
  35. Batteries (Part 7, Power Up Attempt 1)
  36. Batteries (Part 8, MPS Boost Converter and OSHPark Arrived)

  37. USB Hub PCB Design Experiment (Part 3, JLCPCB Boards Arrived)

  38. Batteries (Part 9, Buck/Boost Converter Arrives, Power Up Attempt 2)
  39. Batteries (Part 10, Liftoff)

  40. Soft Latching Power Button (Part 1, Interesting Discovery and Preliminary Research)
  41. Soft Latching Power Button (Part 2, Answer Some Questions)

  42. Batteries (Part 11, Troubleshooting Reboot Loop)
  43. Batteries (Part 12, Taking an S2 Engine into Itself)
  44. Batteries (Part 13, The Absolute State of this Prototype)
  45. Batteries (Part 14, Interfacing with the BQ27441 Fuel Gauge)

  46. Soft Latching Power Button (Part 3, Integration Troubles)
  47. Soft Latching Power Button (Part 4, More Integration Troubles)
  48. Soft Latching Power Button (Part 5, Even More Integration Troubles)
  49. Soft Latching Power Button (Part 6, SparkFun can Kiss My rear end)
  50. Soft Latching Power Button (Part 7, Investigation)

  51. The Secret Life of Engineers

  52. Batteries (Part 15, Interrupt Setup and Handling)
  53. Batteries (Part 16, More Interrupt Setup and Handling)

  54. Status Overlay (Part 1, Who is DispmanX???)
  55. Status Overlay (Part 2, HUD overlay progress)
  56. Status Overlay (Part 3, HUD show and hide plus installation scripts)
  57. Status Overlay (Part 4, Low and Critical Battery Actions)

  58. Soft Latching Power Button (Part 8, Alternative Design Exploration)
  59. Soft Latching Power Button (Part 9, babyeatingpsychopath Elaborates)
  60. Soft Latching Power Button (Part 10, Built myself into a corner :()

  61. PLA Enclosure (Part 23, Second tier holder v2 Design)
  62. PLA Enclosure (Part 24, Power Switch holder)

  63. Batteries (Part 17, Power Supply Installation 1)
  64. Batteries (Part 18, Power Supply Installation 2)
  65. Batteries (Part 19, Ta daaaaaah!)

  66. Bug hunting (Part 1, YOU UNDERESTIMATE MY POWER)
  67. Bug hunting (Part 2, No it Must Be the Hardware that is Faulty)

  68. Play Log (Part 1, Metroid Zero Mission/Buttons/Battery Data)

  69. Bug hunting (Part 3, merging babyeatingpsychopath's PR)

  70. PLA Enclosure (Part 25, Starting Exterior Design)
  71. PLA Enclosure (Part 26, Left Controller Front Plate Mockup)
  72. PLA Enclosure (Part 27, Test Fitting First Left Controller Facade)
  73. PLA Enclosure (Part 28, Test Printing Small Text)
  74. PLA Enclosure (Part 29, Text Swatches and Left Controller Facade Second Iteration)
  75. PLA Enclosure (Part 30, Front Plate Modelled)

  76. Incident Report

  77. Play Log (Part 2, Metroid Zero Mission/Midnight Piss/Arduino Brownout)

  78. PLA Enclosure (Part 31, Fan Replaced and Front Plate Printed)
  79. PLA Enclosure (Part 32, Beginnings of a 3D Printer Shrine)
  80. PLA Enclosure (Part 33, Modeling HDMI Port, Starting Back Plate Modeling)
  81. PLA Enclosure (Part 34, HDMI Port Take 2)
  82. PLA Enclosure (Part 35, Connector Holes Test Fit)

  83. Buy a Screwdriver???
  84. PLA Enclosure (Part 36, Beginning Back Plate Modeling)
  85. PLA Enclosure (Part 37, Concrete Paver for 3D Printer Shine)
  86. PLA Enclosure (Part 38, The Last Test Plate)
  87. PLA Enclosure (Part 39, Back Plate Modeling Done)

  88. Phase 1 Complete
  89. Phase 1 Postmortem

  90. Play Log (Part 3, Pokemon Diamond and Pearl)

  91. Installing Godot Engine player on RetroPie

Proper Uppercut's Project TOC

  1. I've decided to go a slightly different direction with it
  2. Audio setup
  3. Formfactor planning
  4. Printing an enclosure (Part 1)
  5. Printing an enclosure (Part 2)
  6. Printing an enclosure (Part 3)

Phase 2
Part 5: A New Journey
  1. The Legend of Cory: The Hundred Year Handheld
  2. Phase 2 Quest List

  3. 3D Printer Tasks - Acrylic Doors
  4. Shrine Wheels - Planning

  5. Gaming has Changed...

  6. PCB Buttons Test, USB Hub and Shrine Wheels preparation

  7. USB Hub Assembly and Testing (Part 1)
  8. USB Hub Assembly and Testing (Part 2)
  9. USB Hub Assembly and Testing (Part 3)

  10. PCB Buttons Test (Part 2)
  11. PCB Buttons Test (Part 3)

  12. Speakers 2.0 (Part 1) - Research and Planning
  13. Speakers 2.0 (Part 2) - Adafruit Class D Amp Testing
  14. Speakers 2.0 (Part 3) - Speakerdome 2022
  15. Speakers 2.0 (Part 4) - End of Speakerdome
  16. Speakers 2.0 (Part 5) - Custom Class D Amp PCB
  17. Speakers 2.0 (Part 6) - Conclusion

  18. Shrine Wheels - Initial CAD Mockup

  19. LCD Selection - Initial Research and Planning

  20. Shrine Wheels - Locking mechanism ideation

  21. LCD Selection - Alibaba: Special Victims Unit

Documents

TBD

Source Files

Phase 1 github - https://github.com/CoryParsnipson/rpi-proto-1

This repo contains models for 3d printed parts to hold the controller and screen together. CAD models made with FreeCAD and STL files are also in the same directories. There is also a directory containing an Arduino sketch for polling controller buttons via a key matrix.

References
  1. Raspberry Pi Fusion by TodorSauce/Ashen - One of many prior Raspberry Pi portable projects. I really like what this guy did. Very inspirational.

Cory Parsnipson fucked around with this message at 08:02 on Mar 8, 2023

Cory Parsnipson
Nov 15, 2015
As of the time of this writing, I’m actually quite a ways into Phase 1 of my project right now, looking into how to obtain/make custom controller buttons. I have a small screen, speakers, and some buttons hooked up right now which I will eventually write about in more detail. My updates will probably get slower and less organized as I catch up.

Install Retropie

Ok, so after you get a Raspberry Pi, the first step should be to install the operating system on it. Since I am focusing on games, I went to the Retropie website to download an installer. Retropie maintains their own distro of Raspbian (which itself is a fork of Debian Linux) that is stripped down to a minimal set of packages for performance and storage capacity reasons.

The next step is to get stoned and play Super Mario 64 for three weeks and then wake up from a hazy stupor and remember that you’re supposed to be doing something.

Adding on a small LCD screen

Ok so this is where the idea of the project started taking shape. Before I got this working, I was sort of content with feeling some nostalgia playing some games on my TV with a spare PS4 controller and then moving on. But when I got the LCD screen working and seeing everything in action, the idea of actually making a whole portable device seemed possible.

Here’s the screen in action:

https://i.imgur.com/oJUVFd1.mp4

This is a tiny screen. It’s hard to tell in the pictures, but this is a tiiiiny-rear end screen. It’s smaller than the original gameboy screen, but probably about the same size as an old nokia phone or a tomagotchi. The LCD is surprisingly sharp and bright. I bought it a really long time ago and it sat in my closet. You can get this at Adafruit except right now it’s out of stock. It’s a bit overpriced, tbh, at 20 bux and has an unnecessary SD card reader bolted on the back.



Setting up the LCD is actually a bit aggravating because it’s not fully supported by the Raspberry Pi and there was a lot of guesswork involved. As you might guess, the screen is one of the more complicated components.

Prerequisites

I had to enable the SPI interface on the Raspberry Pi to talk to the LCD. Adafruit is a great resource and supports all of their products with great documentation.



The connection is shown in the picture above on the left (the copper circles with white silk screen labels). Serial Peripheral Interface (SPI) is a communication protocol that lets you send data packets across electronic circuits using relatively few (4 or 5) wires. The interface uses a clock signal (SCLK), read and write signals (MOSI and MISO), and a chip select (this signal can be called a lot of things like SS, CE, or D/C in the picture above).

*NOTE: so it’s a little confusing because the adafruit display has 3 chip selects: TFT_CS, CARD_CS, and D/C. The D/C signal is the chip select used in the SPI interface to talk to the LCD. In other places, this signal is called “Slave Select”. The TFT_CS signal can be used to enable/disable the LCD screen ,and the CARD_CS signal can be used to tell the Adafruit screen to use data from the SD card reader instead of the SPI interface.

To enable the SPI interface on Raspberry Pi, you can run sudo raspi-config after SSHing into it, and going to “Interfacing Options” > “SPI” and say “yes” when asked if you want to enable this. Then reboot. Alternatively, you can ssh into the Pi and browse to /boot/config.txt, do a sudo vi config.txt and make sure the line dtparam=spi=on is uncommented.

Hooking up the LCD to the Raspberry Pi

The Raspberry Pi exposes a set of 40 general purpose input/output (GPIO) pins. These provide ways for developers to interface the RPi with different hardware in addition to other ports like USB, HDMI, or the audio jack.



Notice that there’s two pins called MOSI and MISO (GPIO 9 and GPIO 10). The documentation shows that these two pins are part of the Raspberry Pi’s SPI interface. These pins need to be hooked up to the MOSI and MISO pins of the LCD. (Actually, only MOSI needs to be hooked up because we only write to the LCD screen, never read) Most of the pins from the LCD interface will have a Raspberry Pi counterpart. I needed to also hook up VCC, GND, RESET, D/C, TFT_CS, and LITE (this is the LCD’s backlight).


Here’s the Raspberry Pi hooked up to the LCD screen using a breadboard and some easy insert wires. That’s all that’s needed for the hardware hookup. The next part is to get the software working.

Installing the LCD driver

A long time ago, a dude named Notro made LCD drivers for a whole bunch of devices. They were incorporated into the Raspbian kernel a while back so luckily there's no need to download anything.

His driver repo is kind of out of date, but still really useful. Anyway, everything in his repo boils down to this. Just run this command:

code:
sudo modprobe fbtft_device name=adafruit18_green txbuflen=32768 debug=7 rotate=270
This is a linux command to load a linux driver (which is already built into the kernel) for a TFT screen loader that supports a range of specific LCD displays that Notro decided to code drivers for. This is where it gets aggravating because of the guesswork. So he has a list of supported screens here, except that doesn’t really tell you what value you should put down for “fbtft_device name”. I tried “adafruit18” initially following other examples I found online, but what I saw was this:



If the driver works, you’ll see the screen light up but appear dark. If it DOESN’T work (like if you put in the wrong device name), it will look like a blank white screen. This is because the sequence of initialization commands the driver is sending to the screen is incorrect. I learned this information from a forum post here.

I spent a week staring at a blank screen trying to figure out what was going wrong.

The fbtft driver has 4 different names for the 1.8” adafruit display, but it’s not really documented anywhere. The names correspond to different manufacturing suppliers for the LCD panels (this determines which init sequence you need to use), which are marked for the end-users with colored sticker tabs attached to the screen. There's red tabs and green tabs and also screens that don’t have any color on them sometimes referred to as “black” tabs. And occasionally the stickers are incorrect. It’s a whole poo poo show.

Anyway, as you can see above, mine has a green tab so I tried using “adafruit18_green” as the device name on a whim, I think inspired by some other people on the raspberry pi forum suggesting this. I can’t find the forum post anymore, which is a shame. I saw a dark screen after trying this, which was promising. I wrote some random garbage to the screen’s framebuffer and saw colorful static, indicating that it was working!



This looks really stupid in real life, but when something like this happens, I end up standing up on my desk and pumping my fists. You’d think I did something amazing like growing potatoes out of my own poo poo to avoid starving while stranded on Mars.

Ok, so I’m 90% of the way there. The last thing to do is to figure out how to get the video game graphics output to show up on the LCD screen. Unfortunately, the Adafruit 1.8” LCD screen is not officially supported by Raspbian or Raspberry Pi.

Someone made a hack called fbcp that you can download that will kind of work. This is a script someone wrote to copy the contents of framebuffer 0 (going to the HDMI) into framebuffer 1 (going to the LCD screen). The HDMI output is high definition, 60fps video that has low CPU consumption because it’s handled by the really powerful GPU. Once that is set up, the LCD works:



The picture is downscaled from 1920x1080… So good luck reading anything on it..

As a bonus, you can exit to the console and have linux on a tiny 1.8” screen. Good luck using it…



To get the console, browse to the shutdown menu and then run con2fbmap 1 1. That command redirects the console graphical output from framebuffer 0 to framebuffer 1.

Some complaints I have is that the framerate of the small LCD is about 20fps because fbcp does a manual copy of the graphics card buffer to the screen since this LCD isn’t “officially” supported. This is too slow for games and also cuts into the CPU and power consumption of the device. Also you’ll need to turn on the LCD manually every time you start the Raspberry Pi with the modprobe command and then restart fbcp. The right way to do this is to create what’s called a dts overlay so that the device is recognized automatically. That’s a bit too much work for me right now because I’m planning on replacing this LCD with a bigger one and the replacement is going to be a very different screen.

Cory Parsnipson
Nov 15, 2015
Thank you! The sentiment means a lot. :D

Also, I encourage asking questions if you're curious. The electronics stuff isn't super complicated like math or science, but it does require a lot of background information which makes it pretty inaccessible, imo. I've been thinking about maybe separating the nitty gritty details into their own sections within my posts to make it more digestible. One of the things that's in the back of my mind a lot is how to make people think of electronics the way they think of programming; ubiquitous and needing only a computer and the internet to get started. I hope that my posts will be both entertaining to onlookers and useful to people hoping to replicate what I did.

Cory Parsnipson
Nov 15, 2015

Forseti posted:

That's probably an SPI limitation, raw video data gets huge fast. Some dude made a library that optimizes it a bit by updating the parts that change rather than sending the full screen every time. Dunno if the screen you'll be using next is still SPI but if it is you might want to look into this: https://github.com/juj/fbcp-ili9341

The device tree isn't the most intuitive or well documented thing IMO but you'll probably have to mess with it at some point in your project. Basically ARM boards don't have a standardized way of querying unknown hardware to see what driver and system resources a piece of hardware needs to work. They used to hard code it into specific header files for every board back in the day but that got unwieldy fast so they came up with the device tree as a standardized way to describe what hardware is there and how it's connected.

Good luck, cool project! If you haven't actually bought the display yet, https://waveshare.com and https://buydisplay.com are good vendors for displays.

Thanks for the tips! You sound like you know what you're doing. I might need some help down the line!

I didn't know about the SPI mod, that's really cool. I might experiment with that in the future (I have some other project ideas that might be a good fit for the 1.8" screen). However for this project, I'm invested in getting another screen. I have a 5" LCD from osoyoo sitting in a box that allegedly interfaces with the RPi with a DSI cable. It seems like a more preferable way to go. Also, thanks for the vendor leads. I bought a compute module and dev board from waveshare. These two sites will also come in handy much later down the line because this dang 5" LCD was 50 whole bucks! And it comes on its own (bulky) PCB. Probably some time in Phase 2, I want to go back and see if I can learn how to put together a display driver for a "raw" LCD screen because getting the parts separately would be much cheaper. It sounds like a whole debacle though.

I'm writing a post about what I did to add speakers. Coming soon!

Cory Parsnipson
Nov 15, 2015
SOUND

I’m going to talk about sound now and it’s going to take a few weeks to get through it all. I think sound is one of those things that’s kind of like black magic because it requires you to know a whole bunch of jargon and put a couple pieces together before things start working. Luckily, a whole bunch of people like listening to things that sound good, so there’s a lot of designs that come “premade” on the internet that you can copy down without having to understand a whole lot.

First things first, here’s speakers added to the whole rig (at various points during the design):

https://i.imgur.com/fARdPIU.mp4

I guess sound doesn't work with embedding. Link here: https://imgur.com/fARdPIU

https://i.imgur.com/Rz6HTX7.mp4

Sound: https://imgur.com/Rz6HTX7

https://i.imgur.com/2ffKWxz.mp4

Sound: https://imgur.com/2ffKWxz

Sorry about the poo poo camera work, I don’t know how to film properly… I was trying to get close up against the speakers. My phone doesn’t seem to pick up the sound well, but the speakers are actually pretty loud. I’d say as loud or slightly louder than GameBoy Advance speakers.

Note that the first video is missing a Stereo Decoder/DAC (blue circuit board with 3.5mm jack on it) and you might be able to tell that the audio quality is much noisier than the other two (or not, I can’t really tell anymore).

Here’s some Stuff That Might Come in Handy To Know About Sound

There’s 4 “functional” blocks that every speaker system needs:
  1. A power source
  2. An audio signal source
  3. Amplifiers
  4. Speakers (some way to generate noise)



The meat of the design is in the amplifier section. This takes a “weak” audio signal and power source and makes it into a stronger signal. This is because usually the audio source is a computer or portable electronics device and speakers need a lot of power to translate the signal into mechanical vibrations. The difficult part for us is that the amplifier specs must be compatible with the speakers and be driven with the right power source or else you’ll end up exploding something. We don’t want that to happen.

There’s some variations on this formula. For example, if you want headphones instead of speakers, you can probably go without the amplifiers because headphones don’t need that much power.

Speakers

Friendly PSA: They sell tiny widdle speakers for tiny widdle electronics devices! I bought these PUI Audio speakers. They’re about the size of a dime and they’re rated for 8 ohms, which is something important to remember when searching for amplifier designs. The speakers have two terminals, the minus terminal should be hooked up to ground, and the positive terminal should be hooked up to an (amplified) audio signal.

I honestly have no idea how someone on the outside comes to know all this stuff, but when in doubt, go buy parts on digi-key (or other places like mouser, waveshare, or Buy Display). That’s how I get a lot of parts and the rest comes from reading blogs, datasheets, or guides from places like Adafruit.

Power Source and Audio Signal

So for us, the power source and the source of the audio signal will both come from the raspberry pi. Convenient!



Amplifier

The diagram above shows the first design I tried to make. It uses the PWM output of the Raspberry Pi directly into an amplifier. The amplifier design I chose uses an LM386 Op amp that I found off the internet. I will be going into more detail about this design in the next post, though I feel like some people might be wondering, like, “what?? How did you specifically choose this design??” What happened here is that the site I linked describes some very textbook standard amplifier circuits that everyone seems to know about. To get an idea of what this design is, let me just tell you this. It’s babby’s first audio amplifier. If this amplifier was a flavor, it would be pumpkin spice. It’s basic.



That’s great, though, because I’ve never done this before. We just need some recognizable sound coming out of this thing for the first pass. All other amplifier designs are more complicated and either build on this foundational circuit or use some crazy gimmick for special scenarios.

ALSO another note, I could probably have bought an amplifier circuit premade off Adafruit but I decided to breadboard it myself using discrete components. I might have made things more complicated than they should have. But a lot of things off the Adafruit website are overpriced, imo, and everything I use off Adafruit is another thing I’ll need to break down and integrate into my PCB later on. They charge a premium for convenience.

SNEAK PEEK

The second and current design I’m using incorporates an additional step (“2a”) where I broke down and bought a stereo decoder from Adafruit.



This makes the sound quality clearer, frees up the PWM port on the Raspberry Pi for more important things, and also makes it easier to integrate the sound control with Alsa mixer for linux. I will also be talking more about this in a couple of posts.

Cory Parsnipson
Nov 15, 2015

food court bailiff posted:

If I'm a dumbass that spends hours figuring out the most basic of circuits and stuff, is DSI going to be the way to go for a display on something like this? I kind of imagine I want to have as many GPIO headers open as possible for buttons and whatnot, right?

e: also this is going to be a hell of a fun project to try to source parts for when it seems like Adafruit is out of stock of 95% of their total inventory :psyduck:

The easiest is to use a display that connects to the raspberry pi using an HDMI cable,. You can just plug and play in that case, no coding or software configuration necessary. I think DSI would be the next best thing because of the reason you mentioned, but it's weird because for some reason the Raspberry Pi designers don't like exposing this port to the users, so only their official display and maybe like 2 or 3 other displays can use it. It has something to do with the display adapter being closed source or something...

Here's the DSI display that I'm planning to switch to: https://www.amazon.com/OSOYOO-Capacitive-Connector-Resolution-Raspberry/dp/B07KKB5YS9

Here's an alternative display from Pimoroni I was considering: https://shop.pimoroni.com/products/hyperpixel-4?variant=12569485443155
^^ this one looks super cool. It's an IPS screen that's 4" (I consider this the perfect size) and has a touch screen on it. The only problem is that it uses all 40 GPIO pins.

Here's some displays that have an HDMI port (I don't recommend these specifically, just showing some examples):
https://www.adafruit.com/product/1928
https://www.buydisplay.com/4-3-inch-raspberry-pi-touch-screen-tft-lcd-display-hdmi-with-driver-board

Displays are expensive af :psyduck:

Cory Parsnipson
Nov 15, 2015

Forseti posted:

Personally, I'd probably look into something like this 4.3" 480x272 Display at $18 with a carrier board. You'd need to use the DPI Interface on the RPi which will use up a lot of pins, but if you can still find a way to connect everything else you use, the parallel interface is much faster than SPI and you shouldn't have any frame rate issues. It's also plumbed right into the GPU on the SoC so it should have less overhead. 480x272 is the same resolution as the PSP I'm pretty sure, and I'm pretty sure can show things like the SNES without any scaling, but not 100% on that so double check me there. I haven't poked into the datasheet but if it lets you use RGB565 that'll save you some pins, and that would still be 65k colors.

Wow, that's really awesome, this is pretty much exactly what I'm looking for. Well, maybe except with a capacitive touch screen but one thing at a time. To be honest, I'm not ready to go fiddling around with the screen just yet. Not until the end of Phase 1, especially since the DPI interface takes up so many pins. I need to figure out how many GPIO pins I need for the battery, controller buttons, and "glue logic" stuff (like brightness, volume, power button, etc).

EDIT: actually, my controller parts don't look like they'll be coming in until after Thanksgiving so maybe now is a good time to look at screens again.

mediaphage posted:

analogue pocket

Thanks! Ah, yeah I remember hearing about this. Those guys are hardcore :stare:

Analog is known for implementing old game consoles completely in FPGA hardware. This is what I was referring to in the OP by "Tony stark level poo poo". I studied computer architecture in college and I always thought it would be fun to try see how much juice you could get out of a custom portable core/GPU. It's just uh... a lot of work and really hard though. :blush:

By the way, my only critique is that the Gameboy/Gameboy pocket form factor seems outdated and uncomfortable to me. I hope that's not sacrilege since their product is massively polished and clearly shows their nostalgia for the original gameboy. Team GBA ftw though :colbert:

Cory Parsnipson fucked around with this message at 07:59 on Nov 15, 2020

Cory Parsnipson
Nov 15, 2015
An LM386 Amplifier Circuit

In the 70’s and 80’s, Integrated Circuits (ICs) were made by a few select companies like Fairchild Semiconductors and Texas Instruments. When the good ole’ engineers at these companies rolled out new ICs, they’d name them with cryptic letters and numbers. Since this was before we had the internet and video games and readily-available porn, people would hungrily follow news about new chips being released and gobble up datasheets to figure out what other primitive electronic device they could build with them. It was pretty rad.

This brings me to this a specific IC called “LM386”, an op amp* designed for audio applications. It’s a low power amplifier that is commonly used in guitar pedals, radios, etc. Ha! Classic LM386! In fact, this amplifier is so well known it spawned some popular spinoffs like LM386N-1, LM386N-3, LM386N-4, and--who could forget-- the LM386MMX-1, haha oh man. Good times. If you ask somebody how to make a sound amplifier, they’ll just tell you to use an LM386.



I remembered this years after the fact and hit google with a “LM386 amplifier circuit” out of the blue.


https://www.circuitbasics.com/build-a-great-sounding-audio-amplifier-with-bass-boost-from-the-lm386/

I used the one called “A Great Sounding LM386 Audio Amplifier”. The sections I wrote below talk about how and what operational amplifiers are, but like I said before, if you know what you’re looking for, you can ignore all that and just find a design and copy it down.

What to look for

Know your speakers. These tiny speakers have a power rating of 700 milliwatts with a max rating of 1 watt. So as long as the amplifier doesn’t output more power than that, we’re good.

The LM386 datasheet says that, if I use the LM386N-1, the output power is typically around 325 milliwatts. And that’s if I use a 6V input power but I’m going to be using the 5V on the raspberry pi (so average power output will probably be 5/6ths of 325 milliwatts). Now the only thing to worry about is if these speakers will be loud enough. But I will tell you after the fact that I built the whole thing and found that they indeed are loud enough. :smug:

Speaker Breadboarding

Here’s me using a function generator I bought off ebay to test the left speaker in the middle of putting it together:



Here’s a close up when I have both amplifiers built and hooked up to the raspberry pi:



And once again, I over complicated this for myself. I could have searched “audio amplifier” and bought something off Adafruit, sparing you this long post about audio circuitry.

Software Setup: Using PWM audio output

Once the circuit is made, we’re not done yet! We gotta hook up the raspberry pi audio to the speakers. The Raspberry Pi 3 has a 3.5mm audio jack you can get sound out of straight from the box. This is great, but unfortunately, I’ll probably end up ignoring this and using something else. If you want audio signal into a custom circuit, you can go through the GPIO. Once again, the gpio pinout:



There are 4 pins here that you can tell the raspberry pi to generate Pulse-Width Modulation (PWM) signals from. And the pins are grouped into pairs. GPIO 18 and GPIO 19 are one pair of PWM outputs and the other pair is GPIO 12 and GPIO 13. You can set an alternative mode where the PWM signal is used to create an audio signal and is fed by the raspberry pi sound system. This alternate mode can be enabled using the WiringPi utility that comes installed with Raspbian:

code:
gpio mode 26 alt0
gpio mode 22 alt0
These lines of code need to be entered upon every reboot. Or you can change the boot config to make it permanent:

code:
dtoverlay=pwm-2chan,pin=12,fun=2,pin2=13,fun=2
Unfortunately, this doesn’t work, because the dtoverlay doesn’t allow specifying two pwm channels in its parameters. So you’d need a custom dtoverlay to change this. But if someone did, this is the line you’d enter to make it happen.

So in the picture above with all the orange annotations on it, you can see the two wires I used to connect GPIO 18 and GPIO 19 to the amplifiers. The wire labeled “L-Channel Audio” goes from GPIO 18 to the left LM386 amp input and the wire labeled “R-Channel Audio” goes from GPIO 19 to the right amp.

As with the LCD screen, I have gripes about PWM audio:
  1. The PWM audio isn’t very high quality. It’s prone to noise and interference from other signals. And the PWM generator clock isn’t very fine grained so the frequencies it generates may not be correct. This can translate to pops and clicks in the audio signal.
  2. Coupled with the dtoverlay issue I mentioned above, PWM is a pain to use. Either all 4 pins must be in audio mode or general purpose mode. So if I need to use a PWM signal for some purpose other than audio, I’m hosed.
The good news is PWM audio was never the plan, so instead I will add in a stereo decoder. This requires a different software approach, so instead of PWM, I throw all that away and use something called I2S instead. More on that soon.

I will probably end up iterating quite a few times on every part of the design. I hope that doesn’t end up too confusing.

*Operational Amplifiers (a.k.a. “Op Amps”)

Unless you’re an audio geek, or an electrical engineer, or my grandpa who likes fiddling with old transistor radios, you probably don’t care what an “op amp” is. I just thought I’d mention it because otherwise the speaker design would seem like a magic box that generates sound. It is pretty close to being a magic box that generates sound, though.

An op amp’s schematic symbol is this:


THIS IS ALL YOU NEED TO KNOW ABOUT OP AMPS: THEY TAKE IN SMALL SIGNAL AND PUSH OUT BIG SIGNAL.

Like this:


It’s hard to tell from my scribbles, but all the bumps and grooves of the waveforms are the same but the amplitudes (i.e. vertical range) are different. This is where the term “amplifier” applies. In layman’s terms, if you put in a sound wave, it comes out sounding the same but louder and more powerful. Note in this context, amplitude is volume.

WARNING: Science

Skip this section if you don’t care to learn more about op amps.

Judging from the symbol, you’d think they just take the input signal and push it through the triangle and pop out a bigger signal somehow, right? WRONG. First of all, they invert the signal if you use the minus terminal. Secondly, and more weirdly, the input resistance is supposed to be infinite. Meaning the current of the input signal never flows through the op amp at all. Instead the signal goes into a few transistors that are set up to recreate the signal they receive in the gate terminals by drawing from the power rails (top and bottom wires). It’s like the output is “air-gapped” from the input. Op amps are freaky.

If you’d like to get into the mathematics of it, there’s some guides online, but it won’t make much sense until the second year of electronics classes… I’d recommend a school textbook, tbh, there’s useful context in a book.

Cory Parsnipson fucked around with this message at 21:08 on Nov 15, 2020

Cory Parsnipson
Nov 15, 2015

mediaphage posted:

I agree it’s cool and polished and I never want one.

Huh, really? How come? I'm curious to know what the deal breaker is. Hardware emulation is supposed to be the tits.

Forseti posted:

Also, the breadboard is great for prototyping but isn't really a good test for signal to noise ratio and distortion. You essentially have antennas hanging all over the place there and the breadboard connections have very high parasitic capacitance. The antennas will introduce noise and the capacitance will smear out your nice sharp digital transitions for a signal like PWM. Not sure if it makes a huge difference at audio frequencies, but I wouldn't be surprised if you could hear the difference easily.

Haha yeah I forgot to mention that. The sound isn't bad, it's got a little background static. When you add in the DAC, the difference is quite noticeable.

Forseti posted:

Not sure what you're thinking, but I'd get one of the new fangled class D amplifier ICs made by e.g. Texas Instruments. They'll have all the filtering and such inside and just by the nature of being tiny should be more resistant to noise. They're also WAY more efficient than the LM386 and should help your battery life quite a bit and also be able to go considerably louder.

Exactly, that's the plan. I was going to see how far the LM386 took me and then try to do some power analysis to see how much of a difference the class D amp would make. I was also putting it off because the class D amp looks way more complicated...

By "actual audio signal" do you mean an analog signal?

Cory Parsnipson
Nov 15, 2015
Adding a “Stereo Decoder” between the Amplifier and Audio Source

This is going to be a light update. It's kind of boring, imo. It'll get a little better later and after this I'll delve into the controller and buttons, which I think is way more interesting but that could be me being biased since I'm still learning about it.

Up to this point, my speaker setup looks like this:



I added a new block in between the amplifier and the Raspberry Pi:



Here you can see that the change is very minimal. The new block is the blue circuit board in the top right. All that is required is to rewire the input going into the amplifiers (short orange wires) and the audio signal coming from the Raspberry Pi. I was able to quite literally just drop the block into the old design for a quick upgrade.

The “Stereo Decoder” block is something that I bought from Adafruit. It’s really fancy and quite easy to use, but might be hard to integrate later. Despite being called “Stereo Decoder” this thing actually does two very important things.
  1. Stereo Decoding - As in “mono” and “stereo”. The signal coming from the Raspberry Pi will be in stereo, meaning that the datastream will have data for both left and right speakers and this circuit splits (a.k.a. “decodes”) the single datastream into two wires. This is necessary because we’re going to have one speaker/amplifier unit per side and the amplifiers take one wire expecting a single data stream. This wasn’t needed when we were using PWM because it already came in two wires since the Raspberry Pi was already kind enough to split it for us. The I2S output format does not. More on this later.

  2. Digital-to-Analog Converting - Yes, this baby is also a DAC. And it’s a nice one too. I mean not, like, a professional Dr. Dre beats type DAC, but it’s $7 and has a great signal to noise ratio.

Digital-to-Analog Converters (DACs)

The name itself refers to converting a digital signal that switches between two discrete values (0 and 1, or 0V and 5V, etc) into an analog signal that can assume a continuous range of values (e.g. any voltage between 0V and 5V). People use these things mostly for converting audio from digital signal to actual sounds you can hear. (You can think of sounds as made up of a large combination of sinusoidal waves, and sinusoidal waves cannot be expressed using only 2 integers).

Maybe this illustration I found online would help:


Most computers and pieces of technology will need a DAC analogous to the way computers and pieces of technology need a graphics card. Your laptop/desktop probably has a DAC that feeds the 3.5mm jack coming out of it. If it plays sound and it doesn’t sound terrible, it probably has a DAC.

Ok, but what did we gain by doing this?

The sound is slightly better and I don’t have to fiddle with the lovely software options that we’d be stuck with using PWM. This is a “real” sound setup in the respect that we now have a digital audio signal being properly converted to an analog signal, sent to an amplifier, and then played out of a speaker.

Contrary to what I said in the previous section, the Raspberry Pi does not come with a DAC on it’s motherboard. This is presumably to keep the cost/size down and because lots of people wouldn’t need high quality sound when they’re making their light switch dimmers or sprinkler systems or whatnot. The 3.5mm jack coming out of the Raspberry Pi is directly connected to a CPU pin and also driven by software PWM.

PWM vs DAC

Why have both? They’re really different tools that have some overlap. The advantage of PWM is that it only requires one GPIO pin and can be implemented in software, so you don’t need any fancy add-ons. But the PWM signal requires extra CPU cycles to generate the signal and it’s dependent on the clock frequency. This means we can only really express a limited range of analog signals and coupled with the fact that PWM can only assume 256 different values, we end up with not a very high quality analog signal, we may end up with some clicks and hissing in the output due to the low resolution of the PWM signals. This is ok for things like a light bulb dimmer, but for audio, cutting the corners on quality can be noticeable. If we bring in a DAC, and choose a nicer one relative to your PWM generator specs, we can reduce the signal to noise ratio and output an audio signal with much less background noise. (Thanks babyeatingpsychopath)

Software setup for I2S audio output

I2S is yet another communication protocol (like SPI) for transferring data, except this is specially designed for transmitting digital audio signals. ‘Nuff said.

The GPIO pin connections needed for I2S are here:


Adafruit makes this really easy with their installation script. Literally all you need to do is to download and run the script from github and then it configures the I2S interface for you. Once you finish running the command, you need to reboot and then playing audio will automatically come out of the speakers.

One caveat is that there is a hack where they loop a silent audio file in the background to prevent popping when you start and stop playing audio files. This requires some CPU time but according to them, it’s negligible on the Raspberry Pi 3. I currently don’t need this because I’m using Retropie, which never releases the I2S interface but if I switch to Raspbian, it’s something I’d need to consider turning on.

mediaphage posted:

I can appreciate all the hard work and effort that went into its design and construction, but to be entirely honest I really don't care about hardware emulation for my own needs. All the stuff I want to play will work fine in software emulation, for the most part. I bet it feels nice in the hand, though.

Trying to understand more specifically. Do you mean like the specialized hardware makes it too expensive/overkill for playing older games? Or the fact that you still need to lug around cartridges or old peripherals? I think hardware emulation theoretically should not lag at all, except in the instances where the original system itself lags. This is important for me, because when there's lag it really kills the mood imo.

Cory Parsnipson fucked around with this message at 23:00 on Nov 30, 2020

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Because I like to be pedantic, going from 8-bit to 16-bit on your digital audio doesn't do anything for the fidelity, it just lowers the noise floor. If you're using the same sample rate, then you get all your information in the same number of samples, but you get more quantization noise with a lower bit depth. CD players use a 1-bit DAC running at 16x sampling frequency, so it "acts like" a 16-bit (really 14-bit because of math) DAC.

Oh gently caress, I'm spreading misinformation. :saddowns:

Just so I get this clear, do you mean that the fidelity isn't affected because the audio signal is already in digital form so the quality is the same no matter what speaker I use? And that the 16-bit output will have less quantization noise, and this does translate to slightly better perceived sound? I realized that I never looked up the definition of fidelity and the best I could find is "accuracy with respect to the original recorded sound". Is there a more technical definition? I don't remember what I learned in school. :sweatdrop:

babyeatingpsychopath posted:

Can't wait until you get into your buttons and switches. Charlieplexing and diodes, aplenty, right?

I never got why they called it "charlieplexing" and not just "key matrix" but I think so? I've been using the buttons directly hooked up to GPIO, but now that I need like 16 of them, I need to switch to the matrix'd approach. I'm using this page as a reference. The key matrix and charlieplexing look basically the same to me, but I also never done charlieplexing before so I'm not sure if they're the same thing or if I'm missing some nuances.

mediaphage posted:

Mostly the latter. I'm not the most organized person on the best of days, so i'm really mostly only interested in something that works with a minimum of physical units.

Ah, same. I don't get the appeal of the recent "classic" versions of old consoles. It doesn't sound fun to be playing on a tiny controller like 5 feet away from the TV. Sorry if I poo poo on anyone. I'm a digital-only kind of guy, never really liked having to store PlayStation CD cases or switching out CDs and I even got a bigass SD card in my 3ds so everything is just available.

On the other hand... Sitting on a plane with my backpack full of GBA cartridges was awesome. Especially when pokemon had those freakin sweet colored cartridges. I would have killed to get my hands on Pokemon Sapphire.

Cory Parsnipson fucked around with this message at 04:56 on Nov 22, 2020

Cory Parsnipson
Nov 15, 2015
Moved the speaker circuitry to a protoboard

Here’s one last part related to sound and then we can put this away for a while.

I needed to free up my breadboards so I could mess around with circuitry related to other parts of the project. That’s when I had a great idea! The speakers had been sitting on my desk like this for months and now it’s definitely time to move them to a slightly more permanent layout, like a protoboard, for instance.






This is me starting to move the right amplifier and speaker to the protoboard (the green thing).






Once the right amplifier was fully moved over, I temporarily hooked up the power, ground, and audio input signals to it for debugging. It took a few hours going over the connections and fixing mistakes, but finally, after about 3-4 hours it started working again.



A protoboard is different from a breadboard because you need to solder everything down, so it’s pretty permanent. Some protoboards have their holes connected to each other in a similar way breadboards do, but others (like one I’m using) don’t, so you have to wire everything together by yourself. You can see that the underside of it is really messy.



Here’s both speakers added to the protoboard. The left amplifier speaker went a lot faster than the right one. I spent a weekend doing about 5 - 6 hours of soldering and it was pretty fun. I haven’t had to solder anything in a really long time.

The top of it is really cool looking though. I bet I could really freak someone out if I waved it around in public.






Here’s the whole thing wired up and hooked up to the Raspberry Pi. The sound works as it did before. I got rid of one breadboard, but I still need the one to put the stereo decoder and LCD on.

You might have noticed before that the third sound sample I posted above shows the protoboard instead of the breadboard version. This is why.

So with that, we’re basically ready to put this in a shoebox. This is version 1 of the sound system.

Loose ends
  • Replace the LM386 amplifier with a Class D amplifier for better battery life. I also need to remember to measure the current draw during typical usage to estimate the power consumption. I’m too lazy to do that right now...

  • Add in capability of detecting if headphones are plugged in and automatically mute the speakers (but not the headphones) if so. Unmute the speakers when the headphones are unplugged. This may require me to swap out the 3.5mm jack with one specially designed to have inputs for detecting if something is plugged in. Also note that we may need to come up with a script to store “profiles” to remember to unmute/mute or have different volume levels for separate situations such as “handheld mode”, “headphones plugged in”, “headphones plugged in while docked”, “no headphones while docked”, etc. I’m basically describing how laptops and smartphones handle this stuff, and I really like that, so let’s copy those things.

  • Take a look at the Adafruit schematic for the stereo decoder and then put that, the amplifiers, and speakers all on a single PCB (see Phase 2).

  • I can also probably choose a different speaker that has a better physical profile, smaller power requirements, and a more suitable frequency response. The ones I have go from 1kHz to 20kHz. Human hearing is about 20 Hz to 20kHz, but I don’t need the whole range. I can probably save some money by finding ones that stop around 15kHz or use that leeway to get speakers that have a lower cutoff than 1kHz. (Although, the ones I have now sound fine, so it might not be worth optimizing for the lower frequencies)

Next

Whew! We have two main functional areas left--buttons and batteries. I‘m going to get really deep into figuring out what people do to make custom controllers and it’ll involve a lot of hardware. I don’t do hardware trinkets a lot so this was a huge learning experience for me.

On Amplifier Classes

I actually learned this while researching amplifiers for this project, but amplifiers are organized into different classes by letter and there’s like Class A all the way to Class G/H or something.

This page explains things in more detail and gets somewhat technical (but not too technical). I may be oversimplifying, but the gist is that all these different types of classes try to solve the issue of being power efficient vs having high quality audio output.

Class A amplifiers are the first and oldest amplifier design. It’s simple, all the circuitry in the amplifier is always on and drawing full power. It is also the best sounding one, because there’s no concessions for power efficiency or anything else. Class B amplifiers tried to be more power efficient at the cost of sound quality. Using transistors in a different layout, what the Class B amplifier does is try to turn off parts of the circuit when they are not needed. This takes advantage of the sinusoidal qualities of audio waveforms.

Then there’s class AB amplifiers, which is what this LM386 amp falls under (I think), that uses a combination of class A and class B characteristics to compromise between sound quality and power efficiency. It’s less efficient than class B but doesn’t have some of its problems in reproducing sound.

There’s a class C amplifier. This is not a good design for audio amps because it has “nonlinear gain”. These classes are for amplifiers in general and not just audio amplifiers. Class C amps are typically used for radio frequency (RF) transmitters. Think, ham radio, or card readers, I guess.

And then there’s the infamous Class D amp. This is completely different from the previous amplifiers. It was invented by a really smart old guy in the 1950s. This amp tries to output an analog, sinusoidal signal using the PWM technique. The PWM waveform this amp generates is fed into a low pass filter to smooth it out into a close approximation of the analog sound signal. This amp is low power and small size, which makes it great for portable electronics and factory standard sound systems for cars. Only recently have these amplifiers become feasible because of the lower cost and quality of components that allow companies to build class D amps with sound quality approaching class AB amplifiers.

There’s more classes being created to this very day. Class F, G, and I basically are improvements upon the AB amplifier design, trying to hyper optimize certain aspects of the design. There are also class S and T amplifiers that work like the class D amp, also trying to improve upon the basic methodology using different or more modern mechanisms.

Yeah, so there. That’s the amplifier landscape I think.

Cory Parsnipson
Nov 15, 2015

oldskool posted:

this thread is what i wish my electronics engineering classes had been like.

Wow, that's an amazing compliment! My school was super theoretical. We basically only drew circuits on paper and did ginormous math equations, it loving sucked. I mean, there's a ton of knowledge that they shoved into me, but I wish the same thing as you--having a portion of hands-on projects and cool things to build would have been nice.

oldskool posted:

I wish I knew how to solder, but I know if I learned the skill I would just end up with a pile of unused soldering tools and an even larger pile of stuff that I could build/should fix when I get around to setting up the soldering station.

I think a lot of EE people feel the same despair at some point and for me, it made me want to go into computer science for a while. Because all you need is a computer and the internet to get started. For modern consumer electronics there's a ton of things done in the name of "improvement" that make it really unfriendly for hobbyists and I think that's a huge shame. First of all there's surface mount components, and now everything is starting to be incorporated on silicon wafers or NAND chips with really microscopic connection form factors. If your electronics breakage is inside the chip, unfortunately there's nothing you can really do to fix it unless you want to invest in a heat gun and a microscope. I wouldn't worry too much about not being able to fix everything, but every once in a while you'll be surprised. In the electronics thread, some dude just fixed his friend's treadmill and saved, like, $1000. I think being able to indulge in an impromptu electronics project and occasionally fixing something is more than enough to justify having these items sitting around in the garage 99% of the time.

You can get soldering irons for pretty cheap and it doesn't take up a lot of space. And I'd say, you maybe only need 5 things:
  1. Soldering iron, temperature controlled is preferred and a sponge holder is a bonus; no need to get a really expensive one
  2. Solder wick; I love this thing and also rely on it to do certain kinds of surface mount soldering
  3. Solder
  4. Solder flux - marker form is convenient and will work for most things
  5. Wire cutters
Holding clamps and a solder vacuum are optional, but really nice to have. Gonna get me some helpin' hands some day.

All my worldly possessions can fit in an 8x10 room and I have two cardboard moving boxes full of tools and components that I lugged around for 5 years without touching them at all. But now I'm ready to use them and I'm glad I didn't throw any of it away. I've been borrowing my roommate's coffee table and setting everything up/tearing it down every time for some guerilla electronics work. You don't have to build your own electronics workshop to get started (although having one would be super sweet).

You'll pick it up fast! I find soldering to be somewhat therapeutic, much like sewing or knitting. There are far too few opportunities to solder in your own projects.

I really encourage you to jump in if you ever get the itch. Things are so much better now! There's Adafruit and Arduino and a lot of communities where you can get information from. This was much harder before. I recommend making a list of ideas and writing in it every time you come up with one. A small percentage of these ideas will be simple enough to achieve, and that's really something! This could be a combination of ideas that you have while lying in bed or when you have some sort of pain (e.g. cell phone charger dock???? door opener?? PISS CUP???) and ideas you get from other peoples' projects like on Hackaday or something. A good starting point could be copying others' work and then improvising once you get the hang of things.

MINI UPDATE FROM THE FUTURE:

Happy Holidays, everyone! Like most people, I managed to drop some big bucks and snagged myself a brand-new, fancy pants PlayStation 5! I bought a used set of joycons. :downsbravo:



I'm trying to figure out how the shoulder buttons work and I gave up trying to figure it out using just pictures from the internet.

Forseti posted:

They're even passing on the cheap manufacture aspect of surface mount these days, they're happy to stuff the board for you and it's actually not even that much money if you stick to the list of parts that they keep stocked. You can order prototype boards for literally a couple bucks and have the option to get the solder stencil so you can squeegee on the paste, plop the parts down, and then pop it onto a hot plate to solder everything as long as you keep everything mostly on one side.

The PCB fabs will make boards stupidly cheap for smaller board sizes too and you start to realize "oh yeah, this is why everyone uses surface mount" when you can get 250 pieces of a gumstick sized PCB for $30 at your door.

Embrace it man! I think it's a golden age for electronics hobbyists :)

Huh, wow, that's enticing. Maybe I will get into surface mount stuff. :colbert:

Cory Parsnipson fucked around with this message at 21:13 on Nov 26, 2020

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

The audio is converted by the DAC into a band-limited signal. Everything above samplefreq/2 cannot be represented (as per Nyquist). Therefore, if your sample rate is the same, you get precisely one waveform of your sample points, whether or they're 8 bits or 16 bits or whatever. The 16-bit signal is "closer" to the original, but there isn't any more frequency information in it. Because an arbitrary analog signal falls in a random spot between sampling points, the average difference at a single sample point when summed across all the points is white noise. If you only have 8 bits of depth, then you're looking at a larger signal-to-noise ratio, as each point has a larger distance away it can be.

This is called "quantization noise" and if your digitizer is any good (audio ones are) then this noise is exactly equivalent to tape hiss. 4 bits gives more "hiss" than 8, which is more than 16, etc. So if you're playing on a crappy low-fidelity speaker anyway, your sound and tones (especially if they're small numbers of sine waves added together) will sound the same at 8 bits and 16, but you will probably be able to hear the difference in a voice sample or a drum hit or something that's got a lot of complex frequency stuff in it.

Got it, thanks! I read that the Adafruit DAC does a lot of filtering right in the breakout board so maybe that's another reason for the noticeable difference. And that's before accounting for any of the effects from the breadboard. Man, I've got a lot of reading to do if I want to optimize the sound system...

babyeatingpsychopath posted:

Normal switch matrix takes n pins to drive n2/2 pins, but charlieplexing uses n pins to drive n2-n pins. So a charlieplex 4x4 matrix only needs to use 6 pins, instead of 8. By being clever about which of your inputs are high, which are low, and which are input, you can get all your input with fewer pins, as long as you can sacrifice refresh rate.

Oh. Yeah before I skimmed the Wiki page but now I've gone back and I see what you mentioned right there. Sounds awesome! I'm about to reconfigure the controller circuit and now I definitely want to try charlieplexing. I think the controller should work just fine as long as the main code loop takes less than 100-200ms to run. That should be more than enough time to run everything, so I guess I'll find out if everything works pretty soon.

Cory Parsnipson
Nov 15, 2015
INPUT

Yay, time for something new. This is all new to me as well, so there’s gonna be a lot of experimenting here. As a bonus, a lot of the work here will be with physical objects and shiny, colorful hardware to keep my tiny monkey brain entertained.

And as I write that, I’m realizing that the rest of this post will be mostly a text dump talking about preliminary research...

The Simple Way (and Other Alternatives)

The most direct method, and probably what most people would start with, is to wire buttons directly to the Raspberry Pi’s GPIO pins. All you need is a tactile push button, a resistor, and a couple wires and you choose a non-reserved GPIO pin and hook them all together. Then, I guess you need some sort of script or something to periodically read the value of the GPIO pin and map it to a keypress.


Like this, but multiplied by about 20

Wiring up buttons seems more complicated on the Raspberry Pi than other microcontrollers like the Arduino because you have the entire Linux operating system stack to route the GPIO data through and that seems really error prone to me. My personal opinion is that I hate having stray bash scripts around because you have to put them somewhere and then figure out how to make them run automatically on certain system events and then also remember to copy them when you reinstall stuff (and then explaining it to other people who are trying to use your script but with a slightly different environment so the script doesn’t work without tweaks that neither of you can make without digging into each other’s computers). So I really don’t like the idea of doing it this way.

Also another thing that I would realize later when someone on the Raspberry Pi forum pointed this out is that the Raspberry Pi doesn’t have any built-in way to get analog input through the GPIO pins. There are no analog-to-digital converters (ADCs)* hooked up to the pins so you can’t just bolt on a thumbstick or two and/or have analog trigger buttons. I feel like this would be the main deal breaker for most because if you have to bring in extra ICs for this you might as well go with another solution I’ll describe below.

*an ADC does the opposite of digital-to-analog converter (DAC). Clever, huh?

IPACs are Game Controller Brains???

I vaguely remember reading somewhere that there was a whole fighting game scene where they make their own “fight sticks” (portable arcade controllers) and there was some kind of chip or part you needed to buy to “make the computer recognize your buttons as a controller”. So yeah that’s what I had to go on for this part. I’m pleased to say that up until this present moment, I’ve learned a lot of terminology and it’s been very enlightening.

Searching some kind of variation on the phrases above, I discovered that the aforementioned device is called an “IPAC” which is what the people over at Ultimarc call their product. What it is, apparently, is a microcontroller with GPIO pins (that you wire up to arcade buttons and joysticks and whatnot) that appears as a keyboard to whatever computer/arcade system you hook it up to.


Here's a beautiful DIY "IPAC fight stick" setup by an anonymous user from reddit

Each button is bound to a keystroke and you just need to configure whatever game you’re playing to have the right key bindings. I’m not going to do this, and I recommend anyone doing the same not to either, but I’m putting this here for complete-ness.

Microcontroller-ception

Forget that arcade stuff for a moment, because I don’t want to spend, like, $35 on an IPAC that isn’t even small enough for what I want to do. NOTE: Ultimarc does sell a “nano” version of the IPAC device but, alas, they don’t support adding the necessary number of buttons I would need. Additional searching for “how to make a game controller”, will bring up a ton of DIY guides about how to make crappy push button controllers using Arduinos and stuff.

:thunk: Hmmm, this is quite a concept. So, I could use an Arduino in place of an IPAC and do the programming myself??? Actually, since I was fresh off browsing the Raspberry Pi website for different RPi modules, I had a Raspberry Pi Zero in mind because of its compact form factor. This led me to some weird thoughts, like, “what the heck, am I really going to buy a second Raspberry Pi to put inside this box with my first Raspberry Pi? I need a second microcontroller to serve the first one??? And they’re both gonna run LINUX??”


Obligitory internet meme

Yes, actually, but not with a second Raspberry Pi because then that would be pretty nuts. We don’t need a second linux machine inside the handheld, that would be major overkill. BUT a second microcontroller that’s not super powerful and has a small physical profile seems like the perfect tool for the job. Am I overcomplicating things? Ummm….. probably. I do this all the time. But on the other hand, do you have a minute to talk about our lord and savior, Arduino???

Arduino Pro Micro

I decided to go with the Arduino because it’s easy and has a really nice ecosystem. This will pay off for me in the software department later. The Arduino companySparkFun* sells something called an Arduino Pro Micro that is really small and has exactly what I need. 1 USB port for interfacing with other devices, about 9 digital IOs, and 9 (9!!!) analog pins. Even better, the Pro Micro is a popular choice for hobbyists making keyboards and stuff so you can get them really cheap if you’re willing to buy from China.

*So it turns out the Arduino Pro Micro is not an official Arduino product, but instead originally designed by SparkFun. Arduino sells another board called the Arduino Micro, which is larger than the Pro Micro but does similar stuff.



I bought these from Amazon, which makes them about $5 a pop, but you can find them on AliExpress for $1-3. You need to be a little careful because sometimes you’ll get a counterfeit that doesn’t work properly and then you’ll be wondering why your Arduino is acting weird. BTW, you don’t have to use an Arduino. You might be able to find a cheaper or more capable microcontroller, like the ESP8266/ESP32 Forseti mentioned.

Here’s the best part about using a separate microcontroller: you know how before I said the direct buttons and IPAC method map to keyboard presses? We can do even better than that.

The HID protocol and HID Devices

This is really important to the whole project. Human Interface Device (HID) is a protocol defined in the 90’s and co-developed by a bunch of huge tech companies to attempt to standardize device drivers. I bet this is the reason why digging around on the internet for drivers is no longer as much of a pain in the rear end as it used to be.

So what does this have to do with us? Almost every kind of modern peripheral that hooks into the computer via USB now adheres to this HID standard. Mouse, keyboard, microphones, game controllers, you name it. And that’s the key to getting the Arduino to work.

If we figure out a way to turn this Arduino into an HID compliant device we can make it appear as a game controller to the host computer. This way, it will work in an operating system the same way that all other game controllers, like Xbox controllers or Dualshock or third party controllers like 8bitdo, work.

This is extremely nice for the following list of reasons:
  • The raspberry pi and retropie packages support this out of the box. Since they already expect you to pair an external controller and have nice configuration interfaces, we can re-use those because the Arduino will appear like any other controller (except it will be permanently bolted into a PCB inside the case).

  • Automatic multiplayer support because of the previous reason. We get whatever Retropie developers did for free. If you want to play Bomberman or Legend of Zelda with your friends on the couch, there’s nothing stopping you. You can pair additional controllers to a Retropie that has our controller connected without worrying about setting up the scripts to handle different cases.

  • It will make any software developers you tell your project about jizz themselves. The entire controller system connects to the Raspberry Pi through a tiny, well defined interface. Something about encapsulation and decoupling functional blocks in a system design blah blah blah

  • I can test this by plugging it into my laptop and use any diagnostic software to check if the buttons are working instead of exclusively having to go through the Raspberry Pi

  • Unlike the direct GPIO button and IPAC methods, we use HID to make this a genuine gamepad instead of keyboard bindings. If you have a game controller and a keyboard connected, we won’t have to worry about any headaches about binding collisions. It is also easier for random software packages you download to support our buttons out of the box because it’s defined as a gamepad instead of masquerading as a keyboard with 15 buttons. Disclaimer: I’ve never actually used the IPAC or direct GPIO binding methods so they may have workarounds for this but I wouldn’t know of them.

This is one of those moments. Maybe it’s just me. It’s probably really obvious to someone who does this a lot.

HID at a High Level

But how do we “add” HID to the Arduino? The basic gist of HID is that it is a protocol (messaging specification) designed to send data over a USB connection. The protocol sends data using specially defined packets called “reports” that each contain (1) a definition and datatype of all the buttons the device contains and (2) the current state (1/pressed or 0/not pressed or some analog value) of each button. Any compliant HID hosts will understand properly formatted reports.

You can read about the HID in spectacular detail from this amazing blog post. I recommend reading it to become familiar with the concepts, but we actually won’t need to know much about the mechanics of the HID protocol because…

...the Arduino ecosystem already has open source HID libraries! Just slam this into the IDE and follow the included examples in the repo, and we’ll have a working game controller in no time. So that’s what I did and will get to in the next post.

HID and How it Relates to the Previous Methods

In retrospect, the microcontroller in the IPAC probably also contains code to make it appear as an HID keyboard. So we’re just doing the same thing but with more steps using the Arduino. The Adafruit GPIO script doesn’t do this, but roughly “emulates” a keyboard device using bash and/or python scripts. Also note that if you choose a non-Arduino microcontroller, you’ll need to track down an implementation of a compatible HID library or roll your own. And that’ll be a whole thing by itself (you’ll definitely need to read the blog post in this case).

One More Thing

I heard that Microsoft even developed some experimental thing where you can send HID messages over an I2C connection. This would actually be good for us because the Raspberry Pi 3A+ only has 1 USB port and I would rather use it as a general purpose USB port instead of having it be consumed by the gamepad. A cursory search doesn’t turn up anything easy to understand so the effort probably fizzled out because no one needed it. If need be I could just get a USB hub to solve the issue, and figure out something when it comes time to fit it all in a case.

Cory Parsnipson fucked around with this message at 23:54 on Dec 8, 2020

Cory Parsnipson
Nov 15, 2015
Remember when you were little and playing with LegoTM and you got to the part in the instructions where they tell you to put aside the existing piece you’re working on and start making a new piece? I was always like, “oh man how do they know to do that”. Well, now is the day when I get to know to do that. I’m putting aside the Raspberry Pi for a bit to work on the controller. This is because the controller will interface with the Raspberry Pi through the USB port, as mentioned before, so we can work on them as separate items until it’s time to integrate them.

Also note, this information can also be used to create a standalone wired game controller, like those crappy third party ones you see on eBay. I won’t be getting to the part where we mount this stuff on a PCB and make a case for it until later though.

How to Make Your Own Custom Game Controller using an Arduino

The Arduino HID library requires you to pick an Arduino module that is compatible with USB development. Meaning that certain Arduino models let the developers mess around with the USB port to send and receive data inside the program loop. Arduinos that use the ATMega32u4 processors (i.e. the Pro Micro) are compatible. The original Arduino (the Arduino Uno) does *not* come with support for this out of the box, but I read that you can add support for it by replacing the firmware with something called “Hoodloader2”.

Additionally, I also read that there are a couple potential problems with using “Hoodloader2”, but I wouldn’t know anything about that since I started with the Pro Micro. The full compatibility list is in the HID repo README file.

Ok, that’s pretty much all the prep out of the way. Here’s my first breadboard prototype:


In progress shot where I have 2 buttons wired up and 2 more to go


4 buttons wired up and testing the connectivity


Full 10 button prototype that I hosed around with for a while

I used these temporary push button switches that came with my arduino starter pack. You might notice that I have the switches in a pull up configuration. I was unaware/forgot/too dumb to make the connection that Arduinos come with built in pull up resistors for each GPIO pin so I didn’t have to make my own. Not a big deal, but I could have saved a bunch of wires and resistors.

Quick Aside about Pull Up Resistors

I think intuitively, one would normally expect that if you press down the switch, you’ll get a digital one signal on the input and when the switch is open it’s a zero. Unfortunately, because of real life physics, getting this arrangement is less reliable than inverting the logic.

With the former arrangement, if the switch is not pushed down, the wires are disconnected. This does not mean the voltage at the input pin is zero--it is an unknown value. The actual values are influenced by interference in the surrounding environment (electro-magnetic, radio, parasitic, etc), I think. In practice, you’ll probably see that it is zero but this is coincidental and not something you can depend on.

With the pullup arrangement, when the switch is released, the input is connected to VCC (5 volts here) via the pull up resistor. When the switch is pressed down, it connects the input to ground (as well as the pull up resistor, so there is some current flowing). In both scenarios, we have a well defined value at the input pin.

Okay Back To The Controller Hardware Prototype

Here’s a crappy video of me using it to try and play Megaman Battle Network 3 Blue:


https://i.imgur.com/vUmfODW.mp4
Click here if you want sound for some reason

I took this quick video to show somebody something, but then I forgot to take a better video and now I don’t have the controller in this form anymore. I should invest in a tripod… :thunk:

For the full experience, I need about 14 buttons to configure everything. I had to leave out the Select and L shoulder button bindings to juuuust fit everything in 9 buttons so that I could play MMBN3. It’s also very uncomfortable and my fingertips were raw after about 30 minutes of trying to figure out how to walk around haha

HID implementation

We need to do some actual programming for once. After the buttons are wired up like above, we need to loop through all the connected GPIO pins and read the value, and then use the HID library to plug in the values into your HID report.

The NicoHood HID repo comes with examples that show you how to use the HID device presets. The library lets you create a keyboard, mouse, gamepad, and even a “surface dial” thingy (this thing) device. You want to use the right template so the library will generate the correct report format and so the host can figure out how to properly categorize your device.


For example, using the Gamepad HID template will show up as a controller in Windows 10. “Wireless Controller” here is a PS4 controller that I’ve connected previously. Neat huh???

Oh, and there is a way to change “Arduino Leonardo” to a custom value but it requires some manual editing to a config file somewhere. I’ll do that at some point. It’ll be a nice touch.

Breaking Down the Gamepad Code

Unfortunately, there’s no documentation and the wiki page for the Gamepad HID template is blank, but the code is straightforward enough to fill in the blanks with some educated guessing. Peep this file, yo.

The first interesting part is the Gamepad.begin() line. You need to put this in your setup function to initialize the Gamepad template. The Gamepad class/struct is defined as part of the HID library. You would use the corresponding Keyboard or Mouse structs to use those templates.

code:
void setup() {
  pinMode(pinLed, OUTPUT);
  pinMode(pinButton, INPUT_PULLUP);

  // Sends a clean report to the host. This is important on any Arduino type.
  Gamepad.begin();
}
Secondly, the example uses “pinButton” that will loop through some predetermined code to “press” all the Gamepad buttons and move the dPads and thumbsticks programmatically. That might be confusing for a little bit.

code:
Gamepad.press(count);
Gamepad.release(count); // added by me, this is not in the example code
Further down you see that the example counts from 0 to 31 and will eventually press each button individually. This is done through the press() and release() Gamepad member functions. A button is any 2-state (digital) button on a gamepad. This may be things like “ABXY”, Start, Select, shoulder buttons, and even the thumbstick R3 and L3 (or whatever they’re called on a non PlayStation controller). Sometimes, like on the Nintendo Switch and 3ds, the triggers are digital and not analog. So if that’s the case, they would be mapped to buttons as well.

By default the HID library’s Gamepad template has 32 hardcoded buttons. If you don’t need all 32, just don’t connect them. If you need more, you’re gonna have to make a custom Gamepad template. I’m good for now, so I’m not gonna delve into that.

code:
// Move x/y Axis to a new position (16bit)
Gamepad.xAxis(random(0xFFFF));
Gamepad.yAxis(random(0xFFFF));

// Move other thumbstick (added by me, not in example code)
Gamepad.rxAxis(random(0xFFFF));
Gamepad.ryAxis(random(0xFFFF));
From the definition, I can see that there are 2 thumbsticks and you refer to them through different axes. One thumbstick (presumably the “left” one?) has two 16-bit values called xAxis and yAxis, with a third 8-bit value for zAxis. Typical controllers will only use the x and y axes, but if you want something like an accelerometer, you would use the z axis, I guess. The second thumbstick (presumably the “right” one?) has the same values, but labeled rxAxis, ryAxis, and rzAxis. I’ll get to this in the next update.

The dPad is special for some reason. Probably just copying how a lot of companies implemented it. There are 2 dPads for some reason and we will only need one.

code:
// Go through all dPad positions
// values: 0-8 (0==centered)
static uint8_t dpad1 = GAMEPAD_DPAD_CENTERED;
Gamepad.dPad1(dpad1++);
if (dpad1 > GAMEPAD_DPAD_UP_LEFT)
  dpad1 = GAMEPAD_DPAD_CENTERED;
I didn’t use this in my own code by accident… I should have read this more closely. Instead I bound the dPad buttons like all the other buttons. Retropie doesn’t care because you use a utility to define your button mappings anyway, but it would be good to fix this so it’ll be compatible with other things. Like if, for some reason, I want to use my garbage controller with Steam or something.


The configuration wizard in Retropie. You press corresponding buttons (right) to map to Retropie functions (left).

code:
// Functions above only set the values.
// This writes the report to the host.
Gamepad.write();
This is also important. Use this function to send the HID report to the host machine once you’ve made all your updates.

Breaking Down the Code that I Wrote

Here’s my repo with the full example code.

There’s some other stuff in here, but basically I just loop through all the GPIO pins I hooked up and do a digital read and then call press() or release().

code:
for (int idx = 0; idx < NUM_BUTTONS; ++idx) {
    int button = idx + 1;
    int pinIsHigh = digitalRead(idx2Pin[idx]);
    // …
}

if (pinIsHigh) {
  if (!getPressed(button)) {
    setPressed(button, true);
    Gamepad.press(button);
  }
} else {
  setPressed(button, false);
  Gamepad.release(button);
}
Uhhhh... heh :sweatdrop:, I don’t remember why I was keeping track of the button states with getPressed() and setPressed(). I think I was using it to print out diagnostic messages and I forgot to delete it. I’ll clean it up in the next iteration.

The rest of the stuff in there is dealing with the thumbsticks, so you can ignore that for now. This should be everything we need to make the controller act like in the video I posted above.

Testing the Gamepad

In Windows, you can go to the control panel and right click on the Gamepad icon under “Devices” and then click “Gamepad Settings”. This will open a utility that lets you calibrate the gamepad and view which buttons are being pressed.


https://i.imgur.com/w3J6YOH.mp4

For people in Linux, there are a couple utilities. One that I think is nice is called evdev-joystick



This shows analog axes for thumbsticks and underneath is a display for the state of buttons like in the Windows utility. Testing in linux is not as simple as using the utility like in WIndows. More on this in the next update.

Cory Parsnipson fucked around with this message at 22:06 on Dec 16, 2020

Cory Parsnipson
Nov 15, 2015
I Added a Thumbstick to the Arduino Controller

First, the final product:



https://i.imgur.com/2NOOqdS.mp4
You have no idea how good this feels after using the push buttons.

This was both more complicated and simpler than I thought it would be. To be more specific, the hardware was simpler than I thought it was going to be but the software was kind of a pain in the rear end to get right. Working on the thumbsticks turned out to be pretty fun and cool though, because I learned a lot about something I have no idea about.

The first problem is to figure out what everything is called. To this end, the easiest place to start is to google 3DS replacement parts and DIY repair videos. For whatever reason, the part of the thumbstick that contains the electrical and mechanical components is called a “thumbstick module”.


A 3DS thumbstick module. There is supposed to be a grey thumbstick cap that clicks into place on top of this for that recognizable rubber circle look. More on this later.

“Thumbstick module” seems to be a general term for this entire class of parts. For example, here’s a DualShock 4 thumbstick module:


I found a picture with the thumbstick attached on top so you can recognize what it is.

I initially did research into how the circle pad works. It’s a real curiosity, especially since the “slider” type of thumbstick isn’t really in favor anymore. Then I also looked into the Nintendo Switch thumbsticks, after I noticed it seemed really popular with hardware modders for some reason.

How a 3DS Circle Pad Works

When I first used a circle pad on the 3DS I thought it was quite uncomfortable. But it’s really grown on me and I was hoping to include two of these into my RPI shell. I suspect it’s not as popular as a “real” thumbstick, and if anyone reading this has an opinion about 3DS circle pad vs Switch thumbstick I’d be interested in hearing it.

Take a look at this:

Here’s an exploded view of the 3DS circle pad parts.

Yes... there are two separate dust rings and they’re actually completely different parts. I couldn’t really depict this in the illustration, but the outer dust ring actually fits right under the 3DS case and above the lower notched ridge of the thumbstick cap. You can actually see this on the 3DS if you move the thumbstick to one of the extremes. It’s the shiny black plastic film looking thing that is in the gap. This is needed to prevent dirt and grime from getting into the thumbstick column. The inner dust ring sits on top of the thumbstick module and between the bottom of the thumbstick cap. This “washer” is here to make sure the movement between these two parts feels smooth. I did a little searching hoping to see if I could skimp on the dust rings but it looks like that’s not possible as they both have distinct purposes.

Some repair videos and tutorials were really helpful for seeing how everything fits together, especially the super secret technique for fitting the cap through the case hole.

I managed to find really affordable dust rings in large quantities on Aliexpress and it was really hard to find the right keywords for these things, so I’ll link them here:
Outer dust ring
Inner washer ring

I also bought a pair of caps here. I bought from Amazon here, but this was before I resorted to AliExpress, which seems to have better deals. As with anything associated with Nintendo, the parts are really expensive (some going for, like $8 each???) and it’s a pain to buy these because a lot of sellers are making crappy knock-offs.

Thumbstick modules are similarly priced, around $8 - $15, and I’m trying to get the new 3DS parts and not the older models, so you have to be careful there. Expensive, right????

How a Nintendo Switch Thumbstick Works

The Nintendo Switch thumbstick, by comparison, feels like you can buy a single piece and have everything ready to go. It’s clear that Nintendo did a ton of R&D for their crown jewel console and it shows. Not only that but Nintendo Switch replacement parts seem to be cheap and plentiful. I think this is because of how well the Switch is selling and also because they chose to make the design out of inexpensive parts.


This diagram almost feels unnecessary.

Everything is pretty much self explanatory. The gasket does the same thing as the dust ring, but doesn’t seem super necessary.

Buying replacement thumbsticks is muuuch easier. I bought a pack of 4 off Amazon for about $5 each, but on AliExpress you can get some for $2 per. For the whole mechanism! No wonder this is really popular with modders.

I Thought You Were Gonna Use a 3DS Circle Pad???

Yeah that was the plan. I like how the circle pad is designed to be compact and it looks cool, but building a circle pad presented quite a few problems for me.

First of all the most important part is that the circle pad lacks the “click in” button that true analog sticks have. The Nintendo Switch thumbstick and PlayStation thumbsticks both let you press down on the stick and have it click down. This would be a problem if you need to use L3 and R3 in some games. Secondly, the 3DS thumbstick requires so many more parts and not only that but they are more expensive since they are specific to the 3DS. All the parts together can run you up to $20 per thumbstick if you’re not careful! Third, the 3DS thumbstick requires some careful attention to the design of the case. There is a specific size of the through hole that the cap needs to sit inside as well as a constraint on the thickness of the casing so you can fit it in between the ridges of the thumbstick cap. I haven’t even gotten to worrying about the case yet, but this is just making things more complicated for myself.

By comparison, the Switch thumbstick is a cheaper all-in-one package. However, there is one concern and that’s JoyCon drift. I don’t know how it works and what causes it, and neither apparently does anyone else, but from what I’ve read it looks like it could be a problem with the thumbstick design itself. Personally, the ones I bought are just fine, but I’ve barely used them. Just something to watch out for in the future.

Actually I just did another search and now they have “3rd generation” thumbstick replacements that allegedly solve the drifting issue? So I guess go with those. They are slightly more expensive, but probably worth it if the drift is no longer an issue.

That said, I do have all the parts for making two whole 3DS circle pads, but I guess they’ll have to sit in my box for a different project. Or I can try to make a version of the shell with the circle pads just to see what it would be like… :thunk:

Cory Parsnipson
Nov 15, 2015
Connecting the Thumbstick to the Arduino Controller

Ok, let’s go back to the thumbstick module. Now that we’ve figured out how the hardware works, we need to figure out how to interface with this thing.



There’s a small, striped ribbon coming out of the 3DS thumbstick module. The next step is to figure out how to connect this to a breadboard for prototyping. I had no idea what this was called, so I looked up pictures of open 3DS’s and Switches and went on some forums to do some pointing and grunting.


It me.


Point and grunt.

They told me to look into “FPC’s”.

So it turns out this ribbon cable is called a “flat flexible cable” (FFC) and it hooks into a “fine pitch connector” (FPC). The specific type of connector in the Switch picture is a “zero insertion force” (ZIF) connector, meaning that you don’t need to shove the cable into the socket like a NES cartridge, but simply place it gently in and lock it in place with the connector’s hinge. I’ve seen people also call this a “ribbon lock”, which appears to be a more general, colloquial term for it.

This thread has someone who did the hard work of measuring the cable and estimating the specs. It’s important to figure out the right pitch (spacing between wires) of the FPC and ZIF connectors. It turns out the 3DS and Nintendo Switch thumbsticks are 0.5mm pitch. The next important attribute is to figure out how many “positions” you need in the connector. This is just a way of saying how many wires are in the cable. For the Switch, there are 5 positions (see below), and for the 3DS, there are 4 positions. The discrepancy is because the Switch thumbstick can be pressed down and used as a push button. The extra wire is for this signal.

I managed to find the exact part or something extremely close to the Switch connector on digikey. And I also picked up some connectors for the 3DS too.

An invaluable forum post here describes the pinout for the Nintendo Switch thumbstick:


Five wires, nice and simple. “U/D” (up/down) must be the y axis, while “L/R” (left/right) is the x axis. “BTN” is the wire for the click down function I mentioned before.

Since the connector is a surface mount part, I also needed to buy or make a breakout board for this. I bought these off Amazon.



They’ve done the job quite nicely.





You can see the ZIF connector for the Switch thumbstick up close here. The black part is actually a hinge that swings open. You put the Switch FFC into the connector and then close the black hinge on top and if you do it right, the cable is stuck in there.



I added some quick release wires after soldering in the male pin header to the through holes.



Here I mounted the thumbstick and breakout board to a padded manila envelope.



I connected the whole contraption to the proper Arduino pins in my controller. Ok here’s the funny part… The ZIF connector I got actually says the contacts are on the bottom of the connector, so this meant that I needed to flip the cable around. You’ll notice the breakout board is now upside down relative to the thumbstick. This is actually how it is in the real JoyCon as well. This took about a day of debugging while writing the software additions to figure out why no signal was coming through.



I moved onto corrugated cardboard because the manila envelope was too flimsy. This is much better.



And here’s the shot again of the final contraption attached to the Arduino controller. I think I’ve unintentionally re-invented the Wiimote and nunchuck layout. I thought it felt familiar playing games like this.

Next up is going to be a section describing the trials and tribulations of getting the thumbstick software to work. I hope I'm not boring everyone to death...

Cory Parsnipson
Nov 15, 2015

oldskool posted:

This is a fascinating look into joysticks.

I really like the ribbon cable design for the low-profile thumbsticks but I'm sure a large part of that is my aforementioned inability to solder. It almost feels designed to fail considering how fast the actual stick replacement is once you get the controller disassembled.

That's a good point. I guess you could argue that Nintendo went too cheap on the Switch thumbsticks, especially if they're getting sued twice. The ribbon locks are pretty standard. Inside a 3DS, you'll see the SD card reader, LCD screen, and shoulder buttons are also attached this way. The more detachable components the better for repairs.

=============================

On an unrelated note, this is embarrassing... I was looking at my code again to rewrite it and I've completely confused myself over how the push buttons are working.

code:
int pinIsHigh = digitalRead(idx2Pin[idx]);

if (pinIsHigh) {
  if (!getPressed(button)) {
    setPressed(button, true);
    Gamepad.press(button);
  }
} else {
  setPressed(button, false);
  Gamepad.release(button);
}
This part of the code implies that when I press the buttons, the input receives a high signal and when the buttons aren't pressed, the inputs are low. This is the opposite of how the pull up resistor set up should work. In my circuit, I put the pull up resistors in the wrong place:



The resistors here are connecting the wrong side of the switch, so when the switch is open, the input is being pulled to ground*. I think when the switch is closed, the connection to VCC pulls the input high, which the pull up wasn't able to do because it's not a strong voltage source. (Not super sure about this part) So I guess when it's working here, it's working by accident. :saddowns: I mean if it works the way I'm explaining it, then it's a perfectly fine way of doing things but not what I thought I was building. I'm going over all of this again and rewired the controller to use charlieplexing (update coming soon) and using the built in pull ups properly so hopefully I'll get it right the next time around...

*the switches are confusing. They each have 4 contacts. The contacts on the same side are disconnected when the switch is open. But corresponding contacts on opposite sides are always connected. (e.g. the blue wire and the resistor on the bottom most switch are always connected)

Cory Parsnipson fucked around with this message at 22:39 on Dec 17, 2020

Cory Parsnipson
Nov 15, 2015

Forseti posted:

Yeah, you have pull-down resistors there and they'll work as you described. The two pins that are always connected are common (the wiring inside looks like an H where the middle bar is a switch) so that wiring is a bit confusing because you have to know how the switch looks inside to know that, but is electrically valid. Do you mean you have the pull-up resistors in the MCU turned on as well and they're fighting with the the pull down? That would make a voltage divider so technically when the switch is open it would be somewhere between ground and Vcc but if the resistor values are far apart that might not be apparent. When closed, there's no resistance to Vcc so it'll win or destroy something trying (ie: don't press a button if the pin happens to be set to output mode and low).

Indeed, they are pull down resistors. I looked it up, that's good to know. And yes, I did have the pull up resistors in the MCU turned on too. By some cosmic chance, I narrowly avoided breaking my Arduino. Somehow all my mistakes cancelled themselves out and ended up working. Here's the circuit:



The pull up resistor is connected directly to the pull down resistor. When it's open it forms a voltage divider like you said. It says online that the internal pull up resistors are supposed to be around 30k-50k ohms and I was using 1k ohm resistors except for the last two buttons where I used 2k resistors because I ran out. So the voltage divider is around 0.1 or 0.3V and is rounded down to zero by the firmware. When I close the switch, I'm bypassing the pull up resistor so now the full 5 volts goes across the lower resistor.

Modifying the Arduino Code to use the Thumbstick

Ok, time to revisit the controller code and add the handler for the thumbstick. I’ll be referencing the same repository as last time.

Remember this?

Cory Parsnipson posted:

code:
// Move x/y Axis to a new position (16bit)
Gamepad.xAxis(random(0xFFFF));
Gamepad.yAxis(random(0xFFFF));

// Move other thumbstick (added by me, not in example code)
Gamepad.rxAxis(random(0xFFFF));
Gamepad.ryAxis(random(0xFFFF));
From the definition, I can see that there are 2 thumbsticks and you refer to them through different axes. One thumbstick (presumably the “left” one?) has two 16-bit values called xAxis and yAxis, with a third 8-bit value for zAxis. Typical controllers will only use the x and y axes, but if you want something like an accelerometer, you would use the z axis, I guess. The second thumbstick (presumably the “right” one?) has the same values, but labeled rxAxis, ryAxis, and rzAxis. I’ll get to this in the next update.

Now we get to call those functions using the outputs of the Switch thumbstick. The U/D pin goes to y axis and the L/R pin goes into the x axis.



If we look at the pinout of the Pro Micro, pins 18 and 19 are the first two analog inputs. We need to use those and configure them in the software to expect an analog signal. Aside from VCC and GND, I also plugged the BTN signal of the Switch thumbstick arbitrarily into pin 14, a dedicated digital pin. They are defined in the code like this:

code:
const int pinL3 = 14;

const int pinLXAxis = A1;
const int pinLYAxis = A0;


Posting this image a third time… Focusing on the long wires between the thumbstick and the arduino. You can’t identify the exact pins using this picture, but hopefully you can see that in the GPIO diagram, the pins are clustered on the right side of the microcontroller and that’s exactly what I did IRL.

code:
void setup() {
  // ...
  pinMode(pinL3, INPUT);
  digitalWrite(pinL3, HIGH);

  digitalWrite(pinLXAxis, LOW);
  digitalWrite(pinLYAxis, LOW);
}
During setup, I change the L3 pin into an input and write a HIGH value to it (because the BTN signal is high when not pressed and low when pressed). The analog pins are written LOW because we expect them to range between -32767 and 32767 and assume a value of zero when the stick is centered. The Arduino forums say that you don’t need to set the pinMode for analog pins, you just do an analogRead() on them.

Then in the main loop, I treat the L3 button exactly like the other buttons, since the button on the Switch thumbstick will be pulled to ground when the thumbstick is pressed in.

code:
void loop() {
  for (int idx = 0; idx < NUM_BUTTONS; ++idx) {
    int button = idx + 1;
    int pinIsHigh = digitalRead(idx2Pin[idx]);

    if (pinIsHigh) {
      setPressed(button, false);
      Gamepad.release(button);
    } else {
      if (!getPressed(button)) {
        setPressed(button, true);
        Gamepad.press(button);
      }
    }

  //...
}
Finally, I use analogRead() to get the analog value of the thumbstick positions and write the Gamepad’s xAxis and yAxis values after doing a bunch of processing on it. Why so much code? Well, the rest of this post will be dedicated to explaining it.

code:
void loop() {
  // ...

  // analog axes
  int readX = analogRead(pinLXAxis); // store in temporary variables to use in constrain()
  int readY = analogRead(pinLYAxis);

  const int XMIN = 200, XMAX = 880;
  const int YMIN = 125, YMAX = 835;

  // clamp values to observed joystick values
  readX = constrain(readX, XMIN, XMAX);
  readY = constrain(readY, YMIN, YMAX);
    
  Gamepad.xAxis(map(readX, XMIN, XMAX, -32767, 32767)); 
  Gamepad.yAxis(map(readY, YMIN, YMAX, 32767, -32767)); // flip Y axis because I have it oriented upside-down

  Gamepad.write();
}
Testing the Code Using Windows Control Panel

I need to go back to the Windows control panel, and view game controller properties.


https://i.imgur.com/5bb8Fq4.mp4

This time, we need to click the “Settings” tab and then “Calibrate”. This window will let you see the raw values of the analog stick. In this gif, I modified the code above to write the raw values from analogRead() directly to the HID report.



The neutral position for this stick appears to be (509, 509). If I move the thumbstick around, I can observe what range of values the thumbstick will give us. The x axis range is approximately from 237 to 868 and the y axis range is approximately from 134 to 823. This is when the stick is being driven at 5V. I don’t know what a real Switch is calibrated to, but the reverse engineering wiki implies that the thumbstick is driven at 1.8V so the range will be different in that case. These are very random numbers. We want to remap these numbers to less random numbers, -32767 and 32767, which are the min and max you can express with a 16 bit value a.k.a. the size of the axis value storage.

code:
const int XMIN = 200, XMAX = 880;
const int YMIN = 125, YMAX = 835;

// clamp values to observed joystick values
readX = constrain(readX, XMIN, XMAX);
readY = constrain(readY, YMIN, YMAX);
The first step is to clamp the values to the observed min and max. I put in some leeway in case the thumbstick can go a little further. The values are really “jittery” in the windows calibration screen and seem to vary between individual thumbstick units and over time in the same unit as well. This could be a problem which I think is related to how cheaply manufactured the thumbsticks are.

code:
Gamepad.xAxis(map(readX, XMIN, XMAX, -32767, 32767)); 
Gamepad.yAxis(map(readY, YMIN, YMAX, 32767, -32767)); // flip Y axis because I have it oriented upside-down
Arduino comes with a built in map() function that lets you take in a number and transform it to a different interval. Also I flip the y axis because I have the thumbstick oriented upside-down in my cardboard contraption.

Viewing Joystick input on the Raspberry Pi with sdl2-jstest

I wanna note that the previous code is the final product, but before that, I only had the analogRead() lines in the code. At this point, I could see everything working in windows, but when I went to plug the controller into the Raspberry Pi, the analog stick wasn’t doing anything. The configuration wizard refused to map the analog stick movement to any buttons. It was difficult to figure out what was going wrong here because I didn’t know anything about how RetroPie works internally. I looked through some of the relevant configuration files and then annoyed one of the moderators for answers.

I was told to use jstest (and jscal) to try and diagnose the problem. These are joystick utilities that come preinstalled with the RetroPie image.

code:
jstest /dev/input/js0
Using this command, I could see stuff was happening when I moved the joystick:

code:
Driver version is 2.1.0.
Joystick (Arduino LLC Arduino Leonardo) has 10 axes (X, Y, Z, Rx, Ry, Rz, Hat0X, Hat0Y, Hat1X, Hat1Y)
and 32 buttons (Trigger, ThumbBtn, ThumbBtn2, TopBtn, TopBtn2, PinkieBtn, BaseBtn, BaseBtn2, BaseBtn3, BaseBtn4, BaseBtn5, BaseBtn6, ?, ?, ?, BtnDead, (null), (null), ...
Testing ... (interrupt to exit)

Axes:  0:     0  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0:     0  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0:     0  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0:  4599  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0:  8453  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0: 12310  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0: 15203  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0: 19830  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0: 25227  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0: 32455  1:   -15  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Axes:  0: 32455  1:     0  2:     0  3:     0  4:     0  5:     0  6:     0  7:     0  8:     0  9:     0
Initially I'd picked an arbitrary range of 0 to 16384 for the axis values. I dunno why, it just seemed like a good starting point. I read on Wikipedia that old joysticks used whatever range they felt like and then you had to calibrate them to whatever computer you were using. The wiki article also says that modern joysticks seemed to have settled on the full 16-bit range of +/- 32767 (a wise decision imo), so this means that my joystick's full range covered only neutral to half tilt. If RetroPie is expecting the full range, then it makes sense why none of the thumbstick movement registered as anything. I used jscal to recalibrate the joystick to use the full +/- 32767 range which is what you are seeing in the above code snippet. Unfortunately, this did not change my situation at all.

The mods over there told me to use the sdl2-jstest instead of the built in jstest. Not familiar with SDL or how the graphics library stuff works internally, but they said RetroPie uses SDL2 so it’s better to use this program. You have to install it yourself though.

Run jstest /dev/input/js0 and you’ll see something like this:



The numbers here are not the full range. This was where I’d say I had a lot of trouble because I spent a while wondering why the joystick still wasn’t doing anything even after I calibrated it. This is why the mods said to use sdl2-jstest! The other utility and its calibration is not being used by RetroPie. This is when I went back to the Arduino firmware and expanded the range from +/- 16384 to +/- 32767 to avoid having to deal with the calibration headaches. (Seriously, not only would I have had to calibrate it, but then store the calibration output into a file and set up a bash script that would run every time on startup to restore the calibration coefficients. Absolutely avoid this if you can.)



This is what I got afterwards. This is what happens when your initial min and max values are too small. The thumbstick output overflows and wraps around like a Mario Bros level.



Only after I added some leeway and clamped the output to my initial range, was the joystick behaving the way I wanted. And finally, the configuration wizard and RetroPie UI was recognizing my thumbstick inputs. Whew, this part actually took a couple weeks going over my entire setup, looking into RetroPie documentation and config files, and then finally asking for help on the forums. I feel like there were quite a few undocumented gotcha’s where I had to put together unintuitive pieces of information that might have been common knowledge for someone who was familiar with the whole software package. Delving into RetroPie was difficult.

Anyway, it felt super good to have it working. Me using it again for posterity:

https://i.imgur.com/2NOOqdS.mp4

Cory Parsnipson
Nov 15, 2015
LCD iteration 2 (OSOYOO 5" DSI screen with Touch)

Christmas update!





I'm tired of waiting for parts to come in so I opened my second LCD screen and tried it out. It was literally plug and play, so I'm super happy with the amount of effort it took to set up. The only thing is that it is 50 bux so maybe sometime in phase 2, I'll try to find an equivelant mass produced LCD as suggested earlier by Forseti. Physically, the size is perfect for me. I really like this size and hope to stick with screens that are similarly shaped.


https://i.imgur.com/eWxhsaN.mp4

The resolution on the screen is 800x480 and can be configured to be 1920x1080. This is large enough to actually use as a Linux console window! You should be able to see the start up messages in the video above, but it's off angle. I'm not sure if the bad viewing angle is because of the protective film or not.



It's very bright, but the good news is that it's adjustable by running a linux command. I can either hook this up to an external pot with a bash script (like in the GBA) or use a script to provide a digital menu (3DS style).




https://i.imgur.com/SDwNUOW.mp4

I can't wait to package everything up. This is gonna be awesome.

Cory Parsnipson fucked around with this message at 21:38 on Dec 23, 2020

Cory Parsnipson
Nov 15, 2015
The current controller design barely fits 10 buttons and the digital/analog inputs for one thumbstick. Needless to say, this is not enough buttons for a modern controller. Some of the features you’ll find on one of those controllers would be:
  • 4 dpad buttons
  • 4 face buttons (i.e. ABXY, circle cross square triangle, etc)
  • Start
  • Select
  • Home/Meta button
  • Right shoulder (a.k.a. “bumper”) button
  • Left shoulder (a.k.a. “bumper”) button
  • Left Thumbstick Button (“L3”)
  • Right Thumbstick Button (“R3”)
  • Right Trigger (may be analog or digital, not sure yet)
  • Left trigger (may be analog or digital, not sure yet)
  • 2 Analog Axes for Left Thumbstick
  • 2 Analog Axes for Right Thumbstick
  • 3 Axis gyroscope
  • Honorable mention: rumble

Let’s ignore the gyroscope for now, although that would be something really cool to add in for the second version. We have what looks to be a total of 15 digital buttons and 4 analog inputs (or 17 digital and 6 analog if the triggers are digital). This is way more than the 10 buttons that can fit on the Arduino with direct mapping. I’m gonna have to figure something out.

With more complicated wiring schemes there are ways to get more bang for your buck in terms of GPIO. For instance, if you look up how people make Arduino keyboards, they might mention something called a key matrix. You’ll see this type of setup in old telephone button pads or modern button pads like on a garage door opener. In these types of things they cleverly split the GPIO pins into two groups, half inputs and half outputs. The wires are organized into a grid and each intersection corresponds to a button. The software is changed to iterate over all input/output pairs and the output is brought high and the input is checked for the value. If the button at the tested intersection is pressed, the output should have the same value as the input.

When you make a keyboard, you can use 18 GPIO pins to support 81 buttons, which is not enough for a full keyboard, but will let you make a 75% or 60% keyboard. If I were to use this, I’d need 10 pins to support a max of 25 buttons (I could use 8 pins too, but then I’d have to go back and change something if I discovered that I needed to add some more buttons like, for example, a power button, brightness, or volume.) The key matrix setup isn’t too bad, but this is still kind of crowded for an Arduino Pro Micro.



Counting the digital IO pins and ignoring the ones with green (analog) capabilities, there’s 9 dedicated digital pins. Unfortunately, if you wire up pins 0 and 1, you will have to disconnect them each and every time you reprogram the Arduino (because pin 0 and 1 are also used to transfer data over the USB port to the microcontroller’s programmable memory). The spots that say “RX LED” and “TX LED” can also be desoldered and used as digital GPIO pins. I’d prefer not to have to do these things if there’s another way because it’s just a pain in the rear end. We’re left with 7 digital IO pins and then we can use 3 of the analog pins as digital pins, leaving us with just enough remaining analog pins to support thumbsticks and triggers. Kind of a shame imo because we’d need an additional 3 analog pins if we want to add in a gyroscope.

There’s other methods like-

babyeatingpsychopath posted:

Can't wait until you get into your buttons and switches. Charlieplexing and diodes, aplenty, right?

Charlieplexing. The theory is very similar to key matrix, but with more complicated wiring we can get a greater efficiency when it comes to the number of supported inputs.

babyeatingpsychopath posted:

Normal switch matrix takes n pins to drive n2/2 pins, but charlieplexing uses n pins to drive n2-n pins. So a charlieplex 4x4 matrix only needs to use 6 pins, instead of 8. By being clever about which of your inputs are high, which are low, and which are input, you can get all your input with fewer pins, as long as you can sacrifice refresh rate.

I thought the concept was pretty intimidating at first, especially when you see what the wiring looks like:


Hmmmm… this is kind of scary

Also I just happened to come across the term GPIO expander the other day and boy that sounds nice, you can drop this in and direct map all you want at the cost of, like, $2???


Must… not… use unnecessary ICs...

Also I want to bring to your attention this quite interesting tidbit from the Nintendo Switch Reverse Engineering repo:

”dekuNukem” posted:

Also, in a bizarre move, Nintendo didn't use the traditional "one side pulled-up other side to ground" way of reading buttons, instead they used a keypad configuration where buttons are arranged in rows and columns. They used the keypad scanner built-in inside the BCM20734 with 128KHz clock for reading the buttons. That means it would be extremely hard to spoof button presses for TAS and twitch-plays. Maybe the Pro controller is different, need to buy one though.

INTERESTING. By their description of the pull up arrangement, they seem to imply that previous consoles and hardware had the buttons directly connected to GPIO pins in a pull up configuration. And now for the switch, they actually went with the key matrix scheme and called it a day (to be fair, you can’t really beat built-in-to-the-microcontroller in terms of convenience).

And all that stuff about spoofing button presses is interesting. I don’t think anyone would be trying to speed run on this thing I’m making, but I also don’t want to make anything unnecessarily locked down. This is good stuff to keep in mind.

So with that, we got direct connection, key matrix, GPIO expander, charlieplexing. Choices, choices, choices. Whatever should I do????

cakesmith handyman posted:

Just found this thread and it's super interesting, thanks for your explanations.

Thanks, dude, I appreciate it!

PS: Happy new year!

Cory Parsnipson fucked around with this message at 20:24 on Jan 1, 2021

Cory Parsnipson
Nov 15, 2015
I have no idea what I’m going to d-



Tbh, I put off doing this a little bit because Charlieplexing seemed complicated but breaking it down into smaller pieces makes it relatively simple. And the results were achievable with a lot less work than I thought it was going to be. So that’s good.

Charlieplexing requires you to have a microcontroller with controllable GPIO pins and relies on the ability for you to switch the pins between input and output modes. When a pin is set to output, you can write either a high (5V) or low (0V) value to it. Pretty self explanatory. When the pin is set to input, the controller does not write a value to the pin because it is trying to read whatever voltage you have connected to it. It is said that this pin is now in high-impedance (or high-Z, since Z is the symbol for impedance) state. Basically, the pin no longer makes a connection in the circuit and you can pretend, for our purposes, that it and everything connected to it doesn’t exist.

Here’s this diagram for wiring 6 LEDs in a charlieplex arrangement. This circuit allows you to individually light each LED depending on how you configure the GPIO pin modes on all 3 pins.


Stolen from this article. Which explains Charlieplexing better than I am now.

For example, if you want to light the LED labeled “DS1”, you set Pin 0 and Pin 1 to output, write Pin 0 as high (5V) and Pin 1 to low (0V), and set Pin 2 to an input. Since Pin 2 is an input, it is in high impedance state, and we can pretend that all the elements connected to Pin 2 do not exist. (i.e. DS3, 4, 5, and 6 have no current flowing through them right now and they aren’t part of a circuit). Then we can focus on DS1 and DS2. And only DS1 is lighting up because we have Pin 0 acting as a voltage source and Pin 1 acting as a ground. Remember that LEDs are diodes and only allow current to flow in one direction, so DS2 isn’t lighting up.

If we wanted to light DS2 only, we keep everything the same but reverse the values we write to Pins 0 and 1:
  • Set pin 0 to output and write a low value to it
  • Set pin 1 to output and write a high value to it
  • Set pin 2 to input
Hopefully that’s enough information to figure out how to configure the pins to light the other 4 LEDs. The basic gist is that you find the 2 pins that are connected to the LED you’re interested in, figure out which should be high and which one should be low based on the polarity of the LED, and then set the remaining pins to high impedance so the rest of the circuit can gently caress off. This part is key, because now we don’t have to hold this entire mess in our heads, but only care about the small part of the circuit we are interested in at the moment.

Here’s what I did testing this out:


Wired up circuit for 3 pin charlieplexed LEDs


https://i.imgur.com/HsoCYdn.mp4
Video of slow loop across all connected LEDs


https://i.imgur.com/JtU7HZD.mp4
Speed up the looping to make it look like all LEDs are on at the same time. (Flicker much less pronounced in real life than in video)

Let’s take a quick look at the software before I scale up to the required number of pins and make more modifications...

Charlieplexing Arduino Code

I found some starter code here and modified it slightly so that we can scale it up later without having to redo everything:

https://github.com/CoryParsnipson/charlieplexing/blob/83b530d6897d134ddfffb98193c8b465bf7f5082/3pin-leds/3pin-leds.ino
code:
const int CPIN0 = 16;
const int CPIN1 = 14;
const int CPIN2 = 15;

const int NUM_LEDS = 6;
const int REFRESH_INTERVAL = 1000;

const int MODE_MAP[NUM_LEDS][2] = {
  { CPIN0, CPIN1 },
  { CPIN1, CPIN0 },
  { CPIN1, CPIN2 },
  { CPIN2, CPIN1 },
  { CPIN0, CPIN2 },
  { CPIN2, CPIN0 },
};

void setup() {
  reset();
}

void loop() {
  for (int i = 0; i < NUM_LEDS; ++i) {
    drive_pin(i);
    delayMicroseconds(REFRESH_INTERVAL);
  }
}

void drive_pin(int idx) {
  reset();
  
  pinMode(MODE_MAP[idx][0], OUTPUT);
  pinMode(MODE_MAP[idx][1], OUTPUT);

  digitalWrite(MODE_MAP[idx][0], HIGH);
  digitalWrite(MODE_MAP[idx][1], LOW);
}

void reset() {
  pinMode(CPIN0, INPUT);
  pinMode(CPIN1, INPUT);
  pinMode(CPIN2, INPUT);

  digitalWrite(CPIN0, LOW);
  digitalWrite(CPIN1, LOW);
  digitalWrite(CPIN2, LOW);
}
The useful part here is probably the nested array called “MODE_MAP”. I use this array inside drive_pin() to set the GPIO pins whenever I want to light up an LED. drive_pin() is the piece of code where I set the two important pins to output and then write low and high values to them while setting everything else to high impedance, via the reset() subroutine. It takes in a number identifying an LED as an input*, which is the same value used to index into the outer level of the MODE_MAP data structure. Then this function uses the first value of the MODE_MAP entry to set as output and write high, and the second value to set as an output and write low.

*Hmmm… Now that I’m going back over it, drive_pin() is quite the misnomer because I want it to indicate which LED it will turn on and the fact that it drives pins to do so really isn’t useful to the caller. It would probably be better called something like drive_led(). The name of this function ends up changing in my later code snippets.

Persistence of Vision

Lastly, the main loop() iterates through all the LEDs leading to the behavior you see in the above animated loops. This part can be changed and customized as necessary depending on your application. For instance, what you see in the code example is pretty useless in that it unconditionally lights everything up. But if you were making a subway sign for instance, or some kind of control panel where every LED corresponds to a button or setting somewhere, you can drive pins based on that information instead.

The important part here is that you must constantly loop through all LEDs if you want them to look like they’re all on at the same time. Wikipedia says the minimum frequency is 50 Hz, but I personally find that to be way too slow. In the second video above, I have it set to 500Hz and that seems to be around the minimum to work for the naked eye, but as you can see, it still flickers in video. You may need to adjust the frequency up or down a little to capture it on video (it depends on the video capture framerate). Luckily, the Arduino looks to be capable of a much higher range of refresh rates than you would ever need, unless it’s doing a lot more heavy lifting on the side.

Was this worth it

If you have n pins you use to charlieplex LEDs, you can support n2 - n LEDs with them. The benefits of this obviously grows as you scale up n. So far with 3 pins, we can support 6 LEDs and it’s not really worth it at this point to add all this extra complexity just to get 3 more LEDs out of it. But with 5 pins, I can support 25 - 5 = 20 buttons, which will give me support for more than enough buttons and room to grow in the (near) future.

Cory Parsnipson fucked around with this message at 20:56 on Jan 5, 2021

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Looks pretty good. I used UnoJoy back in 2014 to make my two-axis-and-a-bunch-of-buttons. I think it used an Arduino Nano; it's buried back in the base of the joystick. Anyway, there are two chips onboard the device, an atmega8u2 which does all the USB stuff, and a standard atmega328p (normal arduino) that reads all the buttons and axes and stuff.

Switching pin modes from INPUT to OUTPUT may take some time to stabilize; be mindful of switch debouncing and pullups/pulldowns/slew rate.

I learned that the Pro Micro isn't actually an official Arduino but a 3rd party mod from SparkFun. Haha, whoops! You also made me look up the specs out of curiosity and it turns out the atmega32u4 has an integrated usb controller. Neat.

Gotta take another look at the refresh interval. I'm using 1 millisecond, which feels okay to me for now. Is 10 microseconds an arbitrary number or was it something you put in specifically?

babyeatingpsychopath posted:

Then in the 8u2 code, it reads in the controller switch data and converts all the d-pads to actual d-pad values like such:
code:
	switch((btnList.dpad_1_dn<<3)+(btnList.dpad_1_rt<<2)+(btnList.dpad_1_lt<<1)+btnList.dpad_1_up)
	{
		case  1: dpad_1=0;break; // up
		case  5: dpad_1=1;break; // up right
		case  4: dpad_1=2;break; // right
		case 12: dpad_1=3;break; //down right
		case  8: dpad_1=4;break; // down
		case 10: dpad_1=5;break; // down left
		case  2: dpad_1=6;break; // left
		case  3: dpad_1=7;break; //up left
		default: dpad_1=8; //neutral
	}

Do you know why dpads have their own section in the report definition instead of just being treated like other buttons?

=============================

Using Switches instead of LEDs

I’m not here to put on a show and neither are you, so let’s get down to business and do REAL WORK FOR COOL PEOPLE AND INDIVIDUALS WITH THINGS TO DOTM. What I mean is that LEDs aren’t the application that I’m doing all this for, in fact I need buttons, so I need to modify the existing design to support that.

If you scroll down to the bottom of this page that I linked before, you can see they have some advice for using switches in a Charlieplexed configuration.



The article says to replace the LEDs with a combination of a switch and a diode in series. The switch bridges the connection between the two pins but, since it doesn’t have the polarity that the LED has, we need to re-add that in using a separate diode. Also note, if you can spare the expense, schottky diodes are preferred because they don’t eat up your voltage differential as much and have a faster switching speed than a regular diode.

I decided to ignore the article’s advice to use a different pin config scheme to figure out which switch has caused the input to be pulled low. It was simply easier for me to just use the old code with the LEDs since that worked perfectly fine with some minor modifications. I don’t think it’s as efficient as the method mentioned in the article, but I don’t have to go back and optimize this until it becomes a problem.

Software changes for supporting buttons

I kept a separate sketch called “3pin-switches” with the changes:
https://github.com/CoryParsnipson/charlieplexing/blob/83b530d6897d134ddfffb98193c8b465bf7f5082/3pin-switches/3pin-switches.ino
code:
void loop() {
  bool anything_pressed = false;
  
  for (int i = 0; i < NUM_BUTTONS; ++i) {
    check_button_state(i);

    anything_pressed |= IS_PRESSED[i];
    //...
}

void check_button_state(int idx) {
  reset();

  pinMode(BUTTON_MAP[idx][0], INPUT_PULLUP);
  pinMode(BUTTON_MAP[idx][1], OUTPUT);
  
  digitalWrite(BUTTON_MAP[idx][1], LOW);

  int val = digitalRead(BUTTON_MAP[idx][0]);
  IS_PRESSED[idx] = !val;
}

void reset() {
  pinMode(CPIN0, INPUT);
  pinMode(CPIN1, INPUT);
  pinMode(CPIN2, INPUT);

  digitalWrite(CPIN0, LOW);
  digitalWrite(CPIN1, LOW);
  digitalWrite(CPIN2, LOW);
}
If you ignore the state arrays for keeping track of pressed states and all the serial monitor printing stuff (not shown in the snippet above), everything is basically the same. The important changes are in check_button_state(), which is what used to be called drive_pin(). Instead of setting the high line to output like with the LEDs, I set it to INPUT_PULLUP to get a resistor between the voltage source and the low pin*.




https://i.imgur.com/loW6Ldh.mp4

* So after I wrote this, I decided to take out the (blue) resistors in front of the GPIO pins. Should be fine if I stick with INPUT_PULLUP. So either using no resistor and INPUT_PULLUP works or using the resistor and writing the output to high.

ADVANCED Charlieplexing



We got buttons now, we got a little light that shines when I press’em, we got a serial monitor. Now it’s time to move up to 5 pins so we can put 20 buttons on this thing.

This site has some diagrams ranging from 2 pins to 6 pins. Looking at the 3 pin layout again:



There’s a pattern here. Basically, we wire all the LEDs up to each 2-tuple combination of pins. They start logically with 1 step between pins (i.e. connect Pin 1 and 2, and then connect Pin 2 and 3), and then cover all the 2 steps (pin 1 and 3). And with that we’re done because 3 pins is simple. There’s only 3 ways to choose 2 from 3. (And then we double up on directions so we get 6 permutations that we can fit LEDs into.)

The 4 pin layout is basically two 3 pin layouts on top of each other:


NOTE: in the website I linked earlier I think they made a mistake in the 4 pin diagram. I got rid of the extra connection so everything is easier to understand.

This follows the same pattern as before. They make connections between 2 consecutive pins first, and then pins 2 steps away from each other, and then 3 steps away.

The exact same thing happens with the 5 pin layout:



I think this should make sense because when we iterate through all the LEDs, we just isolate a single pair of pins that can drive a specific LED. So naturally, we want to figure out all the unique 2-pin combinations that lets us stuff an LED into it (and double up on each position using diodes).

A lot of people have figured out that you can figure out wiring diagrams for an arbitrary number of pins if you organize the circuit into a matrix:


https://stkwans.blogspot.com/2012/05/designing-large-charlieplex.html

This circuit is equivalent to the ones above it, but may be easier to conceptualize for arbitrary numbers of pins. If it helps, this looks like a table you would make if you wanted to keep track of all the different kinds of pairs you can make from n numbers. It’s just two ways of describing the same thing (i.e. all combinations of 2 pins out of n pins).

Wiring Up the 5 pin switch version

Here goes:


This is gonna take a lot of wires.



More wires





MORE WIRES



I also took out the blue resistors after the fact, like I did for the 3 pin circuit. I only have 10 buttons wired up here, but there’s still room for 10 more buttons. And more wires...

The code for this 5 pin setup is almost identical to the 3 pin sketch, but I lumped some thumbstick code into this one too. I haven’t properly integrated the thumbstick yet, but will write about that soon.

https://github.com/CoryParsnipson/charlieplexing/blob/83b530d6897d134ddfffb98193c8b465bf7f5082/5pin-switches/5pin-switches.ino

Once this code is uploaded and debugged, viewing the controller status in the Windows control panel shows that it’s working just as it did before. So mission accomplished, I guess. For now.

Cory Parsnipson fucked around with this message at 02:56 on Jan 6, 2021

Cory Parsnipson
Nov 15, 2015
Investigating Controller Buttons

Ok, so now the wiring and input code situation is good for now, I need to figure out how to get “real” buttons and fit them into some sort of casing. I’ve been scrounging around trying to figure out what parts I need for the past few months and it’s been quite… difficult. It’s hard to search for these parts because they have generic names and the parts are specific to the 3ds making everything super overpriced.

I opened up my new 3DS to get a look at how the buttons work. As you can see, there is an elaborate stack of parts to get the specific look and feel of the buttons.



As far as the face buttons go, they are identical on the Nintendo Switch joycons. That’s a good sign. If something ain’t broke, don’t fix it. You can bet that this button design works really well. You can see that there’s this huge white shape with metal circles on it in the middle and on the opposite cover, you can see a grey rubbery-silicon cover. On the other side of the silicon cover in this picture are the recognizable ABXY face buttons you physically touch on the 3DS.


Like this (new 3DS XL)


Or this (new 3DS). I like these buttons better but, like the non-XL new 3DS itself, getting these increasingly rare parts are a bitch and a half. These buttons are at least twice as expensive as the less pretty 3DS XL buttons on top of being harder to search for. It may be worth 3D printing my own or learning to cast resin buttons later on...

Underneath the white shape with metal circles are the conductive PCB traces that form the switch element:


This is from http://smilecitrus.info/?p=2929 because I don’t want to peel the membrane back on my own 3DS, since it’s a sticker.

The metal circles are conductive and connect these two copper circle shaped traces together when the button is pressed down. The metal circle layer is called a metal dome switch membrane and the metal circles are called metal dome switches or snap dome switches. These things are what gives the buttons a nice meaty “click” when you press them. I thought that was surprising because they give such a loud sound for something that’s as thin as paper. They work similarly to when you have a weird kink in your soda can and it makes a snapping noise and pops back when you put your finger just in the right place. And the grey silicon membrane gives the buttons a springy, squishy feeling to the buttons.

These buttons are basically a Twix bar. The face buttons are the hard candy coating to the silicon membrane and snap dome switches’ gooey, crunchy interior.

One of the things I always wondered was why so many “gimmicky” game consoles or electronics projects used tactile switches instead of something nice like what you’d see in consumer electronics. I mean obviously the consumer electronics buttons are more expensive, but now I know to what order of magnitude it is. Also, having “real” buttons also depends on having a perfectly fitted casing to hold everything in place and that’s a whole can of worms by itself.


Whelp, PyBadge, I completely underestimated you.

Finding Button Parts

Anyway, I was able to buy most of these parts off AliExpress after a few days of searching (per part...).
  • Metal dome switch membrane: check.
  • “Conductive” silicon rubber pads for 3ds: check
  • 3DS XL button set: check
  • Switch Joycon trigger set: check

The 3ds buttons actually includes 3ds style shoulder and triggers, but I bought a set of joycon trigger buttons too. I haven’t decided which one I want to use, and also I need more parts to complete that set too. (Springs, micro switches, and maybe some special pcb or flex cables) I’ll need to deal with that whole thing later. Right now, let’s concentrate on the face buttons.

Small Aside about Metal Dome Switches

While the 3DS buttons, triggers, and silicon membrane are custom shaped for Nintendo products, the metal dome switch membrane can be switched out for a homemade version with relative ease. Metal dome switches are a whole standard type of electronics part and used in a lot of things. (If you’ve used a rubber button pad on something like an ATM or garage door opener, then that was probably using metal dome switches. Anything in a small form factor that makes a clicking noise also probably uses metal dome switches). More on this here.

There’s this great page about different shapes and types of metal dome switches here. Along with a really detailed page about dimples and shapes for circular metal domes specifically (which is what the 3DS and Switch use). I think the dimples influence how the switch feels and its lifespan, but I don’t know for sure. It’s kind of unnecessary detail at this point, especially since we can see that the circular switch with no dimples is exactly what Nintendo uses, but good to know nonetheless.

Lastly, there’s this thing you need to do with dome switches called “venting”. Since they’re covered by an airtight sticker and you press down, the air underneath the domes may interfere with the switching mechanic. So a solution to this is to add vents in the form of holes underneath the switches on the PCB itself. Saving this here for later… I gotta remember to do this when I’m making the PCB.

But wait there’s more! Let’s look at the 3DS again:



There’s two more golden metal dome switches on top for the start and select buttons. The rest of the face use this type of switch too. The start, select, (along with the + and - buttons on the joycons) and the home button use the same setup. Now how to find those parts...

Search for nintendo 3ds switches turned up nothing relevant. But then, just by chance...


How I accidentally stumbled upon “metal dome” switches

BINGO. Digikey was a pro-click. Obviously this isn’t the same as the switch in the photo, but I managed to find it the “customers also bought” section of site:

https://www.digikey.com/short/4cfd0w

This is close enough for me, if not the exact part used in the 3DS and used for all the buttons in the joycon as well (SR, SL, plus minus).

Cory Parsnipson fucked around with this message at 22:34 on Jan 7, 2021

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Good on you for making it this far.

The reason the d-pads are their own part of the report instead of extra buttons is: I wanted a pair of d-pads so I could just tell my app to "use this axis" and not have to map four buttons to 8+1 directions.

This device had four analog axes, two d-pads, a 3-position selector, a couple of rockers, and six individual buttons, one of which was a two-stage. The USB spec handles all of these nicely, so they got their own breakouts in the report.

If you say "this group of inputs is a D-pad" in the USB descriptor, then Windows Just Knows and it works; you don't have to worry at all about whether or not your software can do what you need it to do based on discrete buttons.

I'll dig it out of the closet and plug it in and see what the windows "joystick button input" screen looks like, maybe.

Um, thanks!

Makes a ton of sense on the d-pad thing. When the controller hardware is figured out I need to remember to add the directional buttons into the d-pad section of the report instead of lumped together with the face buttons like they are right now.

Btw, that sounds like an intense joystick lol. Was it for a dogfighting game or flight sim?

========================

WAIT JUST A MINUTE

I found all the parts and ordered them and that just SOUNDS TOO EASY AND WE CAN’T HAVE THAT. It took literally a month and a half to ship in from China. So I guess protip for those of you trying to do this at home, be aware that shipping from AliExpress can take a while.



They all arrived a couple weeks back and waiting for it all to come in was absolute torture…

Rewind to 2 Months ago...

While I was waiting for those parts to come in, I had plenty of time to do some limited tests on my own. I don’t want to deal just yet with 3d printing or creating PCB layouts in Phase 1, because I don’t even have a good idea of what I need to make. So I bought a conductive ink pen off Amazon to try and make an ad-hoc circuit for some quick prototyping.

How to make a circuit board: a guide for crazy homeless people and small children



Using my multimeter, I tried to test the continuity of the (silver) line I just put down on a piece of corrugated cardboard. Turns out, this doesn’t work very well. The cardboard surface is too porous and prone to abrasion to hold the conductive ink very well.

The next step was to try taping down a piece of paper on the surface.



This passes the continuity test at least. One thing I noticed was that the ink wasn’t very reliable. I had to make a really thick (~2mm) line especially around hard turns and really slather it on to make it conduct. I also think it’s better to draw the circuit on a hard surface, like on a table rather than taping it on the paper to the cardboard and then drawing the circuit. Mainly this is just my personal preference to make sure I don’t dig too hard into the cardboard with the pen.



So next, I tried to mimic the PCB trace. This is an example of what you would do for a single layer PCB switch. You have the two wires on either side of the switch meeting in the center, but not touching. Together they form a circle and when the metal dome switch goes over it and it’s pressed down, the circuit is completed. In this picture is also a small slip of paper with a circle of conductive ink drawn on it in the middle. This was me trying to see if I could make a temporary metal dome switch substitute.



This pic might make it more clear. If I fold the slip in such a way so that the middle dot is suspended, I can flip it over and tape it on top of the mock PCB trace. When I press it down, the two ink drawings should touch and bridge the two sides.




https://i.imgur.com/h8xWHnC.mp4

It worked, but not very well. The paper is too flimsy and sags in the middle. This makes the connection very unreliable and prevents you from pressing it very fast. Also, it doesn’t make a satisfying click like the real thing. At the very least, it shows the basic principle works and that’s good enough for me.

At this point I checked the calendar hoping that this whole experiment managed to kill a whole bunch of time. 15 minutes had passed. Drat.

Next, I tried to rig up a homemade metal dome switch using a coke can:




https://i.imgur.com/9RrKhXF.mp4
Click for sound

This didn’t work well at all. As you can see with the LED in the above video, it’s flickering and doesn’t really correlate to my finger presses. The shape I need to be able to make also is too complicated for me to do by hand. I used some pliers to make two straight folds in the aluminum can (so that it looked like the piece of paper before), but that isn’t good enough to make it spring back into shape when you lift your finger off of it. You really need an arc or a circular fold like in the actual metal dome switches. And the metal material needs to have enough memory to spring back into its original shape after being pressed. It *does* actually make a slight clicking noise as you can hear in the full video clip, but I think that’s from the tape. The metal wasn’t the right shape at all.

Whelp, time to spend some time outside and come back later.

In retrospect, I think copper tape would have been easier to work with than conductive ink. The ink isn’t very reliable and requires you to lay it on thick. If need be, you can cut the tape into different shapes and it comes by the yard. I might pick up a roll if I am having a lot of trouble with just the ink.

You can get copper tape pretty cheap off SparkFun or Amazon. I also found they sell this at Michael’s, but the reviews are really bad. I don’t think the tape they were selling was for electronics. The key is that the tape needs to be treated with “conductive adhesive”. The tape over at Hobby Lobby looks like the right stuff, but is three times more expensive than SparkFun and Amazon.

Fast forward to last night (with your mom EEEYYY)

It is time to try out the switch membrane.



I busted out one of the five sets I bought and stuck it to my paper covered cardboard “testing fixture”.


https://i.imgur.com/KkuQUDC.mp4
Click for sound

It’s perfect. It makes a snap that seems to resonate through the cardboard. Then I added the silicon pad and checked to see if it still clicked. Nice and squishy.



https://i.imgur.com/aY2tnH8.mp4
Click for sound

Once more with the buttons on top. If you ignore the fact that everything slides around really easily, it feels pretty close to the actual 3DS.



https://i.imgur.com/HhZ6COz.mp4
Click for sound

Sometimes the button doesn’t click and it turns out that everything was slightly misaligned (what I mean is that this doesn’t seem to be any sort of defect aside from not having everything lined up nice and tight).

Testing out the button contraption with ink wires

Ok, now time to put all the pieces on top of some ink wires I laid down and watch the entire switch work as planned!

...NOT!

When I placed the membrane sticker down on my “test fixture” and tried pressing it down, one of two things happened. Either it didn’t conduct at all, no matter how I pressed it, or it was constantly conducting, as if the metal dome switch was shorting the two contacts together.

This might be a big problem. I thought I could lay the button parts down on a piece of cardboard with a circuit drawn out and everything would work well enough for me to make a prototype. Trying this out on something more solid like a protoboard also did not work for some reason. I’m worried that I might have to create an actual PCB to test this out. If that’s the case, then this will take a long time for me to learn and can get expensive…

Cory Parsnipson
Nov 15, 2015
To me, 6 months from now

DISCLAIMER: The following events are completely true. I swear. I poo poo you not.

I sat up in bed, brushing aside a mountain of empty beer cans and I scratched at my incorrigible stubble. With dark, heavy bags under my eyes, I squinted at my clock. 4 PM. drat. I hadn’t worked on the Raspberry Pi in six months. I couldn’t. The memories were too painful.

“What am I even doing”, I said to myself. “The buttons, they won’t conduct. This is impossible. I will never be able to play old video games in bed. How stupid of me”

A single tear rolled down my cheek. I was young--so young--and cocky. I thought I could have it all, but instead I had flown too close to the sun and now I was paying dearly for it.

“Yo, duuuuude, get a hold of yourself”

I tensed up, startled at the sudden voice in my room and looked around to find the source. It sounded like… Steve-O???

He was leaning on my door frame. “Uh, Steve-O, what are you doing here? Also I’m naked”, I said.

“Yeah, maaaaan, I was walking Walter when I got lost and accidentally broke into your house. I noticed that you seemed to be having a hard time. I just wanted to say I’ve been there, brooooo. The whole last year before I got sober, I really became a nasty, mean-spirited guy. I think I felt so bad about myself that I took it out on everybody else. I put together this mass e-mail list with the most influential people in my life, and I would blast everyone all these ridiculous e-mails, thinking that it was all, like, really cool at the time...Like, I would describe hallucinations I was having. Or I would talk about jacking off. That was the old me, but now I’m different and I’ve been working hard to improve myself. My main focus in sobriety has been to replace fear with faith or love. I think we could all use some re-examination every so often. Like, for example, have you thought of re-examining your current approach to drawing PCB traces?”

I took a minute to digest what he said, and then I looked at my desk, at the mess of parts and unfinished business. And suddenly, it hit me!

“Wow, Steve-O, you’re right I just had an idea--”

I looked back at the door and it was empty. He was gone.

Man, that was weird.

Button wiring, take 2

Cory Parsnipson posted:

When I placed the membrane sticker down on my “test fixture” and tried pressing it down, one of two things happened. Either it didn’t conduct at all, no matter how I pressed it, or it was constantly conducting, as if the metal dome switch was shorting the two contacts together.

I think what is happening here is that the “bezel” of the round, no-dimple, metal-dome switch contacts the paper and is shorting both wires. I think I need to change the PCB trace to the design I saw in the 3DS. Let’s take a look at the contacts again. It’s not the single layer design I described before. In fact, it just looks like a circle inside a ring. This PCB appears to have at least two layers to route both sides of the switch over/under each other.

Thanks, Steve-O! :thumbsup:



So you have the outer ring that is always connected to the bezel of the metal dome switch and then when you press it down, the middle circle touches the center of the switch and then both leads are shorted together. I probably need to do something similar in my prototype. This is gonna require some careful preparation to make a 2 layer paper circuit.

Making the upper layer contact

Let’s start with the outer ring PCB trace. Get a ruler and make a cross on a piece of white printer paper. Where the two lines cross, is the center of our circle.



Next, get some trusty calipers and measure right in the center of the outer bezel. We want to make a circle that’s about this big.



Now take those calipers and try to get it centered over each line and make two marks where the caliper tines are. We are trying to mark the diameter of the circle here.





Next take a pen and free hand the circle. Do this one quarter at a time.





It’s time to take the conductive ink pen and trace over the circle we just made. Don’t forget to use the multimeter to test for continuity. Make sure it’s thick enough.



Pick an axis and draw out a line. This will eventually become one end that will connect to a wire in our breadboard.



Get a hobby knife (always have a hobby knife) and cut out the whole thing. I cut through the protruding line in an attempt to make it easier to bridge the connection to a second piece of paper.





Use the knife to cut a hole through the center of this piece. While I was doing this, I realized that it might have been much, much easier to do this before the previous step...

Making the lower layer contact

Make another cross using the ruler. This time it goes directly on whatever you’re using as a PCB surface (here it’s my cardboard “test fixture”).



Make another circle using the same technique used in the upper layer contact. This time, we want the diameter of the circle to be slightly smaller than the diameter of the flat part of the metal dome switch.



Fill in the circle with conductive ink and draw a wire coming out of one side. Again, remember to test for continuity.



Now the bottom portion is ready.

Putting it all together

Ok, so take the top piece and tape that b down on the bottom piece. Make sure the hole of the top piece lines up with the big circle on the bottom piece.





The top piece’s protruding lead should be facing away from the bottom piece’s lead. Use the ink pen to continue the line onto the cardboard surface. Trace over the contact and continue onto the backing cardboard and try to get it on the edge and a little on the underside of the paper. If you put a piece of clear tape over that part to hold it down, it will keep everything pressed together and, amazingly, that should be enough to achieve continuity.

”IMPORTANT NOTE” posted:

It’s hard to see in pictures, but I needed an additional step to get this to work. I only found this out after assembling everything, testing it, then taking it apart and trying some stuff.

The bottom contact circle is too sunken to properly conduct the metal dome switch. It appears that even the thickness of a 8x11.5 piece of paper is enough to throw things off. To fix this, I had to take the circle I cut out of the top, slather it in conductive ink and stick it back into the hole. (Is that clear…?) This way, both the outer ring and the inner circle are now at the same height. Getting the middle part to be conductive on both sides was tricky. I needed to cover both sides in ink and then make sure to draw on the edge of the paper as well.

I wasn’t sure that would work, but it did!

For the next iteration, I think instead of cutting out a hole in the top layer, I’d cut an “x” shape into the middle and then slather that part with ink, being careful to keep it separate from the outer ring. This would, ironically (or not??), make it resemble the copper traces in the actual 3DS.

Integration into the Arduino controller

Tape down the wires to the ink leads. It works, trust me!





https://i.imgur.com/XMrsrqL.mp4
Click for sound

We’re getting close now. This is great news, I honestly didn’t think this would work. The button is perfectly clicky and the responsiveness is almost as fast as the real thing. I’d say, maybe it’s like 95% of the way there. It’s not perfect, sometimes I can see the LED flickering, meaning that the traces aren’t conducting perfectly. Good enough for the cardboard prototype. A real PCB should not have this problem.


https://i.imgur.com/cJf4JR6.mp4
Click for sound

Just to make sure, I put the silicon and plastic button shell on it and tried it out. Still works and even shows up as being pressed in the Windows utility.

The cardboard prototype concept is still alive, baby! LET’S GOOOOOOOOOO!!

Cory Parsnipson
Nov 15, 2015
Yeah, I hope to have this quirky artifact that's made entirely of cardboard, paper, glue, and ink like some kind of freakish elementary school project. Obviously after that I need to figure out how to convert it into a "real" thing with actual PCBs and a plastic casing, but that could take months, so I'd rather do more experimenting up front to speed up the back and forth later on.

I didn't go out of my way to debounce anything. I'm doing a tiny bit incidentally as part of the charlieplexing scheme. In the Charlieplexing sketch I use a 1 millisecond delay between button polling. So between reads of the same button, it takes 1 millisecond times the (number of buttons + 1 for the thumbstick), which is about 10-11 milliseconds. Currently seems to be working pretty well, since I don't notice any glaring issues so far.

I am pretty particular about input and I think mismatching button presses or ignoring user input is one of the cardinal sins of game programming (I'm looking at you GENSHIN IMPACT :argh:). Sometimes I swear that I've been on the bad end of a button press a handful of times on the PS4 too. I went back to read Part 1 of the article you linked and it's really interesting. The fact that there's a "once and for all" solution for this is really tempting to spend the extra effort to get it implemented.

The schmitt trigger chip appears to be available in a package that supports up to 6 inputs, which means I'd only need one. I agree with the dude's recommendation to solve a hardware problem with a hardware solution. It speaks to me as a software dev too. I feel like you should be careful to solve a problem using the right level of abstraction rather than applying a bunch of band-aids like one would do at, say, a job... I would also need to make sure this doesn't cause any complications when combined with the charlieplexing setup.

The software solution doesn't require extra parts, or changes to the existing plan, but I'm not sure I agree that it's the "ultimate debouncer". Doesn't seem as bulletproof and simple as using a schmitt trigger. You still need to make assumptions for maximum bounce duration and that makes it feel like not a "once and for all" solution. His description resembles a heuristic branch predictor or some kind of ghetto machine learning model and ain't nobody got time for dat.

I am still undecided on whether I should go with the hardware or software solution, but leaning towards hardware. I need to think about it a little more.

:thunk:

e. Schmitt trigger should be fine. Probably gonna go with that.

Cory Parsnipson fucked around with this message at 02:03 on Jan 16, 2021

Cory Parsnipson
Nov 15, 2015
I need to run some more experiments to check if I can put everything else on a paper circuit. Aside from the face buttons, there’s:
  • Thumbsticks
  • Start and Select (and other misc buttons)
  • Shoulder and trigger buttons
Thumbsticks??? Didn’t I already do that? Yes, but I need to fit it into the charlieplexing scheme which turned out to be trickier than I thought.

The trigger buttons will be tricky because they rely on the shape of the game console casing to operate. I took some pictures of how the joy con triggers work, so it might be more apparent what I mean when I take a look at those. Using 3DS triggers looks easier so I might do that for now. I think I’ll have to 3D-print my own because I don’t really like the Nintendo Switch triggers either.

Hooking up the thumbstick to the charlieplexed circuit

Most of the wires coming out of the thumbstick remain the same. Vcc, ground, and the two analog signals go directly to the arduino pins. There is one wire for when the user presses down on the thumbstick and it clicks down. (This would be L3 or R3 on a PlayStation) This wire needs to be kept at 5V when the thumbstick is not pressed down and then when it is, the thumbstick wire is shorted to ground and goes to 0V.

I asked in the Learning Electronics thread about a week ago, what the best way to do this would be. It’s more complicated because, unlike the other buttons on the controller where I have access to both sides of the switch, the thumbstick only gives me a wire (one side of the switch) that uses active low logic.



Here’s a diagram of what I’m talking about. Normally for the push button switches I photographed before, they physically bridge the vertical wires coming out of the “?” space when pressed down. But here, the thumbstick button is a single wire represented by the horizontal wire coming into the “?” space on the right.

This seems like the perfect candidate to use a MOSFET transistor as a switch. The only problem is that I don’t remember pretty much everything about transistors.


I put the source and drain labels in the wrong spots. They’re flipped around. Why didn’t I just fix this before posting? Uhhhh because I don’t feel like it. So there.

babyeatingpsychopath posted:

I was implying that a FET as a switch behaves differently forward-biased as opposed to reverse-biased. I thing that's a good thing, though. It may be possible to connect the two thumb sticks on the same antiparallel circuit leg and use their body diodes to your advantage.

Does the thumb stick have a pullup on it? Is it just closed-to-ground when pressed? It may make a difference on how to get the FETs to work.

This is a great idea though. After doing some freshening up on the subject, looks like the diagram is mostly correct (drain and source are in the wrong spots though). I found a leaflet about selecting transistors which was really helpful.

I ended up choosing this one off digi-key.

As per the leaflet, there are only a few important characteristics we need to pay attention to. It is important to make sure that we are within the max power dissipation value (pretty much guaranteed for me since we’re working with milliAmps here), and that we are going to drive the transistor with the proper voltage levels. The gate to source voltage (Vgs) and max gate to source voltage are important to note. The transistor I picked off digikey has a Vgs of 2 volts which is well within the 5V and 0V levels we will send it. Vgs max is 20 volts so we have a lot of leeway here. Also important are “continuous current drain” if you are worrying about how much power the transistor will consume, and “drive voltage” which is the manufacturer’s number intended to let you know what voltages you are supposed to supply to the transistor.

Vgs max is also important to us because of our charlieplexing situation. This value also determines the maximum voltage we can have if we drive the transistor in reverse bias (that is 5V in our case). babyeatingpsychopath mentions using two transistors in an “antiparallel circuit leg”. I think this is a nice touch. What I think they mean is we can avoid driving the transistors in reverse bias if we have two in parallel (but facing in opposite directions, like the diodes from before). Because one transistor in forward bias should have much less resistance than the one in the reverse bias, so all the current will go towards the less resistive one and we really won’t have to worry about reverse drive conditions.

I only have 1 thumbstick hooked up so right now I am driving it in reverse. This isn’t as good as described in the previous paragraph, but it will still work, since we’re in its operating range. Another value you should be aware of is “reverse recovery time”. The transistor I bought has a reverse recovery time of 400ns. That’s not super fast, but is within the minimum interval of my charlieplexing code (but not by much).



I dropped the transistor in, and it looks like it’s working. Hopefully nothing will burn out.


https://i.imgur.com/Smt9ZmC.mp4
Click for sound

Shoutout to babyeatingpsychopath, ante, Slanderer, and Cojawfee for the help!

Getting the Start and Select Buttons working

I got the small snap dome switches in and boy are they small af.



This is a surface mount part and it is also a huge pain in the rear end to handle.



As you can see, there are 4 pins on the back. They work the same way as the push button switches do. Two contacts on each side are always connected and then all four are connected when you press the switch down. This must be a standard thing.



Well, let’s try to see if this works with the conductive ink. I measured out the size of the part and then drew down some big contacts in all four corners. I had to take some tweezers and pull down the pins a little bit so they stick out beneath the switch and contact the paper. I’ll have to chalk this part up as a sacrifice to the R&D gods.



I was considering using hot glue to hold the switch in place, but it might be tricky. This part is seriously small. For this test, I used clear tape to hold it down. This covers the top, though, so I think it might be making the switch harder to press down.



The membrane goes over the top. It’s going to be tough to perfectly center this. (If it’s not perfectly centered, it doesn’t work). It feels really stiff unlike the button on my 3DS. I’m not sure if it’s because this part has an operating force of 160gf and the 3DS just has a lower operating force or maybe the tape is messing with it.


https://i.imgur.com/tMy40bL.mp4
Click for sound

One question that’s nagging me right now is, if they use encapsulated switches like this for the Start and Select buttons, why didn’t they do this for the ABXY buttons??? It seems cleaner and would have saved me from trying to MacGuyver together the bottom of the switching mechanism out of ink and paper. Very weird.

By the way...

I’m fully caught up to my progress at this point.

Up until now, I was able to look back on the work I did after the fact and organize everything into a logical progression with a relatively coherent narrative. But the real adventure starts here. This is the wild west, baby. Anything could happen. Maybe I could even die! I really hope not. I would be very annoyed if I died.

Cory Parsnipson
Nov 15, 2015
The shoulder and trigger buttons are really elaborate and hard to duplicate using preschool supplies. I guess that’s pretty obvious, but that’s not really good news for me.

3DS Shoulder buttons

Unlike “full-size” game consoles, the 3DS doesn’t have “trigger” buttons, only bumpers/shoulder buttons. It has four in a single row, instead of two vertical columns. This is weird, but I think it works surprisingly well in my experience. There’s only a few games that use all four of these buttons and even fewer games that have an FPS style control on the 3DS. I had a lot of fun playing Resident Evil Revelations and the controls on that game were never a problem.


They’re called something nuts like “R, ZR, L, ZL” but I can’t be bothered to remember which is which. I like calling them R1, R2 and L1, L2

Despite this, if easily doable I think I’d prefer the normal way of having two triggers underneath the two bumpers because it’s easier to use when your hands are in a bunch of different positions. Not exactly sure why, but I think it’s because it feels like you need to put your hands in a very specific position to use the 4 shoulder buttons and that can get tiring after a while. This is in contrast to the usual layout that gives you multiple options for grip and allows you to use two fingers to operate the trigger/bumpers if you wanted.

I took apart my 3DS.


Take off the faceplate and battery


Undo the screws


Open the cover. Notice that the shoulder buttons are stuck to the bottom plate (top of the picture).


Finally, the good stuff

Opening up my 3DS shows that the shoulder buttons are pretty simple, but the only twist is that it uses a surface mount tactile switch on a flexible printed cable going to the 3DS motherboard. That and it uses some plastic jig to keep everything in place. I’d rather just mount the switch directly onto my PCB if possible, but if not, making an FPC just for this is probably not financially sensible for me. (It’s gonna be good ole’ loose wires for me. What is this, the nineties???)

The outer, bigger shoulder buttons have two cylindrical tines stick out of it. The rightmost one holds a spring in place so the button bounces back and the leftmost one is used to poke at the tactile switch. The only catch is that the button is held in place with a cylindrical hinge. That’s going to be hard to fasten to cardboard. Not sure if that’s doable.

The inner switch is really simple. The plastic button touches the tactile switch directly and is held in place by the casing. I’m not sure what the silicon membrane is there for. I’m going to try and leave it out and see what happens. There’s no springs or hinges or anything fancy.

Nintendo JoyCon Shoulder/Trigger buttons

I took apart one of the used joy cons I bought:



These things are stuffed to the gills with sensors. It’s nuts. I’m surprised that they aren’t actually more expensive than they already are.

Turns out there is a plastic divider in the middle where the trigger rests on. The other layer holds the shoulder button in place.


Shoulder button is missing in this picture






The shoulder button uses a spring and is similar to the 3DS shoulder button except that the shape is different. This also uses a cylindrical hinge to fasten it to the outer casing.

Ok, now here’s the real doozy. The trigger buttons are really complex. I don’t know a thing about 3D printers yet, but I’m also concerned that even with one, it might be hard to replicate this mechanism. I hope I’m wrong, though.


Here’s the top layer with the trigger removed

The Joy Con trigger needs two springs. It also has two cup shaped fingers that stick out and snap onto the corresponding protrusions on the case, like some kind of plastic transformers toy. This looks like a huge pain in the rear end. I feel like this is approaching plastic model kit territory.



What’s also interesting is that when you press the trigger in with your finger, the hinge it’s on transforms the horizontal motion into vertical motion in order to press the button.

I bought some third party springs

I tried to buy some similar parts in the off chance I would find them useful. So I have these without having to wait for shipping.

I have no idea how to source parts that aren’t electronic components. I got nothing to go off of with the springs. I had to eyeball the height, diameter, and coil thickness for the joy con springs. (And I think the 3DS and joycons use the same springs). The closest I could find off digikey were these compression springs from Century Spring Corp. They’re almost twice as long as I need, but that’s fine. I can just cut them to size before I use them.



Putting them side by side, I can see that the springs I bought (pictured, right) were thinner than the official ones (left) and take less force to compress them. I cut one of them in half and tried to replace the official springs with my counterfeit and they are good enough to do the job. Honestly can’t tell the difference, but it’s not like I left it in there and played at least a couple hours of games with both.




As a note to myself, I think I’d also want to buy springs that are stiffer (than even the official ones) to make the triggers feel tighter. That seems to be my personal preference.

Also, I bought these random switches to see if I could use them. They’re not at all like the official switches and just to be sure, I bought a batch of those too. I’m not expecting them until near the end of February though and they’re surface mount, so I probably won’t use them.

Conclusion: probably need to come back to this later

Seeing how everything works is pretty self explanatory, but weirdly enough, I suspect that you could get away with doing something really simple and being 95% of the way there. I’m not really sure how I’m going to pull this off for the cardboard prototype, so maybe I’ll just put down some tactile push buttons and come back to this when I have a 3D printer.

Actually hmmm… Maybe with a small wooden dowel and the right size drill bits, I could make something that might work.

:thunk:

I think next I’m going to try to start putting everything in cardboard housing and bounce back and forth between that and controller stuff as I figure out how I’m going to do the shoulder buttons.

Cory Parsnipson
Nov 15, 2015

https://i.imgur.com/XtpZ70R.mp4

Cory Parsnipson
Nov 15, 2015

csammis posted:

https://www.mcmaster.com/ - 16,591 results for "springs," time to go hog wild :v:

:eyepop:

Cory Parsnipson
Nov 15, 2015
These past few months, I’ve been hoarding cardboard boxes of various sizes and thickness for this very situation.



It’s about time that I get to use it because I’m getting really tired of having to wade through all this cardboard to get to my bed.

VISUALIZATION

The current theme of the week is VISUALIZING. I must VISUALIZE having a bitchin’ video game system. There is a perfectly good case sitting in that mountain of cardboard and it’s my job to remove all the unnecessary pieces.



I’ve measured out the size of the 5” LCD screen and then made the top and bottom boundaries 5 mm offset from it. Then I cut out paper versions of the front facing buttons (carefully measured to be 1:1 in size) and then taped them down to around where I’d like them to be. I used both the 3DS and joy cons for reference.

I wanna point out here that I decided to move the Start and Select buttons from the bottom of the right side to be split along the top of the console, just like in the joy cons. It feels way better to use them like that. This will displace the speakers but in any case I have to install them on the bottom of the console for now because the circuit I have is really big and it won’t fit anywhere else. This will change in Phase 2.



We’re already deviating from my child’s drawing. Also this is a good time to ask. Asymmetric or symmetric thumbsticks? I’ve been favoring two thumbsticks on the top for a while, as you can see in both of my mockups. Weirdly enough, I’ve only seen 1 existing product that has symmetric thumbsticks and that one has them on the bottom of the device. I’d imagine that it’s uncomfortable to use them that low, no? Maybe they know something that I don’t. Oh well, I will know how it feels once I play for some time on this thing.

Size check

Just to give a sense of scale to this whole thing, here’s how it measures up to the existing items:




It’s just about the same height as the 3DS and around one-fifth longer. This is the “theoretical” minimum because of the screen, but I might have to make it taller when I get into the reality of actually putting things together. I’ve been having second thoughts about the 5” screen size, because I think this might make it too big for my taste.



Yep… you can buy them now...

It’s much smaller than a Switch. The Switch is the maximum size for a portable imo. Feels like I’m holding up an iPad. I checked online and it is also slightly smaller than a Switch Lite. That’s a good sign because I also think even the Switch Lite is still too big.

MORE VISUALIZING…





Here I’ve measured out the side boundaries. The length from the sides of the screen to the sides of the device are each 1.25 inches wide. The equivalent area of the bottom of the regular sized 2015 new 3DS is also 1.25 inches wide. I also cut out rounded corners to be a show off.

Note to self: I should pick a system. Gonna try and keep it metric from now on. (Well, we’ll see what happens when I get to using CAD software)

Looking at this and the cardboard mockup (later on in this post) makes me feel better about the size. One of the main questions I want to answer with this prototype is exactly what size do I want? This feels and looks good, but strictly speaking it’s not going to be comfortable in your pocket. What’s the best size for a portable? I also don’t want it to be as small as the 3DS, though, because the screen experience suffers for it.

The bottom line is that I’m trying to decide between keeping this size or going sliiiiightly (0.5” in width) smaller. I want to find a 4.5” LCD and experiment with what that would look like later on.

NOTE: a competent person would be doing all this using CAD but I don’t know how to do any of that and so I will save getting through the overhead of setting all that up for Phase 2. I just want to get to the designing part even if it feels like I’m a first year architecture student. It would be totally easier to do this on the computer and then print it out to get a feel for the size if I had everything ready to go.

Taking a first stab at things

I got excited and cut out what I can only describe as a “face plate” out of cardboard and tried to fit the screen into it.




I had to enlarge the hole to be 1 mm wider. I measured many times before and after trying to figure out where that millimeter went and the only explanation I have is that the screen itself bulges outwards slightly about 1/8th an inch down and when I cut into the cardboard, it deforms a bit and the fluff makes the hole smaller. Good enough though. The fit is so snug that I don’t need any adhesive to keep it stuck to the screen.

Also an important lesson here is that trying to treat cardboard like plastic is going to be bad news. I severely underestimated the structural capabilities of cardboard and leaving long 5 mm bezels on top and bottom has greatly compromised the firmness of it. I almost bent the faceplate badly out of shape by trying to hold it up the wrong way. It would be prudent to widen the prototype design at the expense of having a less “cool” result.

To be more precise, the 5mm sections are thinner than a single “segment” of corrugation. Those pieces are now susceptible to bending as if they were thin pieces of paper. Paying attention to the orientation of the corrugation when I’m cutting pieces would help. The thin segments would be stronger if I cut this piece 90 degrees from how I actually did it.

Figuring out component logistics





This is turning out to be a lot harder than I thought. The parts aren’t playing well with each other and they are going to make the whole thing really thick. Trying to move the parts around and see where they fit best and imagine what I need to make with cardboard at the same time is really tough. One of the big problems I’m looking at right now is the DSI cable running from the Raspberry Pi to the LCD screen (pictured above). It’s not really that flexible and doesn’t give me as much leeway to move things around as I thought. The orientation of the cable means I’m basically stuck with the Raspberry Pi in the middle of the whole thing and all the ports must come out the top. (Lol, I hope none of you super hate that the Nintendo Switch’s audio jack comes out the top. I definitely will put mine on the bottom. In Phase 2 that is. It’s here to stay on top for now. Sucks to suuuuck)

Not to mention that the RPI and the cable will force this thing to be at least 0.5 to 0.75 inches thick. That’s not even counting the arduino, stereo decoder, and speaker circuit that I have to stuff into this thing adding another 0.5 inches to the thickness. (Don’t worry, I might be able to overlap most of them with clever layout-ing)


This is gonna be one chonky boi

Keep in mind that most of this design stuff will not make it into Phase 2. Presumably at that point, I’ll have installed and learned how to use some sort of CAD program, learn how to do PCB design, and have a 3D printer so I won’t have to do all this weird stuff.

Cory Parsnipson
Nov 15, 2015
Backtracking slightly; trying a second approach

I sat there for a few days wondering what to do next after making the cardboard faceplate. I wasn’t sure if I liked being stuck with a single piece (in terms of viable construction options) so I decided to cut out joy con shaped pieces and then glue them together later to form the same shape as the faceplate. I’m going to put the original piece aside in case I need to use it later.


VISUALIZATION II: Visualize Harder

It’s hard to see here but sitting on top of the faceplate is a small joy con shaped piece of cardboard that I cut out separately. I forgot to take a picture of it by itself before I started mutilating it. Also in this pic is a thumbstick and dPad sitting there for VISUALIZATION purposes.



I cut out two of these, actually. Right away I got some guidelines on this puppy and then put down the dPad silicon membrane and traced out an outline. Then I used my hobby knife to cut it out of the left controller. The second piece on the bottom will have paper and conductive ink on it to serve as the bottom of the buttons. The paper will continue past the inner edge of this controller section behind the LCD screen and extend all the way into the Arduino controller circuit.





It fits! This almost looks like I’ve done this before. Again the fit is snug enough for it to hold the silicon membrane and button in place. It’s not actually that tight since the pieces aren’t heavy, but it is quite encouraging that the cut is so accurate. The buttons won’t be responsive if they’re not lined up properly. Every little bit helps.

I must reiterate that in Phase 2, when the circuit is etched into a PCB and I’ve 3D printed a custom made case, I can ensure accuracy the normal way, but right now we just have to get really spergy with a pen, ruler, and a knife.



Next I cut a hole for the thumbstick. This is basically a rectangle with some extra steps. For future reference, the thumbstick module box is 17mm x 19mm with the horizontal direction being the longer length.



Don’t forget to cut two little tabs for the screw holes to fit into. I’m not going to use screws right now, but this will be important to keep track of where the screw holes are for the 3d printed version of the case.





Here’s pics of both the thumbstick and dPad in their respective holes. Before I started cutting up any of this stuff, I did a bunch of thinking and carefully considered how I wanted to approach this part. For now, I think I’m just going to lay the cardboard horizontally and use the thickness of it to hold everything in places. These pieces of cardboard are 1/8th of an inch thick, which is a tiny smidgen thinner than the thumbstick base and much too thick for the dPad and the select button. I will need to compensate for the latter two using some padding on the bottom piece. I also want to lay down a 1/32nd or even 1/16th inch layer of cardboard over the top to serve as the outer layer. If I want the buttons to stick out past this layer properly, I need to do some tests to see how much padding I need to add to the bottom. More on that in the next post.

Next, it’s time to think about the thumbstick cable sticking out of the cardboard.


This is bad, I think.

The thumbstick cable sticks out of my cardboard joy con just enough to slot it into the FPC connector breakout board. Unfortunately, this sticks out behind the LCD right into the same space that the DSI cable is supposed to go and that dude just doesn’t wanna play nice with nobody. (This DSI cable is turning into a real rear end in a top hat.) I might need to come back and redo this section of the controller if I can’t figure out a fix. I think what I’m going to do is cut out a slot just for the thumbstick cable in the back piece and just bend it in a U-shape to get it out of the way of the DSI cable. Pics pending me trying this and it actually working. If it doesn’t work then… uh… just forget I ever said this.



Additionally, two 1/8th inch pieces of cardboard stacked on top of each other like this makes the controller flush to the LCD screen and I think I can use that to my advantage. It just makes it easier to think about if the cross section works out nicely like this. I can use a single, straight piece of cardboard as the backing for the controller ink circuit and Arduino section.

Enough about poo poo I haven’t done yet. We’re getting off topic.

Introduction to Principles of the Structural Integrity of Cardboard

Remember all that poo poo I said about working with cardboard in my last post? Yeah, I’m gonna have to ignore all that for now. I cut everything really close to the edge in the controller section and I need to fill it with more holes for the select button (and eventually a hole coming out of hte top side for the trigger/shoulders). The piece with the holes in it is incredibly weak and I’ve accidentally bent it a couple times. You can see in the previous picture how some parts near the dPad are sunken and bent a little.

I knew all this information and then I thought, “man this thing could use some more holes”.


This seems like a good idea that totally won’t fall apart in my hands, right?

I cut a third hole obnoxiously close to the edge

My last minute design change also means I need to take the silicon pad for the start and select buttons and cut it in half…








What the select pad looks like from the bottom.

Status check: more VISUALIZATION





So yeah, this is where we are right now.

Cory Parsnipson
Nov 15, 2015
Ah yeah I forgot about Cardboard Aided Design. I guess I am a CAD professional now.

Also, I wasn't familiar with Project Binky, but I took a look and :stare:

They're prototyping car parts out of cardboard??? That's nuts, they have movable parts and somewhat load bearing areas on it. I'll take the compliment, but I don't think this comes close to what those guys are doing, haha.

e. this is useful to know. I think I will copy their technique and have a brew before my next cardboard sesh

Cory Parsnipson
Nov 15, 2015
Work continues on left controller piece

I couldn’t shake the feeling that I was leaving something unfinished so I decided to re-cut out the left controller section but rotated 90 degrees so the corrugation was going left/right instead of up/down.




I added green arrows to point out the differences in the corrugation. Also found out from testing that, if you’re looking at the corrugation so that it looks like a sine wave, the best place to cut it seems to be right on the peak of one of the waves. This is not always possible if you have to cut to a pre-measured size, but you can at least align one edge like this.

The new pieces seem noticeably stronger, but I’ve been manhandling them for a few hours since then and they’ve weakened a lot. Despite this, I feel that the cardboard is stronger especially around the select button. However, this new piece is just as bendy and useless around the sides of the dPad. There’s no getting around it; there’s probably no way to get the controller this small and not compromise the cardboard. This is fine because I can glue it down to the back piece to reinforce it and then I can fill in the problem areas with hot glue to further strengthen it.

Moving on to the cover plate, I cut out a small piece as a test. The real thing is supposed to cover the entire device--around the screen and both controller sides. The idea is that there should be no seams visible from the front after I glue it on.



Guess what this is? It’s a kleenex box.



I measured and traced out the dPad shape, thumbstick hole, and select button holes. Then I cut them out, inserted the dPad to test and carved out more of the dPad shape until there was no friction.

As important as hiding seams and looking nice is, the real purpose of this faceplate is to hold the buttons in place. Notice that before the dPad area was just an open pit and you could see the silicon membrane. This is not like the 3DS where all you see is the cross of the dPad. That’s what we do here with this thin faceplate. Now I can flip the controller over and shake it and the dPad and membrane will not fall out. Also if you jiggle the dPad it will not move around and gently caress up the alignment to the metal dome switches underneath (supposedly).



Do you get it? Do you understand now? DO YOU GET IT? DO YOU GET IT???

Wait a minute. This isn’t the full story. As you can see in the picture above, I’ve purposefully positioned the dPad to stick out past the surface about the same height as on the 3DS. Unfortunately, since this piece of 1/8th inch cardboard is absolutely not the right height, I actually need to put padding on the bottom to get it to stick out in this way when I mount it in the final location.

Vertical alignment woes

I cut out a piece of padding from the 1/16th inch cardboard (in case you were wondering, I’m getting this from a box of air filters) and cut it in the shape of the dPad. The select button will also need padding.





I was running out of patience here so I didn’t really measure anything or draw a shape. I just traced the hole and cut it out using that. I think this should be good enough for the prototype.



Vibe check. It’s really hard to tell but the dPad and silicon membrane sits pretty much flush with the top surface of the cardboard when there’s padding underneath. You might be able to see a difference from the old pictures, but I’m not sure.



Ok, here’s the thing. I made a different padding piece from the kleenex box. I wanted to try combinations of padding and faceplate thicknesses.



So here you can see the 1/16th inch padding vs 1/32 inch padding. I want to copy the 3DS where the dPad barely sticks up above the case (i.e. the right side of the picture) but I also want to make the faceplate out of the air filter cardboard thickness. The reason is stupid, it’s because I like the color and texture of that cardboard over the kleenex box. So it’s hard to me to decide which thicknesses I want to use.



I had to make a faceplate out of the thicker cardboard just to be sure.



Here is it. See??!? Isn’t it so much cooler looking??? This looks so awesome, I’m considering literally making a version of the final product using a cardboard aesthetic. This is my dilemma.



This faceplate has major issues. The dPad height is okay. I’m using 1/16th inch padding here too. But the select button is too short to go past this. I think the ABXY buttons will have the same problem. I decided for now to use the thicker padding because if the buttons stick out too much that’s ok, but if they don’t stick out far enough, I won’t be able to press them when playing games. Effectively what I’ve done is to postpone my decision about the faceplate for later…

AAAUUGUH :gonk: This doesn’t even matter for the next version, so I need to remind myself not to go too far down the rabbit hole here.


Pictured: overcoming a fear of commitment

The select button is so thin that I needed to cut out two tabs of 1/16th inch cardboard.





I broke out the big guns and permanently glued the padding down.



Hacking in the thumbstick wiring


The time has come for me to solder up a second FPC breakout board.




BOOM! Still got it.





Ok, now it’s time to address that thing I talked about last time about the thumbstick wires bumping into the DSI cable. The solution was to cut a notch into the bottom piece underneath the thumbstick wire so I could wrap it underneath the controller and away from the LCD screen.


JUST LIKE THIS



The breakout board will have to be taped or glue like this and then I’ll use paper to route the signal around the DSI cable to the arduino. I’m working on all that horseshit right now and it’s looking like it’s going to be wild because of how many wires need to be made.

TO BE COMNITEUEDD

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Just to be 100% clear: the cardboard is for prototype only, and the final version is going to be out of something rigid? Or is the final design going to be cardboard for aesthetic purposes?

Cardboard is for prototyping only. I want to make the final version by using kiCAD to make PCBs and then creating the case from a 3D printer. The prototype looks like it's going to turn out to be quite unpleasant to use. The cardboard is too squishy for pressing buttons fast and that's going to make playing games really un-fun.

Cory Parsnipson
Nov 15, 2015

babyeatingpsychopath posted:

Ok. In that case, 400% do not agonize about things. 3d printer (or a LED laser cutter + acrylic) means all of these problems with height are a down-the-road problem. You just need the outlines and dimensions. Z-axis is for rev. 2, when you can print a stack of shims in .2mm thicknesses and then go with the height that works.

In other words, you're solving a problem that you don't need to solve. I'm here to kindly tell you not to go down the path that so many of us have: trying to make THIS ONE absolutely perfect before moving to the next step. Remember: perfect is the enemy of good.

Thanks. I've only made two thicknesses of padding and faceplate and I stopped there. I'm working on the wiring now. The more problems like this that crop up during cardboarding make me want to get to the actual designing that much faster...

Adbot
ADBOT LOVES YOU

Cory Parsnipson
Nov 15, 2015
Thanks for the advice. Yeah I tend to skew on the neurotic side. There's very little in common the cardboard version will have with the "version 2" aside from the placing, reach, and size like you said. I was just having some fun doing arts and crafts, but I should pick up the pace if I want this thing done this year.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply