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.

Trouble with SPI/SSI buffer - TM4C with EA DOGS102W6 LCD display

Hi all,

I am working with a TM4C123GXL trying to operate an LCD display, EA DOGS120W6. I am using some sample code I got from the manufacturer for an Atmel chip, so adapting that to work with TM4C. I found a couple of TM4C sample programs using SSI/SPI so I am using those as my guide. First, two amateur questions:

  1. Is there a difference between SSI and SPI? Or are they just different names for the same thing (such as IIC and I2C)?
  2. Do I need to use UDMA to send data via SSI? The LCD I am using only receives data 8 bits at a time, and cannot transmit data (there is no transmit line on the display) so I don't need very sophisticated data transfer. The reason I ask is that many of the examples I'm finding use UDMA, and I'm hoping I don't have to dig into that. Learning to work with two different peripherals to operate a simple display sounds a bit daunting!

Now, on to my problem. Here's the code I'm using to set up SSI and the LCD display:

//!*****************************************************************************
//! INCLUSIONS
//!*****************************************************************************

// These are included by the system
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/debug.h"
#include "driverlib/fpu.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"

// I added these
#include "uart0stdio.h"				// Console
#include "uart1stdio.h"				// GSM
#include "string.h"
#include "stdio.h"
#include <stdlib.h>
#include "buttons.h"
#include "driverlib/systick.h"
#include "driverlib/eeprom.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "driverlib/i2c.h"
#include "inc/hw_i2c.h"
#include "driverlib/timer.h"
#include "driverlib/ssi.h"
#include "inc/hw_ssi.h"
#include <inttypes.h>
#include "font_6x8.h"				// Small fonts for LCD
#include "font_8x16.h"				// Large fonts for LCD

//!*****************************************************************************
//! DEFINITIONS
//!*****************************************************************************

// For LCD screen
#define NUM_SSI_DATA 2
#define XPIXEL 102
#define YPIXEL 64
#define XMAX XPIXEL-1
#define YMAX YPIXEL-1
#define DELETE 0
#define ADD	1
#define INVERS 2

//!*****************************************************************************
//! GLOBAL VARIABLES
//!*****************************************************************************

unsigned char LCDbuffer[XPIXEL][YPIXEL/8];

//!*****************************************************************************
//! FUNCTIONS
//!*****************************************************************************

//*****************************************************************************
//
// INITIALIZE SSI/SPI FOR LCD
// PD0 - clock
// PD1 - chip select
// PD2 - MISO / TX
// PD3 - MOSI / RX - NOT PRESENT ON LCD
// PD6 - command
// PD7 - reset
//
//*****************************************************************************
void
initSSI3(void)
{
	uint32_t trashBin[1] = {0};

	// Configure D1 as the SSI Chip Select, set high
	ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_1);
	ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1);

	// Configure D6 as the LCD command, set high
	ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_6);
	ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, GPIO_PIN_6);
	
	// Configure GPIO Pins for SSI3 mode.
	ROM_GPIOPinConfigure(GPIO_PD0_SSI3CLK);
	ROM_GPIOPinConfigure(GPIO_PD3_SSI3TX);
	ROM_GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_3 | GPIO_PIN_0);

	SSIConfigSetExpClk(SSI3_BASE, ROM_SysCtlClockGet(), SSI_FRF_MOTO_MODE_3, SSI_MODE_MASTER, 1000000, 8);

	SSIEnable(SSI3_BASE);

	/* Clear SSI0 RX Buffer */
	while (ROM_SSIDataGetNonBlocking(SSI3_BASE, &trashBin[0])) {}
}

//*****************************************************************************
//
// SEND BYTE ON SSI3
//
//*****************************************************************************
void
SSI3sendByte(uint8_t theData)
{
	uint32_t trashBin[1] = {0};
	
	while (ROM_SSIDataGetNonBlocking(SSI3_BASE, &trashBin[0])) {}
	
	SSIDataPut(SSI3_BASE, theData);			// Send the data
	while(SSIBusy(SSI3_BASE)) {}			// Wait for transmission to finish
	
	/* Clear SSI0 RX Buffer */
	while (ROM_SSIDataGetNonBlocking(SSI3_BASE, &trashBin[0])) {}
}

//*****************************************************************************
//
// SEND BYTE ON LCD
//
//*****************************************************************************
void
LCDsend(uint8_t theData, uint8_t cmdByte)
{
	ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1);				// Slave select
	
	if (cmdByte == 0){ ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, 0); }	//Send command (DCD to 0)
	else { ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, GPIO_PIN_6); }		//Send data (DCD to 1)
	SSI3sendByte(theData);													//Send data
}

//*****************************************************************************
//
// CLEAR LCD
//
//*****************************************************************************
void
LCDclear(uint8_t xs, uint8_t ys, uint8_t xe, uint8_t ye)
{
	//i,j are index variables
	//ps, pe are page start and endadress
	//yr is restpixels
	uint8_t i=0,j=0, ps=0, pe=0, yr=0;

	ps=ys/8; //calculate startpage
	pe=ye/8; //calculate endpage

	//-------------Clear part of startpage--------------
	//Set coloumn adress
	LCDsend(xs&0x0F,0);      //LSB adress
	LCDsend(0x10+(xs>>4),0); //MSB adress

	//set page adress
	LCDsend(0xB0+ps,0);

	j=0xFF; //use j as buffer
	if (pe == ps) //if start and endadress are in same page you have to make sure, not to delete to much
	{
		j=ye%8-0xFF; //calculate stop within first page
	}
	yr=ys%8; //calculate the start within first page
	for(i=xs; i<=xe; i++) //loop starting first colomn to last coloumn
	{
		LCDbuffer[i][ps]&=j>>(8-yr);	//clear the buffer
		LCDsend(LCDbuffer[i][ps],1);	//send the changed pages of the buffer to the display
	}

	//-------------Clear part of endpage----------------
	//Set coloumn adress
	LCDsend(xs&0x0F,0);		//LSB adress
	LCDsend(0x10+(xs>>4),0); //MSB adress

	//set page adress
	LCDsend(0xB0+pe,0);
	yr=ye%8; //calculate the stop within last page

	for(i=xs; i<=xe; i++) //loop starting first colomn to last coloumn
	{
		LCDbuffer[i][pe]&=(0xFF<<(yr+1)); //clear the buffer
		LCDsend(LCDbuffer[i][pe],1);  //send the changed pages of the buffer to the display
	}

	//-------------------Clear middle pages----------------------
	for(j=ps+1; j<pe; j++) //loop starting first middle page to last middle page
	{
		//Set coloumn adress
		LCDsend(xs&0x0F,0); 		//LSB adress
		LCDsend(0x10+(xs>>4),0);	//MSB adress

		//set page adress
		LCDsend(0xB0+j,0);

		for(i=xs; i<=xe; i++) //loop starting first colomn to last coloumn
		{
			LCDbuffer[i][j]=0x00; //clear the buffer
			LCDsend(0x00,1);   //clear display same as LCDsend(LCDbuffer[i][j]);
		}
	}
}

//*****************************************************************************
//
// INITIALIZE LCD
// PD0 - clock
// PD1 - chip select
// PD2 - MISO / TX
// PD3 - MOSI / RX
// PD6 - command
// PD7 - reset
//
//*****************************************************************************
void
initLCD(void)
{
	// Configure D7 as the LCD reset
	ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_7);
	//Set display reset to high -> LCD is running now
	ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_7, GPIO_PIN_7);
	UART0printf("\n\r-> PD7 set as LCD reset, pulled high...");

	//Initialize bottom view 3.3V (booster on) 8Bit SPI
	LCDsend(0x40,0); //Startline 0
	LCDsend(0xA1,0); //SEG reverse
	LCDsend(0xC0,0); //Set COM direction (COM0-COM63)
	LCDsend(0xA4,0); //Set all Pixel to on
	LCDsend(0xA6,0); //Display inverse off
	LCDsend(0xA2,0); //Set bias 1/9
	LCDsend(0x2F,0); //Booster, regulator, follower on
	LCDsend(0x27,0); //Set contrast
	LCDsend(0x81,0); //Set contrast
	LCDsend(0x10,0); //Set contrast
	LCDsend(0xFA,0); //Temperature compensation
	LCDsend(0x90,0); //Temperature compensation
	LCDsend(0xAF,0); //Display on
	UART0printf("\n\r-> LCD parameters set...");

	LCDclear(0,0,XPIXEL-1,YPIXEL-1); //Clear display and set display buffer to 0
	UART0printf("\n\r-> Display cleared...");
}

int
main(void)
{
	// Initial settings
	ROM_FPUEnable();											// Enable floating point unit
	ROM_FPULazyStackingEnable();								// Enable lazy stacking of FPU
	ROM_IntMasterEnable();										// Enable processor interrupts
	
	// Enable device clocking
	ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
	
	// Enable peripherals
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);			// Pins: LCD screen
	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);				// SSI3 for EA DOGS102W6 LCD display
	
	initSSI3();			// Start SSI3/SPI for sending data to LCD
	UART0printf("\n\r> SPI 3 initiated...");
	initLCD();			// Start the LCD screen
	UART0printf("\n\r> EA DOGS102W6 LCD display initiated...");
	
	//Printing a line in big fonts, inverted
	LCDstring(0,5,"EA DOGS102-6!", ptr_font_8x16, INVERS); 
	//Printing next line small fonts, normal
	//LCDstring(0,5 + (uint8_t)ptr_font_8x16 + 5, "this is next line", ptr_font_6x8, DELETE);
	//loop to make a line consisting of small rectangles
	while (i<XMAX) //loop to make a line consisting of small rectangles
	{
		LCDrect(i,32,i+4,32+4); //Making small rectangles as line
		i+=8;
	}
	
	while(1){}
}

When I run this code, the program hangs immediately after executing the LCDclear() function (called by initLCD()). I did some debugging, and if I eliminate all the lines including LCDbuffer, then the function completes (but obviously, doesn't do what it's supposed to). So I believe the problem must be related to this variable and/or how I'm using it. But that's where I'm stuck - not sure what to do next.

Any help is greatly appreciated!

  • Follows several quick/dirty comments/observations:

    • PD2 - MISO / TX
      // PD3 - MOSI / RX - NOT PRESENT ON LCD

    MISO abbreviates, "Master IN - Slave OUT" - thus this is RX - not TX as you show

    MOSI is "Master OUT - Slave In" this then is TX - not RX as you show.   And you've commented this line out - thus you cannot transmit.

    You may begin there.

    Further you write, "(called by LCDinit)" yet No such function reveals!   You have (instead) an "initLCD()" - such attention to detail is required.

    Function "LCDclear()" is HUGE - way too large to (effectively) troubleshoot.    Might you break it down into smaller functions?

    As always - kicking KISS to the curb (as you/others do - w/alarming regularity) proves not best/brightest.  

    Your acquisition of a simple SPI EEProm would far better enable you to master SPI - which should be done prior to attacking your far more demanding display...

    SSI is this vendor's naming convention for the (more usual) SPI.   You do NOT require µDMA to utilize SPI - such speeds - but adds great complexity - I'd "hold" that till you achieve basic display mastery...

  • Thanks cb1, I edited those two mistakes and fixed the pin assignment in my code, but there is no change.

    The LCDclear() function is copied from the LCD manufacturer, I was hoping I could get away with using it verbatim, but that seems not to be the case. I'm going to dig into it a bit and see what I come up with. Stay tuned...

    Otherwise, do my core functions - LCDsend and SSI3sendByte - look correct?

    Thanks again!
  • Much more basic data is required to truly (and effectively) assist.

    You list your MCU - yet not its carrier. If a LPad - danger lurks on/around PD0 & iirc PD1.    Your job must be to closely review your board's schematic - and actively search for any/all "special connections and/or signal handling!" PD0 - for sure - finds itself directly connected to another MCU pin - that's rarely good - and often very wrong. (and it's your job to discover & deal w/such issues)   Such "interesting" (and destructive) forced connection IS noted upon your LPad schematic!

    I could spend the time/effort to exhaustively review your code - yet how does that improve your skill level? A suggestion to adopt KISS was made - most always this will speed, ease & enhance - both your (and my) troubleshooting efforts. You're silent as to your adoption.

    My preference is for a troubleshooting "collaboration" - not for a "cookbook fix" - which cannot best serve you - now and especially long-term.

  • Hi cb1,

    Yes, I'm moving in the KISS direction - basically simplifying my code backwards until I find what is causing the problem. Then from that point I will build my code back up to the functionality I need.

    There are a few terms in your question I'm not familiar with. What do you mean by carrier? I assume you mean the board that's housing the LCD screen and other external hardware I'm working with. If that's the case, then it is a custom designed board made by another member of my team here.

    Second - what do you mean by LPad? I have the schematic for the dev board I'm using, and it doesn't show anything connected to any of the port D pins I need:


    I definitely agree on the collaboration point - right now I'm just working at getting anything on the display, but once crossing that hurdle will need to do quite a bit more with it so knowing the ins and outs of SSI is critical to me!

    However, your point on the MISO vs MOSI pins was very helpful, and obviously something I had overlooked.

    Now, following your suggestion, I am checking the physical voltages on my board vs the software settings to make sure things line up, and have found an issue with PD7, which I'm using for reset. It seems the board designer included a 10k ohm resistor to ground here, and I have an inkling it doesn't belong, so I'm pursuing that with him.

    However, I find the documentation on SSI to be rather un-helpful for someone, like myself, just starting out with SSI and SPI. The Tiva manual includes a description of all the SSI functions and what they do - but not when or why one should use them. This is why I was wondering if you could look at the the two "critical" functions in my code - to see if there are some simple/beginner mistakes I am making:

    //*****************************************************************************
    //
    // SEND BYTE ON SSI3
    //
    //*****************************************************************************
    void
    SSI3sendByte(uint8_t theData)
    {
    	uint32_t trashBin[1] = {0};
    	
    	while (ROM_SSIDataGetNonBlocking(SSI3_BASE, &trashBin[0])) {}
    	
    	SSIDataPut(SSI3_BASE, theData);			// Send the data
    	while(SSIBusy(SSI3_BASE)) {}			// Wait for transmission to finish
    	
    	/* Clear SSI0 RX Buffer */
    	while (ROM_SSIDataGetNonBlocking(SSI3_BASE, &trashBin[0])) {}
    }
    
    //*****************************************************************************
    //
    // SEND BYTE ON LCD
    //
    //*****************************************************************************
    void
    LCDsend(uint8_t theData, uint8_t cmdByte)
    {
    	ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1);				// Slave select
    	
    	if (cmdByte == 0){ ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, 0); }	//Send command (DCD to 0)
    	else { ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, GPIO_PIN_6); }		//Send data (DCD to 1)
    	SSI3sendByte(theData);													//Send data
    }

    Thanks!

  • Sorry - I dislike "free vendor promotion" so LPad means Launchpad - the standard Eval board for your MCU. That board - in (someone's) infinite wisdom - wired 2 sets of MCU pins directly together. (PD0 being one)

    Your PD7 may default as NMI - read the MCU's manual under GPIO for a "mice-type" warning. (vendor cannot bear to admit mistakes - some say (never moi))

    Via KISS - you must master SPI prior to engaging the LCD - that's clear. (I've been "forever" in display biz - trust me (please) on this). A simple SPI based EEProm (1 (USD)) will enable you to build familiarity & confidence w/SPI - both required prior to display engagement.

    Too much - too soon - rarely leads to Roma. (Rome) Yes you're in a rush - yet most all short-cuts yield the opposite - and SPI (due to your choice of that display) is issue one. (unless you choose a far more conventional (and way lower cost) parallel Lcd...)
  • Hi cb1,

    Thanks for the tip on NMI - I found another forum post where you offered steps on how to unlock PD7 and that is now working.

    Also, I think I figured out what you mean about PD0:

    Why is this done, and how do I get around it? Or does this mean that what appears to be four GPIO pins: PD0, PD1, PB6, PB7 is in fact only two: PD0/PB6, PD1,PB7?

    As to KISS and using SPI with EEPROM - that sounds like a logical debugging step to pursue once I get this pin business sorted out.

    Thanks again!

  • Lee Shaver said:
    found another forum post where you offered steps on how to unlock PD7 and that is now working.

    Good that - 101 wrong - 3 right - but (really) who's counting?

    And Eureka - you've found vendors (always) helpful "dead short" between MCU pins.   It's reported that crack decision was made so that past (far lesser) "M0-killer" vendor MCUs could serve here, too.   Yet - that happens rarely - and vendor cannot bring themselves to "Declare Victory" and provide those 2, 0Ω "plague-istors" in a (proper) plastic bag - for those (extreme few) who actually seek (lesser MCU) compatibility!  

    You must remove those 2 devils - I suggest that you "tombstone" them - hard to lose and you'll be (always) reminded of vendor's great care/concern.   (alas little of that directed toward you/other board users...)   (tombstone = remove the 0Ω R - and reinstall it vertically (contacting just one pad - thus "out of circuit.")

    SPI via EEProm always proves best/brightest.    And you'll (always) find great benefit from the ability to read & write non-volatile data - you will!

    If I seem (slightly) negative - that may result from multiple YEARS of begging vendor to FIX this insane 0Ω "plague!"   Vendor (always) "duly notes" (code for, Do nothing!)

    We were taught that to succeed in Sales one should make the purchase & use of product, "Comfortable & Convenient!"   Plague-istors achieve neither - and continue to disrupt hundreds - as (near daily) reported here...   Go figure.   (vendor inertia far trumps user success, ease, morale...)

  • Well, I've made quite a bit of progress in the last couple of days. Using SSI3 on port D involves a bit of fiddling - had to unlock that NMI pin and desolder those 0 ohm resistors.

    Then, I learned that Fss is the same as chip select. Does anyone know what Fss stands for, and why it's always written Fss and not FSS? Strange. Also learned that Tiva's SPI peripheral handles the Fss toggling, where the Atmel chip (for which the code I'm adapting was written) needs the user to handle this. So, I had to give control of Fss to the SSI peripheral.

    Once I took care of these things, I studied the SPI example in the TI library and re-wrote my SPI send function - lo and behold it works! My LCD comes on and shows some static. Now I'm encountering a very strange problem....

    In my LCDclear function below, whenever a value greater than around 86 is sent in xe, it causes my entire program to crash. I've stripped out the function to the parts that seem to be causing problems and here's what I'm left with:

    void
    LCDclear(uint8_t xs, uint8_t ys, uint8_t xe, uint8_t ye)
    {
    	//i,j are index variables
    	//ps, pe are page start and endadress
    	//yr is restpixels
    	uint8_t i=0,j=0, ps=0, pe=0, yr=0;
    
    	ps=ys/8; //calculate startpage
    	pe=ye/8; //calculate endpage
    
    	//-------------Clear part of startpage--------------
    	//Set coloumn adress
    	LCDsend(xs&0x0F,0);      //LSB adress
    	LCDsend(0x10+(xs>>4),0); //MSB adress
    
    	//set page adress
    	LCDsend(0xB0+ps,0);
    
    	j=0xFF; //use j as buffer
    	//if start and endadress are in same page you have to make sure, not to delete to much
    	if (pe == ps) { j=ye%8-0xFF; } //calculate stop within first page
    
    	yr=ys%8; //calculate the start within first page
    	for(i=xs; i<=xe; i++) //loop starting first colomn to last coloumn
    	{
    		LCDbuffer[i][ps]&=j>>(8-yr);     //clear the buffer
    		LCDsend(LCDbuffer[i][ps],1); //send the changed pages of the buffer to the display
    	}
    }

    This is the line that is causing problems:

    LCDbuffer[i][ps]&=j>>(8-yr);

    If I comment this line out, the code executes. Otherwise, when i reaches 90, the program crashes and restarts itself. If I skip over 90 by including the following line in that last for loop:

    if (i==90){i++;}

    ...the code works just fine.

    I'm going to continue debugging but I'm leaving it for the evening, figured I'd post this now in case anyone might be able to take a look before I pick it back up tomorrow.

    Thanks!

  • Have allowed 15+ hours for "anyone's" arrival - no takers...

    Poster wrote: "When i reaches 90, the program crashes!"  

    And w/in his first post - following appeared:

    Lee Shaver said:
    LCDsend(0x90,0); //Temperature compensation

    Might you have over-looked the above?   One expects that an extra (special/parallel) bit is required to distinguish between Lcd "Commands & Data."  I assume that "Temp Comp" falls under "command" - and that you should be able to send "0x90" as "data."

    As to Fss - the "ss" is easy (slave select).   I've swags as for "F" but propose that you (really) read the MCU manual "SPI Chapter" and report.   (should this matter - of course we may always await "anyone...")

  • Yes, anyone doesn't seem to be arriving! You must get lonely in here cb1!

    That's a good catch but not the issue... i is type uint8_t but that 0x90 is in hex, so 144 in dec. Also, i is not being sent through LCDsend, it's a pointer for the array LCDbuffer (which is sent through LCDsend).

    I'm working through the other lines of the code, wondering if there's a good tool or software calculator to punch in things like j=ye%8-0xFF and see what it's actually doing?

  • The way my (forum) day is turning out - should have gone sailing.

    But a really good day at work. (managed NOT to confuse Hex w/Dec...) Brand new Yokogawa WT1800 - 3 phase power analyzer - up/running...
  • I re-wrote the LCDclear function in a way that makes more sense to me (adapted from source). It no longer quits at i=90 (note I changed i to iCol for indexColumn since I kept forgetting what it was I was indexing). Here's the new and improved code:

    void
    LCDclear(uint8_t xPxStart, uint8_t yPxStart, uint8_t xPxEnd, uint8_t yPxEnd)
    {
    	uint8_t iCol=0,iPg=0,pgStart=0,pgEnd=0,skipPx=0;
    	uint8_t maskPx = 0xFF;	// Mask when first and last pixel are on start page
    	
    	// Calculate start and end pages
    	pgStart=yPxStart/8;
    	pgEnd=yPxEnd/8;
    
    	/// CLEAR FIRST PAGE from FIRST COLUMN
    	LCDsend(0xB0+pgStart,0);		// Set page address
    	LCDsend(0x0F&xPxStart,0);		// Set LSB of column address
    	LCDsend(0x10+(xPxStart>>4),0);	// Set MSB of column address
    
    	// Find start within first page
    	skipPx=yPxStart%8;
    	// Find stop within first page (if first and last pixel are on the same page)
    	if (pgEnd == pgStart) { maskPx=yPxEnd%8-0xFF; }
    	
    	// Loop from first to last column
    	for(iCol=xPxStart; iCol<=xPxEnd; iCol++)
    	{
    		LCDbuffer[iCol][pgStart]&=maskPx>>(8-skipPx);	// Clear appropriate parts of the buffer
    		LCDsend(LCDbuffer[iCol][pgStart],1);		// Send buffer to display
    	}
    
    	/// CLEAR LAST PAGE to LAST COLUMN
    	LCDsend(0xB0+pgEnd,0);			// Set page address
    	LCDsend(0x0F&xPxStart,0);		// Set LSB of column address
    	LCDsend(0x10+(xPxStart>>4),0);	// Set MSB of column address
    	
    	// Find stop within last page
    	skipPx=yPxEnd%8;
    
    	// Loop from first to last column
    	for(iCol=xPxStart; iCol<=xPxEnd; iCol++)
    	{
    		LCDbuffer[iCol][pgEnd]&=(0xFF<<(skipPx+1));	// Clear appropriate parts of the buffer
    		LCDsend(LCDbuffer[iCol][pgEnd],1);			// Send buffer to display
    	}
    
    	/// CLEAR MIDDLE PAGES and ALL COLUMNS
    	// Loop from second page to last page less one
    	for(iPg=pgStart+1; iPg<pgEnd; iPg++)
    	{
    		LCDsend(0xB0+iPg,0);			// Set page address
    		LCDsend(0x0F&xPxStart,0);		// Set LSB of column address
    		LCDsend(0x10+(xPxStart>>4),0);	// Set MSB of column address
    
    		// Loop from first to last column (no need for buffer as we're clearing all)
    		for(iCol=xPxStart; iCol<=xPxEnd; iCol++) { LCDsend(0x00,1); }
    	}
    }
    

    This code accomplishes its purpose of clearing the display. Success! But as soon as the function completes executing, it crashes my entire program and causes it to start over from the beginning, running it in an endless loop.

    So, I simplified my entire program down to just the bare essentials to run this one function, and it runs without crashing. What does this tell me? I don't know... how do I debug my program to determine what's causing this? am I running out of memory? triggering an interrupt somewhere?

    I also tried moving the LCDbuffer array into the function, instead of declaring it globally for the whole program. This also worked. Why? Should I do it this way? Many of my LCD functions use LCDbuffer, so I assume declaring it globally was the way to go, even though they're all modifying it on their own, not preserving it's value after running.

    Help!

  • Usually - but not always - issues you note are the result of insufficient "stack."    Many posts (here) detail quick/simple means to increase the stack. 

    In general - many small, limited functions (clearly labeled) vastly improve (when compared to few, larger ones) one's ability to design, troubleshoot & maintain code...

    Early on you were cautioned about the "huge" Lcdclear() function...

  • Got it working. There were some problems elsewhere in my code causing the stack overflow, not the code for the LCD display. Below is the code that works. I'm still working in optimizing a few things. For instance, the LCDchar and LCDstring functions came from TI's MSP430 code, and I had to hack it up a bit to get it to work, so I'll be simplifying that. Also, there are three lines for setting an address that get used quite a bit that I'm going to turn in to functions. But, I wanted to make a progress report! Once I've got it in a final state I'll post it here.

    Also note, I just cut my entire program down to the relevant sections as best I could, so some things may be screwy (in particularly I'm not sure which of those inclusions are actually still needed for what this code snippet does).

    //!*****************************************************************************
    //! INCLUSIONS
    //!*****************************************************************************
    
    // These are included by the system
    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_memmap.h"
    #include "driverlib/debug.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "string.h"
    #include "stdio.h"
    #include <stdlib.h>
    #include "driverlib/systick.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/ssi.h"
    #include "inc/hw_ssi.h"
    
    //!*****************************************************************************
    //! DEFINITIONS
    //!*****************************************************************************
    
    // For LCD screen
    #define XPIXEL			102
    #define YPIXEL			64
    #define XMAX			XPIXEL-1
    #define YMAX			YPIXEL-1
    #define LCD_CMD			0
    #define LCD_DATA		1
    #define NORMAL			1
    #define INVERSE			2
    
    // Functions
    void initSSI3(void);
    void SSI3sendByte(uint32_t theData);
    void initLCD(void);
    void LCDsend(uint32_t theData, uint8_t cmdByte);
    void LCDclear(uint8_t xs, uint8_t ys, uint8_t xe, uint8_t ye);
    void LCDfill(uint8_t xs, uint8_t ys, uint8_t xe, uint8_t ye);
    void LCDchar(uint8_t row, uint8_t col, uint16_t f, uint8_t style);
    void LCDstring(uint8_t row, uint8_t col, char *word, uint8_t style);
    void LCDline(uint8_t xs, uint8_t ys, uint8_t xe, uint8_t ye);
    void LCDrect(uint8_t xs, uint8_t ys, uint8_t xe, uint8_t ye);
    
    //!*****************************************************************************
    //! GLOBAL VARIABLES
    //!*****************************************************************************
    
    // For LCD: Font lookup table
    static const uint8_t FONT6x8[] = {
        /* 6x8 font, each line is a character each byte is a one pixel wide column
         * of that character. MSB is the top pixel of the column, LSB is the bottom
         * pixel of the column. 0 = pixel off. 1 = pixel on. */
    
    	  0,   0,   0,   0,   0,   0,
    	  0,   0,  95,   0,   0,   0,
    	  0,   7,   0,   7,   0,   0,
    	 20, 127,  20, 127,  20,   0,
    	 18,  42, 127,  42,  36,   0,
    	 98, 100,   8,  19,  35,   0,
    	 80,  32,  86,  73,  54,   0,
    	  0,   3,   7,   8,   0,   0,
    	  0,  65,  34,  28,   0,   0,
    	  0,  28,  34,  65,   0,   0,
    	 42,  28, 127,  28,  42,   0,
    	  8,   8,  62,   8,   8,   0,
    	  0,  48, 112, 128,   0,   0,
    	  8,   8,   8,   8,   8,   0,
    	  0,  96,  96,   0,   0,   0,
    	  2,   4,   8,  16,  32,   0,
    	 62,  69,  73,  81,  62,   0,
    	  0,  64, 127,  66,   0,   0,
    	 70,  73,  81,  97,  66,   0,
    	 51,  77,  73,  65,  33,   0,
    	 16, 127,  18,  20,  24,   0,
    	 57,  69,  69,  69,  39,   0,
    	 48,  73,  73,  74,  60,   0,
    	  7,   9,  17,  33,  65,   0,
    	 54,  73,  73,  73,  54,   0,
    	 30,  41,  73,  73,   6,   0,
    	  0,   0,  20,   0,   0,   0,
    	  0,   0,  52,  64,   0,   0,
    	 65,  34,  20,   8,   0,   0,
    	 20,  20,  20,  20,  20,   0,
    	  8,  20,  34,  65,   0,   0,
    	  6,   9,  81,   1,   2,   0,
    	 78,  89,  93,  65,  62,   0,
    	124,  18,  17,  18, 124,   0,
    	 54,  73,  73,  73, 127,   0,
    	 34,  65,  65,  65,  62,   0,
    	 62,  65,  65,  65, 127,   0,
    	 65,  73,  73,  73, 127,   0,
    	  1,   9,   9,   9, 127,   0,
    	122,  73,  73,  65,  62,   0,
    	127,   8,   8,   8, 127,   0,
    	  0,  65, 127,  65,   0,   0,
    	  1,  63,  65,  64,  32,   0,
    	 65,  34,  20,   8, 127,   0,
    	 64,  64,  64,  64, 127,   0,
    	127,   2,  28,   2, 127,   0,
    	127,  16,   8,   4, 127,   0,
    	 62,  65,  65,  65,  62,   0,
    	  6,   9,   9,   9, 127,   0,
    	 94,  33,  81,  65,  62,   0,
    	 70,  41,  25,   9, 127,   0,
    	 50,  73,  73,  73,  38,   0,
    	  1,   1, 127,   1,   1,   0,
    	 63,  64,  64,  64,  63,   0,
    	 31,  32,  64,  32,  31,   0,
    	 63,  64,  56,  64,  63,   0,
    	 99,  20,   8,  20,  99,   0,
    	  3,   4, 120,   4,   3,   0,
    	 67,  69,  73,  81,  97,   0,
    	 65,  65,  65, 127,   0,   0,
    	 32,  16,   8,   4,   2,   0,
    	127,  65,  65,  65,   0,   0,
    	  4,   2,   1,   2,   4,   0,
    	 64,  64,  64,  64,  64,   0,
    	  0,   8,   7,   3,   0,   0,
    	120,  84,  84,  84,  32,   0,
    	 56,  68,  68,  40, 127,   0,
    	 40,  68,  68,  68,  56,   0,
    	127,  40,  68,  68,  56,   0,
    	 24,  84,  84,  84,  56,   0,
    	  2,   9, 126,   8,   0,   0,
    	124, 164, 164, 164,  24,   0,
    	120,   4,   4,   8, 127,   0,
    	  0,  64, 125,  68,   0,   0,
    	  0,  61,  64,  64,  32,   0,
    	  0,  68,  40,  16, 127,   0,
    	  0,  64, 127,  65,   0,   0,
    	120,   4, 120,   4, 124,   0,
    	120,   4,   4,   8, 124,   0,
    	 56,  68,  68,  68,  56,   0,
    	 24,  36,  36,  24, 252,   0,
    	252,  24,  36,  36,  24,   0,
    	  8,   4,   4,   8, 124,   0,
    	 36,  84,  84,  84,  72,   0,
    	 36,  68,  63,   4,   4,   0,
    	124,  32,  64,  64,  60,   0,
    	 28,  32,  64,  32,  28,   0,
    	 60,  64,  48,  64,  60,   0,
    	 68,  40,  16,  40,  68,   0,
    	124, 144, 144, 144,  76,   0,
    	 68,  76,  84, 100,  68,   0,
    	  0,  65,  54,   8,   0,   0,
    	  0,   0, 119,   0,   0,   0,
    	  0,   8,  54,  65,   0,   0,
    	  2,   4,   2,   1,   2,   0,
    	 60,  38,  35,  38,  60,   0,
    	 18,  97, 161, 161,  30,   0,
    	122,  32,  64,  64,  58,   0
    };
    
    //!*****************************************************************************
    //! ERROR HANDLER
    //!*****************************************************************************
    
    #ifdef DEBUG
    void
    __error__(char *pcFilename, unsigned long ulLine)
    {
    }
    #endif
    
    //!*****************************************************************************
    //! FUNCTIONS
    //!*****************************************************************************
    
    //*****************************************************************************
    //
    // INITIALIZE SSI/SPI FOR LCD
    // PD0 - SSI3CLK	clock
    // PD1 - SSI3FSS	chip select
    // PD2 - SSI3RX		MISO		// not present on LCD
    // PD3 - SSI3TX		MOSI
    // PD6 - 			command		// 0 for command, 1 for data
    // PD7 - 			reset		// hold high to activate LCD
    //
    //*****************************************************************************
    void
    initSSI3(void)
    {
    	uint32_t trashBin[1] = {0};
    	
    	// Configure GPIO Pins for SSI3 mode.
    	ROM_GPIOPinConfigure(GPIO_PD0_SSI3CLK);
    	ROM_GPIOPinConfigure(GPIO_PD1_SSI3FSS);
    	ROM_GPIOPinConfigure(GPIO_PD2_SSI3RX);	// Not present on LCD, configure anyway...
    	ROM_GPIOPinConfigure(GPIO_PD3_SSI3TX);
    	ROM_GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0);
    
    	// Configure the SSI port for SPI master mode. Moto modes:
    	// Polarity Phase       Mode
    	//   0       0   SSI_FRF_MOTO_MODE_0
    	//   0       1   SSI_FRF_MOTO_MODE_1
    	//   1       0   SSI_FRF_MOTO_MODE_2
    	//   1       1   SSI_FRF_MOTO_MODE_3 -> select this based on EA DOGS102W6 data sheet
    	SSIConfigSetExpClk(SSI3_BASE, ROM_SysCtlClockGet(), SSI_FRF_MOTO_MODE_3, SSI_MODE_MASTER, 1000000, 8);
    
    	// Enable
    	SSIEnable(SSI3_BASE);
    
    	// Clear SSI0 RX Buffer
    	while (ROM_SSIDataGetNonBlocking(SSI3_BASE, &trashBin[0])) {}
    }
    
    //*****************************************************************************
    //
    // SEND BYTE ON SSI3
    //
    //*****************************************************************************
    void
    SSI3sendByte(uint32_t theData)
    {
    	uint32_t trashBin[1] = {0};
    	
    	SSIDataPut(SSI3_BASE, theData);			// Send the data
    	while(SSIBusy(SSI3_BASE)) {}			// Wait for transmission to finish
    	
    	// Clear SSI0 RX Buffer (not sure if this is needed)
    	while (ROM_SSIDataGetNonBlocking(SSI3_BASE, &trashBin[0])) {}
    }
    
    //*****************************************************************************
    //
    // INITIALIZE LCD
    // PD0 - SSI3CLK	clock
    // PD1 - SSI3FSS	chip select
    // PD2 - SSI3RX		MISO		// not present on LCD
    // PD3 - SSI3TX		MOSI
    // PD6 - 			command		// 0 for command, 1 for data
    // PD7 - 			reset		// hold high to activate LCD
    //
    //*****************************************************************************
    void
    initLCD(void)
    {
    	// Configure D6 as the LCD command, set high
    	ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_6);
    	GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, 0);
    	GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, GPIO_PIN_6);
    	
    	// Set up PD7 as reset (disable NMI) NOTE: PD7 is NMI by default, so unlike 
    	// other pins, this procedure must be followed in order to make the pin 
    	// usable as GPIO.
    	HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY;	// Unlock the port
    	HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= GPIO_PIN_7;		// Unlock the pin
    	HWREG(GPIO_PORTD_BASE + GPIO_O_AFSEL) &= ~GPIO_PIN_7;  
    	HWREG(GPIO_PORTD_BASE + GPIO_O_DEN) |= GPIO_PIN_7;
    	HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0;				// Lock the port
    	ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE, GPIO_PIN_7);	// Set PD7 as output
    	
    	//Set display reset to high -> LCD is running now
    	GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_7, GPIO_PIN_7);
    	
    	//Initialize bottom view 3.3V (booster on) 8Bit SPI
    	LCDsend(0x40,LCD_CMD); //Startline 0
    	LCDsend(0xA1,LCD_CMD); //SEG reverse
    	LCDsend(0xC0,LCD_CMD); //Set COM direction (COM0-COM63)
    	LCDsend(0xA4,LCD_CMD); //Set all Pixel to on
    	LCDsend(0xA6,LCD_CMD); //Display inverse off
    	LCDsend(0xA2,LCD_CMD); //Set bias 1/9
    	LCDsend(0x2F,LCD_CMD); //Booster, regulator, follower on
    	LCDsend(0x27,LCD_CMD); //Set contrast
    	LCDsend(0x81,LCD_CMD); //Set contrast
    	LCDsend(0x10,LCD_CMD); //Set contrast
    	LCDsend(0xFA,LCD_CMD); //Temperature compensation
    	LCDsend(0x90,LCD_CMD); //Temperature compensation
    	LCDsend(0xAF,LCD_CMD); //Display on
    
    	//Clear display and set display buffer to 0
    	LCDclear(0,0,XMAX,YMAX);
    }
    
    //*****************************************************************************
    //
    // SEND BYTE ON LCD
    //
    //*****************************************************************************
    void
    LCDsend(uint32_t theData, uint8_t cmdByte)
    {
    	if (cmdByte == LCD_CMD){ GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, 0); }
    	else { GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, GPIO_PIN_6); }
    	SSI3sendByte(theData);
    }
    
    //*****************************************************************************
    //
    // CLEAR LCD
    //
    //*****************************************************************************
    void
    LCDclear(uint8_t xPxStart, uint8_t yPxStart, uint8_t xPxEnd, uint8_t yPxEnd)
    {
    	unsigned char LCDbuffer[XPIXEL][YPIXEL/8];
    	uint8_t iCol=0,iPg=0,pgStart=0,pgEnd=0,skipPx=0;
    	uint8_t maskPx = 0xFF;	// Mask when first and last pixel are on start page
    	
    	// Calculate start and end pages
    	pgStart=yPxStart/8;
    	pgEnd=yPxEnd/8;
    
    	/// CLEAR FIRST PAGE from FIRST COLUMN
    	LCDsend(0xB0+pgStart,LCD_CMD);		// Set page address
    	LCDsend(0x0F&xPxStart,LCD_CMD);		// Set LSB of column address
    	LCDsend(0x10+(xPxStart>>4),LCD_CMD);	// Set MSB of column address
    
    	// Find start within first page
    	skipPx=yPxStart%8;
    	// Find stop within first page (if first and last pixel are on the same page)
    	if (pgEnd == pgStart) { maskPx=yPxEnd%8-0xFF; }
    	
    	// Loop from first to last column
    	for(iCol=xPxStart; iCol<=xPxEnd; iCol++)
    	{
    		LCDbuffer[iCol][pgStart]&=maskPx>>(8-skipPx);	// Clear appropriate parts of the buffer
    		LCDsend(LCDbuffer[iCol][pgStart],LCD_DATA);		// Send buffer to display
    	}
    
    	/// CLEAR LAST PAGE to LAST COLUMN
    	LCDsend(0xB0+pgEnd,LCD_CMD);			// Set page address
    	LCDsend(0x0F&xPxStart,LCD_CMD);		// Set LSB of column address
    	LCDsend(0x10+(xPxStart>>4),LCD_CMD);	// Set MSB of column address
    	
    	// Find stop within last page
    	skipPx=yPxEnd%8;
    
    	// Loop from first to last column
    	for(iCol=xPxStart; iCol<=xPxEnd; iCol++)
    	{
    		LCDbuffer[iCol][pgEnd]&=(0xFF<<(skipPx+1));	// Clear appropriate parts of the buffer
    		LCDsend(LCDbuffer[iCol][pgEnd],LCD_DATA);			// Send buffer to display
    	}
    
    	/// CLEAR MIDDLE PAGES and ALL COLUMNS
    	// Loop from second page to last page less one
    	for(iPg=pgStart+1; iPg<pgEnd; iPg++)
    	{
    		LCDsend(0xB0+iPg,LCD_CMD);			// Set page address
    		LCDsend(0x0F&xPxStart,LCD_CMD);		// Set LSB of column address
    		LCDsend(0x10+(xPxStart>>4),LCD_CMD);	// Set MSB of column address
    
    		// Loop from first to last column (no need for buffer as we're clearing all)
    		for(iCol=xPxStart; iCol<=xPxEnd; iCol++) { LCDsend(0x00,LCD_DATA); }
    	}
    }
    
    //*****************************************************************************
    //
    // FILL LCD
    //
    //*****************************************************************************
    void
    LCDfill(uint8_t xPxStart, uint8_t yPxStart, uint8_t xPxEnd, uint8_t yPxEnd)
    {
    	unsigned char LCDbuffer[XPIXEL][YPIXEL/8];
    	uint8_t iCol=0,iPg=0,pgStart=0,pgEnd=0,skipPx=0;
    	uint8_t maskPx = 0xFF;	// Mask when first and last pixel are on start page
    	
    	// Calculate start and end pages
    	pgStart=yPxStart/8;
    	pgEnd=yPxEnd/8;
    
    	/// FILL FIRST PAGE from FIRST COLUMN
    	LCDsend(0xB0+pgStart,LCD_CMD);		// Set page address
    	LCDsend(0x0F&xPxStart,LCD_CMD);		// Set LSB of column address
    	LCDsend(0x10+(xPxStart>>4),LCD_CMD);	// Set MSB of column address
    
    	// Find start within first page
    	skipPx=yPxStart%8;
    	// Find stop within first page (if first and last pixel are on the same page)
    	if (pgEnd == pgStart) { maskPx=yPxEnd%8-0xFF; }
    	
    	// Loop from first to last column
    	for(iCol=xPxStart; iCol<=xPxEnd; iCol++)
    	{
    		LCDbuffer[iCol][pgStart]|=maskPx<<skipPx;	// Fill appropriate parts of the buffer
    		LCDsend(LCDbuffer[iCol][pgStart],LCD_DATA);		// Send buffer to display
    	}
    
    	/// FILL LAST PAGE to LAST COLUMN
    	LCDsend(0xB0+pgEnd,LCD_CMD);			// Set page address
    	LCDsend(0x0F&xPxStart,LCD_CMD);		// Set LSB of column address
    	LCDsend(0x10+(xPxStart>>4),LCD_CMD);	// Set MSB of column address
    	
    	// Find stop within last page
    	skipPx=yPxEnd%8;
    
    	// Loop from first to last column
    	for(iCol=xPxStart; iCol<=xPxEnd; iCol++)
    	{
    		LCDbuffer[iCol][pgEnd]|=(0xFF>>(8-skipPx-1));	// Fill appropriate parts of the buffer
    		LCDsend(LCDbuffer[iCol][pgEnd],LCD_DATA);				// Send buffer to display
    	}
    
    	/// FILL MIDDLE PAGES and ALL COLUMNS
    	// Loop from second page to last page less one
    	for(iPg=pgStart+1; iPg<pgEnd; iPg++)
    	{
    		LCDsend(0xB0+iPg,LCD_CMD);			// Set page address
    		LCDsend(0x0F&xPxStart,LCD_CMD);		// Set LSB of column address
    		LCDsend(0x10+(xPxStart>>4),LCD_CMD);	// Set MSB of column address
    
    		// Loop from first to last column (no need for buffer as we're filling all)
    		for(iCol=xPxStart; iCol<=xPxEnd; iCol++) { LCDsend(0xFF,LCD_DATA); }
    	}
    }
    
    //*****************************************************************************
    //
    // SEND CHARACTER TO LCD
    //
    //*****************************************************************************
    void
    LCDchar(uint8_t row, uint8_t col, uint16_t f, uint8_t style)
    {
    	// Each Character consists of 6 Columns on 1 Page
    	// Each Page presents 8 pixels vertically (top = MSB)
    	uint8_t b;
    	uint16_t h;
    	uint8_t inverted_char[6];
    	uint8_t normal_char[6];
    	int iChar;
    
    	// Row boundary check
    	if (row > 7) { row = 7; }
    
    	// Column boundary check
    	if (col > 101) { col = 101; }
    
    	// handle characters not in our table, replace with '.'
    	if (f < 32 || f > 129) { f = '.'; }
    
    	// subtract 32 because FONT6x8[0] is "space" which is ascii 32,
    	// multiply by 6 because each character is columns wide
    	h = (f - 32) * 6;
    
    	LCDsend(0xB0+row,LCD_CMD);		// Set page address
    	LCDsend(0x0F&col,LCD_CMD);		// Set LSB of column address
    	LCDsend(0x10+(col>>4),LCD_CMD);	// Set MSB of column address
    	
    	if (style == INVERSE)
    	{
    		for (b = 0; b < 6; b++)
    		{
    			// invert the character
    			inverted_char[b] = FONT6x8[h + b] ^ 0xFF;
    		}
    		// write inverted character
    		for( iChar=5; iChar>=0; iChar-- ){
    			LCDsend(inverted_char[iChar],LCD_DATA);
    		}
    	}
    	else
    	{
    		for (b = 0; b < 6; b++)
    		{
    			// store character to array
    			normal_char[b] = FONT6x8[h + b];
    		}
    		// write character
    		for( iChar=5; iChar>=0; iChar-- ){
    			LCDsend(normal_char[iChar],LCD_DATA);
    		}
    	}
    }
    
    //*****************************************************************************
    //
    // PRINT STRING TO LCD
    //
    //*****************************************************************************
    void
    LCDstring(uint8_t row, uint8_t col, char *word, uint8_t style)
    {
        // Each Character consists of 6 Columns on 1 Page
        // Each Page presents 8 pixels vertically (top = MSB)
        uint8_t a = 0;
    
        // Row boundary check
        if (row > 7) { row = 7; }
        // Column boundary check
        if (col > 101) { col = 101; }
    
        while (word[a] != 0)
        {
            // check for line feed '/n'
            if (word[a] != 0x0A)
            {
                //check for carriage return '/r' (ignore if found)
                if (word[a] != 0x0D)
                {
                    //Draw a character
                    LCDchar(row, col, word[a], style);
    
                    //Update location
                    col += 6;
    
                    //Text wrapping
                    if (col >= 102)
                    {
                        col = 0;
                        if (row < 7) { row++; }
                        else { row = 0; }
                    }
                }
            }
            // handle line feed character
            else
            {
                if (row < 7) { row++; }
                else { row = 0; }
                col = 0;
            }
            a++;
        }
    }
    
    //*****************************************************************************
    //
    // PRINT LINE TO LCD
    //
    //*****************************************************************************
    void
    LCDline(uint8_t xPxStart, uint8_t yPxStart, uint8_t xPxEnd, uint8_t yPxEnd)
    {
    	unsigned char LCDbuffer[XPIXEL][YPIXEL/8];
    	uint8_t iCol=0,iPg=0,pgStart=0,pgEnd=0,skipPx=0;
    	uint8_t maskPx = 0xFF;	// Mask when first and last pixel are on start page
    	
    	// Calculate start and end pages
    	pgStart=yPxStart/8;
    	pgEnd=yPxEnd/8;
    
    	// Set address of start page
    	LCDsend(0xB0+pgStart,0);		// Set page address
    	LCDsend(0x0F&xPxStart,0);		// Set LSB of column address
    	LCDsend(0x10+(xPxStart>>4),0);	// Set MSB of column address
    
    	// Find start within first page
    	skipPx=yPxStart%8;
    
    	/// HORIZONTAL LINE
    	if ( yPxStart == yPxEnd ){
    		// Loop from first to last column
    		for(iCol=xPxStart; iCol<=xPxEnd; iCol++)
    		{
    			LCDbuffer[iCol][pgStart]|=0x01<<skipPx;	// Fill appropriate parts of the buffer
    			LCDsend(LCDbuffer[iCol][pgStart],1);	// Send buffer to display
    		}
    	}
    	/// VERTICAL LINE
    	else {
    		// START PAGE
    		// Find stop within first page (if first and last pixel are on the same page)
    		if (pgEnd == pgStart) { maskPx=yPxEnd%8-0xFF; }
    		
    		// Fill appropriate parts
    		LCDbuffer[xPxStart][pgStart]|=maskPx<<skipPx;
    		LCDsend(LCDbuffer[xPxStart][pgStart],1);
    		
    		// If line is only one page, exit function here
    		if (pgEnd == pgStart) { return; }
    		
    		// LAST PAGE
    		LCDsend(0xB0+pgEnd,0);			// Set page address
    		LCDsend(0x0F&xPxStart,0);		// Set LSB of column address
    		LCDsend(0x10+(xPxStart>>4),0);	// Set MSB of column address
    		
    		// Find stop within last page
    		skipPx=yPxEnd%8;
    		
    		// Fill appropriate parts
    		LCDbuffer[xPxStart][pgEnd]|=(0xFF>>(8-skipPx-1));
    		LCDsend(LCDbuffer[xPxStart][pgEnd],1);
    		
    		// MIDDLE PAGES
    		for(iPg=pgStart+1; iPg<pgEnd; iPg++)
    		{
    			LCDsend(0xB0+iPg,0);			// Set page address
    			LCDsend(0x0F&xPxStart,0);		// Set LSB of column address
    			LCDsend(0x10+(xPxStart>>4),0);	// Set MSB of column address
    
    			// Fill appropriate parts (no need for buffer as we're filling all)
    			LCDsend(0xFF,1);
    		}
    	}
    }
    
    //*****************************************************************************
    //
    // PRINT RECTANGLE TO LCD
    //
    //*****************************************************************************
    void 
    LCDrect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
    {
    	// (x1,y1)-------------(x2,y1)
    	//    |                   |
    	//    |                   |
    	//    |                   |
    	// (x1,y2)-------------(x2,y2)
    	
    	LCDline(x1, y1, x2, y1);	// Top
    	LCDline(x1, y2, x2, y2);	// Bottom
    	LCDline(x1, y1, x1, y2);	// Left
    	LCDline(x2, y1, x2, y2);	// Right
    }
    
    //!*****************************************************************************
    //! THE PROGRAM
    //!*****************************************************************************
    int
    main(void)
    {
    	// Initial settings
    	ROM_FPUEnable();					// Enable floating point unit
    	ROM_FPULazyStackingEnable();		// Enable lazy stacking of FPU
    	ROM_IntMasterEnable();				// Enable processor interrupts
    	
    	// Enable device clocking
    	ROM_SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
    	
    	// Enable peripherals
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);			// Pins: LCD screen
    	ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);				// SSI3 for EA DOGS102W6 LCD display
    	
    	// LCD TEST AREA
    	initSSI3();			// Start SSI3/SPI for sending data to LCD
    	initLCD();			// Start the LCD screen
    
    	// Print some characters
    	LCDstring(0,0,"ABCDEFGHIJKLMNOPQRSTYVWXYZabcdefghijklmnopqrstuvwxyz01234567890`-=;',.~!@#$%^&*()_+{}|:<>?", NORMAL);
    
    	// MAIN LOOP
    	while(1){}
    	//return(0);
    }
    

  • Glad you corrected your "Strack Overflow" - which I earlier identified as, "likely suspect."   (pity that no credit attached to that identification - nor the even earlier "catch" of the reversal of MISO & MOSI.)    Intrinsic motivation - not always - pays the bills...

    It would be of use to those here - able to afford that high priced display - if you'd measure & report the "time required" to perform a "full CLS" (Clear Screen) via the SPI interface.   As past mentioned - my firm chooses far more cost effective displays - and installs a "baby ARM" (M0) as an "intelligent & multiple serial, Front End."   This saves the user from the burden imposed by a parallel interface - enables I2C, SPI, UART and (coming) CAN - and proves orders of magnitude FASTER due to the parallel interface between ARM M0 & the display.