68008 SBC LCD Control
The following is my first attempt at controlling the LCD on my Wichit Sirichote (URL updated 2024 to new website) 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