文章目录
- GPIO模拟SPI
- 硬件SPI外设
- DMA+硬件SPI外设
- 总结
代码工程:https://github.com/liefyuan/stm32-spi-st7789-tft.git
前言
我的屏幕的分辨率是: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外设
我使用的是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模拟SPI | 220ms | 4.5 fps |
硬件SPI | 188ms | 5.3 fps |
DMA+硬件SPI | 60ms | 16.6 fps |