完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
`本文和设计代码由FPGA爱好者小梅哥编写,未经作者许可,本文仅允许网络论坛复制转载,且转载时请标明原作者。 在嵌入式系统中,LCD屏作为最友好的人机交互方式,被大量的应用到了各个系统中。在基于ARM处理器的系统中,应用更是非常广泛。FPGA作为广义嵌入式系统的一员,自然也有很多时候需要来驱动显示屏显示一些内容,例如经常有需求要用FPGA来做液晶测试架,做显示器驱动测试卡。很多学习了FPGA的朋友都知道,FPGA驱动VGA显示器是比较轻松的,几乎每个板卡商提供的资料中都提供了有诸如显示彩条,显示图案,甚至显示简单的文字。但是,当希望显示更加复杂的内容的时候,往往就很难办到了。因为FPGA设计的是电路,是硬件,特点是头脑简单,四肢发达。而显示复杂的内容,恰恰需要一个头脑发达的控制器来执行这项任务。 在FPGA这些年的发展中,先后经历了简单逻辑扩展、复杂逻辑设计、SOPC系统和SOC系统,逻辑设计部分就不多说了,对于SOPC系统设计,Xilinx家有MicroBlaze软核、Altera家有大名鼎鼎的NIOS II软核处理器。而到了SOC时代,Xilinx家和Altera(现已被因特尔收购,成为Intel的可编程事业部)都推出了内嵌双核ARM Cortex-A9的SOC芯片,Xilinx家著名的zynq7000系列,以及Altera花了大力气在高校推广的Cyclone V SOC。 虽然随着技术的发展以及时间的推移,SOC的应用会越来越广泛,但是作为我们一般学习和使用来说,SOPC技术也还是有其使用的价值的,毕竟内嵌硬核的SOC芯片,动辄几百块,而使用软核的方案,只要40元不到的BOM成本就能完成一个系统设计,优势还是很明显的。本例,我们就带领大家使用Altera Cyclone IV系列最低端的FPGA芯片EP4CE6/EP4CE10设计的能够驱动640*480分辨率显示屏动态显示复杂内容的系统。例如显示文字,显示图片 在之前我们讲解过RGB显示屏的驱动,RGB显示屏驱动时序和VGA驱动时序几乎完全一样,只是不同的分辨率之间,其时序参数不同。说到这个驱动480*272分辨率显示屏动态显示复杂内容,相信很多朋友并不陌生,是的,在我们之前的SOPC公开课时候,就已经给大家讲解过实现这种系统的一种方式,即使用了一片独立的SRAM来作为显示屏的显存,显示驱动模块直接读取SRAM中的数据并实时刷新显示,而NIOS II CPU则只在需要刷新显示内容的时候,才执行对SRAM的写入操作。此种方式,需要一片独立的SRAM作为显存,以及一片SDRAM作为NIOS II的运行内存。除了SRAM的使用会增加系统的BOM成本外,SRAM也会占用掉FPGA芯片较多的管脚,导致必须得使用256脚BGA方案的芯片才能够实现。因此,此种方案仅适合在对成本不太敏感高的场合使用。本节要介绍的方案,是对该系统改进优化得到的。 本节所描述的系统,仅需用到以下硬件资源 1. EP4CE6/EP4CE10型FPGA芯片一片(30元) 2. 16Mbit 或以上SDRAM芯片一片(3元,如华邦w9816g6) 3. 50M有源晶振一片(3元) 4. 4Mbit SPI FLASH芯片(1.5元,如W25Q80) 5. 3.3V、2.5V、1.2V LDO稳压电源(AMS117系列,合计不到1元) 本节希望达到的目的: 在显示屏上显示一帧图像,并在指定位置显示字符内容 1 上述框架是我们经过分析,要实现本系统方案所需的最小硬件系统,本节我们将基于芯航线的AC620学习套件来完成FPGA的系统搭建和NIOS II软件设计。芯航线的AC620 FPGA开发板整体硬件配置高于上述分析,有助于我们进行原型验证。 FPGA系统搭建 本系统主要在Qsys系统中完成,包含了以下IP核: clk_0:输入时钟管理单元,系统默认添加 altpll_0:PLL锁相环,对输入时钟进行分频和倍频,以得到两路频率为100MHz,相位相差180度的时钟信号,分别提供给系统中逻辑电路工作(包含NIOS II软核处理器)和SDRAM芯片使用。以及1路24M的时钟信号,供640*480分辨率的VGA驱动电路使用。 NIOS II CPU:实现系统的控制以及显示内容的处理。 SDRAM:NIOS II CPU运行内存和TFT显示图像帧缓存。 onchip_memory:片上存储器,指定SGDMA要执行的数据传输,主要用作SGDMA的描述符存储器。 lcd_sgdma:SGDMA IP,主要实现大量数据的高效搬运,支持流模式,效率比Avalon MM接口的DMA核高。 timing_adapter:时序匹配IP核,主要用于流数据在两个不同模块间进行传递时,对部分信号加上一定延迟,使得数据和标志信号能够完全同步(说的简单点儿,就是用寄存器打拍的方式对一些信号进行延迟,使数据和控制信号对齐)。 fifo:双时钟fifo,主要完成数据流的传输速度转换。SGDMA输出的数据流,是按照和存储器相同的时钟速度(本例中为100M)进行的,而在数据使用端,即VGA显示部分,是按照9M的时钟取用数据的,因此使用双时钟fifo,解决跨时钟域的问题。 VGA_SINK:该IP为第三方开源IP,由友晶科技提供,主要完成Avalon ST流数据转换成VGA行场时序并驱动VGA屏进行显示。 EPCS:EPCS FLASH存储器控制IP,使用该IP,使得EPCS芯片能够存储FPGA固件和NIOS II的程序。 jtag_uart0:调试串口,主要用来打印一些调试信息,在设计的前期调试中很有用 2 接下来,将详细讲解本系统的搭建过程。 1、 altpll_0 为了保证整个系统能够具有较高的性能,因此让其运行在100MHz,所以需要使用PLL对外部晶振产生的50MHz输入的时钟信号进行倍频,得到两路频率为100M,相位相差90度的时钟信号。另外,还需要提供一路9MHz时钟信号供480*272分辨率的TFT屏驱动使用。关于PLL的详细添加和参数修改方式这里不再多说,仅提供设置结果: inclk0:50M 不需要areset信号和locked信号 c0:9MHz c1:100MHz,相位为0 c2:100MHz,相位为-180度 2、 nios ii cpu 所有设置使用默认值,等后续添加完sdram和EPCS和,将复位向量(Reset Vector)设置为epcs,将异常向量(Exception Vector)设置为sdram。 3、 sdram 数据位宽(Data Width)为16bit。 结构(Architecture)为一个片选,4个bank。 地址宽度(Address Width)Row地址为12、Column地址为9。 其他默认即可。 3 4、 onchip_memory 片上缓存onchip_memory作为SGDMA的描述符存储器,存储SGDMA的数据传输描述内容。 类型为RAM; 数据位宽选择32位; 存储器总量选择16384Bytes(用户可以根据自己芯片的RAM容量适当增加或减小该值); 4 5、 lcd_sgdma 选择传输模式为存储器到数据流模式(Memory To Streram); 数据宽度(Data width)为16bit,该位宽与存储器(SDRAM)的Avalon MM总线宽度一致。 其他按照默认即可,如下图所示。 5 6、 timing_adapter 时序匹配IP核,主要用于流数据在两个不同模块间进行传递时,对部分信号加上一定延迟,使得数据和标志信号能够完全同步(说的简单点儿,就是用寄存器打拍的方式对一些信号进行延迟,使数据和控制信号对齐)。 如下图所示设置,所有勾选项都勾选上,输入Ready Latency设置为0,输出Ready Latency设置为1,每个数据总共有两个symbols,每个symbol含8位数据。(根据RGB数据流的实际意义,这里应该是每个数据有3个symbols,但是本设计使用的是16位色RGB565模式,即RGB总共才16位,所以在搭建系统的时候,假设只有2个symbols,只是在最终数据输出到VGA的时候,将16bit数据拆分成RGB565,分别送给VGA的R、G、B色通道) 6 以上各个模块,都是工作在100MHz的时钟频率下。主要完成将需要显示的数据从SDRAM中读取出来。而读取出来的数据最终是需要送到TFT显示屏上去显示的,TFT显示部分,对于本系统,数据传输速率为9M,因此就需要实现数据从100M时钟域到9M时钟域的跨时钟域传输。而实现数据流跨时钟域传输,较好的方式是使用双时钟fifo。因此,接下来就需要添加一个双时钟fifo,先将100M时钟域的数据缓存起来,然后再等待9M时钟域的读取逻辑来读取。 7、 fifo 设置fifo的深度为512字节,每个数据含2个symbols,每个symbols由8位数据组成,即整个数据宽度为16位。时钟设置为双时钟模式(Dual Clock Mode),输入和输出都使用Avalon ST接口,使能数据包(Enable Packet Data)。这里顺带说一下,Cyclone IV E器件中的嵌入式块RAM为M9K存储器,每个器件里都有若干个M9K存储器。所谓M9K存储器,就是一个块存储器中有9Kb个存储位,每个M9K存储器可以被配置为以下模式: 8192 × 1 4096 × 2 2048 × 4 1024 × 8 1024 × 9 512 × 16 512 × 18 256 × 32 256 × 36 由于本设计中,数据是16位的,因此,如果要想仅使用一个M9K存储器就实现本Fifo,存储深度可在1到512之间任选。假如我们选择存储深度为128,那么就只占用1/4个M9K的存储容量,但是,剩下的3/4的存储容量也依旧无法单独使用,在该设计中会永远的被浪费掉,因此,不如将存储深度直接设置为512,还能保证缓存足够大,避免意外丢失数据。 7 8、 VGA_SINK VGA_SINK模块是从友晶提供的设计中修改得到的,该IP原本仅支持24位色模式,而本系统,由于SDRAM为16位宽度,如果强行使用24位色模式,则必须得从SDRAM中读取两个数据才能拼接成一个像素,导致SDRAM的负载过大,从而使得系统带宽遇到瓶颈,无法正常工作,因此对该IP进行了修改,即降低为16bit的RGB565模式。 (根据RGB数据流的实际意义,这里应该是每个数据有3个symbols,但是本设计使用的是16位色RGB565模式,即RGB总共才16位,所以在搭建系统的时候,假设只有2个symbols,只是在VGA_SINK模块内部,在最终数据输出到VGA的时候,进行了修改,将16bit数据拆分成RGB565,分别送给VGA的R、G、B色通道)。这里参数分别如下设置: H_DISP(行显示有效像素):640 H_FPORCH:16时钟周期 H_SYNC:96时钟周期 H_BPROCH:48时钟周期 V_DISP(行显示有效像素):480 V_FPORCH:1时钟周期 V_SYNC:2时钟周期 V_BPROCH:33时钟周期 8 这些参数都是从VGA标准中查到的。 9、EPCS EPCS的添加没有什么需要特别注意的,一切按照默认设置即可。 至此,我们已经完成了整个显示系统的组件添加工作,接下来就该进行组件间的总线连接了。 在总线连接之前,必须要先给大家讲解一下本系统的数据流向,因为本系统和我们之前在SOPC公开课时候讲过的系统架构还不太一样,本系统主要引入了Avalon ST总线。在之前公开课时候讲过的各种例子,都是基于Avalon MM总线的,所有外设IP都通过Avalon MM总线连接到NIOS II CPU上,因此总线连接是非常简单的。但是Avalon MM总线的数据搬运能力是比较弱的,无法支持高速大量的数据传输。而在基于Avalon ST总线的数据流中,NIOS II CPU实质相当于被旁路了,只起到了状态管理的作用,所有的数据流转都是模块间通过Avalon ST总线进行交互的,不需要NIOS II去执行搬运工作,因此数据的搬运效率大大提高。 本节暂不对Avalon ST总线进行过多的讲解,总之,我们可以把Avalon ST总线想象成一个水管,水从水管的一头可以很容易且快速的流到另一头,不需要第三方用水瓢一瓢一瓢的去舀过去。 Framebuffer系统数据流 在整个FrameBuffer系统中,SGDMA模块是最核心的部分,他实现了对SDRAM存储器的直接读取操作,并将读到的数据最终以数据流的形式输出。SGDMA的使用相当的广泛,不仅是在本系统中,在Altera很多官方设计中也都使用了SGDMA IP核,比如PCIE 示例、千兆以太网示例、VIP示例等,关于SGDMA的详细介绍,可以参看SGDMA的用户手册,我们也希望能尽快推出SGDMA的专题讲解。这里仅对SGDMA的端口和功能进行下简述。 本系统中SGDMA被配置为存储映射模式到数据流模式,即数据的源头采用地址映射的方式组织,而数据的接收方则使用数据流的方式进行接收。在此种模式下,SGDMA总共有5个端口,分别为Avalon MM Slave接口的控制总线,Avalon MM Master接口源数据读取总线、Avalon MM Master接口的描述符写入总线和Avalon MM Master接口的描述符读取总线,以及最终的Avalon ST Source数据输出总线。 9 csr:Avalon MM Slave接口的控制总线,与NIOS II CPU进行连接,NIOS II CPU通过该接口读写SGDMA内部的控制和状态寄存器,以实现DMA的传输控制。这也是整个数据流传输唯一需要NIOS II参与的地方。NIOS II实际就扮演了个老板的角色,安排SGDMA去做什么,SGDMA接到任务后就下去干搬运的苦力活儿了,而NIOS II这个老板,则可以坐在办公室喝喝咖啡,看看报纸,等着SGDMA把苦力干完后回来报告(中断)或者隔一段时间打个电话问问工作状态和进度(查询)。 m_read:Avalon MM Master接口的源数据读取总线,该接口实现对Avalon MM总线上挂载的存储需要传输的数据源存储器的读取,例如SDRAM、DDR2 SDRAM。从这里,大家也可以看到,在Qsys搭建的系统中,不是只有NIOS II能够去读取SDRAM、DDR2等存储器,实际上,只要是Avalon MM Master接口的IP,都可以去读取这些存储器,我们甚至可以自己编写一个Avalon MM Master接口的逻辑,来取代NIOS II CPU完成各种IP核的读写操作。 descriptor_write:描述符写端口,SGDMA实现数据传输需要有一个描述符,SGDMA的所有传输都是受描述符控制的,通过描述符存储SGDMA的实时传输状态。这里专门使用一个片上存储器来存储SGDMA的描述符,能够节省FPGA资源。否则,如果使用FPGA资源来实现描述符,将会带来非常大的资源消耗。 descriptor_read:描述符读端口,SGDMA使用此端口读取描述符,以获得传输信息。 out:数据流输出端口,从SDRAM或DDR2中读取到的数据会经由此端口流出,以提供给数据的使用端使用。 对于我们分析数据流来说,可以暂时忽略csr、descriptor_write和descriptor_read端口,因为这些端口并不处于数据通路上,真正处于数据通路上的,是m_read(数据流入)和out(数据流出)端口。下图为本系统的数据流图。 10 NIOS II CPU使用SDRAM作为运行存储器,存储程序和数据,同时,SGDMA从SDRAM中实时读取需要显示到VGA屏上的数据。NIOS II 和 SGDMA之间对SDRAM的使用仲裁由Avalon MM总线的仲裁机制自动处理。 通过以上介绍,了解了系统的数据流向,就可以首先完成数据流总线的连接了。每个st 流接口的模块都有2个流端口,一个是流输入端口(in: Avalon Streaming Sink),另一个是流输出端口(out: Avalon Streaming Source)。连接时,只需将上一级模块的流out连接到下一级模块的流in端口,即可实现数据流的自动衔接。在本例中每个模块端口连接如下表所示: 11 整体连接完成后,结果如下图所示: 12 当然,连接完成总线后,不要忘了连接复位网络、导出需要引出到系统顶层的信号以及中断网络。 修改NIOS II的复位向量为EPCS、异常向量为SDRAM。 自动分配基地址。 到HDL Eaxmple栏复制例化模版。 保存并开始generate。 至此,整个系统就搭建完成了,下一步就是将系统加入到Quartus II工程中。首先是将mysystem.qsys文件添加到工程,然后完成工程顶层文件的编写。这些最基本的操作,这里就不在赘述,以下为工程顶层代码: module Framebuffer_VGA( input wire clk_50m, input wire reset_n, output wire vga_clk, output wire vga_de, output wire [7:0] vga_r, output wire [7:0] vga_g, output wire [7:0] vga_b, output wire vga_hs, output wire vga_vs, output wire vga_bl, output wire sdram_clk, output wire [11:0] sdram_addr, output wire [1:0] sdram_ba, output wire sdram_cas_n, output wire sdram_cke, output wire sdram_cs_n, inout wire [15:0] sdram_dq, output wire [1:0] sdram_dqm, output wire sdram_ras_n, output wire sdram_we_n, output wire epcs_dclk, output wire epcs_sce, output wire epcs_sdo, input wire epcs_data0 ); assign vga_bl = 1; wire vga_clk_r; assign vga_clk = ~vga_clk_r; //对VGA时钟反相,以保证数据中心对齐 mysystem u0 ( .clk_50m_clk (clk_50m), .reset_50m_reset_n (reset_n), .vga_clk (vga_clk_r), .vga_de (vga_de), .vga_r (vga_r), .vga_g (vga_g), .vga_b (vga_b), .vga_hs (vga_hs), .vga_vs (vga_vs), .altpll_0_phasedone_conduit_export (), .altpll_0_locked_conduit_export (), .altpll_0_areset_conduit_export (), .epcs_dclk (epcs_dclk), .epcs_sce (epcs_sce), .epcs_sdo (epcs_sdo), .epcs_data0 (epcs_data0), .sdram_clk_clk (sdram_clk), .sdram_addr (sdram_addr), .sdram_ba (sdram_ba), .sdram_cas_n (sdram_cas_n), .sdram_cke (sdram_cke), .sdram_cs_n (sdram_cs_n), .sdram_dq (sdram_dq), .sdram_dqm (sdram_dqm), .sdram_ras_n (sdram_ras_n), .sdram_we_n (sdram_we_n) ); endmodule 然后分配引脚,本系统在AC620开发板上的引脚分配请参照AC620开发板引脚分配表。 分配引脚后,记得在quartus ii软件中设置所有双功能引脚为用户模式。 13 编译工程得到sof编程文件。 至此,整个FrameBuffer系统硬件设计就完成了,下一步,我们就可以编写相应的驱动程序和应用程序,在目标板上运行了。 创建Eclipse工程 打开NIOS II EDS软件,导入我们提供的VGA和VGA_bsp两个工程。修改setting.bsp文件中第7行和第9行两个位置为自己电脑上对应的位置。关闭文件,然后build工程。如果编译失败,提示无权限,请先关闭所有文件,然后选择整个文件夹右键获取管理员权限。 14 以下为main函数内容 #include "stdio.h" #include "stdlib.h" #include "io.h" #include "sys/alt_alarm.h" #include "altera_avalon_sgdma.h" #include "altera_avalon_sgdma_descriptor.h" #include "altera_avalon_sgdma_regs.h" #include "alt_types.h" #include "alt_video_display.h" #include "unistd.h" #include "pic1.h" #include "pic2.h" #include "system.h" #define WIDTH 640 #define HEIGHT 480 #define NUM_FRAME 1 int main() { unsigned int d = 0; ////Initial LCD Display alt_video_display* display_global; // printf("Initializing LCD display controller "); display_global = alt_video_display_init(LCD_SGDMA_NAME, // Name of video controller WIDTH, // Width of display HEIGHT, // Height of display 16, // Color depth (32 or 16) SDRAM_BASE + SDRAM_SPAN / 2, // Where we want our frame buffers ONCHIP_MEMORY_BASE, // Where we want our descriptors NUM_FRAME); // if (display_global) // printf(" - LCD Initialization OK "); // else // printf(" - LCD FAILED "); alt_video_display_clear_screen(display_global, 0xff); show_pic(display_global, pic1); usleep(1000000); while(1){ } } 编译完成后下载sof,并在nios ii eds中执行run。连接VGA显示器,就能在屏幕上显示一副美女图,如下图所示: |
|
相关推荐
|
|
1539 浏览 1 评论
助力AIoT应用:在米尔FPGA开发板上实现Tiny YOLO V4
1077 浏览 0 评论
2619 浏览 1 评论
2306 浏览 0 评论
矩阵4x4个按键,如何把识别结果按编号01-16(十进制)显示在两个七段数码管上?
2578 浏览 0 评论
2036 浏览 55 评论
6038 浏览 113 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-29 05:55 , Processed in 0.545232 second(s), Total 65, Slave 47 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号