Ok guys. I am able to write to a 44780 LCD module using a 65C22S VIA without issues. One thing that bothers me is that I'm having to write a delay routine which simply spams NOP commands between each write as LCD is not fast enough unless I run my PHI2 at 2MHz or below.
To address this I was going to use a timer, but as Garth has pointed out elsewhere I should be using the LCD's busy flag.
As such, I've tried writing some code to do this, but so far not got very far.
Here's my efforts so far:
NOTES:
- I know I should be using ORA and AND to flip selective bits rather than writing whole values, but it's easier to see what's going on when writing entire values. Will correct when I get the code right
- VIA_DDRA refers to the data direction register for port A of the VIA. This has been tested and works
- VIA_outA refers to the IRA/ORA register for the VIA. Again, it has been tested and works.
- The LCD is in 4 bit mode when this code is called
- Writing to the LCD works fine using the delay routine (delay40) which uses NOPs to delay the 65C02
- If the delay40 calls in the write character to LCD routine are replaced by calls to this code then the CPU never exits the busy flag checking loop in this code
Code:
# PA0-3 = LCD DB4 to DB7
# PA4 = E
# PA5 = R/W 0=ok for next op, 1=LCD is busy
# PA6 = RS 0=command, 1=data
# PA7 = not connected
SECTION -- LCD is ready for command check --
.checkLCDisvalid
# save A and the flags to the stack
PHA
PHP
# set LCD DB4-7 (VIA port A pins 0-3) to input as well as LCD RW (VIA port A pin 5) (VIA regards 1=output, 0=input)
LDA #%11010000
STA VIA_DDRA
# set LCD RW to read using VIA port A pin 5 = 1 (RW=Read)
# also, set LCD RS to command mode using VIA port A pin 6 = 0 (RS=Instruction mode)
# Set E to low in readiness to send command
LDA #%10100000
STA VIA_outA
# this loop simply keeps checking the busy flag of the LCD and exits when it's 0
.LCDvalidLoop
# send E high to send first part of read busy flag command
LDA #%10110000
STA VIA_outA
JSR delay40
# Set E low (bit 4) and then bring high to send second part of read busy flag command
LDA #%10100000
STA VIA_outA
LDA #%10110000
STA VIA_outA
# read port A - we need pin 3 (LCD DB 7)
LDA VIA_outA
# busy flag (db7, port A pin 3) needs to be 0 to carry on and not loop
# check to see if the bit is set to 1. If not then carry on. Otherwise loop
# if DB7 (BusyFLag) = 1 then LCD is busy. To check, BIT will perform an AND between the result of DB7
# and %00001000. This will reuslt in a 1 (for busy) or a 0 (for ok). If result=0 (ok) then Z flag=1.
# if result=1 (busy) then Z flag=0
# BNE branches if Z=0 (busy)
BIT #%00001000
BNE LCDvalidLoop
# set VIA port A back to output as we need to leave it ready to send commands or data to the LCD
LDA#%11111111
STA VIA_DDRA
# set VIA to RW=0 (write mode), E=0, RS=0 (command mode)
LDA #%00000000
STA VIA_outA
# restore the A register and the flags on routine exit
PLP
PLA
RTS