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.

TM4C123GH6PM + ST7789H2 (LCD+TOUCHSCREEN)

Other Parts Discussed in Thread: TM4C123GH6PM

Hello,

I am trying to interface a TM4C123GH6PM with a LCD (that also have a touchscreen), its a chinese round tft. Its driver is ST7789H2(https://cdn-reichelt.de/documents/datenblatt/A300/ST7789.pdf

Before today i wasn t able to see anything on the screen, what i did today it was modifying the next lines:

ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); here i change the SYSCTL_SYSDIV_2_5 to SYSCTL_SYSDIV_4.

Eliminate the while(SSIBusy(SSI3_BASE)){}; command from sending SPI commands/parameter functions.

And change the transmission frequency from 12Mhz to 1Mhz.

Thank you very much!

Sending a parameter:

Sending a command:

HH

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "timer_delay.h" // delay_ms(),delay_us()
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/rom.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/ssi.h"
#include "driverlib/interrupt.h"

#define SSI_CLK					GPIO_PIN_0
#define SSI_TX					GPIO_PIN_3
#define SSI_FSS					GPIO_PIN_1

#define LCD_RESET_HIGH()		ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, GPIO_PIN_6)// RESET  HIGH
#define LCD_RESET_LOW()			ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, 0)// RESET  LOW
#define LCD_RESET()         	LCD_RESET_HIGH();  delay_ms(50); LCD_RESET_LOW();  delay_ms(50); LCD_RESET_HIGH();

#define LCD_A0_HIGH()			ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, GPIO_PIN_2)// A0  HIGH
#define LCD_A0_LOW()			ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0)// A0  LOW

#define LCD_CS_HIGH()			ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1)// CS  HIGH
#define LCD_CS_LOW()			ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, 0)// CS  LOW

#define disp_y_size 208
#define disp_x_size 240
#define	COLOR_BLUE (uint16_t)(0xF800)
#define LEFT 0
#define RIGHT 9999
#define CENTER 9998

uint8_t	fch, fcl, bch, bcl;

typedef struct
{
	uint8_t* font;
	uint8_t x_size;
	uint8_t y_size;
	uint8_t offset;
	uint8_t numchars;
} _current_font;

_current_font	cfont;

int main(void) {
	
				SPI_Init();
				LCD_RESET();
delay_ms(500);
				LCD_CS_HIGH();
				LCD_A0_LOW();

				delay_ms(25);

				LCD_CS_HIGH();
				LCD_A0_LOW();
 ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE,  GPIO_PIN_1);
 ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
 ROM_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE,  GPIO_PIN_6);
 ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_6, GPIO_PIN_6);
 LCD_CS_HIGH();
 delay_ms(200);
 LCD_Init();
 fillScr(0xF800);
 ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
ROM_GPIOPinTypeGPIOOutput(GPIO_PORTC_BASE,  GPIO_PIN_7);  //ledul
setColor(COLOR_BLUE);
delay_ms(1000);
fillRoundRect(10,10,200,200);
 while(1){
 //WriteCommand(0x11); //sleep out
	// delay_ms(100);
	// ROM_GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_7, GPIO_PIN_7);
	// delay_ms(100);
//ROM_GPIOPinWrite(GPIO_PORTC_BASE, GPIO_PIN_7, 0);
//drawPixel_Color(50,50,COLOR_BLUE);
//delay_ms(2000);
//WriteCommand(0x54);
//WriteParameter(0x20);
	// WriteCommand(0x2C);
//setColor(COLOR_BLUE);
//delay_ms(1000);
//fillRoundRect(10,10,200,200);
	 }
 }


void WriteParameter(unsigned char data)
{
	LCD_CS_LOW();	//select
	LCD_A0_HIGH(); // A0 high for data

	//while(SSIBusy(SSI3_BASE)){}; //STERGE!?!?!?
		 SSIDataPut(SSI3_BASE, data);
		// while(SSIBusy(SSI3_BASE)){};

		// delay_ms(1);
	LCD_CS_HIGH();	//unselect
}

void WriteCommand(unsigned char cmd)
{

	LCD_CS_LOW(); //select
	LCD_A0_LOW();// A0 low for commands
	//while(SSIBusy(SSI3_BASE)){};//STERGE!>!>!>
	SSIDataPut(SSI3_BASE, cmd);
//delay_ms(1);
	// while(SSIBusy(SSI3_BASE)){};
	LCD_CS_HIGH();	//unselect
	// d
}

void SPI_Init(){
	ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN); //  80 Mhz
	//2.5 ERA INAINTE NU 4!!!
	bsp_timer_init();
			ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI3);
			ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
			ROM_GPIOPinTypeGPIOOutput(GPIO_PORTD_BASE,  GPIO_PIN_2 | GPIO_PIN_6); //  A0, RESETals Output
			ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_2, 0);// A0  LOW
			ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_6, GPIO_PIN_6);// RESET  HIGH
			ROM_GPIOPinConfigure(GPIO_PD0_SSI3CLK);//PB4 CLK
			ROM_GPIOPinConfigure(GPIO_PD3_SSI3TX); //PB7 MOSI
			ROM_GPIOPinConfigure(GPIO_PD1_SSI3FSS);//PB5 CS
			ROM_GPIOPinTypeSSI(GPIO_PORTD_BASE, SSI_CLK | SSI_TX | SSI_FSS);
					// Configure SSI2 // bis 12Mhz SPI-Takt ok, > 12Mhz bis... =25Mhz Spi-Takt
			ROM_SSIConfigSetExpClk(SSI3_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8);// 12,5Mhz
				delay_ms(100);
					ROM_SSIDisable(SSI3_BASE);// Enable the SSI module.
				delay_ms(100);
					ROM_SSIEnable(SSI3_BASE);
					ROM_GPIOPinWrite(GPIO_PORTD_BASE, GPIO_PIN_1, GPIO_PIN_1);// CS HIGH
}

void LCD_Init(){
	WriteCommand(0x11); //sleep out
	delay_ms(120);                //Delay 120ms0
delay_ms(10);
	WriteCommand(0x38); // AICI E ADAUGAT DE MINE // IDLE MODE OFF
	//delay_ms(10);
		WriteCommand(0x36); // Memory Data Access Controls
		//delay_ms(10);
		WriteParameter(0x00);
		//delay_ms(10);
		WriteCommand(0x3A); // Interface Pixel Format
		//WriteParameter(0x06);
		//delay_ms(10);
		WriteParameter(0x06); //setare noua
		//delay_ms(10);
		WriteCommand(0xB2); //: Porch Setting
		//delay_ms(10);
		WriteParameter(0x0C);
		//delay_ms(10);
		WriteParameter(0x0C);
		//delay_ms(10);
		WriteParameter(0x00);
		//delay_ms(10);
		WriteParameter(0x33);
		//delay_ms(10);
		WriteParameter(0x33);

		//delay_ms(10);
		WriteCommand(0xB7); //Gate Control
		//delay_ms(10);
		WriteParameter(0x35);

		//delay_ms(10);
		WriteCommand(0xBB); //VCOM Setting
		//delay_ms(10);
		WriteParameter(0x1A);
		//delay_ms(10);
		WriteCommand(0xC0); // LCM Control
		//delay_ms(10);
		WriteParameter(0x2C);

		//delay_ms(10);
		WriteCommand(0xC2); // VDV and VRH Command Enable
		//delay_ms(10);
		WriteParameter(0x01);

		//delay_ms(10);
		WriteCommand(0xC3); // VRH Set
		//delay_ms(10);
		WriteParameter(0x0B);
		//delay_ms(10);
		WriteCommand(0xC4); // VDV Set
		//delay_ms(10);
		WriteParameter(0x20);

		//delay_ms(10);
		WriteCommand(0xC6); //Frame Rate Control in Normal Mode
		//delay_ms(10);
		WriteParameter(0x0F);

		//delay_ms(10);
		WriteCommand(0xD0); // Power Control 1
		//delay_ms(10);
		WriteParameter(0xA4);
		//delay_ms(10);
		WriteParameter(0xA1);

		//delay_ms(10);
		WriteCommand(0x21); //Display Inversion On

		//delay_ms(10);
		WriteCommand(0xE0); //Positive Voltage Gamma Control
		//delay_ms(10);
		WriteParameter(0x00);
		//delay_ms(10);
		WriteParameter(0x19);
		//delay_ms(10);
		WriteParameter(0x1E);
		//delay_ms(10);
		WriteParameter(0x0A);
		//delay_ms(10);
		WriteParameter(0x09);
	//	delay_ms(10);
		WriteParameter(0x15);
		//delay_ms(10);
		WriteParameter(0x3D);
		///delay_ms(10);
		WriteParameter(0x44);
		//delay_ms(10);
		WriteParameter(0x51);
		//delay_ms(10);
		WriteParameter(0x12);
		//delay_ms(10);
		WriteParameter(0x03);
		//delay_ms(10);
		WriteParameter(0x00);
		//delay_ms(10);
		WriteParameter(0x3F);
		//delay_ms(10);
		WriteParameter(0x3F);
		//delay_ms(10);
		WriteCommand(0x29);
		//NEW ENTRY
	/*	WriteCommand(0x2A);// Column set
		WriteParameter(0x00);
		WriteParameter(0x00);
		WriteParameter(0x00);
		WriteParameter(0xEF); //NOWAY
		WriteCommand(0x2B);//Raw set
		WriteParameter(0x00);
		WriteParameter(0x00);
		WriteParameter(0x01);
		WriteParameter(0x3F); //NOWAY
		WriteCommand(0x13); // DISPLAY ON_ADDED 8mai
				WriteCommand(0x29);

//WriteCommand(0x2C); // Memory write*/
}

void fillScr(uint16_t color)
	{
		long n, i, j;
		i = (color >> 8);
		j = (color & 0xFF);
		setXY(0,0,disp_y_size,disp_x_size);
		WriteCommand(0x2C);

		for (n = 0; n < 49920; n++) {
			WriteParameter(i);
			WriteParameter(j);
		}



	}

void setXY(uint16_t x1,uint16_t y1, uint16_t x2, uint16_t y2)
	{


		WriteCommand(0x2A); //column
		WriteParameter(x1>>8);
		WriteParameter(x1);
		WriteParameter(x2>>8);
		WriteParameter(x2);
		WriteCommand(0x2B); //page
		WriteParameter(y1>>8);
		WriteParameter(y1);
		WriteParameter(y2>>8);
		WriteParameter(y2);
		WriteCommand(0x2C); //write

	}

void setBackColor(uint16_t color)
	{
		bch=(color>>8);
		bcl=(color & 0xFF);
	}

void WriteData_2_8(uint8_t VH,uint8_t VL)
{

	LCD_CS_LOW();   //select
	LCD_A0_HIGH();  // A0 high for data

	//while((SSI2_SR_R&SSI_SR_TNF)==0){};   // wait until transmit FIFO not full
	//SSI2_DR_R = VH;      // data out
	while(SSIBusy(SSI3_BASE)){};
		 SSIDataPut(SSI3_BASE, VH);



//	while((SSI2_SR_R&SSI_SR_TNF)==0){};   // wait until transmit FIFO not full
//	SSI2_DR_R = VL;      // data out
	//while(SSIBusy(SSI3_BASE)){};
		 SSIDataPut(SSI3_BASE, VL);

		 //delay_ms(1);

	LCD_CS_HIGH();	//unselect


}

void drawHLine(int x, int y, int l)
	{

		uint16_t i;

		if (l<0)
		{
			l = -l;
			x -= l;
		}
		setXY(x, y, x+l, y);

			for (i=0; i<l+1; i++)
			{
				WriteData_2_8(fch, fcl);
			}


	clrXY();
	}


void drawPixel(int x, int y)
	{

		setXY(x, y, x, y);
		setPixel((fch<<8)|fcl);
	clrXY();

	}

void setPixel(uint16_t color)
	{


		WriteData_16(color);


	}

void WriteData_16(uint16_t data) // 16 Bit
{

	LCD_CS_LOW();	//select
	LCD_A0_HIGH(); 	// A0 high for data

//	while((SSI2_SR_R&SSI_SR_TNF)==0){};   // wait until transmit FIFO not full
//	SSI2_DR_R = data>>8;       // data out

	 while(SSIBusy(SSI3_BASE)){};
			 SSIDataPut(SSI3_BASE, data>>8);


//	while((SSI2_SR_R&SSI_SR_TNF)==0){};   // wait until transmit FIFO not full
//	SSI2_DR_R = data & 0xFF;  // data out

	 while(SSIBusy(SSI3_BASE)){};
			 SSIDataPut(SSI3_BASE, data&0xFF);


	LCD_CS_HIGH();	//unselect

}

void drawPixel_Color(uint16_t x, uint16_t y, uint16_t color)
	{
		setXY(x, y, x, y);

		WriteCommand(0x22);           // Write Data to GRAM (R22h)
		WriteData_16(color);

	}

void fillRoundRect(int x1, int y1, int x2, int y2)
	{
		uint16_t i;

		if (x1>x2)
		{
			swap(x1, x2);
		}
		if (y1>y2)
		{
			swap(y1, y2);
		}

		if ((x2-x1)>4 && (y2-y1)>4)
		{
			for (i=0; i<((y2-y1)/2)+1; i++)
			{
				switch(i)
				{
					case 0:
					drawHLine(x1+2, y1+i, x2-x1-4);
					drawHLine(x1+2, y2-i, x2-x1-4);
					break;
					case 1:
					drawHLine(x1+1, y1+i, x2-x1-2);
					drawHLine(x1+1, y2-i, x2-x1-2);
					break;
					default:
					drawHLine(x1, y1+i, x2-x1);
					drawHLine(x1, y2-i, x2-x1);
				}
			}
		}
	}

void swap(int x1, int x2){
	int t = x1; x1 = x2; x2 = t;
}

void setColor(uint16_t color)
	{
		fch=(color>>8);
		fcl=(color & 0xFF);
	}

void clrXY(void)
	{
		setXY(0,0,disp_x_size,disp_y_size);
	}

  • Hello Iliescu,

    Not sure what the question is?

    Regards
    Amit
  • Hi Amit,

    Raise the tally to two, "unsure as to poster's intent."   (no question has been raised)

    The unique, circular display appears either: unsuccessfully initialized and/or unsuccessful in the processing or receiving of poster's display functions.

    Several functions reveal w/in poster's code.   We're not told which - if any - were "in process" when the camera's trigger was pressed.   Early functions sought to display Blue Pixels - the disordered screen shows that intent significantly failed.

    Initialization and timing between commands (especially) & screen data writes are critical.   Of course we could invest time/energy in reading poster's spec - but would it not be so much more convenient if poster listed those key/critical requirements?

  • Hello Amit,

    My question is how can i correctly initialize the display. I know its a little bit too general, but honestly i don't know what the problem is.

    I want to be able to set some pixels and from there i can handle.

    That happened to the screen after the function fillRoundRect(10,10,200,200); run. But if i modify those coordinates the display doesn t show anything.
  • Iliescu Mihai said:
    how can i correctly initialize the display.

    Wouldn't that be detailed w/in the Display Controller's specification - and sometimes - by the display vendor's (helpful) documentation?

    Usually it is important that you:

    • enter the correct initialization instruction & data
    • strobe or otherwise "latch in" the above - insuring that "Set-up, hold, & all other display timings are met
    • follow the correct (or logical) sequencing of initialization instructions
    • provide the specified time delays between each initialization instruction & data
    • insure that your signal edges are "square & clean" & that signal levels are adequate - when measured ("not" @ the MCU) but @ the display.   "Assuming" rather than (real) test/verify invites endless trouble.   Waveforms you supplied are fine - but their "acquiring" location is unspecified!  (@ Display NOT MCU!)

    When ALL of the above conditions have been met you should monitor your SPI output to insure that what you "hope to send" is (actually) what you (really) send!   Initialization is touchy - great attention to detail is required.   I don't believe your scope caps show any byte sequences - you must insure that multi-byte sequences are correctly received @ the display.    

    *** You may have to manually drive SPI-CS to mate the MCU to the Display Controller ***

    As always - limiting your efforts to (just) one device proves high risk.  (unacceptable, experience teaches)   Does this "display disorder" continue on your (other) displays?

    And agreed that if you can display a single color @ "Left, top" and then, "Right, bottom" you are well on your way.   A "CLS" (clear screen) always proves helpful.

  • Thank you for your help.

    Yes, it is described by the controller datasheet, but it seems that i cant figured it out what the problem is...
    I did everything you write in there, but still doesn t work... And this is my problem, i dont know why. And yes, i test on 2 displays, because as you said before its not safe to test on just a single display that can be broken. Anyway, its not the case. I acquiring the waveform on the display to mcu path. (i got some test points)

    And my scope image show byte sequences... And the correct one. ( i checked that already).

    I already manually drive CS...
  • I think i found a error in my way of sending commands. The datasheet its a little bit confusing... I was deciding if a 8 bit sequence is a command or a data by driving up or down the A0 bit (DCX in the datasheet). But it seems that this is only available in the 4 line SPI, not 3 line (this is how my lcd is configured by the manufacturer). Now i have to sent 9 bit, where the first bit(MSB) is the DCX bit, selecting if the sequence is a line or command.

    I just simply need to modify ROM_SSIConfigSetExpClk(SSI3_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 1000000, 8); ?
    Instead of 8 bit, selecting a 9bit? But how would i send, lets say 0x11 in 9 bit format with DCX being 0 and with DCX being 1?

    Thank you!
  • I'm no expert w/this vendor's MCUs as my firm has moved to 180MHz, DACs, MIPPI-DSI Display Control w/Graphic Accelerator & support for the (entire) Cortex M spectrum. (M0, M0+, M3, M4 & M7).

    Using Forum's Search should reveal how to produce 16 bit SPI transfers - but 9 bit ones - beyond my pay grade. (@ this vendor)

    If you CAN generate proper 8 bit SPI would it not make sense to simply dedicate a GPIO to your "A0" bit - and employ the 4 line SPI mode as you mention? The selection/toggle of "A0" may have to occur w/in the SPI_CS signal - check that you're complying w/that...
  • I think you didn t understand what i think it is my problem.

    My tft driver is already set (internally) to be a 3-line SPI with DC/X bit (A0) sent through a 9-bit interface, by adding another bit(DCX) to the Transmission Byte. (in front of, actually)

    What are you telling me about toggleing the A0 GPIO, its probably right and i didn t do this, but anyway it can t help me now.

    Thank you for all your replies!
  • Hello Ilescu,

    The SPI Peripheral can be configured to send 9-bit instead of 8-bit. Look ta the last parameter in the SSI Configuration function.

    Regards
    Amit
  • Hello Amit, I know, but how the sent command will look like?

    I mean, if i want to send 0x11, and the DC/X is lets say 1, how the command will look like? But if DC/X is 0?

    Thank you!
  • Hello Iliescu

    When sending 0x11 with DC/X set 1 you would need to write 0x111 to the SSI Data register

    When sending 0x11 with DC/X set 0 you would need to write 0x011 to the SSI Data register

    Regards
    Amit
  • Hello,

    Thank you!

    Another question if i may:

    void WriteParameter(unsigned char data)
    {
    LCD_CS_LOW(); //select
    while(SSIBusy(SSI3_BASE)){};
    SSIDataPut(SSI3_BASE, data);
    LCD_CS_HIGH(); //unselect
    }

    How can i concatenate 1 bit to the data parameter? So if i want to sent, for exemple 0x11, this function to automatically add 1 in front of the 8 bits?

    THank you very much!
  • Hello Ilescu.

    That can be done by bitwise OR of the data and 0x100 if write parameter function is for DC/X=1

    Regards
    Amit
  • Thanks from two of us Amit - always helping/assisting...

    May I suggest that you employ two "bitwise-functions" - one for commands and the other for (normal) data writes.   That bitwise (set/clear) function would be the only difference between your Command & Data code blocks.

  • I did it!!! It works fine now. (i dont know why the forum doesn t let my to upload a photo...)

    Thank you very much guys!
  • Thank Amit - and yourself for having the desire & tenacity to first experiment - gain understanding - and only then post.

    The "screen icon" (9 from left-most) enables you to post a photo.

    Would you be so good as to post the screen vendor's name/link & your display's model number?   (you're the 2nd seeking "round TFT" w/in past month...)

  • Hello cb1,

    Yes, indeed. Having this screen vendor's name/link/model number would be good information. This particular screen looks very interesting.

    Regards
    Amit
  • It does look like an interesting screen

    Robert
  • Robert Adsett72 said:
    It does look like an interesting screen 

    Indeed - and in its "disordered state" it resembles NYC "over the air" TV w/a young cb1 (cradling) "rabbit-ears" in famed, "Fox Viewing Position."   (credit Bundy clan)

    Hundreds of tall buildings blocked/degraded signals for all but the highest antennas in NYC - pre cable...  (9 bit SPI [even 8 bit SPI] had (yet) to arrive - this scene!)

  • Hello guys,

    kingtechgroup.en.alibaba.com/

    This is the firm who produced them, i brought them directly from the manufacturer. They got tft's with and without touchscreen (this one, particularly got touchscreen too).

    Now i see that they got a new one with CTP (capacitive tocuhpanel) - kingtechgroup.en.alibaba.com/.../1_5_inch_tft_round_lcd_display.html .
  • Greetings Iliescu,

    We are in your debt - thank you - very much appreciated.

    Too often here posters are aided - then flee - never to return. Good luck w/your continuing project - as one in the display biz such round format displays are a rarity...
  • That's what i coded today, i have some functions, i will adapt&rewrite anothers as well. This is my graduation thesis... It also has touchscreen, bluetooth, accelerometer and power management - charging IC, etc(for Bachelor's Degree). 

    And you helped me, i owe you anyway. (about being in debt..)

    By the way: Noapte buna! means Good Night in romanian.

  • Iliescu Mihai said:
    Noapte buna! means Good Night in romanian.

    Good job - although that bright orange background may "wear" upon user eyes over time.

    Never having worked w/circular screen it appears that you're going to have to track your "pixel row" and trend toward the display's inner columns as you move toward (either) vertical edge (i.e. top/bottom) of this screen.

    BTW - I have a Romanian business partner. (his Dad was a fighter, then commercial pilot)   I've learned some phrases which (may) not be too welcome here.

  • Your initialization states 18-bits per pixel (pixel mode) but you look to use a 16-bits defined color to fill your rectangle.
    Isn't it the source of your multi-color patterned output ?