6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 8:55 pm

All times are UTC




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: LCD busy flag
PostPosted: Sat Jan 14, 2017 5:49 pm 
Offline
User avatar

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


Last edited by banedon on Sat Jan 14, 2017 8:22 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Sat Jan 14, 2017 7:02 pm 
Offline
User avatar

Joined: Tue Feb 10, 2015 5:27 pm
Posts: 80
Location: Germany
banedon wrote:
Code:
   # set LCD DB7 (port A pin 3) to input on the VIA port A pin 5 = 0 (1=output, 0=input)
   LDA #%11010000
   STA VIA_DDRA

By this you fix R/W as it was previously probably 0=Write?


Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Sat Jan 14, 2017 8:08 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
Yes sorry I have just noticed how confusing that must look - I'll correct it. Upon entry to the subroute the LCD is in write mode with the VIA port A pin 5 set to output and set to 0. This section switches VIA port A pins 0 to 3 and pin 5 to input mode. They correspond with DB4-7 and R/W on the LCD.


Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Sat Jan 14, 2017 8:22 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
You have a 40µs delay in there. The LCD needs 40µs to process certain things; but only 1µs to read the busy flag. If you re-arrange the bits and put the LCD's data bits 4-7 on VIAPA4-7 (VIA Port A's bits 4 to 7), you can use BIT to test bit 7 (where the busy bit will be), regardless of what's in the accumulator. The BIT instruction copies bit 7 into the N bit so you can branch on it with BMI or BPL. I've interfaced to these LCDs many times over the years, and in the 6502 primer, I have a sample 4-bit interface circuit at http://wilsonminesco.com/6502primer/potpourri.html#LCD, and sample code in various forms (4- and 8-bit interface, assembly language and Forth, directly on the bus and through a VIA) at http://wilsonminesco.com/6502primer/LCDcode.asm .

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Sat Jan 14, 2017 8:33 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
OK I'm thinking that not only do I have to send two sets of four bits for the command, I then have to read the two sets of 4 bits back with the first set containing DB7 as it is the MSB. Also (and as I originally thought) each section of the command is executed by a falling edge of E. I.e. E must be high and then go low. I'd misremembered which way around this was in the year since I last looked at this stuff.

[edit] I missed what Hobbit1972 was getting at. I had set the pin direction for the r/w pin on the VIA to input when it should be output. I've corrected that.


Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Sat Jan 14, 2017 8:58 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
If you read it, there's no command necessary except that the RS bit tells it what to read back to you, and the R/W bit tells it that you do want to read.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Sat Jan 14, 2017 9:00 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
New code. Seems to be working with PHI2 at 8MHz:

[edit] But not working at 10MHz :(. Code is running as my Bus Monitor shows code executing at the end of the test code segment, but althought the LCD screen looks like it has initialised (all 4 lines available instead of two ok and two not) no characters appear.
Maybe I do need those delays. As such, it sort of makes using the bust flag in 4 bit mode a bit useless lol. More testing ahead.

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
   # A and the flags are used in this routine
   # save A and the flags to the stack
   PHA
   PHP
   
   # set LCD DB7 (port A pin 3) to input on the VIA port A pin 5 = 0 (1=output, 0=input)
   LDA #%11110000
   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 #%10110000
   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 #%10100000
      STA VIA_outA   
      # Set E low (bit 4) and then bring high to send second part of read busy flag command
      LDA #%10110000
      STA VIA_outA
      LDA #%10100000
      STA VIA_outA
      # read port A - we need pin 3 (LCD DB 7). This is the MSB of the result
      LDA VIA_outA
      # save the flags to the stack as we need Z flag
      PHP
      # read the LSB of the result. We don't care about this as we need DB7 which is in the MSB
      LDA VIA_outA
      # restore the flags so we can test Z flag
      PLP
      # 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


Changes made:

- I removed the delay40's as my concern that they were needed was unfounded
- Changed the pin on the VIA connected to the LCD's RW pin to output when instead of input (thanks for the hint Hobbit1972 :))
- Changed the way E was used so that it executes commands by being high and then going low
- After both sets for 4 bits of the command are sent and executed, read *twice*. This gives MSB then LSB of result.


Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Sun Jan 15, 2017 11:47 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
I do not think it is valid to read data after the enable pulse has ended. The data hold time of a HD44780 is specified as 5 ns. Whatever you read 4 cycles later is hi-z and it will be coincidence wether the busy flag still shows correctly (static).

You need to set enable, wait for 160 ns (for which the LDA abs cycles until the input is gated may be enough already), then read the busy flag, then drop enable.

Attachment:
LCD_read_diagram.png
LCD_read_diagram.png [ 21.45 KiB | Viewed 1731 times ]

Attachment:
LCD_read_specs.png
LCD_read_specs.png [ 23.3 KiB | Viewed 1731 times ]

_________________
6502 sources on GitHub: https://github.com/Klaus2m5


Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Sun Jan 15, 2017 11:10 pm 
Offline
User avatar

Joined: Sun Sep 08, 2013 10:24 am
Posts: 740
Location: A missile silo somewhere under southern England
Hmm so I *do* need a timer if PHI2 various/is not set.

[update] Got it working at 10MHz. The issue was caused by the routine that sends commands/data to the LCD still using the old delay40 routine. I replaced the call to delay40 routine with one calling my new BF check.
I still need to test this at 16MHz (max clock my 65C02 GPD design runs at), but don't currently have a 32MHz oscllator can (the 32 is divided by 2 using a D type flipflop to give better rise & fall times). Got an AEL one on order from ebay. If things are still ok at that speed then I'll declare victory on that and start looking trying to implement I2C. To that end, I'll have a reread of Garth's primer.


Top
 Profile  
Reply with quote  
 Post subject: Re: LCD busy flag
PostPosted: Mon Jan 16, 2017 3:51 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
Be sure to do the LCD reset routine to get a consistently good reset. I show the procedure at http://wilsonminesco.com/6502primer/LCDcode.asm . Without it, the LCD may work sometimes and not others, making you think you got it going when really it won't always work, or make it look like the higher frequency isn't working when that was not the problem.

Continuing:
Quote:
Code:
   # 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 #%10110000
   STA VIA_outA

Be sure to leave E down after every read or write, and only change the RS and R/W bits when E is down, and never at the same time with raising or lowering E.

Quote:
Code:
   # 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 #%10100000
      STA VIA_outA   
      # Set E low (bit 4) and then bring high to send second part of read busy flag command
      LDA #%10110000
      STA VIA_outA
      LDA #%10100000
      STA VIA_outA
      # read port A - we need pin 3 (LCD DB 7). This is the MSB of the result
      LDA VIA_outA
      # save the flags to the stack as we need Z flag
      PHP
      # read the LSB of the result. We don't care about this as we need DB7 which is in the MSB
      LDA VIA_outA
      # restore the flags so we can test Z flag
      PLP

Didn't you want PHA and PLA instead of PHP and PLP here? I think you want the high nybble which is read first; but as shown, the next LDA permanently overwrites it. You've saved and restored the status, but then the BIT instruction below overwrites that status before it can get used. I think you wanted to save the accumulator, not the status.

Quote:
Code:
      # 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


Changes made:

- I removed the delay40's as my concern that they were needed was unfounded
- Changed the pin on the VIA connected to the LCD's RW pin to output when instead of input (thanks for the hint Hobbit1972 :))
- Changed the way E was used so that it executes commands by being high and then going low
- After both sets for 4 bits of the command are sent and executed, read *twice*. This gives MSB then LSB of result.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 5 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: