/* lcd_io4.Asm Copyright ©1998, 1999 Larry Barello Author: Larry Barello lbarello@accessone.com You are allowed to use this file for personal use only. You may use, embed, modify or distribute the contents of this file in any way you see fit as long as you include this copyright notice in the resulting file. Any commercial or industrial use including publishing or distributing in any form requires the written authorization of the copyright holder(s). No guarantees are made about fitness, functionality, correctness or performance of this file. The file is supplied on a "AS IS" basis, with no responsibility assumed by the author(s) for bug fixes, support, or damages of any sort arising from the use of this file. Contact the author with problem reports or fixes, feature requests or additions and questions. They are welcomed and will be incorporated as time and energy permits. */ #include "Registers.inc" #include "AVRIODEF.inc" MODULE LCDIO4 #include "lcdio.inc" PUBLIC lcd_wr_data lcd_put_char lcd_rd_data lcd_wr_inst PUBLIC lcd_wr_command lcd_rd_inst lcd_4_init PUBLIC lcd_PutHex lcd_PutHexWord lcd_PutHexByte lcd_putstr ; ; Hitachi LCD Control routines for industry standard LCD controllers. ; This code implements a flat (no stack usage) 4bit interface ; RSEG CODE ;+ ;---------------------------------------------- ; lcd_wr_data ; lcd_wr_command ; lcd_rd_data ; lcd_rd_command ; ; RD/WR LCD Data and Instruction. ; ; PASSED: T = Data/Instruction ; LCD_PARM = Write Data ; RETURN: LCD_PARM = Read Data ; Registers: LCD_TMP = scratch ; Stack: None ;- lcd_wr_data: lcd_put_char: cbi LCD_CTL, LCD_RW ; RW = 0 = WRITE sbi LCD_CTL, LCD_RS ; RS = 1 = DATA rjmp lcd_rw_rs lcd_rd_data: sbi LCD_CTL, LCD_RW ; RW = 1 = READ sbi LCD_CTL, LCD_RS ; RS = 1 = DATA rjmp lcd_rw_rs lcd_wr_inst: lcd_wr_command: cbi LCD_CTL, LCD_RW ; RW = 0 = WRITE cbi LCD_CTL, LCD_RS ; RS = 0 = INSTRUCTION rjmp lcd_rw_rs lcd_rd_inst: sbi LCD_CTL, LCD_RW ; RW = 1 = READ cbi LCD_CTL, LCD_RS ; RS = 0 = INSTRUCTION rjmp lcd_rw_rs lcd_rw_rs: in LCD_TMP, LCD_DATA_DDR andi LCD_TMP, ~0x0F out LCD_DATA_DDR, LCD_TMP ; make DATA an input port. in LCD_TMP, LCD_DATA_OUT andi LCD_TMP, ~0x0F out LCD_DATA_OUT, LCD_TMP ; get rid of any spurious pullups in LCD_TMP, LCD_CTL ; R/S and R/W state in LCD_TMP ; ; Check busy flag ; sbi LCD_CTL, LCD_RW ; RW = 1 = READ cbi LCD_CTL, LCD_RS ; RS = 0 = INSTRUCTION lcd_ck_bf: sbi LCD_CTL, LCD_E LCD_DELAY set sbis LCD_DATA_IN, LCD_BF ; T = state of BF clt cbi LCD_CTL, LCD_E LCD_DELAY sbi LCD_CTL, LCD_E LCD_DELAY cbi LCD_CTL, LCD_E LCD_DELAY brts lcd_ck_bf ; Loop while BF = 1 ; ; Restore R/S and R/W ; sbrc LCD_TMP, LCD_RS sbi LCD_CTL, LCD_RS ; RS = 1 = DATA sbrc LCD_TMP, LCD_RW rjmp lcd_rd lcd_wr: cbi LCD_CTL, LCD_RW ; RW = 0 = WRITE in LCD_TMP, LCD_DATA_DDR ; make DATA an output port. ori LCD_TMP, 0x0F out LCD_DATA_DDR, LCD_TMP ; ; 4 bit I/O Write operation (LCD_CTL restored) ; sbi LCD_CTL, LCD_E ; Raise E (do this before capture state ; of LCD_DATA_OUT in case same port used) in LCD_TMP, LCD_DATA_OUT ; Save a copy of high nibble andi LCD_TMP, ~0x0F ; mask out lower nibble swap LCD_PARM ; Put out High nibble first eor LCD_TMP, LCD_PARM ; add in PARM andi LCD_PARM, ~0x0F eor LCD_TMP, LCD_PARM ; cancel out lower nibble (in high position) out LCD_DATA_OUT, LCD_TMP LCD_DELAY ; Need to delay 500 ns (total) cbi LCD_CTL, LCD_E ; lower E LCD_DELAY ; Need to delay 500 ns swap LCD_PARM andi LCD_TMP, ~0x0F or LCD_TMP, LCD_PARM ; Low nibble sbi LCD_CTL, LCD_E out LCD_DATA_OUT, LCD_TMP LCD_DELAY ; Need to delay 500 ns (total) cbi LCD_CTL, LCD_E ret ; ; 4 bit I/O Read operation (LCD_CTL restored) ; lcd_rd: sbi LCD_CTL, LCD_E ; Raise E LCD_DELAY in LCD_PARM, LCD_DATA_IN cbi LCD_CTL, LCD_E ; Lower E andi LCD_PARM, 0x0F ; Read in high nibble first swap LCD_PARM LCD_DELAY sbi LCD_CTL, LCD_E LCD_DELAY in LCD_TMP, LCD_DATA_IN cbi LCD_CTL, LCD_E andi LCD_TMP, 0x0F or LCD_PARM, LCD_TMP ret ; ;-------------------------------------------------- ; ; lcd_4_init ; ; Switches reset LCD to 4 bit I/F mode. ; ; PASSED: Nothing ; RETURNS: ; USES: LCD_PARM (R24), LCD_TMP, T ; NOTES: Initial read of Busy Flag and write to controller is 8 bit, ; susequent i/o is 4 bit (dual r/w cycles). Need to do a second ; function set to get all bits to the lcd display. ; lcd_4_init: ldi LCD_PARM, LCD_CTL_DDR_INIT out LCD_CTL_DDR, LCD_PARM sbi LCD_CTL, LCD_RW ; RW = 1 = READ cbi LCD_CTL, LCD_RS ; RS = 0 = INSTRUCTION lcd_init_ck_bf: cbi LCD_CTL, LCD_E LCD_DELAY sbi LCD_CTL, LCD_E LCD_DELAY sbic LCD_DATA_IN, LCD_BF ; msb of nibble rjmp lcd_init_ck_bf ; Wait for busy flag to clear cbi LCD_CTL, LCD_E ; Switch to output mode cbi LCD_CTL, LCD_RW ; RW = 0 = READ in LCD_TMP, LCD_DATA_DDR ori LCD_TMP, 0x0F out LCD_DATA_DDR, LCD_TMP LCD_DELAY sbi LCD_CTL, LCD_E nop ; 1 cycle for Pin to reflect Port. in LCD_TMP, LCD_DATA_IN andi LCD_TMP, 0xF0 ; Set mode to 4 bit I/O ori LCD_TMP, (LCD_FUNCTION_SET>>4) out LCD_DATA_OUT, LCD_TMP LCD_DELAY cbi LCD_CTL, LCD_E ldi LCD_PARM, LCD_FUNCTION_SET rjmp lcd_wr_inst ; now set function via 4 bit I/O ;----------------------------------------- ;lcd_PutHex ; ; Passed: Y = Value, R24 = # digits ; RETURN: Nothing ; USES: R25, LCD_PARM ; STACK: 2 ; lcd_PutHex: ldi R25, 4 ; Maximum number of digits. lph00: lsl Yl rol Yh rol LCD_PARM lsl Yl rol Yh rol LCD_PARM lsl Yl rol Yh rol LCD_PARM lsl Yl rol Yh rol LCD_PARM cp R24, R25 brlt lph02 cbr LCD_PARM, 0xF0 subi LCD_PARM, -'0' ; Addi '0' cpi LCD_PARM, ('9' + 1) ; if > '9' brlt lph01 ; subi '9' and add 'A' subi LCD_PARM, ('9' + 1 - 'A') lph01: rcall lcd_put_char lph02: dec R25 brne lph00 ret ;----------------------------------------- ; Put out a hex word ; ; Passed: Y = word ; lcd_PutHexWord: ldi R24, 4 rjmp lcd_PutHex ;----------------------------------------- ; Put out a two ascii hex byte ; Yl = byte ; lcd_PutHexByte: ldi R24, 2 rjmp lcd_PutHex ; ;-------------------------------------------------- ; ; lcd_PutStr ; ; Puts out an ascii string to the LCD display ; ; PASSED: Z = pointer to string in CODE ; RETURNS: ; USES: LCD_PARM, R0 ; CALLS: lcd_put_char ; NOTES: ; lcd_putstr: lpm mov LCD_PARM, R0 tst LCD_PARM breq ps_x rcall lcd_put_char adiw Zl, 1 rjmp lcd_putstr ps_x: ret END