目录

STM32SPI屏幕刷图总结GPIO模拟,硬件SPI,DMA硬件SPI

【STM32】SPI屏幕刷图总结:GPIO模拟,硬件SPI,DMA+硬件SPI

文章目录

代码工程:https://github.com/liefyuan/stm32-spi-st7789-tft.git

https://i-blog.csdnimg.cn/blog_migrate/42d6e9aa8fb7761464e0f66249cb03fd.png

前言

我的屏幕的分辨率是:240*320

驱动是:ST7789V

线驱动方式:四线SPI(CS,DC,SDA,SCL)

以下分别使用了三种方式来实现刷图。

头文件:

#ifndef __ST7789_DRIVER_H__
#define __ST7789_DRIVER_H__

#include "stdint.h"
#include "stm32f4xx.h"
#include "system_stm32f4xx.h"

#define ST7789_LCD_WIDTH 240
#define ST7789_LCD_HEIGHT 320

// System Function Command Table 1
#define ST7789_CMD_NOP 0x00 // No operation
#define ST7789_CMD_SWRESET 0x01 // Software reset
#define ST7789_CMD_RDDID 0x04 // Read display ID
#define ST7789_CMD_RDDST 0x09 // Read display status
#define ST7789_CMD_RDDPM 0x0a // Read display power
#define ST7789_CMD_RDDMADCTL 0x0b // Read display
#define ST7789_CMD_RDDCOLMOD 0x0c // Read display pixel
#define ST7789_CMD_RDDIM 0x0d // Read display image
#define ST7789_CMD_RDDSM 0x0e // Read display signal
#define ST7789_CMD_RDDSDR 0x0f // Read display self-diagnostic result
#define ST7789_CMD_SLPIN 0x10 // Sleep in
#define ST7789_CMD_SLPOUT 0x11 // Sleep out
#define ST7789_CMD_PTLON 0x12 // Partial mode on
#define ST7789_CMD_NORON 0x13 // Partial off (Normal)
#define ST7789_CMD_INVOFF 0x20 // Display inversion off
#define ST7789_CMD_INVON 0x21 // Display inversion on
#define ST7789_CMD_GAMSET 0x26 // Gamma set
#define ST7789_CMD_DISPOFF 0x28 // Display off
#define ST7789_CMD_DISPON 0x29 // Display on
#define ST7789_CMD_CASET 0x2a // Column address set
#define ST7789_CMD_RASET 0x2b // Row address set
#define ST7789_CMD_RAMWR 0x2c // Memory write
#define ST7789_CMD_RAMRD 0x2e // Memory read
#define ST7789_CMD_PTLAR 0x30 // Partial start/end address set
#define ST7789_CMD_VSCRDEF 0x33 // Vertical scrolling definition
#define ST7789_CMD_TEOFF 0x34 // Tearing line effect off
#define ST7789_CMD_TEON 0x35 // Tearing line effect on
#define ST7789_CMD_MADCTL 0x36 // Memory data access control
#define ST7789_CMD_VSCRSADD 0x37 // Vertical address scrolling
#define ST7789_CMD_IDMOFF 0x38 // Idle mode off
#define ST7789_CMD_IDMON 0x39 // Idle mode on
#define ST7789_CMD_COLMOD 0x3a // Interface pixel format
#define ST7789_CMD_RAMWRC 0x3c // Memory write continue
#define ST7789_CMD_RAMRDC 0x3e // Memory read continue
#define ST7789_CMD_TESCAN 0x44 // Set tear scanline
#define ST7789_CMD_RDTESCAN 0x45 // Get scanline
#define ST7789_CMD_WRDISBV 0x51 // Write display brightness
#define ST7789_CMD_RDDISBV 0x52 // Read display brightness value
#define ST7789_CMD_WRCTRLD 0x53 // Write CTRL display
#define ST7789_CMD_RDCTRLD 0x54 // Read CTRL value display
#define ST7789_CMD_WRCACE 0x55 // Write content adaptive brightness control and Color enhancemnet
#define ST7789_CMD_RDCABC 0x56 // Read content adaptive brightness control
#define ST7789_CMD_WRCABCMB 0x5e // Write CABC minimum brightness
#define ST7789_CMD_RDCABCMB 0x5f // Read CABC minimum brightness
#define ST7789_CMD_RDABCSDR 0x68 // Read Automatic Brightness Control Self-Diagnostic Result
#define ST7789_CMD_RDID1 0xda // Read ID1
#define ST7789_CMD_RDID2 0xdb // Read ID2
#define ST7789_CMD_RDID3 0xdc // Read ID3

// System Function Command Table 2
#define ST7789_CMD_RAMCTRL 0xb0 // RAM Control
#define ST7789_CMD_RGBCTRL 0xb1 // RGB Control
#define ST7789_CMD_PORCTRL 0xb2 // Porch control
#define ST7789_CMD_FRCTRL1 0xb3 // Frame Rate Control 1
#define ST7789_CMD_GCTRL 0xb7 // Gate control
#define ST7789_CMD_DGMEN 0xba // Digital Gamma Enable
#define ST7789_CMD_VCOMS 0xbb // VCOM Setting
#define ST7789_CMD_LCMCTRL 0xc0 // LCM Control
#define ST7789_CMD_IDSET 0xc1 // ID Setting
#define ST7789_CMD_VDVVRHEN 0xc2 // VDV and VRH Command enable
#define ST7789_CMD_VRHS 0xc3 // VRH Set
#define ST7789_CMD_VDVSET 0xc4 // VDV Setting
#define ST7789_CMD_VCMOFSET 0xc5 // VCOM Offset Set
#define ST7789_CMD_FRCTR2 0xc6 // FR Control 2
#define ST7789_CMD_CABCCTRL 0xc7 // CABC Control
#define ST7789_CMD_REGSEL1 0xc8 // Register value selection 1
#define ST7789_CMD_REGSEL2 0xca // Register value selection 2
#define ST7789_CMD_PWMFRSEL 0xcc // PWM Frequency Selection
#define ST7789_CMD_PWCTRL1 0xd0 // Power Control 1
#define ST7789_CMD_VAPVANEN 0xd2 // Enable VAP/VAN signal output
#define ST7789_CMD_CMD2EN 0xdf // Command 2 Enable
#define ST7789_CMD_PVGAMCTRL 0xe0 // Positive Voltage Gamma Control
#define ST7789_CMD_NVGAMCTRL 0xe1 // Negative voltage Gamma Control
#define ST7789_CMD_DGMLUTR 0xe2 // Digital Gamma Look-up Table for Red
#define ST7789_CMD_DGMLUTB 0xe3 // Digital Gamma Look-up Table for Blue
#define ST7789_CMD_GATECTRL 0xe4 // Gate control
#define ST7789_CMD_PWCTRL2 0xe8 // Power Control 2
#define ST7789_CMD_EQCTRL 0xe9 // Equalize Time Control
#define ST7789_CMD_PROMCTRL 0xec // Program Control
#define ST7789_CMD_PROMEN 0xfa // Program Mode Enable
#define ST7789_CMD_NVMSET 0xfc // NVM Setting
#define ST7789_CMD_PROMACT 0xfe // Program Action

#define ST7789_CMDLIST_END 0xff // End command (used for command list)

#define RED 0xf800
#define GREEN 0x07e0
#define BLUE 0x001f
#define WHITE 0xffff
#define BLACK 0x0000
#define YELLOW 0xFFE0
#define GRAY0 0xEF7D //灰色 0 3165 00110 001011 00101
#define GRAY1 0x8410 //灰色 1 00000 000000 00000
#define GRAY2 0x4208 //灰色 2 1111111111011111

//#define LCD_SDA //PB15 // SPI 数据引脚
//#define LCD_SCL //PB13 // SPI 时钟引脚
//#define LCD_CS //PB12 // SPI 片选引脚
//#define LCD_DC //PB11 // SPI 数据/命令引脚
//#define LCD_RST //PB10 // 屏幕复位引脚 
//#define LCD_BLK //PB1 // 背光控制引脚

//液晶控制口置 1 操作语句宏定义
#define LCD_SDA_SET GPIO_SetBits(GPIOB, GPIO_Pin_15)
#define LCD_SCL_SET GPIO_SetBits(GPIOB, GPIO_Pin_13)

#define LCD_CS_SET GPIO_SetBits(GPIOB, GPIO_Pin_12) 
#define LCD_DC_SET GPIO_SetBits(GPIOB, GPIO_Pin_11)

#define LCD_RST_SET GPIO_SetBits(GPIOB, GPIO_Pin_10)

#define LCD_BLK_SET GPIO_SetBits(GPIOB, GPIO_Pin_1) 

//液晶控制口置 0 操作语句宏定义
#define LCD_SDA_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_15) 
#define LCD_SCL_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_13) 

#define LCD_CS_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_12) 
#define LCD_DC_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_11) 

#define LCD_RST_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_10)

#define LCD_BLK_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_1)

void LCD_GPIO_Init(void);
void Lcd_Init(void);
void Lcd_Test(void);
void Lcd_Full(uint16_t color);
void Lcd_Dma_Full(uint16_t color);

#endif // **ST7789_DRIVER_H**

GPIO 模拟 SPI

//液晶控制口置 1 操作语句宏定义
#define LCD_SDA_SET GPIO_SetBits(GPIOB, GPIO_Pin_15)
#define LCD_SCL_SET GPIO_SetBits(GPIOB, GPIO_Pin_13)

#define LCD_CS_SET GPIO_SetBits(GPIOB, GPIO_Pin_12) 
#define LCD_DC_SET GPIO_SetBits(GPIOB, GPIO_Pin_11)

#define LCD_RST_SET GPIO_SetBits(GPIOB, GPIO_Pin_10)

#define LCD_BLK_SET GPIO_SetBits(GPIOB, GPIO_Pin_1) 

//液晶控制口置 0 操作语句宏定义
#define LCD_SDA_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_15) 
#define LCD_SCL_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_13) 

#define LCD_CS_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_12) 
#define LCD_DC_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_11) 

#define LCD_RST_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_10)

#define LCD_BLK_CLR GPIO_ResetBits(GPIOB, GPIO_Pin_1)
//液晶 IO 初始化配置
void LCD_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Pin =   GPIO_Pin_1 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;     //普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;    //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;      //上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);

}
//向 SPI 总线传输一个 8 位数据
void SPI_WriteData(uint8_t Data)
{
uint8_t i;

    for(i = 0; i < 8; i++)    // 295 ms 1 frame
    {
        if((Data&0x80) != 0)
        {
            LCD_SDA_SET;
        }
        else
            LCD_SDA_CLR;

        LCD_SCL_CLR;
        LCD_SCL_SET;
        Data <<= 1;
    }

}

//向液晶屏写一个 8 位指令
void Lcd_WriteIndex(uint8_t Index)
{
//SPI 写命令时序开始
LCD_CS_CLR;
LCD_DC_CLR;

    SPI_WriteData(Index);
    LCD_CS_SET;

}

//向液晶屏写一个 8 位数据
void Lcd_WriteData(uint8_t Data)
{
LCD_CS_CLR;
LCD_DC_SET;

    SPI_WriteData(Data);
    LCD_CS_SET;

}
//向液晶屏写一个 16 位数据
void LCD_WriteData_16Bit(uint16_t Data)
{
// LCD_CS_CLR;
// LCD_DC_SET;
SPI_WriteData(Data>>8); //写入高 8 位数据
SPI_WriteData(Data); //写入低 8 位数据
// LCD_CS_SET;
}

void Lcd_WriteReg(uint8_t Index,uint8_t Data)
{
Lcd_WriteIndex(Index);
Lcd_WriteData(Data);
}

void Lcd_Reset(void)
{
LCD_RST_CLR;//RST 引脚输出为低
delay_ms(100);
LCD_RST_SET;//RST 引脚输出为高
delay_ms(100);
}

/***********************************************************************/

void Lcd_Init(void)
{
LCD_GPIO_Init();

    LCD_RST_CLR;
    delay_ms(1000);
    LCD_RST_SET;
    /********************************************************/
    delay_ms(1000);
    Lcd_WriteIndex(ST7789_CMD_SLPOUT); 	//Sleep Out
    delay_ms(120);
    //-----------------------ST7789V Frame rate setting-----------------//
    //************************************************
    Lcd_WriteIndex(ST7789_CMD_COLMOD);       //65k mode
    Lcd_WriteData(0x05);

    Lcd_WriteIndex(ST7789_CMD_VCMOFSET); 	//VCOM
    Lcd_WriteData(0x1A);

    Lcd_WriteIndex(ST7789_CMD_MADCTL);       // 屏幕显示方向设置
    Lcd_WriteData(0x00);
    //-------------ST7789V Frame rate setting-----------//
    Lcd_WriteIndex(ST7789_CMD_PORCTRL);		//Porch Setting
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x00);
    Lcd_WriteData(0x33);
    Lcd_WriteData(0x33);

    Lcd_WriteIndex(ST7789_CMD_GCTRL);		//Gate Control
    Lcd_WriteData(0x05);			//12.2v   -10.43v
    //--------------ST7789V Power setting---------------//
    Lcd_WriteIndex(ST7789_CMD_VCOMS);//VCOM
    Lcd_WriteData(0x3F);

    Lcd_WriteIndex(ST7789_CMD_LCMCTRL); //Power control
    Lcd_WriteData(0x2c);

    Lcd_WriteIndex(ST7789_CMD_VDVVRHEN);	//VDV and VRH Command Enable
    Lcd_WriteData(0x01);

    Lcd_WriteIndex(ST7789_CMD_VRHS);		//VRH Set
    Lcd_WriteData(0x0F);		//4.3+( vcom+vcom offset+vdv)

    Lcd_WriteIndex(ST7789_CMD_VDVSET);		//VDV Set
    Lcd_WriteData(0x20);				//0v

    Lcd_WriteIndex(ST7789_CMD_FRCTR2);		//Frame Rate Control in Normal Mode
    Lcd_WriteData(0X01);			     //111Hz

    Lcd_WriteIndex(ST7789_CMD_PWCTRL1);		//Power Control 1
    Lcd_WriteData(0xa4);
    Lcd_WriteData(0xa1);

    Lcd_WriteIndex(ST7789_CMD_PWCTRL2);		//Power Control 1
    Lcd_WriteData(0x03);

    Lcd_WriteIndex(ST7789_CMD_EQCTRL);		//Equalize time control
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    //---------------ST7789V gamma setting-------------//
    Lcd_WriteIndex(ST7789_CMD_PVGAMCTRL); //Set Gamma
    Lcd_WriteData(0xD0);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x33);
    Lcd_WriteData(0x3F);
    Lcd_WriteData(0x07);
    Lcd_WriteData(0x13);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x30);

    Lcd_WriteIndex(ST7789_CMD_NVGAMCTRL); //Set Gamma
    Lcd_WriteData(0xD0);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    Lcd_WriteData(0x03);
    Lcd_WriteData(0x24);
    Lcd_WriteData(0x32);
    Lcd_WriteData(0x32);
    Lcd_WriteData(0x3B);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x13);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x2F);

    Lcd_WriteIndex(ST7789_CMD_INVON);		//反显

    Lcd_WriteIndex(ST7789_CMD_DISPON);		//开启显示

}

/*************************************************
函数名:LCD_Set_Region
功能:设置 lcd 显示区域,在此区域写点数据自动换行
入口参数:xy 起点和终点,Y_IncMode 表示先自增 y 再自增 x
返回值:无
*************************************************/
void Lcd_SetRegion(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end)
{
Lcd_WriteIndex(0x2a);
Lcd_WriteData(0x00);
Lcd_WriteData(x_start);
Lcd_WriteData(0x00);
Lcd_WriteData(x_end);

    Lcd_WriteIndex(0x2b);
    Lcd_WriteData(0x00);
    Lcd_WriteData(y_start);
    Lcd_WriteData(y_end>>8);
    Lcd_WriteData(y_end);

    Lcd_WriteIndex(0x2c); //开始写入GRAM

}

void Lcd_Full(uint16_t color)
{
uint16_t row,column;

    Lcd_SetRegion(0, 0, ST7789_LCD_WIDTH, ST7789_LCD_HEIGHT);

    LCD_CS_CLR;
    LCD_DC_SET;
    for(row = 0;row < ST7789_LCD_WIDTH; row++)             //ROW loop
    {
    	for(column = 0;column < ST7789_LCD_HEIGHT; column++) //column loop
    	{
    		LCD_WriteData_16Bit(color); // 180ms 1 frame
    	}
    }
    LCD_CS_SET;

}

硬件 SPI 外设

SPI_InitTypeDef SPI_InitStructure;

void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

    //SPI2的时钟来源是APB1 42MHz
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);	//使能GPIOB、SPI2时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);	//使能GPIOB、SPI2时钟

    //PB13--SCL ,PB15--SDI初始化设置,
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;//PB13,PB15复用功能输出
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化

    GPIO_PinAFConfig(GPIOB,GPIO_PinSource13,GPIO_AF_SPI2); //PB13复用为 SPI2

    GPIO_PinAFConfig(GPIOB,GPIO_PinSource15,GPIO_AF_SPI2); //PB15复用为 SPI2

    //这里只针对SPI口初始化
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,ENABLE);//复位SPI2
    RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI2,DISABLE);//停止复位SPI2

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//串行同步时钟的空闲状态为低电平
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//串行同步时钟的第一个跳变沿(上升或下降)数据被采样
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;		//定义波特率预分频的值:波特率预分频值为
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
    SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
    SPI_Init(SPI2, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器

    SPI_Cmd(SPI2, ENABLE); //使能SPI外设
    SPI2_ReadWriteByte(0xff);//启动传输

}

//液晶 IO 初始化配置
void LCD_Hal_Spi_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC,ENABLE);

    GPIO_InitStructure.GPIO_Pin =   GPIO_Pin_10  | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_SetBits(GPIOB,GPIO_Pin_14);//MISO引脚输出为高

    SPI2_Init();//初始化硬件SPI2

}

//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint8_t SPI2_ReadWriteByte(uint16_t TxData)
{
// uint8_t retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的 SPI 标志位设置与否:发送缓存空标志位
{
// retry++;
// if(retry>200)return 0;
}
SPI_I2S_SendData(SPI2, TxData); //通过外设 SPIx 发送一个数据
// retry=0;

    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
    {

// retry++;
// if(retry>200)return 0;
}
return SPI_I2S_ReceiveData(SPI2); //返回通过 SPIx 最近接收的数据
}
//向 SPI 总线传输一个 8 位数据
void SPI_WriteData(uint8_t Data)
{
SPI2_ReadWriteByte(Data);
}

//向液晶屏写一个 8 位指令
void Lcd_WriteIndex(uint8_t Index)
{
//SPI 写命令时序开始
LCD_CS_CLR;
LCD_DC_CLR;

    SPI_WriteData(Index);
    LCD_CS_SET;

}

//向液晶屏写一个 8 位数据
void Lcd_WriteData(uint8_t Data)
{
LCD_CS_CLR;
LCD_DC_SET;

    SPI_WriteData(Data);
    LCD_CS_SET;

}
//向液晶屏写一个 16 位数据
void LCD_WriteData_16Bit(uint16_t Data)
{
// LCD_CS_CLR;
// LCD_DC_SET;
SPI_WriteData(Data>>8); //写入高 8 位数据
SPI_WriteData(Data); //写入低 8 位数据
// LCD_CS_SET;
}

void Lcd_WriteReg(uint8_t Index,uint8_t Data)
{
Lcd_WriteIndex(Index);
Lcd_WriteData(Data);
}

void Lcd_Reset(void)
{
LCD_RST_CLR;//RST 引脚输出为低
delay_ms(100);
LCD_RST_SET;//RST 引脚输出为高
delay_ms(100);
}

/***********************************************************************/

void Lcd_Init(void)
{
LCD_Hal_Spi_Init();

    Lcd_Reset();
    /********************************************************/
    delay_ms(1000);
    Lcd_WriteIndex(ST7789_CMD_SLPOUT); 	//Sleep Out
    delay_ms(120);
    //-----------------------ST7789V Frame rate setting-----------------//
    //************************************************
    Lcd_WriteIndex(ST7789_CMD_COLMOD);       //65k mode
    Lcd_WriteData(0x05);

    Lcd_WriteIndex(ST7789_CMD_VCMOFSET); 	//VCOM
    Lcd_WriteData(0x1A);

    Lcd_WriteIndex(ST7789_CMD_MADCTL);       // 屏幕显示方向设置
    Lcd_WriteData(0x00);
    //-------------ST7789V Frame rate setting-----------//
    Lcd_WriteIndex(ST7789_CMD_PORCTRL);		//Porch Setting
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x00);
    Lcd_WriteData(0x33);
    Lcd_WriteData(0x33);

    Lcd_WriteIndex(ST7789_CMD_GCTRL);		//Gate Control
    Lcd_WriteData(0x05);			//12.2v   -10.43v
    //--------------ST7789V Power setting---------------//
    Lcd_WriteIndex(ST7789_CMD_VCOMS);//VCOM
    Lcd_WriteData(0x3F);

    Lcd_WriteIndex(ST7789_CMD_LCMCTRL); //Power control
    Lcd_WriteData(0x2c);

    Lcd_WriteIndex(ST7789_CMD_VDVVRHEN);	//VDV and VRH Command Enable
    Lcd_WriteData(0x01);

    Lcd_WriteIndex(ST7789_CMD_VRHS);		//VRH Set
    Lcd_WriteData(0x0F);		//4.3+( vcom+vcom offset+vdv)

    Lcd_WriteIndex(ST7789_CMD_VDVSET);		//VDV Set
    Lcd_WriteData(0x20);				//0v

    Lcd_WriteIndex(ST7789_CMD_FRCTR2);		//Frame Rate Control in Normal Mode
    Lcd_WriteData(0X01);			     //111Hz

    Lcd_WriteIndex(ST7789_CMD_PWCTRL1);		//Power Control 1
    Lcd_WriteData(0xa4);
    Lcd_WriteData(0xa1);

    Lcd_WriteIndex(ST7789_CMD_PWCTRL2);		//Power Control 1
    Lcd_WriteData(0x03);

    Lcd_WriteIndex(ST7789_CMD_EQCTRL);		//Equalize time control
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    //---------------ST7789V gamma setting-------------//
    Lcd_WriteIndex(ST7789_CMD_PVGAMCTRL); //Set Gamma
    Lcd_WriteData(0xD0);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x33);
    Lcd_WriteData(0x3F);
    Lcd_WriteData(0x07);
    Lcd_WriteData(0x13);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x30);

    Lcd_WriteIndex(ST7789_CMD_NVGAMCTRL); //Set Gamma
    Lcd_WriteData(0xD0);
    Lcd_WriteData(0x05);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x09);
    Lcd_WriteData(0x08);
    Lcd_WriteData(0x03);
    Lcd_WriteData(0x24);
    Lcd_WriteData(0x32);
    Lcd_WriteData(0x32);
    Lcd_WriteData(0x3B);
    Lcd_WriteData(0x14);
    Lcd_WriteData(0x13);
    Lcd_WriteData(0x28);
    Lcd_WriteData(0x2F);

    Lcd_WriteIndex(ST7789_CMD_INVON);		//反显

    Lcd_WriteIndex(ST7789_CMD_DISPON);		//开启显示

}

/*************************************************
函数名:LCD_Set_Region
功能:设置 lcd 显示区域,在此区域写点数据自动换行
入口参数:xy 起点和终点,Y_IncMode 表示先自增 y 再自增 x
返回值:无
*************************************************/
void Lcd_SetRegion(uint16_t x_start, uint16_t y_start, uint16_t x_end, uint16_t y_end)
{
Lcd_WriteIndex(0x2a);
Lcd_WriteData(0x00);
Lcd_WriteData(x_start);
Lcd_WriteData(0x00);
Lcd_WriteData(x_end);

    Lcd_WriteIndex(0x2b);
    Lcd_WriteData(0x00);
    Lcd_WriteData(y_start);
    Lcd_WriteData(y_end>>8);
    Lcd_WriteData(y_end);

    Lcd_WriteIndex(0x2c); //开始写入GRAM

}

void Lcd_Full(uint16_t color)
{
uint16_t row,column;

    Lcd_SetRegion(0, 0, ST7789_LCD_WIDTH, ST7789_LCD_HEIGHT);

    LCD_CS_CLR;
    LCD_DC_SET;
    for(row = 0;row < ST7789_LCD_WIDTH; row++)             //ROW loop
    {
    	for(column = 0;column < ST7789_LCD_HEIGHT; column++) //column loop
    	{
    		LCD_WriteData_16Bit(color); // 180ms 1 frame
    	}
    }
    LCD_CS_SET;

}

DMA+硬件 SPI 外设

https://i-blog.csdnimg.cn/blog_migrate/b4b23e047193caa36236facba6d18878.png

我使用的是 SPI2,所以对应的 DMA 信息如上表。

void DMA_Config(u32 TX_Buff,u32 SENDBUFF_SIZE)
{
// 中断结构体
NVIC_InitTypeDef NVIC_InitStructure;
// DMA 结构体
DMA_InitTypeDef DMA_InitStructure;
/_ 使能 DMA 时钟 _/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
/_ 复位初始化 DMA 数据流 _/  
 DMA_DeInit(DMA1_Stream4);
/_ 确保 DMA 数据流复位完成 _/  
 while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE);

    /* 配置 DMA Stream */
    /* 通道0,数据流4 */
    DMA_InitStructure.DMA_Channel = DMA_Channel_0;
    /* 外设地址 */
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&SPI2->DR;
    /* 内存地址(要传输的变量的指针) ,DMA存储器0地址*/
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)TX_Buff;
    /* 方向:存储器到外设 */
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    /* 数据传输量 ,可设置为0, 实际发送时会重新设置*/
    DMA_InitStructure.DMA_BufferSize = (uint32_t)SENDBUFF_SIZE;
    /* 外设非增量模式 */
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    /* 存储器增量模式 */
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    /* 外设数据长度:16位 */
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    /* 内存数据长度:16位 */
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    /* DMA模式:正常模式 */
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    /* 优先级:高 */
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    /* 禁用FIFO */
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
    /* 外设突发单次传输 */
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    /* 存储器突发单次传输 */
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    /* 初始化DMA Stream */
    DMA_Init(DMA1_Stream4, &DMA_InitStructure);
    /* 开启传输完成中断  */
    DMA_ITConfig(DMA1_Stream4,DMA_IT_TC,ENABLE);

    // 中断初始化 
    /* DMA发送中断源 */
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream4_IRQn;
    /* 抢断优先级 */
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    /* 响应优先级 */
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    /* 使能外部中断通道 */
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    /* 配置NVIC */
    NVIC_Init(&NVIC_InitStructure);

}
static uint8_t sendFlg = 0;

void DMA1_Stream4_IRQHandler(void)
{
// DMA 发送完成
if(DMA_GetITStatus(DMA1_Stream4, DMA_IT_TCIF4))
{
// 清除 DMA 发送完成标志
DMA_ClearITPendingBit(DMA1_Stream4, DMA_IT_TCIF4);
// 片选拉高,数据发送完毕 
LCD_CS_SET;
sendFlg = 1;
}
}

void DMA_Write_buf(uint32_t SizeLen)
{  
 // 关闭发送 DMA 
DMA_Cmd(DMA1_Stream4, DISABLE);
// 设置发送的数据量 
DMA_SetCurrDataCounter(DMA1_Stream4, SizeLen);
// 清空数据
SPI2->DR;
// 擦除 DMA 标志位 
DMA_ClearFlag(DMA1_Stream4, DMA_IT_TCIF4);
// 片选拉低,接收数据
LCD_CS_CLR;
LCD_DC_SET;
// 开启发送 DMA
DMA_Cmd(DMA1_Stream4, ENABLE);
while(!sendFlg);
sendFlg = 0;
}
#define SEND_BUF_SIZE 480*20

uint16_t SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区
// 单颜色填满屏幕
void Lcd_Dma_Full(uint16_t color)
{
int i = 0;
for(i = 0 ; i < SEND_BUF_SIZE; i++)
{
SendBuff[i] = color; // 缓存区不够,分段来凑
}
for(i = 0; i < 16; i++)
{
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE); // 60ms 1 frame
DMA_Write_buf(SEND_BUF_SIZE);
}
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组 2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为 115200

    LED_Init();					  //初始化LED

    Lcd_Init();

    Lcd_Full(RED);
    delay_ms(1000);

    uint16_t num = 0;

    while(1)
    {
    #if 1
    	//num+=1;
    	Lcd_Dma_Full(num++);

// LED_ON;
//delay_ms(10);
// 
// Lcd_Dma_Full(WHITE);
// LED_OFF;
 delay_ms(50);
// 
// Lcd_Dma_Full(BLUE);
// LED_ON;
 delay_ms(50);
// 
// Lcd_Dma_Full(WHITE);
// LED_OFF;
#else
Lcd_Full(GREEN);
LED_ON;
// delay_ms(50);
Lcd_Full(WHITE);
LED_OFF;
// delay_ms(50);
Lcd_Full(BLUE);
LED_ON;
// delay_ms(50);
Lcd_Full(WHITE);
LED_OFF;
#endif
// delay_ms(50);
// printf("Test \r\n");;
}
}

总结

分辨率:240*320

颜色:RGB565

方式一帧耗时帧率
GPIO 模拟 SPI220ms4.5 fps
硬件 SPI188ms5.3 fps
DMA+硬件 SPI60ms16.6 fps