Logo    gLCD Software
HomePage | Contact | Resume| Client List | EngineeringLinks | Embedded | Forum

Using Bitmapped Fonts With a Graphics LCD Module
Back To Embedded Info Page



Note: This page has been updated with improved code and new code samples for several additional display types. Updated 16 Mar 2003.


I recently started work with a graphics LCD module that is a Chip on Glass (COG) type module. I had spent a fair amount of time searching on the Internet for software drivers to interface an 8051/8052 type processor to a display of this kind. I was rather surprised to find that there is very little freeware of a type suitable for the needs of a typical embedded systems design....so I made it a goal to develop a graphics LCD library with included bitmap font support. This page is a presentation of the results of that work and provides a link where avid 8052.com visitors can access a free download of this software.

Here is a quick look at the nice types of fonts that can be displayed on a graphics LCD module. These pictures should certainly get some readers interested in the use of graphics LCD modules as opposed to the fixed character mode displays of days done by. I suspect that many 8051/8052 system designers would like to use a graphic display on their microcontroller but are held back by the learning curve and implementation hurdle. Well that need not be a problem any longer!!

(Click on image above to see a bigger version).



(Click on image above to see a bigger version).



I decided to use an off the shelf development board to host the creation of the software. Readers of my pages here will know that I am a fan of the 8051 derivative microcontrollers from Silicon Labs so it should be no surprise that I chose to use a low cost board with the Silicon Labs C8051F020 processor. This processor is a device with 64K of FLASH program memory and 4K bytes of XRAM resident on the chip. The development board is setup with a 22.1184 MHz crystal and with the Cygnal 1X clock divide ratio the board provides good code execution performance. The board comes with connectors for power, the Cygnal JTAG download/debug cable, a 96-pin DIN connector that provides access for almost all processor pins and headers for each of the 8 ports. There is even an RS232 port connector on this board so it is easy to connect it to your PC or other serial device.

Here is a picture of the Silicon Labs evaluation board with a link for C8051F020DK Information at the Silicon Labs Web Site.



The display I used for this project is a small Chip On Glass (COG) type from TIANMA. This display is organized as a 106 x 56 pixel array. The controller IC mounted on the glass is a Samsung S6B0724 that is interfaced to a fine pitch 20 way flex cable. The logical interface to the flex cable is provided by connecting the flex cable directly to port pins of the microcontroller and using software to implement the serial communications to the controller. Here are links to reference information about the controller chip and the display module.

S6B0724A Controller General Description

S6B0724A Controller Data Sheet

TIANMA Display Picture

TIANMA 106 x 56 Display Drawing


At first I messed around with this display using a quick adapter that I fabricated so that I could attach it to the microcontroller development board. You can see pictures of that work here. More recently I made a small PC board adapter to directly connect the display to the Silicon Labs C8051F020 development board. Here is a picture of that adapter that also shows the TIANMA display module. Note that the adapter shown has two sites for connecting LCD modules from different manufacturers. The TIANMA connects to the lower one in the picture.



A schematic diagram of the adapter is shown below. This will show how the 20 signals of the flex cable are connected to the microcontroller. Note in particular the group of capacitors that are used by a charge pump on the S6B0724 chip to boost the VDD of 3.3 volts up to the 9 -> 10 volts required as a bias for the LCD glass.


(Click on image above to see higher resolution schematic).



To develop the software I used the Keil C51 C language compiler installed with the Silicon Labs IDE. This provided me a very nice development environment due to the source level debugging offered by the Silicon Labs IDE when used in conjunction with the JTAG debug hardware support that is built into all Silicon Labs processors. Here is a picture of the complete development setup. Notice the small adapter device on the right side of the picture. This device converts the RS232 port of the development PC to the JTAG signals needed by the Silicon Labs microcontroller.




The code I developed for this project was designed with the S6B0724 display controller in mind, but the code can be used with the display controllers on other LCD modules as well. There are several graphic display controllers from other manufacturers that operate almost identical to the S6B0724 chip. In addition there are other chips that implement the LCD control function is a slightly different way, but the code I developed can be adapted to these other display controllers without too much work. The main concerns when working with graphics modules are:

  1. Orientation of the data bytes in controller to the horizontal or vertical direction.


  2. Orientation of the rasters of the data bytes in the bitmapped font data.


  3. Order of the bits of the within the byte in controller such as if D0 is to top/left or to the bottom/right.




The diagram below shows the layout that is specific the S6B0724 controller chip.




The LCD graphics functions are coded into a single C source file along with a companion header file that exports all the significant function names and defined constants for use in other source files. The developed code includes the following list of functions:

    void lcd_init(void);
    void lcd_out_dat(char dat);
    void lcd_out_ctl(char dat);
    void lcd_erase(void);
    void lcd_test(unsigned char pattern);
    void lcd_clear_area(unsigned char left, unsigned char top,
                        unsigned char right, unsigned char bottom);
    void lcd_invert_area(unsigned char left, unsigned char top,
                         unsigned char right, unsigned char bottom);
    void lcd_horz_line(unsigned char left, unsigned char right,
                       unsigned char row);
    void lcd_vert_line(unsigned char top, unsigned char bottom,           
                       unsigned char column);
    void lcd_clr_horz_line(unsigned char left, unsigned char right,
                           unsigned char row);
    void lcd_clr_vert_line(unsigned char top, unsigned char bottom,
                           unsigned char column);
    void lcd_box(unsigned char left, unsigned char top,           
                 unsigned char right, unsigned char bottom);
    void lcd_clr_box(unsigned char left, unsigned char top,
                     unsigned char right, unsigned char bottom);
    void lcd_glyph(unsigned char left, unsigned char top,
                   unsigned char width, unsigned char height,
                   unsigned char *glyph, unsigned char store_width);
    void lcd_text(unsigned char left, unsigned char top,
                  unsigned char font, char *str);
    void lcd_update(unsigned char top, unsigned char bottom);

I have organized the font handling in this code so that bitmaps for the font are compiled into the FLASH code space of the microcontroller as constant data. The bitmap data for the fonts was created as C source code using the FontGen utility created by a clever gentleman named Bahri Okuroglu. You can read about FontGen and access a download link at his FontGen Web Page. Each font that is "sourced" by FontGen uses a definition structure of the format shown below:

    struct FONT_DEF
    {
        unsigned char store_width;        /* glyph storage width in bytes */
        unsigned char glyph_height;       /* glyph height for storage */
        unsigned char code *glyph_table;  /* font table start address in memory */ 
        unsigned char fixed_width;        /* fixed width of glyphs. If zero */      
                                          /* then use the width table. */
        unsigned char code *width_table;  /* variable width table start address */
    }

I have organized the font file in the developed source code so that it contains an array of these FONT_DEF structures. Then the text display routines can simply reference the font typefaces by font number. For example the code I wrote has three fonts installed as "normal", "bold", and "bigbold" that are referred to fonts 0, 1, and 2 respectively. Here is the code that shows this array of the structures:.


    /* definition tables for three fonts as follows:                             */
    /* all fonts include 96 glyphs from 0x20 to 0x7F that are in ASCII order     */
    /*                                                                           */
    /* Font #0: normal_font - a light variable width font that is 13 pixels high */
    /* Font #1: bold_font - a heavy variable width font that is 13 pixels high   */
    /* Font #2: bigbold_font - a large fixed width font that is 32 pixels high   */
    /*                                                                           */
    struct FONT_DEF code fonts[] = 
               {
                {2, 13, normal_glyph_table, 0, normal_width_table},    /* normal */
                {2, 13, bold_glyph_table, 0, bold_width_table},          /* bold */
                {3, 32, bigbold_glyph_table, 20, NULL},               /* bigbold */
               };

As you can see from the table above the fonts can be fixed width or variable width. Variable width fonts have an indirectly referenced table that provides the widths for each of the glyphs in the font set. Note that these tables are also built by Bahri Okuroglu's FontGen program.

The bitmapped font rendering code that I wrote uses a concept of a screen image array kept in the processor memory space that is then copied out to the LCD controller as needed. This is an efficient method to implement a graphics LCD driver for two reasons. First off it is far more convenient to be able to read the existing pixel image data from the memory array when it is necessary to insert new pixels into a partially modified byte as opposed to trying to read them back out of the LCD controller chip. Secondly the common COG style LCD modules often are setup to use a serial interface as opposed to a parallel interface. This is nice in that it makes the flex cable narrower but, as in the case of the S6B0724 controller chip, it also leaves the internal ram in the controller accessible in a write only manner. (i.e. the serial interface is unidirectional). Another consideration is that it is possible to write a very tight and efficient routine to copy this memory buffer to the display controller because of the fact that graphics LCD controllers permit you to set the address within a memory page once and then you can simply transfer the bytes for the page by a sequence of data register writes and the internal address auto increments. The 106x56 display I used has 7 pages of display memory so the whole screen can be updated by setting the page/column address 7 times and squirting out 106 bytes of data to each page. The total size of the memory buffer for the 106x56 display is 742 bytes. This buffer was placed in the on-board XRAM space of the Silicon Labs C8051F020 processor where it used less than 25% of the available 4K byte memory. The modern processors of this type that have this onboard XRAM make embedded products with graphic LCD modules possible without having to design in a separate memory chip. A real common type of graphics module is the 128x64 pixel size. These require a 1024 byte buffer.

The code to display the screen images shown at the beginning of this web page is shown below. As you can see it is very easy once the font bitmap and the LCD interface and font rendering code is in place. Note in particular that the display is changed via the various calls in the LCD code set to draw lines, boxes, cleared areas, inverted areas, and bitmap font data. These calls simply draw pixels into the internal image buffer. Once the software has "painted" the new image a call to the lcd_update() routine is made to cause the actual display to be updated from the memory image buffer. Notice that this routine has entry arguments that permit just a portion of the display to be updated. This feature is provided to increase performance in instances where software is updating only a small area on the screen.


sbit SWT = P3^7;

void main (void)
{
    config(); // setup all the SFR initialization
    lcd_init()   // initialize LCD display
    lcd_erase();   // erase the display 

    while(1)
    {
        // switch over to the buffered interface
        lcd_clear_area(SCRN_LEFT,SCRN_TOP,SCRN_RIGHT,SCRN_BOTTOM);
        lcd_box(SCRN_LEFT,SCRN_TOP,SCRN_RIGHT,SCRN_BOTTOM);
        lcd_box(SCRN_LEFT+2,SCRN_TOP+2,SCRN_RIGHT-2,SCRN_BOTTOM-2);

        lcd_text(6,3,1,"Michael Karas");
        lcd_text(11,15,2,"1234");     
        lcd_text(5,40,0,"carousel-design.com");
        lcd_update(SCRN_TOP,SCRN_BOTTOM);
		
        while(SWT == 1);
        while(SWT == 0);
		
        lcd_invert_area(SCRN_LEFT+2,SCRN_TOP+2,SCRN_RIGHT-2,SCRN_BOTTOM-2);
        lcd_update(SCRN_TOP,SCRN_BOTTOM);
        while(SWT == 1);
        while(SWT == 0);
	}
}  

I have gathered the code for this project into a ZIP file that you are free to download and use as you wish. The code provided is all written in C language and compiled using the Keil C51 compiler. The code is small enough that it should be possible to compile it with the evaluation version of the Keil compiler that comes with the Silicon Labs development board. (That version is limited to 4K of code. The download version from the Keil web site is limited to 2K of code). However it will most likely be necessary to strip out two of the fonts. There is no reason that this code cannot be compiled with other C compilers and targeted to other types of microcontrollers as well. There would be only minor changes to the code required to port in this manner.

If you download this code and use it in a project I would request that you send me an email of how you used the gLCDcode


Download gLCDcode


(Please note that I am providing this code "as-is" and it is up to you to determine its usefulness for your application. As such you assume all responsibility for its use and application. I cannot provide free technical support to help you get it working for your controller or hardware setup. However if you have a minor question of how some portion of the code works or why it was written in a particular way please feel free to send me a question via email. I will try to answer all questions but cannot guarantee this as I get tons of email and I also run a consulting business to earn a living and that has to come first. You can also email if you want support on a consulting basis. There is a link above with my email address).


UPDATE SECTION


I have done some additional work to the gLCD code that is now available for download. The new code sets are an update to the original download package, which is still available above. The updates to be found in all of the new code sets include several bug fixes in the font glyph painter routine, a new feature of the lcd_text() routine that causes it to clip any text that extends beyond the edge of the screen, and support for fonts that do not consist of the complete ASCII 0x20-0x7E character range. There are three different download sets available for different sized displays. In one case the supported display uses a different LCD module controller.


* * * * *


gLCD for Tianma 106x56 Display with S6B0724 Controller

(Click on image above to see a bigger version).



(Click on image above to see a bigger version).



This 106x56 pixel display is the same display module discussed above in the main project page. The display is mapped to the memory buffer bytes such that the bits in a specific byte are shown on the display as 8 vertical dots. Bands of these bytes called “pages” make up eight pixel high stripes across the display. The S6B0742 controller can be used on displays up to 132x65 and it is necessary to program certain chip registers in a special manner to map the display in a way that makes it fast and efficient to update the display. One example of this mapping that has to be done is to start the loading of the screen image at column 26 for the left edge of the screen.

Download gLCD106x56.zip


(Please note that I am providing this code "as-is" and it is up to you to determine its usefulness for your application. As such you assume all responsibility for its use and application. I cannot provide free technical support to help you get it working for your controller or hardware setup. However if you have a minor question of how some portion of the code works or why it was written in a particular way please feel free to send me a question via email. I will try to answer all questions but cannot guarantee this as I get tons of email and I also run a consulting business to earn a living and that has to come first. You can also email if you want support on a consulting basis. There is a link above with my email address).



* * * * *


gLCD for Tianma 128x64 Display with S6B0724 Controller

(Click on image above to see a bigger version).



(Click on image above to see a bigger version).



This 128x64 pixel display is a similar module from Tianma that is connected to the Silicon Labs development board in exactly the same manner as the smaller display discussed above in the main project page. This display is mapped to the memory buffer bytes such that the bits in a specific byte are shown on the display as 8 vertical dots. Bands of these bytes called “pages” make up eight pixel high stripes across the display. The S6B0742 controller can be used on displays up to 132x65 and it is necessary to program certain chip registers in a special manner to map the display in a way that makes it fast and efficient to update the display. One example of this mapping that has to be done is to start the loading of the screen image at column 4 for the left edge of the screen.

Download gLCD128x64.zip


(Please note that I am providing this code "as-is" and it is up to you to determine its usefulness for your application. As such you assume all responsibility for its use and application. I cannot provide free technical support to help you get it working for your controller or hardware setup. However if you have a minor question of how some portion of the code works or why it was written in a particular way please feel free to send me a question via email. I will try to answer all questions but cannot guarantee this as I get tons of email and I also run a consulting business to earn a living and that has to come first. You can also email if you want support on a consulting basis. There is a link above with my email address).



* * * * *



gLCD for Optronix 240x64 Display with Toshiba T6963C Controller

(Click on image above to see a bigger version).



(Click on image above to see a bigger version).



This 240x64 pixel display is a unit with a parallel interface to an onboard Toshiba T6963C graphics LCD controller. This is connected to the SIgnal Labs development board using two ports, one for the 8-bit bus to the module and the other for the handshake lines. I have configured the software to communicate with the Toshiba controller using a bit banging technique. I chose this approach because it is generally more portable to take the same hook-up and supporting code and move it to a different processor platform. It is also possible to connect the T6963C controller to the external XRAM bus of a typical 8051/8052 derivative chip and use MOVX instructions to communicate to the graphics module in that manner. The code supplied below can be easily modified to support this mode of operation. The schematic below shows the connections from the Port 2 and Port 3 headers of the Cygnal development platform to the Optrex display. Note that the Optrex display is a device with a 5 volt power supply requirement and the pullup resistors on all the lines are there to provide full 5 volt swings of the interface signals. The Silicon Labs processor is quite happy with this mode of operation as it has I/Os that are 5V tolerant.


(Click on image above to see higher resolution schematic).



This display is mapped to the memory buffer bytes such that the bits in a specific byte are shown on the display as 8 horizontal dots. Each line across the screen is made up of a string of these horizontal bytes for a total of 30 bytes per line. There are a total of 64 lines of these bytes. The part number of this display is Optrex America DMF-5005NY-LY-AKE and they are available in stock at Digikey under part number 73-1157-ND.

Download gLCD240x64.zip


(Please note that I am providing this code "as-is" and it is up to you to determine its usefulness for your application. As such you assume all responsibility for its use and application. I cannot provide free technical support to help you get it working for your controller or hardware setup. However if you have a minor question of how some portion of the code works or why it was written in a particular way please feel free to send me a question via email. I will try to answer all questions but cannot guarantee this as I get tons of email and I also run a consulting business to earn a living and that has to come first. You can also email if you want support on a consulting basis. There is a link above with my email address).




Email: mkaras@carousel-design.com
Web Site: www.carousel-design.com