FPGA之旅设计99例之第二十一例----VGA串口SDRAM显示图片

简介: 笔记

一. 简介


本例将接着上一例实现的sdram控制器进行封装。上例中只是实现了一个基本的控制器,在实际使用中,通常读写时钟是两个不同频率的,所以并不能满足要求。


在本例中,将对读写接口进行封装,将读写接口封装成FIFO接口这样封装主要是为了让,读写的时候,满足设计要求(存储OV5640传输过来的图像,并且显示在VGA显示器上)。


最后将设计好的接口,配置之前写好的串口以及VGA驱动,实现一个小例子。通过串口发送图片,sdram存储,vga显示。本例完成后,就可以使用此sdram模块做很多事情啦!


欢迎关注微信公众号 FPGA之旅 回复 FPGA之旅设计99例之第二十一例 获取完整代码,以及相关软件。


本例写的比较匆忙,望见谅。


二. 写接口封装


在封装的时候,使用到了FIFO IP,主要用来,外部传输图像数据到SDRAM中间的一个缓存区域,接口信号设计如下,外部给定帧地址,以及同步信号后(将写入sdram的地址复位为帧的起始地址),后面来的时候,就会依次往sdram中存储,这样外部就不需要管地址了,只需要知道存储到第几个帧的位置就可以了。帧大小以及写的突发长度,通过宏定义在sdram_defines.v文件中,方便修改。整个代码实现如下,非常简单。

15.png

//写正常 中转,外部写入数据暂存于此,然后写入sdram
`include "sdram_defines.v"
module  sdram_hpfifo_write
(
    input                       rst_n,
    input                       write_clk,              //写时钟
    input                       write_en,               //写使能
    input[1:0]                  write_frame_addr,       //帧地址选择
    input                       write_frame_sync,       //帧同步
    input[15:0]                 write_data,
    //sdram
    input                       read_clk,
    output                      write_req,
    input                       write_ack,
    output[23:0]                write_addr,
    output[9:0]                 write_burst_length,
    output[15:0]                write_sdram_data,
    input                       write_data_en
);
wire[9:0] rdusedw;
reg [23:0]  read_addr_reg;
assign  write_burst_length     =  `burst_length;
assign    write_addr    =   read_addr_reg;
assign  write_req    =  ( rdusedw >= `burst_length )  ? 1'b1 : 1'b0;
always@(posedge  read_clk or negedge rst_n)
begin
  if( rst_n == 1'b0)
  read_addr_reg <= 'd0;
  else if( write_ack == 1'b1 )
  read_addr_reg <= read_addr_reg + `burst_length;
  else
  read_addr_reg <= read_addr_reg;
end
 fifo  fifo_w
 (
  .aclr   ( ~rst_n     ),
  .data   ( write_data  ),
  .rdclk  ( read_clk      ),
  .rdreq  ( write_data_en ),
  .wrclk  ( write_clk    ),
  .wrreq  ( write_en  ),
  .q    ( write_sdram_data),
  .rdusedw  ( rdusedw       ),
  .wrusedw  ()
);
endmodule

三. 读接口封装


读接口主要用于外部从sdram读取数据,内部也调用了一个FIFO IP。信号接口,以及实现过程和写接口封装一模一样。就不做信息的说明了。

16.png


四. SDRAM_FIFO 模块


封装完成后,整体的框图如下,也是非常的简介。

17.png



封装的实现还是比较容易的,大家可以试试不调用FIFO,自己实现一个FIFO实现。


五. 串口-VGA-SDRAM显示图片

为了检测封装的是否成功,通过这个小例子,就可以检测出来。如果图片显示无误,那么说明封装正确了。


本例所使用到的模块,均是前几例中实现了的模块,所以这个例子也就是将其组合在一起。


module  main(
    input                       sys_clk,
    input                       rst_n,
  //????
  input                       uartrx,         /*uart rx???*/
  //vga
  output[15:0]    vga_rgb,
  output      vga_hsync,
  output      vga_vsync,
  input        key,
    //sdram
  output                      sdram_clk,         //sdram clock
  output                      sdram_cke,         //sdram clock enable
  output                      sdram_cs_n,        //sdram chip select
  output                      sdram_we_n,        //sdram write enable
  output                      sdram_cas_n,       //sdram column address strobe
  output                      sdram_ras_n,       //sdram row address strobe
  output[1:0]                 sdram_dqm,         //sdram data enable
  output[1:0]                 sdram_ba,          //sdram bank address
  output[12:0]                sdram_addr,        //sdram address
  inout[15:0]                 sdram_dq           //sdram data
);
wire  uart_rxs_done;
wire[15:0]  uart_data;
wire  display_data_en;
wire[15:0]  display_data;
wire  vga_clk_25M;
wire  sdram_clk_75M;
wire  sdram_clk_75M_Shift;
reg[23:0] cnt;
reg[1:0]  read_frame_addr;
always@(posedge vga_clk_25M or negedge rst_n)
begin
  if( rst_n == 1'b0)
  read_frame_addr <= 2'b00;
  else if( key == 1'b0)
  read_frame_addr  <= read_frame_addr + 1'b1;
  else
  read_frame_addr <= read_frame_addr;
end
pll pll_PL(
  .inclk0 (sys_clk),
  .c0  (vga_clk_25M),
  .c1  (sdram_clk_75M),
  .c2  (sdram_clk_75M_Shift));
UART_MulRX UART_MulRX_HP(
    .sys_clk      ( sys_clk   ),        /*???? 50M*/
    .rst_n      ( rst_n      ),          /*????*/
    .uart_rxs_done    ( uart_rxs_done ),   /*??????*/
    .odats      ( uart_data  ),           /*????*/
    .uartrx            (  uartrx    )/*uart rx???*/
);
vga_driver  vga_driver_HP(
  .vga_clk        ( vga_clk_25M  ),
  .rst_n      ( rst_n   ),
  .display_data_en    ( display_data_en ),
  .curr_x      (      ),
  .curr_y      (      ),
  .display_data    (  display_data  ),
  .vga_rgb        ( vga_rgb   ),
  .vga_hsync      ( vga_hsync  ),
  .vga_vsync      ( vga_vsync  )
);
sdram_hpfifo sdram_hpfifoHP(
   .sys_clk                 (  sdram_clk_75M      ),                //sdram_??
  .sdram_clk_100M_F    (  sdram_clk_75M_Shift ),
   .rst_n                   (   rst_n               ),
    //?    
   .read_clk                (  vga_clk_25M          ),               //???
   .read_en                 (  display_data_en      ),                //???
   .read_frame_addr         (  read_frame_addr                  ),        //?????
   .read_fram_sync          (  vga_vsync            ),         //???
   .read_data               (  display_data         ),
    //?    
    .write_clk              (   sys_clk             ),              //???
    .write_en               (   uart_rxs_done       ),               //???
    .write_frame_addr       (   2'b00               ),       //?????
    .write_frame_sync       (   1'b0                ),       //???
    .write_data             (   uart_data          ),
      //sdram??
    .sdram_clk              (   sdram_clk          ),         //sdram clock
  .sdram_cke              (   sdram_cke          ),         //sdram clock enable
  .sdram_cs_n             (   sdram_cs_n         ),        //sdram chip select
  .sdram_we_n             (   sdram_we_n         ),        //sdram write enable
  .sdram_cas_n            (   sdram_cas_n        ),       //sdram column address strobe
  .sdram_ras_n            (   sdram_ras_n        ),       //sdram row address strobe
  .sdram_dqm              (   sdram_dqm          ),         //sdram data enable
  .sdram_ba               (   sdram_ba           ),          //sdram bank address
  .sdram_addr             (   sdram_addr         ),        //sdram address
  .sdram_dq               (   sdram_dq           )        //sdram data
);
endmodule


通过串口发送图片的时候,并不需要额外去提取图像数据,像很多例程中说提到的通过其他编程语言来实现,只需要用来下面的软件即可生成。这里一定要选择生成二进制文件。


18.png


然后将生成好的bin文件,放入com软件中,发送即可。

19.png



最后的显示效果如图所示。最后上面的软件会放到本例的下载链接中。

20.png



ps: 测试时,本人使用的开发板跑不到100M,调试了好久,才发现这个问题,最终将时钟频率降低到了75M。

公众号:FPGA之旅

目录
相关文章
|
7月前
|
数据格式 异构计算
|
算法 芯片 异构计算
通过FPGA实现基于RS232串口的指令发送并控制显示器中目标位置
通过FPGA实现基于RS232串口的指令发送并控制显示器中目标位置
|
5月前
|
异构计算
FPGA进阶(3):SDRAM读写控制器的设计与验证(二)
FPGA进阶(3):SDRAM读写控制器的设计与验证(二)
43 0
|
5月前
|
异构计算 内存技术
FPGA进阶(3):SDRAM读写控制器的设计与验证(一)
FPGA进阶(3):SDRAM读写控制器的设计与验证
130 0
|
异构计算
FPGA项目四:串口通信(下)
FPGA项目四:串口通信
132 2
FPGA项目四:串口通信(下)
|
异构计算