I'm trying to use an ATmega328 to interface with a NES controller, but I'm running into some issues.
The ATmega328 is programmed to pulse the latch pin, wired to the 4021's P/S pin, high for ~10 μs, then alternating between reading and storing the data pin (Q7 on 4021) and pulsing the clock pin. However, the ATmega328 only reads 0 for every shift, no matter what buttons are pressed on the controller.
Testing the controller using a breadboard (No ATmega328), some things I found were:
- When latch is high, data (Q7) reads the same as P7 (A button, high when released, low when pressed), and data sustains its value when latch is low. This is as expected, however, when latch is low and data is high, pulling P7 low pulls data low, but pulling P7 high does not pull data high, it instead stays low.
- When the clock has a rising edge, instead of shifting data to the next bit, data instead matches P7 like before, and the same applies where pulling P7 low pulls data low, but not back up.
- For any test I did, only P7 seemed to have any effect, and P0-6 did not seem to do anything at anytime.
The controller I am using is tested with and fully work with original hardware with all buttons.
Program that the ATmega328 is using:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
char unsigned buff[64];
uint8_t buffAvailable;
uint8_t buffIndex;
uint8_t buttonData;
uint8_t shiftRegister;
int main(void){
DDRD = 0b00001100;
sei();
UBRR0L = (uint8_t)(1 & 0xFF);
UBRR0H = (uint8_t)(1 >> 8);
UCSR0B |= (1 << RXEN0) | (1 << TXEN0) | (1<<RXCIE0);
sendByte(0x55);
sendByte(0xAA);
sendByte(0x88);
while (1) {
buttonData = 0x00;
shiftRegister = 0x00;
PORTD |= 0b00001000;
_delay_us(10);
PORTD &= 0b11110111;
buttonData |= (PIND & 0x10) >> 1;
shiftRegister |= (PIND & 0x10) >> 4;
shiftRegister <<= 1;
PORTD |= 0b00000100;
PORTD &= 0b11111011;
buttonData |= (PIND & 0x10) >> 2;
shiftRegister |= (PIND & 0x10) >> 4;
shiftRegister <<= 1;
PORTD |= 0b00000100;
PORTD &= 0b11111011;
buttonData |= (PIND & 0x10) >> 4;
shiftRegister |= (PIND & 0x10) >> 4;
shiftRegister <<= 1;
PORTD |= 0b00000100;
PORTD &= 0b11111011;
buttonData |= (PIND & 0x10) >> 3;
shiftRegister |= (PIND & 0x10) >> 4;
shiftRegister <<= 1;
PORTD |= 0b00000100;
PORTD &= 0b11111011;
buttonData |= (PIND & 0x10);
shiftRegister |= (PIND & 0x10) >> 4;
shiftRegister <<= 1;
PORTD |= 0b00000100;
PORTD &= 0b11111011;
buttonData |= (PIND & 0x10) << 1;
shiftRegister |= (PIND & 0x10) >> 4;
shiftRegister <<= 1;
PORTD |= 0b00000100;
PORTD &= 0b11111011;
buttonData |= (PIND & 0x10) << 2;
shiftRegister |= (PIND & 0x10) >> 4;
shiftRegister <<= 1;
PORTD |= 0b00000100;
PORTD &= 0b11111011;
buttonData |= (PIND & 0x10) << 3;
shiftRegister |= (PIND & 0x10) >> 4;
buttonData = ~buttonData;
//buttonData = PIND;
//sendByte(0xab);
while (buffAvailable > 0) {
char unsigned data = readByte();
switch(data) {
case 0x00:
sendByte(buttonData & 0xFC);
break;
case 0x01:
sendByte(0x00);
break;
case 0x02:
sendByte((buttonData & 0x03) << 3);
break;
case 0x03:
sendByte(buttonData & 0x80 ? (buttonData & 0x40 ? 0x80 : 0xFF) : (buttonData & 0x40 ? 0x00 : 0x80));
break;
case 0x04:
sendByte(buttonData & 0x20 ? (buttonData & 0x10 ? 0x80 : 0x00) : (buttonData & 0x10 ? 0xFF : 0x80));
break;
case 0x05:
sendByte(0x80);
break;
case 0x06:
sendByte(0x80);
break;
case 0x07:
sendByte(0x00);
break;
case 0x08:
sendByte(0x00);
break;
case 0x40:
sendByte(0x06);
break;
case 0xDE:
sendByte(buttonData);
sendByte(shiftRegister);
break;
case 0xFF:
sendByte(0x88);
break;
default:
sendByte(0x00);
break;
}
}
}
return(0);
}
ISR(USART_RX_vect) {
uint8_t b = UDR0;
uint8_t ind = (char*)(buffIndex+buffAvailable);
while (ind >= 0x40) ind -= 0x40;
buff[ind] = b;
buffAvailable++;
}
char readByte() {
char unsigned b = buff[buffIndex];
if (buffIndex == 0x3F) {
buffIndex = 0x00;
} else {
buffIndex++;
}
buffAvailable--;
return b;
}
void sendByte(char b) {
while(!(UCSR0A & (1 << UDRE0)));
UDR0 = b;
}
Using a serial monitor to send 0xDE to get shift register data
Schematic used:
simulate this circuit – Schematic created using CircuitLab
What could I be doing wrong?