Author Topic: Saturn Controller Protocol MK80117 and Emulation  (Read 2772 times)

Online RDC

  • Administrator
  • Around the block
  • *
  • Posts: 2585
  • Post quality +90/-2
  • Gender: Male
  • The CGnome Project
Saturn Controller Protocol MK80117 and Emulation
« on: March 19, 2013, 02:12:37 AM »
After tinkering around with the standard 6 button Saturn pads, MK-80116 and MK-80100. https://www.acidmods.com/forum/index.php/topic,42733.0.html

I figured I'd give the 3D (Nights) Controller a look see. This is based on the reader understanding Binary, specifically 8-bits ( or 1 Byte) or at the very least being able to count to 15 (4 bits) which if you can't do, Google it up, it's fun, you'll learn something and you can then appreciate that old joke, "There are 10 kinds of people that understand Binary, those that do, and those that don't. ;)

Now, the 3D Controller is by far different from the protocol used on the standard 6 buttons pads. Those only use 6 lines for communication, 2 Select bits and 4 Data, while the 3D Controller uses 7 lines.

The connector pinout is the same, looking into the end of the controller's connector, beveled side up.

Code: [Select]
/-----------\
| 987654321 |
|___________|

1 - 5v (Power to Controller)
2 - D1 (Data 1)
3 - D0 (Data 0)
4 - Request or REQ (Select 1, also known as TR)
5 - Select or SEL (Select 0, also known as TH)
6 - Acknowledge or ACK (also known as TL)
7 - D3 (Data 3)
8 - D2 (Data 2)
9  - Ground

NOTE* All 4 Data and the TR, TH, TL lines are pulled up to 5v with 100k Resistors inside the controller.

So here we see the data that's sent when the 3D Controller has the switch in the 'Digital' position.



Then here it is with the switch in the 'Analog' position.



The 4 Data lines still do the same thing, which is send 4 bits of Data at once. This is half of a Byte, which is 8 bits, so the 4 bits of Data here is called a 'nibble'. But the 3 T lines on the 3D controller differs in how that Data is sent.

The TH line acts like a 'Select', when it's pulled Lo then that controller is the one that's about to be queried for Data.

The TR line is a 'Request' from the Saturn for Data to be sent from the controller. When it changes states that's when it's Requesting Data to be sent, so from Hi to Lo is a Request, as is going from Lo to Hi.

The TL line is an 'Acknowledge' that the Data is ready for the Saturn to read it. This line 'follows' the TR 'Request' line, so when TR goes from Hi to Lo, after the Data is ready to be read, then the TL line also goes from Hi to Lo, or vice-versa depending on where you're starting from.

The 6 button pads only used 2 Bytes of Data, which were derived from the 4 states that the TR (S1) and TL (S0) lines could be put into. The 3D controller does this a little differently. The first Byte of Data sent is for both the ID for the type of controller, Digital, Analog, etc., and also the number of Bytes needed for the rest of the Data.

The first Byte sent goes like this.

First the SEL line is pulled Lo (yellow arrow down) This means the Saturn is getting ready to ask for Data from that device.
Second the REQ line goes Lo (green arrow down) This is the Saturn asking for Data from the controller.
Third the ACK line goes Lo (blue arrow down) This is the controller Acknowledging that the Data, 0000 for Digital controller in this case, is ready for the Saturn to read from D3~D0.
Fourth the REQ line goes Hi (green arrow up) This is the Saturn again requesting Data from the controller.
Fifth the ACK line goes Hi (blue arrow up) This is the controller again Acknowledging that the Data is ready, but this time it is 0010, which means 2 Bytes for the remaining Data.

This is how that first Byte looks on the Logic Analyzer.



Now, following those same steps, when the controller is in the 'Analog' mode, the first Byte is then 0001-0110, which is 0001 for Analog, then 0110 for 6 Bytes of Data.



Like the 6 button pads, my test setup used the PIC16F1516, PicKit 3, Saleae Logic Analyzer and 16x2 LCD screen.



Close up of the screen in Digital mode.



..Analog mode..



..and no 3D controller connected.




I'll post the code up for this one later on once I go back thru it all as I want to give it a bit of an overhaul.

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Now, Emulating the 3D controller. That is, making the Saturn 'think' you have a 3D controller connected, when it fact, it's just a  PIC, which is in this case again, the 16F1516. When using an external Crystal like I did here, this thing has just enough I/O (Input/Output) pins to pull this off.

This is also not 100% complete yet either. I do have both Digital and Analog modes working, but I don't have them setup so I can just flip a switch and go back and forth between them yet.

The buttons at the top are, from left to right, L, R, X, Y, Z, Start, A, C, B, D-pad R, L, D and U. The Stick is just from an old 360 controller. The original 3D controller uses a Hall Sensor type of Stick, which uses magnets, sensors and an OpAmp to do pretty much the exact same thing that a POT style Stick does.



This is the Data being sent between the PIC and the Saturn, which looks a lot like the pic above from the Data capture from the 3D controller in the Analog mode, but that was the idear. ;)



This is just the Digital portion of the code.

Code: [Select]
/*******************************************************************************
SEGA SATURN 3D CONTROLLER EMULATOR

PIC16F1516
EXTERNAL OSC @ 16MHz
5v POWER FROM SATURN

RDC 2013
*******************************************************************************/

char SPID, DATA_SIZE;

char DATA1_1, DATA1_2;
char DATA2_1, DATA2_2;
char DATA3_1, DATA3_2;

#define TH_SEL RA3_bit                   // Configure as Input
#define TR_REQ RA4_bit                   // Configure as Input
#define TL_ACK RA5_bit                   // Configure as Output

// Initialize the PIC
void INIT() {
ANSELA = 0b00000011;                     // AN0 and AN1 Analog to X and Y Axis
ANSELB = 0b00000000;                     // All AN are Digital
ANSELC = 0b00000000;                     // All AN are Digital
TRISA = 0b00011111;                      // PORTA
TRISB = 0b11111111;                      // PORTB, pins 6 and 7 also for ICSP
TRISC = 0b11110000;                      // PORTC
TRISE = 0b00001000;                      // PORTE, only 1 pin, RE3
TL_ACK = 1;
}


void main() {

   INIT();
     
  SPID = 0b00000000;
  DATA_SIZE = 0b00000010;

///// DIGITAL:

/////  Set Initial Button DATA for power up

    DATA1_1 = 0b11111111;                 // DATA1_1
    DATA1_2 = 0b11111111;                 // DATA1_2
    DATA2_1 = 0b11111111;                 // DATA2_1
    DATA2_2 = 0b11111111;                 // DATA2_2
    DATA3_1 = 0b00000000;                 // DATA3_1
    DATA3_2 = 0b00000001;                 // DATA3_2

  delay_ms(500);   // Wait for the Saturn to start up (takes around 1.5s)

  while(1) {

///// START COMMS WITH SATURN

    while(TH_SEL == 1) {}   // Wait for the Saturn to select controller
    delay_us(40);

    while (TR_REQ == 1) {}  // Wait for Saturn to request SPID
    PORTC = SPID;           // SPID  0000 = Digital  // 0001 = Analog
    TL_ACK = 0;             // Here is the data
     
    while (TR_REQ == 0) {}  // Wait for Saturn to request Data Size
    PORTC = DATA_SIZE;      // DATA_SIZE  0010 = 2 Bytes, 0110 = 6 Bytes
    TL_ACK = 1;             // Here is the data
     
///// START FIRST BYTE
   
    while (TR_REQ == 1) {}  // Wait for Saturn to request first half of Data1
    PORTC = DATA1_1;        // DR, DL, DD, DU
    TL_ACK = 0;             // Here is the data
     
    while (TR_REQ == 0) {}  // Wait for Saturn to request second half of Data1
    PORTC = DATA1_2;        // ST, A, C, B
    TL_ACK = 1;             // Here is the data
   
///// END FIRST BYTE

///// START SECOND BYTE

    while (TR_REQ == 1) {}  // Wait for Saturn to request first half of Data2
    PORTC = DATA2_1;        // R, X, Y, Z
    TL_ACK = 0;             // Here is the data

    while (TR_REQ == 0) {}  // Wait for Saturn to request second half of Data2
    PORTC = DATA2_2;        // L, 1, 1, 1
    TL_ACK = 1;             // Here is the data

///// END SECOND BYTE

///// START THIRD BYTE, END OF DATA

    while (TR_REQ == 1) {}  // Wait for Saturn to request first half End
    PORTC = DATA3_1;        // 0000
    TL_ACK = 0;             // Here is the data

    while (TR_REQ == 0) {}  // Wait for Saturn to request second half of End
    PORTC = DATA3_2;        // 0001
    TL_ACK = 1;             // Here is the data

///// END THIRD BYTE

    while(TH_SEL == 0) {}   // Wait for the Saturn to deselect controller
   
///// END COMMS WITH SATURN
   
/////  Get Current Button DATA (in less than 15ms)

    DATA1_1 = PORTC >> 4;                 // DATA1_1
    DATA1_2 = PORTB;                      // DATA1_2
    DATA2_1 = PORTB >> 4;                 // DATA2_1
    DATA2_2 = (PORTA << 1) + 7;           // DATA2_2
    DATA3_1 = 0b00000000;                 // DATA3_1
    DATA3_2 = 0b00000001;                 // DATA3_2

  }
}


-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

If anyone can, or would like to, build and test out the 3D controller Emulator, here are the hex and schematic files.

https://mega.nz/#!rk0WCKJL!Zg_CDYkPJIXGjWYMC_DIIhHs1j-bnyYgdq5Z5xdhLS0

If that link says you need the decryption key, it is - !Zg_CDYkPJIXGjWYMC_DIIhHs1j-bnyYgdq5Z5xdhLS0

The PIC needs to be a 16F1516, and it requires the PicKit 3 to flash it.

X1 is a 16MHz Crystal, the C1 and C2 values depend on the Crystal used, but 20pf is a 'ballpark' value if you don't know what value it requires.

C3 is a DeCoupling Capacitor and is optional but recommended, anything from 0.01uf to 1uf will do.

S1 is a SPDT switch for the Digital/Analog modes.

Any 10k POT style stick can be used for the X-Axis and Y-Axis. (['m sure this needs some adjusting in code)

J1 is the controller cable that plugs into the Saturn. 1- 5v, 2- D1, 3- D0, 4- REQ, 5- SEL, 6- ACK, 7- D3, 8- D2, 9- GND

J2 is the programming header for the PIC. 1- VPP, 2- VDD, 3- VSS, 4- DAT, 5- CLK

R1 thru R21 can be anything from 10k to 100k in value.
« Last Edit: June 09, 2021, 08:33:57 PM by RDC »
Screwing up is one of the best learning tools, so long as the only thing you're not learning is how to screw up.

 

SMF spam blocked by CleanTalk
SimplePortal 2.3.5 © 2008-2012, SimplePortal