;********************************************************************
;====================================================================
; Program: Anim_1
; programmer(s): Dincer Aydin
; function:Demonstrates a simple animation on LCD.
; The animation is a rotating stick and displayed in multiple locations.
;====================================================================
;********************************************************************
; 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
	numofd 		equ 10h	        ; number of string bytes
	
; 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
	
; This part sends strings to the LCD:
; Two of the string bytes are ASCII Charater 0
; This is the first custom character of LCD
	ld 	hl,databegadr	; set HL to point the first string byte
	ld 	b,numofd	; put the number of string bytes to be sent in B
nextdata:			
	call 	sendchar	; send (HL) as string data 
	inc 	hl		; point the next string byte
	djnz	nextdata	; loop till all string bytes are sent

; The text and custom character #1 is displayed now
; The code below will modify CG RAM contents to create a simple 4-frame-animation
; This animation routine was tested with Z80 clocked at 2 MHz. For a different clock
; frequency it may be necessary to change the delay paramater. 

cycle:
	ld	e,4h		; use E to count the frames (4 frames in this case)
	ld   	hl,anim_data	; make (HL) point custom character data
next_frame:
	ld	b,8h		; each frame has 8 bytes of data
	ld 	a,40h		 
	call 	sendcomA	; Set CG RAM address to 00h by sendind 40h as a command
next_byte:
	call	sendchar	; write (HL) to CG RAM
	inc	hl		; point the next byte to be written to CG RAM
	djnz	next_byte	; loop till 8 bytes (1 frame/custom character) are sent
				
	push 	hl 		; save HL
	ld 	hl,4040h	; put delay parameter for "pdealy" routine into HL
	call    pdelay		; A frame was sent. Wait for while so that it can be seen.
	pop hl			; restore HL
	
	dec 	e		; decrease frame counter 	
	jp 	nz,next_frame	; loop till all frames are sent
	jp	cycle		; if all frames are sent ,start the the animation again
	
	


; ====================================================================
; 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
databegadr:
				; Custom character 0 "IT IS EASY" Custom character 0
	db 20h,00h,20h,49h,54h,20h,49h,53h,20h,45h,41h,53h,59h,20h,00h,20h
anim_data:
	db 4,4,4,4,4,0,0,0  ;  |
	db 16,8,4,2,1,0,0,0 ;  \
	db 0,0,31,0,0,0,0,0 ;  -
	db 1,2,4,8,16,0,0,0 ;  /
1