基于FPGA的串口传图SRAM缓存VGA显示

简介
在DE2开发板上使用串口接收PC发送的640*480分辨率灰度图,存入SRAM,通过VGA进行显示 。
开发板:DE2
型号:
开发工具: II 13.0 +10.5 SE
全局时钟: 50M
VGA时钟:25M
SRAM大小:256k*16bit,总共512kb
目前还不会用SDRAM,先从简单的SRAM入手 。
由于640*480分辨率的24位彩色图片需要900kb,SRAM装不下,所以使用8位灰度图(300kb) 。
该SRAM为256k*16bit,为了存下300kb的灰度图,我将其包装为512k*8bit
RTL视图
一共五个模块:PLL、串口接收、写入地址计数、SRAM驱动、VGA驱动
PLL模块为VGA驱动模块提供25M时钟 。
串口接收模块接收来自PC发送的图片数据 。
写入地址计数模块根据接收到的数据,产生写入地址,并在接收完整张图片后,输出信号,允许VGA从SRAM读取数据 。
SRAM驱动模块对SRAM芯片进行读写 。

基于FPGA的串口传图SRAM缓存VGA显示

文章插图
VGA驱动模块产生VGA时序显示图片 。
串口接收模块
波特率:
数据位:8
校验:无
停止位:1
module uart_rx(// clk, rst_ninputclk,inputrst_n,// uart rxinputrx,// valid data outputoutput regvalid,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下降沿regrx_1;regrx_2;regrx_3;// 工作使能regwork_ena;// 波特计数器 比特计数器reg [8:0]cnt_baud;reg [4:0]cnt_bit;// 计数器使能、清零wirecnt_baud_ena;wirecnt_baud_end;wirecnt_bit_ena;wirecnt_bit_end;// data移位寄存器reg [7:0]data_shift;// valid打一拍再输出,和data同步输出regvalid_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的地址,接收完整张图片后,拉高信号,允许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