最近在使用一款TFT驱动芯片ST7789,在阅读芯片数据手册和液晶屏数据手册时,发现总是对不上,芯片手册中,有好几个引脚,一会儿是这个作用,一会儿又变成另一种作用,实在是让人感到混淆。网上找了好久,也没有人专门针对这款芯片进行细致地讲解,按理说,这款芯片很常用,为啥没有一个专门的教程呢,难道这个确实太简单了,只是我不会看数据手册吗?为此,从网上找了些零碎的内容,做一个简单的汇总整理,并根据我自己的理解和使用情况做一些必要的补充。

ST7789v是Sitronix公司研制的,用于驱动LCD的芯片,在市场上有很多TFT屏使用这款芯片驱动。注意:虽然驱动芯片相同,但不同TFT厂家在设计接口时各有不同

按照《ST7789v Datasheet》的描述,ST7789v的接口有以下几种:

- Parallel 8080-series MCU Interface (8-bit, 9-bit, 16-bit & 18-bit)

- 6/16/18 RGB Interface(VSYNC, HSYNC, DOTCLK, ENABLE, DB[17:0])

- Serial Peripheral Interface(SPI Interface)
- VSYNC Interface

其中Parallel 8080-series MCU Interface、Serial Peripheral Interface两种使用最多,市场上的TFT屏提供的基本是这两中接口或其中之一。

有几点需要注意:

(1)TFT厂家提供的接口描述与《ST7789v Datasheet》里的可能不一致,特别是引脚名称,需要核对清楚;

(2)TFT屏幕内的IM3是连接的高电平还是低电平,这直接约束可以使用哪些接口,IM3,它常常被TFT厂家在内部连好了;

(3)并口引脚的线序必须与厂家核对清楚。

本次,我使用的是SPI接口(4-line 8bit serial I/F Ⅱ下的SDO没有使用)。

端口定义示例如下:

/*MCU连接ST7789V端口定义*/
#define LCD_CS_PORT      	GpioPortA
#define LCD_CS_PIN       	GpioPin4 //CS
#define LCD_DCX_PORT     	GpioPortA
#define LCD_DCX_PIN      	GpioPin5 //不同显示屏厂家标识不同,如:RS/SPISCL/SCK		
#define LCD_SDA_PORT    	GpioPortA
#define LCD_SDA_PIN     	GpioPin7 //SDA/MOSI
 
#define LCD_WRX_PORT    	GpioPortA
#define LCD_WRX_PIN     	GpioPin3 //不同显示屏厂家标识不同,如:WR
 
/*ST7789 Reset控制端口定义*/
#define LCD_RESX_PORT		GpioPortA
#define LCD_RESX_PIN		GpioPin10 //不同显示屏厂家标识不同,如:RESET/RES

参考:HC32L196 驱动 ST7789v 经验_junzheng的博客-CSDN博客

ST7789V数据手册重点内容摘录

This chip is capable of connecting directly to an external microprocessor, and accepts, 8-bits/9-bits/16-bits/18-bits parallel interface.

基本特征

Display Resolution: 240*RGB (H) *320(V)

Frame Memory Size: 240 x 320 x 18-bit = 1,382,400 bits

MCU Interface

- Parallel 8080-series MCU Interface (8-bit, 9-bit, 16-bit & 18-bit)

- 6/16/18 RGB Interface(VSYNC, HSYNC, DOTCLK, ENABLE, DB[17:0])

- Serial Peripheral Interface(SPI Interface)

- VSYNC Interface

Wide Supply Voltage Range

- I/O Voltage (VDDI to DGND): 1.65V ~ 3.3V (VDDI≦VDD)

- Analog Voltage (VDD to AGND): 2.4V ~ 3.3V

框图

以上注意,DCX/RS和WRX/SCL这两个引脚的功能是可配置的。 

因此,具体厂家生产的液晶屏,需要核对好接口功能。

关键引脚

IM3 IM2 IM1 IM0这几位是决定使用哪种接口的。以及对应的一些位的作用。

复位

并行接口中用作数据/命令的选择位,SPI中用作时钟

 

片选,低电平使能

并口中是写使能,4线SPI中用作数据/命令选择接口

用在并口中,读使能

SPI接口的输入输出或者仅作为输入,数据在时钟的上升沿被锁存,要么是半双工,要么相当于MOSI引脚

SPI输出,在时钟下降沿输出数据,相当于MISO

DB[17:0] 并行口时用到的数据位。 

注意,上面DCX/RS和WRX/SCL这两个引脚的RS和SCL功能,并未提及,不知道具体是什么含义。

针对具体的液晶屏ASL024HLCGB00-210

只实现了两种接口,IM3和IM0固定为0 

当IM2和IM1均为1时,使用的就是4线8位SPI

片选

时钟

IM3固化为低电平,因此是数据输入/输出口

这里只能实现半双工,其实,可以将SDA作为输入(上升沿),然后还有个单独的SDO作为输出(下降沿),以此实现全双工。

命令/参数选择

又回到ST7789V数据手册

直接关注四线八位SPI,4-line serial interface

引脚定义

片选

The write mode of the interface means the micro controller writes commands and data to the LCD driver.

In 4-lines serial interface, data packet contains just transmission byte and control bit WRX is transferred by the WRX pin. If WRX is “low”, the transmission byte is interpreted as a command byte. If WRX is “high”, the transmission byte is stored in the display data RAM (memory write command), or command register as parameter.

Any instruction can be sent in any order to the driver. The MSB is transmitted first. The serial interface is initialized when CSX is high. In this state, SCL clock pulse or SDA data have no effect. A falling edge on CSX enables the serial interface and indicates the start of data transmission.

写时序

读时序

The read mode of the interface means that the micro controller reads register value from the driver. To achieve read function, the micro controller first has to send a command (read ID or register command) and then the following byte is transmitted in the opposite direction. After that CSX is required to go to high before a new command is send (see the below figure). The driver samples the SDA (input data) at rising edge of SCL, but shifts SDA (output data) at the falling edge of SCL. Thus the micro controller is supported to read at the

rising edge of SCL. After the read status command has been sent, the SDA line must be set to tri-state no later than at the falling edge of SCL of the last bit.

更多内容,详见数据手册。其他具体内容在实践中再总结补充吧。 

相关命令参考数据手册9 COMMAND 

ST7789驱动

/********************************************************************
* name         : 
* description  :    STM32F407        LCD
                    PB3  SPI1_SCK  - DC
                    PB4  SPI1_MISO - SD0
                    PB5  SPI1_MOSI - SDA
* Input        : 
* Return       : 
********************************************************************/
void Spi1Init(void)
{
    GPIO_InitTypeDef     GPIO_InitStruct;
    SPI_InitTypeDef      SPI_InitStruct;

    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB, ENABLE );
    RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1,  ENABLE ); //使能SPI1时钟

    /* GPIO配置 */
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_AF; //配置为复用模式
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd  = GPIO_PuPd_UP;

    /* MISO */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4;           
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* MOSI */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5;           
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_SetBits(GPIOB, GPIO_Pin_5);

    /* SCK */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;           
    GPIO_Init(GPIOB, &GPIO_InitStruct);

    GPIO_SetBits(GPIOB, GPIO_Pin_3);

    // 复用
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource3, GPIO_AF_SPI1);       /* PB3复用为 SPI1 */ 
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource4, GPIO_AF_SPI1);       /* PB4复用为 SPI1 */
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_SPI1);       /* PB5复用为 SPI1 */

    RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, ENABLE);          /* 复位 SPI1 */
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1, DISABLE);         /* 停止复位 SPI1 */

    SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //全双工模式;
    SPI_InitStruct.SPI_Mode = SPI_Mode_Master;     //主机模式
    SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; //SPI发送接收8位帧结构
    SPI_InitStruct.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
    SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge; //第二个跳变沿数据被采样
    SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;        //NSS信号由软件控制
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;   //传输速度为 84M/256=328.125KHz
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;  //数据传输从MSB位开始   
    SPI_InitStruct.SPI_CRCPolynomial = 7;    //CRC值计算的多项式 
    SPI_Init(SPI1, &SPI_InitStruct);

    SPI_Cmd(SPI1, ENABLE);
}

/********************************************************************
* name         : 
* description  : SPI1 读写一个字节
* Input        : 要写入的字节
* Return       : 读取到的字节
********************************************************************/
uint8_t SPI1ReadWriteByte(uint8_t TxData)
{		 			 
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空
	
	SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个byte数据
		
    while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一个byte 
 
	return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据	
}

/********************************************************************
* name         : 
* description  : SPI 发送数据
* Input        : 
* Return       : 
********************************************************************/
static void SendValue(uint8_t value)
{
    uint8_t i;
    
    OUT_LCD_SCL_LO;
    OUT_LCD_CS_ON;
    
    for(i = 0; i < 8; i++)
    {
        if(value & 0x80)
            OUT_LCD_SDA_HI;
        else
            OUT_LCD_SDA_LO;

        OUT_LCD_SCL_LO;
        value <<= 1;
        OUT_LCD_SCL_HI;
    }

    OUT_LCD_CS_OFF;
}

/********************************************************************
* name         : 
* description  : 写屏命令
* Input        : 
* Return       : 
********************************************************************/
static void WriteCommand(uint8_t value)
{
    OUT_LCD_WR_CMD;
    SendValue(value);
}

/********************************************************************
* name         : 
* description  : 写屏数据
* Input        : 
* Return       : 
********************************************************************/
static void WriteData(uint8_t value)
{
    OUT_LCD_WR_DAT;
    SendValue(value);
}

/********************************************************************
* name         : 
* description  : 写16位数据
* Input        : 
* Return       : 
********************************************************************/
static void Write16Bits(uint16_t value)
{
    OUT_LCD_WR_DAT;
    SendValue(value >> 8);
    SendValue(value);
}

/********************************************************************
* name         : 
* description  : 显示屏驱动芯片初始化
* Input        : 
* Return       : 
********************************************************************/
void St7789Init(void)
{
	OUT_LCD_RESET_START; 
	delay_ms(200);
	OUT_LCD_RESET_STOP;
	delay_ms(100);
	
	WriteCommand(0x11);
	delay_ms(10);

	WriteCommand(0x36);
	WriteData (0xa0);
    
	WriteCommand(0x3a);
	WriteData (0x05);      //像素点的数据格式设置为 RGB:565

    //与屏的型号有关
	WriteCommand(0x20);  // 颜色值需按位取反

	WriteCommand(0xb2);
	WriteData (0x0c); 
	WriteData (0x0c); 
	WriteData (0x00); 
	WriteData (0x33);
	WriteData (0x33);
	 
	WriteCommand(0xb7);
	WriteData (0x35);

	WriteCommand(0xbb);
	WriteData (0x35);
	WriteCommand(0xc0);
	WriteData (0x2c);
	WriteCommand(0xc2);
	WriteData (0x01);
	WriteCommand(0xc3);
	WriteData (0x0b);
	WriteCommand(0xc4);
	WriteData (0x20);
	WriteCommand(0xc6);
	WriteData (0x1e);
	WriteCommand(0xd0);
	WriteData (0xa4);
	WriteData (0xa1);

	WriteCommand(0xE0);    //Set Gamma
	WriteData (0xd0);
	WriteData (0x00);
	WriteData (0x02);
	WriteData (0x07);
	WriteData (0x0b);
	WriteData (0x1a);
	WriteData (0x31);
	WriteData (0x54);
	WriteData (0x40);
	WriteData (0x29);
	WriteData (0x12);
	WriteData (0x12);
	WriteData (0x12);
	WriteData (0x17);
	
	WriteCommand(0XE1);    //Set Gamma 
	WriteData (0xd0);
	WriteData (0x00);
	WriteData (0x02);
	WriteData (0x07);
	WriteData (0x05);
	WriteData (0x25);
	WriteData (0x2d);
	WriteData (0x44);
	WriteData (0x45);
	WriteData (0x1c);
	WriteData (0x18);
	WriteData (0x16);
	WriteData (0x1c);
	WriteData (0x1d);
    
	WriteCommand(0x29);
}

/********************************************************************
* name         : 
* description  : 画点函数,在坐标为(xStart,yStart)的位置,画一个点
* Input        : 
* Return       : 
********************************************************************/
void LcdDrawPoint(uint32_t xStart, uint32_t yStart, uint32_t color) 
{
	WriteCommand(0x2a);
    Write16Bits(xStart);
	
	WriteCommand(0x2b);
    Write16Bits(yStart);
	
	WriteCommand(0x2c);
    Write16Bits(color);
}

/********************************************************************
* name         : 
* description  : 窗口设置函数
* Input        : 
* Return       : 
********************************************************************/
void SetWindow(uint32_t xStart, uint32_t yStart, uint32_t xEnd, uint32_t yEnd)
{
	WriteCommand(0x2a);
	Write16Bits(xStart);
    Write16Bits(xEnd);
	
	WriteCommand(0x2b);
    Write16Bits(yStart);
    Write16Bits(yEnd);
	
	WriteCommand(0x2c);
}

/********************************************************************
* name         : 
* description  : 设置背景色
* Input        : 
* Return       : 
********************************************************************/
void St7789SetBGColor(uint32_t color)
{
	uint32_t i,j;
	
	SetWindow(0,0,(LCD_WIDTH-1),(LCD_HEIGHT-1));
    
	for(i=0;i<LCD_HEIGHT;i++)
	{
		for(j=0;j<LCD_WIDTH;j++)
		{
            Write16Bits(color);
		}
	}
}

/********************************************************************
* name         : 
* description  : 填充块
* Input        : 
* Return       : 
********************************************************************/
void St7789FillBlock(uint32_t xStart, uint32_t yStart, uint32_t block_width, uint32_t block_height, uint16_t color)
{
	uint32_t i,j;
	
	SetWindow( xStart, yStart, (xStart+block_width-1), (yStart+block_height-1) );
	for(i=0;i<block_width;i++)
	{
		for(j=0;j<block_height;j++)
		{
            Write16Bits(color);
		}
	}
}

/********************************************************************
* name         : 
* description  : 在坐标为(xStart,yStart)的位置,
                 填充一个宽和高分别为block_width、block_height的图片
* Input        : block_data为指向图片点阵数据的指针,
                 图片点阵数据格式为 RGB:565
* Return       : 
********************************************************************/
void St7789DrawPic(uint32_t xStart, uint32_t yStart, uint32_t block_width, uint32_t block_height, const uint8_t *block_data)
{
	uint32_t i,j;

	SetWindow( xStart, yStart, (xStart+block_width-1), (yStart+block_height-1) );
    
	for(i=0;i<block_width;i++)
	{
		for(j=0;j<block_height;j++)
		{
			WriteData(*(block_data+1));
			WriteData(*block_data);
			
			block_data += 2;
		}
	}
}

/********************************************************************
* name         : 
* description  : 二进制画图
* Input        : 
* Return       : 
********************************************************************/
void St7789DrawImageBin(uint32_t x, uint32_t y, uint32_t w, uint32_t h, const uint8_t *image_mask, uint32_t color, bool reverse)
{
    uint32_t i, j;
    uint32_t x0, y0;
    uint8_t  bit_mask;
    
    for(i = 0; i < h; i++)
    {
        y0 = y + i;
        
        bit_mask = 0x80;
        for(j = 0; j < w; j++)
        {
            if(reverse)
                x0 = x + w - 1 - j;
            else
                x0 = x + j;
 
            if(*image_mask & bit_mask)
            {
                LcdDrawPoint(x0, y0, color);
            }

            bit_mask >>= 1;
            if(bit_mask == 0)
            {
                bit_mask = 0x80;
                image_mask++;
            }
        }
        if(bit_mask != 0x80)
            image_mask++;        
    }
}

/********************************************************************
* name         : 
* description  : 绘制字符串,可设置前景色和背景色
* Input        : 
* Return       : 
********************************************************************/
void St7789DrawChar(uint32_t x, uint32_t y, uint32_t w, uint32_t h, const uint8_t *str, uint32_t forecolor, uint32_t backcolor)
{
    uint32_t i, j;
    uint8_t  mask;
    
    SetWindow( x, y, x + w - 1, y + h -1);
    
    for(i = 0; i < h; i++)
    {
        mask = 0x80;//取模时:阴码,高位在前
        for(j = 0; j < w; j++)
        {
            if(*str & mask)
                Write16Bits(forecolor);
            else
                Write16Bits(backcolor);
            
            mask >>= 1;
            if(mask == 0)
            {
                mask = 0x80;
                str++;
            }
        }
        
        if(mask != 0x80)
            str++;
    }
}

/********************************************************************
* description  : 画一个圆形(无填充)
* Input        : x0,y0	        圆心坐标
                 r              圆半径
                 mask_quadrant  象限选择
* Return       : 
********************************************************************/
void St7789DrawCycle(uint32_t x0, uint32_t y0, uint32_t r, uint32_t forecolor, uint8_t mask_quadrant)
{
    int a, b;
    int di;
    
    a = 0;
    b = r;
    di = 3 - (r << 1);

    while(a <= b)
    {
        // 第 1 象限
        if(mask_quadrant & 0x01)
        {
            LcdDrawPoint(x0 + b, y0 - a, forecolor);
            LcdDrawPoint(x0 + a, y0 - b, forecolor);
        }
        
        // 第 2 象限
        if(mask_quadrant & 0x02)
        {
            LcdDrawPoint(x0 - b, y0 - a, forecolor);
            LcdDrawPoint(x0 - a, y0 - b, forecolor);
        }
        
        // 第 3 象限
        if(mask_quadrant & 0x04)
        {
            LcdDrawPoint(x0 - a, y0 + b, forecolor);
            LcdDrawPoint(x0 - b, y0 + a, forecolor);
        }
        
        // 第 4 象限
        if(mask_quadrant & 0x08)
        {
            LcdDrawPoint(x0 + b, y0 + a, forecolor);
            LcdDrawPoint(x0 + a, y0 + b, forecolor);
        }
             
        a++;

        if(di < 0)
        {
            di += 4 * a + 6;
        }
        else
        {
            di += 10 + 4 * (a - b);
            b--;
        }
    }
}

/********************************************************************
* description  : 画一个圆块
* Input        : x0,y0	        圆心坐标
                 r              圆半径
                 color          颜色
* Return       : 
********************************************************************/
void St7789DrawFilledCycle(uint32_t x0, uint32_t y0, uint32_t r, uint32_t color)
{
    int16_t sCurrentX, sCurrentY;
	int16_t sError;
  
	sCurrentX = 0;
  	sCurrentY = r;	
	sError    = 3- (r<<1);   //判断下个点位置的标志
	
	while(sCurrentX <= sCurrentY)
	{
		int16_t sCountY;		
			
        for(sCountY=sCurrentX;sCountY<=sCurrentY;sCountY++)
        {                      
            LcdDrawPoint(x0 + sCurrentX, y0 + sCountY, color); 
            LcdDrawPoint(x0 - sCurrentX, y0 + sCountY, color);       
            LcdDrawPoint(x0 - sCountY,   y0 + sCurrentX, color);
            LcdDrawPoint(x0 - sCountY,   y0 - sCurrentX, color);
            LcdDrawPoint(x0 - sCurrentX, y0 - sCountY, color);   
            LcdDrawPoint(x0 + sCurrentX, y0 - sCountY, color);
            LcdDrawPoint(x0 + sCountY,   y0 - sCurrentX, color);
            LcdDrawPoint(x0 + sCountY,   y0 + sCurrentX, color);		
        }
    		
		sCurrentX++;		
		if(sError < 0) 
    	{
			sError += (4*sCurrentX + 6);	  
		}
		else
		{
			sError += (10 + 4*(sCurrentX - sCurrentY));   
			sCurrentY--;
		} 
	}
}
/*************************** END OF FILE ***************************/

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐