vga_char设计

实验通过字符转换工具将字符转换为8进制mif文件存放在单端口的ROM IP核中,再从ROM中把转换后的数据读取出来显示到VGA上。

上图为该设计的RTL视图,我们可以看到该系统大体上分为三个模块:video_pll,color_bar,osd_display。pll这里不需要多讲,它起到是一个对系统时钟分频倍频的作用。color_bar以及osd_display模块的clk连接到pll倍频出来的时钟c0,这里凸显出来一个问题就是我们如何通过刷新率来计算得出这两个模块需要的时钟?已知标准的VGA显示的场频60HZ,也就是平常经常听到的刷新率,想必在座的各位有接触个各种大型网络游戏吧,对显示器的要求都是2K,144HZ了吧。那么又是如何通过刷新率来计算像素点时钟频率呢?60HZ也是指一秒钟刷新60帧,刷新一帧画面的时间:1/60s,本实验的分辨率是1024*768(有效显示区),通过下图我们就可以清晰的发现:分为显示区,blank区。 

可以看出Blanking分为”Front Porch”、”Sync”、”Back Porch”三段。而Blanking time加上Active time就是一行的时间。以1024*768为例,每场对应806个行周期,其中768为显示行。每个显示行包括1344点时钟,其中1024点为有效显示区。故每刷新一个像素点所需时间为:

1/(60*1344*806),即像素点时钟频率:(60*1344*806)约65MHZ。

我们可以从上图中看出,整个VGA显示部分,也就是active part大体上分为两个部分,一部分是文字显示,一部分是背景(屏幕彩条)。那么我们应该就可以联想到剩余两个模块的功能是什么?到底有什么作用?其中color_bar主要负责背景显示(彩条),osd_display主要负责文字显示(ALINX芯驿)。下面我们先来分析color_bar这个模块。

 关于H_FP/V_FP,H_SYNC/V_SYNC,H_BP/V_BP在前文已经讲过了,后面定义的值是指在blank区域的像素点,而H_ACTIVE/V_ACTIVE是指显示区域的像素点。 

 

虽然这里没什么难点,但是总要BB两句,h_cnt是记录水平像素点个数的计数器,而v_cnt是记录行数的计数器,我们通过hcnt==H_FP-1是否为1来判断是否已经扫描一行,如果为1,v_cnt<=v_cnt+1。active_x是指显示区域的横坐标。

 

讲到这段代码,我又要拿出VGA显示的镇山之宝,大家就会豁然开朗。

 

何时将hs_reg以及vs_reg置1?通过上图我们可以分析出,当完成H/V Front Porch区域的扫描。何时将hs_reg以及vs_reg置0呢?当完成H/V Sync Time区域的同步。h_active/v_active呢?又是该如何描述呢?同理,依然看图,我认为在做任何外设的驱动,都是在完成看图说话的过程,虽然在VGA驱动时并不需要h_active/v_active,但是当我们做HDMI驱动就会发现由一个de的信号,de==h_active&v_active(它就是一个显示有效信号)。有效就是指H/V active start(可以在图中发现)。 

 

下面我们来看字符显示了,也就是osd_display这个模块。

 

timing_gen_xy.v

 

其实在这里我有一个困惑的地方,vs/de的二级锁存可以理解,它是为了抓取边沿跳变(vs_edge/de_falling),但是我不清楚为什么要对i_vs/i_hs/idata也就是color_bar模块中输出的hs/vs/{rgb_r,rgb_g,rgb_b}二级锁存?还望有知道的大神提供帮助,再次感激不尽!!!

 

这里的x_cnt/y_cnt由于de=h_active&v_active,de由1到0,可以得到列像素点在该行超过了显示区域,即清0,在该行的有效显示区内,每个clk(像素点时钟频率)上升沿,x_cnt+1。

在第二个always块中,我们会看到de_falling这个信号,在上段中讲到de由1到0列像素点在该行超出了显示区,即说明了该行的显示信息已经刷新完了,y_cnt+1(应该显示下一行了)。每刷新一帧图像,进行一次场同步,故我们可以通过场同步的跳变来将纵坐标清0,所以有了这条if(vs_edge==1’b1) y_cnt<=12’d0;

接下来我们需要做的是将字符转换成能够被FPGA识别的.mif文件。这里我们通过上位机的一个软件生成了.mif文件。还需要将mif文件存储在FPGA中,这时我们在FPGA中配置一个单口ROM,因为软件生成的mif文件是8位的,所以在ROM的配置中宽度选择8位,深度选择2048words,在Mem Init中将.mif文件加载到ROM中,到这我们就已经将字符信息存储到FPGA内部了。

下面我们来讲字符显示了,osd_display

 

这段代码大体上完成了三件事:

①规定了字符显示区域:通过横纵坐标,以及字符大小的判断逻辑完成,输出了一个标志信号region_active(标志着进入了字符显示区),这里的初始坐标可以根据你的需要而定。

②通过逻辑,提取ROM中的字符信息,并完成显示字符还是背景的功能:这里我想有些人会有诸多疑惑,已经规定了字符显示区?为什么还要通过逻辑继续判断是显示字符还是背景呢?其实所谓字符的显示区域,就是我要在这个区域里显示我的文字,但在这个区域里并不只有文字,还有背景。那么又是通过怎样的逻辑完成判断的呢?且听我慢慢BC。

这个判断逻辑很简单,我在前文中有讲过上位机软件输出的是8bit的数值文件,而一位data占了一个像素点。因此if(q(osd_x[2:0])==1’b1) v_data<=24’hff0000;这条逻辑应该就很好理解了吧,每一位的数值为1则代表在该为含有字符信息,那么在这个像素点上就输出我们设定的颜色(24’hff0000),否则在该像素点上输出背景(彩条)。但是问题来了,根据这条判断逻辑,判断从ROM中输出的data(q),需要8个CLK,但是第二个clk后ROM输出的data就不再是我们要判断的data了啊?这个问题困扰了我好久,终于聪明的我看出了设计者巧妙的地方:

 

 

有粗心的同学会问:咦?addr还是每个CLK加1啊?但是细心的你会发现:在例化rom的时候address已经露出了她神秘的面纱:osd_ram_addr[15:3],是不是会豁然开朗,一处巧妙的设计,将原本每个clk会加1的address变成了每8个clk才会加1,是不是很牛B。这就是FPGA的乐趣吧,需要你的探索和挑战!!!

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值