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
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.