Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I am building a transmitter and reciever pair for two SNES controllers, as I don't like using long extension cords to get the controllers to reach the couch. I'm using atmega328p's for the avr's, with RF24l01 wireless transcievers (using ManiacBugs RF24 library). I am using a modified snesPad library on the transmitter to poll the button states of two controllers and return them as a 32bit unsigned long, then transmitting that to the reciever. All standard libraries, no issues there (so far).

However, on the reciever side, I have to properly respond to the latch and clock signals from the SNES, and I haven't found any stock libraries for that. For those not familiar with the SNES controllers, they are basically two 8bit parallel to serial shift registers in series. They latch all of the button states on the rising edge of the latch signal (12us pulse high, normally low), drive the first bit on the falling edge of latch, and then drive each successive bit on the rising edge of clock (6us delay from fall of latch, normally high, 6us low - 6us high cycle). I've determined my best option is to use an external interrupt to trigger the proper behavior for the latch pulse and each clock pulse. I'm new to programming Arduinos though, and new to C/C++ as well. Although my code will compile, I'm not certain if it will actually function as intended. The variables in particular where fun to get straight, as the radio.read and radio.write classes didn't like being passed volatile variables. If someone who has some experience with AVR's could take a look at my code and let me know if it will work, and if not, where and why, I would be very greatful!

Arduino reciever sketch follows:

/*
Copyright (C) 2012 John Byers <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 3 as published by the Free Software Foundation
*/

/** 
 * Dual Wireless Retro Controller Adapter Transmitter
 *
 * This is the reciever side code for the adapter set.
 */

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>

//
// Hardware Configuration
//

RF24 radio(9,10);

//
// Variable Inits
//

volatile unsigned long state2 = 0xFFFFFFFF;
volatile byte i = 0;
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
volatile int strobe = 2;
int clock = 3;
volatile int data1 = 5;
volatile int data2 = 6;
bool firstLoop = true;
volatile int status2 = 1;

void setup()
{
  //Setup radio and serial debugging
  radio.begin();
  radio.setRetries(0,15);
  radio.enableDynamicPayloads();
  Serial.begin(57600);

  //setup SNES pins
  pinMode(strobe, INPUT);
  pinMode(clock, INPUT);
  pinMode(data1, OUTPUT); digitalWrite(data1, LOW);
  pinMode(data2, OUTPUT); digitalWrite(data2, LOW);

  //open radio pipes
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);

  //Dump the configuration of the RF unit for debugging - remove in final code
  radio.printDetails();

  //Setup Interupts  
  attachInterrupt(strobe,latch,CHANGE);
  attachInterrupt(clock,data,RISING);

}

void loop()
{
  //check if this is the first execution of loop()
  if (firstLoop) {
    int status1 = 1;

    //send ping packet to let transmitter know we are ready for a packet
    bool ok = radio.write( &status1, sizeof(int));

    //begin listenting for button state packet
    radio.startListening();

    //debug check to make sure ping packet was sent - remove in final code
    if (!ok) {
      Serial.println("sync packet transmission failed");
    }
    else {
      Serial.println("sync packet transmission successful");

    //let the program know we have succesfully executed the first loop
    firstLoop = false;
    }
  }

  //check for data packet from transmitter
  if ( radio.available() )
  {
    //read data packet from transmitter
    unsigned long state = 0;
    radio.read( &state, sizeof(unsigned long) );

    //debug output recieved packet contents - remove in final code
    Serial.println(state, BIN);

    //copy button state data to volatile variable for use in interrupts
    state2 = state;
  }

  //debuging output if no data packet present yet  - remove in final code
  else
  {
    Serial.println("No data recieved yet");
  }
}

//Latch interrupt routine

void latch()
{
  //check to see if latch signal is high or low
  if (strobe) {

    //set both data lines high
    digitalWrite(data1,HIGH);
    digitalWrite(data2,HIGH);
  }
  else {

    //set first bit on data lines
    digitalWrite(data1,bitRead(state2,i));
    digitalWrite(data2,bitRead(state2,(i+16)));

    //initialize clock signal counter to 0
    i = 0;

    //debug status output
    Serial.println("Bit0 out");
  }
}

//Data interrupt routine

void data()
{
  //increment clock signal counter
  i++;

  //output next bit on data lines
  digitalWrite(data1,bitRead(state2,i));
  digitalWrite(data2,bitRead(state2,(i+16)));

  //debug status output
  Serial.print("Bit");
  Serial.print(i);
  Serial.println(" out");

  //check to see if this is the final clock cycle in a read cycle
  if(i=15)
  {
    //drive data lines low
    digitalWrite(data1,LOW);
    digitalWrite(data2,LOW);

    //take radio out of listening mode
    radio.stopListening();

    //read ping bit into ISR local variable from volatile local
    int status1 = status2;

    //send ping packet to transmitter
    bool ok = radio.write( &status1, sizeof(int));

    //debug check to see if packet sent - remove in final code 
    if (!ok) {
      Serial.println("sync packet transmission failed");
    }
    else {
      Serial.println("sync packet transmission successful");
    }

    //put radio back in listening mode
    radio.startListening();
  }
}

and for reference, here's the transmitter sketch:

/*
Copyright (C) 2012 John Byers <[email protected]>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 3 as published by the Free Software Foundation
*/

/**
 * Dual Wireless Retro Controller Adapter Transmitter
 *
 * This is the transmitter side code for the adapter set.
 */

#include <SNESpadDual.h>
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>

// Hardware Configuration
RF24 radio(9,10);
SNESpad nintendo = SNESpad(4,3,5,6);

// Variable Inits
unsigned long state = 0;
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

void setup()
{

  //setup radio and serial debugging lines
  radio.begin();
  radio.setRetries(0,15);
  radio.enableDynamicPayloads();
  Serial.begin(57600);

  //setup radio pipes and put radio in listening mode
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(1,pipes[1]);
  radio.startListening();

  //Dump the configuration of the RF unit for debugging
  radio.printDetails();
}

void loop() {

  //check if radio has recieved ping from reciever and read data in
  int ready = 0;
  if (radio.available() ) {
    radio.read (&ready, sizeof(char));
  }

  //if ping has been recieved, read in button states and transmit
  if (ready) {

    //take radio out of listening mode
    radio.stopListening();

    // Get controller button states 
    state = nintendo.buttons();

    //debugging output - remove in final code
    Serial.println(~state, BIN);

    // Send button states to reciever
    bool ok = radio.write( &state, sizeof(unsigned long) );

    //debugging output - remove in final code
    if (ok) {
      Serial.println("transmission successful");
    }
    else {
      Serial.println("transmission failed!!");
    }

    //put radio back in listening mode to await next ping
    radio.startListening();
  }
}
share|improve this question
    
Can't really help, but I noticed that the ping sent is sizeof(int) but what is read is sizeof(char) (which is 1 by definition). –  William Morris Oct 13 '12 at 2:42
    
Also noticed that although you mentioned two 8-bit parallel to serial regs, you are doing a bitRead(state2,i) and bitRead(state2,i+16), implying a 16-bit reg. Also the data being transmitted is 32-bit so maybe the 16 is the right value... I don't really understand so I'm probably up the pole completely. –  William Morris Oct 13 '12 at 2:51
    
This might not directly help you, since you seem to be doing something a little different, but we have a way set up to use Wii controllers to control a SNES in this Github repo: github.com/AwesomeController/awesome_controller. You might be able to find something useful in here. –  user18607 Oct 23 '12 at 16:47
add comment

closed as off-topic by Jamal Feb 21 at 18:17

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Your question must contain working code for us to review it here. For questions regarding specific problems encountered while coding, try Stack Overflow. After getting your code to work, you may edit this question seeking a review of your working code." – Jamal
If this question can be reworded to fit the rules in the help center, please edit the question.

Browse other questions tagged or ask your own question.