一、硬件初始化
本次例程使用的外设是SPI0, DMA1-CH5,IO口使用情况如下:
IO | 定义 |
---|---|
PA5 | SPI0-SCK 时钟 |
PA7 | SPI0-MOSI SPI发送 |
PB10 | LCD-RES 复位,低电平使能 |
PB11 | LCD-DC 数据/命令选择,低电平命令,高电平数据 |
PB12 | LCD-CS 片选,低电平使能 |
PB13 | LCD-BK 背光,悬空/高电平使能, 接地关闭 |
代码如下:
GPIO初始化
static void GPIO_Config(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
/* configure SPI0 GPIO */
gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_7);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_7);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
/* set BackUp RES CS DC as GPIO*/
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_14 | GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_12);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14 | GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_12);
gpio_bit_set(GPIOB,GPIO_PIN_12);
}
DMA配置初始化
static void DMA_Config(void)
{
rcu_periph_clock_enable(RCU_DMA1);
dma_single_data_parameter_struct dma_init_struct;
/* configure SPI0 transmit DMA */
dma_deinit(DMA1, DMA_CH5);
dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI0);
dma_init_struct.memory0_addr = (uint32_t)spi0_send_array; // 自己定义一个数组,用来储存发往LCD的数据
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_init_struct.number = LCD_BUFFER_SIZE;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_single_data_mode_init(DMA1, DMA_CH5, &dma_init_struct);
dma_channel_subperipheral_select(DMA1, DMA_CH5, DMA_SUBPERI3);
}
SPI外设配置初始化
static void SPI_Config(void)
{
rcu_periph_clock_enable(RCU_SPI0);
spi_parameter_struct spi_init_struct;
/* configure SPI0 parameter */
spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_HARD;
spi_init_struct.prescale = SPI_PSC_2;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI0, &spi_init_struct);
spi_enable(SPI0);
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
}
调用这个函数初始化GPIO,SPI和DMA
void SPI_Init(void)
{
GPIO_Config();
DMA_Config();
SPI_Config();
}
注意事项
有以下几点配置时需要注意下,
这里对应以下这段代码,DMA_SUBPERI3 对应表格左侧的通道3,截自GD32F4xx 用户手册 v3.0
dma_channel_subperipheral_select(DMA1, DMA_CH5, DMA_SUBPERI3);
IO的复用设置,对应上图,截自GD32F407xx 数据手册 v2.8
gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_7);
二、屏幕初始化
屏幕使用的是 “1.44寸TFT彩屏 不焊针” 这一项,购买链接如下
TFT-LCD 1.44寸 ST7735 淘宝链接
使用时还要注意连接屏幕的杜邦线不要太长,否则对SPI信号有影响导致通信不稳定。
屏幕复位
这里移植了RT-Thread,使用的是系统延时
void ST7735_Reset(void)
{
LCD_RES_L;
rt_thread_mdelay(150);
LCD_RES_H;
rt_thread_mdelay(150);
}
向屏幕发送数据
void st7735_dma_write(uint8_t *data,uint16_t len)
{
dma_flag_clear(DMA1, DMA_CH5, DMA_FLAG_FTF);
dma_channel_disable(DMA1, DMA_CH5);
dma_memory_address_config(DMA1, DMA_CH5,DMA_MEMORY_0,(rt_uint32_t)data);
dma_transfer_number_config(DMA1, DMA_CH5,len);
dma_channel_enable(DMA1, DMA_CH5);
while(dma_flag_get(DMA1, DMA_CH5, DMA_FLAG_FTF) == RESET) {}
}
void st7735_write(uint8_t data)
{
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE)) {}
spi_i2s_data_transmit(SPI0, data);
while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE)) {}
spi_i2s_data_receive(SPI0);
}
void Lcd_WriteIndex(uint8_t cmd)
{
LCD_DC_L;
LCD_CS_L;
st7735_write(cmd);
LCD_CS_H;
}
void Lcd_WriteData(uint8_t data)
{
LCD_DC_H;
LCD_CS_L;
st7735_write(data);
LCD_CS_H;
}
uint8_t LCD_DMA_WriteData_16Bit(uint8_t *data,uint16_t len)
{
LCD_DC_H;
LCD_CS_L;
st7735_dma_write(data,len);
LCD_CS_H;
}
屏幕初始化
void ST7735_Init(void)
{
//Reset before LCD Init.
ST7735_Reset();
//LCD Init For 1.44Inch LCD Panel with ST7735R.
Lcd_WriteIndex(0x11);//Sleep exit
rt_thread_mdelay(120);
//ST7735R Frame Rate
Lcd_WriteIndex(0xB1);
Lcd_WriteData(0x01);
Lcd_WriteData(0x2C);
Lcd_WriteData(0x2D);
Lcd_WriteIndex(0xB2);
Lcd_WriteData(0x01);
Lcd_WriteData(0x2C);
Lcd_WriteData(0x2D);
Lcd_WriteIndex(0xB3);
Lcd_WriteData(0x01);
Lcd_WriteData(0x2C);
Lcd_WriteData(0x2D);
Lcd_WriteData(0x01);
Lcd_WriteData(0x2C);
Lcd_WriteData(0x2D);
Lcd_WriteIndex(0xB4); //Column inversion
Lcd_WriteData(0x07);
//ST7735R Power Sequence
Lcd_WriteIndex(0xC0);
Lcd_WriteData(0xA2);
Lcd_WriteData(0x02);
Lcd_WriteData(0x84);
Lcd_WriteIndex(0xC1);
Lcd_WriteData(0xC5);
Lcd_WriteIndex(0xC2);
Lcd_WriteData(0x0A);
Lcd_WriteData(0x00);
Lcd_WriteIndex(0xC3);
Lcd_WriteData(0x8A);
Lcd_WriteData(0x2A);
Lcd_WriteIndex(0xC4);
Lcd_WriteData(0x8A);
Lcd_WriteData(0xEE);
Lcd_WriteIndex(0xC5); //VCOM
Lcd_WriteData(0x0E);
Lcd_WriteIndex(0x36); //MX, MY, RGB mode
Lcd_WriteData(0xC8);
//ST7735R Gamma Sequence
Lcd_WriteIndex(0xe0);
Lcd_WriteData(0x0f);
Lcd_WriteData(0x1a);
Lcd_WriteData(0x0f);
Lcd_WriteData(0x18);
Lcd_WriteData(0x2f);
Lcd_WriteData(0x28);
Lcd_WriteData(0x20);
Lcd_WriteData(0x22);
Lcd_WriteData(0x1f);
Lcd_WriteData(0x1b);
Lcd_WriteData(0x23);
Lcd_WriteData(0x37);
Lcd_WriteData(0x00);
Lcd_WriteData(0x07);
Lcd_WriteData(0x02);
Lcd_WriteData(0x10);
Lcd_WriteIndex(0xe1);
Lcd_WriteData(0x0f);
Lcd_WriteData(0x1b);
Lcd_WriteData(0x0f);
Lcd_WriteData(0x17);
Lcd_WriteData(0x33);
Lcd_WriteData(0x2c);
Lcd_WriteData(0x29);
Lcd_WriteData(0x2e);
Lcd_WriteData(0x30);
Lcd_WriteData(0x30);
Lcd_WriteData(0x39);
Lcd_WriteData(0x3f);
Lcd_WriteData(0x00);
Lcd_WriteData(0x07);
Lcd_WriteData(0x03);
Lcd_WriteData(0x10);
Lcd_WriteIndex(0x2a);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x7f);
Lcd_WriteIndex(0x2b);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x9f);
Lcd_WriteIndex(0xF0); //Enable test command
Lcd_WriteData(0x01);
Lcd_WriteIndex(0xF6); //Disable ram power save mode
Lcd_WriteData(0x00);
Lcd_WriteIndex(0x3A); //65k mode
Lcd_WriteData(0x05);
Lcd_WriteIndex(0x29);//Display on
LCD_BK_H;
}
显示函数
// 设置lcd显示区域,在此区域写点数据自动换行
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+2);
Lcd_WriteData(0x00);
Lcd_WriteData(x_end+2);
Lcd_WriteIndex(0x2b);
Lcd_WriteData(0x00);
Lcd_WriteData(y_start+3);
Lcd_WriteData(0x00);
Lcd_WriteData(y_end+3);
Lcd_WriteIndex(0x2c);
}
// 设置lcd显示起始点
void Lcd_SetXY(uint16_t x,uint16_t y)
{
Lcd_SetRegion(x,y,x,y);
}
// 画一个点
void Gui_DrawPoint(uint16_t x,uint16_t y,uint16_t Data)
{
uint8_t data[2];
data[0] = Data>>8;
data[1] = Data&0xFF;
Lcd_SetRegion(x,y,x + 1,y + 1);
LCD_DMA_WriteData_16Bit(data,2);
}
// 全屏清屏函数,填充颜色Color
void Lcd_Clear(uint16_t Color)
{
unsigned int i,m;
Lcd_SetRegion(0,0,ST7735_WIDTH - 1,ST7735_HEIGHT - 1);
Lcd_WriteIndex(0x2C);
for(i = 0;i < LCD_BUFFER_SIZE;i = i + 2)
{
spi0_send_array[i] = Color>>8;
spi0_send_array[i+1] = Color&0xFF;
}
LCD_DMA_WriteData_16Bit(spi0_send_array,LCD_BUFFER_SIZE);
}
参数定义
// 屏幕参数定义
#define ST7735_WIDTH 128
#define ST7735_HEIGHT 128
#define LCD_BUFFER_SIZE (ST7735_WIDTH * ST7735_HEIGHT * 2) // RGB565格式
// 颜色宏定义
#define ST7735_BLACK 0x0000
#define ST7735_BLUE 0x001F
#define ST7735_RED 0xF800
#define ST7735_GREEN 0x07E0
#define ST7735_CYAN 0x07FF
#define ST7735_MAGENTA 0xF81F
#define ST7735_YELLOW 0xFFE0
#define ST7735_WHITE 0xFFFF
#define SPI0_SCK_PIN GPIO_PIN_5 // SPI时钟线
#define SPI0_MOSI_PIN GPIO_PIN_7 // SPI发送
#define LCD_RES_PIN GPIO_PIN_10 // 复位,低电平使能
#define LCD_DC_PIN GPIO_PIN_11 // 数据/命令选择,低电平命令,高电平数据
#define LCD_CS_PIN GPIO_PIN_12 // 片选,低电平使能
#define LCD_BK_PIN GPIO_PIN_14 // 背光,悬空使能, 接地关闭,默认上拉至3.3V
#define LCD_PORT GPIOB
#define SPI0_PORT GPIOA
// GPIO输出高低电平宏定义
#define SPI_SCK_H gpio_bit_set(SPI0_PORT,SPI0_SCK_PIN)
#define SPI_SCK_L gpio_bit_reset(SPI0_PORT,SPI0_SCK_PIN)
#define SPI_SDA_H gpio_bit_set(SPI0_PORT,SPI0_MOSI_PIN)
#define SPI_SDA_L gpio_bit_reset(SPI0_PORT,SPI0_MOSI_PIN)
#define LCD_RES_H gpio_bit_set(LCD_PORT,LCD_RES_PIN)
#define LCD_RES_L gpio_bit_reset(LCD_PORT,LCD_RES_PIN)
#define LCD_RES_H gpio_bit_set(LCD_PORT,LCD_RES_PIN)
#define LCD_RES_L gpio_bit_reset(LCD_PORT,LCD_RES_PIN)
#define LCD_CS_H gpio_bit_set(LCD_PORT,LCD_CS_PIN)
#define LCD_CS_L gpio_bit_reset(LCD_PORT,LCD_CS_PIN)
#define LCD_DC_H gpio_bit_set(LCD_PORT,LCD_DC_PIN)
#define LCD_DC_L gpio_bit_reset(LCD_PORT,LCD_DC_PIN)
#define LCD_BK_H gpio_bit_set(LCD_PORT,LCD_BK_PIN)
#define LCD_BK_L gpio_bit_reset(LCD_PORT,LCD_BK_PIN)
总结
本文介绍了GD32F407VET6单片机基于rt-thread nano如何驱动TFT-LCD屏幕 ST7735,GD32和STM32使用SPI时还是有不小的差别,希望这篇文章能给大家带来帮助,需要代码也可以留言。