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();
}
}
sizeof(int)
but what is read issizeof(char)
(which is 1 by definition). – William Morris Oct 13 '12 at 2:42