HDMI系列之一:基于Nios II的HDMI显示图片
来源:互联网 发布:营销活动数据库设计 编辑:程序博客网 时间:2024/04/29 10:00
一休哥将在本文中介绍一个基于Nios II的HDMI显示图片的工程。我将主要分三个部分来介绍这一工程,从而实现工程效果。
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 Interfaceoutput [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; //VGAoutput 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文件。
首先,我们从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芯片,加快读写速度,缩短马赛克现象的存在时间。
- HDMI系列之一:基于Nios II的HDMI显示图片
- 8168 HDMI显示图片
- 基于S5PV210的HDMI移植
- HDMI
- HDMI
- HDMI
- hdmi
- HDMI
- 基于3520D的HDMI产品设计
- S5PV210 WINCE HDMI全屏显示的问题
- HDMI支持的视频显示格式
- 基于IMX6UL添加 HDMI
- 基于NIOS-II的示波器:PART2 界面动态显示功能
- 基于nios II的verilog VGA字符显示控制
- s5pv210 HDMI 显示实现
- zedboard demo hdmi显示
- 基于NIOS 2 的网络通信(使用cyclone II EP2C35F672C6)【图片不能显示,正在处理中】
- Uboot中支持lcd和hdmi显示不同的logo图片
- [Lintcode]最长公共前缀
- 公众号运营攻略:教你一天涨粉200以上
- Ubuntu交叉编译libusb库
- tyvj1463[智商问题]
- Oracle的外连接内连接和自连接
- HDMI系列之一:基于Nios II的HDMI显示图片
- 内部函数和外部函数
- java的继承
- Mybatis数据库中的rollback怎么个使用法
- 前端面试题笔试题汇总-收集各大网络论坛
- Java基础知识
- 冒泡排序的简单理解
- 使用Django rest framework api时,客户端返回结果为html标签
- Java网络爬虫-总结