I made myself a character LCD driver (LCD has an HD47780 chipset) in hardware where data is predefined on a ROM, and I also made a circuit to load the ROM.
In the first image below, part of the Rom maker circuit (which I hook up to my computer through a parallel port) is wired up so that the data pins on the ROM are arranged as follows from LSB (least significant bit) to MSB (most significant bit):
A8,A9,A10,A11,A12,A13,A14,A0,A1,A2,A3,A4,A5,A6,A7
This next image is part of the LCD driver. The rom (made with the Rom maker) is inserted into the driver, and the shift registers are used to select the address and control RS (whether the LCD is in command or data mode).
The clock of the both shift registers is tied to one pin of the microcontroller as well as a timer that makes the LCD enable line go high for 220 microseconds with a time extension each time the clock logic level changes. The data inputs of the first register (INP) are tied together and also to another pin of the microcontroller. The CLR inputs are tied high to enable outputs.
I tested the first 256 bytes of data in rom with a rom tester I made and the output is correct, so I can't see my rom being the issue, so now I see the problem is with code.
This is my code:
LCDC equ (clock to the shift register GPIO pin) DAT equ (shift register data input pin)
;Inputs to function:
; RSLINE (0=want LCD command mode, 1=want LCD data mode)
; DPTR (15-bit address to data. highest bit ignored)
lcdwrite:
; Reset values
clr LCDC
clr LCDEOD
clr C
; (I might have screwed up here) Take low byte and shift left and save result to R7
mov A,DPL
rlc A
mov R7,A
; Shift high byte and let the MSB of the low byte be the LSB of the high byte and save to R5
mov A,DPH
rlc A
mov R5,A
; Take low shifted byte and shift the low 7 bits back and the new MSB is the RSLINE bit
mov A,R7
mov C,RSLINE
rrc A
; Shift low 8 bits into register
mov R7,#08h
shift8:
rlc A
mov DAT,C
nop
setb LCDC
nop
clr LCDC
nop
djnz R7,shift8
; shift high 8 bits into register
mov A,R5
mov R7,#08h
shift82:
rlc A
mov DAT,C
nop
setb LCDC
nop
clr LCDC
nop
djnz R7,shift82
nop
clr LCDC
mov R7,#0h
mov R5,#0h
;wait 40ms (micro is on a 20Mhz clock)
waitloop:
djnz R7,$
djnz R5,waitloop
inc dptr
ret
I simply call the function to issue commands with:
mov DPTR,(address of value)
clr RSLINE
lcall lcdwrite
or for data
mov DPTR,(address of value)
setb RSLINE
lcall lcdwrite
Some commands seem to execute (unless I'm getting my addressing mixed up), however when I try to print a normal character, I get a strange one instead.
For example, on my rom, I made the first 256 bytes of it filled with the same bytes (example: address zero has value 00h, address 255 has value 0FFh). If I execute:
mov DPTR,0038h
clr RSLINE
lcall lcdwrite
mov DPTR,0041h
setb RSLINE
lcall lcdwrite
I wanted to see a letter "A" appear on screen but nothing appears.
Is my coding correct? or could I improve on it?
I'm using the assembler from http://plit.de/asem-51/asemw.htm, so I don't know if it is just me or if some assemblers have bugs and that I should modify and/or eliminate some code to satisfy those assemblers.
Please advise.
Thanks.