1)实验平台:正点原子开拓者FPGA 开发板
2)摘自《开拓者FPGA开发指南》关注官方微信号公众号,获取更多资料:正点原子
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-13912-1-1.html
![bcfe98880dcd02892b4e780b77144eb9.png](https://img-blog.csdnimg.cn/img_convert/bcfe98880dcd02892b4e780b77144eb9.png)
第三十三章 SDRAM读写测试实验
SDRAM控制器顶层模块主要完成SDRAM控制器及SDRAM读写端口FIFO控制模块的例化。代码
中56行给SDRAM数据掩码赋值,因为我们读写测试过程中,数据线的高字节和低字节均一直有
效,因此整个SDRAM读写过程中不需要屏蔽数据线。
SDRAM FIFO控制模块代码如下所示:
1 module sdram_fifo_ctrl(
2 input clk_ref, //SDRAM控制器时钟
3 input rst_n, //系统复位
4
5 //用户写端口
6 input clk_write, //写端口FIFO: 写时钟
7 input wrf_wrreq, //写端口FIFO: 写请求
8 input [15:0] wrf_din, //写端口FIFO: 写数据
9 input [23:0] wr_min_addr, //写SDRAM的起始地址
10 input [23:0] wr_max_addr, //写SDRAM的结束地址
11 input [ 9:0] wr_length, //写SDRAM时的数据突发长度
12 input wr_load, //写端口复位: 复位写地址,清空写FIFO
13
14 //用户读端口
15 input clk_read, //读端口FIFO: 读时钟
16 input rdf_rdreq, //读端口FIFO: 读请求
17 output [15:0] rdf_dout, //读端口FIFO: 读数据
18 input [23:0] rd_min_addr, //读SDRAM的起始地址
19 input [23:0] rd_max_addr, //读SDRAM的结束地址
20 input [ 9:0] rd_length, //从SDRAM中读数据时的突发长度
21 input rd_load, //读端口复位: 复位读地址,清空读FIFO
22
23 //用户控制端口
24 input sdram_read_valid, //SDRAM 读使能
25 input sdram_init_done, //SDRAM 初始化完成标志
26
27 //SDRAM 控制器写端口
28 output reg sdram_wr_req, //sdram 写请求
29 input sdram_wr_ack, //sdram 写响应
30 output reg [23:0] sdram_wr_addr, //sdram 写地址
31 output [15:0] sdram_din, //写入SDRAM中的数据
32
33 //SDRAM 控制器读端口
34 output reg sdram_rd_req, //sdram 读请求
35 input sdram_rd_ack, //sdram 读响应
36 output reg [23:0] sdram_rd_addr, //sdram 读地址
37 input [15:0] sdram_dout //从SDRAM中读出的数据
38 );
39
40 //reg define
41 reg wr_ack_r1; //sdram写响应寄存器
42 reg wr_ack_r2;
43 reg rd_ack_r1; //sdram读响应寄存器
44 reg rd_ack_r2;
45 reg wr_load_r1; //写端口复位寄存器
46 reg wr_load_r2;
47 reg rd_load_r1; //读端口复位寄存器
48 reg rd_load_r2;
49 reg read_valid_r1; //sdram读使能寄存器
50 reg read_valid_r2;
51
52 //wire define
53 wire write_done_flag; //sdram_wr_ack 下降沿标志位
54 wire read_done_flag; //sdram_rd_ack 下降沿标志位
55 wire wr_load_flag; //wr_load 上升沿标志位
56 wire rd_load_flag; //rd_load 上升沿标志位
57 wire [9:0] wrf_use; //写端口FIFO中的数据量
58 wire [9:0] rdf_use; //读端口FIFO中的数据量
59
60 //*****************************************************
61 //** main code
62 //*****************************************************
63
64 //检测下降沿
65 assign write_done_flag = wr_ack_r2 & ~wr_ack_r1;
66 assign read_done_
SDRAM是一种可以指定任意地址进行读写的存储器,它具有存储容量大,读写速度快的特
点,同时价格也相对低廉。因此,SDRAM常作为缓存,应用于数据存储量大,同时速度要求较
高的场合,如复杂嵌入式设备的存储器等。本章我们将利用FPGA实现SDRAM控制器,并完成开
发板上SDRAM芯片的读写测试。
本章包括以下几个部分:
33.1 SDRAM简介
33.2 实验任务
33.3 硬件设计
33.4 程序设计
33.5 下载验证
SDRAM简介
SDRAM(Synchronous Dynamic Random Access Memory),同步动态随机存储器。同步是
指内存工作需要同步时钟,内部的命令的发送与数据的传输都以它为基准;动态是指存储阵列
需要不断的刷新来保证数据不丢失;随机是指数据不是线性依次存储,而是自由指定地址进行
数据读写。
SDRAM具有空间存储量大、读写速度快、价格相对便宜等优点。然而由于SDRAM内部利用电
容来存储数据,为保证数据不丢失,需要持续对各存储电容进行刷新操作;同时在读写过程中
需要考虑行列管理、各种操作延时等,由此导致了其控制逻辑复杂的特点。
SDRAM的内部是一个存储阵列,你可以把它想象成一张表格。我们在向这个表格中写入数
据的时候,需要先指定一个行(Row),再指定一个列(Column),就可以准确地找到所需要
的“单元格”,这就是SDRAM寻址的基本原理。如图 33.1.1所示:
![f667ab078144b8ec1eba24a32df48625.png](https://img-blog.csdnimg.cn/img_convert/f667ab078144b8ec1eba24a32df48625.png)
图 33.1.1 SDRAM寻址原理
图 31.1.1中的“单元格”就是SDRAM存储芯片中的存储单元,而这个“表格”(存储阵列)
我们称之为L-Bank。通常SDRAM的存储空间被划分为4个L-Bank,在寻址时需要先指定其中一个
L-Bank,然后在这个选定的L-Bank中选择相应的行与列进行寻址(寻址就是指定存储单元地址
的过程)。
对SDRAM的读写是针对存储单元进行的,对SDRAM来说一个存储单元的容量等于数据总线的
位宽,单位是bit。那么SDRAM芯片的总存储容量我们就可以通过下面的公式计算出来:
SDRAM总存储容量 = L-Bank的数量×行数×列数×存储单元的容量
SDRAM存储数据是利用了电容的充放电特性以及能够保持电荷的能力。一个大小为1bit的存储
单元的结构如下图所示,它主要由行列选通三极管,存储电容,刷新放大器组成。行地址与列
地址选通使得存储电容与数据线导通,从而可进行放电(读取)与充电(写入)操作。
![15491802ca284f6c613650a6f955d719.png](https://img-blog.csdnimg.cn/img_convert/15491802ca284f6c613650a6f955d719.png)
图 33.1.2 SDRAM存储单元结构示意图
图 33.1.3为SDRAM的功能框图,SDRAM内部有一个逻辑控制单元,并且有一个模式寄存器
为其提供控制参数。SDRAM接收外部输入的控制命令,并在逻辑控制单元的控制下进行寻址、
读写、刷新、预充电等操作。
![a159ab15c0581c4296fae0d2595414da.png](https://img-blog.csdnimg.cn/img_convert/a159ab15c0581c4296fae0d2595414da.png)
图 33.1.3 SDRAM功能框图
在了解SDRAM的寻址原理及存储结构之后,我们来看下如何实现SDRAM的读写。首先,在对
SDRAM进行读写操作之前需要先对芯片进行初始化;其次,SDRAM读写是一个较为复杂的控制流
程,其中包括行激活、列读写、预充电、刷新等一系列操作。大家需要熟练掌握每一个操作所
对应的时序要求,才能够正确地对SDRAM进行读写操作。
1、芯片初始化
SDRAM芯片上电之后需要一个初始化的过程,以保证芯片能够按照预期方式正常工作,初
始化流程如图 33.1.4所示:
![905621034c656353d1d7cda002e580b6.png](https://img-blog.csdnimg.cn/img_convert/905621034c656353d1d7cda002e580b6.png)
图 33.1.4 SDRAM初始化
SDRAM上电后要有200us的输入稳定期,在这个时间内不可以对SDRAM的接口做任何操作;
200us结束以后给所有L-Bank预充电,然后是连续8次刷新操作;最后设置模式寄存器。初始化
最关键的阶段就在于模式寄存器(MR,Mode Register)的设置,简称MRS(MR Set)。
![8b9882e6c764e7f75245ef8d88acd6b5.png](https://img-blog.csdnimg.cn/img_convert/8b9882e6c764e7f75245ef8d88acd6b5.png)
图 33.1.5 模式寄存器
如上图所示,用于配置模式寄存器的参数由地址线提供,地址线不同的位分别用于表示不
同的参数。SDRAM通过配置模式寄存器来确定芯片的工作方式,包括突发长度(Burst Length)、
潜伏期(CAS Latency)以及操作模式等。
需要注意的是,在模式寄存器设置指令发出之后,需要等待一段时间才能够向SDRAM发送
新的指令,这个时间我们称之为模式寄存器设置周期tRSC(Register Set Cycle)。
2、行激活
初始化完成后,无论是读操作还是写操作,都要先激活(Active)SDRAM中的一行,使之
处于活动状态(又称行有效)。在此之前还要进行SDRAM芯片的片选和L-Bank的定址,不过它
们与行激活可以同时进行。
![9bfd828eedfdd8ee78b91f7f928359c1.png](https://img-blog.csdnimg.cn/img_convert/9bfd828eedfdd8ee78b91f7f928359c1.png)
图 33.1.6 行激活时序图
从上图可以看出,在片选CS#(#表示低电平有效)、L-Bank定址的同时,RAS(Row Address
Strobe,行地址选通脉冲)也处于有效状态。此时An地址线则发送具体的行地址。如图中是A0-
A11,共有12个地址线,由于是二进制表示法,所以共有4096个行(2^12=4096),A0-A11的不
同数值就确定了具体的行地址。由于行激活的同时也是相应L-Bank有效,所以行激活也可称为L-Bank有效。
3、列读写
行地址激活之后,就要对列地址进行寻址了。由于在SDRAM中,地址线是行列共用的,因
此列寻址时地址线仍然是A0-A11。在寻址时,利用RAS(Row Address Strobe,行地址选通脉
冲)与CAS(Column Address Strobe,列地址选通脉冲)来区分行寻址与列寻址,如图 33.1.7
所示。
图 33.1.7中“x16”表示存储单元容量为16bit。一般来说,在SDRAM中存储阵列(L-Bank)
的列数小于行数,即列地址位宽小于行地址,因此在列地址选通时地址线高位可能未用到,如
下图中的A9、A11。
另外,列寻址信号与读写命令是同时发出的,读/写命令是通过WE(Write Enable,写使
能)信号来控制的,WE为低时是写命令,为高时是读命令。
![717147c2c08d5ee32a87c5d7bd2d584f.png](https://img-blog.csdnimg.cn/img_convert/717147c2c08d5ee32a87c5d7bd2d584f.png)
图 33.1.7 列选通与读操作时序图
然而,在发送列读写命令时必须要与行激活命令有一个时间间隔,这个间隔被定义为tRCD,
即RAS to CAS Delay(RAS至CAS延迟)。这是因为在行激活命令发出之后,芯片存储阵列电子
元件响应需要一定的时间。tRCD是SDRAM的一个重要时序参数,广义的tRCD以时钟周期(tCK,
Clock Time)数为单位,比如tRCD=3,就代表RAS至CAS延迟为三个时钟周期,如图 33.1.8所
示。具体到确切的时间,则要根据时钟频率而定。
![31400caa683c48c8f6ac78d96568a9ac.png](https://img-blog.csdnimg.cn/img_convert/31400caa683c48c8f6ac78d96568a9ac.png)
图 33.1.8 tRCD = 3时序图
4、 数据输出(读)
在选定列地址后,就已经确定了具体的存储单元,剩下的事情就是数据通过数据I/O通道
(DQ)输出到内存总线上了。但是在CAS发出之后,仍要经过一定的时间才能有数据输出,从
CAS与读取命令发出到第一笔数据输出的这段时间,被定义为CL(CAS Latency,CAS潜伏期)。
CL时间越短,读数据时SDRAM响应就越快。由于CL只在读取时出现,所以CL又被称为读取潜伏
期(RL,Read Latency)。CL的单位与tRCD一样,为时钟周期数,具体耗时由时钟频率决定。
![c2d4ff113e02eea9ed0c8c5333d64155.png](https://img-blog.csdnimg.cn/img_convert/c2d4ff113e02eea9ed0c8c5333d64155.png)
图 33.1.9 CL = 2 时序图
5、数据输入(写)
数据写入的操作也是在tRCD之后进行,但此时没有了CL(记住,CL只出现在读取操作中),
行寻址与列寻址的时序图和上文一样,只是在列寻址时,WE#为有效状态。
![fe1c8c2839acf297c2e6485210362d6c.png](https://img-blog.csdnimg.cn/img_convert/fe1c8c2839acf297c2e6485210362d6c.png)
图 33.1.10 数据写入的时序图
从上图中可见,数据与写指令同时发送。不过,数据并不是即时地写入存储单元,数据的
真正写入需要一定的周期。为了保证数据的可靠写入,都会留出足够的写入/校正时间(tWR,
Write Recovery Time),这个操作也被称作写回(Write Back)。tWR至少占用一个时钟周期
或再多一点(时钟频率越高,tWR占用周期越多)。
6、突发长度
突发(Burst)是指在同一行中相邻的存储单元连续进行数据传输的方式,连续传输所涉
及到存储单元(列)的数量就是突发长度(Burst Lengths,简称BL)。
上文讲到的读/写操作,都是一次对一个存储单元进行寻址。然而在现实中很少只对SDRAM
中的单个存储空间进行读写,一般都需要完成连续存储空间中的数据传输。在连续读/写操作
时,为了对当前存储单元的下一个单元进行寻址,需要不断的发送列地址与读/写命令(行地
址不变,所以不用再对行寻址),如图 33.1.11所示:
![b0ee64f26b21b326a039137174aeb708.png](https://img-blog.csdnimg.cn/img_convert/b0ee64f26b21b326a039137174aeb708.png)
图 33.1.11 非突发连续读操作
由上图可知,虽然由于读延迟相同可以让数据的传输在I/O端是连续的,但它占用了大量
的内存控制资源,在数据进行连续传输时无法输入新的命令,效率很低。为此,人们开发了突
发传输技术,只要指定起始列地址与突发长度,内存就会依次地自动对后面相应数量的存储单
元进行读/写操作而不再需要控制器连续地提供列地址。这样,除了第一笔数据的传输需要若
干个周期(主要是之前的延迟,一般的是tRCD+CL)外,其后每个数据只需一个周期的延时即
可获得。如图 33.1.12所示:
![3f6bd747414a08529931d53a2dec6053.png](https://img-blog.csdnimg.cn/img_convert/3f6bd747414a08529931d53a2dec6053.png)
图 33.1.12 突发连续读操作
至于BL的数值,也是不能随便设或在数据进行传输前临时决定。在上文讲到的初始化过程
中的模式寄存器配置(MRS)阶段就要对BL进行设置。突发长度(BL)可以为1、2、4、8和“全
页(Full Page)”,其中“全页”是指突发传输一整行的数据量。
另外,在MRS阶段除了要设定BL数值之外,还需要确定“读/写操作模式”以及“突发传输
模式”。读/写操作模式分为“突发读/突发写”和“突发读/单一写”。 突发读/突发写表示
读和写操作都是突发传输的,每次读/写操作持续BL所设定的长度,这也是常规的设定。突发
读/单一写表示读操作是突发传输,写操作则只是一个个单独进行。
突发传输模式代表着突发周期内所涉及到的存储单元的传输顺序。顺序传输是指从起始单
元开始顺序读取。假如BL=4,起始存储单元编号是n,突发传输顺序就是n、n+1、n+2、n+3。
交错传输就是打乱正常的顺序进行数据传输(比如第一个进行传输的单元是n,而第二个进行
传输的单元是n+2而不是n+1)。由于交错传输很少用到,它的传输规则在这里就不详细介绍了,
大家可以参考所选用的SDRAM芯片手册。
7、预充电
在对SDRAM某一存储地址进行读写操作结束后,如果要对同一L-Bank的另一行进行寻址,
就要将原来有效(工作)的行关闭,重新发送行/列地址。L-Bank关闭现有工作行,准备打开
新行的操作就是预充电(Precharge)。在读写过程中,工作行内的存储体由于“行激活”而使存储电容受到干扰,因此在关闭工作行前需要对本行所有存储体进行重写。预充电实际上就
是对工作行中所有存储体进行数据重写,并对行地址进行复位,以准备新行工作的过程。
预充电可以通过命令控制,也可以通过辅助设定让芯片在每次读写操作之后自动进行预充
电。现在我们再回过头看看读写操作时的命令时序图(图 33.1.7),从中可以发现地址线A10
控制着是否进行在读写之后对当前L-Bank自动进行预充电,这就是上文所说的“辅助设定”。
而在单独的预充电命令中,A10则控制着是对指定的L-Bank还是所有的L-Bank(当有多个L-Bank
处于有效/活动状态时)进行预充电,前者需要提供L-Bank的地址,后者只需将A10信号置于高
电平。
在发出预充电命令之后,要经过一段时间才能发送行激活命令打开新的工作行,这个间隔
被称为tRP(Precharge command Period,预充电有效周期),如图 33.1.13所示。和tRCD、
CL一样,tRP的单位也是时钟周期数,具体值视时钟频率而定。
![f7f0b233a8254f4b6ab551898e74f666.png](https://img-blog.csdnimg.cn/img_convert/f7f0b233a8254f4b6ab551898e74f666.png)
图 33.1.13 读取时预充电时序图(CL=2、BL=4、tRP=2)
自动预充电的开始时间与上图一样,只是没有了单独的预充电命令,并在发出读取命令时,
A10地址线要设为高电平(允许自动预充电)。可见控制好预充电启动时间很重要,它可以在
读取操作结束后立刻进入新行的寻址,保证运行效率。
写操作时,由于每笔数据的真正写入则需要一个足够的周期来保证,这段时间就是写回周
期(tWR)。所以预充电不能与写操作同时进行,必须要在tWR之后才能发出预充电命令,以确
保数据的可靠写入,否则重写的数据可能出错,如图 33.1.14所示。
![7ab5d3cfd74070f2fc13bc1c07fa5cdc.png](https://img-blog.csdnimg.cn/img_convert/7ab5d3cfd74070f2fc13bc1c07fa5cdc.png)
图 33.1.14 写入时预充电时序图(BL=4、tWR=1、tRP=2)
8、刷新
SDRAM之所以称为同步“动态”随机存储器,就是因为它要不断进行刷新(Refresh)才能
保留住数据,因此刷新是SDRAM最重要的操作。
刷新操作与预充电类似,都是重写存储体中的数据。但为什么有预充电操作还要进行刷新
呢?因为预充电是对一个或所有L-Bank中的工作行(处于激活状态的行)操作,并且是不定期
的;而刷新则是有固定的周期,并依次对所有行进行操作,以保留那些久久没经历重写的存储
体中的数据。但与所有L-Bank预充电不同的是,这里的行是指所有L-Bank中地址相同的行,而
预充电中各L-Bank中的工作行地址并不是一定是相同的。
那么要隔多长时间重复一次刷新呢?目前公认的标准是,存储体中电容的数据有效保存期
上限是64ms,也就是说每一行刷新的循环周期是64ms。我们在看SDRAM芯片参数时,经常会看
到4096 Refresh Cycles/64ms或8192 Refresh Cycles/64ms的标识,这里的4096与8192就代表
这个芯片中每个L-Bank的行数。刷新命令一次仅对一行有效,也就是说在64ms内这两种规格的
芯片分别需要完成4096次和8192次刷新操作。因此,L-Bank为4096行时刷新命令的发送间隔为
15.625μs(64ms/4096),8192行时为7.8125μs(64ms/8192)。
刷新操作分为两种:自动刷新(Auto Refresh,简称AR)与自刷新(Self Refresh,简称
SR)。不论是何种刷新方式,都不需要外部提供行地址信息,因为这是一个内部的自动操作。
对于自动刷新(AR),SDRAM内部有一个行地址生成器(也称刷新计数器)用来自动生成行地
址。由于刷新是针对一行中的所有存储体进行,所以无需列寻址,或者说CAS在RAS之前有效。
所以,AR又称CBR(CAS Before RAS,列提前于行定位)式刷新。
在自动刷新过程中,所有L-Bank都停止工作。每次刷新操作所需要的时间为自动刷新周期
(tRC),在自动刷新指令发出后需要等待tRC才能发送其他指令。64ms之后再次对同一行进行
刷新操作,如此周而复始进行循环刷新。显然,刷新操作肯定会对SDRAM的性能造成影响,但
这是没办法的事情,也是DRAM相对于SRAM(静态内存,无需刷新仍能保留数据)取得成本优势的同时所付出的代价。
自刷新(SR)主要用于休眠模式低功耗状态下的数据保存。在发出AR命令时,将CKE置于
无效状态,就进入了SR模式,此时不再依靠系统时钟工作,而是根据内部的时钟进行刷新操作。
在SR期间除了CKE之外的所有外部信号都是无效的(无需外部提供刷新指令),只有重新使CKE
有效才能退出自刷新模式并进入正常工作状态。
9、数据掩码
在讲述读/写操作时,我们谈到了突发长度。如果BL=4,那么也就是说一次就传送4笔数据。
但是,如果其中的第二笔数据是不需要的,怎么办?还要传输吗?为了屏蔽不需要的数据,人
们采用了数据掩码(Data I/O Mask,简称DQM