Close
0%
0%

Stingray

Nintendo Classic controller adapter with keypad emulation for Atari 5200

Similar projects worth following
Controller adapter for Atari 5200 featuring :
# Analog Controller (using precise timing);
# Digital Controller on D-PAD just like a Masterplay adapter;
# Full keypad emulation;
# Auto detected second controller adapter for games like Robotron
# Independent Top/Bottom buttons on second controller.

This project is heavily based on #MegaPlay and uses an Arduino nano to provide a Wii Classic Controller adapter for Atari 5200.

Mai features are: 

  • Analog Controller (using precise timing);
  • Digital Controller on D-PAD just like a Masterplay adapter;
  • Full keypad emulation;
  • Auto detected second controller adapter for games like Robotron
  • Independent Top/Bottom buttons on second controller.

Controls Mapping, one controller:

image.thumb.png.4e4e3f2f43cfd207e929d48b2890f98f.png

Controls Mapping, two controller emulation

image.thumb.png.dbf808709af47edcf8b6cb18ce83ca46.png

Second controller adapter consists of a USB A male plug and a DB-15 connector. Shield  connection on USB plug is used to detect the presence of the adapter and switch behavior accordingly.

usb-connection.png

Printed Circuit Board measures 1.8" x 2.0" (~46mm x 51mm ) and incorporates a connector for the Wii Classic controller.

The board also provides an USB type A female for the dual controller adapter cable and a Mini-Din6 connector with wiring ready to interface a PS/2 mouse.

Precise Timing

The analog controller information is measured by Pokey chip that measures the time a capacitor takes to increase its voltage from near zero to a given value. This time varies with the resistance of the potentiometer axis.

  Many videogames and computers, like ATari 2600, PC gameport, Apple][ gameport usually discharges the capacitors right before start a new reading cycle. On these systems is just a matter of waiting for the capacitors to discharge to know when to push the line high to provide a desired position (timing) information.

  But in Atari 5200 that is not so easy because Pokey chip keeps the capacitors discharged by until the next sampling cycle that depends upon the game loo, therefore the discharge moment can not be used as a time reference.

The experiments that I have done consisted in:

  1. polarize one of the pot inputs with a resistor that provides a low counting, e.g. 10KOhms and detect the voltage increase before it reaches ~1.9V that is the input threshold voltage of POT pins in Pokey Chip.
  2. Then the line is forced LOW by the time enough to provide the desired counting in Pokey chip.
  3. Finally the line is pushed high to exceed the threshold voltage and that makes pokey capture the exact counting.

Worth to mention that this method does not depend upon internal calibration of Vac voltage (at pin 9).

The links [1][2] are for two videos with the first experiments. The tests have been performed on a AVR (Arduino board) together with the #Atari 5200 Controller Port Emulator 

image.thumb.png.1fbab83ac90a6d604670509e901ffcb0.png image.thumb.png.ebbda832fb9ee8958bdf301758054913.png


  • 1 × Arduino Nano V3
  • 2 × CD4052 Analog Multiplexer
  • 1 × PCB Printed Circuit Board
  • 1 × BZX79C5V1 Zener 5.1 Volts
  • 1 × 100R Electronic Components / Misc. Electronic Components

View all 11 components

  • PCB rev A

    danjovic4 days ago 0 comments

    Thanks to the feedback from @Chris Belcher I have corrected the mirrored footprint of the Wii connector.


    Additionally I have turned the footprint upside down so now the Classic controller can be mounted with the plastic tab facing upwards.



  • Alpha Release

    danjovic03/24/2020 at 02:06 0 comments

    Just released an Alpha on github repository. So far I have tested:

    •  Combined Analog control (either right or left stick control the axes)
    •  Dual controller auto detection
    •  Dual controller (left stick control main axes, right stick control secondary axes, buttons X,Y secondary buttons
    •  D-Pad override over left stick to provide full digital control (like Masterplay)

    Keypad emulation is yet to be tested on this prototype but it was verified to work on Megaplay.

  • Adding provision for more features

    danjovic03/22/2020 at 15:02 0 comments

    Changed the DETECT logic for one of the extra analog signals (A6) of the Nano board and that let me free 2 IO pins (D0 and D1). Now I can use the remaining space on the board to add a PS/2 mouse connector  to be able to use a mouse to emulate a trackball.

  • Nonlinear response to improve usability

    danjovic03/17/2020 at 23:35 0 comments

    I should apply a gamma curve to the analog axes read from Classic controller to make the response of the stick more subtle near the center and more steep close to the edges.

    Classic controller analog sticks provide position information with a low resolution. Left stick provides 64 steps and Right stick provides 32.  

    Both axes are combined using the following equations:

    index = LeftJoy + (RightJoy * 2) - 32;
    if (index > 63) index = 63;
    if (index < 0 ) index = 0 ;
    

    The variable index  shoulld assume a value between 0 and 63.

    When both sticks are in center position the resulting will be 32, right in the middle of the scale.

    Either stick can be pushed or pulled to make the index value swing from 0 to 63. If both sticks are moved in the same direction the resulting value will reach the maximum (or minimum) on the middle of their course (not exactly in the middle because of the gamma curve). On the other hand, when both sticks are thoroughly moved in opposite directions the resulting will be again the middle of the scale.

    Whole code to process the joysticks is then:

      lx=classic.leftJoyX();
      ly=classic.leftJoyY(); 
    
      rx=(classic.rightJoyX()<<1); 
      ry=(classic.rightJoyY()<<1); 
      
      combinedXaxis = lx+rx-32;
      if (combinedXaxis>63) combinedXaxis = 63;
      if (combinedXaxis<0)  combinedXaxis = 0;
    
      combinedYaxis = ly+ry-32;
      if (combinedYaxis>63) combinedYaxis = 63;
      if (combinedYaxis<0)  combinedYaxis = 0;
    
      combinedYaxis = 63-combinedYaxis;

    The latter statement on code above inverts the way that Y axis behaves so the resulting value grows when the stick is moved down and vice versa.

    Gamma

    The curve below depicts the values from middle scale to the upper limits (down and right), being a total of 31 counts. The Y axis represents the amount of countings that should be read by the 5200 system.

    logscale.png

    The whole curve along with a  gamma = 2.0 and a linear reference (gamma = 1.0) is depicted below

    The spreadsheet that generated the curve provides the array for correction of gamma values:
    uint8_t gammaCurve[64] = { // gamma = 2.0
    5  , 12 , 18 , 24 , 30 , 36 , 42 , 47 , 52 , 57 , 62 , 66 , 71 , 75 , 78 , 82 , 
    86 , 89 , 92 , 95 , 97 , 100, 102, 104, 106, 107, 109, 110, 111, 112, 112, 112, 
    113, 113, 113, 114, 114, 115, 117, 118, 120, 122, 124, 126, 129, 131, 134, 138, 
    141, 145, 149, 153, 157, 162, 167, 172, 177, 182, 188, 194, 200, 207, 213, 220 
    }

  • Controller detection logic

    danjovic03/15/2020 at 12:34 0 comments

    Working on controller detection logic. I will support Nunchucks too. 

    The adapter is now able to detect the presence of either the Classic controller or the Nunchuck and react accordingly (hot-plugging) without adding overhead to the sampling (aka multiple readings).

    /*   Stingray  -  Controller Logic */
    
    #include <NintendoExtensionCtrl.h>
    
    ExtensionPort controller;
    Nunchuk::Shared nchuk(controller);  // Read Nunchuk formatted data from the port
    ClassicController::Shared classic(controller);  // Read Classic Controller formatted data from the port
    
    void setup() {
      Serial.begin(9600);
      controller.begin();
    }
    
    void loop() {
      if (controller.connect()) { // valid controller was connected
        while (controller.update()) {
          ExtensionType conType = controller.getControllerType();
          switch (conType) {
            case (ExtensionType::Nunchuk):
              mapNunchuckData();
              break;
            case (ExtensionType::ClassicController):
              mapClassicData();
              break;
            default:
              Serial.println("Other controller connected!");
              disableOutputs();
          } // Switch
          processControllerData();
        } // while
        disableOutputs();
      } else { // Controller not connected}
        Serial.println("No controller found!");
        disableOutputs();
      }
      delay(200);
    }
    
    void disableOutputs() {
      Serial.println("Disable Outputs");
    }
    
    void  processControllerData() {
      Serial.println("Process Data");
    }
    
    void mapNunchuckData() { 
        nchuk.printDebug();  
    }
    
    void mapClassicData() {
      classic.printDebug();
    }  

View all 5 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates