This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Kentec QVGA S1 TM4C123 SPI Driver

Other Parts Discussed in Thread: MSP-EXP430FR5969

Hi,

I see that new booster pack Kentec QVGA S1 has been changed from 8-bit parallel interface to SPI interface. So I am attaching the driver for new interface (SPI Interface) and I hope that it will be helpful for others.

Best Regards,

Sattar Malokani

2844.Kentec320x240x16_SSD2119_SPI.c
//*****************************************************************************
//
// Kentec320x240x16_ssd2119_SPI.c - Display driver for the Kentec
//                                  BOOSTXL-K350QVG-S1 TFT display with an SSD2119
//                                  controller.  This version assumes an SPI interface
//                                  between the micro and display.
//
//*****************************************************************************

//*****************************************************************************
//
//! \addtogroup display_api
//! @{
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/ssi.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/rom.h"
#include "driverlib/pin_map.h"
#include "grlib/grlib.h"
#include "drivers/Kentec320x240x16_SSD2119_SPI.h"
//*****************************************************************************
//
// This driver operates in four different screen orientations.  They are:
//
// * Portrait - The screen is taller than it is wide, and the flex connector is
//              on the left of the display.  This is selected by defining
//              PORTRAIT.
//
// * Landscape - The screen is wider than it is tall, and the flex connector is
//               on the bottom of the display.  This is selected by defining
//               LANDSCAPE.
//
// * Portrait flip - The screen is taller than it is wide, and the flex
//                   connector is on the right of the display.  This is
//                   selected by defining PORTRAIT_FLIP.
//
// * Landscape flip - The screen is wider than it is tall, and the flex
//                    connector is on the top of the display.  This is
//                    selected by defining LANDSCAPE_FLIP.
//
// These can also be imagined in terms of screen rotation; if portrait mode is
// 0 degrees of screen rotation, landscape is 90 degrees of counter-clockwise
// rotation, portrait flip is 180 degrees of rotation, and landscape flip is
// 270 degress of counter-clockwise rotation.
//
// If no screen orientation is selected, "landscape flip" mode will be used.
//
//*****************************************************************************
#if ! defined(PORTRAIT) && ! defined(PORTRAIT_FLIP) && \
    ! defined(LANDSCAPE) && ! defined(LANDSCAPE_FLIP)
#define LANDSCAPE
//#define PORTRAIT_FLIP
#endif

//*****************************************************************************
//
// Various definitions controlling coordinate space mapping and drawing
// direction in the four supported orientations.
//
//*****************************************************************************
#ifdef PORTRAIT
#define HORIZ_DIRECTION 0x28
#define VERT_DIRECTION 0x20
#define MAPPED_X(x, y) (319 - (y))
#define MAPPED_Y(x, y) (x)
#endif
#ifdef LANDSCAPE
#define HORIZ_DIRECTION 0x00
#define VERT_DIRECTION  0x08
#define MAPPED_X(x, y) (319 - (x))
#define MAPPED_Y(x, y) (239 - (y))
#endif
#ifdef PORTRAIT_FLIP
#define HORIZ_DIRECTION 0x18
#define VERT_DIRECTION 0x10
#define MAPPED_X(x, y) (y)
#define MAPPED_Y(x, y) (239 - (x))
#endif
#ifdef LANDSCAPE_FLIP
#define HORIZ_DIRECTION 0x30
#define VERT_DIRECTION  0x38
#define MAPPED_X(x, y) (x)
#define MAPPED_Y(x, y) (y)
#endif

//#define SPI3	//9-bit 3-wire SPI (SSI2) mode (SCLK, SDA, SCS)
              // Default setting for the BOOSTXL-K350QVG-S1
							// Need to remove the "R10" (connect the "PB7/SSI2Tx" to "PD1/AIN6_TOUCH_XP") on Launchpad
#define SPI4	//8-bit 4-wire SPI (SSI2) mode (SCLK, SDA, SCS, SDC)
							// Need to remove the "R10" (connect the "PB7/SSI2Tx" to "PD1/AIN6_TOUCH_XP") on Launchpad
							// Need to move the "R2" to "R3" position, 
							// and move "R8" to "R9" position on the BOOSTXL-K350QVG-S1

//*****************************************************************************
//
// Defines for the pins that are used to communicate with the SSD2119.
//
//*****************************************************************************
#define LCD_CS_PERIPH           SYSCTL_PERIPH_GPIOA
#define LCD_CS_BASE             GPIO_PORTA_BASE
#define LCD_CS_PIN              GPIO_PIN_4

#define LCD_DC_PERIPH           SYSCTL_PERIPH_GPIOA
#define LCD_DC_BASE             GPIO_PORTA_BASE
#define LCD_DC_PIN              GPIO_PIN_5

#define LCD_RST_PERIPH           SYSCTL_PERIPH_GPIOD
#define LCD_RST_BASE             GPIO_PORTD_BASE
#define LCD_RST_PIN              GPIO_PIN_7

#define LCD_LED_PERIPH           SYSCTL_PERIPH_GPIOF
#define LCD_LED_BASE             GPIO_PORTF_BASE
#define LCD_LED_PIN              GPIO_PIN_2

//*****************************************************************************
//
// The dimensions of the LCD panel.
//
//*****************************************************************************
#define LCD_VERTICAL_MAX 240
#define LCD_HORIZONTAL_MAX 320

#define SSD2119_ENTRY_MODE_REG        0x11
#define SSD2119_RAM_DATA_REG          0x22
#define SSD2119_V_RAM_POS_REG         0x44
#define SSD2119_H_RAM_START_REG       0x45
#define SSD2119_H_RAM_END_REG         0x46
#define SSD2119_X_RAM_ADDR_REG        0x4E
#define SSD2119_Y_RAM_ADDR_REG        0x4F
#define ENTRY_MODE_DEFAULT 0x6830
#define MAKE_ENTRY_MODE(x) ((ENTRY_MODE_DEFAULT & 0xFF00) | (x))

//*****************************************************************************
//
// Translates a 24-bit RGB color to a display driver-specific color.
//
// \param c is the 24-bit RGB color.  The least-significant byte is the blue
// channel, the next byte is the green channel, and the third byte is the red
// channel.
//
// This macro translates a 24-bit RGB color into a value that can be written
// into the display's frame buffer in order to reproduce that color, or the
// closest possible approximation of that color.
//
// \return Returns the display-driver specific color.
//
//*****************************************************************************
#define DPYCOLORTRANSLATE(c)    ((((c) & 0x00f80000) >> 8) |               \
                                 (((c) & 0x0000fc00) >> 5) |               \
                                 (((c) & 0x000000f8) >> 3))
//*****************************************************************************
//
// Macro used to set the LCD data bus in preparation for writing a byte to the
// device.
//
//*****************************************************************************
uint16_t pui16Data[2];

#ifdef SPI3
//*****************************************************************************
// Writes a data word to the SSD2119.  This function implements the 3-wire SPI
// interface to the LCD display.
//*****************************************************************************
static void
WriteDataSPI(unsigned short usData)
{
		pui16Data[0] = 0x100 | (usData >> 8);// set the most significant byte of the data.
		pui16Data[1] = 0x100 | usData;// set the least significant byte of the data.

		HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = 0;//CS="0"

		SSIDataPut(SSI2_BASE, pui16Data[0]);
		SSIDataPut(SSI2_BASE, pui16Data[1]);
		while(SSIBusy(SSI2_BASE)){ }   // Wait until SSI0 is done transferring all the data in the transmit FIFO.

		HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = LCD_CS_PIN;
}
//*****************************************************************************
// Writes register word to the SSD2119.  This function implements the 3-wire SPI
// interface to the LCD display.
//*****************************************************************************
static void
WriteCommandSPI(unsigned short usData)
{
		pui16Data[0] = 0;// set the most significant byte of the data.
    pui16Data[1] = 0xFF & usData;// set the least significant byte of the data.

		HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = 0;//CS="0"

		SSIDataPut(SSI2_BASE, pui16Data[0]);
		SSIDataPut(SSI2_BASE, pui16Data[1]);
		while(SSIBusy(SSI2_BASE)){ }   // Wait until SSI0 is done transferring all the data in the transmit FIFO.

		HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = LCD_CS_PIN;
}
#endif

#ifdef SPI4
//*****************************************************************************
// Writes a data word to the SSD2119.  This function implements the 4-wire SPI
// interface to the LCD display.
//*****************************************************************************
static void
WriteDataSPI(unsigned short usData)
{
	pui16Data[0] = (usData >> 8);// Write the most significant byte of the data to the bus.
	pui16Data[1] = usData;// Write the least significant byte of the data to the bus.

	HWREG(LCD_DC_BASE + GPIO_O_DATA + (LCD_DC_PIN << 2)) = LCD_DC_PIN;//DC="1"
	HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = 0;//CS="0"
		
	SSIDataPut(SSI2_BASE, pui16Data[0]);
	SSIDataPut(SSI2_BASE, pui16Data[1]);
	while(SSIBusy(SSI2_BASE)){ }   // Wait until SSI0 is done transferring all the data in the transmit FIFO.

	HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = LCD_CS_PIN;
}
//*****************************************************************************
// Writes register word to the SSD2119.  This function implements the 3-wire SPI
// interface to the LCD display.
//*****************************************************************************
static void
WriteCommandSPI(unsigned short usData)
{
	pui16Data[0] = 0;// Write the most significant byte of the data to the bus.
	pui16Data[1] = usData;// Write the least significant byte of the data to the bus.

	HWREG(LCD_DC_BASE + GPIO_O_DATA + (LCD_DC_PIN << 2)) = 0;//DC="0"
	HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = 0;//CS="0"
	
	SSIDataPut(SSI2_BASE, pui16Data[0]);
	SSIDataPut(SSI2_BASE, pui16Data[1]);
	while(SSIBusy(SSI2_BASE)){ }   // Wait until SSI0 is done transferring all the data in the transmit FIFO.

	HWREG(LCD_CS_BASE + GPIO_O_DATA + (LCD_CS_PIN << 2)) = LCD_CS_PIN;
}
#endif

//*****************************************************************************
// Initializes the LCD interface.
// Enable the SSI2 for LCD data/register transfer.
// Set the LCD_CS_PIN, LCD_DC_PIN, LCD_RST_PIN.
//*****************************************************************************
static void
LCD_PORT_Init(void)
{		
		uint32_t pui32DataRx[3];
		
    // The SSI2 peripheral must be enabled for use.
		SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);

    // For this example SSI2 is used with PortB[7:4].  The actual port and pins
    // used may be different on your part, consult the data sheet for more
    // information.  GPIO port B needs to be enabled so these pins can be used.
    // TODO: change this to whichever GPIO port you are using.
		SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
		
		// Enable the PortA[5:4] for the LCD_SCS, LCD_SDC
		// Enable the PortD[7] for LCD_RST
		// Enable the PortF[2] for LED backlight
		SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
		SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
		SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

		// Change PD7 into GPIO output.
    HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) |= GPIO_LOCK_KEY;
		HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= 0x80;
    HWREG(GPIO_PORTD_BASE + GPIO_O_AFSEL) &= 0x7f;
		GPIOPinTypeGPIOOutput(LCD_RST_BASE, LCD_RST_PIN);
		
		GPIOPinTypeGPIOOutput(LCD_CS_BASE, LCD_CS_PIN);
		GPIOPinTypeGPIOOutput(LCD_DC_BASE, LCD_DC_PIN);

		GPIOPinTypeGPIOOutput(LCD_LED_BASE, LCD_LED_PIN);
    //GPIOPadConfigSet(LCD_LED_BASE, LCD_LED_PIN, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_STD);


		// Configure the pin muxing for SSI2 functions on port B4, B5, B6, and B7.
    // This step is not necessary if your part does not support pin muxing.
    // TODO: change this to select the port/pin you are using.
    GPIOPinConfigure(GPIO_PB4_SSI2CLK);
    GPIOPinConfigure(GPIO_PB5_SSI2FSS);
    GPIOPinConfigure(GPIO_PB6_SSI2RX);
    GPIOPinConfigure(GPIO_PB7_SSI2TX);
		
    // Configure the GPIO settings for the SSI pins.  This function also gives
    // control of these pins to the SSI hardware.  Consult the data sheet to
    // see which functions are allocated per pin.
    // The pins are assigned as follows:
    //      PB7 - SSI2Tx
    //      PB6 - SSI2Rx
    //      PB5 - SSI2Fss
    //      PB4 - SSI2CLK
    // TODO: change this to select the port/pin you are using.
    GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 | GPIO_PIN_4);
    GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_7, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_STD);

    // Configure and enable the SSI port for SPI master mode.  Use SSI0,
    // system clock supply, idle clock level low and active low clock in
    // freescale SPI mode, master mode, 1MHz SSI frequency, and 8-bit data.
    // For SPI mode, you can set the polarity of the SSI clock when the SSI
    // unit is idle.  You can also configure what clock edge you want to
    // capture data on.  Please reference the datasheet for more information on
    // the different SPI modes.
	#ifdef SPI3		
		SSIConfigSetExpClk(SSI2_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 20000000, 9);
	#endif
	#ifdef SPI4
		SSIConfigSetExpClk(SSI2_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 20000000, 8);
	#endif
    
    // Enable the SSI2 module.
    SSIEnable(SSI2_BASE);
		
    // Read any residual data from the SSI port.  This makes sure the receive
    // FIFOs are empty, so we don't read any unwanted junk.  This is done here
    // because the SPI SSI mode is full-duplex, which allows you to send and
    // receive at the same time.  The SSIDataGetNonBlocking function returns
    // "true" when data was returned, and "false" when no data was returned.
    // The "non-blocking" function checks if there is any data in the receive
    // FIFO and does not "hang" if there isn't.
		while(SSIDataGetNonBlocking(SSI2_BASE, &pui32DataRx[0]))    {    }

}

void LED_backlight_ON(void)
{
	HWREG(LCD_LED_BASE + GPIO_O_DATA + (LCD_LED_PIN << 2)) = LCD_LED_PIN;
}
void LED_backlight_OFF(void)
{
	HWREG(LCD_LED_BASE + GPIO_O_DATA + (LCD_LED_PIN << 2)) = 0;
}

//*****************************************************************************
//
//! Initializes the display driver.
//!
//! This function initializes the SSD2119 display controller on the panel,
//! preparing it to display data.
//!
//! \return None.
//
//*****************************************************************************
void
Kentec320x240x16_SSD2119Init(void)
{
		unsigned int ulClockMS, ulCount;

    // Get the current processor clock frequency.
    ulClockMS = SysCtlClockGet() / (3 * 1000);

		// Initializes the LCD port
		LCD_PORT_Init();

		// Reset the LCD
    HWREG(LCD_RST_BASE + GPIO_O_DATA + (LCD_RST_PIN << 2)) = 0;//RST="0"
    SysCtlDelay(10 * ulClockMS);
		HWREG(LCD_RST_BASE + GPIO_O_DATA + (LCD_RST_PIN << 2)) = LCD_RST_PIN;//RST="1"
    SysCtlDelay(20 * ulClockMS);

    // Enter sleep mode (if we are not already there).
    WriteCommandSPI(0x10);//SLEEP_MODE_REG
    WriteDataSPI(0x0001);

    //
    // Set initial power parameters.
    //
    WriteCommandSPI(0x1E);//SSD2119_PWR_CTRL_5_REG
    WriteDataSPI(0x00BA);
    WriteCommandSPI(0x28);//SSD2119_VCOM_OTP_1_REG
    WriteDataSPI(0x0006);

    //
    // Start the oscillator.
    //
    WriteCommandSPI(0x00);
    WriteDataSPI(0x0001);

    //
    // Set pixel format and basic display orientation (scanning direction).
    //
    WriteCommandSPI(0x01);
    WriteDataSPI(0x30EF);
    WriteCommandSPI(0x02);
    WriteDataSPI(0x0600);

    //
    // Exit sleep mode.
    //
    WriteCommandSPI(0x10);//SSD2119_SLEEP_MODE_REG
    WriteDataSPI(0x0000);

    //
    // Delay 30mS
    //
    SysCtlDelay(30 * ulClockMS);

    //
    // Configure pixel color format and MCU interface parameters.
    //
    WriteCommandSPI(SSD2119_ENTRY_MODE_REG);
    WriteDataSPI(ENTRY_MODE_DEFAULT);

    //
    // Enable the display.
    //
    WriteCommandSPI(0x07);
    WriteDataSPI(0x0033);

    //
    // Set VCIX2 voltage to 6.1V.
    //
    WriteCommandSPI(0x0C);//SSD2119_PWR_CTRL_2_REG
    WriteDataSPI(0x0005);

    //
    // Configure gamma correction.
    //
    WriteCommandSPI(0x30);    WriteDataSPI(0x0000);//SSD2119_GAMMA_CTRL_1
    WriteCommandSPI(0x31);    WriteDataSPI(0x0400);//SSD2119_GAMMA_CTRL_2
    WriteCommandSPI(0x32);    WriteDataSPI(0x0106);//SSD2119_GAMMA_CTRL_3
    WriteCommandSPI(0x33);    WriteDataSPI(0x0700);//SSD2119_GAMMA_CTRL_4
    WriteCommandSPI(0x34);    WriteDataSPI(0x0002);//SSD2119_GAMMA_CTRL_5
    WriteCommandSPI(0x35);    WriteDataSPI(0x0702);//SSD2119_GAMMA_CTRL_6
    WriteCommandSPI(0x36);    WriteDataSPI(0x0707);//SSD2119_GAMMA_CTRL_7
    WriteCommandSPI(0x37);    WriteDataSPI(0x0203);//SSD2119_GAMMA_CTRL_8
    WriteCommandSPI(0x3A);    WriteDataSPI(0x1400);//SSD2119_GAMMA_CTRL_9
    WriteCommandSPI(0x3B);    WriteDataSPI(0x0F03);//SSD2119_GAMMA_CTRL_10

    //
    // Configure Vlcd63 and VCOMl.
    //
    WriteCommandSPI(0x0D);//SSD2119_PWR_CTRL_3_REG
    WriteDataSPI(0x0007);
    WriteCommandSPI(0x0E);//SSD2119_PWR_CTRL_4_REG
    WriteDataSPI(0x3100);

    //
    // Set the display size and ensure that the GRAM window is set to allow
    // access to the full display buffer.
    //
    WriteCommandSPI(SSD2119_V_RAM_POS_REG);
    WriteDataSPI((LCD_VERTICAL_MAX-1) << 8);
    WriteCommandSPI(SSD2119_H_RAM_START_REG);
    WriteDataSPI(0x0000);
    WriteCommandSPI(SSD2119_H_RAM_END_REG);
    WriteDataSPI(LCD_HORIZONTAL_MAX-1);
    WriteCommandSPI(SSD2119_X_RAM_ADDR_REG);
    WriteDataSPI(0x00);
    WriteCommandSPI(SSD2119_Y_RAM_ADDR_REG);
    WriteDataSPI(0x00);

    // Clear the contents of the display buffer.
    WriteCommandSPI(SSD2119_RAM_DATA_REG);
    for(ulCount = 0; ulCount < (320 * 240); ulCount++)
    {
        WriteDataSPI(0x0000);
    }
		LED_backlight_ON();
}

//*****************************************************************************
//
//! Draws a pixel on the screen.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param lX is the X coordinate of the pixel.
//! \param lY is the Y coordinate of the pixel.
//! \param ulValue is the color of the pixel.
//!
//! This function sets the given pixel to a particular color.  The coordinates
//! of the pixel are assumed to be within the extents of the display.
//!
//! \return None.
//
//*****************************************************************************
static void
Kentec320x240x16_SSD2119PixelDraw(void *pvDisplayData, int lX, int lY,
                                   unsigned int ulValue)
{
    //
    // Set the X address of the display cursor.
    //
    WriteCommandSPI(SSD2119_X_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_X(lX, lY));

    //
    // Set the Y address of the display cursor.
    //
    WriteCommandSPI(SSD2119_Y_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_Y(lX, lY));

    //
    // Write the pixel value.
    //
    WriteCommandSPI(SSD2119_RAM_DATA_REG);
    WriteDataSPI(ulValue);
}

//*****************************************************************************
//
//! Draws a horizontal sequence of pixels on the screen.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param lX is the X coordinate of the first pixel.
//! \param lY is the Y coordinate of the first pixel.
//! \param lX0 is sub-pixel offset within the pixel data, which is valid for 1
//! or 4 bit per pixel formats.
//! \param lCount is the number of pixels to draw.
//! \param lBPP is the number of bits per pixel; must be 1, 4, or 8.
//! \param pucData is a pointer to the pixel data.  For 1 and 4 bit per pixel
//! formats, the most significant bit(s) represent the left-most pixel.
//! \param pucPalette is a pointer to the palette used to draw the pixels.
//!
//! This function draws a horizontal sequence of pixels on the screen, using
//! the supplied palette.  For 1 bit per pixel format, the palette contains
//! pre-translated colors; for 4 and 8 bit per pixel formats, the palette
//! contains 24-bit RGB values that must be translated before being written to
//! the display.
//!
//! \return None.
//
//*****************************************************************************
static void
Kentec320x240x16_SSD2119PixelDrawMultiple(void *pvDisplayData, int lX,
                                           int lY, int lX0, int lCount,
                                           int lBPP,
                                           const unsigned char *pucData,
                                           const unsigned char *pucPalette)
{
    unsigned int ulByte;

    //
    // Set the cursor increment to left to right, followed by top to bottom.
    //
    WriteCommandSPI(SSD2119_ENTRY_MODE_REG);
    WriteDataSPI(MAKE_ENTRY_MODE(HORIZ_DIRECTION));

    //
    // Set the starting X address of the display cursor.
    //
    WriteCommandSPI(SSD2119_X_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_X(lX, lY));

    //
    // Set the Y address of the display cursor.
    //
    WriteCommandSPI(SSD2119_Y_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_Y(lX, lY));

    //
    // Write the data RAM write command.
    //
    WriteCommandSPI(SSD2119_RAM_DATA_REG);

    //
    // Determine how to interpret the pixel data based on the number of bits
    // per pixel.
    //
    switch(lBPP)
    {
        //
        // The pixel data is in 1 bit per pixel format.
        //
        case 1:
        {
            //
            // Loop while there are more pixels to draw.
            //
            while(lCount)
            {
                //
                // Get the next byte of image data.
                //
                ulByte = *pucData++;

                //
                // Loop through the pixels in this byte of image data.
                //
                for(; (lX0 < 8) && lCount; lX0++, lCount--)
                {
                    //
                    // Draw this pixel in the appropriate color.
                    //
                    WriteDataSPI(((unsigned int *)pucPalette)[(ulByte >>
                                                             (7 - lX0)) & 1]);
                }

                //
                // Start at the beginning of the next byte of image data.
                //
                lX0 = 0;
            }

            //
            // The image data has been drawn.
            //
            break;
        }

        //
        // The pixel data is in 4 bit per pixel format.
        //
        case 4:
        {
            //
            // Loop while there are more pixels to draw.  "Duff's device" is
            // used to jump into the middle of the loop if the first nibble of
            // the pixel data should not be used.  Duff's device makes use of
            // the fact that a case statement is legal anywhere within a
            // sub-block of a switch statement.  See
            // http://en.wikipedia.org/wiki/Duff's_device for detailed
            // information about Duff's device.
            //
            switch(lX0 & 1)
            {
                case 0:
                    while(lCount)
                    {
                        //
                        // Get the upper nibble of the next byte of pixel data
                        // and extract the corresponding entry from the
                        // palette.
                        //
                        ulByte = (*pucData >> 4) * 3;
                        ulByte = (*(unsigned int *)(pucPalette + ulByte) &
                                  0x00ffffff);

                        //
                        // Translate this palette entry and write it to the
                        // screen.
                        //
                        WriteDataSPI(DPYCOLORTRANSLATE(ulByte));

                        //
                        // Decrement the count of pixels to draw.
                        //
                        lCount--;

                        //
                        // See if there is another pixel to draw.
                        //
                        if(lCount)
                        {
                case 1:
                            //
                            // Get the lower nibble of the next byte of pixel
                            // data and extract the corresponding entry from
                            // the palette.
                            //
                            ulByte = (*pucData++ & 15) * 3;
                            ulByte = (*(unsigned int *)(pucPalette + ulByte) &
                                      0x00ffffff);

                            //
                            // Translate this palette entry and write it to the
                            // screen.
                            //
                            WriteDataSPI(DPYCOLORTRANSLATE(ulByte));

                            //
                            // Decrement the count of pixels to draw.
                            //
                            lCount--;
                        }
                    }
            }

            //
            // The image data has been drawn.
            //
            break;
        }

        //
        // The pixel data is in 8 bit per pixel format.
        //
        case 8:
        {
            //
            // Loop while there are more pixels to draw.
            //
            while(lCount--)
            {
                //
                // Get the next byte of pixel data and extract the
                // corresponding entry from the palette.
                //
                ulByte = *pucData++ * 3;
                ulByte = *(unsigned int *)(pucPalette + ulByte) & 0x00ffffff;

                //
                // Translate this palette entry and write it to the screen.
                //
                WriteDataSPI(DPYCOLORTRANSLATE(ulByte));
            }

            //
            // The image data has been drawn.
            //
            break;
        }

        //
        // We are being passed data in the display's native format.  Merely
        // write it directly to the display.  This is a special case which is
        // not used by the graphics library but which is helpful to
        // applications which may want to handle, for example, JPEG images.
        //
        case 16:
        {
            unsigned short usByte;

            //
            // Loop while there are more pixels to draw.
            //
            while(lCount--)
            {
                //
                // Get the next byte of pixel data and extract the
                // corresponding entry from the palette.
                //
                usByte = *((unsigned short *)pucData);
                pucData += 2;

                //
                // Translate this palette entry and write it to the screen.
                //
                WriteDataSPI(usByte);
            }
        }
    }
}

//*****************************************************************************
//
//! Draws a horizontal line.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param lX1 is the X coordinate of the start of the line.
//! \param lX2 is the X coordinate of the end of the line.
//! \param lY is the Y coordinate of the line.
//! \param ulValue is the color of the line.
//!
//! This function draws a horizontal line on the display.  The coordinates of
//! the line are assumed to be within the extents of the display.
//!
//! \return None.
//
//*****************************************************************************
static void
Kentec320x240x16_SSD2119LineDrawH(void *pvDisplayData, int lX1, int lX2,
                                   int lY, unsigned int ulValue)
{
    //
    // Set the cursor increment to left to right, followed by top to bottom.
    //
    WriteCommandSPI(SSD2119_ENTRY_MODE_REG);
    WriteDataSPI(MAKE_ENTRY_MODE(HORIZ_DIRECTION));

    //
    // Set the starting X address of the display cursor.
    //
    WriteCommandSPI(SSD2119_X_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_X(lX1, lY));

    //
    // Set the Y address of the display cursor.
    //
    WriteCommandSPI(SSD2119_Y_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_Y(lX1, lY));

    //
    // Write the data RAM write command.
    //
    WriteCommandSPI(SSD2119_RAM_DATA_REG);

    //
    // Loop through the pixels of this horizontal line.
    //
    while(lX1++ <= lX2)
    {
        //
        // Write the pixel value.
        //
        WriteDataSPI(ulValue);
    }
}

//*****************************************************************************
//
//! Draws a vertical line.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param lX is the X coordinate of the line.
//! \param lY1 is the Y coordinate of the start of the line.
//! \param lY2 is the Y coordinate of the end of the line.
//! \param ulValue is the color of the line.
//!
//! This function draws a vertical line on the display.  The coordinates of the
//! line are assumed to be within the extents of the display.
//!
//! \return None.
//
//*****************************************************************************
static void
Kentec320x240x16_SSD2119LineDrawV(void *pvDisplayData, int lX, int lY1,
                                   int lY2, unsigned int ulValue)
{
    //
    // Set the cursor increment to top to bottom, followed by left to right.
    //
    WriteCommandSPI(SSD2119_ENTRY_MODE_REG);
    WriteDataSPI(MAKE_ENTRY_MODE(VERT_DIRECTION));

    //
    // Set the X address of the display cursor.
    //
    WriteCommandSPI(SSD2119_X_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_X(lX, lY1));

    //
    // Set the starting Y address of the display cursor.
    //
    WriteCommandSPI(SSD2119_Y_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_Y(lX, lY1));

    //
    // Write the data RAM write command.
    //
    WriteCommandSPI(SSD2119_RAM_DATA_REG);

    //
    // Loop through the pixels of this vertical line.
    //
    while(lY1++ <= lY2)
    {
        //
        // Write the pixel value.
        //
        WriteDataSPI(ulValue);
    }
}

//*****************************************************************************
//
//! Fills a rectangle.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param pRect is a pointer to the structure describing the rectangle.
//! \param ulValue is the color of the rectangle.
//!
//! This function fills a rectangle on the display.  The coordinates of the
//! rectangle are assumed to be within the extents of the display, and the
//! rectangle specification is fully inclusive (in other words, both sXMin and
//! sXMax are drawn, along with sYMin and sYMax).
//!
//! \return None.
//
//*****************************************************************************
static void
Kentec320x240x16_SSD2119RectFill(void *pvDisplayData, const tRectangle *pRect,
                                  unsigned int ulValue)
{
    int lCount;

    //
    // Write the Y extents of the rectangle.
    //
    WriteCommandSPI(SSD2119_ENTRY_MODE_REG);
    WriteDataSPI(MAKE_ENTRY_MODE(HORIZ_DIRECTION));

    //
    // Write the X extents of the rectangle.
    //
    WriteCommandSPI(SSD2119_H_RAM_START_REG);
#if (defined PORTRAIT) || (defined LANDSCAPE)
    WriteDataSPI(MAPPED_X(pRect->i16XMax, pRect->i16YMax));
#else
    WriteDataSPI(MAPPED_X(pRect->i16XMin, pRect->i16YMin));
#endif

    WriteCommandSPI(SSD2119_H_RAM_END_REG);
#if (defined PORTRAIT) || (defined LANDSCAPE)
    WriteDataSPI(MAPPED_X(pRect->i16XMin, pRect->i16YMin));
#else
    WriteDataSPI(MAPPED_X(pRect->i16XMax, pRect->i16YMax));
#endif

    //
    // Write the Y extents of the rectangle
    //
    WriteCommandSPI(SSD2119_V_RAM_POS_REG);
#if (defined LANDSCAPE_FLIP) || (defined PORTRAIT)
    WriteDataSPI(MAPPED_Y(pRect->i16XMin, pRect->i16YMin) |
             (MAPPED_Y(pRect->i16XMax, pRect->i16YMax) << 8));
#else
    WriteDataSPI(MAPPED_Y(pRect->i16XMax, pRect->i16YMax) |
             (MAPPED_Y(pRect->i16XMin, pRect->i16YMin) << 8));
#endif

    //
    // Set the display cursor to the upper left of the rectangle (in application
    // coordinate space).
    //
    WriteCommandSPI(SSD2119_X_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_X(pRect->i16XMin, pRect->i16YMin));

    WriteCommandSPI(SSD2119_Y_RAM_ADDR_REG);
    WriteDataSPI(MAPPED_Y(pRect->i16XMin, pRect->i16YMin));

    //
    // Tell the controller we are about to write data into its RAM.
    //
    WriteCommandSPI(SSD2119_RAM_DATA_REG);

    //
    // Loop through the pixels of this filled rectangle.
    //
    for(lCount = ((pRect->i16XMax - pRect->i16XMin + 1) *
                  (pRect->i16YMax - pRect->i16YMin + 1)); lCount >= 0; lCount--)
    {
        //
        // Write the pixel value.
        //
        WriteDataSPI(ulValue);
    }

    //
    // Reset the X extents to the entire screen.
    //
    WriteCommandSPI(SSD2119_H_RAM_START_REG);
    WriteDataSPI(0x0000);
    WriteCommandSPI(SSD2119_H_RAM_END_REG);
    WriteDataSPI(0x013F);

    //
    // Reset the Y extent to the full screen
    //
    WriteCommandSPI(SSD2119_V_RAM_POS_REG);
    WriteDataSPI(0xEF00);
}

//*****************************************************************************
//
//! Translates a 24-bit RGB color to a display driver-specific color.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//! \param ulValue is the 24-bit RGB color.  The least-significant byte is the
//! blue channel, the next byte is the green channel, and the third byte is the
//! red channel.
//!
//! This function translates a 24-bit RGB color into a value that can be
//! written into the display's frame buffer in order to reproduce that color,
//! or the closest possible approximation of that color.
//!
//! \return Returns the display-driver specific color.
//
//*****************************************************************************
static unsigned int
Kentec320x240x16_SSD2119ColorTranslate(void *pvDisplayData,
                                        unsigned int ulValue)
{
    //
    // Translate from a 24-bit RGB color to a 5-6-5 RGB color.
    //
    return(DPYCOLORTRANSLATE(ulValue));
}

//*****************************************************************************
//
//! Flushes any cached drawing operations.
//!
//! \param pvDisplayData is a pointer to the driver-specific data for this
//! display driver.
//!
//! This functions flushes any cached drawing operations to the display.  This
//! is useful when a local frame buffer is used for drawing operations, and the
//! flush would copy the local frame buffer to the display.  For the SSD2119
//! driver, the flush is a no operation.
//!
//! \return None.
//
//*****************************************************************************
static void
Kentec320x240x16_SSD2119Flush(void *pvDisplayData)
{
    //
    // There is nothing to be done.
    //
}
//*****************************************************************************
//
//! The display structure that describes the driver for the Kentec
//! K350QVG-V2-F TFT panel with an SSD2119 controller.
//
//*****************************************************************************
const tDisplay g_sKentec320x240x16_SSD2119 =
{
    sizeof(tDisplay),
    0,
#if defined(PORTRAIT) || defined(PORTRAIT_FLIP)
    240,
    320,
#else
    320,
    240,
#endif
    Kentec320x240x16_SSD2119PixelDraw,
    Kentec320x240x16_SSD2119PixelDrawMultiple,
    Kentec320x240x16_SSD2119LineDrawH,
    Kentec320x240x16_SSD2119LineDrawV,
    Kentec320x240x16_SSD2119RectFill,
    Kentec320x240x16_SSD2119ColorTranslate,
    Kentec320x240x16_SSD2119Flush
};

//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
5557.Kentec320x240x16_SSD2119_SPI.h

  • Hello Sattar

    It would definitely be useful to a lot of other forum members.

    Regards
    Amit
  • Also, for all who need it, make sure to remove the R10 resistor. It will not work if you don't do that.

    Paulo

  • Paulo Costa said:
    make sure to remove the R10 resistor. It will not work if you don't do that.

    Might it prove wise to remove (equal partner in crime) R9 - as well?      With one pulled - 2nd serves NO purpose!

  • Hi Paulo,

    Thanks for pointing out R10, I really forgot to point out about R10 when using kentec booster pack.

    Sattar Malokani

  • Sattar,


    I am working on "lab 10" from the TM4C123g Workshop. The workshop code seems to be written for the 8bit version of the Kentec display. Thanks to your SPI driver, I now have the Kentec with the SPI interface working as far as displaying the various widgets.   However, I am not getting any response to the touch screen.  I wonder if there is something additional I have to modify to make the touch screen work?


    best regards,

    -- mike

  • Hello Mike,

    First of all did you remove the R10 resistor and secondly, which touch.c/.h file are you using?

    Regards

    Amit

  • Amit,

    Yes, I did remove the R10 resistor, and subsequently the R9 resistor as well.

    I am using the touch.c/h files from "lab 10". The .c file begins with comment:

    // touch.c - Touch screen driver for the DK-LM3S9B96 board.

    I think it may be for the older version of the Boosterpack as well, but I don't know where to find an updated one for the SPI version. Is that a file you can post or send me a reference?

    regards,
    -- mike
  • Hello Mike

    I don't have a tested file, but based on my schematic, the channels are PD0 and PD1 (AIN7 and AIN6 respectively for XP and YP)

    Regards
    Amit
  • Hello Michael,

    The touch drivers for spi are also changed. I have attached the files for you reference. try these I hope these will work.

    regards,

    sattar malokani

    touch350SPI.c
    //*****************************************************************************
    //
    // touch.c - Touch screen driver for the DK-TM4C123GXL board.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    //! \addtogroup touch_api
    //! @{
    //
    //*****************************************************************************
    #include <stdint.h>
    #include <stdbool.h>
    
    #include "inc/hw_adc.h"
    #include "inc/hw_gpio.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_timer.h"
    #include "inc/hw_types.h"
    
    #include "driverlib/adc.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/timer.h"
    
    #include "grlib/grlib.h"
    #include "grlib/widget.h"
    
    #include "drivers/touch.h"
    #include "drivers/Kentec320x240x16_SSD2119_SPI.h"
    
    //*****************************************************************************
    //
    // This driver operates in four different screen orientations.  They are:
    //
    // * Portrait - The screen is taller than it is wide, and the flex connector is
    //              on the left of the display.  This is selected by defining
    //              PORTRAIT.
    //
    // * Landscape - The screen is wider than it is tall, and the flex connector is
    //               on the bottom of the display.  This is selected by defining
    //               LANDSCAPE.
    //
    // * Portrait flip - The screen is taller than it is wide, and the flex
    //                   connector is on the right of the display.  This is
    //                   selected by defining PORTRAIT_FLIP.
    //
    // * Landscape flip - The screen is wider than it is tall, and the flex
    //                    connector is on the top of the display.  This is
    //                    selected by defining LANDSCAPE_FLIP.
    //
    // These can also be imagined in terms of screen rotation; if portrait mode is
    // 0 degrees of screen rotation, landscape is 90 degrees of counter-clockwise
    // rotation, portrait flip is 180 degrees of rotation, and landscape flip is
    // 270 degress of counter-clockwise rotation.
    //
    // If no screen orientation is selected, "landscape flip" mode will be used.
    //
    //*****************************************************************************
    #if ! defined(PORTRAIT) && ! defined(PORTRAIT_FLIP) && \
        ! defined(LANDSCAPE) && ! defined(LANDSCAPE_FLIP)
    #define LANDSCAPE
    //#define PORTRAIT_FLIP
    #endif
    
    //*****************************************************************************
    //
    // The GPIO pins to which the touch screen is connected.
    //
    //*****************************************************************************
    #define TS_P_PERIPH             SYSCTL_PERIPH_GPIOD
    #define TS_P_BASE               GPIO_PORTD_BASE
    #define TS_YP_PIN               GPIO_PIN_0//U
    #define TS_XP_PIN               GPIO_PIN_1//R
    
    #define TS_XN_PERIPH             SYSCTL_PERIPH_GPIOF
    #define TS_XN_BASE               GPIO_PORTF_BASE
    #define TS_XN_PIN               GPIO_PIN_4//L
    
    #define TS_YN_PERIPH             SYSCTL_PERIPH_GPIOA
    #define TS_YN_BASE               GPIO_PORTA_BASE
    #define TS_YN_PIN               GPIO_PIN_2//D
    
    //*****************************************************************************
    //
    // The ADC channels connected to each of the touch screen contacts.
    //
    //*****************************************************************************
    #define ADC_CTL_CH_YP ADC_CTL_CH7
    #define ADC_CTL_CH_XP ADC_CTL_CH6
    
    //*****************************************************************************
    //
    // The coefficients used to convert from the ADC touch screen readings to the
    // screen pixel positions.
    //
    //*****************************************************************************
    #define NUM_TOUCH_PARAM_SETS 2
    #define NUM_TOUCH_PARAMS     7
    
    #define SET_NORMAL           0
    #define SET_SRAM_FLASH       1
    
    //*****************************************************************************
    //
    // Touchscreen calibration parameters.  We store several sets since different
    // LCD configurations require different calibration.  Screen orientation is a
    // build time selection but the calibration set used is determined at runtime
    // based on the hardware configuration.
    //
    //*****************************************************************************
    const int32_t g_lTouchParameters[NUM_TOUCH_PARAM_SETS][NUM_TOUCH_PARAMS] =
    {
        //
        // Touchscreen calibration parameters for use when no LCD-controlling
        // daughter board is attached.
        //
        {
    #ifdef PORTRAIT
            -4320,          // M0
            187008,          // M1
            -175805280,       // M2
            290528,         // M3
            -14208,            // M4
            -129632480,       // M5
            1605992,         // M6
    #endif
    #ifdef LANDSCAPE
         	307456,	// M0
            -6528,	// M1
            -175440160,	// M2
            1464,		// M3
            -308736,		// M4
            992064864,	// M5
            2808747,		// M6
    #endif
    #ifdef PORTRAIT_FLIP
            1152,           // M0
            -194880,         // M1
            586541664,       // M2
            -291584,         // M3
            29984,           // M4
            625271584,       // M5
            1680556,         // M6
    #endif
    #ifdef LANDSCAPE_FLIP
            -291200,// M0	
            18048,// M1	
            644276768,// M2	
            2712,// M3	
            191856,// M4	
            -187423752,// M5	
            1654753,// M6	
    #endif
        },
        //
        // Touchscreen calibration parameters for use when the SRAM/Flash daughter
        // board is attached.
        //
        {
    #ifdef PORTRAIT
            -449664,          // M0
            187008,          // M1
            63226752,       // M2
            -751424,         // M3
            -14912,            // M4
            377755392,       // M5
            -4356880,         // M6
    #endif
    #ifdef LANDSCAPE
            303616,         // M0
            -6912,           // M1
            -171108160,       // M2
            5928,          // M3
            -307128,         // M4
            973099392,       // M5
            2758286,         // M6
    #endif
    #ifdef PORTRAIT_FLIP
            2496,           // M0
            -94368,         // M1
            74406768,       // M2
            -104000,        // M3
            -1600,          // M4
            100059200,      // M5
            290550,         // M6
    #endif
    #ifdef LANDSCAPE_FLIP
            -289920,        // M0
            17280,           // M1
            638897760,       // M2
            1488,             // M3
            191112,          // M4
            -185258712,       // M5
            1640415,         // M6
    #endif
        },
    };
    
    //*****************************************************************************
    //
    // A pointer to the current touchscreen calibration parameter set.
    //
    //*****************************************************************************
    const int32_t *g_plParmSet;
    
    //*****************************************************************************
    //
    // The minimum raw reading that should be considered valid press.
    //
    //*****************************************************************************
    short g_sTouchMin = TOUCH_MIN;
    
    //*****************************************************************************
    //
    // The current state of the touch screen driver's state machine.  This is used
    // to cycle the touch screen interface through the powering sequence required
    // to read the two axes of the surface.
    //
    //*****************************************************************************
    static uint32_t g_ulTSState;
    #define TS_STATE_INIT           0
    #define TS_STATE_READ_X         1
    #define TS_STATE_READ_Y         2
    #define TS_STATE_SKIP_X         3
    #define TS_STATE_SKIP_Y         4
    
    //*****************************************************************************
    //
    // The most recent raw ADC reading for the X position on the screen.  This
    // value is not affected by the selected screen orientation.
    //
    //*****************************************************************************
    volatile short g_sTouchX;
    
    //*****************************************************************************
    //
    // The most recent raw ADC reading for the Y position on the screen.  This
    // value is not affected by the selected screen orientation.
    //
    //*****************************************************************************
    volatile short g_sTouchY;
    
    //*****************************************************************************
    //
    // A pointer to the function to receive messages from the touch screen driver
    // when events occur on the touch screen (debounced presses, movement while
    // pressed, and debounced releases).
    //
    //*****************************************************************************
    static int32_t (*g_pfnTSHandler)(uint32_t ulMessage, int32_t lX, int32_t lY);
    
    //*****************************************************************************
    //
    // The current state of the touch screen debouncer.  When zero, the pen is up.
    // When three, the pen is down.  When one or two, the pen is transitioning from
    // one state to the other.
    //
    //*****************************************************************************
    static unsigned char g_cState = 0;
    
    //*****************************************************************************
    //
    // The queue of debounced pen positions.  This is used to slightly delay the
    // returned pen positions, so that the pen positions that occur while the pen
    // is being raised are not send to the application.
    //
    //*****************************************************************************
    static short g_psSamples[8];
    
    //*****************************************************************************
    //
    // The count of pen positions in g_psSamples.  When negative, the buffer is
    // being pre-filled as a result of a detected pen down event.
    //
    //*****************************************************************************
    static signed char g_cIndex = 0;
    
    //*****************************************************************************
    //
    //! Debounces presses of the touch screen.
    //!
    //! This function is called when a new X/Y sample pair has been captured in
    //! order to perform debouncing of the touch screen.
    //!
    //! \return None.
    //
    //*****************************************************************************
    static void
    TouchScreenDebouncer(void)
    {
        int32_t lX, lY, lTemp;
    
        //
        // Convert the ADC readings into pixel values on the screen.
        //
        lX = g_sTouchX;
        lY = g_sTouchY;
        lTemp = (((lX * g_plParmSet[0]) + (lY * g_plParmSet[1]) + g_plParmSet[2]) /
                 g_plParmSet[6]);
        lY = (((lX * g_plParmSet[3]) + (lY * g_plParmSet[4]) + g_plParmSet[5]) /
              g_plParmSet[6]);
        lX = lTemp;
    
        //
        // See if the touch screen is being touched.
        //
        if((g_sTouchX < g_sTouchMin) || (g_sTouchY < g_sTouchMin))
        {
            //
            // See if the pen is not up right now.
            //
            if(g_cState != 0x00)
            {
                //
                // Decrement the state count.
                //
                g_cState--;
    
                //
                // See if the pen has been detected as up three times in a row.
                //
                if(g_cState == 0x80)
                {
                    //
                    // Indicate that the pen is up.
                    //
                    g_cState = 0x00;
    
                    //
                    // See if there is a touch screen event handler.
                    //
                    if(g_pfnTSHandler)
                    {
                        //
                        // Send the pen up message to the touch screen event
                        // handler.
                        //
                        g_pfnTSHandler(WIDGET_MSG_PTR_UP, g_psSamples[g_cIndex],
                                       g_psSamples[g_cIndex + 1]);
                    }
                }
            }
        }
        else
        {
            //
            // See if the pen is not down right now.
            //
            if(g_cState != 0x83)
            {
                //
                // Increment the state count.
                //
                g_cState++;
    
                //
                // See if the pen has been detected as down three times in a row.
                //
                if(g_cState == 0x03)
                {
                    //
                    // Indicate that the pen is up.
                    //
                    g_cState = 0x83;
    
                    //
                    // Set the index to -8, so that the next 3 samples are stored
                    // into the sample buffer before sending anything back to the
                    // touch screen event handler.
                    //
                    g_cIndex = -8;
    
                    //
                    // Store this sample into the sample buffer.
                    //
                    g_psSamples[0] = lX;
                    g_psSamples[1] = lY;
                }
            }
            else
            {
                //
                // See if the sample buffer pre-fill has completed.
                //
                if(g_cIndex == -2)
                {
                    //
                    // See if there is a touch screen event handler.
                    //
                    if(g_pfnTSHandler)
                    {
                        //
                        // Send the pen down message to the touch screen event
                        // handler.
                        //
                        g_pfnTSHandler(WIDGET_MSG_PTR_DOWN, g_psSamples[0],
                                       g_psSamples[1]);
                    }
    
                    //
                    // Store this sample into the sample buffer.
                    //
                    g_psSamples[0] = lX;
                    g_psSamples[1] = lY;
    
                    //
                    // Set the index to the next sample to send.
                    //
                    g_cIndex = 2;
                }
    
                //
                // Otherwise, see if the sample buffer pre-fill is in progress.
                //
                else if(g_cIndex < 0)
                {
                    //
                    // Store this sample into the sample buffer.
                    //
                    g_psSamples[g_cIndex + 10] = lX;
                    g_psSamples[g_cIndex + 11] = lY;
    
                    //
                    // Increment the index.
                    //
                    g_cIndex += 2;
                }
    
                //
                // Otherwise, the sample buffer is full.
                //
                else
                {
                    //
                    // See if there is a touch screen event handler.
                    //
                    if(g_pfnTSHandler)
                    {
                        //
                        // Send the pen move message to the touch screen event
                        // handler.
                        //
                        g_pfnTSHandler(WIDGET_MSG_PTR_MOVE, g_psSamples[g_cIndex],
                                       g_psSamples[g_cIndex + 1]);
                    }
    
                    //
                    // Store this sample into the sample buffer.
                    //
                    g_psSamples[g_cIndex] = lX;
                    g_psSamples[g_cIndex + 1] = lY;
    
                    //
                    // Increment the index.
                    //
                    g_cIndex = (g_cIndex + 2) & 7;
                }
            }
        }
    }
    
    //*****************************************************************************
    //
    //! Handles the ADC interrupt for the touch screen.
    //!
    //! This function is called when the ADC sequence that samples the touch screen
    //! has completed its acquisition.  The touch screen state machine is advanced
    //! and the acquired ADC sample is processed appropriately.
    //!
    //! It is the responsibility of the application using the touch screen driver
    //! to ensure that this function is installed in the interrupt vector table for
    //! the ADC3 interrupt.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    TouchScreenIntHandler(void)
    {
        //
        // Clear the ADC sample sequence interrupt.
        //
        HWREG(ADC0_BASE + ADC_O_ISC) = 1 << 3;
    
        //
        // Determine what to do based on the current state of the state machine.
        //
        switch(g_ulTSState)
        {
            //
            // The new sample is an X axis sample that should be discarded.
            //
            case TS_STATE_SKIP_X:
            {
                //
                // Read and throw away the ADC sample.
                //
                HWREG(ADC0_BASE + ADC_O_SSFIFO3);
    
                //
                // Set the analog mode select for the YP pin.
                //
                HWREG(TS_P_BASE + GPIO_O_AMSEL) =
                    HWREG(TS_P_BASE + GPIO_O_AMSEL) | TS_YP_PIN;
    
                //
                // Configure the Y axis touch layer pins as inputs.
                //
                HWREG(TS_P_BASE + GPIO_O_DIR) =
                    HWREG(TS_P_BASE + GPIO_O_DIR) & ~TS_YP_PIN;
                //if(g_eDaughterType == DAUGHTER_NONE)
                {
                    HWREG(TS_YN_BASE + GPIO_O_DIR) =
                        HWREG(TS_YN_BASE + GPIO_O_DIR) & ~TS_YN_PIN;
                }
                //else if(g_eDaughterType == DAUGHTER_SRAM_FLASH)
                //{
                //    HWREGB(LCD_CONTROL_SET_REG) = LCD_CONTROL_YN;
                //}
    
                //
                // The next sample will be a valid X axis sample.
                //
                g_ulTSState = TS_STATE_READ_X;
    
                //
                // This state has been handled.
                //
                break;
            }
    
            //
            // The new sample is an X axis sample that should be processed.
            //
            case TS_STATE_READ_X:
            {
                //
                // Read the raw ADC sample.
                //
                g_sTouchX = HWREG(ADC0_BASE + ADC_O_SSFIFO3);
    
                //
                // Clear the analog mode select for the YP pin.
                //
                HWREG(TS_P_BASE + GPIO_O_AMSEL) =
                    HWREG(TS_P_BASE + GPIO_O_AMSEL) & ~TS_YP_PIN;
    
                //
                // Configure the X and Y axis touch layers as outputs.
                //
                HWREG(TS_P_BASE + GPIO_O_DIR) =
                    HWREG(TS_P_BASE + GPIO_O_DIR) | TS_XP_PIN | TS_YP_PIN;
    
                //if(g_eDaughterType == DAUGHTER_NONE)
                {
                    HWREG(TS_YN_BASE + GPIO_O_DIR) =
                        HWREG(TS_YN_BASE + GPIO_O_DIR) | TS_XN_PIN | TS_YN_PIN;
                }
    
                //
                // Drive the positive side of the Y axis touch layer with VDD and
                // the negative side with GND.  Also, drive both sides of the X
                // axis layer with GND to discharge any residual voltage (so that
                // a no-touch condition can be properly detected).
                //
                //if(g_eDaughterType == DAUGHTER_NONE)
                {
                    HWREG(TS_XN_BASE + GPIO_O_DATA +
                          ((TS_XN_PIN) << 2)) = 0;
                    HWREG(TS_YN_BASE + GPIO_O_DATA +
                          ((TS_YN_PIN) << 2)) = 0;
                }
                //else if(g_eDaughterType == DAUGHTER_SRAM_FLASH)
                //{
                //    HWREGB(LCD_CONTROL_CLR_REG) = LCD_CONTROL_XN | LCD_CONTROL_YN;
                //}
                HWREG(TS_P_BASE + GPIO_O_DATA + ((TS_XP_PIN | TS_YP_PIN) << 2)) =
                    TS_YP_PIN;
    
                //
                // Configure the sample sequence to capture the X axis value.
                //
                HWREG(ADC0_BASE + ADC_O_SSMUX3) = ADC_CTL_CH_XP;
    
                //
                // The next sample will be an invalid Y axis sample.
                //
                g_ulTSState = TS_STATE_SKIP_Y;
    
                //
                // This state has been handled.
                //
                break;
            }
    
            //
            // The new sample is a Y axis sample that should be discarded.
            //
            case TS_STATE_SKIP_Y:
            {
                //
                // Read and throw away the ADC sample.
                //
                HWREG(ADC0_BASE + ADC_O_SSFIFO3);
    
                //
                // Set the analog mode select for the XP pin.
                //
                HWREG(TS_P_BASE + GPIO_O_AMSEL) =
                    HWREG(TS_P_BASE + GPIO_O_AMSEL) | TS_XP_PIN;
    
                //
                // Configure the X axis touch layer pins as inputs.
                //
                HWREG(TS_P_BASE + GPIO_O_DIR) =
                    HWREG(TS_P_BASE + GPIO_O_DIR) & ~TS_XP_PIN;
                //if(g_eDaughterType == DAUGHTER_NONE)
                {
                    HWREG(TS_XN_BASE + GPIO_O_DIR) =
                        HWREG(TS_XN_BASE + GPIO_O_DIR) & ~TS_XN_PIN;
                }
                //else if(g_eDaughterType == DAUGHTER_SRAM_FLASH)
                //{
                //    HWREGB(LCD_CONTROL_SET_REG) = LCD_CONTROL_XN;
                //}
    
                //
                // The next sample will be a valid Y axis sample.
                //
                g_ulTSState = TS_STATE_READ_Y;
    
                //
                // This state has been handled.
                //
                break;
            }
    
            //
            // The new sample is a Y axis sample that should be processed.
            //
            case TS_STATE_READ_Y:
            {
                //
                // Read the raw ADC sample.
                //
                g_sTouchY = HWREG(ADC0_BASE + ADC_O_SSFIFO3);
    
                //
                // The next configuration is the same as the initial configuration.
                // Therefore, fall through into the initialization state to avoid
                // duplicating the code.
                //
            }
    
            //
            // The state machine is in its initial state
            //
            case TS_STATE_INIT:
            {
                //
                // Clear the analog mode select for the XP pin.
                //
                HWREG(TS_P_BASE + GPIO_O_AMSEL) =
                    HWREG(TS_P_BASE + GPIO_O_AMSEL) & ~TS_XP_PIN;
    
                //
                // Configure the X and Y axis touch layers as outputs.
                //
                HWREG(TS_P_BASE + GPIO_O_DIR) =
                    HWREG(TS_P_BASE + GPIO_O_DIR) | TS_XP_PIN | TS_YP_PIN;
                //if(g_eDaughterType == DAUGHTER_NONE)
                {
                    HWREG(TS_XN_BASE + GPIO_O_DIR) =
                        HWREG(TS_XN_BASE + GPIO_O_DIR) | TS_XN_PIN;
                    HWREG(TS_YN_BASE + GPIO_O_DIR) =
                        HWREG(TS_YN_BASE + GPIO_O_DIR) | TS_YN_PIN;
                }
    
                //
                // Drive one side of the X axis touch layer with VDD and the other
                // with GND.  Also, drive both sides of the Y axis layer with GND
                // to discharge any residual voltage (so that a no-touch condition
                // can be properly detected).
                //
                HWREG(TS_P_BASE + GPIO_O_DATA + ((TS_XP_PIN | TS_YP_PIN) << 2)) =
                    TS_XP_PIN;
                //if(g_eDaughterType == DAUGHTER_NONE)
                {
                    HWREG(TS_XN_BASE + GPIO_O_DATA +
                          ((TS_XN_PIN) << 2)) = 0;
                    HWREG(TS_YN_BASE + GPIO_O_DATA +
                          ((TS_YN_PIN) << 2)) = 0;
                }
                //else if(g_eDaughterType == DAUGHTER_SRAM_FLASH)
                //{
                //    HWREGB(LCD_CONTROL_CLR_REG) = LCD_CONTROL_XN | LCD_CONTROL_YN;
                //}
                //
                // Configure the sample sequence to capture the Y axis value.
                //
                HWREG(ADC0_BASE + ADC_O_SSMUX3) = ADC_CTL_CH_YP;
    
                //
                // If this is the valid Y sample state, then there is a new X/Y
                // sample pair.  In that case, run the touch screen debouncer.
                //
                if(g_ulTSState == TS_STATE_READ_Y)
                {
                    TouchScreenDebouncer();
                }
    
                //
                // The next sample will be an invalid X axis sample.
                //
                g_ulTSState = TS_STATE_SKIP_X;
    
                //
                // This state has been handled.
                //
                break;
            }
        }
    }
    
    //*****************************************************************************
    //
    //! Initializes the touch screen driver.
    //!
    //! This function initializes the touch screen driver, beginning the process of
    //! reading from the touch screen.  This driver uses the following hardware
    //! resources:
    //!
    //! - ADC sample sequence 3
    //! - Timer 1 subtimer A
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    TouchScreenInit(void)
    {
        //
        // Set the initial state of the touch screen driver's state machine.
        //
        g_ulTSState = TS_STATE_INIT;
    
        //
        // Determine which calibration parameter set we will be using.
        //
        g_plParmSet = g_lTouchParameters[SET_NORMAL];
        //if(g_eDaughterType == DAUGHTER_SRAM_FLASH)
        {
            //
            // If the SRAM/Flash daughter board is present, select the appropriate
            // calibration parameters and reading threshold value.
            //
        //    g_plParmSet = g_lTouchParameters[SET_SRAM_FLASH];
        //    g_sTouchMin = 40;
        }
    
        //
        // There is no touch screen handler initially.
        //
        g_pfnTSHandler = 0;
    
        //
        // Enable the peripherals used by the touch screen interface.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
        SysCtlPeripheralEnable(TS_P_PERIPH);
        SysCtlPeripheralEnable(TS_XN_PERIPH);
        SysCtlPeripheralEnable(TS_YN_PERIPH);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
    
        //
        // Configure the ADC sample sequence used to read the touch screen reading.
        //
        ADCHardwareOversampleConfigure(ADC0_BASE, 4);
        ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_TIMER, 0);
        ADCSequenceStepConfigure(ADC0_BASE, 3, 0,
                                 ADC_CTL_CH_YP | ADC_CTL_END | ADC_CTL_IE);
        ADCSequenceEnable(ADC0_BASE, 3);
    
        //
        // Enable the ADC sample sequence interrupt.
        //
        ADCIntEnable(ADC0_BASE, 3);
        IntEnable(INT_ADC0SS3_TM4C123);
    
        //
        // Configure the GPIOs used to drive the touch screen layers.
        //
        GPIOPinTypeGPIOOutput(TS_P_BASE, TS_XP_PIN | TS_YP_PIN);
    
        //
        // If no daughter board is installed, set up GPIOs to drive the XN and YN
        // signals.
        //
        //if(g_eDaughterType == DAUGHTER_NONE)
        {
            GPIOPinTypeGPIOOutput(TS_XN_BASE, TS_XN_PIN);
            GPIOPinTypeGPIOOutput(TS_YN_BASE, TS_YN_PIN);
        }
    
        GPIOPinWrite(TS_P_BASE, TS_XP_PIN | TS_YP_PIN, 0x00);
        //if(g_eDaughterType == DAUGHTER_NONE)
        {
            GPIOPinWrite(TS_XN_BASE, TS_XN_PIN, 0x00);
            GPIOPinWrite(TS_YN_BASE, TS_YN_PIN, 0x00);
        }
        //else if(g_eDaughterType == DAUGHTER_SRAM_FLASH)
        {
        //    HWREGB(LCD_CONTROL_CLR_REG) = LCD_CONTROL_XN | LCD_CONTROL_YN;
        }
    
        //
        // See if the ADC trigger timer has been configured, and configure it only
        // if it has not been configured yet.
        //
        if((HWREG(TIMER1_BASE + TIMER_O_CTL) & TIMER_CTL_TAEN) == 0)
        {
            //
            // Configure the timer to trigger the sampling of the touch screen
            // every millisecond.
            //
            TimerConfigure(TIMER1_BASE, (TIMER_CFG_SPLIT_PAIR |
                                         TIMER_CFG_A_PERIODIC |
                                         TIMER_CFG_B_PERIODIC));
           // TimerLoadSet(TIMER1_BASE, TIMER_A, (SysCtlClockGet() / 1000 ) - 1);
            TimerLoadSet(TIMER1_BASE, TIMER_A, (SysCtlClockGet() / 4 ) - 1);
            TimerControlTrigger(TIMER1_BASE, TIMER_A, true);
    
            //
            // Enable the timer.  At this point, the touch screen state machine
            // will sample and run once per millisecond.
            //
            TimerEnable(TIMER1_BASE, TIMER_A);
        }
    }
    
    //*****************************************************************************
    //
    //! Sets the callback function for touch screen events.
    //!
    //! \param pfnCallback is a pointer to the function to be called when touch
    //! screen events occur.
    //!
    //! This function sets the address of the function to be called when touch
    //! screen events occur.  The events that are recognized are the screen being
    //! touched (``pen down''), the touch position moving while the screen is
    //! touched (``pen move''), and the screen no longer being touched (``pen
    //! up'').
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    TouchScreenCallbackSet(int32_t (*pfnCallback)(uint32_t ulMessage, int32_t lX,
                                               int32_t lY))
    {
        //
        // Save the pointer to the callback function.
        //
        g_pfnTSHandler = pfnCallback;
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    
    touch.h

  • Hello Sattar,

    There is a bug in the code which is being fixed for the next release. Note that the timer comment is to generate a ADC trigger every 1ms. However the value of system clock when divided by 1000 does not yield a 16-bit load value for the timer. E.g. 80MHz becomes 80000 which is more than 16 bit load value of the timer

    TimerConfigure(TIMER1_BASE, (TIMER_CFG_SPLIT_PAIR |
    TIMER_CFG_A_PERIODIC |
    TIMER_CFG_B_PERIODIC));

    Should be

    TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);

    Regards
    Amit
  • Many thanks to Amit and Sattar both!  I now have lab 10 working.  This, in my mind, is a pivotal lab since I am now able to create projects that I can interact with in a meaningful way.  Your help is very much appreciated.


    best regards,

    -- mike

  • Michael Litzkow said:
    I am now able to create projects that I can interact with in a meaningful way. 

    Quite true my friend - quite true.   And also true - how neat of you to thank poster Sattar and our "Turbo-charged forum expert, Amit."   Such thanks - as you've provided here - is all too infrequent and (really) is the, "Spirit of the forum!"

    Your content - I believe - is very well chosen as well.   So often - a single (or several) Leds serve as, "output indicators."   And in that role - provide value.   Yet - as you suggest - a working, Graphic display enables the creation of clear text messages, and images, counters or bar-graphs and other "info-conveying" adaptations.

    The Led provides (some) value - your success w/a graphic display spectacularly extends that.   Good job...

  • Hi Amit,

    Thank you very much for pointing out bugs, would you please let me know when new release will be available. And once available please tag me.

    thanks a lot.

    Sattar Malokani

  • Hello Sattar,

    The next release is planned for Apr-May time frame.

    Regards
    Amit
  • I just copied and pasted the code into the 8 bit kentec driver files. is that the correct thing to do?

  • I clicked on the links above opened them into word-pad and copied the code. I then pasted it into the existing 8bit driver files, and that did not work. I then tried saving the h and c files as wordpads in the examples,boards,kentec file. That did not work either. I am still getting this error. how do i fix it?error kentec.h

  •  This didnt open. The error says

  • Hello Michael

    I would suggest importing the existing examples and baselining the board-setup.

    Also another request would be to stop using different posts to communicate. rather use a new post so that I can track the progress and debug. Otherwise it becomes too difficult to make connections between multiple posts that you are using to respond/
  • Hello Amit,

    Sorry for the incoveniance i just kept seeing new things to trouble shoot so I replied to those posts. I am not quite sure as to what you mean by importing the existing examples and baselining the board-setup? I thought i could just add in the new kentec spi interface? I added the directories to it and it did build but now I got a different error #148 saying that the void Kentec(void) function isnt compatable. Any ideas?

  • Hello Michael,

    First open a new post. We can track that post for all the Q&A and debug.
  • Okay i just posted one int he TM4C forum
  • Guys - Having just received a Kentec QVGA S1, I'd like to see how to integrate it with either the MSP-EXP430FR5969 or the EK-TM4C129.

    IE, I know I have some work ahead - but which examples are the best jumping-off point?
  • I should certainly answer my own question here. Contained in the TivaWare 'complete' download are examples for the Kentec display. Build and run cleanly out-of-the-box on the EK-TM4C1294EXL. ( Apologies for the noob questions; am new to the TI ecosystem. )

    Thanks to all who contributed to this!

    ( Would love to find the most current revision of the Workshop 10, which references the new spi interface for the Kentec )

  • LouEEEE! said:
    Would love to find the most current revision of the Workshop 10 ... references the new spi interface

    Might that "love" first require the creation of such a revision?       Neither firm nor I use this - yet I cannot recall any "hint or promise" of such a revision.

    Thus - has anyone any awareness of such an update to poster's requested, "Workshop 10?"     (employing the new SPI interface)