10BitWorks Homepage
 

Building a device that interfaces with an NES controller port and replays inputs recorded from an FCEUX FM2 movie (specifically speedruns from TAS).

todo-list

optional bits with VideoOverlayShield


Current code

NesController.pde

#include <Arduino.h>
 
#define clockPort A0
#define strobePort A1
#define dataPort A2
 
#define clockPin PINC
#define clockShift 0
#define strobePin PINC
#define strobeShift 1
#define dataDDR DDRC
#define dataPortPORT PORTC
#define dataShift 2
#define dataMask (B00000001 << dataShift)
 
#define indexButton_A 0
#define indexButton_B 1
#define indexButton_Select 2
#define indexButton_Start 3
#define indexButton_Up 4  
#define indexButton_Down 5
#define indexButton_Left 6
#define indexButton_Right 7
 
#define waitOneMicroSec __asm__("nopnt""nopnt""nopnt""nopnt""nopnt""nopnt""nopnt""nopnt""nopnt""nopnt");
 
#define writeBit 0
#define readBit 1
 
boolean switchBool = false;
 
#define NUM_KEYS 8
 
uint8_t keyButtonIndex[] = {indexButton_A, indexButton_B, indexButton_Start,
                      indexButton_Select, indexButton_Right, indexButton_Up,
                      indexButton_Left, indexButton_Down};
 
// This is to keep track of cycle for testing purposes
byte quarterStart = 0;
 
uint8_t buttonValuesOrig = B11111111;
 
void setup() {
  pinMode(strobePort, INPUT);
  pinMode(clockPort, INPUT);
  pinMode(dataPort, OUTPUT);
  pinMode(13, OUTPUT); 
    // dataPort Low
  dataPortPORT = (dataPortPORT & ~dataMask) | (B00000000 << dataShift);
}
 
void loop()
{
  if (quarterStart<30) {
   buttonValuesOrig = B11110111; //Start hit
   digitalWrite(13, HIGH);
  } else {
   buttonValuesOrig = B11111111; //No hits
   digitalWrite(13, LOW);
  }
  quarterStart++;
  if(quarterStart>60) quarterStart = 0;
 
  for(uint8_t duplicateCounter = 0; duplicateCounter < 7; duplicateCounter++)
  {
    byte buttonValues = buttonValuesOrig;    
    byte buttonValues2 = buttonValuesOrig;
    // We pre compute these values because we are going into a region of code 
    // were every instruction matters.
    byte firstValToWrite = (buttonValues & B00000001) << dataShift;
    buttonValues = buttonValues >> 1;
 
    while((strobePin & (1 << strobeShift)) == 0)
    {
      // wait
    }
 
     dataPortPORT =  (dataPortPORT & ~dataMask) | firstValToWrite;
     while((clockPin & (1 << clockShift)) == 1 )
     {
       // wait
     }
     waitOneMicroSec;
     // We are assuming that we only need to detect the drop to low
     // because it happens so fast.
 
    // shift by 1
     dataPortPORT = (dataPortPORT & ~dataMask) | (buttonValues & B00000001) << dataShift;
     buttonValues = buttonValues >> 1;
     //while( digitalRead(clockPort) == HIGH)
     while((clockPin & (1 << clockShift)) == 1)
     {
       // wait
     } 
     waitOneMicroSec;  
 
     // shift by 2
     dataPortPORT = (dataPortPORT & ~dataMask) | (buttonValues & B00000001) << dataShift;
     buttonValues = buttonValues >> 1;
     while((clockPin & (1 << clockShift)) == 1)
     {
       // wait
     }  
     waitOneMicroSec;    
 
      // shift by 3
     dataPortPORT = (dataPortPORT & ~dataMask) | (buttonValues & B00000001) << dataShift;
     buttonValues = buttonValues >> 1;
     //while( digitalRead(clockPort) == HIGH)
     while((clockPin & (1 << clockShift)) == 1)
     {
       // wait
     }  
     waitOneMicroSec;         
 
      // shift by 4
     dataPortPORT = (dataPortPORT & ~dataMask) | (buttonValues & B00000001) << dataShift;
     buttonValues = buttonValues >> 1;
     //while( digitalRead(clockPort) == HIGH)
     while((clockPin & (1 << clockShift)) == 1 )
     {
       // wait
     }  
     waitOneMicroSec;           
 
      // shift by 5
     dataPortPORT = (dataPortPORT & ~dataMask) | (buttonValues & B00000001) << dataShift;
     buttonValues = buttonValues >> 1;
     //while( digitalRead(clockPort) == HIGH)
     while((clockPin & (1 << clockShift)) == 1)
     {
       // wait
     }  
     waitOneMicroSec;            
 
      // shift by 6
     dataPortPORT = (dataPortPORT & ~dataMask) | (buttonValues & B00000001) << dataShift;
     buttonValues = buttonValues >> 1;
     //while( digitalRead(clockPort) == HIGH)
     while((clockPin & (1 << clockShift)) == 1)
     {
       // wait
     }  
     waitOneMicroSec;         
 
     // shift by 7
     dataPortPORT = (dataPortPORT & ~dataMask) | (buttonValues & B00000001) << dataShift;
     //buttonValues = buttonValues >> 1;
       uint16_t maxTotalIterations1 = 50;
     //while( digitalRead(clockPort) == HIGH)       
       while((clockPin & (1 << clockShift)) == 1 && maxTotalIterations1 !=0)
       {
         // wait
         maxTotalIterations1--;
       }           
     // We are assuming that we only need to detect the drop to low
     // because it happens so fast.
 
    dataPortPORT = (dataPortPORT & ~dataMask) | (B00000000 << dataShift);
  }
    /// Done with crazy speed region
 
}

Credits to the MezzoMill crew for their Arduino NES Controller and associated code.

nesarduino.txt · Last modified: 2012/01/30 01:20 by Nam-Ereh-Won
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Noncommercial-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki