目录
1.TFT与LCD
TFT屏(ThinFilmTransistor)是薄膜晶体管型液晶显示屏,它的每一个象素点都是由集成在其后的薄膜晶体管即TFT来驱动的,这样不仅提高了显示屏的响应速度,同时可以精确控制显示色阶,所以TFT液晶的色彩更逼真。LCD表示液态晶体显示,也就是常说的液晶屏。TFT-LCD就是指用TFT(薄膜晶体管)控制液晶像素的液晶屏,它是众多LCD中最常用的一类。除了TFT常见的LCD还有,TN、IPS、VA等。LCD 液晶屏是 Liquid Crystal Display 的简称,LCD 的构造是在两片平行的玻璃当中放置液态的晶体,按照晶体类型的不同进行了划分。
2.TFT与VGA
TFT说的是液晶屏晶体的材质,VGA是屏幕的显示接口。该TFT与控制器的接口是RGB接口,RGB接口和VGA是并列的接口,除此之外,还有HDMI、DP、DVI等显示接口,这都是在显示屏上的接口,通常是控制器通过这些接口与显示器相连进行数据的传输与控制以达到显示的目的。在视频领域还有另外一些接口与显示接口做区分,如DVP接口、LVDS接口、Mipi接口,这些接口是接在图像传感器上的,称之为采集接口,通常是控制器通过这类接口与图像传感器相连,然后获取视频流数据并进行处理和转发。
TFT采用的RGB接口和VGA(Video Graphics Array)接口的时序几乎是一样的,二者最主要的区别在于RGB接口是数字信号,而VGA连接线走的是模拟信号,而在FPGA使用VGA场景中,通常可以使用RGB接口的驱动对其时序参数做修改,在FPGA与VGA接口之间加一个数模转换的芯片即可(例如 ADV7123)。另外一个区别是,VGA接口的时序参数是由制定VGA接口标准的协会协定好的,而TFT的时序参数是由屏幕厂家提供的。
早期,显示领域CRT领域蓬勃发展,家家电视机后面有个大脑袋,俗称叫做显像管,色彩是由 RGB 三基色组成。其原理就是一个电子枪在“Z”字形扫描,即用逐行扫描的方式解决。阴极射线枪发出的电子束打在涂有荧光粉的荧光屏上,产生 RGB 三基色,合成一个彩色像素,扫描从屏幕的左上方开始,从左到右,从上到下进行扫描,每扫完一行,电子束都回到屏幕的下一行左边的起始位置。在这期间,CRT 对电子束进行消隐。每行结束时,用行同步信号进行行同步;扫描完所有行,用场同步信号进行场同步,并使扫描回到屏幕的左上方。同时进行场消隐,预备下一场的扫描。这项技术很大程度影响了VGA接口的时序。随着显示技术的发展,出现了液晶显示器,液晶显示器的成像原理与 CRT 不同,并且液晶技术晚于 CRT 显示技术诞生,为了能够兼容传统的显示接口,液晶显示器通过内部电路实现了对 VGA 接口的完全兼容。因此,在使用显示器时,只要该显示器带有标准的 VGA 接口,就不用去关注其成像原理,直接使用标准的 VGA 时序即可驱动。RGB 接口的 TFT 屏,扫描方式与 VGA 完全一致。
3.屏幕组成
屏幕是由厂家提供的TFT显示模组和屏幕PCB背板组成。PCB的作用是提供LCD背光所需的电压、用于屏幕显示的电压、与其他设备相连的排针或者其他连接器形式。当模组支持触摸功能时还可以接上触摸转换或触摸控制芯片,通过SPI等方式向控制端提供触摸信息。
4.接口与时序
如下图所示,不同分辨率下不同的帧率厂家会提供不同的时序参数,时序参数是指下图中各个部分的时长,结合TFT像素时钟即可计算处时钟个数。HSYNC称为行同步信号,按照下图所示,适时拉低拉高即可,VSYNC称为场同步信号,当且仅当二者都处于有效数据段的时候,需要控制器提供有效数据,区域显示图像,另外De信号即为数据有效信号应该拉高,即在显示有效区域,打开该信号以使能信号输入,在非有效区域,关闭该信号以禁止像素数据输入(需为0),以免影响到消隐。初学者应该注意,xcnt每一个时钟周期计数一次就像电子枪按照固定频率扫描一样,ycnt是xcnt计数一行之后加1。其他信号还有像素时钟信号PCLK和数据信号Data。
5.工程源码与效果
该工程可以用来显示彩条但并没有实际意义,因此在写程序时将接口留好一边将程序轻松移植到大项目里。Ctrl模块将产生数据显示的条件,即管理屏幕是否工作,工程中通过板卡按键控制屏幕显示与否;driver模块接受来自ctrl模块的命令指示,产生各驱动信号。工程中数据是模拟的彩条数据在ctrl模块中,在实际应用时可来自于一个单独的模块。其代码和运行效果如下:
源码tft_driver模块:
module tft_driver(
input clk_33,
input rst_n,
input start_en,
input [15:0]user_data,
output data_req,
output [11:0]addr_x,
output [11:0]addr_y,
output[15:0]tft_data,
output tft_hs,
output tft_vs,
output tft_clk,
output tft_de,//背光使能信号
output tft_pwm
);
parameter H_Total_Time = 12'd1056;
parameter H_Right_Border = 12'd0;
parameter H_Front_Porch = 12'd40;
parameter H_Sync_Time = 12'd128;
parameter H_Back_Porch = 12'd88;
parameter H_Left_Border = 12'd0;
parameter V_Total_Time = 12'd525;
parameter V_Bottom_Border= 12'd8;
parameter V_Front_Porch = 12'd2;
parameter V_Sync_Time = 12'd2;
parameter V_Back_Porch = 12'd25;
parameter V_Top_Border = 12'd8;
reg [11:0] h_cnt;//行计数
reg [11:0] v_cnt;//场计数
wire h_pulse;
reg start_show;
/***********RGB 接口时序输出****************/
assign tft_hs = (h_cnt >= H_Sync_Time);//行场同步在数据无效的时候也可能有效
assign tft_vs = (v_cnt >= V_Sync_Time);
assign tft_data = tft_de ? user_data : 16'd0;
//数据有效区域,使能背光并且使能计数器
assign tft_de = (h_cnt >= H_Sync_Time + H_Back_Porch + H_Left_Border -1)&&
(h_cnt < H_Total_Time- H_Right_Border - H_Front_Porch-1)&&
(v_cnt >= V_Sync_Time + V_Back_Porch + V_Top_Border -1)&&
(v_cnt < V_Total_Time - V_Bottom_Border - V_Front_Porch-1);
assign data_req = tft_de;
assign tft_clk = clk_33;//这是刷新率和屏幕参数决定的
assign tft_pwm = 1'b1;
//按钮控制是否显示
always@(posedge clk_33 or negedge rst_n)
if(!rst_n)
start_show <= 0;
else if(start_en)
start_show <= ~start_show;
//行同步计数
always@(posedge clk_33 or negedge rst_n)
if(!rst_n)
h_cnt <= 0;
else if(start_show)begin
if(h_pulse)
h_cnt <= 0;
else
h_cnt <= h_cnt+1;
end else
h_cnt <= 0;
assign h_pulse = (h_cnt >= H_Total_Time-1);//计一行产生一个脉冲 用于刷新行计数器和场计数器
//场同步计数
always@(posedge clk_33 or negedge rst_n)
if(!rst_n)
v_cnt <= 0;
else if(start_show)begin
if(h_pulse)begin
if(v_cnt == V_Total_Time - 1)
v_cnt <= 0;
else
v_cnt <= v_cnt+1;
end else
v_cnt <= v_cnt;
end else
v_cnt <= 0;
//x坐标返回
assign addr_x = tft_de?(h_cnt - H_Sync_Time - H_Back_Porch - H_Left_Border +1):12'd0;;
//y坐标返回
assign addr_y = tft_de?(v_cnt - V_Sync_Time - V_Back_Porch - V_Top_Border +1):12'b0;
ila_0 your_instance_name (
.clk(clk_33), // input wire clk
.probe0({tft_de,start_show,start_en,tft_hs,tft_vs,tft_clk,tft_pwm}), // input wire [7:0] probe0
.probe1(tft_data), // input wire [15:0] probe1
.probe2(addr_x), // input wire [11:0] probe2
.probe3(h_cnt) // input wire [11:0] probe3
);
endmodule
源码tft_ctrl模块:
module tft_ctrl(
input clk_33,
input rst_n,
input key,
input [11:0]x_addr,
input [11:0]y_addr,
input data_req,
output reg [15:0]pix_data,
output start_en
);
//控制显示屏显示与否
reg touch_key_d0;
reg touch_key_d1;
//对arp_tx_en信号延时打拍两次,用于采touch_key的下降
always @(posedge clk_33 or negedge rst_n) begin
if(!rst_n) begin
touch_key_d0 <= 1'b0;
touch_key_d1 <= 1'b0;
end else begin
touch_key_d0 <= key;
touch_key_d1 <= touch_key_d0;
end
end
assign start_en = ~touch_key_d1 & touch_key_d0;//key信号下降沿
//提供显示数据
wire s_1;//指示四块区域
wire s_2;
wire s_3;
wire s_4;
wire [3:0]s_list;
localparam
BLACK = 16'h0000, //黑色
BLUE = 16'h001F, //蓝色
RED = 16'hF800, //红色
PURPPLE = 16'hF81F; //紫色
assign s_1 = data_req && x_addr >= 0 && x_addr < 200; //正在扫描第1列条纹;
assign s_2 = data_req && x_addr >= 200 && x_addr < 400;//正在扫描第2列条纹;
assign s_3 = data_req && x_addr >= 400 && x_addr < 600;//正在扫描第3列条纹;
assign s_4 = data_req && x_addr >= 600 && x_addr < 800;//正在扫描第4列条纹;
assign s_list = {s_1,s_2,s_3,s_4};
always @(*) begin
case (s_list)
4'b0001: pix_data = BLACK;
4'b0010: pix_data = BLUE;
4'b0100: pix_data = RED;
4'b1000: pix_data = PURPPLE;
default: pix_data = BLACK;
endcase
end
endmodule
6.传送门
●我的主页
●下一篇:图像显示(2)VGA接口
END
🔈文章原创,首发于CSDN论坛。
🔈欢迎点赞❤❤收藏⭐⭐打赏💴💴!
🔈欢迎评论区或私信指出错误❌,提出宝贵意见或疑问❓。