Contents | Back: LCD Display | Next: Interrupts

We have a display to output information to the user, now we need a keyboard so that the user can type information into our system. I salvaged a keyboard PCB from an unused USB keyboard and trimmed away the part containing the original controller circuit. We only need the keys and the keyboard matrix circuitry. Now we need to decipher the keyboard matrix by tracing the connections or checking them with a continuity tester. In my case this keyboard needs 14 row output and 8 column input lines. The Fn and Windows are connected to an additional input line. We can use these keys for a "warm reboot" so that pressing them both will trigger an NMI interrupt.

Homecomputer 6502 V10 Keyboard 1 Homecomputer 6502 V10 Keyboard 2


The circuit is straightforward. We only need to connect all keyboard lines to IO pins of our VIAs.

Homecomputer 6502 V10 Keyboard Schematic

Download the Schematic PDF

Breadboard construction

Homecomputer 6502 V10 Keyboard Breadboard

Now this looks more like a real computer! Add a battery pack, put this all in an eclosure and you get a typical mobile computer system of the 1980s like the Epson HX-20 .


The keys_update function scans the whole keyboard, performs a simple debounce (read, wait, read again and compare) and stores the code of a pressed key in KEYS_CODE.

keys_update:      phaxy
                  jsr scan
                  cmp #$ff
                  bne @debounce
                  sta KEYS_CODE
@debounce:        sta KEYS_CODE
                  ldx #10
                  jsr delay_ms
                  jsr scan
                  cmp KEYS_CODE
                  beq @key_pressed
                  lda #$ff
                  sta KEYS_CODE
@key_pressed:     plaxy

The scan function enables one row after the other and reads its column value. For the first row that has a key pressed, the bit position of the column is calculated and #row * 8 is added. The resulting value is the position of the key in the matrix, i.e. the key code. If no key is pressed, $FF is returned.

scan:             ldx #13
@next_row:        jsr read_row
                  bne @row_pressed
                  bpl @next_row
                  lda #$ff
@row_pressed:     ldy #7
@next_column:     asl
                  bcs @column_found
                  bpl @next_column
@column_found:    tya
@add_row_offset:  dex
                  bmi @got_scan_code
                  adc #8
                  bne @add_row_offset
@got_scan_code:   rts

The read_row function activates a single row (sets it low) and reads and returns the corresponding column value.

read_row:         ; Set row X low
                  lda row_out_reg_lo,x
                  sta TMP0
                  lda row_out_reg_hi,x
                  sta TMP0 + 1
                  lda row_bit_mask,x
                  ldy #0
                  and (TMP0),y
                  sta (TMP0),y
                  ; Read column values
                  lda VIA2_IRA
                  eor #$ff
                  ; Set all rows high
                  lda #$ff
                  sta VIA2_ORB
                  lda VIA1_ORB
                  ora #$3f
                  sta VIA1_ORB

; Table of output register addresses for each row

row_out_reg_lo:   .byte VIA2_ORB, >VIA2_ORB, >VIA2_ORB, >VIA2_ORB, >VIA2_ORB, >VIA2_ORB, >VIA2_ORB, >VIA2_ORB
                  .byte >VIA1_ORB, >VIA1_ORB, >VIA1_ORB, >VIA1_ORB, >VIA1_ORB, >VIA1_ORB
; Table of output register bit masks for each row (with a 0 bit for the selected row)
row_bit_mask:     .byte <~VIA_PB0, <~VIA_PB1, <~VIA_PB2, <~VIA_PB3, <~VIA_PB4, <~VIA_PB5, <~VIA_PB6, <~VIA_PB7
                  .byte <~VIA_PB0, <~VIA_PB1, <~VIA_PB2, <~VIA_PB3, <~VIA_PB4, <~VIA_PB5


Homecomputer 6502 Keyboard PBC

I added the second VIA and the keyboard connector.

This page was last updated on 07. February 2016