Nokia PCD8544 (5110 LCD display) is a little strange
  • So, I bought one of these things to use with my first personal Arduino-based project.  Have it wired up to a prototype board now.  I'm using the display library from Adafruit, which seems to work ok, as far as it goes.  So, here's my question: when I put pixel values into an array of bytes, and tell the LCD to display them, it gets them quite mixed up.  It seems to help a little bit to actually order the array so that your pixels are listed in order top->bottom,left->right -- as opposed to the more conventional reverse of that, where you would put one row after the next.  Still, even this won't get the image quite right.  Does anyone have any idea what this display is trying to do with my pixel data? 

    There do appear to be one standalone and two online image converters, and the output of these converters -- at least, the output of this one -- displays properly on the screen.  I can't quite figure out how to do my own conversion and get it to work properly, though, and there appears to be absolutely no available information on the process.   I have managed to come up with a correct conversion this 16x16 pixel image(image), but when I try to scale things up, it breaks for some reason.  Does anyone know what these displays expect in terms of image data?  Also, does anyone know why the libraries haven't been specifically written to treat said data in a more sane manner? :)  It looks like these guys are using a setpixel function, but if my reading of the code is correct, they're really setting the location in the array, and not the location in the display; they just let the display shuffle things around on you.  Is there some kind of standard method of pixel-shuffling of which I'm unaware?

    Chris
  • I'm afraid that I don't have any personal experience with this LCD.   

    Have you followed the Adafruit tutorial on wiring and programming this display ( http://ladyada.net/products/nokia5110/ ) ?   They also have a support forum for LCD display issues, which is probably the best place to ask questions like these ( http://forums.adafruit.com/viewforum.php?f=47 ). There are several questions in the forums there that may be related, and it stands to reason that other people who have been through these issues do frequent these forums.

    -Windell 
  • Thanks Windell.  I did go through the tutorial, and everything works as advertised, but it doesn't seem to cover this subject.  I haven't tried their forum, but I did look through it to see if anyone else was talking about this, which they werent.  I've looked over the library several times and the impression it gives me is that this is all a straightforward matter of packing bits row wise into a byte array, but I haven't been able to get that to work as well as it should except in that one case I mention above.  Now there are two special things about that case.  First, the other images are larger than the test image that worked.  Next, I actually did the conversion by hand instead of using some scripts that _should_ do the same work.  To make a long story short, I'm beginning to suspect that the code that's supposed to build the array isn't doing what it's supposed to.  Maybe it's insisting on using signed values, or who knows.. I'm thinking about going through and writing a conversion script that does a little debugging.  That or something in c where I can guarantee the behavior.

    Chris
  • So, after going back and looking at the library, things are slightly stranger than I thought.  The drawBitmap function assumes that each byte
    you hand it is a column (yes, really) of 8 bits, but the columns are
    written out from left to right, then top to bottom.  So the first byte
    represents the top, left column of 8 bits.  The second represents the
    one to the right of it, and so on.  It's quite odd.  It draws it back
    out with this code:

    void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 
    const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
    for (int16_t j=0; j<h; j++) {
    for (int16_t i=0; i<w; i++ ) {
    if (pgm_read_byte(bitmap + i + (j/8)*w) & _BV(j%8)) {
    drawPixel(x+i, y+j, color);
    }
    }
    }
    }

    Anyway, once you arrange your pixels in this way, they do show up in the correct spot on the screen.

    Chris

  • I should also note that the least significant bit of the number seems to become the top of the column, and then following pixels proceed downward to the most significant bit.

    Chris
  • Using 8x8-bit blocks for displaying is a method that dates back to at least the mid 80s - it makes writing text easier because you can write consecutive bytes from your character definition into consecutive bytes of "screen memory" to form a character. 

    I remember that some BBC micro display modes used 8-pixel rows stacked in 8s so that 8 bytes made a character. But then you are limited to 8-pixel wide characters.  By using 8-bit columns you make it easy to write fonts 8-pixels high by any arbitrary width.  I suppose that for less height you would still have one byte per column in the font definition and just mask off some of the bits when you display it. 

    I don't imagine that this will help you at all but I would guess at this as the reason.
  • That makes some sense now that you mention it.  Fonts tend to be stretched horizontally much more often than vertically.  I do also note that 48 is divisible evenly by eight, while 84 is not.  This means that if you're obsessive-compulsive enough to want to insist on your rows (or columns) always ending on a byte boundary, you'll need to draw column-wise on this display.

    Chris
  • It also makes horizontal scrolling easier because you can shift whole bytes around in screen memory to move one pixel horizontally or (if the setup allows) just shift the screen memory start pointer and tidy up the edges.
  • Well, you'd be able to do it a row at a time, where if you were doing 84 pixel rows, each set of two rows would have a byte split between them, so it would be equally easy to scroll off the edge by two rows, but it would be kind of a pain to do one.  Still, I think aesthetically, I'd prefer that they picked a direction and stuck with it.  If they're mapping everything column-wise, just do one screen column after the next, so that your image ends up needing a simple rotation in order to behave the way you think it should.  Start at the top left, draw the entire column straight down, and so on.  With a little bit of pointer magic, you could still make it reasonably easy to scroll something off the display.

    Anyway, that being said, it's now _just_ an aesthetic argument, since everything is working.  I'm looking at the way it handles text now, which has its own oddities.  The font that's built in is a 5x7 pixel font.  The entire font is packed into an array, and the text handling functions have the 5x7 hard-wired into them.  They'll resize it in multiples of two by drawing filled squares on the display instead of pixels, but that's pretty much it.  I'm thinking about trying to load in a larger font (at least to display numerics) and also support alternate languages, at least in such a way that you could use the display to render non-ascii characters in some way.

    Chris