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:
- Is there a difference between SSI and SPI? Or are they just different names for the same thing (such as IIC and I2C)?
- 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!