Hi guys
I have a slight conundrum: An LCD 44780 efficiency one.
My current 65C02GPB rev B runs at 12MHz and works fine with my LCD 44780 mini-library code. However, I'm trying to make the code a little more efficient, primarily by removing the fixed timer delays and adding busy flag (BF) checks instead.
The delays work well, utilising a VIA T1 free running timer to interrupt every 5ms (quicker seemed unreasonable resource use) and decrement a memory location. The write cmd/chr LCD routine simply writes how many lots of 5ms it wants to wait to the memory location and then checks it until Z=1 (i.e. the location value is 0). Easy.
Looking at the BF, it requires the following:
RW=1, RS=0, E=0
Set DB0-7 as input (we're in 8 bit mode)
Loop:
set E = 1
set E = 0
Test bit 7 of DB0-DB7
Is 1? loop again, otherwise continue
The above doesn't work: It misses out commands and bytes. The delay version of the routines still work fine.
Looking at the data sheet, it requires 40us to execute the read operation if I'm not mistaken. At 12MHz that's 482 clock cycles (0.083us per cycle (@12MHz), 40us / 0.083 = 481.92). So, going to need a timer for that unless the NOP instruction wants to be my drinking buddy! As such, I might as well keep using the above T1 timer as-is? It's slower than needed and also is general purpose and not just for the LCD. I could use T2 one shot timer, but the whole point was to move away from timers
.
If I have the facts wrong about the timing/BF flag, my code is wonky (see below) or anyone has a different approach, can you let me know? This isn't the end of the world using timers - just wanted to be efficient and run it past a second set of eyes.
Code:
; Port B used for LCD DB0-7 set elsewhere
; Port A used for control pins (PA0=E, PA1=RS, PA2=RW)
LCD_E = %00000001
LCD_RS = %00000010
LCD_RW = %00000100
.LCD_CheckBusy2
PHA ; Be nice, save contents of A to stack as we're going to use A below
; Prep work:
; Change Port B for read (DB0 to 7)
STZ DEV_VIA_User_DDRB ; Set DDRB to read on all pins (=0 for input). We're actually after bit 7 as input, but setting them all saves some bytes
; Set the LCD control lines (E, RS, RW)
LDA DEV_VIA_User_IOA
ORA #LCD_RW || LCD_E ; Initialise E & RW (E = 1, RW = 1)
AND #~LCD_RS ; Initialise RS (RS = 0). Note: We're using LCD_RS, inverted, as a mask. Inversion denoted by '~'.
STA DEV_VIA_User_IOA
AND #~LCD_E ; Execute command (E = 0)
STA DEV_VIA_User_IOA
; Main checking loop:
.LCD_CheckBusy2Loop
ORA #LCD_E ; Bring E high in preparation for bringing it low (E = 1)
STA DEV_VIA_User_IOA
AND #~LCD_E ; Bring E low, executing the read (E = 0)
STA DEV_VIA_User_IOA
BIT DEV_VIA_User_DDRB ; BIT reads port B and copies bit 6 & 7 into bit 6 & 7 of the status register - we can test bit 7 this way
BMI LCD_CheckBusy2Loop ; if bit 7 is 1 then LCD is still busy & we loop around again
; clean up
LDA DEV_VIA_User_IOA
AND #~LCD_RW ; Set LCD to write mode (RW = 0)
STA DEV_VIA_User_IOA
LDA #$ff ; set port B back to write mode
STA DEV_VIA_User_DDRB
PLA ; Restore A
RTS