Page 1 of 1

NES Controller to VIA Question

Posted: Thu Jun 19, 2025 10:23 pm
by cbmeeks
I'm connecting two NES controllers to one VIA (65C22).

For those that don't know, the NES controllers essentially have a simple shift register in them. You set the latch pin, then clock it 8 times and you will get the 8-bit value of the buttons.

Since I want to drive two of them, I was thinking that I could use PA0 for CLOCK on both controllers (clock them at the same time). And PA1 for the latch on both controllers (latch them at the same time).

But each controller has a D0 (data) output pin. As I am clocking them, I need to capture two bits at the same time but split them out into two separate bytes. I hope that makes sense.

It would seem using the shift register of the VIA would be a good fit but I would need two of them.
So in theory, I should just need four pins.

Code: Select all

CLK
LATCH
D0
D1
Any suggestions?

Thanks!

Re: NES Controller to VIA Question

Posted: Fri Jun 20, 2025 10:00 am
by drogon
cbmeeks wrote:
I'm connecting two NES controllers to one VIA (65C22).

For those that don't know, the NES controllers essentially have a simple shift register in them. You set the latch pin, then clock it 8 times and you will get the 8-bit value of the buttons.

Since I want to drive two of them, I was thinking that I could use PA0 for CLOCK on both controllers (clock them at the same time). And PA1 for the latch on both controllers (latch them at the same time).

But each controller has a D0 (data) output pin. As I am clocking them, I need to capture two bits at the same time but split them out into two separate bytes. I hope that makes sense.

It would seem using the shift register of the VIA would be a good fit but I would need two of them.
So in theory, I should just need four pins.

Code: Select all

CLK
LATCH
D0
D1
Any suggestions?

Thanks!
Shift it in software.

I did this many years back on the Raspberry Pi with my wiringPi library. At the time I used 3 pins per controller but worked out how to do it with 2 pins plus one per controller. It was all done in software, clock then sampling the input pin once every 50µS. I found that any faster wasn't reliable, although I was running it all at 3.3v which was just inside the tolerance of the CMOS 4021N used in the controller. At 50µS per pulse, that's 400µS to read N joysticks. Not too shabby and worth experimenting with the timing if you need to.

My code is all in C, but may be of use for a single joystick case. Easy to change to multiple global variables or an array, one for each joystick, so a single VIA port could handle up to 6 joysticks. Here is the 'core' of it all:

Code: Select all

unsigned int readNesJoystick (int joystick)
{
  unsigned int value = 0 ;
  int  i ;

  struct nesPinsStruct *pins = &nesPins [joystick] ;
 
// Toggle Latch - which presents the first bit

  digitalWrite (pins->lPin, HIGH) ; delayMicroseconds (PULSE_TIME) ;
  digitalWrite (pins->lPin, LOW)  ; delayMicroseconds (PULSE_TIME) ;

// Read first bit

  value = digitalRead (pins->dPin) ;

// Now get the next 7 bits with the clock

  for (i = 0 ; i < 7 ; ++i)
  {
    digitalWrite (pins->cPin, HIGH) ; delayMicroseconds (PULSE_TIME) ;
    digitalWrite (pins->cPin, LOW)  ; delayMicroseconds (PULSE_TIME) ;
    value = (value << 1) | digitalRead (pins->dPin) ;
  }

  return value ^ 0xFF ;
}
-Gordon

Re: NES Controller to VIA Question

Posted: Fri Jun 20, 2025 12:15 pm
by cbmeeks
Very helpful, thanks!

Re: NES Controller to VIA Question

Posted: Fri Jun 20, 2025 5:11 pm
by Yuri
drogon wrote:
I found that any faster wasn't reliable...

Pretty much the entire circuit of the NES controller is a 4021 wired directly to the buttons. That IC is a 40 series version of the 74xx166, and tops out at about 12MHz according to the TI datasheet, vs. the 74LS version at 45Mhz.

I would either just do one at a time using the shift register CB1/CB2 pins and a couple of PAx pins, or you could put in two serial input registers like the 74xx164 or 74xx299. Personally I'm a fan of the 74xx299, which allows you to control the output of the parallel I/O pins directly.