6502-OS/system/lcd.s65

212 lines
5.7 KiB
Plaintext
Raw Normal View History

2023-10-26 19:51:20 +02:00
;********************************************************************************
; @module LCD-W164B
; @type driver
; @device ELECTRONIC ASSEMBLY - W164B-NLW
; @details
; Assumes it is connected to a W65C22N Interface Chip:
; - IO.RB0-7 -> LCD.D0-7 data lines
; - IO.RA5 -> LCD.RS register select
; - IO.RA6 -> LCD.R/W read/write
; - IO.RA7 -> LCD.E enable
;
; @requires LCD_IO: Base Address of IO Chip
; @optparam LCD_MEM: Address to a block of memory 1B. Default = $300
; @depends IO-W65C22N
;********************************************************************************
.ifndef LCD_IO
.fatal "LCD_IO is not defined: set it to the base address of the IO chip of the LCD"
.endif
.ifndef INCLUDE_IOW65C22
.error "IO-W65C22 module is not included"
.endif
2023-10-27 16:50:58 +02:00
.include "utility.h65"
2023-10-26 19:51:20 +02:00
; RAM VARIABLES
.ifndef LCD_MEM
LCD_MEM = $300
.endif
LCD_CHARCOUNT = LCD_MEM
; PIN MASKS
LCD_E = %10000000
LCD_RW = %01000000
LCD_RS = %00100000
; .local LCD_E,LCD_RW,LCD_RS
; LCD Instructions
LCD_CMD_CLEAR = %00000001 ; clear display
LCD_CMD_ENTRY_MODE = %00000110 ; auto-shift cursor
LCD_CMD_DISPLAY_ON = %00001111 ; everything on, with blinking cursor
LCD_CMD_FUNCTION_SET = %00111000 ; 8-bit, 4 lines, 5x7 font
LCD_CMD_SET_ADDRESS = %10000000 ; or with the address
; LCD Constants
LCD_LINE1 = $00 ; line 1
LCD_LINE2 = $40
LCD_LINE3 = $10
LCD_LINE4 = $50
LCD_CLEAR = %00000000
;********************************************************************************
; @function Initialize the lcd module
; @details call before doing anything else
;********************************************************************************
.proc lcd_init
; init IO
lda #$ff ; RB 0-7 output
sta LCD_IO+IO_DDRB
UT_update_with_mask LCD_IO + IO_DDRA, (LCD_RS | LCD_RW | LCD_E), (LCD_RS | LCD_RW | LCD_E)
; lda #(LCD_RS | LCD_RW | LCD_E) ; RA 5-7 output
; sta LCD_IO+IO_DDRA
; init lcd
lda #LCD_CMD_FUNCTION_SET
jsr _lcd_cmd
lda #LCD_CMD_DISPLAY_ON
jsr _lcd_cmd
lda #LCD_CMD_CLEAR
jsr _lcd_cmd
lda #LCD_CMD_ENTRY_MODE
jsr _lcd_cmd
stz LCD_CHARCOUNT
rts
.endproc
;********************************************************************************
; PRINTING TO LCD
;********************************************************************************
_lcd_clear: ; clear lcd
stz LCD_CHARCOUNT
lda #LCD_CLEAR
jsr _lcd_cmd
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1)
jsr _lcd_cmd
rts
;********************************************************************************
; @function Clear the display and print a null-terminated string
; @see lcd_print
;********************************************************************************
lcd_print_clear: ; clear lcd and print word located at message
stz LCD_CHARCOUNT
lda #LCD_CLEAR
jsr _lcd_cmd
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1)
jsr _lcd_cmd
;********************************************************************************
; @function Print a null-terminated string
; @param ARG0-1 Address of the string to print
;********************************************************************************
lcd_print:
ldx #$00
_lcd_print_loop:
lda (ARG0,x)
beq _lcd_print_end
jsr _lcd_char
inx
bra _lcd_print_loop
_lcd_print_end:
rts
;********************************************************************************
; LCD Commands
;********************************************************************************
; read busy flag
_lcd_wait_nbusy:
stz LCD_IO + IO_DDRB ; set IO1-LCD_IO + IO_RB to input
@lcd_wait_nbusy_loop: ; read the busy flag
lda #LCD_RW
sta LCD_IO + IO_RA
lda #(LCD_RW | LCD_E)
sta LCD_IO + IO_RA
lda LCD_IO + IO_RB
and #%10000000 ; and updates zero flag, if not set retry
bne @lcd_wait_nbusy_loop
lda #%00000000 ; TODO dont overwrite 0-4
sta LCD_IO + IO_RA
lda #%11111111 ; set IO1-LCD_IO + IO_RB to output
sta LCD_IO + IO_DDRB
rts
_lcd_cmd: ; send cmd in acc
pha
jsr _lcd_wait_nbusy
pla
; TODO use UT_update_with_mask?
sta LCD_IO + IO_RB
lda #LCD_CLEAR
sta LCD_IO + IO_RA
lda #LCD_E
sta LCD_IO + IO_RA
lda #LCD_CLEAR
sta LCD_IO + IO_RA
rts
_lcd_char:
pha
pha
; TODO use UT_update_with_mask?
jsr _lcd_wait_nbusy
pla
sta LCD_IO + IO_RB
lda #LCD_RS
sta LCD_IO + IO_RA
lda #(LCD_RS | LCD_E)
sta LCD_IO + IO_RA
lda #LCD_RS
sta LCD_IO + IO_RA
inc LCD_CHARCOUNT
jsr _lcd_set_address
pla ; put char back in a
;********************************************************************************
; Set the LCD DD-RAM Address so that text linebreaks after 16 chars
;********************************************************************************
_lcd_set_address:
; check if checks are necessary
lda LCD_CHARCOUNT
beq @lcd_line1
and #%10001111 ; ($10 | $20 | $30 | $40) = %01110000
bne @lcd_set_address_done
; checks necessary
lda LCD_CHARCOUNT
beq @lcd_line1
cmp #$10
beq @lcd_line2
cmp #$20
beq @lcd_line3
cmp #$30
beq @lcd_line4
cmp #$40 ; set to line1 when full ; set to line1 when full
beq @lcd_line1
@lcd_set_address_done:
rts
@lcd_line1:
stz LCD_CHARCOUNT
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE1)
jsr _lcd_cmd
rts
@lcd_line2:
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE2)
jsr _lcd_cmd
rts
@lcd_line3:
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE3)
jsr _lcd_cmd
rts
@lcd_line4:
lda #(LCD_CMD_SET_ADDRESS | LCD_LINE4)
jsr _lcd_cmd
rts