Using 8bit parallel char lcd with the Propeller.
ihmech
Posts: 179
I've been pouring through every bit of documentation that I can get my hands on trying to learn how to use a parallel lcd. I have the HD44780 data sheet and other various resources along with studying different lcd drivers on the OBEX. My only lcd experience has been with a Parallax 2x16 serial display and I have several 2x24 parallel displays I would like to use.
I have most of it figured out, but for the life of me cannot figure out how this chunk of code works for char position.
PUB MOVE (X,Y) | ADR
' X : Horizontal Position : 1 to 16
' Y : Line Number : 1 or 2
ADR := (Y-1) * 64
ADR += (X-1) + 128
I don't understand how these two lines work.
ADR := (Y-1) * 64
ADR += (X-1) + 128
If anyone can give me some explanation in how char positioning works I would be grateful and so would my wife. She get's tired of me spreading books and papers all over the bed trying to figure this problem out. :-)
I have most of it figured out, but for the life of me cannot figure out how this chunk of code works for char position.
PUB MOVE (X,Y) | ADR
' X : Horizontal Position : 1 to 16
' Y : Line Number : 1 or 2
ADR := (Y-1) * 64
ADR += (X-1) + 128
I don't understand how these two lines work.
ADR := (Y-1) * 64
ADR += (X-1) + 128
If anyone can give me some explanation in how char positioning works I would be grateful and so would my wife. She get's tired of me spreading books and papers all over the bed trying to figure this problem out. :-)
Comments
If you have basic LCD functionality, then this may help you make more sense of what's happening. The constants used are the DDRAM addresses for the first character of each line.
This comes from my LCD object:
-- http://obex.parallax.com/objects/474/
My code uses a 4-bit interface, but this only affects a few of the methods (i.e., those methods that do hardware io). If you adjust those for your 8-bit interface you should have an object that does what you need. If you're looking for additional features, MagIO2 has written a PASM driver for LCDs that does lots of neat things.
I'm learning 8 bit first...then I'll get into 4 bit. Have to walk before we run.
PUB MOVE (X,Y) | ADR
' X : Horizontal Position : 1 to 16
' Y : Line Number : 1 or 2
ADR := (Y-1) * 64
ADR += (X-1) + 128
If X = 5 and Y = 2 then ADR is assigned 64 in this line of code " ADR := (Y-1) * 64 "? Then the next line would take ADR(64) and add it to " (X-1) + 128 " with a result of 197?
Is my math right or am I completely wrong. I'm just not understanding what is going on with the math and what the usable result is from this method.
This chunk of code has me feeling pretty stupid. I can get characters on the display without a problem, it's just understanding how to put them where I want. I would like to know what is going on step by step.
If you look at the command table in the HD44780 docs you'll see that you must set bit7 to move the cursor within the DDRAM (display ram) -- this is where the 128 comes from. Internally, that ram is organized such that the first character of the second line is offset by 64 bytes from the start of DDRAM. It should come together now. The values you're passing are 1-based, that is, the first character on the first line would be addressed as 1, 1. Doing the math
(1-1) * 64 = 0
0 + (1-1) + 128 = 128
-- which is the start of display ram. When you write this value in command mode (RS pin is low) the cursor will be moved to that position in ram. Subsequent writes will start there. In your example:
(2-1) * 64 = 64
64 + (5-1) + 128 = 196
Again, the key here is that bit7 of the value is set which causes the LCD controller to interpret the command as a cursor move within the DDRAM address space.
I'm sure I sound older than my 50 years when I say these things, but if you're going to bother studying code, find good stuff -- there's a lot of it out there.
It's not as complicated as I thought, once I understood that 128 is %1000_0000 putting a 1 in DB7, it made perfect sense.
Another trap I have found is that some LCDs swap the 3 pins RW, RS, E so make sure you check.
There are pros and cons for 4bit vs 8 bits. Obviously 8 bits is faster but this depends on your code and usually text is slow anyways, so the pins are more valuable.
I was able to get a basic lcd driver built and understand it pretty well. I rewrote it a week ago to clean it up, get more speed out of it, and add more features. I've been trying to pick your driver(jm_lcd4_ez.spin) apart trying to learn from it. I have had great success with my driver and I am having fun with adjusting and adding to it. I want to be able to load custom characters into the CGRAM and then later use them when needed. I've used custom characters quite a bit with a Stamp and a serial lcd. But I'm having a terrible time trying to understand how to do it with a Prop and a parallel lcd. Here is part of your code I can't seem to understand.
*********************************************************************************
pub setchar(c, pntr) | ok
'' Write character map data to CGRAM
'' -- c is the custom character # (0..7)
'' -- pntr is the address of the bytes that define the cahracter
if (c < 8) ' legal char # (0..7)?
cmd(CGRAM + (c << 3)) ' move cursor
repeat 8 ' output character data
out(byte[pntr++])
ok := true
else
ok := false
return ok
*********************************************************************************
If you or anyone else for that matter can help me I would really appreciate it greatly. I've been working on this problem for several days and it's keeping me up at night.
Thanks!
One bit two bit
Red bit blue bit.......
All depends on what you want to accomplish, and how many I/O pins you want to burn. If you want 2 or 3 bit use a shift register as I did. 4 bits seems cheapest and easiest if you can spare 7 I/O pins. 8 bit will wipe out a third of your I/O pins. Some one also did a 1 bit driver, but I never tried this as i was afraid there would be race conditions.
It's probably simple and I'm just not capable of understanding. I don't know why I can't seem to get it.
Well (obviously) they are setting bits 6 then 7.
No clue why - and Plus 1 on what JM said!
Take proper care of the little lady - then hit the data sheet.
Somewhere in there it will tell you why that works.
Why? It's actually quite easy -- and I've spelled it out for you in my object!
Remember:
-- set the cursor to the CGRAM space that you want to write to
-- write 8 bytes per character
My code does this -- all you have to do is pass a pointer to the block of bytes that defines your character. Maybe the attached demo will be helpful.
I'm past this trouble. Sorry, I should have started a new thread. I have most of my lcd driver built and understood. I can position the cursor anywhere I want, send text strings to the display, and have no problem with it. My big hangup now is trying to figure out the CGRAM. I've used a Stamp and a serial display quite a bit, but I'm not getting it with the Prop and a parallel display. I've made and used custom characters with a serial, but not a parallel.
I've been studying good code as JM said (it's his code). I keep reading my data sheet, books, code and I'm not getting it. I understand that CGRAM address starts at $40 and goes up from there.
I don't want a handout or someone to do the work for me. Believe me, I've been working! I don't ask questions until I've spent hours on a problem and can't get anywhere.
Thanks JonnyMac. I'll study this one too. I can probably figure it out soon with the demo code. I'm sorry for troubling any of you guys. I just needed a start in a good direction.
Remember, there's only 64 bytes of CGRAM (8 bytes per character). This puts character 0 at $40, character 1 at $48, character 2 at $50, etc. In my code the << 3 is multiplying the character number (0 to 7) by 8 and then adding that to the base address ($40). Why use <<? Because its a whole lot faster than * when using powers of 2 (2, 4, 8, 16, etc.).
Thanks again!
Here's a tip that I used on a recent project: if you want to embed a custom character into an pre-defined string, don't use character 0. For example, I have a constant called ARROW which is defined as 1, and custom character 1 is my arrow character map.
Steps:
-- create named constants for 1 - 7
-- create your custom characters; download to LCD
-- embed constant names into strings as shown above
-- use the .str() method to print
I have a version of my LCD code that includes access to six buttons for an HMI (human machine interface); it's worked quite well in two commercial projects.
I think my display may be a little goofy. I tried loading a custom character in each address to make sure everything was working fine. I can get a char loaded and displayed on 4 of the addresses. The other three either come up with a strange character or nothing at all. It's a factory new display in a sealed package, but since I got it on ebay it could have some small defects who knows. Or something happened to it when I soldered the ribbon cable to it. Other than that, it works just fine.