;************************************************************************
;========================================================================
; Program: Code template for using HD44780 based LCDs with Z80 and a 8255
; programmer(s):
; function:
;========================================================================
;************************************************************************
; This code requires a 2*16 LCD connected to a 8255 with base address of 00h
; routines sendcomA & sendcom & sendcharA & sendchar have been tested on 
; >> 2*16 Hitachi LCD with HD44780 chip 
; >> Samsung 1*16 LCD with a KS0062F00 chip
; >> 2*16 Epson LCD marked P300020400 SANTIS 1 ,and 
; >> noname 1*16 HD44780 based LCD.
; The Z80 was clocked at 2 MHz and 4,9152 MHz for each display.This was done 
; because the routines mentioned above take many t states and in most cases 
; that will be longer that the time a HD44780 will need to execute a command. 
;
; Connections:
; LCD data bus(pins #14-#7) connected to Port A of a 8255 with 00h base address
; LCD Enable pin(#6) connected to Port C bit #7
; LCD R/W pin(#5) connected to Port C bit #6
; LCD RS pin(#4) connected to Port C bit #5


;8255 port address(base 00h):	
	paadr 		equ 00h		; Address of PortA
	pbadr 		equ 01h		; Address of PortB
	pcadr 		equ 02h		; Address of PortC
	cwadr 		equ 03h		; Address of Control Word
;stuff to be written into the control word of the 8255:
;Some of the change the state of the ports and some manipulate
;bits on port C
	allpsin 	equ 9bh		; set all ports to input mode
	paincout 	equ 90h		; A input,C output,B output
	pandcout	equ 80h		; set all ports to output mode
	pacoutbin	equ 82h		; A output,C output,B input
	
;bit set/reset commands.These bits are the control signals for the LCD
	enable 		equ 0fh		; set portC bit #6
	disable		equ 0eh		; reset portC bit #6
	read 		equ 0dh		; set portC bit #5
	write 		equ 0ch		; reset portC bit #5
	command 	equ 0ah		; reset portC bit #4
	data 		equ 0bh		; set portC bit #4
	
; Define number of commands and length of string data
	numofc 		equ 4h		; number of commands

	
; initialization:		
	ld 	sp,200h 	; Set stack pointer
	ld 	c,cwadr 
	ld 	a,pacoutbin 	; Ports A&C output,B input
	out	(c),a

; *********It all begins here**********:
; This part sends commands to initialize the LCD
				
	call 	delay	
	ld 	a,38h		; function set command
	ld 	b,4		
again:	ld 	c,cwadr		
	ld 	d,command	
	out	(c),d		; select the instruction register 
	ld 	d,write
	out	(c),d		; reset RW pin for writing to LCD
	out	(paadr),a	; place the command into portA
	ld 	d,enable	
	out	(c),d		; enable the LCD
	ld 	d,disable
	out	(c),d		; disable the LCD 
	call	delay		; wait for a while
	djnz	again		; loop till the command is sent 4 times
	
; send commands to set input mode, cursor,number of lines ,and etc.
	ld 	hl,combegadr 	; set HL to point the first command
	ld 	b,numofc	; put the number of commands to be sent in B
nextcom:
	call 	sendcom		; send (HL) as a command 
	inc 	hl		; point the next command
	djnz 	nextcom		; loop till all commands are sent
	
; Initialization is complete.


; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;
;
;
; Insert your code here.
;
;
;
; >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
	


; ====================================================================
; Subroutine name:sendcomA & sendcom & sendcharA & sendchar 
; programmer:Caner Buyuktuna & Dincer Aydin
; input:A or (HL)
; output:
; Registers altered:A 
; function:	sendcharA sends the data in A to the LCD
;  	  	sendchar sends the data in (HL) to the LCD
; 		sendcomA sends the command in A to the LCD
;  		sendcom sends the command in (HL) to the LCD	
; ====================================================================
sendchar:
	ld 	a,(hl)		; put the data to be sent to the LCD in A
sendcharA:	
	push 	bc		; save BC
	push 	de		; save DE
	ld 	e,data		;  
	jp 	common

sendcom:
	ld 	a,(hl)
sendcomA:	
	push 	bc		; save BC
	push 	de		; save DE   
	ld 	e,command	   

common:	
	call 	bfcheck    	; See if the LCD is busy. If it is busy wait,till it is not.
	out 	(c),e		; Set/reset RS accoring to the content of register E
	ld 	d,write		
	out	(c),d		; reset RW pin for writing to LCD
	out	(paadr),a	; place data/instrucrtion to be written into portA
	ld 	d,enable	
	out	(c),d		; enable the LCD
	ld 	d,disable	
	out 	(c),d		; disable the LCD 
	pop 	de		; restore DE
	pop 	bc		; restore BC
	ret			; return
; ====================================================================
; Subroutine name:bfcheck
; programmer:Dincer Aydin
; input:
; output:
; Registers altered:D
; function:Checks if the LCD is busy and waits until it is not busy
; ====================================================================

bfcheck:
	push 	af		; save AF
	ld 	c,cwadr
	ld 	d,paincout
	out 	(c),d		; make A input,C output,B output
	ld 	d,read		
	out 	(c),d		; set RW pin for reading from LCD
	ld 	d,command
	out	(c),d		; select the instruction register 
check_again:	
	ld 	d,enable	
	out	(c),d		; enable the LCD
	in 	a,(paadr)	; read from LCD
	ld 	d,disable
	out 	(c),d		; disable the LCD 
	rlca			; rotate A left through C flag to see if the busy flag is set
	jp 	c,check_again	; if busy check it again,else continue
	ld 	d,pandcout	
	out	(c),d		; set all ports to output mode
	pop 	af		; restore AF
	ret

;====================================================================
; Subroutine name:DELAY and PDELAY
; programmer(s):Dincer Aydin
; input:the value in HL (for PDELAY only)
; output:-
; Registers altered:H,L
; function:delay 
; for more delay you can add a few nops or or some junk commands using the index 
; registers
; pdelay uses what you put into HL before you called the PDELAY routine 
;====================================================================

delay:	
	ld 	hl,1010h
pdelay:	
	dec	l
	jp 	nz,pdelay
	dec	h
	jp 	nz,pdelay
	ret

;====================================================================
; commands and strings
combegadr:
	db 01h,80h,0ch,06h  	; clear display,set DD RAM adress,
				; turn on display with cursor hidden,set entry mode


1