;***********************************************
; LCD tester for Single Chip using PORT-A 4-bit*
; Data=PORTB --- Control=PORTD		       *
;***********************************************

;*************************************************************************
; LCD PIN CONFIGURATION:
;------------------------------------------------------------------------
; 1. GND	7.  D0
; 2. VCC	8.  D1
; 3. VLCD 	9.  D2	  VLCD    => LCD Brightness Intensity (TYPICAL=GND)
; 4. R'/S	10. D3	  RS      => 0=Instruction Register, 1=Data Register
; 5. R/W'	11. D4	  RW      => 0=Write, 1=Read
; 6. E_Clock	12. D5	  E_clock => 0=Disable, 1=Enable
; 		13. D6
; 		14. D7

; D0..D4 =>	PORT-A 4..7
; RS	 =>	PC1
; RW	 =>	PC6
; E_LCD	 =>	PC7

;*************************************************************************
; RS RW	 Operation
;------------------------------------------------------------------------
; 0  0	 Write Function Command (Display, Clear, etc)
; 0  1	 Read Busy Flag
; 1  0	 Write Data Register to Display Data RAM/Char Generator RAM
; 1  1	 Read DDRAM/CGRAM to Data Register

;*************************************************************************
; RS RW	D7..D0	Function Command
;------------------------------------------------------------------------
; 0  0   01	Clear display and Return home
; 0  0   02	return home (position line-1 & char-1)

; 0  0   04	Shift left,	   display not shift (overwrite mode)
; 0  0   05	Cursor move left,  display shift (insert mode)
; 0  0   06	Shift right,	   display not shift (overwrite mode)
; 0  0   07	Cursor move right, display shift (insert mode)

; 0  0   08	Display OFF
; 0  0   0C	Display ON
; 0  0   0D	Display ON, Cursor OFF
; 0  0   0E	Display ON, Cursor ON  & not Blinking
; 0  0   0F	Display ON, Cursor ON  & Blinking

; 0  0   10	Shift cursor left
; 0  0   14	Shift cursor right
; 0  0   18	Shift Display left.  Cursor follow display shift
; 0  0   1C	Shift Display right. Cursor follow display shift

; 0  0   20	4 bit operation, 1 line, 5x8  dots, duty cycle 1/8
; 0  0   24	4 bit operation, 1 line, 5x10 dots, duty cycle 1/11
; 0  0   28	4 bit operation, 2 line, 5x8  dots {?? DC 1/16, bener nggak ??}
; 0  0   2C	4 bit operation, 2 line, 5x10 dots {??? bisa nggak ???}

; 0  0   30	8 bit operation, 1 line, 5x8  dots {?? DC 1/16, bener nggak ??}
; 0  0   34	8 bit operation, 1 line, 5x10 dots {?? DC 1/16, bener nggak ??}
; 0  0   38	8 bit operation, 2 line, 5x8  dots, duty cycle 1/16
; 0  0   3C	8 bit operation, 2 line, 5x10 dots {??? bisa nggak ???}

; 0  0   80-8F	Set cursor to Line-1, Char 1-16
; 0  0   C0-CF	Set cursor to Line-2, Char 1-16

; 0  0   02	Return home (position line-1 & char-1)
; 0  0   C0	Move cursor to second line (for 2 lines mode)
; 		1 line => 00H-4FH
; 		2 line => line-I: 00H-27H, line-II: 40H-67H

; 0  1   FF	Read busy flag (D7=1 busy, D7=0 not busy)
; 1  0   00-FF  Write data to CGRAM/DDRAM
; 1  1   00-FF  Read data from CGRAM/DDRAM


;***************************** EQU - DEF Definition ********************************
.nolist
.include	"8515def.inc"
.include	"Macro.asm"

.DSEG                       ; Start data segment 

.equ	RS		= 1 ; Bit PC.1
.equ	RW		= 6 ; Bit PC.6
.equ	EClock		= 7 ; Bit PC.7

.equ	BL		= 5 ; Bit PB.5

.equ	DataOut	 = PORTA
.equ	DataIn	 = PINA
.equ	DataDir	 = DDRA
.equ	Control	 = PORTC
.equ	CntrlDir = DDRC
.equ	BckLghtDir = DDRB
.equ	BackLight  = PORTB

.def	A=R16
.def	B=R17

.equ	RCursor     = $14
.equ	LCursor     = $10
.equ	RDisplay    = $1F
.equ	LDisplay    = $18
.equ	HomeLCD     = 2
.equ	ClearLCD    = 1
.equ	BarisDua    = $C0

;**************************** Main Program ******************************
.CSEG			; Start code segment
.org 0
	LDX	$25F		; X <= Stack Pointer init address
	out 	SPL,XL		; Setup Stack Pointer Low byte
	out 	SPH,XH          ; Setup Stack Pointer High byte

	ser	A
	out	CntrlDir,A
	out	DataDir,A
	out	BckLghtDir,A

	clr	A
	out	Control,A	; PD=output'0'

	rcall	Init_LCD

Screen:
	sbi	BackLight,BL
	rcall	Clear_Display
	LDZ	TABLE1*2
	rcall	KirimPesan_LCD

	rcall	Baris2_LCD
	LDZ	TABLE2*2
	rcall	KirimPesan_LCD

	cbi	BackLight,BL
DLY_131m:			; xtall 11.0592 = 124.77 ms
	ldi	A,50
	clr	B
	clr	R18
DLY:	DJNZ	R18,DLY
	DJNZ	B,DLY
	DJNZ	A,DLY

	rjmp	Screen


TABLE1:	.DB	"LCD Test Program",$F,0
TABLE2:	.DB	"Design By GunMan",$F,0

Init_LCD:
	sbi	Control,RW
	sbi	Control,RS
	cbi	Control,EClock

	ldi	A,220		; WAIT 15mS	(220*255*3Cycle = 168.960cycles = ±15.32ms)
	clr	B		; IF VCC=3V, WAIT 40mS: ldi A,??
LP_IN1:	DJNZ	B,LP_IN1	; DJNZ=3 cycle
	DJNZ	A,LP_IN1

	ldi	A,$28
	rcall	Kirim_Perintah
	ldi	A,$28
	rcall	Kirim_Perintah
	ldi	A,$28
	rcall	Kirim_Perintah

	ldi	A,$1          ;Display Clear
	rcall   Kirim_Perintah      ;

	ldi	A,$E          ;Display ON
	rcall   Kirim_Perintah      ;

	ldi	A,$6          ;Mode Increment Address
	rcall   Kirim_Perintah      ;
	ret

KirimPesan_LCD:
LoopKirimPesan_LCD:
	lpm	          ;Ambil data dari memori yg ditunjuk
	mov	A,R0
	CIJE	A,$F,selesai_kirim_LCD    ;Kirim ke LCD selama belum ditemukan
	rcall   Kirim_Karakter
	ld	A,Z+		;Tunjuk ke memori selanjutnya
	rjmp    LoopKirimPesan_LCD
selesai_kirim_LCD:
	ret

Kirim_Perintah:
	cbi	Control,RS
	cbi	Control,RW
	rcall   Kirim_DataLCD       ;4 bit sebanyak 2 x
	swap    A
	rcall   Kirim_DataLCD       ;
	rcall   PeriksaBusy
	ret

Kirim_Karakter:
	cbi	Control,RW
	sbi	Control,RS
	rcall   Kirim_DataLCD       ;ke LCD 2x
	swap    A
	rcall   Kirim_DataLCD       ;
	rcall   PeriksaBusy
	ret

Kirim_DataLCD:
	sbi	Control,EClock
	out	DataOut,A		; Kirim ke Port 0
	rcall	return			; delay 6 cycle (6*90ns=540ns)
	cbi	Control,EClock
return:	ret


PeriksaBusy:
	clr	A		;Jadikan PortA sebagai input
	out	DataDir,A

	cbi	Control,RS
	sbi	Control,RW	;LCD mode Read

BUSY:	rcall	Ambil_DataLCD
        push    A
        rcall	Ambil_DataLCD
        swap    A
        pop	B
	add	A,B

	JB	A,7,BUSY

	ser	A
	out	DataDir,A
	ret

Ambil_DataLCD:
	sbi	Control,EClock
	rcall	return		; delay 6 cycle (6*90ns=540ns)
	in	A,DataIn
	andi	A,$F0
	cbi	Control,EClock
	ret

Baris2_LCD:
	ldi	A,BarisDua
	rcall   Kirim_Perintah
	ret

Baris1_LCD:
	ldi	A,HomeLCD
	rcall   Kirim_Perintah
	ret

Clear_Display:
	ldi	A,ClearLCD
	rcall   Kirim_Perintah
	ret

GeserDisplay_Kanan:
	ldi	A,RDisplay
	rcall   Kirim_Perintah
	ret

GeserDisplay_Kiri:
	ldi	A,LDisplay
	rcall   Kirim_Perintah
	ret

GeserCursor_Kiri:
	ldi	A,LCursor
	rcall   Kirim_Perintah
	ret

GeserCursor_Kanan:
	ldi	A,RCursor
	rcall   Kirim_Perintah
	ret