[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-22 TPG图像测试数据发生器设计
软件版本:Anlogic -TD5.9.1-DR1_ES1.1
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板
板卡获取平台:https://milianke.tmall.com/
登录"米联客"FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述
TPG(video_test_pattern generator) 视频测试模式发生器用于产生测试数据,对视频数据通路测试。本课设计一个图像数据发生器,该模块能够产生不同颜色和样式的图像数据,并按顺序将RGB图像数据发送到有效显示区域。
1.1 RGB像素格式
RGB是一种颜色标准,俗称三基色模式,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,是运用最广的颜色系统之一。像素点就相当于一个RGB灯,通过控制R、G、B 这三种颜色的亮度就可以显示出各种各样的色彩。在显示器发明之后,从黑白显示器发展到彩色显示器,人们开始使用发出不同颜色的光的荧光粉(CRT,等离子体显示器),或者不同颜色的滤色片(LCD),或者不同颜色的半导体发光器件(OLED和LED大型全彩显示牌)来形成色彩,不管采用何种技术,都以红(R)、绿(G)、蓝(B)三个颜色作为基本的发光单元,通过控制光强度,组合出了人类视力所能感知的所有颜色。
常见RGB像素格式:
1、索引格式:
索引格式是比较老的格式,随着越来越高的视觉需求,索引格式基本不再被使用了,这里只做简单介绍。索引格式中bit存储的值并非是实际的R、G、B值,而是对应点的像素在调色板中的索引,即在图像文件中划出一个区域存放一个调色板来存储图像中的每一种颜色,这个像素的颜色对应到调色板的第几号颜色。
RGB1:每个像素用1个bit表示,能够表示的索引范围是0-1,共2种颜色,即调色板中包含2中颜色。
RGB4:每个像素用4个bit表示,能够表示的索引范围是0-15,共16种颜色,即调色板中包含16中颜色。
RGB8:每个像素用8个bit表示,能够表示的索引范围是0-255,共256种颜色,即调色板中包含256中颜色。
2、像素格式:
RGB像素格式不同于索引格式,索引格式bit存储的是每一个像素的色彩索引,而像素格式中的bit用来存储像素点中R、G、B三个颜色的值。
RGB888:也叫RGB24,一个像素点由3个字节组成,共8bit*3=24bit。其中bit23~bit16是RED 通道,红色对应的值就是24'hFF0000;bit15~bit8 是GREEN 通道,绿色对应的值就是24'h00FF00;bit7~bit0 是BLUE通道,蓝色对应的值为 24'h0000FF,使用RGB888格式,理论上可以产生1670万种色彩。RGB888像素格式如下图所示:
RGB888 数据格式
RGB565:只需要两个字节,可以降低成本,RGB分量分别使用5bit、6bit、5bit,但在色彩鲜艳度上较差一些。
RGB555:只需要两个字节,RGB分量都使用5bit(最高位不用)。
RGB1555:只需要两个字节,RGB分量都使用5bit,1bit用于表示透明度(0完全透明,1完全不透明)。
我们可以通过电脑的"画图"工具,使用调色板即可获取到想要的颜色对应的数值。
2 程序设计
2.1系统框图
本次实验通过测试视频发生器模块,产生测试图形,即彩条、渐变、纯色、棋方格,将相应测试图形的RGB数据依次放入有效的显示区域内。实验包含3个模块, VTC视频时序控制器模块、TPG视频测试模式发生器模块、用户控制模块。以下给出系统框图,关于VTC视频时序控制器驱动的详细描述请看前面的实验,我们主要学习TPG视频测试模式发生器驱动。
TPG视频测试模式发生器:
视频数据的有效区域如下图所示:视频数据在H_AcitiveSize和V_AcitiveSize同时有效时候有效
I_tpg_ck:视频格式的像素时钟
I_tpg_vs:视频格式的场同步信号
I_tpg_hs:视频格式的行同步信号
I_tpg_de:视频格式的有效数据阶段
O_tpg_vs:同I_tpg_vs
O_tpg_hs:同I_tpg_hs
O_tpg_de:同I_tpg_de
O_tpg_data:rgb格式数据输出
计数器模块:
h_cnt计数器模块:I_tpg_de为高电平时,表示有效显示区域阶段,此时h_cnt列计数器开始计数,计数为H_ActiveSize的值。
v_cnt计数器模块:I_tpg_vs拉高表示一帧有效图像数据传输完成,v_cnt置0,否则,I_tpg_hs拉高表示传输完一行有效数据,v_cnt加1。
1 //h_cnt计数器模块 2 always @(posedge I_tpg_clk) 3 h_cnt <= I_tpg_de ? h_cnt + 1'b1 : 12'd0; //计数行有效像素,当de无效,重置 h_cnt=0 4 5 //v_cnt计数器模块 6 always @(posedge I_tpg_clk) 7 if(I_tpg_vs) //通过vs产生同步复位 8 v_cnt <= 12'd0; //重置v_cnt=0 9 else 10 v_cnt <= ((!tpg_hs_r)&&I_tpg_hs) ? v_cnt + 1'b1 : v_cnt; //hs信号的上升沿,v_cnt计数,这种方式可以不管hs有效是高电平还是低电平的情况,v_cnt 视频垂直方向,行计数器,计数行数量
测试图像产生模块:
使用状态机将我们要显示的所有样式的图形数据列举出来,通过不断累加的dis_mode,为了减慢显示变换图形样式的速度,取dis_mode高位值进行判断该显示何种图形。
黑白格:h_cnt[4]和v_cnt[4]进行"异或"运算,即相同为0,不同为1,再进行条件判断,0显示全黑,1显示全白。
RGB彩条:使用列计数器h_cnt,将有效显示区域划分为9块,分别显示不同的RGB数据。
1 //显示模式切换 2 always @(posedge I_tpg_clk) 3 if(I_tpg_rstn==1'b0) 4 dis_mode <= 0; 5 else 6 dis_mode <= ((!tpg_vs_r)&&I_tpg_vs) ? dis_mode + 1'b1 : dis_mode; 7 8 //grid_data发生器 9 always @(posedge I_tpg_clk)begin 10 grid_data <= ((v_cnt[4]==1'b1) ^ (h_cnt[4]==1'b1)) ? 8'h00 : 8'hff; //方格大小16*16,黑白交替 11 end 12 13 //RGB彩条发生器 14 always @(posedge I_tpg_clk) 15 begin 16 if(h_cnt==260) 17 color_bar <= 24'hff0000;//红 18 else if(h_cnt==420) 19 color_bar <= 24'h00ff00;//绿 20 else if(h_cnt==580) 21 color_bar <= 24'h0000ff;//蓝 22 else if(h_cnt==740) 23 color_bar <= 24'hff00ff;//紫 24 else if(h_cnt==900) 25 color_bar <= 24'hffff00;//黄 26 else if(h_cnt==1060) 27 color_bar <= 24'h00ffff;//青蓝 28 else if(h_cnt==1220) 29 color_bar <= 24'hffffff;//白 30 else if(h_cnt==1380) 31 color_bar <= 24'h000000;//黑 32 else 33 color_bar <= color_bar; 34 end 35 36 //测试图形输出 37 always @(posedge I_tpg_clk)begin 38 case(dis_mode[10:7])//截取高位,控制切换显示速度 39 4'd0:begin 40 r_reg <= 0; 41 b_reg <= 0; 42 g_reg <= 0; 43 end 44 4'd1:begin 45 r_reg <= 8'b11111111; //白 46 g_reg <= 8'b11111111; 47 b_reg <= 8'b11111111; 48 end 49 4'd2,4'd3:begin//连续两个状态输出相同图形 50 r_reg <= 8'b11111111; //红 51 g_reg <= 0; 52 b_reg <= 0; 53 end 54 4'd4,4'd5:begin//连续两个状态输出相同图形 55 r_reg <= 0; //绿 56 g_reg <= 8'b11111111; 57 b_reg <= 0; 58 end 59 4'd6:begin 60 r_reg <= 0; //蓝 61 g_reg <= 0; 62 b_reg <= 8'b11111111; 63 end 64 4'd7,4'd8:begin //连续两个状态输出相同图形 65 r_reg <= grid_data; //方格 66 g_reg <= grid_data; 67 b_reg <= grid_data; 68 end 69 4'd9:begin 70 r_reg <= h_cnt[7:0]; //水平渐变 71 g_reg <= h_cnt[7:0]; 72 b_reg <= h_cnt[7:0]; 73 end 74 4'd10,4'd11:begin //连续两个状态输出相同图形 75 r_reg <= v_cnt[7:0]; //垂直渐变 76 g_reg <= v_cnt[7:0]; 77 b_reg <= v_cnt[7:0]; 78 end 79 4'd12:begin 80 r_reg <= v_cnt[7:0]; //红垂直渐变 81 g_reg <= 0; 82 b_reg <= 0; 83 end 84 4'd13:begin 85 r_reg <= 0; //绿垂直渐变 86 g_reg <= h_cnt[7:0]; 87 b_reg <= 0; 88 end 89 4'd14:begin 90 r_reg <= 0; //蓝垂直渐变 91 g_reg <= 0; 92 b_reg <= h_cnt[7:0]; 93 end 94 4'd15:begin 95 r_reg <= color_bar[23:16]; //彩条 96 g_reg <= color_bar[15:8]; 97 b_reg <= color_bar[7:0]; 98 end 99 endcase 100 end
2.2 TPG源码
1 `timescale 1ns / 1ns//仿真时间刻度/精度 2 3 module uitpg 4 ( 5 input I_tpg_clk, //系统时钟 6 input I_tpg_rstn,//系统复位 7 input I_tpg_vs, //场同步输入 8 input I_tpg_hs, //行同步输入 9 input I_tpg_de, //视频数据有效输入 10 output O_tpg_vs, //场同步输出 11 output O_tpg_hs, //行同步输出 12 output O_tpg_de, //视频数据有效输出 13 output [23:0] O_tpg_data //有效测试数据 14 ); 15 16 reg tpg_vs_r = 1'b0; //对vs信号寄存 17 reg tpg_hs_r = 1'b0; //对hs信号寄存 18 reg [7 :0] grid_data = 8'd0; //grid棋方格寄存器 19 reg [23:0] color_bar = 24'd0;//RGB 彩条寄存器 20 reg [10:0] dis_mode = 11'd0;//显示模式寄存器 21 reg [7 :0] r_reg = 8'd0; //红寄存器 22 reg [7 :0] g_reg = 8'd0; //绿寄存器 23 reg [7 :0] b_reg = 8'd0; //蓝寄存器 24 25 always @(posedge I_tpg_clk)begin 26 tpg_vs_r <= I_tpg_vs; //对vs信号寄存一次 27 tpg_hs_r <= I_tpg_hs; //对hs信号寄存一次 28 end 29 30 reg [11:0]v_cnt = 12'd0; //视频垂直方向,行计数器 31 reg [11:0]h_cnt = 12'd0; //视频水平方向,列计数器 32 33 //h_cnt计数器模块 34 always @(posedge I_tpg_clk) 35 h_cnt <= I_tpg_de ? h_cnt + 1'b1 : 12'd0; //计数行有效像素,当de无效,重置 h_cnt=0 36 37 //v_cnt计数器模块 38 always @(posedge I_tpg_clk) 39 if(I_tpg_vs) //通过vs产生同步复位 40 v_cnt <= 12'd0; //重置v_cnt=0 41 else 42 v_cnt <= ((!tpg_hs_r)&&I_tpg_hs) ? v_cnt + 1'b1 : v_cnt; //hs信号的上升沿,v_cnt计数,这种方式可以不管hs有效是高电平还是低电平的情况,v_cnt 视频垂直方向,行计数器,计数行数量 43 44 //显示模式切换 45 always @(posedge I_tpg_clk) 46 if(I_tpg_rstn==1'b0) 47 dis_mode <= 0; 48 else 49 dis_mode <= ((!tpg_vs_r)&&I_tpg_vs) ? dis_mode + 1'b1 : dis_mode; 50 51 //grid_data发生器 52 always @(posedge I_tpg_clk)begin 53 grid_data <= ((v_cnt[4]==1'b1) ^ (h_cnt[4]==1'b1)) ? 8'h00 : 8'hff; //方格大小16*16,黑白交替 54 end 55 56 //RGB彩条发生器 57 always @(posedge I_tpg_clk) 58 begin 59 if(h_cnt==260) 60 color_bar <= 24'hff0000;//红 61 else if(h_cnt==420) 62 color_bar <= 24'h00ff00;//绿 63 else if(h_cnt==580) 64 color_bar <= 24'h0000ff;//蓝 65 else if(h_cnt==740) 66 color_bar <= 24'hff00ff;//紫 67 else if(h_cnt==900) 68 color_bar <= 24'hffff00;//黄 69 else if(h_cnt==1060) 70 color_bar <= 24'h00ffff;//青蓝 71 else if(h_cnt==1220) 72 color_bar <= 24'hffffff;//白 73 else if(h_cnt==1380) 74 color_bar <= 24'h000000;//黑 75 else 76 color_bar <= color_bar; 77 end 78 79 //测试图形输出 80 always @(posedge I_tpg_clk)begin 81 case(dis_mode[10:7])//截取高位,控制切换显示速度 82 4'd0:begin 83 r_reg <= 0; 84 b_reg <= 0; 85 g_reg <= 0; 86 end 87 4'd1:begin 88 r_reg <= 8'b11111111; //白 89 g_reg <= 8'b11111111; 90 b_reg <= 8'b11111111; 91 end 92 4'd2,4'd3:begin//连续两个状态输出相同图形 93 r_reg <= 8'b11111111; //红 94 g_reg <= 0; 95 b_reg <= 0; 96 end 97 4'd4,4'd5:begin//连续两个状态输出相同图形 98 r_reg <= 0; //绿 99 g_reg <= 8'b11111111; 100 b_reg <= 0; 101 end 102 4'd6:begin 103 r_reg <= 0; //蓝 104 g_reg <= 0; 105 b_reg <= 8'b11111111; 106 end 107 4'd7,4'd8:begin //连续两个状态输出相同图形 108 r_reg <= grid_data; //方格 109 g_reg <= grid_data; 110 b_reg <= grid_data; 111 end 112 4'd9:begin 113 r_reg <= h_cnt[7:0]; //水平渐变 114 g_reg <= h_cnt[7:0]; 115 b_reg <= h_cnt[7:0]; 116 end 117 4'd10,4'd11:begin //连续两个状态输出相同图形 118 r_reg <= v_cnt[7:0]; //垂直渐变 119 g_reg <= v_cnt[7:0]; 120 b_reg <= v_cnt[7:0]; 121 end 122 4'd12:begin 123 r_reg <= v_cnt[7:0]; //红垂直渐变 124 g_reg <= 0; 125 b_reg <= 0; 126 end 127 4'd13:begin 128 r_reg <= 0; //绿垂直渐变 129 g_reg <= h_cnt[7:0]; 130 b_reg <= 0; 131 end 132 4'd14:begin 133 r_reg <= 0; //蓝垂直渐变 134 g_reg <= 0; 135 b_reg <= h_cnt[7:0]; 136 end 137 4'd15:begin 138 r_reg <= color_bar[23:16]; //彩条 139 g_reg <= color_bar[15:8]; 140 b_reg <= color_bar[7:0]; 141 end 142 endcase 143 end 144 145 assign O_tpg_data = {r_reg,g_reg,b_reg};//测试图形RGB数据输出 146 assign O_tpg_vs = I_tpg_vs; //VS同步信号 147 assign O_tpg_hs = I_tpg_hs; //HS同步信号 148 assign O_tpg_de = I_tpg_de; //DE数据有效信号 149 150 endmodule
3 RTL仿真
3.1仿真激励文件
1 `timescale 1ns / 1ns//仿真时间刻度/精度 2 3 module video_test_tb; 4 5 localparam SYS_TIME = 20;//系统时钟周期10ns 6 7 reg I_vid_rstn,I_vid_clk; 8 wire O_vid_vs,O_vid_hs,O_vid_de; 9 wire [7:0]O_rgb_r,O_rgb_g,O_rgb_b; 10 11 //例化video_test 12 video_test video_test_inst 13 ( 14 .I_vid_clk(I_vid_clk), 15 .I_vid_rstn(I_vid_rstn), 16 .O_vid_vs(O_vid_vs), 17 .O_vid_hs(O_vid_hs), 18 .O_vid_de(O_vid_de), 19 .O_rgb_r(O_rgb_r), 20 .O_rgb_g(O_rgb_g), 21 .O_rgb_b(O_rgb_b) 22 ); 23 24 //初始化 25 initial begin 26 I_vid_clk = 1'b0; 27 I_vid_rstn = 1'b0; 28 #100;//产生100ns的系统复位 29 I_vid_rstn = 1'b1;//复位完成 30 end 31 //产生仿真时钟 32 always #(SYS_TIME/2) I_vid_clk= ~I_vid_clk; 33 34 endmodule
为简化仿真,这里模拟的视频格式为320*5 即一行的有效数据为350个像素,一帧数据有5行像素数据。
1 .H_ActiveSize(320), //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素,设置320个像素 2 .H_FrameSize(320+88+44+239),//视频时间参数,行视频信号,一行视频信号总计占用的时钟数 3 .H_SyncStart(320+88), //视频时间参数,行同步开始,即多少时钟数后开始产生行同步信号 4 .H_SyncEnd(320+88+44), //视频时间参数,行同步结束,即多少时钟数后停止产生行同步信号,之后就是行数据有效数据部分 5 .V_ActiveSize(5), //视频时间参数,场视频信号,一帧图像所占用的有效(需要显示的部分)行数量,通常说的视频分辨率即H_ActiveSize*V_ActiveSize 6 .V_FrameSize(5+4+5+28), //视频时间参数,场视频信号,一帧视频信号总计占用的行数量 7 .V_SyncStart(5+4), //视频时间参数,场同步开始,即多少行数后开始产生场同步信号 8 .V_SyncEnd (5+4+5) //视频时间参数,场同步结束,即多少行数后停止产生场同步信号,之后就是场有效数据部分
3.2仿真结果
本文来米联客(milianke),作者:米联客(milianke),转载请注明原文链接:https://www.cnblogs.com/milianke/p/18335245