The GDI library for Netduino targets a LCD module.

Posted by Mario Vernari Saturday, February 16, 2013 9:34:20 AM
Rate this Content 0 Votes

In this post I will show how the GDI library for Netduino can be used for a generic LCD character module (typically HD44780 driven).

The library abstracts the physical layer pretty well, although it’s rather hard to ignore the huge differences between a colored led-matrix and a back-and-white display.

First off, as said, the colors are just two: black and white. Better: blank and shaded, because there are LCDs which displays dark dots on a bright background, but also other models which displays bright dots on a dark background. To mimic the blending as in the led-matrix case, I considered the “Black” as blank (inactive) and the “White” as shaded (active).

Secondly, this kind of LCD module is structured as a character-matrix, so it has an intrinsic ability to display a character. For the led-matrix there’s a font-oriented character generator, which compose the character pattern using the display’s dots.

Thirdly, in a character-oriented LCD module, you cannot target a single “pixel” (meant as a single dot of a character). The “pixels” are something inaccessible from the outside interface, which understands the “character-entity” only, instead.

 

The hardware and the “old” LCD Boost library.

This project actually replaces the old LcdBoost library, but just for the software side. The hardware is still the same, because it works fine and it’s very fast compared to other solutions.

So, before dealing with the step-by-step tutorial, you should wire up the hardware. Here follows the Fritzing board-view of the circuit.

Netduino-LcdBoost_bb

 

Project setup.

The project setup is practically the same as seen in this article, except for the different driver project which has to be considered.

After linking the Cet.HW.GDI_MF42 project, you have to link the Cet.HW.Drivers.BoostHD44780_MF42 project. So, your solution should look like this:

tutorial8

 

Using the library.

I’ll follow a different sequence of functions than it was for the led-matrix. That’s because the typical usage of a character module: mainly display characters.

So, let’s start with the minimal program for displaying stuffs on the LCD.

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
 
using Cet.HW.GDI;
using Cet.HW.Drivers;
 
namespace NetduinoLcdGdi1
{
    public class Program
    {
 
        private static ICompositionRenderer _renderer;
 
 
        public static void Main()
        {
            //create a lcd-char driver instance
            _renderer = new BoostHD44780(
                cspin: Pins.GPIO_PIN_D8,
                config: BoostHD44780.Layout20x4);
 
            //creates the target composition instance
            var composition = _renderer.CreateTarget();
 
 
 
            //dumps the composition to the physical device
            _renderer.Dump(composition);
 
            //keep alive
            Thread.Sleep(Timeout.Infinite);
        }
 
    }
}

As you can see, it is not much different than the led-matrix case.

 

Understanding the colors.

As above mentioned, an HD44780 LCD module is monochromatic, thus there are just two colors: black and white. However, it’s better to mean the blending as “active” and “inactive”, because many LCD modules ship with negative screens.

As for the led-matrix where the “white” is composed by all three colors “active”, here is the same: the “activity” will be referred as “white”. This might lead to a little confusion, but I like more this rule other than relying on the actual screen color, which can be different upon the model.

The “activity” does not imply transparency. The “alpha channel” is supported in this case, but it’s just a “boolean” state, much more similar to the GIF’s transparency mask, other than a real “alpha-blending”. As for the led-matrix, a color will blend as “opaque” when its alpha byte-value is greater or equals 0x80 (=128).

NOTE: my LCD module is a standard positive-polarization glass, thus an “active” dot will display as dark. Again, bear in mind that the “activity” has to be specified as “white”.

 

Drawing a simple text.

As said, drawing text is the most trivial function to do.

Due the intrinsic ability of the LCD module to draw characters, it has no sense specifying a font, thus we’ll refer as “null”.

    public class Program
    {
 
        private static ICompositionRenderer _renderer;
 
 
        public static void Main()
        {
            //create a lcd-char driver instance
            _renderer = new BoostHD44780(
                cspin: Pins.GPIO_PIN_D8,
                config: BoostHD44780.Layout20x4);
 
            //creates the target composition instance
            var composition = _renderer.CreateTarget();
 
 
            //draw some text
            composition.DrawString(
                "Ciao!",
                null,
                Brushes.White,
                new Point(3, 0)
                );
 
 
            //dumps the composition to the physical device
            _renderer.Dump(composition);
 
            //keep alive
            Thread.Sleep(Timeout.Infinite);
        }
 
    }

Here is the result.

WP_000303

 

Displaying custom characters.

Often we need some custom shaped character which is not part of the internal char-set of the LCD module. The HD44780 yields the creation of up to 8 custom character, in the chip’s RAM. We may change those characters’ shape anytime, but no more than 8 different pattern can be displayed on a same screen.

The character can be shaped by defining a bitmap (i.e. a bit-matrix) as a byte-array, where the bits are the columns and the bytes are the rows. The LSB is the rightmost dot, as well the first byte represents the topmost row.

As in the below snippet, to create a custom “heart” character you may proceed with paper and pencil (or Excel, if you like more!), as follows:

lcd-custom-char

The grayed area indicates that no value is taken in account for this particular display, since it works on a 5 columns by 8 rows base.

 

Afterward, the definition of the new character is trivial:

    public class Program
    {
 
        private static ICompositionRenderer _renderer;
 
 
        public static void Main()
        {
            //create a lcd-char driver instance
            _renderer = new BoostHD44780(
                cspin: Pins.GPIO_PIN_D8,
                config: BoostHD44780.Layout20x4);
 
            //creates the target composition instance
            var composition = _renderer.CreateTarget();
 
 
            //create the "heart" custom character
            ((BoostHD44780)_renderer).DefineCustomCharacter(
                1,
                new byte[8] { 0x00, 0x0A, 0x1F, 0x1F, 0x1F, 0x0E, 0x04, 0x00 }
                );
 
            //draw some text
            composition.DrawString(
                new string((char)1, 3) + " Ciao amore! " + new string((char)1, 3),
                null,
                Brushes.White,
                new Point(0, 0)
                );
 
 
            //dumps the composition to the physical device
            _renderer.Dump(composition);
 
            //keep alive
            Thread.Sleep(Timeout.Infinite);
        }
 
    }

Here is the result.

WP_000302

NOTE: due to a limitation of the .Net Micro Framework, you should avoid using the character with code 0x00 (=NUL), because the string composition fails and/or yields unpredictable results.

My suggestion is using any code from 1 to 7, which have no problems at all. Whereas you need the 8th custom pattern, use zero as code in the pattern definition, but 0x0100 as actual char-code in the string. Since the Unicode code will be casted to a byte, the string works fine and the fed code to the display is actually zero.

 

Drawing text with a custom font.

What if you specify any font in the function call, other than leaving it as “null”?

Since the GDI abstracts the “pixels” as an “atomic” block of screen, the result would be pretty surprising.

    public class Program
    {
 
        private static ICompositionRenderer _renderer;
 
 
        public static void Main()
        {
            //create a lcd-char driver instance
            _renderer = new BoostHD44780(
                cspin: Pins.GPIO_PIN_D8,
                config: BoostHD44780.Layout20x4);
 
            //creates the target composition instance
            var composition = _renderer.CreateTarget();
 
 
            //draw some huge text
            composition.DrawString(
                "Huge",
                Fonts.Fixed5x7,
                Brushes.White,
                new Point(0, -3)
                );
 
 
            //dumps the composition to the physical device
            _renderer.Dump(composition);
 
            //keep alive
            Thread.Sleep(Timeout.Infinite);
        }
 
    }

Here is the result, although the screen size is not large enough to contain the entire word.

WP_000304

 

Drawing straight lines.

The same abstraction will come in rescue for drawing other graphics primitives, such as straight lines.

    public class Program
    {
 
        private static ICompositionRenderer _renderer;
 
 
        public static void Main()
        {
            //create a lcd-char driver instance
            _renderer = new BoostHD44780(
                cspin: Pins.GPIO_PIN_D8,
                config: BoostHD44780.Layout20x4);
 
            //creates the target composition instance
            var composition = _renderer.CreateTarget();
 
 
            //draw some straight lines
            composition.DrawLine(
                Pens.White,
                new Point(0, 0),
                new Point(19, 0)
                );
 
            composition.DrawLine(
                Pens.White,
                new Point(0, 3),
                new Point(19, 0)
                );
 
 
            //dumps the composition to the physical device
            _renderer.Dump(composition);
 
            //keep alive
            Thread.Sleep(Timeout.Infinite);
        }
 
    }

Here is the result.

WP_000305

 

Drawing rectangles.

Drawing complex geometric figures such as rectangles, both framed and/or filled, comes for free.

    public class Program
    {
 
        private static ICompositionRenderer _renderer;
 
 
        public static void Main()
        {
            //create a lcd-char driver instance
            _renderer = new BoostHD44780(
                cspin: Pins.GPIO_PIN_D8,
                config: BoostHD44780.Layout20x4);
 
            //creates the target composition instance
            var composition = _renderer.CreateTarget();
 
 
            //draw an empty frame
            composition.DrawRectangle(
                Pens.White,
                new Rectangle(4, 0, 11, 3)
                );
 
 
            //dumps the composition to the physical device
            _renderer.Dump(composition);
 
            //keep alive
            Thread.Sleep(Timeout.Infinite);
        }
 
    }

Here is the result.

WP_000306

 

Conclusions.

The hardware abstraction clearly gets a lot of advantages, because you may use almost the same business-layer source code, without being aware to a specific display device.

This concept will be even more concrete in my next article, where I put both the led-matrix and the LCD module in the same app, and I let them work together.

The code can be found, as usual, in the Cet Toolbox repository on Codeplex.

Comments are closed on this post.