GD32F4提供了TFT-LCD接口,能为无源LCD显示屏提供像素数据,时钟以及时序信号。拥有一个内嵌的DMA不断的从系统存储器搬移数据到TLI然后输出到外部的LCD显示。本文接下来详细介绍基于GD32450Z芯片使用TFT-LCD接口实现AT070TN94液晶RGB-LCD的控制。
1、RGB-LCD基本知识介绍
RGB-LCD可以视为一个个像素点组成的,每个像素点相当于一个RGB 小灯,通过控制R、G、B 这三种颜色的亮度就可以显示出不同色彩。
(1) RGBLCD 的信号线
信号线 | 说明 |
---|---|
R[0:7] | 红色数据线 |
G[0:7] | 绿色数据线 |
B[0:7] | 蓝色数据线 |
DE | 数据使能线 |
VSYNC | 垂直同步信号线 |
HSYNC | 水平同步信号线 |
DCLK | 像素时钟信号线 |
其中R[7:0]、G[7:0]和B[7:0]这24 根是数据线,DE、VSYNC、HSYNC 和PCLK 这四根是控制信号线。
为了节省引脚,可以使用RGB565像素模式,忽略低位的颜色信号,如只使用R[7:3]、G[7:2]和B[7:3],其余未使用到的数据线置为低电平。
(2) RGBLCD 的驱动模式
RGB 屏一般有 2 种驱动模式: DE 模式和 HV 模式。
DE 模式使用 DE 信号来确定有效数据;而 HV 模式,则需要行同步和场同步,来表示扫描的行和列。这里选择采用DE模式驱动LCD,使用DE模式时,只需要DE和PCLK 这两根信号线,节省芯片引脚。
通过查询AT070TN94屏幕手册的针脚说明,第8号MODE针脚为DE/SYNC模式选择,即MODE置高电平,同时第10 (VS)、11 (HS)号针脚也要置为高电平。
2、RGB-LCD初始化设置
(1) 像素缓存
由于使用RGB565模式,每个像素占用2B数据,AT070TN94的屏幕分辨率为800×480,并且TLI支持两个独立的显示层,由此计算需要的内存空间为:2×800×480×2/1024=1500kb。这需要用到SDRAM,SDRAM的设置这里暂不做介绍。首先建立一个数组用来储存像素数据,其中 LCD_FRAME_BUF_ADDR 为储存的起始地址,这里设为 0xC0000000(具体看SDRAM的配置)
uint8_t blended_address_buffer[1600][480] __attribute__((at(LCD_FRAME_BUF_ADDR)));
同时我们定义两结构体,用于LCD初始化和层初始化配置。
tli_parameter_struct tli_init_struct;
tli_layer_parameter_struct tli_layer_init_struct;
(2) 时间参数配置
RGB-LCD时序图如上所示,图中有效显示区域,就是我们 RGBLCD 面板的显示范围。图中参数的说明如下表所示:
参数 | 说明 |
HSW(horizontal sync width) | 水平同步脉宽,单位为相素时钟( CLK)个数 |
VSW(vertical sync width) | 垂直同步脉宽,单位为行周期个数 |
HBP(horizontal back porch) | 水平后廊,表示水平同步信号开始到行有效数据开始之间的像素时钟(CLK)个数 |
HFP(horizontal front porch) | 水平前廊,表示行有效数据结束到下一个水平有效信号开始之前的像素时钟(CLK)个数 |
VBP(vertical back porch) | 垂直后廊,表示垂直同步信号后,无效行的个数 |
VFP(vertical front porch) | 垂直前廊,表示一帧数据输出结束后,到下一个垂直同步信号开始之前的无效个数 |
通过查询AT070TN94屏幕手册,其时间参数如下:
由此定义时间参数如下:
#define HORIZONTAL_SYNCHRONOUS_PULSE 1
#define HORIZONTAL_BACK_PORCH 46
#define ACTIVE_WIDTH 800
#define HORIZONTAL_FRONT_PORCH 210
#define VERTICAL_SYNCHRONOUS_PULSE 1
#define VERTICAL_BACK_PORCH 23
#define ACTIVE_HEIGHT 480
#define VERTICAL_FRONT_PORCH 22
(3) LCD初始化函数
1. RCU_TLI时钟开启
rcu_periph_clock_enable(RCU_TLI);
2. GPIO初始化配置
引脚的配置要根据原理图来配置,这里举例配置DE引脚,其他引脚配置方法也相同。
由原理图可知DE引脚所连接的是PF10,查看《GD32F450xx_Datasheet》的引脚复用表,可知TLI_DE为AF14。由此DE引脚的配置代码如下所示:
rcu_periph_clock_enable(RCU_GPIOF);
gpio_af_set(GPIOF, GPIO_AF_14, GPIO_PIN_10);
gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10);
gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_10);
3. 时钟源配置
由屏幕手册其时钟频率为33.3MHz,设置TFT-LCD的时钟源来自于25M高速外部时钟HXTAL经PSC 25分频,再经过PLLSAI_VOC倍频,再PLLSAI_R分频,最后DIV分频得到。即TLI时钟频率为 HXTAL / PSC × PLLSAI_VOC / PLLSAI_R / DIV。
TLI时钟源配置代码如下:
if(ERROR == rcu_pllsai_config(256, 2, 3)) //三个参数分别为:PLLSAI_VOC PLLSAI_Q PLLSAI_R
{while(1);}
rcu_tli_clock_div_config(RCU_PLLSAIR_DIV4);
rcu_osci_on(RCU_PLLSAI_CK);
if(ERROR == rcu_osci_stab_wait(RCU_PLLSAI_CK)){while(1);}
4. LCD初始化配置
tli_struct_para_init(&tli_init_struct);
tli_init_struct.signalpolarity_hs = TLI_DE_ACTLIVE_LOW; //水平同步极性,设置低电平或是高电平有效
tli_init_struct.signalpolarity_vs = TLI_DE_ACTLIVE_LOW; //垂直同步极性
tli_init_struct.signalpolarity_de = TLI_DE_ACTLIVE_LOW; //数据使能极性
tli_init_struct.signalpolarity_pixelck = TLI_PIXEL_CLOCK_TLI; //像素时钟极性
tli_init_struct.synpsz_hpsz = HORIZONTAL_SYNCHRONOUS_PULSE - 1; //水平同步宽度
tli_init_struct.synpsz_vpsz = VERTICAL_SYNCHRONOUS_PULSE - 1; //垂直同步宽度
tli_init_struct.backpsz_hbpsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH - 1; //水平同步后沿宽度
tli_init_struct.backpsz_vbpsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH - 1; //垂直同步后沿高度
tli_init_struct.activesz_hasz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH - 1; //有效宽度
tli_init_struct.activesz_vasz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT - 1; //有效高度
tli_init_struct.totalsz_htsz = HORIZONTAL_SYNCHRONOUS_PULSE + HORIZONTAL_BACK_PORCH + ACTIVE_WIDTH + HORIZONTAL_FRONT_PORCH - 1; //总宽度
tli_init_struct.totalsz_vtsz = VERTICAL_SYNCHRONOUS_PULSE + VERTICAL_BACK_PORCH + ACTIVE_HEIGHT + VERTICAL_FRONT_PORCH - 1; //总高度
tli_init_struct.backcolor_red = 0x00; //屏幕背景层红色部分 设为黑色
tli_init_struct.backcolor_green = 0x00; //屏幕背景层绿色部分
tli_init_struct.backcolor_blue = 0x00; //屏幕背景色蓝色部分
tli_init(&tli_init_struct);
5. 层初始化配置
tli_layer_struct_para_init(&tli_layer_init_struct);
tli_layer_init_struct.layer_window_leftpos = 00+0+lcdltdc.hsw + lcdltdc.hbp;
tli_layer_init_struct.layer_window_rightpos = 800+0+lcdltdc.hsw + lcdltdc.hbp - 1;
tli_layer_init_struct.layer_window_toppos = 00+0 + lcdltdc.vsw + lcdltdc.vbp;
tli_layer_init_struct.layer_window_bottompos = (480 +0 + lcdltdc.vsw + lcdltdc.vbp - 1);
tli_layer_init_struct.layer_ppf = 0x02; //TLI_LxPPF PPF[2:0] 010:RGB565
tli_layer_init_struct.layer_sa = 0xFF; //层透明度 255为完全不透明
tli_layer_init_struct.layer_acf1 = LAYER_ACF1_PASA; //层混合模式 归一化的像素 Alpha 乘以归一化的恒定 Alpha
tli_layer_init_struct.layer_acf2 = LAYER_ACF2_PASA; //111:归一化的像素 Alpha 乘以归一化的恒定 Alpha
tli_layer_init_struct.layer_default_alpha = 0xFF; //该层显示范围外的颜色
tli_layer_init_struct.layer_default_blue = 0xFF;
tli_layer_init_struct.layer_default_green = 0xFF;
tli_layer_init_struct.layer_default_red = 0xff;
tli_layer_init_struct.layer_frame_bufaddr = 0xC0000000; //缓存地址
tli_layer_init_struct.layer_frame_line_length = (800*2+3); //行长度 这个值为一行的字节数+3
tli_layer_init_struct.layer_frame_buf_stride_offset =(800*2); //步幅偏移 定义了从某行起始处到下一行起始处之间的字节数
tli_layer_init_struct.layer_frame_total_line_number = 480; //总行数 定义了一帧行数
tli_layer_init(LAYER0, &tli_layer_init_struct); // LAYER0初始化
3、点亮屏幕
tli_layer_enable(LAYER0); //使能层1
tli_reload_config(TLI_FRAME_BLANK_RELOAD_EN);
tli_enable(); //使能TLI
此时向SDRAM中的TLI缓存输入像素数据,LCD屏会相应的显示出。