HDMI系列之一:基于Nios II的HDMI显示图片
2017-07-16 17:49
190 查看
一休哥将在本文中介绍一个基于Nios II的HDMI显示图片的工程。我将主要分三个部分来介绍这一工程,从而实现工程效果。
1、 Nios II的常规使用套路
2、 自定义HDMI IP核的制作
3、 Nios II显示图片
本文涉及到的全部资料链接:
链接:http://pan.baidu.com/s/1eRNXagy 密码:uv9w
![](https://img-blog.csdn.net/20170716164556102?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
上图是基于Nios II的FPGA工程的简要结构图,其中属于Nios II的部分有两个,一个是Qsys系统,它是Nios II的硬件;一个是软核工程,它是Nios II的软件。
首先我们新建一个空的FPGA工程,然后点击软件界面的Qsys按钮,进入Qsys的建立界面。
![](https://img-blog.csdn.net/20170716164612282?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后,在界面中,我们双击Clock Source IP核,修改里面的参数,设置时钟频率为100MHz,并给这个IP核重命名为clk。
![](https://img-blog.csdn.net/20170716164634911?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
接着,我们添加一个Nios II Processor IP核,在左上角的Library的搜索窗口中搜nios即可。然后重命名为nios_qsys。
![](https://img-blog.csdn.net/20170716164649101?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后,添加SDRAM Controller IP核,同样搜索之后,我们需要根据自己板子上SDRAM的型号来配置IP核。我使用的是锆石科技的A4开发板,使用的SDRAM芯片为MT48LC16M16A2,所以仅供大家参考。最后同样的重命名为sdram。
![](https://img-blog.csdn.net/20170716164658298?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后接着添加JTAG UART和System ID Peripheral IP核,无需进行任何配置,仅需要重命名为jtag_uart和sysid_qsys即可。
![](https://img-blog.csdn.net/20170716164710347?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
接着,我们添加自定义的HDMI IP核。大家在使用该IP时,需要将我提供的IP核文件放在下图这个路径上。(嘿嘿,由于这个IP核是我仿照锆石科技的VGA IP核而制作的,为了防止被锆石大大给和谐掉,因此也放在同样的IP核路径中。)
![](https://img-blog.csdn.net/20170716164722937?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后,我们可以在zircon_ip的IP组里找到zircon_hdmi的IP了,直接调用就行了。
![](https://img-blog.csdn.net/20170730112641814?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
至此,Qsys系统所需的IP核就调用完了,接下来的操作就是连线,连线主要有clk端口,reset端口,Nios的数据与指令端口和Avalon—MM端口。首先我们把除Clock Source IP核以外的IP核的时钟端口连上。由于我们这个Qsys系统只有一个Clock Source IP核,所以当然是用这个IP提供的时钟端口来连接其他IP核。然后将Clock Source IP核的复位端口连接上其他IP核。接着将Nios II Processor IP核的jtag_debug_module_reset复位端口连接上其他IP核。
![](https://img-blog.csdn.net/20170730112710236?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730112843277?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730112851700?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
接着,我们来连接Nios的数据与指令端口,连接这个的时候有一个规律,就是有存储功能的IP核需要同时连接数据与指令端口,如SDRAM,RAM,ROM,EPCS等,而其他外设只需要连接数据端口。
![](https://img-blog.csdn.net/20170730112909280?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后,由于我制作的HDMI IP核是基于Avalon-MM协议的,通过这个协议可以实现HDMI IP核与Nios II Processor IP核和SDRAM Controller IP核的数据通讯,所以需要将HDMI IP核的Avalon—MM的主端口与SDRAM Controller IP核来读取存储在SDRAM中的图片数据,HDMI IP核的Avalon—MM的从端口与Nios II Processor IP核的数据端口相连来接收Nios II软件发送的图片地址数据。关于HDMI IP核具体的介绍,将会在后两个部分中详细介绍。
![](https://img-blog.csdn.net/20170730112926193?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
完成所有的连线之后,需要双击Nios II Processor IP核,设置其复位向量和异常向量为sdram.s1。接着,设置jtag_uart IP核的中断号,引出sdram IP和HDMI IP的引脚。点击软件界面右上角的System下拉菜单中的Assign Base Address自动分配各个IP的地址。点击软件界面右上角的File下拉菜单中的Save as保存Qsys文件。最后点击软件界面右上角的Generate下拉菜单中的Generate,生成Qsys系统。这样,一个Qsys系统就生成完了。
![](https://img-blog.csdn.net/20170730112944660?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730112956454?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730113006268?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-b<br/>4000<br/>log.csdn.net/20170730113029387?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后,回到Quartus主界面,右键点击Files,添加新生成的Qsys.qip文件。
![](https://img-blog.csdn.net/20170730113044446?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后,我们的顶层文件是这样的,这样我们的硬件工程就算建立完毕了。
接下来,一休哥将着重介绍HDMI IP核的制作。首先我们来看下HDMI的硬件原理图。HDMI芯片与FPGA相连的接口可以分为两类,一类是IIC接口,一类是类似于VGA的视频时序接口。驱动HDMI芯片需要两个步骤,先使用IIC接口对HDMI芯片进行配置,然后使用视频时序接口输出视频时序信号。这些操作都是通过HDMI IP核来实现的。
![](https://img-blog.csdn.net/20170730114009255?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
接下来,打开HDMI IP核的文件夹。可以看到有5个v文件,这就是HDMI IP核的硬件。后缀为hw的tcl文件是硬件配置文件,这一文件是通过Qsys界面生成的,通过这个文件可以让Qsys系统生成时自动调用这5个v文件融于系统中。
![](https://img-blog.csdn.net/20170730114028845?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
其中zircon_avalon_hdmi 是HDMI IP核的硬件的顶层文件,i2c_timing_ctrl是用来完成IIC配置的,zircon_avalon_hdmi_logic是用来模拟视频时序的,并控制读取zircon_avalon_hdmi_fifo的FIFO模块中的数据。zircon_avalon_hdmi_register是HDMI IP核内部的寄存器操作,通过Avalon-MM协议可以实现HDMI IP核与Nios II Processor IP核和SDRAM Controller IP核的数据通讯。关于每个v文件具体的作用,大家可以参考锆石科技推出的《软核演练篇》系列教程中VGA IP核的相关内容,在这里就不一一介绍了。
接下来,我教大家来制作后缀为hw的硬件配置tcl文件。首先我们在路径下将文件夹中的hw文件删除。这时打开Qsys界面,大家可以发现,我们已经找不到HDMI IP核了。
![](https://img-blog.csdn.net/20170730114046787?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114057292?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后,双击New Component,然后配置IP核的信息。嘿嘿,由于我这个IP核有抄袭锆石科技的嫌疑,在这里允许我把创建人写为zircon吧。(锆石大大,别怪我)
![](https://img-blog.csdn.net/20170730114113832?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后进入下一个界面,点击添加按钮,将路径中的那5个v文件选中添加,并且将zircon_avalon_hdmi.v文件设置为顶层文件,点击Analysis Synthesis Files文件。
![](https://img-blog.csdn.net/20170730114128222?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114245995?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114312548?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
接着,来到最后一个Interfaces界面,针对avalon_slave接口、avalon_master接口和conduit_end接口做如下修改:改名和添加复位信号。最后点击Finish完成IP核的硬件创建。
![](https://img-blog.csdn.net/20170730114349030?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114403102?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114413150?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后在FPGA工程的文件夹目录中可以找到zircon_avalon_hdmi_hw.tcl,然后打开这个文件,对文件中的部分代码进行修改。然后将这个文件剪切到源HDMI IP核路径中即可。然后重新打开Qsys界面,就可以重新搜索到HDMI IP核了。
![](https://img-blog.csdn.net/20170730114505215?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114514636?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114522300?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114531556?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114541344?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114611003?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
然后点击Quartus软件界面中的Nios II Software Build Tools for Eclipse,在弹出来的软件工程路径中选择C:\Users\Administrator\Desktop\Qsys_Hdmi_Ip\software。开始创建软件工程。
![](https://img-blog.csdn.net/20170730114624801?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114638403?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
接下来我们进入Nios II-Eclipse软件界面,点击Nios II Application and BSP from Template,开始创建工程。
![](https://img-blog.csdn.net/20170730114650465?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114708300?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
创建完工程后,首先我们点击更新BSP
![](https://img-blog.csdn.net/20170730114725242?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114732840?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
此时在BSP目录下就可以找到HDMI IP核的c和h文件。问个问题,这些文件是如何自动综合到BSP中的呢?答案就是之前提到的HDMI IP核中的zircon_avalon_hdmi_sw.tcl文件,里面包含了所有c和h文件的详细路径。
![](https://img-blog.csdn.net/20170730114812216?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
其中,kai、qiong、qiu1、qiu2、shui和ying的h文件是我使用软件Img2Lcd将图片转换成数组的(该软件的使用方法在上篇博文中具体介绍过。)该软件的具体配置如下,然后点击保存为h文件即可。可以看到,一休哥将640*480的24bit图片转换成了相应的数组。由于一休哥采取的是24位深度转换,所以得到的是一个长度为921600的无符号字符型数组,每相连的3个8bit数据组成一个24bit的像素值。
![](https://img-blog.csdn.net/20170730114822329?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
HDMI IP核中,除了包含图片数据外,还包含了IP核所必备的寄存器头文件,功能函数库的c和h文件。
b022
首先,我们从main函数开始看起。首先需要调用HDMI IP核初始化函数zircon_avalon_hdmi_init。这个函数非常简单。第一步,对HDMI IP核的控制寄存器写0,即默认HDMI IP核停止工作。第二步,对HDMI IP核的数据寄存器进行配置,将数组hdmi_buffer的首地址值写进去。第三步,对HDMI IP核的控制寄存器写1,即让DMI IP核开始工作。其中,hdmi_buffer是一个大小为640*480的深度为32bit的数组,这一数组是一个全局变量,即它预先就在SDRAM中占据了一块固定的内存。通过将数组hdmi_buffer的首地址值写入HDMI IP核的数据寄存器。则HDMI IP核就会连续对SDRAM中这块内存进行循环读取操作(起始地址为数组hdmi_buffer的首地址值,范围大小为640*480,深度为32bit)
![](https://img-blog.csdn.net/20170730114837256?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114851112?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730114926889?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
进行完初始化之后,直接进入一个while的死循环中,在这里就执行着显示图片的操作zircon_avalon_hdmi_DisplayPic1,这里有六个显示图片函数,并且中间会有一段时间的延时。所以本工程的效果就是六张图片来回切换。我们最后来介绍下zircon_avalon_hdmi_DisplayPic1函数,这个函数就是一个连续画点函数,先将原图片数组的3个8bit数据拼成一个24bit数据,然后依次写入数组hdmi_buffer。
![](https://img-blog.csdn.net/20170730115008826?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730115042564?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
最后我们运行程序,来看一下效果。
![](https://img-blog.csdn.net/20170730115054585?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730115109397?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
![](https://img-blog.csdn.net/20170730115128389?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzkyMTAwMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
总结一下,学习Nios II,我们需要关心Nios II与IP核、IP核与SDRAM之间的数据交换,也就是Avalon-MM协议,这才是我们学习的重点所在。一般我们会用一个FIFO来缓存数据(而不会用ram),解决跨时钟域的数据交换问题。大家可以发现,在本工程的效果图中,图片切换的过程中存在明显的马赛克现象,这是因为SDRAM不支持同时读写的缘故,马赛克的持续时间是由于Nios的读写速度造成的。因此,可以选择将SDRAM换成可支持同时读写的大容量SRAM芯片,不过这个成本很高。最值得尝试的解决办法就是,可以尝试使用DDR芯片,加快读写速度,缩短马赛克现象的存在时间。
1、 Nios II的常规使用套路
2、 自定义HDMI IP核的制作
3、 Nios II显示图片
本文涉及到的全部资料链接:
链接:http://pan.baidu.com/s/1eRNXagy 密码:uv9w
1 Nios II的常规使用套路
虽然使用Nios II可以为我们简化编写Verilog代码的难度。但往往需要额外更多的GUI界面操作。本文为了照顾到Nios II的初学者,将带领大家重新创建一个基于Nios II的FPGA工程。上图是基于Nios II的FPGA工程的简要结构图,其中属于Nios II的部分有两个,一个是Qsys系统,它是Nios II的硬件;一个是软核工程,它是Nios II的软件。
首先我们新建一个空的FPGA工程,然后点击软件界面的Qsys按钮,进入Qsys的建立界面。
然后,在界面中,我们双击Clock Source IP核,修改里面的参数,设置时钟频率为100MHz,并给这个IP核重命名为clk。
接着,我们添加一个Nios II Processor IP核,在左上角的Library的搜索窗口中搜nios即可。然后重命名为nios_qsys。
然后,添加SDRAM Controller IP核,同样搜索之后,我们需要根据自己板子上SDRAM的型号来配置IP核。我使用的是锆石科技的A4开发板,使用的SDRAM芯片为MT48LC16M16A2,所以仅供大家参考。最后同样的重命名为sdram。
然后接着添加JTAG UART和System ID Peripheral IP核,无需进行任何配置,仅需要重命名为jtag_uart和sysid_qsys即可。
接着,我们添加自定义的HDMI IP核。大家在使用该IP时,需要将我提供的IP核文件放在下图这个路径上。(嘿嘿,由于这个IP核是我仿照锆石科技的VGA IP核而制作的,为了防止被锆石大大给和谐掉,因此也放在同样的IP核路径中。)
最后,我们可以在zircon_ip的IP组里找到zircon_hdmi的IP了,直接调用就行了。
至此,Qsys系统所需的IP核就调用完了,接下来的操作就是连线,连线主要有clk端口,reset端口,Nios的数据与指令端口和Avalon—MM端口。首先我们把除Clock Source IP核以外的IP核的时钟端口连上。由于我们这个Qsys系统只有一个Clock Source IP核,所以当然是用这个IP提供的时钟端口来连接其他IP核。然后将Clock Source IP核的复位端口连接上其他IP核。接着将Nios II Processor IP核的jtag_debug_module_reset复位端口连接上其他IP核。
接着,我们来连接Nios的数据与指令端口,连接这个的时候有一个规律,就是有存储功能的IP核需要同时连接数据与指令端口,如SDRAM,RAM,ROM,EPCS等,而其他外设只需要连接数据端口。
最后,由于我制作的HDMI IP核是基于Avalon-MM协议的,通过这个协议可以实现HDMI IP核与Nios II Processor IP核和SDRAM Controller IP核的数据通讯,所以需要将HDMI IP核的Avalon—MM的主端口与SDRAM Controller IP核来读取存储在SDRAM中的图片数据,HDMI IP核的Avalon—MM的从端口与Nios II Processor IP核的数据端口相连来接收Nios II软件发送的图片地址数据。关于HDMI IP核具体的介绍,将会在后两个部分中详细介绍。
完成所有的连线之后,需要双击Nios II Processor IP核,设置其复位向量和异常向量为sdram.s1。接着,设置jtag_uart IP核的中断号,引出sdram IP和HDMI IP的引脚。点击软件界面右上角的System下拉菜单中的Assign Base Address自动分配各个IP的地址。点击软件界面右上角的File下拉菜单中的Save as保存Qsys文件。最后点击软件界面右上角的Generate下拉菜单中的Generate,生成Qsys系统。这样,一个Qsys系统就生成完了。
然后,回到Quartus主界面,右键点击Files,添加新生成的Qsys.qip文件。
最后,我们的顶层文件是这样的,这样我们的硬件工程就算建立完毕了。
module Qsys_Hdmi_Ip ( //时钟复位端口 CLK_50M,RST_N, //SDRAM端口 SDRAM_ADDR,SDRAM_BA,SDRAM_CAS_N,SDRAM_CLK,SDRAM_CKE, SDRAM_CS_N,SDRAM_DQ,SDRAM_DQM,SDRAM_RAS_N,SDRAM_WE_N, //HDMI端口 HDMI_CLK,HDMI_RST_N,HDMI_HS,HDMI_VS,HDMI_DE, HDMI_RGB_R,HDMI_RGB_G,HDMI_RGB_B,HDMI_SCLK,HDMI_SDAT ); //时钟复位 input CLK_50M; input RST_N; // SDRAM Interface output [12:0] SDRAM_ADDR; output [ 1:0] SDRAM_BA; output SDRAM_CAS_N; output SDRAM_CLK; output SDRAM_CKE; output SDRAM_CS_N; inout [15:0] SDRAM_DQ; output [ 1:0] SDRAM_DQM; output SDRAM_RAS_N; output SDRAM_WE_N; //VGA output HDMI_CLK; output HDMI_RST_N; output HDMI_HS; output HDMI_VS; output HDMI_DE; output [ 7:0] HDMI_RGB_R; output [ 7:0] HDMI_RGB_G; output [ 7:0] HDMI_RGB_B; output HDMI_SCLK; //iic的时钟信号 inout HDMI_SDAT; //iic的数据信号 assign HDMI_RST_N = 1'b1; wire clk_100m; wire clk_30m; wire HDMI_CLK; PLL PLL_Init ( .inclk0 (CLK_50M ), .c0 (clk_100m ), .c1 (SDRAM_CLK ), .c2 (clk_30m ) ); PLL_Hdmi PLL_Hdmi_Init ( .inclk0 (clk_30m ), .c0 (HDMI_CLK ) ); Qsys_system Qsys_system_Init ( .clk_clk (clk_100m ), //clk.clk .reset_reset_n (RST_N ), //reset.reset_n .sdram_addr (SDRAM_ADDR ), //sdram_conduit.addr .sdram_ba (SDRAM_BA ), // .ba .sdram_cas_n (SDRAM_CAS_N ), // .cas_n .sdram_cke (SDRAM_CKE ), // .cke .sdram_cs_n (SDRAM_CS_N ), // .cs_n .sdram_dq (SDRAM_DQ ), // .dq .sdram_dqm (SDRAM_DQM ), // .dqm .sdram_ras_n (SDRAM_RAS_N ), // .ras_n .sdram_we_n (SDRAM_WE_N ), // .we_n .zircon_avalon_hdmi_clk (HDMI_CLK ), // zircon_hdmi.clk .zircon_avalon_hdmi_hsync (HDMI_HS ), // .hsync .zircon_avalon_hdmi_vsync (HDMI_VS ), // .vsync .zircon_avalon_hdmi_de (HDMI_DE ), // .de .zircon_avalon_hdmi_rgb (HDMI_RGB ), // .rgb .zircon_avalon_hdmi_sclk (HDMI_SCLK ), // .sclk .zircon_avalon_hdmi_sdat (HDMI_SDAT ) // .sdat ); wire [31:0] HDMI_RGB; assign HDMI_RGB_R = {HDMI_RGB[23:18],2'b11}; assign HDMI_RGB_G = {HDMI_RGB[15:10],2'b11}; assign HDMI_RGB_B = {HDMI_RGB[ 7: 2],2'b11}; endmodule
2 自定义HDMI IP核的制作
在第一个部分,一休哥详细的介绍了如何新建Nios II的硬件工程。大家可以发现,这个工程十分简洁,两个PLL模块用于产生100M时钟,SDRAM的时钟和HDMI的时钟,一个Qsys系统的顶层模块。这个Qsys系统的顶层模块是我们在Qsys设计界面中生成的。所以,在这个工程中,不需要我们手动编写Verilog逻辑代码吗?嘿嘿,好像真的是这样哦,这就是Nios的简便之处吧,不需要编写复杂代码就能够控制SDRAM。接下来,一休哥将着重介绍HDMI IP核的制作。首先我们来看下HDMI的硬件原理图。HDMI芯片与FPGA相连的接口可以分为两类,一类是IIC接口,一类是类似于VGA的视频时序接口。驱动HDMI芯片需要两个步骤,先使用IIC接口对HDMI芯片进行配置,然后使用视频时序接口输出视频时序信号。这些操作都是通过HDMI IP核来实现的。
接下来,打开HDMI IP核的文件夹。可以看到有5个v文件,这就是HDMI IP核的硬件。后缀为hw的tcl文件是硬件配置文件,这一文件是通过Qsys界面生成的,通过这个文件可以让Qsys系统生成时自动调用这5个v文件融于系统中。
其中zircon_avalon_hdmi 是HDMI IP核的硬件的顶层文件,i2c_timing_ctrl是用来完成IIC配置的,zircon_avalon_hdmi_logic是用来模拟视频时序的,并控制读取zircon_avalon_hdmi_fifo的FIFO模块中的数据。zircon_avalon_hdmi_register是HDMI IP核内部的寄存器操作,通过Avalon-MM协议可以实现HDMI IP核与Nios II Processor IP核和SDRAM Controller IP核的数据通讯。关于每个v文件具体的作用,大家可以参考锆石科技推出的《软核演练篇》系列教程中VGA IP核的相关内容,在这里就不一一介绍了。
接下来,我教大家来制作后缀为hw的硬件配置tcl文件。首先我们在路径下将文件夹中的hw文件删除。这时打开Qsys界面,大家可以发现,我们已经找不到HDMI IP核了。
然后,双击New Component,然后配置IP核的信息。嘿嘿,由于我这个IP核有抄袭锆石科技的嫌疑,在这里允许我把创建人写为zircon吧。(锆石大大,别怪我)
然后进入下一个界面,点击添加按钮,将路径中的那5个v文件选中添加,并且将zircon_avalon_hdmi.v文件设置为顶层文件,点击Analysis Synthesis Files文件。
接着,来到最后一个Interfaces界面,针对avalon_slave接口、avalon_master接口和conduit_end接口做如下修改:改名和添加复位信号。最后点击Finish完成IP核的硬件创建。
最后在FPGA工程的文件夹目录中可以找到zircon_avalon_hdmi_hw.tcl,然后打开这个文件,对文件中的部分代码进行修改。然后将这个文件剪切到源HDMI IP核路径中即可。然后重新打开Qsys界面,就可以重新搜索到HDMI IP核了。
3 Nios II显示图片
完成了上述两个部分后,接下来我们来介绍Nios 软件工程。首先在FPGA工程的根目录下新建一个software文件夹。然后点击Quartus软件界面中的Nios II Software Build Tools for Eclipse,在弹出来的软件工程路径中选择C:\Users\Administrator\Desktop\Qsys_Hdmi_Ip\software。开始创建软件工程。
接下来我们进入Nios II-Eclipse软件界面,点击Nios II Application and BSP from Template,开始创建工程。
创建完工程后,首先我们点击更新BSP
此时在BSP目录下就可以找到HDMI IP核的c和h文件。问个问题,这些文件是如何自动综合到BSP中的呢?答案就是之前提到的HDMI IP核中的zircon_avalon_hdmi_sw.tcl文件,里面包含了所有c和h文件的详细路径。
其中,kai、qiong、qiu1、qiu2、shui和ying的h文件是我使用软件Img2Lcd将图片转换成数组的(该软件的使用方法在上篇博文中具体介绍过。)该软件的具体配置如下,然后点击保存为h文件即可。可以看到,一休哥将640*480的24bit图片转换成了相应的数组。由于一休哥采取的是24位深度转换,所以得到的是一个长度为921600的无符号字符型数组,每相连的3个8bit数据组成一个24bit的像素值。
HDMI IP核中,除了包含图片数据外,还包含了IP核所必备的寄存器头文件,功能函数库的c和h文件。
b022
首先,我们从main函数开始看起。首先需要调用HDMI IP核初始化函数zircon_avalon_hdmi_init。这个函数非常简单。第一步,对HDMI IP核的控制寄存器写0,即默认HDMI IP核停止工作。第二步,对HDMI IP核的数据寄存器进行配置,将数组hdmi_buffer的首地址值写进去。第三步,对HDMI IP核的控制寄存器写1,即让DMI IP核开始工作。其中,hdmi_buffer是一个大小为640*480的深度为32bit的数组,这一数组是一个全局变量,即它预先就在SDRAM中占据了一块固定的内存。通过将数组hdmi_buffer的首地址值写入HDMI IP核的数据寄存器。则HDMI IP核就会连续对SDRAM中这块内存进行循环读取操作(起始地址为数组hdmi_buffer的首地址值,范围大小为640*480,深度为32bit)
进行完初始化之后,直接进入一个while的死循环中,在这里就执行着显示图片的操作zircon_avalon_hdmi_DisplayPic1,这里有六个显示图片函数,并且中间会有一段时间的延时。所以本工程的效果就是六张图片来回切换。我们最后来介绍下zircon_avalon_hdmi_DisplayPic1函数,这个函数就是一个连续画点函数,先将原图片数组的3个8bit数据拼成一个24bit数据,然后依次写入数组hdmi_buffer。
最后我们运行程序,来看一下效果。
总结一下,学习Nios II,我们需要关心Nios II与IP核、IP核与SDRAM之间的数据交换,也就是Avalon-MM协议,这才是我们学习的重点所在。一般我们会用一个FIFO来缓存数据(而不会用ram),解决跨时钟域的数据交换问题。大家可以发现,在本工程的效果图中,图片切换的过程中存在明显的马赛克现象,这是因为SDRAM不支持同时读写的缘故,马赛克的持续时间是由于Nios的读写速度造成的。因此,可以选择将SDRAM换成可支持同时读写的大容量SRAM芯片,不过这个成本很高。最值得尝试的解决办法就是,可以尝试使用DDR芯片,加快读写速度,缩短马赛克现象的存在时间。
相关文章推荐
- 基于basys2驱动LCDQC12864B的verilog设计图片显示
- 从MySQL中读取图片并基于VTK显示
- 基于struct2实现保存图片到mysql的blob字段和显示
- 【Python_OpenCv】笔记1:基于Python和OpenCv的图片的加载,显示和图片的保存
- 基于ZedBoard的Webcam设计(二):USB摄像头图片采集+QT显示
- 基于JSP实现数据库中图片的存储与显示(已经通过测试)
- 从零开始学习Node.js系列教程三:图片上传和显示方法示例
- 基于MFC控件STATIC显示图片数据
- 基于VUE选择上传图片并页面显示(图片可删除)
- 基于对话框的图片打开与显示
- 基于VUE选择上传图片并在页面显示(图片可删除)
- WEBGL 2D游戏引擎研发系列 第二章 <显示图片>
- 基于Jquery插件Uploadify实现实时显示进度条上传图片
- cocos2dx opengl入门系列四-显示图片
- Android(基于imx53开发板)修改内核支持HDMI显示
- 基于MongoDB GridFS取二进制数据转换为图片在jsp页面显示
- 基于RLE的图片在GBA上显示的尝试
- fancybox1.3.1 基于Jquery的插件在IE中图片显示问题
- 使用QT搭建点云显示框架系列五·基于QT的QML图像选点、动态绘制十字丝功能 ,以及纹理映射
- 基于JSP实现图片的数据库存储与显示