Lianshengde HLK-W806: software SPI and hardware SPI drive ST7735 LCD

catalogue

ST7735 introduction

ST7735 is a TFT driver chip for driving up to 162x132 pixels, with 396 (128 * 3 colors) x162 line output. It can be directly connected to an external controller in SPI protocol or 8-bit / 9-bit / 16-bit parallel
The display data can be stored in the on-chip 132 x 162 x 18 bits memory. The reading and writing of the display memory does not need to be driven by an external clock

128x160 TFT LCD module using ST7735

connect

The LCD module of ST7735 has different resolutions such as 128x128 and 128x160. There are 6 external wires except VCC and GND

  • SCL SPI clock, corresponding to the SCK of the host computer SPI
  • SDA SPI data input, corresponding to MOSI of host computer SPI
  • RES is restarted, the low level is valid, and it is at the high level during operation
  • DC command mode and data mode switching bit. Low level is command mode and high level is data mode
  • CS chip selection signal, corresponding to CS of host computer SPI
  • BL backlight, high level on, low level off

If software SPI is used, the IO port can be selected freely. If hardware SPI is used, CS, SCK, MOSI and MISO(ST7735 not used) can only use specific IO ports. According to the manual of W806, the following options are available

  • CS: B4, B14
  • SCK: B1, B2, B15, B24
  • MOSI: B5, B17, B26, PA7
  • MISO: B0, B3, B16, B25

The connection mode corresponding to this test is

  • B10 -> RES, RESET
  • B11 -> DC, CD
  • B14 -> CS, Chip Select
  • B15 -> SCK, SCL, CLK, Clock
  • B16 -> BL, Back Light
  • B17 -> MOSI, SDA
  • GND -> GND
  • 3.3V -> VCC

Control of ST7735

Basic communication method

  • Software SPI mode
static void ST7735_TransmitByte(uint8_t dat)
{
    uint8_t i;
    ST7735_CS_LOW;
    for (i = 0; i < 8; i++)
    {
        ST7735_SCK_LOW;
        if (dat & 0x80)
        {
            ST7735_MOSI_HIGH;
        }
        else
        {
            ST7735_MOSI_LOW;
        }
        ST7735_SCK_HIGH;
        dat <<= 1;
    }
    ST7735_CS_HIGH;
}
  • Hardware SPI mode
static void ST7735_TransmitByte(uint8_t dat)
{
    ST7735_CS_LOW;
    HAL_SPI_Transmit(&hspi, &dat, 1, 100);
    ST7735_CS_HIGH;
}

Use BUFFER to improve refresh speed

Under hardware SPI, because the interface implementation is based on batch data, the efficiency of batch writing data is much higher than that of single byte or double byte writing. You can apply for a small section of memory to increase buffer in the code, and call SPI through buffer in drawing, which can make full use of the transmission speed of hardware SPI

Declare buffer area

static uint8_t st7735_buf[ST7735_BUF_SIZE];
static uint16_t st7735_buf_pt = 0;

Write buffer and empty buffer

static void ST7735_WriteBuff(uint8_t* buff, size_t buff_size)
{
    while (buff_size--)
    {
        st7735_buf[st7735_buf_pt++] = *buff++;
        if (st7735_buf_pt == ST7735_BUF_SIZE)
        {
            ST7735_Transmit(st7735_buf, st7735_buf_pt, HAL_MAX_DELAY);
            st7735_buf_pt = 0;
        }
    }
}

static void ST7735_FlushBuff(void)
{
    if (st7735_buf_pt > 0)
    {
        ST7735_Transmit(st7735_buf, st7735_buf_pt, HAL_MAX_DELAY);
        st7735_buf_pt = 0;
    }
}

Use buffer in area filling

void ST7735_Fill(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end, uint16_t color)
{
    uint16_t i,j;
    ST7735_SetAddrWindow(x_start, y_start, x_end - 1, y_end - 1);
    for(i = y_start; i < y_end; i++)
    {
        for( j = x_start; j < x_end; j++)
        {
            ST7735_WriteBuff((uint8_t *)&color, 2);
        }
    }
    ST7735_FlushBuff();
}

Test code

Control backlight

ST7735_BackLight_On();
ST7735_BackLight_Off();

Fill color block

ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_RED);

Output character

ST7735_DrawString(5, y, (const char *)"0123456789ABCDE", Font_6x12, ST7735_YELLOW, ST7735_RED);

Output picture

ST7735_DrawImage(0, 0, 128, 160, (uint16_t *)testimage1);

Reference st7735.h in the main program and initialize it

main.c

#include <stdio.h>
#include "wm_hal.h"
#include "st7735.h"
#include "testimg2.h"

void Error_Handler(void);

SPI_HandleTypeDef hspi;

static void SPI_Init(void)
{
    hspi.Instance = SPI;
    hspi.Init.Mode = SPI_MODE_MASTER;
    hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi.Init.NSS = SPI_NSS_SOFT;
    hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    hspi.Init.FirstByte = SPI_LITTLEENDIAN;

    if (HAL_SPI_Init(&hspi) != HAL_OK)
    {
        Error_Handler();
    }
}

int main(void)
{
    uint8_t y = 10;
    SystemClock_Config(CPU_CLK_240M);
    ST7735_GPIO_Init();
    SPI_Init();
    ST7735_Init();
    while(1)
    {
        ST7735_BackLight_On();
        ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_RED);
        HAL_Delay(500);
        ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_YELLOW);
        HAL_Delay(500);
        ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_GREEN);
        HAL_Delay(500);
        ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_CYAN);
        HAL_Delay(500);
        ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_MAGENTA);
        HAL_Delay(500);
        ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_ORANGE);
        HAL_Delay(500);
        ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_BROWN);
        HAL_Delay(500);
        ST7735_Fill(0, 0, ST7735_WIDTH, ST7735_HEIGHT, ST7735_BLUE);
        HAL_Delay(500);
        y = 10;
        ST7735_DrawString(5, y, (const char *)"0123456789ABCDE", Font_6x12, ST7735_YELLOW, ST7735_RED);
        HAL_Delay(1000);

        ST7735_DrawImage(0, 0, 128, 160, (uint16_t *)testimage1);
        HAL_Delay(1000);
        ST7735_DrawImage(0, 0, 128, 160, (uint16_t *)testimage2);
        HAL_Delay(1000);
        ST7735_BackLight_Off();
        HAL_Delay(1000);
    }
}

In addition, it needs to be in WM_ hal_ Adding SPI initialization method in MSP. C

wm_hal_msp.c

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
    __HAL_RCC_SPI_CLK_ENABLE();
    __HAL_AFIO_REMAP_SPI_CS(ST7735_CS_PORT, ST7735_CS_PIN);
    __HAL_AFIO_REMAP_SPI_CLK(ST7735_SCK_PORT, ST7735_SCK_PIN);
    __HAL_AFIO_REMAP_SPI_MOSI(ST7735_MOSI_PORT, ST7735_MOSI_PIN);
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{
    __HAL_RCC_SPI_CLK_DISABLE();
    HAL_GPIO_DeInit(ST7735_CS_PORT, ST7735_CS_PIN);
    HAL_GPIO_DeInit(ST7735_SCK_PORT, ST7735_SCK_PIN);
    HAL_GPIO_DeInit(ST7735_MOSI_PORT, ST7735_MOSI_PIN);
}

test data

In the 128x160 LCD, test two 128x160 pictures in the main process through the following code without intermittent cyclic refresh

for (uint16_t i = 0; i < 1000; i++)
{
    ST7735_DrawImage(0, 0, 128, 160, (uint16_t *)testimage1);
    ST7735_DrawImage(0, 0, 128, 160, (uint16_t *)testimage2);
}
printf("done");

The recorded results are

[2021-11-28 08:06:33.267]
RX: done
[2021-11-28 08:07:12.256]
RX: done
[2021-11-28 08:07:51.232]
RX: done
[2021-11-28 08:08:30.204]
RX: done
[2021-11-28 08:09:09.181]
RX: done
[2021-11-28 08:09:48.166]
RX: done
[2021-11-28 08:10:27.145]
RX: done
[2021-11-28 08:11:06.113]
RX: done
[2021-11-28 08:11:45.145]
RX: done
[2021-11-28 08:12:24.073]
RX: done

It can be seen that the interval is basically about 39 seconds. According to this result, the calculated full screen refresh rate is 2000/39 = 51.2 FPS

Related code

The above code is located in Github: https://github.com/IOsetting/wm-sdk-w806/tree/dev/demo/spi/st7735_lcd

Posted on Sat, 27 Nov 2021 21:23:45 -0500 by tamir_malas