相信我,SDRAM真的不难(九)----基于SDRAM缓存的串口传图综合实战(UART + SDRAM + VGA)
写在前面
本文是SDRAM系列文章的第九篇,前面八篇已经实现了一个简单的SDRAM控制器。正所谓光说不练云玩家,接下来我们搞搞实战,真正把SDRAM给用起来。
本文将结合UART模块、VGA模块、SDRAM模块(含PLL、FIFO)来做一个基于SDRAM缓存的串口传图实验,实现UART发送数据、SDRAM缓存数据、VGA显示数据这一过程。
其他博文链接:
相信我,SDRAM真的不难----汇总篇(电梯直达)
1、总体架构
期待实现的功能:在PC端使用串口助手发送一幅分辨率为 640*480 的图片数据给 FPGA,FPGA 以外接 SDRAM 做缓存,将接收到的图片数据通过 VGA 显示器显示出来。
总体架构示意图如下:
- PLL模块:时钟生成模块。由于各个模块的时钟不尽相同,通过PLL统一生成时钟,全部接到全局时钟网络上
- uart_rx:串口接收模块。将接收到的串行信号,转换成8bit并行信号
- merge:数据拼接模块。将2个输入的8bit数据转换成16bit数据
- sdram_top:sdram读写控制器。可以实现高速、大量的数据缓存
- vga_driver:VGA接口驱动。实现图片(RGB565像素值)的VGA显示
这工程一看好像还挺多挺复杂的,那么我接下来就对整个图片的传送显示流程做一个讲解:
- 首先将需要显示的图片,转为RGB565格式的txt文件(16bit像素值),然后通过PC端的串口发送上位机,将数据发送给FPGA
- FPGA将通过串口接收模块uart_rx将串行线上的数据转成8bit的并行数据
- 通过数据拼接模块merge将每2个8bit数据转换成16bit数据,然后,将其写入SDRAM缓存
- 在FPGA接收数据的同时通过VGA接口,用屏幕将写入SDRAM的数据”读出“在屏幕上显示
2、设计实现
接下里就一步一步讲解具体的设计实现了。
2.1、图片预处理
图片格式:640 * 480。
图片内容:老婆。
显然我们无法直接通过串口发送图片,需要将图片转化成RGB565的像素值(其他RGB格式不讨论)才能使用VGA接口显示。我们可以先使用MATLAB将图片转换成RGB565,代码如下:
%--------------------------------------------------------------------------
%-- 图片数据转换:1个像素转换成2个 8bit hex 数据
%--------------------------------------------------------------------------
clear all;
RGB24 = imread('laopo.bmp'); %读取图片文件fid = fopen('rgb565.txt','w+'); %打开文件
[ROW,COL,N] = size(RGB24); %获得图片尺寸[高度,长度,维度]for i = 1:ROWfor j = 1:COLRG = bitand(RGB24(i,j,1),248) + bitshift(RGB24(i,j,2),-5); %{R[7:3],3'd0} + {5'd0,G[7:5]}G = bitand(RGB24(i,j,2),28); %{3'd0,G[4:2],2'd0}GB = bitshift( G,3) + bitshift(RGB24(i,j,3),-3); %{G[4:2],5'd0} + {3'd0,B[7:3]}fprintf(fid,'%02x %02x ',RG,GB);%将字符打印到txt文件中end
end
2.2、子模块
接下来介绍各个子模块的功能及实现方式。这几个子模块,都是我之前的文章写过的模块,所以等下不会介绍的很详细,会贴出链接,感兴趣的朋友可以自己去看看。
2.2.1、串口接收模块
由于我们在PC端使用UART来发送图片信息,而UART是串行协议,所以我们需要一个模块来将接收到的串行数据转为并行数据。
串口模块将PC端通过UART接口(含协议)发送过来的图片的像素信息(RGB565格式)接收,并转化为8bit并行数据。串口接收模块的波特率在本次实验中选为115200。
供参考:串口(UART)的FPGA实现
2.2.2、数据拼接模块
由于目前的主流串口发送软件很少能支持16bit数据的发送,只能将16bit的像素信息拆成2个8bit数据来发送。所以需要一个模块将分别接收的2个8bit数据合并成1个16bit数据(完整的RGB565)。
数据拼接模块将串口接收模块发送的两个8bit数据转换成16bit数据。
供参考:一个简单方便的数据拼接模块(支持任意位宽、任意整数倍)
2.2.3、SDRAM控制模块
SDRAM控制模块可以将接收到串口发送的图片信息暂存到SDRAM芯片,同时显示器也在不停地通过VGA接口对SDRAM控制模块进行操作以读取SDRAM中存取的图片信息。在640*480@60Hz时序下的VGA接口,一幅图片的大小约为640*480*16bit /8 /1024 = 600KB,这个大小显然无法使用FPGA的片内资源来缓存,所以选择SDRAM这种大容量器件来作为接收的缓存。
供参考:相信我,SDRAM真的不难----汇总篇(电梯直达)
2.2.4、VGA驱动模块
VGA驱动模块将SDRAM中缓存的图片信息以VGA时序输出,从而在显示器上显示图片。
供参考:如何用VGA接口乳法?
2.2.5、PLL模块
使用PLL模块统一生成时钟,有利于统一管理时钟,约束时序。各模块需要用到的时钟如下:
- 50M:串口接收模块、数据拼接模块使用
- 100M:SDRAM控制模块使用
- 100M(偏移-30°):SDRAM芯片使用
- 25M:VGA驱动模块使用
2.3、顶层模块
顶层模块主要实现化上述几个子模块,并设定一些参数:
- 突发长度:256
- SDRAM起始地址:0;SDRAM停止地址:640*480(刚好缓存一幅图片)
- 串口波特率:115200bps
顶层模块完整代码如下:
module pic_uart_sdram #(parameter BPS = 115200 //发送波特率
)
( input sys_clk , //50M系统时钟input sys_rst_n , //系统复位input uart_rxd , //串口接收output h_sync , //VGA行同步output v_sync , //VGA场同步output [15:0] rgb_data , //在VGA时序下的RGB数据
//SDRAM相关信号output sdram_clk_out ,output sdram_cke ,output sdram_cs_n ,output sdram_ras_n ,output sdram_cas_n ,output sdram_we_n ,output [1:0] sdram_bank ,output [12:0] sdram_addr ,output [1:0] sdram_dqm ,inout [15:0] sdram_dq
);
localparam CLK_FRE = 50_000_000 ; //输入时钟频率
localparam H_PIXEL = 24'd640 ; //水平方向像素个数,用于设置 SDRAM 缓存大小
localparam V_PIXEL = 24'd480 ; //垂直方向像素个数,用于设置 SDRAM 缓存大小//8bit转16bit模块
localparam integer DATA_WIDTH = 8 ; //输入数据位宽
localparam integer MERGE_STAGE = 2 ; //合并级数,如2则将两个数据合并为一个 //PLL
wire rst_n ; //低电平有效的复位信号,除PLL模块外均使用该信号
wire locked ; //PLL输出稳定信号,高电平有效
wire pll_50M ; //用于串口模块
wire pll_100M ; //用于SDRAM
wire pll_100M_shift ; //用于SDRAM
wire pll_25M ; //用于25M
//uart
wire [7:0] rx_data; //接收到的串口数据
wire rx_flag; //串口数据有效
//VGA
wire pix_data_req; //RGB数据请求信号,用作SDRAM的读请求
wire [15:0] sdram_rd_data; //从SDRAM中读出的数据
//merge
wire [15:0] data_16bit; //8bit转16bit后的数据
wire data_16bit_valid; //16bit数据有效信号assign rst_n = sys_rst_n & locked; //PLL未稳定视为复位状态//例化PLL
clk_gen clk_gen_inst (.areset (~sys_rst_n ), //.inclk0 (sys_clk ), //50M输入.c0 (pll_50M ), //50M.c1 (pll_100M ), //100M.c2 (pll_100M_shift ), //100M_SHIFT.c3 (pll_25M ), //25M.locked (locked ) //PLL输出稳定信号,高电平有效
);
//例化VGA驱动模块(640*480@60,时钟25M)
vag_driver vag_driver_inst( .vga_clk (pll_25M ), //VGA时钟.sys_rst_n (rst_n ), //复位信号、低电平有效.pixel_data (sdram_rd_data ), //输入RGB数据 .h_sync (h_sync ), //行同步信号 .v_sync (v_sync ), //场同步信号.pixel_x ( ), //行坐标,不需要使用.pixel_y ( ), //场坐标,不需要使用.pix_data_req (pix_data_req ), //RGB数据请求信号,比rgb_valid提前一拍.rgb_data (rgb_data ) //在VGA时序下的RGB数据
);
//例化8bit转16bit模块
merge #(.DATA_WIDTH (DATA_WIDTH ), //输入数据位宽.MERGE_STAGE (MERGE_STAGE ) //合并级数,如2则将两个数据合并为一个。
)
merge_inst( .sys_clk (pll_50M ), //50M系统时钟.sys_rst_n (rst_n ), //系统复位.data_in (rx_data ), .data_in_valid (rx_flag ), .data_out (data_16bit ),.data_out_valid (data_16bit_valid )
);//例化串口接收模块
uart_rx
#(.BPS (BPS ), //发送波特率.CLK_FRE (CLK_FRE ) //输入时钟频率
)
uart_rx_inst( .sys_clk (pll_50M ), //50M系统时钟.sys_rst_n (rst_n ), //系统复位 .uart_rxd (uart_rxd ), //接收数据线 .uart_rx_done (rx_flag ), //数据接收完成标志,当其为高电平时,代表接收数据有效.uart_rx_data (rx_data ) //接收到的数据,在uart_rx_done为高电平时有效
);//例化SDRAM控制模块
sdram_top sdram_top_inst
(.sdram_clk (pll_100M ), //sdram时钟.sdram_rst_n (rst_n ), //sdram复位信号 .clk_out (pll_100M_shift ), //sdram相位偏移时钟(直接给SDRAM芯片)
//写FIFO信号 .wr_fifo_rst (~rst_n ), //写FIFO复位信号 .wr_fifo_wr_clk (pll_50M ), //写FIFO写时钟 .wr_fifo_wr_req (data_16bit_valid ), //写FIFO写请求.wr_fifo_wr_data (data_16bit ), //写FIFO写数据.sdram_wr_b_addr (0 ), //写SDRAM首地址.sdram_wr_e_addr (H_PIXEL*V_PIXEL ), //写SDRAM末地址.wr_burst_len (256 ), //写SDRAM数据突发长度.wr_fifo_num ( ), //写fifo中的数据量
//读FIFO信号 .rd_fifo_rd_clk (pll_25M ), //读FIFO读时钟,与VGA时钟一致.rd_fifo_rst (~rst_n ), //读复位信号 .rd_fifo_rd_req (pix_data_req ), //读FIFO读请求.sdram_rd_b_addr (0 ), //读SDRAM首地址.sdram_rd_e_addr (H_PIXEL*V_PIXEL ), //读SDRAM末地址.rd_burst_len (256 ), //读SDRAM数据突发长度.rd_fifo_rd_data (sdram_rd_data ), //读FIFO读数据,用于VGA显示的数据.rd_fifo_num ( ), //读fifo中的数据量
//功能信号 .read_valid (1'b1 ), //SDRAM读使能.init_end ( ), //SDRAM初始化完成标志
//SDRAM接口信号 .sdram_clk_out (sdram_clk_out ), //SDRAM芯片时钟.sdram_cke (sdram_cke ), //SDRAM时钟有效信号.sdram_cs_n (sdram_cs_n ), //SDRAM片选信号.sdram_ras_n (sdram_ras_n ), //SDRAM行地址选通脉冲.sdram_cas_n (sdram_cas_n ), //SDRAM列地址选通脉冲.sdram_we_n (sdram_we_n ), //SDRAM写允许位.sdram_bank (sdram_bank ), //SDRAM的L-Bank地址线.sdram_addr (sdram_addr ), //SDRAM地址总线.sdram_dqm (sdram_dqm ), //SDRAM数据掩码.sdram_dq (sdram_dq ) //SDRAM数据总线
);endmodule
3、仿真
略。因为VGA的时序如果不改动参数仿真,那么时间就太长了;改了吧,看起来意义又不大。干脆不仿真了,直接看现象吧。
4、上板验证
验证环境:
- 串口上位机:野火多功能调试助手
- MATLAB:MATLAB R2014a
- Quartus II:Quartus II 13.1 (64-bit)
- FPGA:EP4CE10F17C8
- SDRAM:W9825G6KH-6
需要注意的是因为串口的发送速度太慢了,而VGA读取的速度又相对较快,所以看起来,图片是一行、一行的显示出来的。实验结果如下:
5、其他
- 创作不易,如果本文对您有帮助,还请多多点赞、评论和收藏。GAKKI都来了,你好意思不给我点赞?
- 关于本文,您有什么想法均可在评论区留言交流。如果需要整个工程,请在评论留下邮箱或者私信我邮箱(注意保护隐私)。
- 自身能力不足,如有错误还请多多指出!
版本信息
文件:V1.0
编号:69
Vivado:无
Modelsim:无
Quartus II:Quartus II 13.1 (64-bit)
相信我,SDRAM真的不难(九)----基于SDRAM缓存的串口传图综合实战(UART + SDRAM + VGA)相关推荐
- 相信我,SDRAM真的不难(一)----初识SDRAM
写在前面 本文是SDRAM系列文章的第一篇,旨在对SDRAM做一个初步的介绍与认识. 其他博文链接:相信我,SDRAM真的不难----汇总篇(电梯直达) 1.什么是SDRAM SDRAM(Synchr ...
- 相信我,SDRAM真的不难(二)----初始化操作
写在前面 本文是SDRAM系列文章的第二篇,对SDRAM的初始化操作进行了详细介绍.代码编写与仿真验证. 其他博文链接:相信我,SDRAM真的不难----汇总篇(电梯直达) 1.初始化 SDRAM 的 ...
- 相信我,SDRAM真的不难(四)----写操作(页突发模式)
写在前面 本文是SDRAM系列文章的第四篇,对SDRAM的突发写操作进行了详细介绍.代码编写与仿真验证. 其他博文链接:相信我,SDRAM真的不难----汇总篇(电梯直达) 1.写操作 SDRAM提供 ...
- 基于 DDR3 的串口传图帧缓存系统设计实现(整体设计)
文章目录 前言 一.串口传图顶层系统设计框图 二.各模块说明 三.系统工程及 IP 创建 四.uart_ddr3_tft模块 五.uart_ddr3_tft模块仿真文件 六.传图展示 前言 结合串口接 ...
- 基于 DDR3 的串口传图帧缓存系统设计实现(fifo2mig_axi )
文章目录 前言 一.接口转换模块设计 二.fifo2mig_axi 模块 二.接口转换模块仿真 四.fifo2mig_axi_tb 五.仿真展示 前言 结合串口接收模块和 tft 显示屏控制模块,设计 ...
- 相信我,SDRAM真的不难----汇总篇
- 基于DDR3的串口传图帧缓存系统设计实现
整体设计框图如图所示 模块名称 模块功能 uart_byte_rx模块 负责串口图像数据的接收 bit8_trans_bit16模块 将串口接收的每两个 8bit 数据转换成一个 16bit 数据(图 ...
- FPGA uart+sdram+vga传图
项目介绍 注意事项 这个练手项目本来在七月份就完成了,但是其中有个bug我怎么改也改不了,其中的sdram看了下b站上明德扬的sdram视频,然后借鉴了他们的摄像头采集模块的sdram代码,这里的主要 ...
- Jquery真的不难~第八回 JS的闭包问题
百度百科中对闭包的定义: 闭包是可以包含自由(未绑定到特定对象)变量的代码块:这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义."闭包" 一词来源 ...
最新文章
- mlcc激光雷达与相机外参标定初体验
- 怎样判断子进程已经结束 process.waitFor();的问题
- pytorch 笔记:torch.nn.Conv2d
- EL表达式 JSTL(详解)
- 【模拟】游戏(jzoj 1614)
- 云计算-从基础到应用架“.NET研究”构系列-云计算的演进
- 百度BCC云解析配置(新旧文档对比) - (文档篇)
- iOS 接入微信 支付宝 参数设置
- Linux系统文件管理以及连接文件和inode简介
- MFC界面开发帮助文档:BCG可视化设计器使用指南
- 蓝宝石rx470d原版bios_狼神矿卡烤机89°C!强刷蓝宝石RX570超白金显卡BIOS降温75°教程...
- 【科普】数字货币的基石--区块链
- matlab二项式,动态规划 – 计算二项式系统 —MATLAB代码 – 算法网
- MySQL 报OperationalError: (1130, “XX‘ is not allowed to connect to this MySQL server“)的正确解决方法
- Apache Log4j2 漏洞解决办法
- 【考试题解】 递归递推
- 智科模式识别期末大课设:多种方法对数据集进行手写数字识别(数据集:MINIST)
- DoIP协议从入门到精通系列——车载网络拓扑
- DICOM:DICOM万能编辑工具之Sante DICOM Editor
- secureCRT,永久设置,保护眼睛,配色方案