VGA显示图片
在上一个笔记熟悉了VGA的时序后,显示了一个翡翠台彩条的图片,采用的思想是在vga_output模块上,根据x,y坐标的不同,把图片分成了三个800*200的区域,分别在三个区域上显示蓝,绿,红的颜色,如果我们要显示一副图片的话,同样也可以采取这个思路,不过每个像素的数据不像彩条那么简单了,我们需要建立一个ROM,根据x和y的的坐标,也就是是地址,来实时获取每个像素点的数据,显示一副图像,下面就以显示一个这样的图片为例。
这个图片像素为640*640,我们打开画图软件,把它的像素调整为240*240,并保存为24bit的位图格式,即bmp格式。然后我们再打开一个BMP2MIF的软件,把BMP转化为一个MIF文件,这样我们使用ROM的IP核时,便可以加载这个MIF文件了。笔者使用的FPGA芯片型号为EP4CE6F17C8,这款芯片的Memory Bits一共有276480,我们显示一个240*240的RGB565图像一共需要240*240*16=921600bits,明显是不够的,所以我们只能显示黑白图像,这样的话只需用到240*240*1=57600bits,是可以满足需要的。
整个设计采用的模块架构仍与笔记5大体相同,只是多了一个ROM模块,vga_out模块需要多一个addr和q的接口。
我们仍然使用的是800*600*60Hz分辨率的VGA时序,但是我们要显示的是一副240*240的画面,并显示在屏幕的中间,我们只需改变一下vga_ctrl模块的参数便可以。对于笔记5中,valid信号对于800*600的有效显示区域为高电平,我们现在只需修改为240*240这个区域valid才为高电平,同样的,x坐标以前为1-800,y坐标以前为1-600,我们修改后的x坐标和y坐标都为1-240。如以下代码所示,加粗部分即为修改的部分。对于x坐标,我们规定了495-735这240个像素才为有效的,而这也刚好处在屏幕的中间,而y坐,我们规定了194-434这240个像素点为有效像素点。
module vga_ctrl(clk,rst_n,hs,vs,valid,x,y);
input clk;
input rst_n;
output hs;
output vs;
output valid;
output [10:0] x,y;
reg [10:0]count_h;
reg [10:0]count_v;
reg valid;
always @(posedge clk or negedge rst_n)
if (!rst_n)
count_h<=11'd0;
else if (count_h==11'd1055)
count_h<=11'd0;
else
count_h<=count_h+11'd1;
always @(posedge clk or negedge rst_n)
if (!rst_n)
count_v<=11'd0;
else if (count_v==11'd627)
count_v<=11'd0;
else if(count_h==11'd1055)
count_v<=count_v+11'd1;
always @(posedge clk or negedge rst_n)
if (!rst_n)
valid<=1'b0;
else if(count_h>=11'd495&&count_h<11'd735&&count_v>=11'd194&&count_v<11'd434)
valid<=1'b1;
else
valid<=1'b0;
assign hs=(count_h<=11'd127)? 1'b0:1'b1;
assign vs=(count_v<=11'd3)? 1'b0:1'b1;
assign x=valid?count_h-11'd495:11'd0;
assign y=valid?count_v-11'd194:11'd0;
endmodule
对于vga_out模块,我们也要作出一些修改,在这个模块中,增加了16bit的地址接口和q接口,这是与ROM连接的,我们根据地址坐标来获取像素点,如果q为1'b1,RGB信号就取16'd65535即为白色,若q为1'b0,则RGB信号就取1'b0,即为黑色。在不是有效区域的地方,我们同样显示黑色,即16'd0。对于地址,240*240的图像一共有57600个像素点,即有0-57599一共57600个地址,对于第1行第1个像素 地址为16'd0,第240个像素,地址为16'd239,第2行第1个像素,地址为16'd240,第y行第x个像素地址为x+y*9'd240,即计算公式为addr=x+y*9'd240。
module vga_output(clk,rst_n,x,y,valid,rs,gs,bs,addr,q);
input clk,rst_n;
input [10:0]x,y;
input valid;
input q;
output [15:0]addr;
output [4:0]rs;
output [5:0]gs;
output [4:0]bs;
reg [4:0]rs;
reg [5:0]gs;
reg [4:0]bs;
always @(posedge clk or negedge rst_n)
if(!rst_n)
{rs[4:0],gs[5:0],bs[4:0]}<=16'd0;
else if(valid)
case (q)
1'b1:{rs[4:0],gs[5:0],bs[4:0]}<=16'd65535;
1'b0:{rs[4:0],gs[5:0],bs[4:0]}<=16'd0;
endcase
else
{rs[4:0],gs[5:0],bs[4:0]}<=16'd0;
assign addr=x+y*9'd240;
endmodule
关于ROM的配置,同样的我们可以根据PLL那样。我们选用一个ROM:1-PORT。
注意红色部分,因为我们显示的是一个黑白图像,所以数据只有1个位,而240*240的图像有57600个像素,即57600个地址,我们需要用16个位的地址,即2的16次方为65536,下面选择使用M4K块资源。
我们再找个位置添加我们的mif文件。然后即可完成ROM的配置了。
综合过后,把sof文件烧到FPGA上,即可看到在800*600分辨率的液晶屏上显示一副240*240的图片了。
如果我们要显示480*480的图片怎么办呢,此时像素点一共为480*480=230400,地址有230400个,而芯片地址最多只能有16位,一共65536个,硬件资源并不能满足,我们仍然使用240*240的图片,但是我们可以对这幅图片进行放大,4个像素点公用一个地址便可,即第1行第1,2个像素,第2行第1,2个像素这4个像素点的地址为0,第1行第3,4个像素,第2行第3,4个像素地址为1,即addr=x[10:1]+y[10:1]*9'd240这样的逻辑。而对于480*480的区域,我们的修改也非常简单,只用修改valid为高电平的有效矩形区域即可了,即如下代码所示。
always @(posedge clk or negedge rst_n)
if (!rst_n)
valid<=1'b0;
else if(count_h>=11'd375&&count_h<11'd855&&count_v>=11'd74&&count_v<11'd554)
valid<=1'b1;
else
valid<=1'b0;
assign x=valid?count_h-11'd375:11'd0;
assign y=valid?count_v-11'd74:11'd0;
在vga_out 和vga_ctrl模块作了以上修改后,我们观察现象,发现图像变成了480*480,大体上图像的质量也是可以接受的。
用户411430 2016-2-21 10:14