68008 SBC LCD Control

68008 SBC LCD Control

The following is my first attempt at controlling the LCD on my Wichit Sirichote Single Board Computer. Please forgive any terrible programming as I’m not very familiar with assembly language, and even less so with 68k assembly language programming. I’ve tried to make the code a little modular so the subroutines can be re-used. I previously described the software setup I’m using to program the board from Linux here. There are two versions of the same program (almost) in this post, the second of which animates the little stickman using interrupts for timing.

; Hardware Locations in Memory
gpio1		equ	$f0000		; LED PORT
lcdcw		equ	$60000		; LCD command WR
lcddw		equ	$60001		; LCD data WR
lcdcr		equ	$60002		; LCD command RD
lcddr		equ	$60003		; LCD data RD

; LCD Commands
lcdbsy		equ	$80		; LCD BUSY
lcd8bt		equ	$38		; Select 8 bits interface
lcdinc		equ	$06		; Entry Mode - Increment
lcddcb		equ	$0E		; Display On, Cursor On, Blink OFF
lcddnc		equ	$0C		; Display On, Cursor Off, Blink Off
lcdoff		equ	$08		; Display Off, Cursor Off
lcdclr		equ	$01		; Clear Display
lcd1st		equ	$80		; Set first line start
lcd2nd		equ 	$C0		; Set second line start

; Program location in memory
		org 	$400		; start of program

START
		move.l	#stack,a7	; sure
		move.w	#$2100,sr	; what these do
		bsr 	subinit		; initialise LCD
		bsr 	subcust		; send little man
		bsr 	subclr		; clear screen
		bsr 	subrow1		; go to home address
;send text
		lea	text1,A2	; get address of text string
		bsr 	subsend		; send the text located at A2
		bsr 	subrow2		; go to second line
		lea 	text2,A2	; next line text address
		bsr 	subsend		; send it
loop		jmp	loop		; forever

; ---------------------------------------------------

sublcdr	; wait for lcd ready
		movem.l	D0-D1,-(sp)
		move.w	#$ffff,D1
lcd_bu0
		move.b	(lcdcr),D0
		andi.b	#lcdbsy,D0
		beq.s	lcd_bu1
		dbra	D1,lcd_bu0
		moveq	#1,D1
lcd_bu1
		movem.l	(sp)+,D0-D1
		rts

subinit ; set up the display
		move.b	#lcd8bt,(lcdcw)	; write command $38 - 8 bit mode
		move.b	#lcd8bt,(lcdcw)
		move.b	#lcd8bt,(lcdcw)
		bsr	sublcdr		; wait for ready
		move.b	#lcdinc,(lcdcw)	; write command $06 increment cursor
		bsr	sublcdr
		move.b	#lcddnc,(lcdcw)	; display on, cursor off, blink off
		rts

subclr	; clear the display
		bsr	sublcdr		; wait for ready
		move.b	#lcdclr,(lcdcw)	; write command $01, clear display
		rts

subrow1	; go to first line
		bsr	sublcdr
		move.b	#lcd1st,(lcdcw)	; write command $80, first line start
		rts
	
subrow2	; go to second line
		bsr	sublcdr
		move.b	#lcd2nd,(lcdcw)	; write command $C0, first line start
		rts
	
subsend	; send string that starts at A2, and ends with zero
		movem.l	D0,-(sp)
ss1		bsr	sublcdr
		move.b	(A2)+,D0
		beq.s	senddone
		bsr	sublcdr
		move.b	D0,(lcddw)
		bra ss1			; blt next
senddone
		movem.l	(sp)+,D0
		rts

subcust	; create and send a custom character
			bsr	sublcdr
			move.b	#$48,(lcdcw)	; custom char 0 edit
			lea man,A2		; send data for man (note, can't have 0 in data)
			bsr	subsend
			rts

; string to display, terminating with zero
text1		dc.b	'This is a M68008',0
text2		dc.b	1,' Doing Stuff! ',1,0	; 1 gives special char 1. (a little man)
man			dc.b	%01110,%01110,%00100,%01110,%10101,%00100,%01010,%01010,0

ram	ds.b	32		; not sure
stack		equ	*	; what these do

This second version uses interrupts for timing a simple animation, but there is more code that I do not understand in it, so please forgive me if there are non-critical errors. The code isn’t very efficient in its use of data registers.

; Hardware Locations in Memory
gpio1		equ	$f0000			; LED PORT
lcdcw		equ	$60000			; LCD command WR
lcddw		equ	$60001			; LCD data WR
lcdcr		equ	$60002			; LCD command RD
lcddr		equ	$60003			; LCD data RD

; LCD Commands
lcdbsy		equ	$80			; LCD BUSY
lcd8bt		equ	$38			; Select 8 bits interface
lcdinc		equ	$06			; Entry Mode - Increment
lcddcb		equ	$0E			; Display On, Cursor On, Blink OFF
lcddnc		equ	$0C			; Display On, Cursor Off, Blink Off
lcdoff		equ	$08			; Display Off, Cursor Off
lcdclr		equ	$01			; Clear Display
lcd1st		equ	$80			; Set first line start
lcd2nd		equ 	$C0			; Set second line start

; Program location in memory
		org 	$400			; start of program

START
		move.l	#service_level2,$68	; not
		move.l	#stack,a7		; sure
		move.w	#$2100,sr		; what these do
		move.b	#$0,d2
		move.b	#$0,d3
		move.b	#0,d4
		bsr 	subinit			; initialise LCD
		bsr 	subcust			; set up little man in char 1 & 2
		bsr 	subclr			; clear screen
		bsr 	subrow1			; go to home address
;send text
		lea	text1,A2		; get address of text string
		bsr 	subsend			; send the text located at A2
loop		cmpi.b	#1,d4			; Don't re-send if you've already done so
		bge	loop			; loop if already shown
		bsr	subrow2			; pre-move to the start of the second line
		cmpi.b	#1,d3		
		blt	alt			; go to alt if d3<1
		lea 	text2,A2		; send text2
		bsr 	subsend			; send it
		move.b	#1,d4
		bra	loop
alt		lea	text3,A2		; send text3
		bsr	subsend
		move.b	#1,d4
		bra	loop			; forever - note jmp is an absolute address, bra is rel

; ---------------------------------------------------

service_level2
		addi.b	#1,d2		; increment d2
		cmpi.b	#50,d2		; check if d2 is 50 or more
		blt	skip		; rte if not 50
		clr.b	d2		; reset d2 to 0
		move.b	d3,gpio1	; debug code - shows status on leds
		clr.b	d4		; reset "don't send again" value
		addi.b	#1,d3		; increase d3 (which line 2 to send)
		cmpi.b	#2,d3		; check if d3 is too big
		blt		skip	; if it isn't, finish
		clr.b	d3		; if it is, make it = 0
skip		rte			; return

sublcdr	; wait for lcd ready
		movem.l	D0-D1,-(sp)
		move.w	#$ffff,D1
lcd_bu0
		move.b	(lcdcr),D0
		andi.b	#lcdbsy,D0	; check if the lcd is busy
		beq.s	lcd_bu1
		dbra	D1,lcd_bu0
		moveq	#1,D1
lcd_bu1
		movem.l	(sp)+,D0-D1
		rts

subinit ; set up the display
		move.b	#lcd8bt,(lcdcw)	; write command $38 - 8 bit mode
		move.b	#lcd8bt,(lcdcw)
		move.b	#lcd8bt,(lcdcw)
		bsr	sublcdr				; wait for ready
		move.b	#lcdinc,(lcdcw)	; write command $06 increment cursor
		bsr	sublcdr
		move.b	#lcddnc,(lcdcw)	; display on, cursor off, blink off
		rts

subclr	; clear the display
		bsr	sublcdr				; wait for ready
		move.b	#lcdclr,(lcdcw)	; write command $01, clear display
		rts

subrow1	; go to first line
		bsr	sublcdr
		move.b	#lcd1st,(lcdcw)	; write command $80, first line start
		rts
	
subrow2	; go to second line
		bsr	sublcdr
		move.b	#lcd2nd,(lcdcw)	; write command $C0, first line start
		rts
	
subsend	; send string that starts at A2, and ends with zero
		movem.l	D0,-(sp)
ss1		bsr	sublcdr
		move.b	(A2)+,D0
		beq.s	senddone
		bsr	sublcdr
		move.b	D0,(lcddw)
		bra 	ss1					; blt next
senddone
		movem.l	(sp)+,D0
		rts

subcust	; create and send a custom character
		bsr	sublcdr
		move.b	#$48,(lcdcw)	; custom char 0 edit
		lea 	man,A2		; send data for man (note, can't have 0 in data)
		bsr 	subsend
		rts

; --------------------------------------------------------


; string to display, terminating with zero
text1		dc.b	'This is a M68008',0
text2		dc.b	2,' Doing Stuff! ',1,0	; 1 gives special char 1. (a little man)
text3		dc.b	1,' Doing Stuff! ',2,0	; 2 gives special char 2. (a little man arms up)
man			dc.b	%01110,%01110,%00100,%01110,%10101,%00100,%01010,%01010,%01110,%01110,%10101,%01110,%00100,%00100,%01010,%01010,0

ram	ds.b	32		; not sure
stack		equ	*	; what these do