Home > LCD, microcontroller, pic32 > Microchip Graphics Library Integration

Microchip Graphics Library Integration

Here is some code for the eBay HX8347-A LCD I’ve been dinking with that utilizes the Graphics Library provided by Microchip. They have a few nice app notes on creating the graphical widgets on one of their development boards, but not really for a custom setup like my Commander32. All of their microcontrollers use the PMP feature to communicate with the LCD, while I just use pins directly.  Their help file gives a nice summary of copying the library files to a new project to keep the file structure intact. Once that is done, the following steps should help make your own setup.

Title Screen for GUI demo

Main Menu with images.

Button pressed on Main Menu.

  1. Write a new HardwareProfile.h

Write from scratch to contain the definition of the LCD pins to the microcontroller pins  and the clock frequency define for SYS_FREQ (required for library). This goes in source folder with your main.c file.

#define SYS_FREQ        (80000000)

// Definitions for reset pin
#define RST_TRIS_BIT    TRISGbits.TRISG12
#define RST_LAT_BIT     LATGbits.LATG12
#define    LCD_REST        RST_LAT_BIT

// Definitions for CS pin
#define CS_TRIS_BIT     TRISGbits.TRISG13
#define CS_LAT_BIT      LATGbits.LATG13
#define    LCD_CS            CS_LAT_BIT

// Definitions for RS pin
#define RS_TRIS_BIT        TRISGbits.TRISG15
#define RS_LAT_BIT      LATGbits.LATG15
#define    LCD_RS            RS_LAT_BIT

// Definitions for WR pin
#define WR_TRIS_BIT        TRISGbits.TRISG14
#define WR_LAT_BIT        LATGbits.LATG14
#define    LCD_WR            WR_LAT_BIT

// Definitions for WR pin
#define RD_TRIS_BIT        TRISDbits.TRISD9
#define RD_LAT_BIT        LATDbits.LATD9

// Data Port for 16 bits
#define    LCD_DATA        LATB
#define    LCD_DATA_TRIS    TRISB
#define DataPortIn()  LCD_DATA_TRIS = 0xffff;
#define DataPortOut() LCD_DATA_TRIS = 0x0000;
  1. Custom LCD Driver (HX8347A_16BIT.c &.h)

The Library contains some blank custom driver files (.c and .h in separate folders w/in library) with the two basic functions, DeviceReset() and PutPixel() required, but empty. My previous LCD initialization code was dumped into DeviceReset() and similarly with the PutPixel(). I also needed to write my own routines for ClearDevice() and Bar(), to optimize drawing. This required the appropriate lines in the header file to be uncommented to use these functions over the Library’s.

HX8347A_16BIT.c

/*****************************************************************************
 *  Module for Microchip Graphics Library
    HX8347 LCD Controller
 *  Custom display controller driver template
 *  By: Ryan Milewski, 2012
 *****************************************************************************/
#include "Graphics/Graphics.h"
#include "HardwareProfile.h"

// Color
WORD_VAL    _color;

// Clipping region control
SHORT       _clipRgn;

// Clipping region borders
SHORT       _clipLeft;
SHORT       _clipTop;
SHORT       _clipRight;
SHORT       _clipBottom;

/*********************************************************************
* Function:  void  DelayMs(WORD time)
* PreCondition: none
* Input: time - delay in ms
* Output: none
* Side Effects: none
* Overview: delays execution on time specified in ms
* Note: none
********************************************************************/
void DelayMs(unsigned int msec)
{
    unsigned int tWait, tStart;

    tWait=(SYS_FREQ/2000)*msec;
    tStart=ReadCoreTimer();
    while((ReadCoreTimer()-tStart)<tWait);        // wait for the time to pass

}

void LCD_write_COM(WORD data)
{

    LCD_RS = 0;
    LCD_CS = 0;
    LCD_DATA = data;
    LCD_WR = 0;
    //Nop();
    //Nop();
    //Nop();
    LCD_WR = 1;
    LCD_CS = 1;    

}

void LCD_write_DATA(WORD data)
{
    LCD_RS = 1;
    LCD_CS = 0;

    LCD_DATA = data;
    LCD_WR = 0;
    //Nop();
    //Nop();
    //Nop();
    LCD_WR = 1;
    LCD_CS = 1;

}//end of WriteLCD_DATA()

void LCD_write_COM_DATA(BYTE index, WORD value)
{
    LCD_write_COM(index);
    LCD_write_DATA(value);

}

/*********************************************************************
* Function:  void ResetDevice()
* PreCondition: none
* Input: none
* Output: none
* Side Effects: none
* Overview: resets LCD, initializes PMP
* Note: none
********************************************************************/
void ResetDevice(void)
{

    // Set uController pins TRIS
    AD1PCFG = 0xffff;    //analog pins all digital

    CS_TRIS_BIT = 0;
    RS_TRIS_BIT = 0;
    WR_TRIS_BIT = 0;
    RD_TRIS_BIT = 0;
    DataPortOut();

    //Reset LCD    
    LCD_REST = 1;
    DelayMs(5);    //5ms delay
    LCD_REST = 0;
    DelayMs(10);    //10ms delay
    LCD_REST = 1;
    DelayMs(20);    //20ms delay

    //Vendor gamma
    LCD_write_COM_DATA(0x0046,0x00a4);
    LCD_write_COM_DATA(0x0047,0x0053);
    LCD_write_COM_DATA(0x0048,0x0000);
    LCD_write_COM_DATA(0x0049,0x0044);
    LCD_write_COM_DATA(0x004a,0x0004);
    LCD_write_COM_DATA(0x004b,0x0067);
    LCD_write_COM_DATA(0x004c,0x0033);
    LCD_write_COM_DATA(0x004d,0x0077);
    LCD_write_COM_DATA(0x004e,0x0012);
    LCD_write_COM_DATA(0x004f,0x004c);
    LCD_write_COM_DATA(0x0050,0x0046);
    LCD_write_COM_DATA(0x0051,0x0044);

    //240x320 window settings
    LCD_write_COM_DATA(0x0002,0x0000);    //Column address start2
    LCD_write_COM_DATA(0x0003,0x0000);    //column address start1
    LCD_write_COM_DATA(0x0004,0x0000);    //Column address end2
    LCD_write_COM_DATA(0x0005,0x00ef);    //Column address end1
    LCD_write_COM_DATA(0x0006,0x0000);    //Row address start2
    LCD_write_COM_DATA(0x0007,0x0000);    //Row address start1
    LCD_write_COM_DATA(0x0008,0x0001);    //Row address end2
    LCD_write_COM_DATA(0x0009,0x003f);    //Row address end1

    //display settings
    LCD_write_COM_DATA(0x0001,0x0006);    //IDMON=0,INVON=1,NORON=1,PTLON=0
    LCD_write_COM_DATA(0x0016,0x0078);    //MY=0,MX=0,MV=0,ML=1,BGR=0,TEON=0
    LCD_write_COM_DATA(0x0023,0x0095);    //N_DC=1001 0101
    LCD_write_COM_DATA(0x0024,0x0095);    //PI_DC=1001 0101
    LCD_write_COM_DATA(0x0025,0x00ff);    //I_DC=1111 1111

    LCD_write_COM_DATA(0x0027,0x0002);    //N_BP=0000 0010
    LCD_write_COM_DATA(0x0028,0x0002);    //N_FP=0000 0010
    LCD_write_COM_DATA(0x0029,0x0002);    //PI_BP=0000 0010
    LCD_write_COM_DATA(0x002a,0x0002);    //PI_FP=0000 0010
    LCD_write_COM_DATA(0x002c,0x0002);    //I_BP=0000 0010
    LCD_write_COM_DATA(0x002d,0x0002);    //I_FP=0000 0010

    LCD_write_COM_DATA(0x003a,0x0001);    //N_RTN=0000,N_NW=001
    LCD_write_COM_DATA(0x003b,0x0000);    //P_RTN=0000,P_NW=001
    LCD_write_COM_DATA(0x003c,0x00f0);    //I_RTN=1111,I_NW=000
    LCD_write_COM_DATA(0x003d,0x0000);    //DIV=00
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0035,0x0038);    //EOS=38h
    LCD_write_COM_DATA(0x0036,0x0078);    //EQP=78h
    LCD_write_COM_DATA(0x003e,0x0038);    //SON=38h
    LCD_write_COM_DATA(0x0040,0x000f);    //GDON=0fh
    LCD_write_COM_DATA(0x0041,0x00f0);    //GDOFF

    //Power Supply Settings
    LCD_write_COM_DATA(0x0019,0x0049);    //CADJ=0100,CUADJ=100,OSD_EN=1,60Hz
    LCD_write_COM_DATA(0x0093,0x000f);    //RADJ=1111, 100%
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0020,0x0040);    //BT=0100
    LCD_write_COM_DATA(0x001d,0x0007);    //VC1=111
    LCD_write_COM_DATA(0x001e,0x0000);    //VC3=000
    LCD_write_COM_DATA(0x001f,0x0004);    //VRH=0011

    //VCOM Settings
    LCD_write_COM_DATA(0x0044,0x004d);    //VCM=101 0000
    LCD_write_COM_DATA(0x0045,0x000e);    //VDV=1 0001
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x001c,0x0004);    //AP=100
    DelayMs(2);    //2ms delay
    LCD_write_COM_DATA(0x001b,0x0018);    //GASENB=0,PON=1,DK=1,XDK=0,VLCD TRI=0,STB=0
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x001b,0x0010);    //GASENB=0,PON=1,DK=0,XDK=0,VLCD TRI=0,STB=0
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0043,0x0080);    //set VCOMG=1
    DelayMs(2);    //2ms delay

    //Display On Setting
    LCD_write_COM_DATA(0x0090,0x007f);    //SAP=0111 1111
    LCD_write_COM_DATA(0x0026,0x0004);    //GON=0,DTE=0,D=01
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0026,0x0024);    //GON=1,DTE=0,D=01
    LCD_write_COM_DATA(0x0026,0x002c);    //GON=1,DTE=0,D=11
    DelayMs(1);    //1ms delay
    LCD_write_COM_DATA(0x0026,0x003c);    //GON=1,DTE=1,D=11

    //Internal Register Settings
    LCD_write_COM_DATA(0x0057,0x0002);    //TEST_Mode=1: into test mode
    LCD_write_COM_DATA(0x0095,0x0001);    //SET DISPLAY CLOCK AND PUMPKING CLOCK TO SYCRONIZE
    LCD_write_COM_DATA(0x0057,0x0000);    //TEST Mode=0:exit TEST Mode

    LCD_write_COM(0x0022);
}

void LCD_address_set(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2)
{
    LCD_write_COM_DATA(0x0002,x1>>8);        //Column address start2
    LCD_write_COM_DATA(0x0003,x1);    //Column address start1
    LCD_write_COM_DATA(0x0004,x2>>8);        //column address end2
    LCD_write_COM_DATA(0x0005,x2);    //column address end1

    LCD_write_COM_DATA(0x0006,y1>>8);        //Row address start2
    LCD_write_COM_DATA(0x0007,y1);    //row address start1
    LCD_write_COM_DATA(0x0008,y2>>8);        //row address end2
    LCD_write_COM_DATA(0x0009,y2);    //row address end1

    LCD_write_COM(0x0022);
}

/*********************************************************************
* Function: void PutPixel(SHORT x, SHORT y)
* PreCondition: none
* Input: x,y - pixel coordinates
* Output: none
* Side Effects: none
* Overview: puts pixel
* Note: none
********************************************************************/
void PutPixel(SHORT x, SHORT y)
{
    unsigned int ncolor;
    ncolor = GetColor();
    LCD_address_set(x,y,x,y);
    LCD_write_DATA(ncolor);
}

/*********************************************************************
* Function: WORD GetPixel(SHORT x, SHORT y)
* PreCondition: none
* Input: x,y - pixel coordinates
* Output: pixel color
* Side Effects: none
* Overview: returns pixel color at x,y position
* Note: none
********************************************************************/
WORD GetPixel(SHORT x, SHORT y)
{
    return (0);
}

/*********************************************************************
* Function: void ClearDevice(void)
* PreCondition: none
* Input: none
* Output: none
* Side Effects: none
* Overview: clears screen with current color and sets cursor to 0,0
* Note: none
********************************************************************/
void ClearDevice(void)
{
    int i,j;
    unsigned int ncolor;

    ncolor = GetColor();
    LCD_address_set(0,0,DISP_HOR_RESOLUTION-1,DISP_VER_RESOLUTION-1);

    for(i=0;i<DISP_HOR_RESOLUTION;i++)
    {
        for(j=0;j<DISP_VER_RESOLUTION;j++)
        {
        LCD_write_DATA(ncolor);
        }
    }
}

/*********************************************************************
* Function: WORD Bar(SHORT left, SHORT top, SHORT right, SHORT bottom)
* PreCondition: none
* Input: left,top - top left corner coordinates,
*        right,bottom - bottom right corner coordinates
* Output: For NON-Blocking configuration:
*         - Returns 0 when device is busy and the shape is not yet completely drawn.
*         - Returns 1 when the shape is completely drawn.
*         For Blocking configuration:
*         - Always return 1.
* Side Effects: none
* Overview: draws rectangle filled with current color
* Note: none
********************************************************************/
WORD Bar(SHORT left, SHORT top, SHORT right, SHORT bottom)
{
    unsigned ncolor;
    int i,j;

    ncolor = GetColor();

    LCD_address_set(left,top,right,bottom);
    for(i=0;i<=(right-left);i++)
    {
        for(j=0;j<=(bottom-top);j++)
        {
            LCD_write_DATA(ncolor);
        }

    }
    return (1);
}
  1. Select options in GraphicsConfig.h

This should be copied from Microchip and placed in your project folder (like the help file says). Put in the Horizontal and Verticle resolution defines your LCD and uncomment the Graphics options to be used.

  1. Replace DeviceDriver.h with Custom Driver

There are two Library files that need to be changed to use the custom driver in the #includes; Primitive.c and Graphics.h. In my case, #include “DeviceDriver.h” was replaced with “HX8347A_16BIT.h”.

Primitive.c 

#include "HardwareProfile.h"              // needed to provide values for GetMaxX() and GetMaxY() macros
#include "HX8347A_16BIT.h"        //Change to custom driver header HERE!!
#include "Graphics/Primitive.h"
#include "Compiler.h" 

 

Then,

Graphics.h

////////////////////////////// INCLUDES //////////////////////////////
    #include <stdlib.h>             // needed because of malloc()
    #include "GenericTypeDefs.h"
	#include "GraphicsConfig.h"
    #include "HX8347A_16BIT.h"      // Display Driver layer
    #include "Primitive.h"          // Graphic Primitives layer
    #include "GOL.h"                // Graphics Object layer

At this point, the Library’s Primitive Layer can be tested. I just grabbed some example code to draw the basic shapes available, text, and some images. Yay!

  1. Custom Touchscreen Driver

The files Touchscreen.c and.h were copied to my project folder and renamed ADS7843Touchscreen.c and .h for customizing. Microchip’s dev boards all drive the touch screen using the ADC, but mine uses the ADS7843 chip which takes care of all that. I kept the function TouchGetMsg() which processes the touch actions into predefined states, and added my own code for initializing and TouchGetXY(). My function gets both x and y coordinates at the same time and needed multiple readings of each and averaged to reduce noise. The ADS7843 has a convientent PenIRQ pin to signal an actual touch or an Idle condition (x = -1,y = -1).

ADS7843Touchscreen.c

SHORT touchX,touchY;

void spistart(void)
{
    D_CS = 1;
    D_CLK = 1;
    D_DIN = 1;
}//end of spistart()

void ADS7843_write(unsigned char num)
{
    unsigned int count,mask,temp;
    int i;
    
    D_CLK = 0;
    mask = 0x80;

    for(count=0;count<8;count++)
    {
        temp = mask&num;
        if (temp == 0)    D_DIN = 0;
        else    D_DIN = 1;
        
        //D_DIN = temp>>(count);
        D_CLK = 0;
        
        for(i=0;i<5;i++)
        {
            Nop();
        }
  
        D_CLK = 1;
        for(i=0;i<5;i++)
        {
            Nop();
        }
        mask>>=1;
    }
}//end of ADS7843_write()


unsigned int ADS7843_read(void)
{
    unsigned int count;
    unsigned int num;
    int i;
    
    num = 0;
    for(count=0;count<12;count++)
    {    
        num<<=1;
        D_CLK = 1;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        D_CLK = 0;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        if(D_DOUT) num++;
     }
    return(num);
}//end of ADS7843_read()



void TouchInit(void)
{
    //Port Init
    D_CLK_TRIS = 0;
    D_CS_TRIS = 0;
    D_DIN_TRIS = 0;
    D_DOUT_TRIS = 1;
    D_IRQ_TRIS = 1;

    spistart();

}

void TouchGetXY(void)
{
    int i,count,x_set,y_set;
    int TP_X,TP_Y;    

    count =0;
    x_set = 0;
    y_set = 0;

    while(count<8)
    {
        //PORTAbits.RA1 = 1;
        //Delay1KTCYx(4);    //2ms delay (8MHz clk)

        D_CS = 0;
        ADS7843_write(0xd4);

        D_CLK = 1;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        D_CLK = 0;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        y_set = y_set + ADS7843_read();
        count++;
    }
    
    count = 0;
    while(count<16)
    {

        ADS7843_write(0x94);
    
        D_CLK = 1;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        D_CLK = 0;
        for(i=0;i<5;i++)
        {
            Nop();
        }

        x_set = x_set + ADS7843_read();

        
        count++;
    }
    D_CS = 1;
    TP_X = x_set/16;
    TP_Y = y_set/8;

    touchX = .0925*TP_X-.0040*TP_Y-31.1315;    //X-coordinate
    touchY = .0006*TP_X+.0661*TP_Y-19.5759;        //Y-coordinate
}

SHORT TouchGetX(void)
{
    int x;
    x = touchX;
    return(x);
}

SHORT TouchGetY(void)
{
    int y;
    y = touchY;
    return(y);
}

int TouchIRQ(void)
{
    int temp;
    temp = D_IRQ;
    return(temp);
}


Those functions will interact with Microchip’s TouchGetMsg(), and only needs ads7843touchscreen.h included in the main .c file source.

  1. Add required main() code

A little bit of code needs to be added to the main() while loop, which is shown more than once in a Microchip app note. Also a data structure, GOL_MSG msg, to relay events needs to be cast.

So hopefully your project is going. Adding and interacting with the widgets is pretty straight forward and documented in the help file (you should have been there already). I had several issues along the way, such as:

  • The default font. Solution: use Font25 or Font35 and cast correctly.
  • Start with the newest version 3 something, drastic changes were made and things didn’t work.
  • While developing touch screen driver, the data wasn’t being transferred to the rest of the GOL, so the widgets wouldn’t draw as pushed. Solution: start new project completely with same drivers. ?????
Advertisements
  1. Evil Monkey
    May 2, 2012 at 3:14 pm

    Cool, looking good. I’m just about to start a project using a PIC24 and the same LCD. Is there any reason you didn’t use the Microchip HX8347-A drive with the PMP changes ? Also It looks like you are ‘bit banging’ the SPI is there any reason you aren’t using one of the on chip SPI controllers ? Thanks for publishing this it’s given me a few ideas to make a start…

    • May 2, 2012 at 10:03 pm

      I ported it from a 18F4580 Library I wrote, then was confused by how Microchip’s files assigned the pins for their dev boards. After digging through the code long enough I used their custom template for the basic functions. The touchscreen code came with it as an example and worked, so just went with it. I’ll probably make changes later.

  2. Evil Monkey
    May 2, 2012 at 3:20 pm

    Opps sorry forgot to ask how fas are the screen draws using the just the 16 bit port.

    • May 2, 2012 at 10:05 pm

      On the PIC32 at 80MHz it’s fast. Too slow on the 18F at 20MHz.

  3. Sascha_Focus
    May 23, 2012 at 7:38 am

    Hello,

    can you post a complete Project with the TFT Display?

    Regards Sascha

    • May 23, 2012 at 8:07 am

      Not directly yet. I’ll have to set up someplace else to post a zip file. I sent you an email with it.

      • August 16, 2012 at 6:24 pm

        Dear blackrynius, is it possible to mail the complete project to me? I’m working on something similar but I’m stuck somewhere in some errors… 🙂 Thanks in advance

  4. November 27, 2012 at 7:30 am

    Dear Black Rynius,

    I follwed your instructions

    My Setup ;
    Graphics Library v3.06
    Graphics Display Designer X Beta v0.20
    3.2″ 320×240 tft module + touchscreen
    PIC32MX575F512L, pmp16 bit 8080, with SSD1298 controller

    I have succesfuly managed using lcd and touchscreen drivers.
    System can draw static primitives ( like static text , line , rectangle.) by typing codes
    or using GDD tool without any problems.
    Also software can show correct touch point values on the lcd screen..

    ***But when I use dynamic widgets like Button, system gets stuck in the code.
    Only ClearDevice() can execute then system stop, lcd shows blank screen.

    debug the code, find the stuck point

    under the “GDD_Screens.c”

    if(defscheme != NULL) free(defscheme);

    defscheme = GOLCreateScheme();
    defscheme->Color0 = RGBConvert(72, 140, 248); // <= HERE STUCK in CODE

    Already create new project with working drivers…
    any idea ?
    Could you please email me your complete project ? I can share mine…

    Thank you anyway this page is very helpful

    Oscar

    • November 27, 2012 at 7:59 am

      hehe problem solved. heap size was the problem.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: