catalogue
- Lianshengde HLK-W806 (I): development environment configuration, compilation and burning instructions under Ubuntu 20.04
- Lianshengde HLK-W806 (II): description of development environment configuration, compilation and burning under Win10
- Lianshengde HLK-W806 (III): key free automatic download and reset
- Lianshengde HLK-W806 (IV): ST7735 LCD driven by software SPI and hardware SPI
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