Testing my SNES controllers with two new controller test ROMs

Many weeks ago I was wondering how quickly I could manually read a SNES controller in 65816 assembly.1 This led me to wondering if I could read and display the controller data once per scanline to measure the contact bounce and detect bad button contacts to find my best SNES controller.

I was unable to read and display all 16 bits of controller data in a single scanline. Luckily there's just enough CPU time to read and display 12 bits of data and a Standard Controller has 12 buttons.

Rapid Read Test

This test reads 12 bits of controller data from port 1 every scanline and displays it by writing to BGnVOFS (vertical scroll offset register) every horizontal blank.2

Since I do not have super-vision, I used a 60Hz USB HDMI capture device to record the console output while mashing buttons on the controller. I then played back the recording, advancing each frame one at a time to inspect the stability and contact bounce of my controllers.

rapid_read_test A button press rapid_read_test A button release rapid_read_test holding ABXY rapid_read_test pressing down-right, releasing down

Super Famicom 1-CHIP screen captures of my joypad rapid read test.

  1. No contact bounce when A is pressed.
  2. Minor contact bounce when A is released.
  3. A, B, X and Y is held down. The output is stable.
  4. Pressing down-right on the D-Pad. Down is released with some contact bounce. Right remains pressed at the end of the frame.

Here is the output of a controller with bad start and select buttons. On this controller I have to press hard for the console to register a start or select button. Looking at the test output it's clear that the button contacts have gone bad and it's not making a stable connection.

rapid_read_test unstable select button rapid_read_test unstable start button
Bad button contacts for the select button (left) and start button (right).
Recorded on a 1-CHIP Super Famicom console.


When playing around with the test I found phantom inputs on one of my D-Pads. I was repeatedly pressing the right button and the recording showed the occasional unintended down press that lasted 2 to 5 frames.

I'm fairly certain this is a controller issue and not a technique issue. I've repeated this test on multiple controllers, with the same hand positions and tapping rhythm and 2 of my controllers have no phantom input issues.

rapid_read_test right held, down pressed. Over half a frame of contact bounce for down press. rapid_read_test right held, down released. A third of the frame has contact bounce for down release.
Phantom down input when pressing right.
This phantom input has a lot of contact bounce and lasted 5 frames.
Recorded on a 1-CHIP Super Famicom console.

Bounce Test

I wanted to look at the contact bounce of all of my controllers but I found recording the rapid-read-test and checking each frame annoying. So I made a new test that can detect button presses and releases.

This test will wait until a controller button is pressed. Then it reads the controller once per scanline, writing the data to RAM and looping until no button presses have been detected for 262 scanlines (1 frame). Finally, it builds multiple HDMA tables to display 214 scanlines of controller reads after key-press and up to 214 scanlines of controller reads before button-release.

To use the joypad-bounce-test, you simply press and release a single button and look at the results. No screen recording is required (unless you are analysing 10 seconds of button mashing like I did below).

Each pair of vertical lines represents a controller button. The left line shows the controller data after key-press, the right line shows the controller data before key-release.

I also added a counter to the test because I was uncertain if the test registered my controller input or not.

joypad_bounce_test. A press. 2 scanlines of contact bounce on A button release joypad_bounce_test. B press. No contact bounce. joypad_bounce_test. Y press. No contact bounce. joypad_bounce_test. X press. No contact bounce.
Joypad bounce test screen captures.
The left line shows the controller data after key-press, the right line shows the controller data before key-release.
Each screen capture is a regular press of the A (red), B (yellow), Y (green) and X (blue) buttons.
The A button has 2 scanlines of contact bounce on release. The other buttons have no measurable contact bounce.
Recorded on a 1-CHIP Super Famicom console.

The joypad-bounce-test is useful for confirming bad contacts in my controllers. Annoyingly, it is not useful for detecting phantom inputs.

joypad_bounce_test. Up press. ~26 scanlines of contact bounce on button press and more than 160 scanlines of contact bounce on button release. joypad_bounce_test. Down press. The entire button press is unstable lasts ~75 scanlines.
Joypad bounce test on a controller with a known bad D-Pad.
Recorded on a 1-CHIP Super Famicom console.

How I hold the controller affects contact bounce

While this is obvious in hindsight, I was unaware that resting my controller on my leg and repeatedly Y tapping with my index finger has different contact bounce than holding the controller in two hands (with both middle fingers underneath the controller) and tapping with my thumb.

On my Super Famicom controller, repeatedly tapping the Y button on my leg has worse contact bounce than holding the controller in two hands and tapping Y with my thumb.

joypad_bounce_test. Y button. Just under half a frame of contact bounce on button press. joypad_bounce_test. Y button. Approximately 15% of a frame of contact bounce on button release. joypad_bounce_test. Y button. Approximately 28% of a frame of contact bounce on button press.
Contact bounce with my SFC controller resting on my leg.
Rapidly tapping Y with my index finger 60 times in 10 seconds.
3 of the button presses had measurable contact bounce.
joypad_bounce_test. Y button. ~15 scanlines of contact bounce on release.
Contact bounce when holding the same SFC controller with two hands.
Rapidly pressing Y with my thumb 58 times in 10 seconds.
Only 1 of the button presses had measurable contact bounce.


I did not know if this is a sign of a bad controller or not. So I repeated this test with a different controller and got different result. This controller had minor contact bounce when tapping Y on my leg and (surprisingly) large contact bounce when holding the controller in two hands.

I initially did not believe this output and seriously thought there was something wrong with my code. Holding the controller in two hands should be more stable than resting it on my leg. The code looked fine. So I repeated the setup with my PAL controller using the rapid-read test ROM, manually reviewed each frame and got similar results (controller on leg, controller in 2 hands).

joypad_bounce_test. Y button. ~5 scanlines of contact bounce on release. joypad_bounce_test. Y button. ~2 scanlines of contact bounce on release.
Contact bounce with my best PAL controller resting on my leg.
Rapidly pressing Y with my index finger 72 times in 10 seconds.
2 button presses had measurable contact bounce.
joypad_bounce_test. Y button. Approximately a third of a frame of contact bounce on release. joypad_bounce_test. Y button. ~14 scanlines of contact bounce on release. joypad_bounce_test. Y button. Approximately 22% of a frame of contact bounce on release. joypad_bounce_test. Y button. ~2 scanlines of contact bounce on release.
Contact bounce when holding the same PAL controller with two hands.
Rapidly pressing Y with my thumb 59 times in 10 seconds.
4 button presses had measurable contact bounce.

Conclusions

I have the following conclusions about my 5 controllers (3 Nintendo and 2 late-2010's clone controllers):

  • The Start and Select buttons are horrible and barely work on my 2 clone controllers.
  • The D-Pad is bad on 3 of my controllers (1 Nintendo PAL and 2 clone).
  • The L and R buttons are good on all of my controllers.
  • The face buttons are OK on all of my controllers. I do see significant contact bounce when I button mash and minor or no contact bounce for regular button presses.

Most of the time I did not detect measurable contact bounce on my good controllers. Occasionally I saw contact bounce that lasted less then 20 scanlines and when I was mashing the controller I rarely saw contact bounce that lasted just under half a frame.

These tests confirm that I do not need to add debounce logic to my homebrew SNES game when I am using a good controller.3 The worst contact bounce I saw with my good controllers stabilises in less than half a frame when mashing heavily. Take this with a grain of salt, the sample size is small and I'm not the best button masher.

Downloads

These tests are free to distribute. The source code can be found on GitHub (zlib licensed):


  1. Most SNES games do not manually read the controller ports. The SNES contains a joypad auto-read feature that will read 16-bits from the controller ports once per frame.
    Manual reading is required for the Multitap and non-standard peripherals that transfer more than 16 bits of data like the Super NES Mouse and the NTT Data Keyboard. 

  2. I can display 8 bits data of every scanline by writing value - scanline - 1 to the BGnVOFS register every horizontal blank with a background pattern that shows the scanline's binary value on every scanline.

    scanline-bit-pattern

    I'm using mode 0. Where 4 horizonatally offsetted backgrounds can be used to display 32 bits of data every scanline. Mode 0 also gives each background its own independednt palette, allowing to to indivually colourise the on and off colours for all 32 vertical lines. 

  3. My game does include input buffering for the attack action.