Shop OBEX P1 Docs P2 Docs Learn Events
Using 8bit parallel char lcd with the Propeller. — Parallax Forums

Using 8bit parallel char lcd with the Propeller.

ihmechihmech Posts: 179
edited 2012-04-26 18:02 in Propeller 1
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. :-)

Comments

  • JonnyMacJonnyMac Posts: 9,197
    edited 2011-12-29 09:38
    I'd be leary of any object that uses *magic numbers* embedded into important parts of the program listing. After looking over my own code I see that what you have will only work for 2-line displays; the line 1 offset in display ram is 0 and line 2 offset is 64 ($40). The beginning of the DDRAM address space is $80 (128 in the code you list). Again, this bit of code will only work for 2-line displays. Many of us have written objects that will work with 1-, 2-, and 4-line LCDs.

    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.
    pub moveto(col, line) | ok, pos
    
    '' Moves DDRAM cursor to column, row position
    '' -- home position is indexed as 1, 1
    '' -- minimal error trapping
    
      ok := false
      
      if (col => 1) and (col =< LcdX)                               ' valid position?
        if (line => 1) and (line =< LcdY)
          pos := lookup(line : LINE1, LINE2, LINE3, LINE4)          ' convert line to DDRAM pos
          pos := pos + col - 1                                      ' add column
          cmd(pos)                                                  ' move  
          ok := true
        else
          ok := false
         
      return ok
    


    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.
  • MagIO2MagIO2 Posts: 2,243
    edited 2011-12-29 11:48
    I think there is no good reason for using the 8-bit mode! It only eats pins ;o) 4-bit is by far fast enough
  • ihmechihmech Posts: 179
    edited 2011-12-29 14:15
    MagIO2 wrote: »
    I think there is no good reason for using the 8-bit mode! It only eats pins ;o) 4-bit is by far fast enough

    I'm learning 8 bit first...then I'll get into 4 bit. Have to walk before we run.
  • ihmechihmech Posts: 179
    edited 2011-12-29 14:53
    Thanks JonnyMac, I'm fine with 2 line display code, all of the displays I have to work with are 2 line anyway. I just want to figure out the bare bones basics and then build from there. I want some understanding about what I'm working with since I'm just learning the Prop.

    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.
  • JonnyMacJonnyMac Posts: 9,197
    edited 2011-12-29 15:51
    It saddens me that you want to spend time studying bad code, but it's your time.

    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.
  • ihmechihmech Posts: 179
    edited 2011-12-29 20:32
    Thank you very, very much! I'm pretty new to the Propeller so I don't know what bad code is quite yet, but I do know I will soon learn. I found what bad code was when I was learning stamps and rewriting my own programs at a later date. What you laid out makes sense to me and I will sit down and work through it again to reinforce what I just learned.
  • ihmechihmech Posts: 179
    edited 2011-12-30 06:10
    Yes!!!! I get it now! I wrote in some instructions to put the cursor in several different positions and then returned it to the home position. Thank you very much for helping me understand!!

    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.
  • Cluso99Cluso99 Posts: 18,069
    edited 2011-12-30 10:45
    The way the LCD internal RAM is addressed on these is really stupid. I guess there was a reason when the chip was designed... maybe it was for a specific set of chars and lines. But anyway, we have to live with it not being sequential.

    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.
  • ihmechihmech Posts: 179
    edited 2012-04-23 19:29
    @ JonnyMac

    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!
  • frank freedmanfrank freedman Posts: 1,983
    edited 2012-04-23 22:29
    Cluso99 wrote: »
    The way the LCD internal RAM is addressed on these is really stupid. I guess there was a reason when the chip was designed... maybe it was for a specific set of chars and lines. But anyway, we have to live with it not being sequential.

    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.

    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.
  • ihmechihmech Posts: 179
    edited 2012-04-24 18:45
    I'm beating my head against the wall trying to figure out how to load custom characters to and from CGRAM on a HD44780 with a Prop. I've spent several days at this and I'm ready to give up. I've been studying any book or sections of code I can get my hands on with no luck. If anyone can help me or point me to resources that can help me I would greatly appreciate it.

    It's probably simple and I'm just not capable of understanding. I don't know why I can't seem to get it.
  • cavelambcavelamb Posts: 720
    edited 2012-04-24 19:07
    ihmech wrote: »
    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. :-)

    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.
  • JonnyMacJonnyMac Posts: 9,197
    edited 2012-04-24 20:02
    I'm beating my head against the wall trying to figure out how to load custom characters to and from CGRAM on a HD44780 with a Prop.

    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.
  • ihmechihmech Posts: 179
    edited 2012-04-24 20:09
    cavelamb wrote: »
    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.

    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.
  • ihmechihmech Posts: 179
    edited 2012-04-24 20:14
    JonnyMac wrote: »
    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.

    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.
  • JonnyMacJonnyMac Posts: 9,197
    edited 2012-04-24 20:17
    I understand that CGRAM address starts at $40 and goes up from there.

    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.).
  • ihmechihmech Posts: 179
    edited 2012-04-25 19:08
    Thank you so much!! I just sat down for a bit to work on it and it works. I was able to load and display a custom character. It looks like I wasn't having a problem loading a custom char, it was displaying it. I don't feel so stupid now, I was just missing something small.

    Thanks again!
  • JonnyMacJonnyMac Posts: 9,197
    edited 2012-04-26 10:37
    Excellent. Congrats.

    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.
    dat
    
    Prompt                  byte    ARROW,"Enter minutes: ", 0
    


    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.
  • ihmechihmech Posts: 179
    edited 2012-04-26 18:02
    Thanks for the tips. I'll give them a try.

    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.
Sign In or Register to comment.