简介

DE2开发板上使用串口接收PC发送的640*480分辨率灰度图,存入SRAM,通过VGA进行显示。

开发板:DE2
型号:EP2C35F672C6
开发工具:Quartus II 13.0 + Modelsim 10.5 SE
全局时钟: 50M
VGA时钟:25M
SRAM大小:256k*16bit,总共512kb

目前还不会用SDRAM,先从简单的SRAM入手。
由于640*480分辨率的24位彩色图片需要900kbSRAM装不下,所以使用8位灰度图(300kb)。
SRAM256k*16bit,为了存下300kb的灰度图,我将其包装为512k*8bit

RTL视图


一共五个模块:PLL、串口接收、写入地址计数、SRAM驱动、VGA驱动

PLL模块为VGA驱动模块提供25M时钟。

串口接收模块接收来自PC发送的图片数据。

写入地址计数模块根据接收到的数据,产生写入地址,并在接收完整张图片后,输出receive_done信号,允许VGASRAM读取数据。

SRAM驱动模块对SRAM芯片进行读写。

VGA驱动模块产生VGA时序显示图片。

串口接收模块

波特率:115200
数据位:8
校验:
停止位:1

module uart_rx(// clk, rst_ninput               clk,input               rst_n,// uart rxinput               rx,// valid data outputoutput reg          valid,output reg [7:0]    data
);parameter CLK_FRE      = 50_000_000;parameter BAUD_RATE    = 115200;       // 默认115200波特率parameter cnt_baud_max = CLK_FRE / BAUD_RATE - 1;  // 115200波特率下是434时钟周期一波特// 打两拍防止亚稳态,rx_3用于检测rx下降沿reg         rx_1;reg         rx_2;reg         rx_3;// 工作使能reg         work_ena;// 波特计数器 比特计数器reg [8:0]   cnt_baud;reg [4:0]   cnt_bit;// 计数器使能、清零wire        cnt_baud_ena;wire        cnt_baud_end;wire        cnt_bit_ena;wire        cnt_bit_end;// data移位寄存器reg [7:0]   data_shift;// valid打一拍再输出,和data同步输出reg         valid_reg;// 打两拍防止亚稳态always @(posedge clk, negedge rst_n) beginif(!rst_n) beginrx_1 <= 0;rx_2 <= 0;rx_3 <= 0;end else beginrx_1 <= rx;rx_2 <= rx_1;rx_3 <= rx_2; endend// rx下降沿检测,出现下降沿开始工作,接收完数据结束工作always @(posedge clk, negedge rst_n) beginif(!rst_n) beginwork_ena <= 0;end else beginif(~rx_2 & rx_3)work_ena <= 1;else if(cnt_bit_ena && cnt_bit_end)work_ena <= 0;endend// 波特计数器always @(posedge clk, negedge rst_n) beginif(!rst_n)cnt_baud <= 0;else if(cnt_baud_ena) beginif(cnt_baud_end)cnt_baud <= 0;elsecnt_baud <= cnt_baud + 1;end elsecnt_baud <= 0;endassign cnt_baud_ena = work_ena;assign cnt_baud_end = (cnt_baud == cnt_baud_max);// 比特计数器always @(posedge clk, negedge rst_n) beginif(!rst_n)cnt_bit <= 0;else if(cnt_bit_ena) beginif(cnt_bit_end)cnt_bit <= 0;elsecnt_bit <= cnt_bit + 1;endendassign cnt_bit_ena = (cnt_baud == cnt_baud_max / 2);assign cnt_bit_end = (cnt_bit == 8);// data移位寄存器always @(posedge clk, negedge rst_n) beginif(!rst_n)data_shift <= 0;else if(cnt_bit_ena)data_shift <= {rx_2, data_shift[7:1]}; end// 内部valid_reg有效信号always @(posedge clk, negedge rst_n) beginif(!rst_n) beginvalid_reg <= 0;end else if(cnt_bit_ena && cnt_bit_end)valid_reg <= 1;elsevalid_reg <= 0;end// valid_reg 打一拍再输出,和data同步always @(posedge clk, negedge rst_n) beginif(!rst_n)valid <= 0;elsevalid <= valid_reg;end// 输出dataalways @(posedge clk, negedge rst_n) beginif(!rst_n)data <= 0;else if(valid_reg)data <= data_shift;endendmodule

写入地址计数模块

根据串口接收模块接收到的数据,输出该数据需要写入SRAM的地址,接收完整张图片后,拉高receive_done信号,允许VGA模块读取SRAM中的数据。

module uart_rx_addr(input clk,input rst_n,// uart_rx sideinput valid,// sram_ctrl sideoutput reg receive_done,output reg [18:0] addr
);wire cnt_end = (addr == 640 * 480);always @(posedge clk, negedge rst_n) beginif(!rst_n)addr <= 0;else if(valid) beginif(cnt_end)addr <= 0;elseaddr <= addr + 1;endend// 串口传完整张图后,拉高receive_done,允许vga从sram中读取数据always @(posedge clk, negedge rst_n) beginif(!rst_n)receive_done <= 0;else if(cnt_end)receive_done <= 1;endendmodule

SRAM驱动模块

SRAM256k*16bit,为了存下300kb的灰度图,我将其包装为512k*8bit,写优先。
包装方法:地址低于256k的数据写入SRAM的数据位低8位,地址高于高256kb数据写入SRAM的数据位高8位

module sram_ctrl(input               clk,input               rst_n,// wrinput               wr_req,input   [18:0]      wr_addr,input   [7:0]       wr_data,// rdinput               rd_req,input   [18:0]      rd_addr,output reg  [7:0]   rd_data,// sram sideoutput  [17:0]      SRAM_ADDR,inout   [15:0]      SRAM_DQ,output              SRAM_WE_N,output              SRAM_OE_N,output              SRAM_UB_N,output              SRAM_LB_N,output              SRAM_CE_N
);assign SRAM_CE_N = 0;assign SRAM_OE_N = 0;assign SRAM_DQ   = wr_req ? (SRAM_LB_N ? {wr_data, 8'hzz} : {8'hzz, wr_data}) : 16'hzzzz;assign SRAM_WE_N = ~wr_req;assign SRAM_ADDR = wr_req ? wr_addr[17:0] : rd_addr[17:0];// 将地址最高位作为256k分界线// 地址低于256k的数据写入SRAM的低8位,地址高于高256kb数据写入SRAM的高8位assign SRAM_LB_N = wr_req ? wr_addr[18] : rd_addr[18];assign SRAM_UB_N = ~SRAM_LB_N;// rd_dataalways @(posedge clk, negedge rst_n) beginif(!rst_n)rd_data <= 0;else if(rd_req) beginif(SRAM_LB_N)rd_data <= SRAM_DQ[15:8];elserd_data <= SRAM_DQ[7:0];endendendmodule

VGA驱动模块

使用友晶官方的VGA驱动模块,稍作修改,将输入输出的RGB信号从10位宽改为8位宽。

module   VGA_Ctrl    (   //  Host SideiRed,iGreen,iBlue,oCurrent_X,oCurrent_Y,oAddress,oRequest,//   VGA SideoVGA_R,oVGA_G,oVGA_B,oVGA_HS,oVGA_VS,oVGA_SYNC,oVGA_BLANK,oVGA_CLOCK,// Control SignaliCLK,iRST_N   );
//  Host Side
input       [7:0]   iRed;
input       [7:0]   iGreen;
input       [7:0]   iBlue;
output      [21:0]  oAddress;
output      [10:0]  oCurrent_X;
output      [10:0]  oCurrent_Y;
output              oRequest;
//  VGA Side
output      [7:0]   oVGA_R;
output      [7:0]   oVGA_G;
output      [7:0]   oVGA_B;
output  reg         oVGA_HS;
output  reg         oVGA_VS;
output              oVGA_SYNC;
output              oVGA_BLANK;
output              oVGA_CLOCK;
//  Control Signal
input               iCLK;
input               iRST_N;
//  Internal Registers
reg         [10:0]  H_Cont;
reg         [10:0]  V_Cont;

//  Horizontal  Parameter
parameter   H_FRONT =  16;
parameter   H_SYNC  =  96;
parameter   H_BACK  =  48;
parameter   H_ACT   =  640;
parameter   H_BLANK =  H_FRONT+H_SYNC+H_BACK;
parameter   H_TOTAL =  H_FRONT+H_SYNC+H_BACK+H_ACT;

//  Vertical Parameter
parameter   V_FRONT =  11;
parameter   V_SYNC  =  2;
parameter   V_BACK  =  31;
parameter   V_ACT   =  480;
parameter   V_BLANK =  V_FRONT+V_SYNC+V_BACK;
parameter   V_TOTAL =  V_FRONT+V_SYNC+V_BACK+V_ACT;

assign  oVGA_SYNC   =  1'b1;          //  This pin is unused.
assign  oVGA_BLANK  =  ~((H_Cont<H_BLANK)||(V_Cont<V_BLANK));
assign  oVGA_CLOCK  =  ~iCLK;
assign  oVGA_R      =  iRed;
assign  oVGA_G      =  iGreen;
assign  oVGA_B      =  iBlue;
assign  oAddress    =  oCurrent_Y*H_ACT+oCurrent_X;
assign  oRequest    =  ((H_Cont>=H_BLANK && H_Cont<H_TOTAL) &&(V_Cont>=V_BLANK && V_Cont<V_TOTAL));
assign  oCurrent_X  =  (H_Cont>=H_BLANK)   ?   H_Cont-H_BLANK  :   11'h0  ;
assign  oCurrent_Y  =  (V_Cont>=V_BLANK)   ?   V_Cont-V_BLANK  :   11'h0  ;// Horizontal Generator: Refer to the pixel clock
always@(posedge iCLK or negedge iRST_N)
beginif(!iRST_N)beginH_Cont     <=  0;oVGA_HS       <=  1;endelsebeginif(H_Cont<H_TOTAL)H_Cont   <=  H_Cont+1'b1;elseH_Cont    <=  0;//    Horizontal Syncif(H_Cont==H_FRONT-1)          //  Front porch endoVGA_HS  <=  1'b0;if(H_Cont==H_FRONT+H_SYNC-1)   //  Sync pulse endoVGA_HS   <=  1'b1;end
end//   Vertical Generator: Refer to the horizontal sync
always@(posedge oVGA_HS or negedge iRST_N)
beginif(!iRST_N)beginV_Cont     <=  0;oVGA_VS       <=  1;endelsebeginif(V_Cont<V_TOTAL)V_Cont   <=  V_Cont+1'b1;elseV_Cont    <=  0;//    Vertical Syncif(V_Cont==V_FRONT-1)            //  Front porch endoVGA_VS  <=  1'b0;if(V_Cont==V_FRONT+V_SYNC-1)   //  Sync pulse endoVGA_VS   <=  1'b1;end
end
endmodule

顶层模块

顶层模块例化所有模块进行连线,和上面的RTL图一致

module uart_sram_vga(input               clk,input               rst_n,// uart sideinput               rx,// sram sideoutput  [17:0]      SRAM_ADDR,inout   [15:0]      SRAM_DQ,output              SRAM_WE_N,output              SRAM_OE_N,output              SRAM_UB_N,output              SRAM_LB_N,output              SRAM_CE_N,// vga sideoutput              VGA_HS,output              VGA_VS,output      [9:0]   VGA_R,output      [9:0]   VGA_G,output      [9:0]   VGA_B,output              VGA_CLK,output              VGA_BLANK,output              VGA_SYNC
);// 用不上assign {VGA_R[1:0], VGA_G[1:0], VGA_B[1:0]} = 0;// pll输出25M时钟给vga_ctrlwire            clk_25;// uart接收到的数据和有效位wire            valid;wire    [7:0]   data;// wr_addr:数据的写入地址,uart接收完数据后拉高receive_donewire    [18:0]  wr_addr;wire            receive_done;// vga_ctrl输出的坐标、地址、请求、rgbwire    [9:0]   x;wire    [9:0]   y;wire    [21:0]  address;wire            oRequest;wire    [7:0]   R,G,B;// 从sram中读取的数据wire    [7:0]   rd_data;vga_pll inst_vga_pll (.inclk0 (clk),.c0     (clk_25));uart_rx inst_uart_rx (.clk   (clk),.rst_n (rst_n),.rx    (rx),.valid (valid),.data  (data));uart_rx_addr inst_uart_rx_addr (.clk          (clk), .rst_n        (rst_n), .valid        (valid), .receive_done (receive_done),.addr         (wr_addr));sram_ctrl inst_sram_ctrl (.clk       (clk),.rst_n     (rst_n),.wr_req    (valid),.wr_addr   (wr_addr),.wr_data   (data),.rd_req    (receive_done & oRequest),.rd_addr   (address),.rd_data   (rd_data),.SRAM_ADDR (SRAM_ADDR),.SRAM_DQ   (SRAM_DQ),.SRAM_WE_N (SRAM_WE_N),.SRAM_OE_N (SRAM_OE_N),.SRAM_UB_N (SRAM_UB_N),.SRAM_LB_N (SRAM_LB_N),.SRAM_CE_N (SRAM_CE_N));VGA_Ctrl inst_VGA_Ctrl (.iRed       (rd_data),.iGreen     (rd_data),.iBlue      (rd_data),.oCurrent_X (x),.oCurrent_Y (y),.oAddress   (address),.oRequest   (oRequest),.oVGA_R     (VGA_R[9:2]),.oVGA_G     (VGA_G[9:2]),.oVGA_B     (VGA_B[9:2]),.oVGA_HS    (VGA_HS),.oVGA_VS    (VGA_VS),.oVGA_SYNC  (VGA_SYNC),.oVGA_BLANK (VGA_BLANK),.oVGA_CLOCK (VGA_CLK),.iCLK       (clk_25),.iRST_N     (rst_n));
endmodule

结果分析

图片选择友晶资料盘里的图片,分辨率640*480,将其转灰度图用于实验。
仿真就不放了,直接放上板验证:
用正点原子的XCOM串口软件发送bmp图片,实验结果如下:

图像上下反转了,而且左右也有错位,说明直接使用串口软件发送bmp文件是不对的。
网上查了很多FPGA串口传图的代码,他们都喜欢自己写一个串口程序来传图,但我太菜了,不会写,他们的程序我也不好用,因为我要传灰度图。
解决方法:将图片转存为hex文件,然后用串口软件发送hex文件。
方式1:matlab

gray = imread('gray_640_480.bmp');
f = fopen('gray_640_480.hex', 'w+');
for y = 1:480for x = 1:640fprintf(f, '%x', gray(y, x));end
end
fclose(f);

方式2:python+opencv

import cv2 as cv
gray = cv.imread('gray_640_480.bmp', cv.IMREAD_GRAYSCALE)
f = open("gray_640_480.hex", "w+")
for y in range(0, 480):for x in range(0, 640):# 记得去掉0x开头hex_data = hex(gray[y][x])[2:4]f.write(hex_data)
f.close()

执行上述代码后,只是将bmp文件转化为了hex文本,其内容还是ASCII字符,2位十六进制数对应1字节,此时的hex文件大小(600kb)是bmp文件大小(300kb)的2倍。

接下来需要执行最后一步:以十六进制编码保存文件,我用的是sublime编辑器,打开hex文件,选择文件->以…编码保存->十六进制

执行完最后一步,hex文件大小变成300kb了,转hex完毕。
之后再用串口软件发送该hex文件即可,实验结果如下,与原图一致:

基于FPGA的串口传图SRAM缓存VGA显示相关推荐

  1. 基于FPGA的串口传图SDRAM缓存VGA显示

    简介 在DE2开发板上,使用串口接收PC上的Qt程序发送的640*480彩色图片,以RGB565格式存入SDRAM,通过VGA显示在屏幕上. 开发板:DE2 开发工具:Quartus II 13.0 ...

  2. 基于 DDR3 的串口传图帧缓存系统设计实现(整体设计)

    文章目录 前言 一.串口传图顶层系统设计框图 二.各模块说明 三.系统工程及 IP 创建 四.uart_ddr3_tft模块 五.uart_ddr3_tft模块仿真文件 六.传图展示 前言 结合串口接 ...

  3. UART串口传图LCD显示----图像处理

    UART串口传图LCD显示----图像处理 设计介绍 首先需要准备一个txt文本,里面存储一个16进制200* 200的图片数据,通过串口调试助手使用串口传输一个200* 200图片,然后通过开发板上 ...

  4. 基于 DDR3 的串口传图帧缓存系统设计实现(fifo2mig_axi )

    文章目录 前言 一.接口转换模块设计 二.fifo2mig_axi 模块 二.接口转换模块仿真 四.fifo2mig_axi_tb 五.仿真展示 前言 结合串口接收模块和 tft 显示屏控制模块,设计 ...

  5. 基于FPGA的视频图像直方图均衡 图像处理 图像增强 VGA对比度增强CLAHE

    基于FPGA的视频图像直方图均衡 图像处理 图像增强 VGA对比度增强CLAHE 本设计是基于FPGA的视频图像直方图均衡,实现的效果是可以实时地将摄像头采集的图像进行直方图均衡,具体过程是FPGA控 ...

  6. 基于FPGA的数字钟——(三)时钟显示模块(数码管)

    基于FPGA的数字钟--(三)数码管显示模块 一.硬件原理 本设计中使用 6 个共阳数码管,可以显示 6 个数字(包含小数点) .电路用 PNP管来反向驱动并且控制列扫描信号来选择哪个数码管.而且所有 ...

  7. FPGA基础设计(一):VGA显示方法(文字、图形、波形)

    概述   VGA是一种学习FPGA最常见的基础实验.虽然现在的显示屏大多已经采用DVI和HDMI方案,但其实VGA在另一个地方还有应用,那就是大屏的LCD.目前4.3寸以上的TFT基本都是VGA接口, ...

  8. FPGA 20个例程篇:15.VGA显示八种颜色的彩条

    第六章 图像显示处理,经典再现 15.VGA显示八种颜色的彩条 图像和视频处理可以说是FPGA中又一个经典地应用,使用FPGA做图像处理最核心的优势就在于:FPGA能进行实时流水线运算,从而达到更高的 ...

  9. 基于DDR3的串口传图帧缓存系统设计实现

    整体设计框图如图所示 模块名称 模块功能 uart_byte_rx模块 负责串口图像数据的接收 bit8_trans_bit16模块 将串口接收的每两个 8bit 数据转换成一个 16bit 数据(图 ...

最新文章

  1. 看别人的C/C++代码时发现自己所不知道的语法~
  2. 测试 MySQL 性能的几款工具
  3. mysql部署策略_MySQL延迟问题和数据刷盘策略流程分析
  4. (王道408考研操作系统)第五章输入/输出(I/O)管理-第一节3:I/O控制方式
  5. 自适应滤波器设计及matlab实现,(终稿)自适应滤波器设计及Matlab实现.doc(OK版)...
  6. GeeksForGeeks 翻译计划 | ApacheCN
  7. SpringSecurity-1-前言,登录原理
  8. 借给朋友两万块钱,已经两年,每次要钱都各种借口,我该怎么办?
  9. JavaScript 预解析机制
  10. java 读取excel wps_安装WPS引发的excel上传问题
  11. js中for循环的优化写法
  12. 【优化算法】孪生支持向量机(TWSVM)【含Matlab源码 1257期】
  13. 电力拖动自动控制系统复习(一)
  14. 使用Scala实现Either数据结构
  15. typora用Pandoc导出html,typora使用pandoc导出功能
  16. 零基础学习PS——#photoshop# 的167个技能!
  17. 8、TM4单片机的滴答定时器,及利用定时器精确延时
  18. matlab中xpcapi库的调用,关于MATLAB中xpc实时控制平台搭建的心得
  19. PyAutoGUI应用
  20. 万维网发布服务(w3svc)已停止。除非万维网发布服务(w3svc)正在运行,否则无法启动网站。

热门文章

  1. HashMap中put方法详解
  2. php excel模板导出
  3. U盘在电脑上读不出来怎么办?详细解决方法在这!
  4. Go语言的学习【2】基础语法
  5. PPT目录页怎么设计才高大上?告诉你一个万能排版法!
  6. Pyspark:DataFrame的转化操作及行动操作
  7. 基于ISO26262的功能安全 学习笔记2
  8. linux查看lmgrd进程,FlexNet License Server Manager 'lmgrd' 组件栈缓冲区溢出漏洞
  9. 数说CS|北大软微是怎样的存在?
  10. mysql数据库级联删除_怎样对数据库进行级联删除?