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!