Using an LCD

I would like to add an LCD to my computer, as it will give me a way of viewing characters that are outputted from programs.

The first two pins are power: VSS and VDD. V0 is for the contrast, which can be connected to ground, via a resistor. I will use a variable resistor, so I can fine tune the contrast. A and K are for the backlight of the display – A is for the anode and K is for the cathode. This can be connected directly to 5V because the LCD contains a current limiting resistor. Connecting will allow me to test the backlight and contrast is working. Now I want to connect the data lines, so I can send data to the LCD. D0 to D7 are the pins for the data lines. I will connect these to the data pins of the 6522.

Technically I could connect just 4 of the data pins! The LCD can be operated in either a 4-bit or 8-bit mode. The benefit of the 4-bit mode is that it frees up 4 connections, which could be valuable in a computer. However, there is a trade-off in speed, as it will take longer to get data to the LCD, when compared with the 8-bit mode.

There are controls signals that need connecting, RS, RW and E.

We can send data through the data lines to either an instruction register or a data register. Which one is used is determined by the register select (RS) pin. If RS is low then data will go to the instruction register, such as initialise the display or clear the display or move the cursor around. If register select is high, then the data goes into the data register, such as sending characters to the screen.

The read write pin (RW), such as reading whats in the data register.

The E (enable) pin has to be high for reading or writing to take place.

With all of these pins connected, I want to write a program to check that the LCD is working correctly.

PORTB = $6000
PORTA = $6001
DDRB = $6002
DDRA = $6003

E  = %10000000
RW = %01000000
RS = %00100000

  .org $8000

reset:
  ldx #$ff
  txs

  lda #%11111111 ; Set all pins on port B to output
  sta DDRB
  lda #%11100000 ; Set top 3 pins on port A to output
  sta DDRA

  lda #%00111000 ; Set 8-bit mode; 2-line display; 5x8 font
  jsr lcd_instruction
  lda #%00001110 ; Display on; cursor on; blink off
  jsr lcd_instruction
  lda #%00000110 ; Increment and shift cursor; don't shift display
  jsr lcd_instruction
  lda #$00000001 ; Clear display
  jsr lcd_instruction

  ldx #0
print:
  lda message,x
  beq loop
  jsr print_char
  inx
  jmp print

loop:
  jmp loop

message: .asciiz "Hello, world!"

lcd_wait:
  pha
  lda #%00000000  ; Port B is input
  sta DDRB
lcdbusy:
  lda #RW
  sta PORTA
  lda #(RW | E)
  sta PORTA
  lda PORTB
  and #%10000000
  bne lcdbusy

  lda #RW
  sta PORTA
  lda #%11111111  ; Port B is output
  sta DDRB
  pla
  rts

lcd_instruction:
  jsr lcd_wait
  sta PORTB
  lda #0         ; Clear RS/RW/E bits
  sta PORTA
  lda #E         ; Set E bit to send instruction
  sta PORTA
  lda #0         ; Clear RS/RW/E bits
  sta PORTA
  rts

print_char:
  jsr lcd_wait
  sta PORTB
  lda #RS         ; Set RS; Clear RW/E bits
  sta PORTA
  lda #(RS | E)   ; Set E bit to send instruction
  sta PORTA
  lda #RS         ; Clear E bits
  sta PORTA
  rts

  .org $fffc
  .word reset
  .word $0000