GLCD 128×64 ST7920 interfacing with STM32

Today in this tutorial, we will interface ST7920 GLCD (128×64) display with STM32 using the Serial mode. This way we only have to use 4 pins from the microcontroller to control the entire display.

We will start with displaying simple texts, than we will look into some bitmaps and finally we will draw some shapes on the LCD. I am using STM32F103C8 microcontroller.

Setup

I will start this tutorial by setting up the CubeMx. In Cube Mx, for the connection purpose, we only need to select 4 pin as output as shown below

PINOUT

Also some of the delays will be required in the microseconds, and so, I will use the TIMER 1 to create delays in microseconds. The setup is shown below. I already did a tutorial on this. You can check it HERE

This is all the setup, that is needed for the ST7920. Let’s see some functions that we are going to use to interface this display.






Some Insight into the CODE

void SendByteSPI(uint8_t byte)

Sends a byte to the MOSI / SID Pin. This is Just like How the SPI transfers the data.


Sending Command

void ST7920_SendCmd (uint8_t cmd)
{

	HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);  // PUll the CS high

	SendByteSPI(0xf8+(0<<1));  // send the SYNC + RS(0)
	SendByteSPI(cmd&0xf0);  // send the higher nibble first
	SendByteSPI((cmd<<4)&0xf0);  // send the lower nibble
	delay_us(50);

	HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);  // PUll the CS LOW

}

According to the datasheet of ST7920, In order to send a command to the display, We need to perform the following operations:-
1. Pull the CS Pin HIGH
2. Send the Synchronizing byte (0xF8) along with R/W and RS
3. Send the Higher command Byte
4. Send the Lower command Byte
5. Pull the CS Pin LOW to end the transfer


Sending Data

void ST7920_SendData (uint8_t data)
{

	HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);  // PUll the CS high

	SendByteSPI(0xf8+(1<<1));  // send the SYNC + RS(1)
	SendByteSPI(data&0xf0);  // send the higher nibble first
	SendByteSPI((data<<4)&0xf0);  // send the lower nibble
	delay_us(50);
	HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);  // PUll the CS LOW
}

Data is also sent in the same manner as the command, except the RS will be a ‘1’. Following are the operations:-
1. Pull the CS Pin HIGH
2. Send the Synchronizing byte (0xF8) along with R/W and RS
3. Send the Higher data Byte
4. Send the Lower data Byte
5. Pull the CS Pin LOW to end the transfer


Initializing Display

void ST7920_Init (void)
{
	HAL_GPIO_WritePin(RST_PORT, RST_PIN, GPIO_PIN_RESET);  // RESET=0
	HAL_Delay(10);   // wait for 10ms
	HAL_GPIO_WritePin(RST_PORT, RST_PIN, GPIO_PIN_SET);  // RESET=1

	HAL_Delay(50);   //wait for >40 ms


	ST7920_SendCmd(0x30);  // 8bit mode
	delay_us(110);  //  >100us delay

	ST7920_SendCmd(0x30);  // 8bit mode
	delay_us(40);  // >37us delay

	ST7920_SendCmd(0x08);  // D=0, C=0, B=0
	delay_us(110);  // >100us delay

	ST7920_SendCmd(0x01);  // clear screen
	HAL_Delay(12);  // >10 ms delay


	ST7920_SendCmd(0x06);  // cursor increment right no shift
	HAL_Delay(1);  // 1ms delay

	ST7920_SendCmd(0x0C);  // D=1, C=0, B=0
    HAL_Delay(1);  // 1ms delay

	ST7920_SendCmd(0x02);  // return to home
	HAL_Delay(1);  // 1ms delay

}

To initialize the display, we have to follow some sequence of command. And they are mentioned below:
1. Reset the display and wait for more than 40 ms
2. Send the Function Set command and wait for more than 100 us
3. Send the Function Set command and wait for more than 37 us
4. Send the Display ON/OFF Control command and wait for more than 100 us
5. Send the Display Clear command and wait for more than 10 ms
6. Send the Entry Mode set command and this will end the initialization of the display.


Graphic Mode

void ST7920_GraphicMode ()   
{
  ST7920_SendCmd(0x30);  // 8 bit mode
  HAL_Delay (1);
  ST7920_SendCmd(0x34);  // switch to Extended instructions
  HAL_Delay (1);
  ST7920_SendCmd(0x36);  // enable graphics
  HAL_Delay (1);
}

To enable the Graphic mode, we have to
-> Switch to Extended Instruction Set
-> Enable the Graphics
Note that we have to perform both of these operations in separate commands as according to it is mentioned in the datasheet.


Drawing Bitmaps

void ST7920_DrawBitmap(const unsigned char* graphic)
{
	uint8_t x, y;
	for(y = 0; y < 64; y++)
	{
		if(y < 32)
		{
			for(x = 0; x < 8; x++)	/ Draws top half of the screen.
			{			
                 		// In extended instruction mode, vertical and horizontal coordinates must be specified before sending data in.
				ST7920_SendCmd(0x80 | y);	// Vertical coordinate of the screen is specified first. (0-31)
				ST7920_SendCmd(0x80 | x);	// Then horizontal coordinate of the screen is specified. (0-8)
				ST7920_SendData(graphic[2*x + 16*y]);	// Data to the upper byte is sent to the coordinate.
				ST7920_SendData(graphic[2*x+1 + 16*y]);	// Data to the lower byte is sent to the coordinate.
			}
		}
		else
		{
			for(x = 0; x < 8; x++)	// Draws bottom half of the screen.
			{
                           // Actions performed as same as the upper half screen.
			   ST7920_SendCmd(0x80 | (y-32));// Vertical coordinate must be scaled back to 0-31 as it is dealing with another half of the screen.
			  ST7920_SendCmd(0x88 | x);
			  ST7920_SendData(graphic[2*x + 16*y]);
			  ST7920_SendData(graphic[2*x+1 + 16*y]);
			}
		}

	}
}

In order to draw a bitmap, we need to draw on the two half of the screen. First upper half and than the lower half.
To draw, first set the coordinate of the Y axis and than the coordinate of the X axis.
After the coordinates are set, send the upper byte of the data and than the lower byte.




RESULT

Connection ST7920 STM32F103

Check out the Video Below










Info

You can help with the development by DONATING
To download the code, click DOWNLOAD button and view the Ad. The project will download after the Ad is finished.

42 Comments. Leave new

  • sushma gawde
    March 20, 2024 3:38 PM

    how to set cursor position at particular row and column

    Reply
  • Can we display character other than ASCII? I want to display character of language other than english. Please sugges.t

    Reply
  • Hello! there’s a way to rotate 180 degrees the LCD matrix?? i devenloped a project but didnt notice that i made a 3d case on the wrong direction, and now i cant print anoter case.

    Reply
  • Hi, I want to clear pixel. What I have to do?
    Pls help me

    Reply
  • Adam Hamilton
    July 24, 2022 8:57 AM

    Just want to share one experience I had.

    I came here because I had trouble with my display and couldn’t get it working properly.

    I used the default SPI mode that CubeIDE had given me during program creation and it seemed that certain data wouldn’t work properly. I was getting areas where I the display ram was not affected.

    I noticed that the SPI was a roll your own type, so I thought maybe the SPI mode was wrong in my setup so I changed it to the following
    CPOL=Low
    CPHA=2 Edge

    It works now so if anyone comes here who has problems if they have used the SPI peripheral, then maybe this can work for you

    Reply
  • Hello. Will this program work with stm32f446re – 180MHz?

    Reply
  • Hello everyone!

    I tried at least 4 weeks running this program in the STM32F108 with the LCD 20 x 4 ( type is 12864 V 2.0 ) but the LCD doesn’t show anything!! When I put voltage on or reset the systems, the LCD only flashes one time. I used use CubeIDE, not CubeMX, but think so that is not make any sense make program wrong way….

    • I tried download program many time to the STM-board.
    • Reset card
    • Used some other card of STM32F108
    • Used some other card of LCD ( It was similar 12864 V2.0 )
    • I checked wiring many times….
    • I tried change some time-parameter too….but few time the LCD showed some letters in the screen but only some microsecond.
    • So..I think that some timing problem it should be!

    Does somebody else this kind of problems? What should be done for timings?

    Reply
  • Can you make Nokia 5110 LCD example?

    Reply
  • ST7920_DrawBitmap(image);
    what is image? int or char

    Reply
  • Maker Garage
    August 5, 2021 7:18 PM

    Can change font size?

    Reply
  • how can i fix this error?
    Error: L6200E: Symbol image multiply defined (by st7920_serial.o and main.o).

    Reply
  • ambaliya sharda
    March 3, 2021 2:54 PM

    can i use this library for jhd12864 glcd ?

    Reply
  • ambaliya sharda
    March 3, 2021 2:52 PM

    can i use this library for jhd12864 lcd

    Reply
  • How to display wifi scanning gif on lcd with stm32.please suggest me

    Reply
  • How do I set Pixels of lcd to make semicircle. Actually I want to make Wifi graphics over LCD,& reset pixels after high strength vice versa.

    Reply
  • Also Done this but after completing one loop. it only display large triangle actually small triangles overlap over large triangle,
    Im also try with increasing delay, but it only display large triangle.Please help me.

    while( i < 10)
    {
    ST7920_GraphicMode(1);
    DrawFilledTriangle(60,60,68,60,64,64);// min Triangle Values
    ST7920_Update();
    HAL_Delay(1000);
    DrawFilledTriangle(40,40,88,40,64,64);// mid Triangle Values
    ST7920_Update();
    HAL_Delay(1000);
    DrawFilledTriangle(20,20,108,20,64,64);// Max Triangle Values
    ST7920_Update();
    HAL_Delay(1000);
    ST7920_Clear();
    HAL_Delay(1000);
    i++;
    }

    Reply
    • try without the large triangle and see if others print.
      ST7920_GraphicMode(1); remove this. as it’s already in the graphic mode..

      Reply
      • I m also Try with this changes , in 1st loop it display perfect but in second loop it only prints large or medium which is greater than small triangle.

        Reply
  • Hi Sir, I have a question regarding your library ,
    when Im using draw filled triangle in loop from increasing to decreasing order ,It doesnt display smaller filled triangle, only display large triangle, Actually its Clear_St7920 issue, How to solve this problem, Here is my code
    while(uint8_t i<10)
    {
    ST7920_GraphicMode(1);
    DrawFilledTriangle(60,60,68,60,64,64);// min searching Values
    ST7920_Update();
    HAL_Delay(1000);
    DrawFilledTriangle(40,40,88,40,64,64);// mid searching Values
    ST7920_Update();
    HAL_Delay(1000);
    DrawFilledTriangle(20,20,108,20,64,64);// Max searching Values
    ST7920_Update();
    HAL_Delay(1000);
    ST7920_GraphicMode(0);
    ST7920_Clear();
    HAL_Delay(1000);
    i++;
    }

    Reply
    • don’t change the mode before clearing display

      Reply
      • Also Done this but after completing one loop. it only display large triangle actually small triangles overlap over large triangle,
        Im also try with increasing delay, but it only display large triangle.Please help me.

        while( i < 10)
        {
        ST7920_GraphicMode(1);
        DrawFilledTriangle(60,60,68,60,64,64);// min Triangle Values
        ST7920_Update();
        HAL_Delay(1000);
        DrawFilledTriangle(40,40,88,40,64,64);// mid Triangle Values
        ST7920_Update();
        HAL_Delay(1000);
        DrawFilledTriangle(20,20,108,20,64,64);// Max Triangle Values
        ST7920_Update();
        HAL_Delay(1000);
        ST7920_Clear();
        HAL_Delay(1000);
        i++;
        }

        Reply
  • .

    Reply
  • Hello, would this be compatible for an STM32L432KC. If yes, then how would you initialise the display?

    Reply
  • Abhishek Gupta
    May 18, 2020 4:53 PM

    I used the code for SINDA SDGB12864-02 graphical LCD but it is not showing any DATA on LCD since I do all needful steps to do in stm32f030r8t6 Evaluation board.
    I am using Keil v5 for coding.

    Reply
  • Hello, in the upper left corner are some randomly set /reset pixel. (in graphical mode) I have the same issue. Does somebody found the reason?

    Reply
  • Hi
    Code work’s fine on my stm32103c8t6, i’m using stm32cubeide
    How i can add & print custom character?

    Reply
  • Hello, in the left upper corner are sone random set/reset Pixel – in graphical mode. Did you found the reason? I habe the Sam Problem.

    Reply
  • hello guy. Thanks your document very much. but I have a question. I didnt use STM32f1. I used STM32f030C8, and it didnot work. I modified delay function in F0 because F0 on ly have 8M HSI, to create 1us delay. But it seem didnt work. Can you give me any idea?

    Reply
    • void SystemClock_Config(void)
      {
      RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

      /** Initializes the CPU, AHB and APB busses clocks
      */
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
      RCC_OscInitStruct.HSIState = RCC_HSI_ON;
      RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
      RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
      if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
      {
      Error_Handler();
      }
      /** Initializes the CPU, AHB and APB busses clocks
      */
      RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
      |RCC_CLOCKTYPE_PCLK1;
      RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
      RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV8;
      RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

      if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
      {
      Error_Handler();
      }
      }

      Reply
    • static void MX_TIM1_Init(void)
      {

      /* USER CODE BEGIN TIM1_Init 0 */

      /* USER CODE END TIM1_Init 0 */

      TIM_ClockConfigTypeDef sClockSourceConfig = {0};
      TIM_MasterConfigTypeDef sMasterConfig = {0};

      /* USER CODE BEGIN TIM1_Init 1 */

      /* USER CODE END TIM1_Init 1 */
      htim1.Instance = TIM1;
      htim1.Init.Prescaler = 1-1;
      htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
      htim1.Init.Period = 0xffff-1;
      htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
      htim1.Init.RepetitionCounter = 0;
      htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
      if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
      {
      Error_Handler();
      }
      sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
      if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
      {
      Error_Handler();
      }
      sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
      sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
      if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
      {
      Error_Handler();
      }
      /* USER CODE BEGIN TIM1_Init 2 */

      /* USER CODE END TIM1_Init 2 */

      }

      Reply
    • There is external crystal on F030c8. But even if you have used HSI, it should be okay.
      while doing the clock setup, in the HCLK, type 48 and hit enter
      Now select any timer for the delay purpose, use prescalar as 48-1, and ARR as 0xffff-1

      Reply

Leave a Reply

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

Fill out this field
Fill out this field
Please enter a valid email address.

keyboard_arrow_up

Adblocker detected! Please consider reading this notice.

We've detected that you are using AdBlock Plus or some other adblocking software which is preventing the page from fully loading.

We don't have any banner, Flash, animation, obnoxious sound, or popup ad. We do not implement these annoying types of ads!

We need money to operate the site, and almost all of it comes from our online advertising.

Please add controllerstech.com to your ad blocking whitelist or disable your adblocking software.

×