Working with STM32F4 and SPI-TFT: ST7789 IPS 240×240 LCD

This guide shows how to interface the STM32F4 board with ST7789 TFT display.
The ST7789 TFT module contains a display controller with the same name: ST7789. It’s a color display that uses SPI interface protocol and requires 3, 4 or 5 control pins, it’s low cost and easy to use. This display is an IPS display, it comes in different sizes (1.3″, 1.54″ …) but all of them should have the same resolution of 240×240 pixel, this means it has 57600 pixels. 

TFT: Thin-Film Transistor.
SPI: Serial Peripheral Interface.
IPS: In-Plane Switching.

In this guide, we shall cover the following:

  • ST7789 connection with STM32F411 Nucleo-64
  • SPI setup.
  • Macros of DC and RST pin.
  • Write data and command functions.
  • LCD initializing.
  • Support functions.
  • Code.
  • Demo

1. ST7789 Connection with STM32F411 Nucleo-64:

The connection as following:

ST7789 TFTSTM32F411 Nucloe
5VVcc
GNDGND
SCLPA5 (SCK)
SDAPA7 (MOSI)
RESPA0
DCPA1

Hence the connection as following:

Notice that this TFT has no CS (Chip select) pin which is internally connected to ground.

2. SPI Setup:

Since this TFT has no CS pin, instead MODE0 of SPI, the module uses MODE3 of SPI:

For detailed operation and how to initialize the SPI, check this guide from here.

From the connection, PA5 and PA7 are used by SPI1 of STM32F411. Hence we start of by enabling clock access and set PA5, PA6 and PA7 to AF5, set PA0 and PA1 to GPIO output mode:

#define AF05 0x05

	RCC->AHB1ENR|=RCC_AHB1ENR_GPIOAEN;
	/*SPI pins*/
	GPIOA->MODER|=GPIO_MODER_MODE5_1|GPIO_MODER_MODE6_1|GPIO_MODER_MODE7_1;
	GPIOA->MODER&=~(GPIO_MODER_MODE5_0|GPIO_MODER_MODE6_0|GPIO_MODER_MODE7_0);
	GPIOA->AFR[0]|=(AF05<<GPIO_AFRL_AFSEL5_Pos)|(AF05<<GPIO_AFRL_AFSEL6_Pos)|(AF05<<GPIO_AFRL_AFSEL7_Pos);

	/*DC and RST pins*/
	GPIOA->MODER|=GPIO_MODER_MODE0_0|GPIO_MODER_MODE1_0;
	GPIOA->MODER&=~(GPIO_MODER_MODE0_1|GPIO_MODER_MODE1_1);

For SPI setup:

  • CPOL and CPHA is set to 1.
  • Divide the clock by 4 (Max of 25MHz for this module and the MCU is running at 100MHz).
  • Set the mode to master.
  • Software slave management.
  • Enable SPI module
	RCC->APB2ENR|=RCC_APB2ENR_SPI1EN;
	SPI1->CR1|=SPI_CR1_CPHA|SPI_CR1_CPOL|SPI_CR1_SSM|SPI_CR1_BR_0|SPI_CR1_SSI|SPI_CR1_MSTR|SPI_CR1_SPE;

Since we need to write multiple bytes of data, we need the following function:

void st7789_spi_transmit(uint8_t *data,uint32_t size)
{
	uint32_t i=0;
	uint8_t temp;

	while(i<size)
	{
		/*Wait until TXE is set*/
		while(!(SPI1->SR & (SPI_SR_TXE))){}

		/*Write the data to the data register*/
		SPI1->DR=data[i];
		//*spidr = data[i];
		i++;
	}
	/*Wait until TXE is set*/
	while(!(SPI1->SR & (SPI_SR_TXE))){}

	/*Wait for BUSY flag to reset*/
	while((SPI1->SR & (SPI_SR_BSY))){}

	/*Clear OVR flag*/
	temp = SPI1->DR;
	temp = SPI1->SR;
}

3. Macros of CS and RST:

We shall use the following to control the RST(PA0) and DC(PA1) pins:

#define LCD_RST1 GPIOA->BSRR=GPIO_BSRR_BS0
#define LCD_RST0 GPIOA->BSRR=GPIO_BSRR_BR0

#define	LCD_DC1	GPIOA->BSRR=GPIO_BSRR_BS1
#define	LCD_DC0 GPIOA->BSRR=GPIO_BSRR_BR1

4. Write Command and data to the LCD:

In order to send command, we need to set the DC to low and write the data over SPI as following:

/**
 * @brief Write command to ST7789 controller
 * @param cmd -> command to write
 * @return none
 */



static void ST7789_WriteCommand(uint8_t cmd)
{

	LCD_DC0;
	st7789_spi_transmit(&cmd,1);
}

And we have 2 function to write the data as following:

  • Small data which is 1 byte
  • Data which takes an argument for how bytes to be written.
/**
 * @brief Write data to ST7789 controller
 * @param buff -> pointer of data buffer
 * @param buff_size -> size of the data buffer
 * @return none
 */
static void ST7789_WriteData(uint8_t *buff, uint32_t buff_size)
{
	LCD_DC1;
	st7789_spi_transmit(buff,buff_size);

}
/**
 * @brief Write data to ST7789 controller, simplify for 8bit data.
 * data -> data to write
 * @return none
 */
static void ST7789_WriteSmallData(uint8_t data)
{

	LCD_DC1;
	st7789_spi_transmit(&data,1);

}

4. LCD Initializing:

In order to initialize the LCD, the following commands and data shall be sent:

/**
 * @brief Initialize ST7789 controller
 * @param none
 * @return none
 */
void ST7789_Init(void)
{
	st7789_spi_init();
	delay(25);
	LCD_RST0;
	delay(50);
    LCD_RST1;
    delay(50);
    ST7789_WriteCommand(ST7789_SWRESET);
    delay(100);
    ST7789_WriteCommand(ST7789_COLMOD);		//	Set color mode
    ST7789_WriteSmallData(ST7789_COLOR_MODE_16bit);
  	ST7789_WriteCommand(0xB2);				//	Porch control
	uint8_t data[] = {0x0C, 0x0C, 0x00, 0x33, 0x33};
	ST7789_WriteData(data, sizeof(data));

	/* Internal LCD Voltage generator settings */
    ST7789_WriteCommand(0XB7);				//	Gate Control
    ST7789_WriteSmallData(0x35);			//	Default value
    ST7789_WriteCommand(0xBB);				//	VCOM setting
    ST7789_WriteSmallData(0x20);			//	0.725v (default 0.75v for 0x20)
    ST7789_WriteCommand(0xC0);				//	LCMCTRL
    ST7789_WriteSmallData (0x2C);			//	Default value
    ST7789_WriteCommand (0xC2);				//	VDV and VRH command Enable
    ST7789_WriteSmallData (0x01);			//	Default value
    ST7789_WriteCommand (0xC3);				//	VRH set
    ST7789_WriteSmallData (0x0b);			//	+-4.45v (defalut +-4.1v for 0x0B)
    ST7789_WriteCommand (0xC4);				//	VDV set
    ST7789_WriteSmallData (0x20);			//	Default value
    ST7789_WriteCommand (0xC6);				//	Frame rate control in normal mode
    ST7789_WriteSmallData (0x0F);			//	Default value (60HZ)
    ST7789_WriteCommand (0xD0);				//	Power control
    ST7789_WriteSmallData (0xA4);			//	Default value
    ST7789_WriteSmallData (0xA1);			//	Default value
	/**************** Division line ****************/

	ST7789_WriteCommand(0xE0);
	{
		uint8_t data[] = {0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23};
		ST7789_WriteData(data, sizeof(data));
	}

    ST7789_WriteCommand(0xE1);
	{
		uint8_t data[] = {0xD0, 0x04, 0x0C, 0x11, 0x13, 0x2C, 0x3F, 0x44, 0x51, 0x2F, 0x1F, 0x1F, 0x20, 0x23};
		ST7789_WriteData(data, sizeof(data));
	}
    ST7789_WriteCommand (ST7789_INVON);		//	Inversion ON
	ST7789_WriteCommand (ST7789_SLPOUT);	//	Out of sleep mode
  	ST7789_WriteCommand (ST7789_NORON);		//	Normal Display on
  	ST7789_WriteCommand (ST7789_DISPON);	//	Main screen turned on

  	delay(50);
	ST7789_Fill_Color(BLACK);				//	Fill with Black.

}

5. Supporting function:

/**
 * @brief Set the rotation direction of the display
 * @param m -> rotation parameter(please refer it in st7789.h)
 * @return none
 */
void ST7789_SetRotation(uint8_t m)
{
	ST7789_WriteCommand(ST7789_MADCTL);	// MADCTL
	switch (m) {
	case 0:
		ST7789_WriteSmallData(ST7789_MADCTL_MX | ST7789_MADCTL_MY | ST7789_MADCTL_RGB);
		break;
	case 1:
		ST7789_WriteSmallData(ST7789_MADCTL_MY | ST7789_MADCTL_MV | ST7789_MADCTL_RGB);
		break;
	case 2:
		ST7789_WriteSmallData(ST7789_MADCTL_RGB);
		break;
	case 3:
		ST7789_WriteSmallData(ST7789_MADCTL_MX | ST7789_MADCTL_MV | ST7789_MADCTL_RGB);
		break;
	default:
		break;
	}
}

/**
 * @brief Set address of DisplayWindow
 * @param xi&yi -> coordinates of window
 * @return none
 */
static void ST7789_SetAddressWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
	uint16_t x_start = x0 + X_SHIFT, x_end = x1 + X_SHIFT;
	uint16_t y_start = y0 + Y_SHIFT, y_end = y1 + Y_SHIFT;

	/* Column Address set */
	ST7789_WriteCommand(ST7789_CASET);
	{
		uint8_t data[] = {x_start >> 8, x_start & 0xFF, x_end >> 8, x_end & 0xFF};
		ST7789_WriteData(data, sizeof(data));
	}

	/* Row Address set */
	ST7789_WriteCommand(ST7789_RASET);
	{
		uint8_t data[] = {y_start >> 8, y_start & 0xFF, y_end >> 8, y_end & 0xFF};
		ST7789_WriteData(data, sizeof(data));
	}
	/* Write to RAM */
	ST7789_WriteCommand(ST7789_RAMWR);
}

/**
 * @brief Fill the DisplayWindow with single color
 * @param color -> color to Fill with
 * @return none
 */
void ST7789_Fill_Color(uint16_t color)
{
	uint16_t i;
	ST7789_SetAddressWindow(0, 0, ST7789_WIDTH - 1, ST7789_HEIGHT - 1);

		uint16_t j;
		for (i = 0; i < ST7789_WIDTH; i++)
				for (j = 0; j < ST7789_HEIGHT; j++) {
					uint8_t data[] = {color >> 8, color & 0xFF};
					ST7789_WriteData(data, sizeof(data));
				}

}

/**
 * @brief Draw a Pixel
 * @param x&y -> coordinate to Draw
 * @param color -> color of the Pixel
 * @return none
 */
void ST7789_DrawPixel(uint16_t x, uint16_t y, uint16_t color)
{
	if ((x < 0) || (x >= ST7789_WIDTH) ||
		 (y < 0) || (y >= ST7789_HEIGHT))	return;

	ST7789_SetAddressWindow(x, y, x, y);
	uint8_t data[] = {color >> 8, color & 0xFF};
	ST7789_WriteData(data, sizeof(data));
}

/**
 * @brief Fill an Area with single color
 * @param xSta&ySta -> coordinate of the start point
 * @param xEnd&yEnd -> coordinate of the end point
 * @param color -> color to Fill with
 * @return none
 */
void ST7789_Fill(uint16_t xSta, uint16_t ySta, uint16_t xEnd, uint16_t yEnd, uint16_t color)
{
	if ((xEnd < 0) || (xEnd >= ST7789_WIDTH) ||
		 (yEnd < 0) || (yEnd >= ST7789_HEIGHT))	return;
	uint16_t i, j;
	ST7789_SetAddressWindow(xSta, ySta, xEnd, yEnd);
	for (i = ySta; i <= yEnd; i++)
		for (j = xSta; j <= xEnd; j++) {
			uint8_t data[] = {color >> 8, color & 0xFF};
			ST7789_WriteData(data, sizeof(data));
		}
}

/**
 * @brief Draw a big Pixel at a point
 * @param x&y -> coordinate of the point
 * @param color -> color of the Pixel
 * @return none
 */
void ST7789_DrawPixel_4px(uint16_t x, uint16_t y, uint16_t color)
{
	if ((x <= 0) || (x > ST7789_WIDTH) ||
		 (y <= 0) || (y > ST7789_HEIGHT))	return;

	ST7789_Fill(x - 1, y - 1, x + 1, y + 1, color);

}

/**
 * @brief Draw a line with single color
 * @param x1&y1 -> coordinate of the start point
 * @param x2&y2 -> coordinate of the end point
 * @param color -> color of the line to Draw
 * @return none
 */
void ST7789_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1,
        uint16_t color) {
	uint16_t swap;
    uint16_t steep = ABS(y1 - y0) > ABS(x1 - x0);
    if (steep) {
		swap = x0;
		x0 = y0;
		y0 = swap;

		swap = x1;
		x1 = y1;
		y1 = swap;
        //_swap_int16_t(x0, y0);
        //_swap_int16_t(x1, y1);
    }

    if (x0 > x1) {
		swap = x0;
		x0 = x1;
		x1 = swap;

		swap = y0;
		y0 = y1;
		y1 = swap;
        //_swap_int16_t(x0, x1);
        //_swap_int16_t(y0, y1);
    }

    int16_t dx, dy;
    dx = x1 - x0;
    dy = ABS(y1 - y0);

    int16_t err = dx / 2;
    int16_t ystep;

    if (y0 < y1) {
        ystep = 1;
    } else {
        ystep = -1;
    }

    for (; x0<=x1; x0++) {
        if (steep) {
            ST7789_DrawPixel(y0, x0, color);
        } else {
            ST7789_DrawPixel(x0, y0, color);
        }
        err -= dy;
        if (err < 0) {
            y0 += ystep;
            err += dx;
        }
    }
}

/**
 * @brief Draw a Rectangle with single color
 * @param xi&yi -> 2 coordinates of 2 top points.
 * @param color -> color of the Rectangle line
 * @return none
 */
void ST7789_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{

	ST7789_DrawLine(x1, y1, x2, y1, color);
	ST7789_DrawLine(x1, y1, x1, y2, color);
	ST7789_DrawLine(x1, y2, x2, y2, color);
	ST7789_DrawLine(x2, y1, x2, y2, color);

}

/**
 * @brief Draw a circle with single color
 * @param x0&y0 -> coordinate of circle center
 * @param r -> radius of circle
 * @param color -> color of circle line
 * @return  none
 */
void ST7789_DrawCircle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color)
{
	int16_t f = 1 - r;
	int16_t ddF_x = 1;
	int16_t ddF_y = -2 * r;
	int16_t x = 0;
	int16_t y = r;


	ST7789_DrawPixel(x0, y0 + r, color);
	ST7789_DrawPixel(x0, y0 - r, color);
	ST7789_DrawPixel(x0 + r, y0, color);
	ST7789_DrawPixel(x0 - r, y0, color);

	while (x < y) {
		if (f >= 0) {
			y--;
			ddF_y += 2;
			f += ddF_y;
		}
		x++;
		ddF_x += 2;
		f += ddF_x;

		ST7789_DrawPixel(x0 + x, y0 + y, color);
		ST7789_DrawPixel(x0 - x, y0 + y, color);
		ST7789_DrawPixel(x0 + x, y0 - y, color);
		ST7789_DrawPixel(x0 - x, y0 - y, color);

		ST7789_DrawPixel(x0 + y, y0 + x, color);
		ST7789_DrawPixel(x0 - y, y0 + x, color);
		ST7789_DrawPixel(x0 + y, y0 - x, color);
		ST7789_DrawPixel(x0 - y, y0 - x, color);
	}

}

/**
 * @brief Draw an Image on the screen
 * @param x&y -> start point of the Image
 * @param w&h -> width & height of the Image to Draw
 * @param data -> pointer of the Image array
 * @return none
 */
void ST7789_DrawImage(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint16_t *data)
{
	if ((x >= ST7789_WIDTH) || (y >= ST7789_HEIGHT))
		return;
	if ((x + w - 1) >= ST7789_WIDTH)
		return;
	if ((y + h - 1) >= ST7789_HEIGHT)
		return;


	ST7789_SetAddressWindow(x, y, x + w - 1, y + h - 1);
	ST7789_WriteData((uint8_t *)data, sizeof(uint16_t) * w * h);

}

/**
 * @brief Invert Fullscreen color
 * @param invert -> Whether to invert
 * @return none
 */
void ST7789_InvertColors(uint8_t invert)
{

	ST7789_WriteCommand(invert ? 0x21 /* INVON */ : 0x20 /* INVOFF */);

}

/**
 * @brief Write a char
 * @param  x&y -> cursor of the start point.
 * @param ch -> char to write
 * @param font -> fontstyle of the string
 * @param color -> color of the char
 * @param bgcolor -> background color of the char
 * @return  none
 */
void ST7789_WriteChar(uint16_t x, uint16_t y, char ch, FontDef font, uint16_t color, uint16_t bgcolor)
{
	uint32_t i, b, j;

	ST7789_SetAddressWindow(x, y, x + font.width - 1, y + font.height - 1);

	for (i = 0; i < font.height; i++) {
		b = font.data[(ch - 32) * font.height + i];
		for (j = 0; j < font.width; j++) {
			if ((b << j) & 0x8000) {
				uint8_t data[] = {color >> 8, color & 0xFF};
				ST7789_WriteData(data, sizeof(data));
			}
			else {
				uint8_t data[] = {bgcolor >> 8, bgcolor & 0xFF};
				ST7789_WriteData(data, sizeof(data));
			}
		}
	}

}

/**
 * @brief Write a string
 * @param  x&y -> cursor of the start point.
 * @param str -> string to write
 * @param font -> fontstyle of the string
 * @param color -> color of the string
 * @param bgcolor -> background color of the string
 * @return  none
 */
void ST7789_WriteString(uint16_t x, uint16_t y, const char *str, FontDef font, uint16_t color, uint16_t bgcolor)
{

	while (*str) {
		if (x + font.width >= ST7789_WIDTH) {
			x = 0;
			y += font.height;
			if (y + font.height >= ST7789_HEIGHT) {
				break;
			}

			if (*str == ' ') {
				// skip spaces in the beginning of the new line
				str++;
				continue;
			}
		}
		ST7789_WriteChar(x, y, *str, font, color, bgcolor);
		x += font.width;
		str++;
	}

}

/**
 * @brief Draw a filled Rectangle with single color
 * @param  x&y -> coordinates of the starting point
 * @param w&h -> width & height of the Rectangle
 * @param color -> color of the Rectangle
 * @return  none
 */
void ST7789_DrawFilledRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
{

	uint8_t i;

	/* Check input parameters */
	if (x >= ST7789_WIDTH ||
		y >= ST7789_HEIGHT) {
		/* Return error */
		return;
	}

	/* Check width and height */
	if ((x + w) >= ST7789_WIDTH) {
		w = ST7789_WIDTH - x;
	}
	if ((y + h) >= ST7789_HEIGHT) {
		h = ST7789_HEIGHT - y;
	}

	/* Draw lines */
	for (i = 0; i <= h; i++) {
		/* Draw lines */
		ST7789_DrawLine(x, y + i, x + w, y + i, color);
	}

}

/**
 * @brief Draw a Triangle with single color
 * @param  xi&yi -> 3 coordinates of 3 top points.
 * @param color ->color of the lines
 * @return  none
 */
void ST7789_DrawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color)
{

	/* Draw lines */
	ST7789_DrawLine(x1, y1, x2, y2, color);
	ST7789_DrawLine(x2, y2, x3, y3, color);
	ST7789_DrawLine(x3, y3, x1, y1, color);

}

/**
 * @brief Draw a filled Triangle with single color
 * @param  xi&yi -> 3 coordinates of 3 top points.
 * @param color ->color of the triangle
 * @return  none
 */
void ST7789_DrawFilledTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color)
{

	int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
			yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
			curpixel = 0;

	deltax = ABS(x2 - x1);
	deltay = ABS(y2 - y1);
	x = x1;
	y = y1;

	if (x2 >= x1) {
		xinc1 = 1;
		xinc2 = 1;
	}
	else {
		xinc1 = -1;
		xinc2 = -1;
	}

	if (y2 >= y1) {
		yinc1 = 1;
		yinc2 = 1;
	}
	else {
		yinc1 = -1;
		yinc2 = -1;
	}

	if (deltax >= deltay) {
		xinc1 = 0;
		yinc2 = 0;
		den = deltax;
		num = deltax / 2;
		numadd = deltay;
		numpixels = deltax;
	}
	else {
		xinc2 = 0;
		yinc1 = 0;
		den = deltay;
		num = deltay / 2;
		numadd = deltax;
		numpixels = deltay;
	}

	for (curpixel = 0; curpixel <= numpixels; curpixel++) {
		ST7789_DrawLine(x, y, x3, y3, color);

		num += numadd;
		if (num >= den) {
			num -= den;
			x += xinc1;
			y += yinc1;
		}
		x += xinc2;
		y += yinc2;
	}

}

/**
 * @brief Draw a Filled circle with single color
 * @param x0&y0 -> coordinate of circle center
 * @param r -> radius of circle
 * @param color -> color of circle
 * @return  none
 */
void ST7789_DrawFilledCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
{

	int16_t f = 1 - r;
	int16_t ddF_x = 1;
	int16_t ddF_y = -2 * r;
	int16_t x = 0;
	int16_t y = r;

	ST7789_DrawPixel(x0, y0 + r, color);
	ST7789_DrawPixel(x0, y0 - r, color);
	ST7789_DrawPixel(x0 + r, y0, color);
	ST7789_DrawPixel(x0 - r, y0, color);
	ST7789_DrawLine(x0 - r, y0, x0 + r, y0, color);

	while (x < y) {
		if (f >= 0) {
			y--;
			ddF_y += 2;
			f += ddF_y;
		}
		x++;
		ddF_x += 2;
		f += ddF_x;

		ST7789_DrawLine(x0 - x, y0 + y, x0 + x, y0 + y, color);
		ST7789_DrawLine(x0 + x, y0 - y, x0 - x, y0 - y, color);

		ST7789_DrawLine(x0 + y, y0 + x, x0 - y, y0 + x, color);
		ST7789_DrawLine(x0 + y, y0 - x, x0 - y, y0 - x, color);
	}

}


/**
 * @brief Open/Close tearing effect line
 * @param tear -> Whether to tear
 * @return none
 */
void ST7789_TearEffect(uint8_t tear)
{

	ST7789_WriteCommand(tear ? 0x35 /* TEON */ : 0x34 /* TEOFF */);

}


/**
 * @brief A Simple test function for ST7789
 * @param  none
 * @return  none
 */
void ST7789_Test(void)
{
	ST7789_Fill_Color(WHITE);
	delay(1000);
	ST7789_WriteString(10, 20, "Speed Test", Font_11x18, RED, WHITE);
	delay(1000);
	ST7789_Fill_Color(CYAN);
    delay(500);
	ST7789_Fill_Color(RED);
    delay(500);
	ST7789_Fill_Color(BLUE);
    delay(500);
	ST7789_Fill_Color(GREEN);
    delay(500);
	ST7789_Fill_Color(YELLOW);
    delay(500);
	ST7789_Fill_Color(BROWN);
    delay(500);
	ST7789_Fill_Color(DARKBLUE);
    delay(500);
	ST7789_Fill_Color(MAGENTA);
    delay(500);
	ST7789_Fill_Color(LIGHTGREEN);
    delay(500);
	ST7789_Fill_Color(LGRAY);
    delay(500);
	ST7789_Fill_Color(LBBLUE);
    delay(500);
	ST7789_Fill_Color(WHITE);
	delay(500);

	ST7789_WriteString(10, 10, "Font test.", Font_16x26, GBLUE, WHITE);
	ST7789_WriteString(10, 50, "Hello Steve!", Font_7x10, RED, WHITE);
	ST7789_WriteString(10, 75, "Hello Steve!", Font_11x18, YELLOW, WHITE);
	ST7789_WriteString(10, 100, "Hello Steve!", Font_16x26, MAGENTA, WHITE);
	delay(1000);

	ST7789_Fill_Color(RED);
	ST7789_WriteString(10, 10, "Rect./Line.", Font_11x18, YELLOW, BLACK);
	ST7789_DrawRectangle(30, 30, 100, 100, WHITE);
	delay(1000);

	ST7789_Fill_Color(RED);
	ST7789_WriteString(10, 10, "Filled Rect.", Font_11x18, YELLOW, BLACK);
	ST7789_DrawFilledRectangle(30, 30, 50, 50, WHITE);
	delay(1000);

	ST7789_Fill_Color(RED);
	ST7789_WriteString(10, 10, "Circle.", Font_11x18, YELLOW, BLACK);
	ST7789_DrawCircle(60, 60, 25, WHITE);
	delay(1000);

	ST7789_Fill_Color(RED);
	ST7789_WriteString(10, 10, "Filled Cir.", Font_11x18, YELLOW, BLACK);
	ST7789_DrawFilledCircle(60, 60, 25, WHITE);
	delay(1000);

	ST7789_Fill_Color(RED);
	ST7789_WriteString(10, 10, "Triangle", Font_11x18, YELLOW, BLACK);
	ST7789_DrawTriangle(30, 30, 30, 70, 60, 40, WHITE);
	delay(1000);

	ST7789_Fill_Color(RED);
	ST7789_WriteString(10, 10, "Filled Tri", Font_11x18, YELLOW, BLACK);
	ST7789_DrawFilledTriangle(30, 30, 30, 70, 60, 40, WHITE);
	delay(1000);

	//	If FLASH cannot storage anymore datas, please delete codes below.
	ST7789_Fill_Color(WHITE);
	ST7789_DrawImage(0, 0, 128, 128, (uint16_t *)saber);
	delay(3000);
}

6. Code:

You may download the code from here

7. Demo:

Happy coding 🙂

23 Comments

  • Mehran Posted January 25, 2023 9:18 am

    Hi,
    kindly please inform me about which font editor you used for making font for this project.
    thank you in advance for your help

    • Husamuldeen Posted February 1, 2023 4:45 am

      I just used one found it on google.
      There are tons of fonts to chose from.

  • helloworld1 Posted May 25, 2023 9:22 am

    Hi. I use 170×320 display but when I want set rotation to horizontal its not work. I tried every 4 rotation modes but work only 0 and 2 but they are the same on my display. Please Help

    • notproblem Posted May 25, 2023 9:26 am

      Hello There!
      You must use ST7789_SetRotation(x);

    • Husamuldeen Posted May 25, 2023 11:23 am

      Not all tft support rotations in all orientation.

  • eloelo320 Posted May 25, 2023 11:19 am

    hi. I can’t display my image. someone help?

    • Husamuldeen Posted May 25, 2023 12:41 pm

      Hi,
      you need to convert the image to array in order to display the image.

      • Klaus Posted December 5, 2023 7:42 pm

        Hello, I”m trying to display an image, the color is 0xDCEF (some kind of orange), but when I put in the array, it displays as light green (fill screen by this color is ok). Black is black, White is white. Blue is blue. what the problem it may be. Thanks!

        • Husamuldeen Posted December 13, 2023 3:48 am

          Hi,
          Try to fill the screen with Red, then Green then Blue and see if there is something wrong.

  • stcoool Posted May 25, 2023 12:34 pm

    Hello everyone. I tried display simple logo monochrome. I use DrawImage function but always is somethink wrong. How to do this if i have bitmap logo?

    • Husamuldeen Posted May 25, 2023 12:40 pm

      You need to convert the image to array.
      There are tools on the internet to convert image to array.

  • Harsh Bhatt Posted June 21, 2023 9:50 am

    Hi we are using nrf52832 controller, so this code is use for in our case?

    • Husamuldeen Posted June 24, 2023 2:20 pm

      Hi,
      the TFT code will work with any MCU as long as you provide the correct driver for SPI and pin control.

      • Michael Posted August 20, 2024 6:06 am

        Hi. I Have some problem witch stm32C011. My configuration of SPI:
        void SPI_Init(void){
        // Włączenie zegara dla SPI1
        RCC->APBENR2 |= RCC_APBENR2_SPI1EN;

        // Konfiguracja SPI1
        SPI1->CR1 = 0;
        SPI1->CR2 = 0;
        SPI1->CR1 |= SPI_CR1_BR_1;
        SPI1->CR1 |= SPI_CR1_SSI;
        SPI1->CR1 |= SPI_CR1_SSM;

        SPI1->CR1 |= (SPI_CR1_CPOL|SPI_CR1_CPHA); //CPOL = 1, CPHA = 1
        SPI1->CR1 &=~ (SPI_CR1_BIDIMODE|
        SPI_CR1_RXONLY);
        SPI1->CR1 &=~ SPI_CR1_LSBFIRST;
        SPI1->CR1 |= SPI_CR1_MSTR; //Master mode

        SPI1->CR2 &=~ (SPI_CR2_DS); //8-DATA Size

        SPI1->CR2 |= SPI_CR2_TXEIE;
        SPI1->CR1 |= SPI_CR1_SPE; //SPI enable

        NVIC_EnableIRQ(SPI1_IRQn);
        NVIC_SetPriority(SPI1_IRQn, 0);

        }

        It’s taking me a few days now and I still don’t see the problem.

        • Husamuldeen Posted August 20, 2024 6:44 am

          Hi,
          in C011, use CubeMX to generate the code for the drivers.

          • Michael Posted August 20, 2024 8:15 am

            Well, okay, I use CubeMX for file generation but in general it writes on registers. The configuration seems correct for the ST7789 but it still won’t work

          • Husamuldeen Posted August 22, 2024 2:47 pm

            It should work without any issue.

  • STFun Posted August 22, 2024 9:49 am

    Hi. I need to set rotation in initialization?

    • Husamuldeen Posted August 22, 2024 2:46 pm

      Yes.

      • STFun Posted August 23, 2024 7:17 am

        Ok, I have problem: When i choos rotation 0 or 180 degree its fine. But rotation 90 and 270 dont work. its still like 180 degree orientation but in half display

        • Husamuldeen Posted September 15, 2024 4:11 am

          With this specific LCD, since it is square, the rotation doesn’t matter.

Add Comment

Your email address will not be published. Required fields are marked *