top of page
Writer's picturerehsd

6502 Basic Joystick

Updated: Feb 11, 2022


Most Arduino kits come with a basic joystick with an integrated push button. I had one these sitting around and decided to figure out how to interface it with my 6502 build, hoping to connect it to one of my VIAs.


The joystick has five connections: ground, power, x-axis, y-axis, and push button switch. As the joystick is an analog joystick, the x and y movement outputs a voltage on the associated pins that ranges from ~0V to ~5V. The 6502 and VIA are digital and work with 0V and 5V, having a middle ground that is neither high nor low. In the case of the W65C22S, low is anything from 0V to ~1.5V, and high is anything from 5V down to ~4V.


My first challenge was to convert the analog output of the joystick into a digital input for the VIA. To accomplish this, I used a set of simple voltage dividers and an LM339 comparator to split the analog joystick output into four signals -- left, right, up, and down. As the joystick is pushed in a direction, the associated signal will go high (see image below for an example of the vertical control analog to digital conversion). The joystick button press simply connects the switch (SW) signal to ground. At this point in the process, I had a momentary switch from the joystick and four digital outputs of the LM339. I pulled the joystick SW signal high with a pull-up resistor and ran the signal through a 74LS04 inverter. Now, I had five signals, each going high when their respective actions were taken: left, right, up, down, and press. I connected these five signals directly to PORTB of VIA2.

Using voltage dividers and the LM339 comparator to convert analog to digital
Using voltage dividers and the LM339 comparator to convert analog to digital

I still had the problem of letting the 6502 know when there was joystick interaction. I suppose I could have constantly polled the VIA port for the data, but I decided to use an interrupt. To get a single interrupt signal for the joystick, I ran all five joystick digital signals into a 74HC4078 8-input NOR gate. I connected the X output to CB1 on the VIA. Essentially, if any of the five joystick signals went high, the VIA CB1 interrupt would be pulled low (triggering the interrupt).


To finalize the hardware portion of the solution, I added an LED to the interrupt line from X to CB1. This would let me see when an interrupt was occurring (LED on = no interrupt; LED off = interrupt). The resulting schematic and breadboard circuit:






Now I needed to handle the interrupt in assembly code, read the joystick data, and do something with that data. As of this writing, the latest version of my ROM assembly is available here. Relevant portions:

;VIA2 Address Line A12
PORT2B = $5000
PORT2A = $5001
DDR2B  = $5002
DDR2A  = $5003
PCR2   = $500C
IFR2   = $500D
IER2   = $500E

;VIA Pins
JOYSTICK_DOWN           = %00000001
JOYSTICK_UP             = %00000010
JOYSTICK_PRESS          = %00000100
JOYSTICK_RIGHT          = %00001000
JOYSTICK_LEFT           = %00010000

lda #%10010000    ;Enable CB1 interrupt
sta IER2

lda #$00      ; Set all pins to input
sta DDR2B

irq: 
  pha ;a to stack
  phx ;x to stack
  phy ;y to stack
  BIT  IFR2			; Check status register for VIA2
  BMI  VIA2_IRQ			; Branch if VIA2 is interrupt source
  
VIA2_IRQ:               ;joystick
  lda PORT2B
  sta $69
  AND #JOYSTICK_DOWN
  bne Handle_Joystick_Down
  lda $69
  AND #JOYSTICK_PRESS
  bne Handle_Joystick_Press
  lda $69
  AND #JOYSTICK_LEFT
  bne Handle_Joystick_Left
  lda $69
  AND #JOYSTICK_RIGHT
  bne Handle_Joystick_Right
  lda $69
  AND #JOYSTICK_UP
  bne Handle_Joystick_Up
  ;falls into VIA2_IRQ_OUT

VIA2_IRQ_OUT:
  lda #$D0  ;delay duration, counting from $D0 to $FF
  sta delayDurationHighByte
  jsr Delay

  ;read the port. if still bits there, repeat the interrupt handler -      
                ;allows holding the joystick to keep cursor moving
  lda PORT2B
  cmp #$00
  bne VIA2_IRQ

  jmp irq_done
  
Handle_Joystick_Left:
  jsr RestoreCurrentPixelInfo
  ldx fill_region_start_x
  dex
  stx fill_region_start_x
  jsr StorePrevPixelInfo
  jsr DrawPixel
  jmp VIA2_IRQ_OUT
Handle_Joystick_Right:
  ...
Handle_Joystick_Press:
  ...
Handle_Joystick_Up:
  ...
Handle_Joystick_Down:
  ...
irq_done:
  ply ;stack to y
  plx ;stack to x
  pla ;stack to a
  rti

The Handle_xxx routines move a pixel around the screen and allow toggling of drawing as the pixel is moved. The result can be viewed in the following video.



I later implemented a USB mouse using very similar code, taking in the movement and button press signals directly from an Arduino (to which the mouse is connected).


For a future video, I could walk through the assembly code I have up to this point for drawing on the screen, using Ben's World’s worst video card. If that's of interest, let me know!


As will be the case with all of my posted mini-projects, I'm sure there is plenty of room for improvement. :)

282 views0 comments

Recent Posts

See All

Comments


bottom of page