Es probable que esto sea algo tonto cuando puedo esperar a que lleguen mis CD4021 (74HC165Ns) y evitarme la molestia, pero siento que esto se puede hacer y simplemente me estoy perdiendo algo. He estudiado detenidamente toda la documentación que puedo encontrar en la web sobre el protocolo del controlador de NES y cómo emular un registro de desplazamiento de salida en serie y salida de 8 bits de paralelo, pero parece que no logro que funcione correctamente. . Estoy usando interrupciones en el latch y las señales de reloj de la NES y bombeo los bits utilizando la manipulación del puerto, por lo que es un poco feo. Esta es también mi primera vez escribiendo algo similar. Puede que me esté equivocando.
¿Puede alguien decirme qué podría estar haciendo mal? Aquí hay algunos documentos sobre el protocolo NES: enlace y el protocolo SNES: enlace (más detallado pero ligeramente diferente, no estoy seguro en cuál confiar).
Aquí está mi código como está ahora:
#include <Arduino.h>
#define plPin PIND
#define latchPin 2
#define latchShift 2
#define dataPort PORTB
#define dataPin 8
#define dataShift 0
#define dataMask (B00000001 << dataShift)
byte origButtons = B11111111; // Set each bit low (0) to push button.
volatile byte buttons;
volatile byte bit_num = 0;
void setup() {
pinMode(dataPin, OUTPUT);
pinMode(latchPin, INPUT);
dataPort = (dataPort & ~dataMask) | (B00000000 << dataShift);
attachInterrupt(0, latch, CHANGE);
attachInterrupt(1, pulse, RISING);
delay(1);
}
void loop() {
}
void latch() {
// Check the state of the latch pin to see if we're rising (1) or falling (0).
if ((plPin & (1 << latchShift)) != 0) {
// Start pulled high.
dataPort = (dataPort & ~dataMask) | (B00000001 << dataShift);
} else {
// Pull low if A button is pressed at fall of latch pulse.
dataPort = (dataPort & ~dataMask) | ((buttons >> bit_num) & B00000001) << dataShift;
bit_num++;
}
}
void pulse() {
// On the rising edge of the clock pulse, check for the state of the next button.
// If the button is pressed, pull (or stay) low. Otherwise, pull high.
//
// Bit Math
// --------------
// Example values:
// dataPort: 11111111
// buttons: 11001100 (1 = HIGH/not pressed - 0 = LOW/pressed)
// bit_num: 3
// Reverse the dataMask (result: 11111011).
// AND that result to the current value of dataPort (result: 11111011).
// Shift buttons to the right by bit_num (result: 00011001).
// AND 00000001 to that result so the least significant digit is the value of the current button (result: 00000001).
// Shift that result by the data pin's position (result: 00000100).
// OR that with the result from ANDing the reverse of the data mask and the current value of dataPort - see 4 lines up (result: 11111111).
// Final result: button 3 not pressed.
if (bit_num == 7) {
// On the last pulse in a sequence, spit out the last button, wait until it has been sampled by the CPU, and reset the pin to the default low.
dataPort = (dataPort & ~dataMask) | ((buttons >> bit_num) & B00000001) << dataShift;
delayMicroseconds(12);
dataPort = (dataPort & ~dataMask) | (B00000000 << dataShift);
bit_num = 0;
} else {
// Otherwise, just spit out the current button and increment the offset.
dataPort = (dataPort & ~dataMask) | ((buttons >> bit_num) & B00000001) << dataShift;
bit_num++;
}
}