.include "system/lcd.h65" .ifndef lcd::LCD_IO .fatal "lcd::LCD_IO is not defined: set it to the base address of the IO chip of the LCD" .endif Export lcd,init,clear,print,print_char,set_position ; RAM VARIABLES .bss charcount: .res 1 .code ;;******************************************************************************** ;; @function Initialize the lcd module ;; @details call before doing anything else ;; @modifies A ;;******************************************************************************** .proc init ; init IO lda #$ff ; RB 0-7 output sta lcd::LCD_IO+IO::DDRB ; UT_update_with_mask IO + IO::DDRA, (RS | LCD_RW | LCD_E), (LCD_RS | LCD_RW | LCD_E) lda #(lcd::RS | lcd::RW | lcd::E) ; RA 5-7 output sta lcd::LCD_IO+IO::DDRA ; init lcd lda #lcd::CMD_FUNCTION_SET jsr _cmd lda #lcd::CMD_DISPLAY_ON jsr _cmd lda #lcd::CMD_CLEAR jsr _cmd lda #lcd::CMD_ENTRY_MODE jsr _cmd stz charcount rts .endproc ;;******************************************************************************** ;; PRINTING TO LCD ;;******************************************************************************** ;;******************************************************************************** ;; @function Clear the display ;; @see lcd_print ;; @modifies A ;;******************************************************************************** .proc clear stz charcount lda #lcd::CLEAR jsr _cmd lda #(lcd::CMD_SET_ADDRESS | lcd::LINE1) jsr _cmd rts .endproc ;;******************************************************************************** ;; @function Print a null-terminated string ;; @param ARG0-1 Address of the string to print ;; @modifies: A,Y ;;******************************************************************************** .proc print ldy #$00 @lcd_print_loop: lda (ARG0),y beq @lcd_print_end jsr print_char iny bra @lcd_print_loop @lcd_print_end: rts .endproc ;;******************************************************************************** ;; @macro Print a single character ;; @param A: Character to print ;;******************************************************************************** .proc print_char pha pha ; TODO use UT_update_with_mask? jsr _wait_nbusy pla sta lcd::LCD_IO + IO::RB lda #lcd::RS sta lcd::LCD_IO + IO::RA lda #(lcd::RS | lcd::E) sta lcd::LCD_IO + IO::RA lda #lcd::RS sta lcd::LCD_IO + IO::RA inc charcount jsr _break_line pla ; put char back in a .endproc ;;******************************************************************************** ;; Internal LCD Commands ;;******************************************************************************** ; read busy flag .proc _wait_nbusy stz lcd::LCD_IO + IO::DDRB ; set IO1-IO + IO::RB to input @lcd_wait_nbusy_loop: ; read the busy flag lda #lcd::RW sta lcd::LCD_IO + IO::RA lda #(lcd::RW | lcd::E) sta lcd::LCD_IO + IO::RA lda lcd::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::LCD_IO + IO::RA lda #%11111111 ; set IO1-IO + IO::RB to output sta lcd::LCD_IO + IO::DDRB rts .endproc ;;******************************************************************************** ;; @function Send a command to the lcd ;; @param A: command ;; @modifies A ;;******************************************************************************** .proc _cmd ; send cmd in acc pha jsr _wait_nbusy pla ; TODO use UT_update_with_mask? sta lcd::LCD_IO + IO::RB lda #lcd::CLEAR sta lcd::LCD_IO + IO::RA lda #lcd::E sta lcd::LCD_IO + IO::RA lda #lcd::CLEAR sta lcd::LCD_IO + IO::RA rts .endproc ;;******************************************************************************** ;; @function Set the cursor to a position ;; @param A: cursor position: `(lcd::LINEX + offset)`, where offset € [$0, $f] ;; @details: ;; If the position is too large, it will be set to char 5 in line 2 ;; @returns A: the cursor position ;;******************************************************************************** .proc set_position cmp #$40 bge @invalid sta charcount pha ora #lcd::CMD_SET_ADDRESS jsr _cmd pla @rts: rts @invalid: lda $14 sta charcount lda #(lcd::CMD_SET_ADDRESS | (lcd::LINE2 + 4)) jsr _cmd lda #(lcd::LINE2 + 4) bra @rts .endproc ;;******************************************************************************** ;; @function Set the LCD DD-RAM Address so that text linebreaks after 16 chars ;;******************************************************************************** .proc _break_line ; check if checks are necessary lda charcount beq @line1 and #%10001111 ; ($10 | $20 | $30 | $40) = %01110000 bne @rts ; checks necessary lda charcount beq @line1 cmp #$10 beq @line2 cmp #$20 beq @line3 cmp #$30 beq @line4 cmp #$40 ; set to line1 when full bge @line1 @rts: rts @line1: stz charcount lda #(lcd::CMD_SET_ADDRESS | lcd::LINE1) jsr _cmd rts @line2: lda #(lcd::CMD_SET_ADDRESS | lcd::LINE2) jsr _cmd rts @line3: lda #(lcd::CMD_SET_ADDRESS | lcd::LINE3) jsr _cmd rts @line4: lda #(lcd::CMD_SET_ADDRESS | lcd::LINE4) jsr _cmd rts .endproc