Skip to content

Instantly share code, notes, and snippets.

@evinjaff
Created May 24, 2023 02:21
Show Gist options
  • Save evinjaff/65406133b9823e21a53ba5cb11d8ec3c to your computer and use it in GitHub Desktop.
Save evinjaff/65406133b9823e21a53ba5cb11d8ec3c to your computer and use it in GitHub Desktop.
// NES Controller FSM implementation - By Evin Jaff (2023)
// Wrote this for funsies during a DnD session with friends because I was bored
// Wanted to see if I could write some code to emulate the NES Controller signals - might use this driver code for another project
// https://tresi.github.io/nes/
// https://www.nesdev.org/wiki/Standard_controller
//Preprocessed Pins
#define LATCH_PIN 4
#define CLCK_PIN 5
#define DATA_PIN 6
#define check_latch digitalRead(LATCH_PIN)
#define check_pulse digitalRead(CLCK_PIN)
//global vars
bool pulse_fall;
bool latch_fall;
unsigned int previous_pulse_state = 0;
unsigned int previous_latch_state = 0;
enum states {
IDLE,
A,
B,
SELECT,
START,
UP,
DOWN,
LEFT,
RIGHT
};
enum states curr_state;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
curr_state=IDLE;
pulse_fall = false;
latch_fall = false;
}
void loop() {
// put your main code here, to run repeatedly:
unsigned int pulse = check_pulse;
unsigned int latch = check_latch;
//Main loop pseudocode - Start in Idle before a Latch
//Wait for a HIGH on the latch, and then poll the controller for inputs
switch (curr_state){
case IDLE:
//check transition
if (latch){
curr_state = A;
}
break;
case A:
if(!latch_fall){
check_latch_fall(latch);
}
//check latch fall instead
if(pulse == 1){
pulse_fall = false;
latch_fall = false;
curr_state = B;
}
break;
case B:
if(!pulse_fall){
check_pulse_fall(pulse);
}
//signal states
//check latch fall instead
if(pulse == 1 && pulse_fall){
pulse_fall = false;
latch_fall = false;
curr_state = SELECT;
}
break;
case SELECT:
if(!pulse_fall){
check_pulse_fall(pulse);
}
//signal states
//check transition
if(pulse && pulse_fall){
pulse_fall = false;
curr_state = START;
}
break;
case START:
if(!pulse_fall){
check_pulse_fall(pulse);
}
//signal states
digitalWrite(DATA_PIN, 0);
//check transition
if(pulse && pulse_fall){
pulse_fall = false;
curr_state = UP;
}
break;
case UP:
if(!pulse_fall){
check_pulse_fall(pulse);
}
//signal states
digitalWrite(DATA_PIN, 0);
//check transition
if(pulse && pulse_fall){
pulse_fall = false;
curr_state = DOWN;
}
break;
case DOWN:
if(!pulse_fall){
check_pulse_fall(pulse);
}
//signal states
digitalWrite(DATA_PIN, 0);
//check transition
if(pulse && pulse_fall){
pulse_fall = false;
curr_state = LEFT;
}
break;
case LEFT:
if(!pulse_fall){
check_pulse_fall(pulse);
}
//signal states
digitalWrite(DATA_PIN, 0);
//check transition
if(pulse && pulse_fall){
pulse_fall = false;
curr_state = RIGHT;
}
break;
case RIGHT:
if(!pulse_fall){
check_pulse_fall(pulse);
}
//signal states
digitalWrite(DATA_PIN, 0);
//check transition
if(pulse && pulse_fall){
pulse_fall = false;
curr_state = IDLE;
}
break;
}
previous_pulse_state = pulse;
previous_latch_state = latch;
// Delay for stepping through polling
// delay(200);
}
//Code to make sure that a lingering HIGH on the latch doesn't skip the FSM state. Does this by checking every cycle if the latch has fallen to 0
void check_pulse_fall(unsigned int pulse){
if (previous_pulse_state == 1 & pulse == 0){
pulse_fall = true;
}
else if(pulse == 0){
pulse_fall = true;
}
else{
pulse_fall = false;
}
}
//Code to make sure that a lingering HIGH on the latch doesn't skip the FSM state. Does this by checking every cycle if the latch has fallen to 0
void check_latch_fall(unsigned int latch){
if (latch == 0){
latch_fall = true;
}
}
//debugging function
void print_state(enum states state){
switch (curr_state){
case IDLE:
Serial.println("IDLE");
break;
case A:
Serial.println("A");
break;
case B:
Serial.println("B");
break;
case SELECT:
Serial.println("SELECT");
break;
case START:
Serial.println("START");
break;
case UP:
Serial.println("UP");
break;
case DOWN:
Serial.println("DOWN");
break;
case LEFT:
Serial.println("LEFT");
break;
case RIGHT:
Serial.println("RIGHT");
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment