手撕sdram控制器,实现图像的缓存和vga实时显示

手撕sdram控制器,实现图像的缓存和vga实时显示

前言

1.采用器件

Xilinx Spartan 6 XC6SLX9-2TQG144C FPGA芯片,Hynix公司生产的型号为HY57V281620F的sdram芯片

2.参考的手册

《IS42S83200G, IS42S16160G》《Hynix 4Bank x 2M x 16bits Synchronous DRAM》《Proposed VESA and Industry Standards and Guidelines for Computer Display Monitor Timing (DMT) Version 1.0, Revision 12p, Draft 2》

3.sdram工作原理

网上的资料非常多,讲的很清楚,主要是要搞清楚SDRAM的操作时序;知道什是突发写;知道sdram的芯片需要不停的刷新操作保证数据不丢失;知道数据写入和读出可以按照地址自由的操作;知道SDRAM的读写是不能同时进行的是时分复用的,这个从sdram内部的结构框图就能看出,读写的地址线是共用的。
在这里插入图片描述

还有就是要学会画各种操作的时序,读写操作的命令一定要和数据保持正确的时序对应关系,不然会出错。

详细的设计方案

1.总体思考

1.1 整体的架构

sdram的控制器包括初始化、自刷新、突发读、突发写的操作,SDRAM 是动态 RAM 必须要通过刷新才能保证给每一个存储单元充电,并保证存储单元中的数据不丢失。 外部是一个VGA显示端,每个显示行都需要读数据,此时需要通过 SDRAM 读操作完成数据读出,但是如果读数据期间出现刷新请求,就需要中断当前读操作执行刷新请求,如果数据未读完,继续读出剩余数据,这里就需要用到仲裁机制。初始化、自刷新、突发读、突发写的操作有自己的操作时序,因此,采用主状态机描述初始化、自刷新、突发读、突发写操作之间的仲裁机制,每个单独的操作采用从状态机描述自己的操作时序。

顶层包括架构如下:

Entity: top_sdram_ctrl
  • File: top_sdram_ctrl.v
Diagram

在这里插入图片描述

Generics
Generic nameTypeValueDescription
T_REFERSH'd780
P_RST_CYCLE'd5
NOP20’b0111_0000_0000_0000_0000
PRECHARGE20’b0010_0000_0100_0000_0000
REFRESH20’b0001_0000_0000_0000_0000
MODE_REGISTER20’b0000_0000_0000_0011_0010
WRITE_CMD6’b0100_00
ACTIVE6’b0011_00
RD_CMD6’b0101_00
P_SYSTEM_CLK50_000_000
P_UART_BUADRATE921600
P_UART_DATA_WIDTH8
P_UART_STOP_WIDTH1
P_UART_CHECK0
CHECK_TYPE1
Ports
Port nameDirectionTypeDescription
i_clkinputwire
i_uart_rxinputwire
Addroutput[11 : 0]
Baoutput[1 : 0]
sdclkoutput
Ckeoutput
Cs_noutput
Ras_noutput
Cas_noutput
We_noutput
Dqmoutput[1: 0]
vgaoutput[7: 0]
v_syncoutput
h_syncoutput
Dqinout[15 : 0]
Signals
NameTypeDescription
o_rstwire
o_vga_startwire
o_rfifo_datawire [7:0]
rd_fifo_enwire
dewire
lockedwire
clk_out50wire
clk_out25wire
o_user_rx_datawire [7:0]
o_user_rx_validflagwire
Instantiations
  • clk_gen_instance: clk_wiz_50Mhz_25Mhz
  • uart_rx_inst: uart_rx
  • sdram_main_ctrl_inst: sdram_main_ctrl
  • VGA_TIMING_inst: VGA_TIMING

1.2 带宽的思考

  1. 首先从整体来讲,要实现vga图像的实时显示,显示和写入数据带宽总和要小于sdram缓存的理论带宽。sdram的工作时钟是50MHz,每次的读写是16bit,其带宽为50Mhzx16bit=800Mbit/s。vga(工作时钟为25MHz,RGB332格式),640X480的像素点,刷新率为60帧,显示和写入数据带宽总和为2x640x480x60x8bit=295Mbit/s,所以是可以满足图像实时显示要求。
  2. 整个工程的场景是uart写数据到sdram,vga从sdram读数据,uart的写带宽是921600bit/s,vga(工作时钟为25MHz,RGB332格式)从sdram读数据,sdram的读数据带宽是25MHzx8,即(25x10^6x8),写比读慢,因此在整个工程上,应该等uart的数据全部写入sdram之后,再把数据从sdram里面读出来,用vga显示。
  3. 由于读写带宽不相同,所以在sdram读模块和sdram写模块中都需要fifo来缓存数据,利用data_count来判断读和写的时刻。其中sdram读模块的fifo是异步fifo,因为vga模块的工作时钟为25MHz,sdram的工作时钟为50MHz。

1.3 各模块设计

1.3.1 sdram_main_ctrl主状态机的设计
Entity: sdram_main_ctrl
  • File: sdram_main_ctrl.v
Diagram

在这里插入图片描述

Generics
Generic nameTypeValueDescription
T_REFERSH'd780
NOP20’b0111_0000_0000_0000_0000
PRECHARGE20’b0010_0000_0100_0000_0000
REFRESH20’b0001_0000_0000_0000_0000
MODE_REGISTER20’b0000_0000_0000_0011_0010
WRITE_CMD6’b0100_00
ACTIVE6’b0011_00
RD_CMD6’b0101_00
Ports
Port nameDirectionTypeDescription
i_clkinputwire
i_rstinputwire
i_vgaclkinputwire
i_write_datainputwire [7:0]
i_data_valid_flaginputwire
i_rd_eninputwire
o_cmdoutputwire [19:0]
o_vga_startoutputwire
o_rfifo_dataoutputwire [7:0 ]
dqinoutwire [15:0]
Signals
NameTypeDescription
ro_cmdreg [19:0]
statereg [5:0]
ini_flagreg
ref_enreg
w_enreg
r_enreg
ro_wfifo_datareg [15:0]
ri_sdram_datareg [15:0]
initial_endwire
ref_reqwire
w_reqwire
r_reqwire
ref_endwire
write_data_endwire
write_ref_break_endwire
read_data_endwire
read_ref_break_endwire
o_ref_cmdwire [19:0]
o_initial_cmdwire [19:0]
o_write_cmdwire [19:0]
o_read_cmdwire [19:0]
o_wfifo_datawire [15:0]
Constants
NameTypeValueDescription
IDLE6’b000001
INI6’b000010
SW6’b000100
REF6’b001000
WRITE6’b010000
READ6’b100000
Instantiations
  • sdram_refresh_inst: sdram_refresh
  • sdram_init_inst: sdram_init
  • sdram_write_inst: sdram_write
  • sdram_read_inst: sdram_read
State machines

在这里插入图片描述

1.3.2 sdram_init初始模块设计
Entity: sdram_init
  • File: sdram_init.v
Diagram

在这里插入图片描述

Generics
Generic nameTypeValueDescription
NOP20’b0111_0000_0000_0000_0000
PRECHARGE20’b0010_0000_0100_0000_0000
REFRESH20’b0001_0000_0000_0000_0000
MODE_REGISTER20’b0000_0000_0000_0011_0010
Ports
Port nameDirectionTypeDescription
i_clkinputwire
i_rstinputwire
o_initial_endoutputwire
o_initial_cmdoutputwire [19:0]
Signals
NameTypeDescription
ro_initial_endreg
ro_initial_cmdreg [19:0]
init_cntreg [15:0]
Constants
NameTypeValueDescription
DELY_200us'd10000
PRE_20ns'd1
AFTER_PRE_40ns'd2
REFRESH_20ns'd1
AFTER_REFRESH_80ns'd3
MODE_REGISTER_20ns'd1
AFTER_MODE_REGISTER_40ns'd2
1.3.3 sdram_refresh自刷新模块设计
Entity: sdram_refresh
  • File: sdram_refresh.v
Diagram

在这里插入图片描述

Generics
Generic nameTypeValueDescription
T_REFERSH'd780
NOP20’b0111_0000_0000_0000_0000
REFRESH20’b0001_0000_0000_0000_0000
Ports
Port nameDirectionTypeDescription
i_clkinputwire
i_rstinputwire
i_initial_endinputwire
i_ref_eninputwire
o_ref_reqoutputwire
o_ref_endoutputwire
o_ref_cmdoutputwire [19:0]
Signals
NameTypeDescription
ref_cntreg [15:0]
ro_ref_reqreg
ro_ref_endreg
ro_ref_cmdreg [19:0]
cmd_keepreg
keep_cntreg [3:0]
Constants
NameTypeValueDescription
KEEP_CNT_MAX'd10
1.3.4 sdram_write写模块从状态机设计
Entity: sdram_write
  • File: sdram_write.v
Diagram

在这里插入图片描述

Generics
Generic nameTypeValueDescription
T_REFERSH'd780
NOP20’b0111_0000_0000_0000_0000
REFRESH20’b0001_0000_0000_0000_0000
WRITE_CMD6’b0100_00
ACTIVE6’b0011_00
PRECHARGE20’b0010_0000_0100_0000_0000
Ports
Port nameDirectionTypeDescription
i_clkinputwire
i_rstinputwire
i_ref_reqinputwire
i_w_eninputwire
i_write_datainputwire [7:0]
i_data_valid_flaginputwire
o_w_reqoutputwire
o_write_data_endoutputwire
o_write_ref_break_endoutputwire
o_write_cmdoutputwire [19:0]
o_wfifo_dataoutputwire [15:0]
Signals
NameTypeDescription
statereg [4:0]
bank_cntreg [1:0]
row_cntreg [11:0]
burst_col_cntreg [1:0]
burst_cntreg [11:0]
rd_enreg
active_endreg
act_cntreg [2:0]
pre_endreg
pre_cntreg [3:0]
ro_w_reqreg
write_data_endreg
write_ref_break_endreg
write_data_end_keepreg
write_ref_break_keepreg
ro_write_cmdreg [19:0]
rd_data_countwire [10 : 0]
doutwire [15 : 0]
Constants
NameTypeValueDescription
IDLE5’b00001
WRITE_REQ5’b00010
ACT5’b00100
WRI5’b01000
PRE5’b10000
REQ_FIFONUM'd512
PRE_CNT_MAX'd8
ACT_CNT_MAX'd3
BURST_LENGTH'd4
BURST_CNT_MAX'd128
ROW_CNT_MAX'd4096
ROW_CNT_MAX_300'd300
BANK_CNT_MAX'd4
Instantiations
  • fifo_instance1: sfifo_2048x8_write1024x16
State machines

在这里插入图片描述

1.3.5 sdram_read读模块从状态机设计
Entity: sdram_read
  • File: sdram_read.v
Diagram

在这里插入图片描述

Generics
Generic nameTypeValueDescription
T_REFERSH'd780
NOP20’b0111_0000_0000_0000_0000
REFRESH20’b0001_0000_0000_0000_0000
ACTIVE6’b0011_00
PRECHARGE20’b0010_0000_0100_0000_0000
RD_CMD6’b0101_00
Ports
Port nameDirectionTypeDescription
i_clkinputwire
i_vgaclkinputwire
i_rstinputwire
i_ref_reqinputwire
i_r_eninputwire
i_sdram_datainputwire [15:0]
i_rd_eninputwire
o_rfifo_dataoutputwire [7:0]
o_r_reqoutputwire
o_read_data_endoutputwire
o_read_ref_break_endoutputwire
o_read_cmdoutputwire [19:0]
o_vga_startoutputwire
Signals
NameTypeDescription
statereg [4:0]
ro_vga_startreg
bank_cntreg [1:0]
row_cntreg [11:0]
burst_col_cntreg [1:0]
burst_cntreg [11:0]
wr_enreg
active_endreg
act_cntreg [2:0]
pre_endreg
pre_cntreg [3:0]
ro_r_reqreg
read_data_endreg
read_ref_break_endreg
read_data_end_keepreg
read_ref_break_keepreg
ro_read_cmdreg [19:0]
state_dly5reg [4 : 0]
state_dly4reg [4 : 0]
state_dly3reg [4 : 0]
state_dly2reg [4 : 0]
state_dly1reg [4 : 0]
rd_data_countwire [11 : 0]
wr_data_countwire [10 : 0]
doutwire [7 : 0]
fullwire
emptywire
Constants
NameTypeValueDescription
IDLE5’b00001
READ_REQ5’b00010
ACT5’b00100
RD5’b01000
PRE5’b10000
REQ_FIFONUM'd512
PRE_CNT_MAX'd8
ACT_CNT_MAX'd3
BURST_LENGTH'd4
BURST_CNT_MAX'd128
ROW_CNT_MAX'd4096
ROW_CNT_MAX_300'd300
BANK_CNT_MAX'd4
Instantiations
  • fifo_instance1: asfifo_2048x16read4096x8
State machines
1.3.6 VGA_TIMING模块

这个模块不做详细解释,主要对照手册设计,控制好行计数器和列计数器就行。

上板调试验证并演示

在这里插入图片描述

传了一个aliya的图,可爱捏!

总结分析

1.新技能

1.1状态机的输出采用与或的形式节省资源

单就这个项目来说,在状态结果输出这一步,其实就是把命令输出,我采用二段式状态机来来写代码,也就是非阻塞赋值来赋值输出,但其实可以用组合逻辑来赋值输出来写
在这里插入图片描述

1.2inout信号的三态门描述

在这里插入图片描述

oe控制信号为高的时候,FPGA芯片往sdram里面写数据ro_wfifo_data,即三态门输出数据;

oe控制信号为低的时候,三态门输出高阻态,sdram的数据输入到FPGA芯片,用reg寄存器ri_sdram_data来接收数据,即三态门输入数据。申明reg寄存器ri_sdram_data来接收数据是用来隔绝三态门输出数据对输入数据所连电路的影响。
https://blog.csdn.net/qq_28541715/article/details/118344356
这篇文章讲的很好。
inout端口的实现是使用三态门,inout端口模型必须要抓住三点:

  1. inout端口不可能独立存在;

  2. 作为输入必须有reg型缓冲(一个inout两个控制信号);

  3. 相连的两个inout端口由一对信号交错控制;

误解:用一对相反的信号控制两个inout端口实现双向传输。造成这种误解的原因是在两个module中的inout端口中,三态门不可能同时导通,默认两个三态门总是一个导通另一个不导通,忽略了两个都不导通的情况。所以在实际电路中,用于控制两个inout端口的,必然是一对控制信号的交叉形式。

1.3独热码新打拍的写法

之前写信号的打拍一直打几拍就申明多少个变量很繁杂,
在这里插入图片描述

现在学了一种新的写法,比较高效
在这里插入图片描述

打几拍就把read_state_dly声明成多少位宽的变量,因为最后取高位,这样写节省资源

2.报错debug

2.1 因为在顶层中没有例化相应的信号,然后PAR的时候就出现引脚没有驱动源

https://support.xilinx.com/s/question/0D52E00006hpq1iSAA/%E6%B1%82%E5%8A%A9%E7%94%9F%E6%88%90bit%E6%B5%81%E6%96%87%E4%BB%B6%E9%94%99%E8%AF%AF?language=en_US

2.2 Assignment under multiple single edges is not supported for synthesis 错误

https://blog.csdn.net/zhufeizi123/article/details/88782415

原因是本该上升沿的 posedge i_rst

  always @(posedge i_clk or posedge i_rst) begin
      if (i_rst) begin
        ro_wfifo_data <= 'd0;
      end
      else 
        ro_wfifo_data <= o_wfifo_data;
  end

写成了

  always @(posedge i_clk or negedge i_rst) begin
      if (i_rst) begin
        ro_wfifo_data <= 'd0;
      end
      else 
        ro_wfifo_data <= o_wfifo_data;
  end
2.3 sdram的命令一定要和数据时序满足要求
  1. sdram的写命令一定要和inout端口上的数据dq对齐
  2. sdram的读命令因为CAS Latency我们设置的是3,因此读取的数据时返回数据具有 3 拍的延时,sdram的读模块中的fifo的使能要注意和从sdram里面来的延时的数据对齐。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅癌晚期的彦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值