6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri May 17, 2024 9:41 pm

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
 Post subject: LCD efficiency conundrum
PostPosted: Sun Jan 09, 2022 12:55 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
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 :D.

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


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 09, 2022 3:02 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
You need to set it to read mode before your checking loop - it looks like right now you're leaving it in write mode.

Also I'd recommend setting the mode up first (RS and RW) then toggling E on in a separate operation, to ensure the RS and RW state is constant at the time E goes high. Edit: actually I see from your comments that E is triggered on the falling edge, so that's fine how it is.

Generally you can also move the idle check loop to before you write data rather than afterwards, so the CPU can get on with other things while the LCD is processing the data internally.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 09, 2022 4:57 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1930
Location: Sacramento, CA, USA
gfoot wrote:
Generally you can also move the idle check loop to before you write data rather than afterwards, so the CPU can get on with other things while the LCD is processing the data internally.

That may be a significant factor. Way, way back in the day I was modifying an assembler and noticed that it sent a char to the printer then waited for the printer to acknowledge before proceeding during the second pass. Flipping that code around resulted in a small but measurable performance improvement. That assembler did a lot of buffer zeroing and copying too, but improving that situation was much more tedious and bug-prone, and I eventually moved my attention elsewhere.

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 09, 2022 5:59 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
My calling code call:
(main code) JSR LCD_SendChr2 > immediately JSR LCD_CheckBusy2 > (do LCD Busy check) > RTS back to LCD_SendChr2 > Sends Chr to LCD > RTS back to main code
The LCD_SendChr2 routine is exactly the same as the delay one version (LCD_SendChr), except it has the timer delay JSR commented out and the JSR LCD_CheckBusy2 added in a line below it.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 09, 2022 6:24 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
Oh I see, the above is meant to just check for it being busy? I misunderstood because of your "execute command" comment, as this is not executing anything, it's just reading the status register.

The main bug you have, I think, is your BIT instruction is testing DDRB, whereas it should be testing ORB.

The "AND" and "STA" just before the loop are unnecessary but should do no harm.

For the tidy-up I would set E again, but it doesn't matter much.


Last edited by gfoot on Sun Jan 09, 2022 11:00 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 09, 2022 7:57 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
I was under the impression that DB7 is set or clear, depending on if the LCD is busy or not and if a read operation is done? Just to advise that Port B 0 to 7 is mapped to LCD DB0 to 7.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jan 09, 2022 11:00 pm 
Offline

Joined: Fri Jul 09, 2021 10:12 pm
Posts: 741
banedon wrote:
I was under the impression that DB7 is set or clear, depending on if the LCD is busy or not and if a read operation is done? Just to advise that Port B 0 to 7 is mapped to LCD DB0 to 7.

It is, but to read from port B you must read from the 6522's register 0 (ORB) not register 2 (DDRB). DDRB just defines the direction of each pin - ORB handles the data. (I said IRB before, but that's not the right name, the datasheet calls it ORB for both input and output.)


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 10, 2022 12:48 am 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
Whoops! One of those times when you read something back so many times you kind of don't actually "see" it, but instead what you think should be there.
Thanks for letting me know where I'd gone wrong - I was seeing IOB not DDRB :oops:.
I'll give it a test tomorrow.

[edit] Now appears to be working - so thanks for spotting that.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 12 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: