Close

Fourth Release: The Attack of cloNES

A project log for Control Freak

Collection of Arduino Micro firmware and schematics for connecting your retro Joysticks and Gamepads to USB port.

danjovicdanjovic 04/18/2020 at 18:340 Comments

There is a lot of NES/SNES controler adapter projects availabe online, and I even have built  myself one ( #Digi:[S]NES ).

The code is very straightforward:

  1. Pulse the latch line
  2. Read a bit
  3. Pulse the clock
  4. Repeat step 2 until you have read 12 bits

NES and SNES controller protocol

The same code can be used for NES and SNES, with  one minor inconvenience that the buttons A and B are not on the same position in either controller, meaning that the buttons assigned to B and Y will be activated when a NES controller is plugged.
The code that I have has been proven on several NES controllers that I have but none of them were original controllers.

According to the schematics of the NES controllers that I have found online that shouldn't happen (quite right) because the NES controller is based on a 4021 shift register chip which have the SHIFT IN pin connected to GND (that was done by Nintendo to provide means to detect the presence of the controller).

NES controller schematic

But the Knockoffs that I have always present a HIGH after the last button read (RIGHT)
Waveform for the Knockoff NES controller

Ok, that is a good effect of using knockoffs but I want this firmware to be ready to use original controllers, and I wish also to have A and B mapped to the same (PC) buttons, no matter if a NES or an SNES controller is attached. For accomplishing that I need to differentiate the SNES controller from the NES controller (and from the Knockoffs).

The solution came from the analysis of the SNES controller schematic. It uses two 4021s in series and also have the serial input of the last shift register connected to the GND and the last bits (which are unused) are pulled up to VCC. Tha means that after the 12 button bits I should have 4 bits HIGH and after that any bit read will be LOW.

So considering the complete waveform, we can read 17 bits from the controller then analyze the last 5 bits received:

The code is implemented slightly different because I use a 16 bit variable for the shifted bits and after all bits are shifted in I test the 17th bit, and test for 8 bits in LOW for the NES controller.

  // read 16 bits from the controller
  dataIn = 0;
  for (i = 0; i < 16; i++) {
    dataIn >>= 1;
    if (digitalRead(dataPin)==0) dataIn |= (1<<15) ; // shift in one bit
    Pulse_clock();
  }
    
  if (digitalRead(dataPin)) { // 17th bit should be a zero if an original controller is attached
    controllerType = NONE;
  } else {
    if ( (dataIn & 0xf000) == 0x0000)
      controllerType = SNES;
    else  if ( (dataIn & 0xff00) == 0xff00)
      controllerType = NES;
     else
       controllerType = NONE;
      }

Luckly the knockof SNES controller that I have worked as expected. As the SNES uses the last bits to identify some different types of controllers like the mouse, I thinkg that the knockoff manufacurers took care in following the behaviour or the original controller.

Here's a waveform for the SNES controller.


And that concludes the fourth release. I left below a montage with my knockoffs:

Discussions