Snes controller to philips CDI - no power from CDI

Hello, first of all thank you for any help you can provide. I appreciate that I am someone at the moment requiring only a small part of a large subject to get something done.

I have been following this GitHub - anarterb/SNEStoCDi: SNEStoCDi allows to use a Nintendo SNES (Super NES) / SFC (Super Famicom) gamepad on a Philips CDi player / game console (Arduino-based project) method to try and get a SNES controller working on a CDI using an Arduino Uno. All wiring is as indicated there and has now proven successful on both ends but not at the same time.

Initially my soldering skills were not good enough to get the snes controller working locally via controller test sketches but power from the CDI was successful. I could connect the board and controller to the CDI and get no input, but I would get power to the LEDs.

I have since resoldered everything and the controller input now works locally on my laptop (using serial.printline to check button presses etc), but I can no longer get power to the LEDs via the CDI.

What could be going wrong here? Is it possible I have messed up the power from CDI to 5v on the board? How could I check this if so? I have tried disconnecting the snes pins and trying only CDI and still get no response. I am not sure how else to troubleshoot the connections from the CDI to the board.

Any help would be very appreciated.

Edit.
I see there was a similar previous thread Arduino Forum

I'll try some more debugging, but currently it seems at though even the loop is not reached as the LED does not turn on.

Edit 2 -
Hmm ok, so didn't realise I could keep it hooked up to laptop and debug at the same time. Well, I'm assuming that is ok to do.

It is getting stuck in the endless while loop, so analogRead(RTSpin) < RTSthreshold is always true, at least when hooked up to laptop as well.

It's not receiving and analog from the CDI when plugged into CDI and laptop and not receiving any power(anything?) when just plugged into the CDI.

Edit 3 - there is an additional shield ground from CDI, that when added to the board allows the power on without laptop and indicates that the analog is coming through but no input is received. Can't debug though laptop at the same time it is receiving power from cdi... Guess I can debug with LEDs?

Edit 4 - analogRead(RTSpin) seems to max out at about 15 where the threshold is 328, so no updates ever occur. Lowering the threshold goes through the conditionals seemingly as you'd expect, although the vSerial.write, I guess, is not working.

Edit 5 - suspect I have been using the incorrect wires from the cdi. Trying to match them directly to pinout has allowed the while loop to break, but still no input. So if it can work, probably need to get the last correct wires.

Edit 6 - wires all seem correct, however checking vSerial.availableForWrite() suggests it never is...

Following the above the issue appears to be with SoftwareSerial.write().

Checking availableForWrite, available and read values of serial, it seems that nothing can be sent to the CD-I.

Any help with any possible causes or ways to further debug the issue would be appreciated.

I was wondering if it was the baud value of serial that could be causing problems.

Hi,
Welcome to the forum.

Please read the post at the start of any forum , entitled "How to use this Forum".
OR
http://forum.arduino.cc/index.php/topic,148850.0.html.
Then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom... :slight_smile:

Hi Tom, thank you for your patience and apologies for not providing enough detail.

Here is the full code.

/*******************************
 *
 *  File: sketchSNEStoCDi.ino
 *  Description: software for the SNEStoCDi gamepad converter (allows to use a Nintendo SNES/SFC gamepad on a Philips CDi)
 *  Author: Laurent Berta
 *  Date: 03-21-2016
 *  Version: 0.2
 *  Thanks: Rob Duarte (SNESpad library), Paul Hackmann (documentation about the CDi pointing devices)
 *  License: CC-BY 4.0 ( http://creativecommons.org/licenses/by/4.0/legalcode )
 *
 ******************************/

#include <SoftwareSerial.h>
#include <SNESpad.h>
#include <EEPROM.h>

SNESpad pad = SNESpad(5, 6, 7); // Create a SNESpad instance, change the pin values to match your wiring (latch, clock, data)
SoftwareSerial vSerial(9, 10, true); // RX, TX, inverse_logic. RX is not used here, as the CDi only communicates on the RTS line
const int RTSpin = 5; // the number of the analog pin used to receive the RTS signal from the CDi
const int ledPin = 13; // the number of the inboard LED pin

const int RTSthreshold = 328; // threshold for the CDi RTS analog detection
uint16_t btns;
bool btnRpressed = false;
int padbyte0, padbyte1, padbyte2, oldpadbyte0, oldpadbyte1, oldpadbyte2, x, y;
byte spd;
bool firstId = true;
bool btnLpressed = false;
bool btnSEpressed = false;
bool standardMapping = true;

// init
void setup()
{
  oldpadbyte0 = 0;
  oldpadbyte1 = 0;
  oldpadbyte2 = 0;

  byte eepromData = EEPROM.read(0); // retrieve speed setting from the Arduino's EEPROM
  if(eepromData >= 1 && eepromData <= 5) spd = eepromData;
  else spd = 3;
  
  pinMode(ledPin, OUTPUT);
  vSerial.begin(1200); // open serial interface to send data to the CDi
}

// main
void loop()
{
  if(!assertRTS()) {
    digitalWrite(ledPin, HIGH);
    while(!assertRTS()) { } // wait for CDi to assert the RTS line
    if(firstId) delay(100);
    else delay(1);
    firstId = false;
    vSerial.write(0b11001010); // send device id ("maneuvering device")
  }
  digitalWrite(ledPin, LOW);

	// Get the state of the SNES pad buttons
	btns = pad.buttons();

  // manage speed control
  if(btns & SNES_R) {
    if(!btnRpressed) changeSpeed(spd+1); // speed : up
    btnRpressed = true;
  }
  else btnRpressed = false;
  if(btns & SNES_L) {
    if(!btnLpressed) changeSpeed(spd-1); // speed : down
    btnLpressed = true;
  }
  else btnLpressed = false;
  if(btns & SNES_START) changeSpeed(3); // speed : default (3)

  padbyte0 = 0b11000000;  //initialize data bytes
  padbyte1 = 0b10000000;
  padbyte2 = 0b10000000;

  // Dpad X axis
  x = 127;
  if(btns & SNES_LEFT) x = 254;
  if(btns & SNES_RIGHT) x = 1;
  x = adjustSpeed(x);
  
  if(x<127) // right
  {
    x = x ^ 0b01111111;
    x = x + 1;
    padbyte1 = padbyte1 | x;
    padbyte1 = padbyte1 & 0b10111111;
    if((x & 0b01000000) != 0)
      padbyte0 = padbyte0 | 0b00000001;
  }
  else if(x>127) // left
  {
    x = x ^ 0b01111111;
    x = x + 1;
    padbyte1 = padbyte1 | x;
    padbyte1 = padbyte1 & 0b10111111;
    if((x & 0b01000000) != 0)
      padbyte0 = padbyte0 | 0b00000011;
    else
      padbyte0 = padbyte0 | 0b00000010; 
  }

  // Dpad Y axis
  y = 127;
  if(btns & SNES_UP) y = 254;
  if(btns & SNES_DOWN) y = 1;
  y = adjustSpeed(y);

  if(y<127) // down
  {
    y = y ^ 0b01111111;
    y = y + 1;
    padbyte2 = padbyte2 | y;
    padbyte2 = padbyte2 & 0b10111111;
    if((y & 0b01000000) != 0)
      padbyte0 = padbyte0 | 0b00000100;
  }
  else if(y>127) // up
  {
    y = y ^ 0b01111111;
    y = y + 1;
    padbyte2 = padbyte2 | y;
    padbyte2 = padbyte2 & 0b10111111;
    if((y & 0b01000000) != 0)
      padbyte0 = padbyte0 | 0b00001100;
    else
      padbyte0 = padbyte0 | 0b00001000;
  }

  // buttons
  if(btns & SNES_SELECT) {
    if(!btnSEpressed) standardMapping = !standardMapping; // mapping change : invert buttons 1 & 2 (Y & B)
    btnSEpressed = true;
  }
  else btnSEpressed = false;
  if(standardMapping) {
    if(btns & SNES_Y) padbyte0 = padbyte0 | 0b00100000;  //button 1 (Y)
    if(btns & SNES_B) padbyte0 = padbyte0 | 0b00010000;  //button 2 (B)
  }
  else {
    if(btns & SNES_B) padbyte0 = padbyte0 | 0b00100000;  //button 1 (B)
    if(btns & SNES_Y) padbyte0 = padbyte0 | 0b00010000;  //button 2 (Y)
  }
  if((btns & SNES_X) || (btns & SNES_A)) padbyte0 = padbyte0 | 0b00110000; // button 3 (A or X)

  if((padbyte0 != oldpadbyte0) || (padbyte1 != 0b10000000) || (padbyte2 != 0b10000000) || ((padbyte0 & 0b00001111) != 0))  // see if state has changed
  {     
    if(assertRTS()) vSerial.write(padbyte0);
    if(assertRTS()) vSerial.write(padbyte1);
    if(assertRTS()) vSerial.write(padbyte2);
  }

  // save state
  oldpadbyte0 = padbyte0; 
  oldpadbyte1 = padbyte1;
  oldpadbyte2 = padbyte2;
}

// true if RTS asserted
bool assertRTS() {
  if(analogRead(RTSpin) < RTSthreshold) return false;
  else return true;
}

// send back the correct Dpad value depending on the speed setting
int adjustSpeed(int val)
{
  if(val==127 || spd==5) return val;

  if(val==254) {
    if(spd==4) return 202;
    if(spd==3) return 170;
    if(spd==2) return 149;
    if(spd==1) return 130;
  }
  else {
    if(spd==4) return 53;
    if(spd==3) return 85;
    if(spd==2) return 106;
    if(spd==1) return 125;
  }
}

// change speed setting and save it to the EEPROM
void changeSpeed(byte newspeed)
{
  if(newspeed<1) newspeed=1;
  else if(newspeed>5) newspeed=5;
  
  spd=newspeed;
  EEPROM.write(0, spd);
}

I believe here in the code indicates my problem, this is it with some debugging lines added.

// on pad input change padbyte0, padbyte1 and padbyte2 are populated (seemingly correctly)
// but vSerial.write appears not to take the input, if that makes sense.
// I've added some output for debugging as per below
  if((padbyte0 != oldpadbyte0) || (padbyte1 != 0b10000000) || (padbyte2 != 0b10000000) || ((padbyte0 & 0b00001111) != 0))  // see if state has changed
  {     
    Serial.println(vSerial.available()); // always 0

    if (vSerial.availableForWrite() > 1) { // is never true
      Serial.println("Available for write");
    }

    if(assertRTS()) {
      vSerial.write(padbyte0);
    }
    if(assertRTS()) {
      vSerial.write(padbyte1);
    }
    if(assertRTS()) {
      Serial.println("sent value"); // does print
      vSerial.write(padbyte2);
      if (vSerial.available()) { // is never true
        Serial.println(vSerial.read());
      }
    }
  }

Please find attached my attempt at drawing the circuit and the wiring jpg from git as reference. Let me know if anything is completely meaningless.

Initially there was some issues with wiring. I was following a video tutorial which had different coloured wires. I have since, as accurately as I can, determined the correct wires to go to each port.

Thank you for any help.

Edit - the number indicators in the SNES and CDI are arbitrary, couldn't figure out how to change them, but the notations on the diagram all correspond correctly.

Edit 2 - There's an additional ground wire I'm using from the cdi not mentioned on git repo/jpg. Otherwise have also only displayed the wires in use.

Edit 3 - have noticed there's specific rx and tx on the board so might try using them instead of pin 10.

Edit 4 - also now seeing that both vcc should perhaps be going through the one 5v pin? The video tutorial I watched mentioned having two 5v and some search results indicated that IOREF could be used as a substitute, though that could have been my misunderstanding.

Would it be correct to combine the controller and cdi vccs on the one 5v??

Edit 5 - tried using regular serial for talking to the cdi. No luck there. IOREF looks ok to use. SoftwareSerial.isListening() at least.
Tried all possible baud values, no luck.

I'm guessing it is either more wiring/soldering issues, but how do I confirm that?

Or something in the cdi model. I don't think I've seen mention of someone having this working on a 205 which is all I have.

Last bump on this I promise. Sadly I've given up trying to get the above to work. I tried a few of the things I considered, multiple rewirings and debugging softwareSerial. Nothing got any closer.

SoftwareSerial seems to get all the right bits and calls something to send to the pins, but I'm not sure how to check this further. Calling read seems to indicate the buffer is never filled and when trying to debug the recv method the output seems too garbled by the interrupts that I can't see what it's putting in there or whether it's correct. Likely is a problem with my wiring or the cdi over the software though.

Any help would still be appreciated, but I think I will move on to what other cool things I can do with my Uno.