博客首页 | 排行榜 |

utoo的博客

个人档案
博文分类
【FPGA博客大赛】优化Xilinx的plb_tft_cntlr_ref IP 的历程  2010-03-02 18:12

  这段时间一直在XUPV2P上做高清视频解码器,但是解码器总是要有能显示的东西,不然总是给人感觉不真实。但是从头开始编写display feeder工作量有些大,所以想偷偷懒。真幸运,给我找到了Slide Show using 256 MB DDR Memory plb_tft_cntlr_ref

   这个IP能显示640x480BMP图片,但是离高清720p1280x720)还是差距不小。

我想弄清其原理,优化应该不难。刚开始以为就是调几个参数就能搞定。结果这一搞就是一个多月,不过还是收获良多。

   总结起来学到的东西与大家分享:plb_tft_cntlr_ref的原理与框图 ,VGA的显示原理,PLB总线的transfer的优化,BLOCK_RAM的使用,DCM的使用,chipsocpe的使用。

plb_tft_cntlr_ref原理:

Slide Show using 256 MB DDR Memory 这个例程的功能是这样:

首先,从CF卡里读取多个BMP图片的数据,去掉BMP的头信息之后,把RGB的数据放到内存中。

同时,每个BMP图片在内存中的地址都被记录。

最后,PPC通过DCR总线向把要显示的图片的地址写给plb_tft_cntlr_refplb_tft_cntlr_ref 就会根据这个地址从内存中读取数据进行显示。PPC通过传不同的地址给plb_tft_cntlr_ref,这样就能显示不同的图片,做到幻灯片的效果。

当然还有许多细节,下面遇到再说。

VGA的显示原理:

VGA的显示最先是用在CRT显示器上,虽然现在也可以用在LCD上,但是我们还是看看CRT的显示的原理图:

 

 

显示的时候电子枪是按下面的方法扫描:

 

 

简化点来说,显示的控制是这样的:

 

 

Controller要给出符合VGA显示时序的RGBvsynchsync,显示器才进行正确地显示。

 

怎样才能符合VGA的显示时序呢?

下面这张图给出答案。

 

 

 

 

 

从上图我们可以看到整个时序图可以分为4段:

1,显示阶段,也就是video_on使能的阶段。这个时候controlller要将RGB数据送给显示器,而且是每一个pixel_clk送出一个pixelRGB数据。

2,折回(retrace),也就是电子枪扫完一行之后回到最初扫描的位置用的时间。

3,前沿(front porch),之所以称为前沿,是因为它在retrace的前面吧。对应于显示右边黑掉的部分。

4,后沿(back porch),对于与显示左边黑掉的部分。

显然,改成1280x720,最起码显示这些参数是要改动的,但是我不知道是多少。

在网上找了半天,结果还是在XUPV2Puser guide 上找到答案。真是佩服Xilinxuser guide做得可真全。

我想他们也不会介意我切一点上来:

 

 

 

                      这样就要找到plb_tft_cntlr_ref中,与这四个阶段有关的参数。  

   在h_sync.vv_sync.v中我找到了这些参数,这四个阶段是用状态机来完成。不过修改起来还算简单。修改对应计数器的值就行了。

   这个表格的参数也提示我pixel_clk要进行修改。而且与DCM有关。

 

DCM参数的修改

 

 

 

主要修改了两处,原来的IP是用DCM的分频功能从100Mhz分频得到50Mhzpixel_clk.但是75Mhz是没法用分频得到,所以要用CLKFX。而且下面的参数要修改。这样就能从100Mhz的时钟得到75Mhz的时钟。

 

plb_tft_cntlr_ref 的框图:

   一开始我并没有往1280x720去做,而是往800x600做,因为有一个问题会造成1280x720不成功,那就是Blockram的大小问题。      

   下面这张图可以说明这个IP从读数据到显示的过程。

由于PLB总线的时钟是100Mhz,pixel_clk通常都不是100Mhz,那么这就是一个跨时钟域的问题,那么这就需要有一个bufferFPGA中当然是用Blockram来完成。这个例程真的教会我很多东西。

   先介绍一下数据的读取过程。

   plb_tft_cntlr_ref从内存读取显示数据时并没有一次读一个图片的数据,因为数据量太大,FPGA上没有这么大的存储空间,它只是读取一行的显示数据到Blockram中,再由显示那边读去显示,一旦显示完成就会有一个getline的信号要求plb_tft_cntlr_ref从内存中读取另一行的显示数据。

 

 

 

 

所以现在只有1K,也就是1024,那么1280将超过这个数,那么就会出错。

我又想验证上面的修改是否正确,只能先做800x600

这样把上面那些地方改成800x600之后,果然能显示800x600的图片。这都让我兴奋了一整晚。

BLOCK_RAM的修改

接下来就是修改Blockram了,我想还是先在800x600改改,从user guide上可以看到VGADAC8位,这里只是用到6位,我想主要是为了节省BLOCKRAM,但是我想看看8位数据会不会能显示的效果好一点,而且为下面720p做好准备,所以决定用3BLOCKRAM来代替一个BLOCKRAM,每一个BLOCKRAM存放一种颜色的8位数据。

修改代码如下:

 

 

 

 

PLB总线的transfer的优化

   结果在意料之中,能正确地显示,但是没有看到比原来更好的效果,我想6位就够用了吧。

   不过,既然Blockram都改大了,那就往720P做吧。

   改完上面的时序参数之后,显示不出来正确的图像。我观察了一阵那些图像,好像前面几列是正确的,但是后面错了。想了很久都没有发现哪里错了,最后代码里的注释给了我启发,原IP用的是64-bit Master 8-word Line Read From a 64-bit Slave传输方式。这让我想到会不会是从内存读取的数据的速度太慢,显示已经用到后面的像素,所以没能显示。

   因为这种传输方式每一次申请总线才读8个word。

   我不过证实我的猜测是我学会用chipsocpe之后(对于如何使用chipscope来观察coreconnect的时序,我之前的博文中介绍过这里不再罗嗦。)

有兴趣的朋友可以看看:

使用chipscope来观察coreconnect总线时序之plb时序

使用chipscope来观察coreconnect总线时序之DCR时序

 

使用chipscope来观察coreconnect总线时序之OPB时序

 

 

看到了下面张图后,我才发现原来这种传输方式用在这个地方多么的浪费总线的带宽。

 

 

 

 

   每一次等待16个clk之后能从DDR里读出数据,却只读了8个WORD,然后再去申请,再等16个clk。我想问题就出在这。为什么不多读几个呢,甚至一整行都读完。

   我只有在PLB总线的datasheet里苦苦地寻找我要的那种transfer。终于,我发现Sequential Burst Read Transfer Terminated by Master十分的合适,一次能读完一整行的数据。所以就决定用它了

 

 

 

对比64-bit Master 8-word Line Read From a 64-bit Slave

 

 

   可以看到Sequential Burst Read Transfer Terminated by Master最大的区别在于多了一个Mn_rdBurst信号,这个信号一旦使能,就可以从DDR中连续不断地读到数据。

  那Mn_rdBurst要使能多久呢?是不是640个时钟呢?(因为DDR是上下沿都能出数据,所以一个clk能出64个bit的数据)刚开始我也这样认为,但是用chipsocpe一看,才发现Mn_rdBurst使能的时候,DDR有时数据会有间断,所以不能准确地用640个时钟,应该多一点。看图就明白。

 

 

 

      

                              那怎样才知道传完一行数据呢。用PLB_MnRdDAck来使能计数器可以做到。

   就这样,720P的显示被我征服了。呵呵!

   虽然这只是万里长征的第一步,但是感觉这一步还是迈得挺踏实的,学会了不少东西。

   生活总是这样,遇到问题,解决问题。在解决问题的过程中,我们不断地积累,不断地成长。

   老师让我多做笔记,我想就用与非网这个博客来记录我的积累和成长。

 

无图不事实:

 

 

 

类别:项目历程 |
上一篇:【FPGA博客大赛】XUPV2P上移植linux的三种方法以及移植后进一步开发的思考 | 下一篇:【FPGA博客大赛】使用chipscope来观察coreconnect总线时序之opb时序
以下网友评论只代表其个人观点,不代表本网站的观点或立场