完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
第1节 SDRAM读写控制器
--作者:小黑同学 本文为明德扬原创及录用文章,转载请注明出处! 同步动态随机存取内存(synchronousdynamic randon-access menory,简称SDRAM)是有一个同步接口的动态随机存取内存(DRAM)。通常DRAM是有一个异步接口的,这样它可以随时响应控制输入的变化。而SDRAM有一个同步接口,在响应控制输入前会等待一个时钟信号,这样就能和计算机的系统总线同步。时钟被用来驱动一个有限状态机,对进入的指令进行管线操作。这使得SDRAM与没有同步接口的异步DRAM相比,可以有一个更复杂的操作模式。 管线意味着芯片可以在处理完之前的指令前,接受一个新的指令。在一个写入的管线中,写入命令在另一个指令执行完之后可以立刻执行,而不需要等到数据写入存储队列的时间。在一个读取的流水线中,需要的数据在读取指令发出之后固定数量的时钟频率后到达,而这个等待的过程可以发出其他附加指令。这种延迟被称为等待时间(Latency),在为计算机购买内存时是一个很重要的参数。 SDRAM之所以称为DRAM就是因为他要不断进行刷新才能保留住数据,因为刷新是DRAM最重要的操作。那么要隔多长时间重复一次刷新,目前公认的标准是,存储体中电容的数据有效保存期上限是64ms,也就是每一行刷新的循环周期是64ms。 SDRAM是多Bank结构,例如在一个具有两个Bank的SDRAM模组中,其中一个Bank在进行预充电期间,另一个Bank却马上可以被读取,这样当进行一次读取后,又马上读取已经预充电Bank的数据时,就无需等待而是可以直接读取了,这也就大大提高了存储器的访问速度 1.1.2 设计目标 设计SDRAM读写控制器来控制开发板上的一片SDRAM进行读写数据的操作,具体功能要求如下: 1. SDRAM的读写分别由两个按键进行控制,每按下一次,就会产生一个读使能或者写使能; 2. SDRAM读写模式为全页突发模式,每次写入某个Bank512个数据,在读此Bank的时候,也应该读出相同的512个数据; 3. SDRAM读写地址都是从地址0开始; 4. 通过一个按键控制读写SDRAM的Bank地址,按键每按下一次,Bank地址加1。 1.1.3 系统结构框图 系统结构框图如下图一所示: 图一 1.1.4模块功能按键检测模块实现功能 1、 将外来异步信号打两拍处理,将异步信号同步化。 2、 实现20ms按键消抖功能。 3、 实现矩阵键盘或者普通案件的检测功能,并输出有效按键信号。 锁相环 1、产生工程所需要的100M时钟。 1、 通过按键控制产生读/写请求。 2、 通过按键控制Bank地址选择。 3、 产生地址和写数据。 SDRAM接口模块实现功能 1、 接收上游模块发送的读/写请求、Bank地址、行地址和写数据,产生SDRAM的控制时序。 1.1.5顶层信号
1.1.6三态门 由于SDRAM只有一条数据总线,虽然可以既当作输入,又当作输出来用,但是输入和输出是不能同时进行的,因此需要在工程的顶层设计中采用三态门。代码如下: 关于三态门详细的介绍可以看明德扬《FPGA至简设计原理与应用》书中的第一篇第三章5.2.4高阻态一节。 【FPGA至简设计原理与应用】书籍连载03第一篇FPGA基础知识第三章硬件描述语言Verilog 1.1.7参考代码 下面是使用工程的顶层代码:
1.2 按键检测模块设计1.2.1接口信号 下面为使用矩阵键盘时的接口信号:
下面是使用普通按键时的接口信号:
1.2.2 设计思路 在前面的按键控制数字时钟的案例中已经有介绍,所以这里不在过多介绍,详细介绍请看下方链接: http://fpgabbs.com/forum.php?mod=viewthread&tid=310 1.2.3 参考代码 1. //矩阵键盘
1.3 锁相环1.3.1 接口信号
1.3.2 设计思路 此模块是使用Quartus生成的PLL IP核,相关的生成步骤、功能原理等可以看明德扬论坛中关于PLL的介绍。 IP核设计(PLL) 1.4 数据产生模块设计1.4.1接口信号
1.4.2设计思路 该模块主要实现的功能是根据按键,产生读请求、写请求、Bank地址、写数据和SDRAM地址。下面是该模块主要信号的设计思路: 写请求wr_req:初始状态为低电平,表示没有往SDRAM里面写数据的请求;当按下按键key1的时候,写请求变为高电平,表示请求往SDRAM内部写入数据,因此写请求拉高的条件为key_vld[0]==1;当接收到接收到写响应为高电平的时候,表示同意往SDRAM写入数据,此时将写请求置为低电平,因此写请求的拉低条件为wr_ack==1。 读请求rd_req:初始状态为低电平,表示没有读出SDRAM中数据的请求;当按下按键key2的时候,读请求变为高电平,表示请求读出SDRAM内部数据,因此读请求拉高的条件为key_vld[1]==1;当接收到接收到读响应为高电平的时候,表示SDRAM同意读出数据,此时将读请求置为低电平,因此读请求的拉低条件为rd_ack==1。 读写Bank地址信号bank:初始状态为0,表示默认选择Bank0进行数据的读写操作;加一条件为key_vld[2]==1,表示按键key3每按下一次,Bank地址就加一;结束条件为数4个,因为一片SDRAM共有4个Bank,数完就清零。 SDRAM地址信号addr:固定为0即可。 写数据wdata:该信号表示要写入SDRAM中的数据,在接收到写响应后有效。设置时钟计数器cnt2,在收到写响应之后开始计数,由于本工程使用SDRAM全页突发模式一次写数据为512个,因此该计数器结束条件为数512个,将该计数器的值作为写数据。 1.4.3参考代码
1.5 SDRAM接口模块设计1.5.1接口信号
1.5.2SDRAM工作流程 SDRAM初始化 再SDRAM内部有一个逻辑控制单元,并且有一个模式寄存器为其提供控制参数。每次开机时SDRAM都要先对这个控制逻辑核心进行初始化。SDRAM必须以预定义的方式启动和初始化。在电源同时作用于Vdd和Vddq后开始初始化SDRAM,此时的时钟稳定并且将数据掩码和时钟使能信号拉高。在向SDRAM发送命令之前需要有100us的延时,此时SDRAM不执行任何操作。在100us延时满足后,需要对Bank进行预充电,在此期间所有的Bank处于空闲状态。预充电之后会有至少两个自刷新操作,完成自刷新便可以对SDRAM进行模式寄存器配置。下面是初始化的时序图 从上图中可以看出,上电后等待时间为T=100us,预充电操作需要的时间为TRP,一次自刷新需要的时间是TRC,加载模式寄存器需要的时间为TMRD。 在初始化中的预充电期间,地址线A10定义自动预充电,以确定是否所有Bank都被预充电,也可以通过Bank地址选择信号BA0和BA1来决定进行预充电的Bank地址。在加载模式寄存器期间,地址线A0到A11一起组成命令码。 初始化完成之后,在向SDRAM发送读或者写命令之前必须打开该Bank中的一行,通过ACTIVE命令来确定要激活的Bank和行。要想对一个Bank中的阵列进行寻址,首先要确定行(Row),然后确定列。片选信号与Bank选择信号与行有效同时进行,下面是激活的时序图 从上图中可以看出,在片选信号、Bank地址选定的同时,行地址选通信号RAS也处于有效状态,此时An地址线发送具体的行地址。行地址位宽为12,共可以指示2^12=4096个具体的行地址。当行地址被激活后,相应的Bank也被激活,因此行激活又叫L-Bank激活。 行地址确定后,就要对列地址进行寻址,地址线仍使用A0~A11,即行地址与列地址共用地址线。当列地址选通后,就需要对SDRAM进行读写,而给SDRAM读命令还是写命令由WE信号决定。当WE信号拉低时,SDRAM接收到的是写命令;当WE拉高,SDRAM接收读命令。列寻址信号与读写命令是同时发出的。虽然地址线与行寻址共用,但列地址选通脉冲CAS则可以区分开行与列寻址的不同,配合A0~A9、A11来确定具体的地址。 在发送列读写命令时必须要与有效命令有一个时间间隔,这个时间间隔被定义为TRCD。 读操作 读命令从输入信号BA0、BA1中选取要进行读数据操作的BANK,并在已激活的行中进行突发读写操作。输入的A0~A7用来进行列寻址。在选定列地址后,就已经确定了具体的存储单元,剩下的事情就是数据通过dq输出到内存总线上了。但是再CAS发出之后,仍要经过一定的时间才能有数据输出,从CAS与读取命令发出到第一个数据输出的这段时间,被定义为CALLatency(CAS潜伏期)。由于此现象只在读的时候出现,所以又称作读潜伏期 由于存储体中晶体管存在反应时间,从而造成数据不可能与CAS 在同一上升沿触发,因此要延后至少一个时钟周期。考虑到芯片体积较小的因素,存储单元中的电容容量很小,所以信号要经过放大来保证其有效的识别性,这个放大/驱动工作由 S-AMP 负责,一个存储体对应一个 S-AMP 通道。但它要有一个准备时间才能保证信号的发送强度(事前还要进行电压比较以进行逻辑电平的判断),因此从数据 I/O 总线上有数据输出之前的一个时钟上升沿开始,数据即已传向 S-AMP,也就是说此时数据已经被触发,经过一定的驱动时间最终传向数据 I/O 总线进行输出,这段时间我们称之为 tAC(Access-Time-from-CLK,时钟触发后的访问时间),单位是 ns。在突发读操作完成后,如果选择了自动预充电模式,那么该行就会直接进入充电。如果没有选择此模式,那么该行将保持打开状态,供后续访问。自动预充电模式的选择与 A10的值有关,A10 为高时为自动预充电命令模式。 数据写入的操作也是在 tRCD 之后进行,但此时没有 CL(CL 只出现在读取操作中),行寻址与列寻址的时序一样致,只是在列寻址时,WE#为有效状态。由于数据信号由控制端发出,输入时芯片无需做任何调校,只需直接传到数据输入寄存器中,然后再由写入驱动器进行对存储电容的充电操作,因此数据可以与 CAS 同时发送,也就是说写入延迟为 0。不过,数据并不是即时地写入存储电容,因为选通三极管(就如读取时一样)与电容的充电必须要有一段时间,所以数据的真正写入需要一定的周期。 突发(Burst)是指在同一行中相邻的存储单元连续进行数据传输的方式,连续传输所涉及到存储单元(列)的数量就是突发长度(Burst Lengths,简称 BL)。前文讲到的读/写操作,都是一次对一个存储单元进行寻址,如果想要连续的向 SDRAM 中读数据或者写数据,就需要对当前存储单元的下一个单元进行寻址,也即是需要不停给 SDRAM 列激活信号以及读/写命令(行地址不变,所以不用再对行寻址)。虽然由于读/写延迟相同可以让数据的传输在 I/O 端是连续的,但它占用了大量的内存控制资源,在数据进行连续传输时无法输入新的命令,效率很低。为此,人们开发了突发传输技术,只要指定起始列地址与突发长度,SDRAM 就会不再需要控制器连续地提供列地址,依次地自动对后面相应数量的存储单元进行读/写操作。这样,在突发模式读写中,除了第一个数据的传输需要若干个周期(主要是之前的延迟,一般的是tRCD+CL),其后每个数据只需一个周期的即可获得。至于突发长度 BL 的数值,也是不能随便设或在数据进行传输前临时决定,而是在上文讲到的 SDRAM 初始化过程中模式寄存器配置阶段就要对突发长度进行设置。目前可用的选项是 1、2、4、8、全页(FullPage),常见的突发长度设定是 BL=4、BL=8 或者全页突发模式。 1.5.3设计思路 经过上面对SDRAM工作流程的介绍,可以采用状态机作为本工程的一个架构,根据指令的不同,划分为8个状态,分别为空操作(NOP)、预充电(PER)、自刷新(REF)、加载模式寄存器(MOD)、空闲(IDL)、激活(ACT)、读数据(RED)和写数据(WIR)。 由于每个操作需要的时间都不同,因此需要一个计数器来对每个操作需要的时间进行计数。 该计数器加一条件为state_c!=IDL,表示只要不是处于空闲状态,就进行计数;结束条件为数x个,x根据目前所处的状态的不同而不同,具体数据可以看下面的表格。
由于再初始化阶段,自刷新需要连续进行两次,因此需要将初始化阶段区分出来,设计一个初始化指示信号init_flag:该信号初始状态为高电平,表示上电之后SDRAM处于初始化阶段;当初始化完成之后变为低电平,因此从高变低的条件为mod2idl_start。 自刷新计数器cnt1:该计数器表示初始化阶段进行自刷新的次数。加一条件为(init_flag && state_c==REF && end__cnt),表示在初始化阶段,如果当前状态为自刷新,则时钟计数器数完一次就加一;结束条件为数两个,初始化阶段共进行两次自刷新,因此只需要数两个即可。 在初始化完成之后,需要进行自刷新、读数据和写数据等操作,由于自刷新是必须进行的,因此自刷新请求的优先级是最高的,那么读请求和写请求的优先级怎么确定呢?假设设置读请求的优先级高于写请求,读请求和写请求一起来的时候,总是先执行读请求,如果读请求一直有效的话,便不会执行写操作。反之设置写请求的优先级高于读请求,也会出现这样的问题,这当然是不可以的。因此我们设置为如果两个请求不是同时有效,则哪一个有效便执行哪一个。如果同时来的时候,第一次同时来,先执行写操作,第二次同时有效的时候在执行写操作,如此交替进行即可。通过两个信号进行控制: 读操作指示信号flag_rd:初始状态为低电平,表示上一次执行的写操作;从低变高的条件为state_c==RED,表示如果执行的是读操作,则置为高电平;当执行的是写操作的时候,该信号置为0,所以变0的条件是state_c==WIR。 读写同步指示信号flag_syn:初始状态为0,表示读写请求没有同时有效,如果当前处于激活状态,并且读写请求同时有效,则置为1,当激活状态结束,重新变为0。 设计中的辅助信号已经完成的差不多了,下面开始进行状态机的架构,架构图如下图所示: 下面介绍一个各个状态之间的跳转条件。 上电之后,先进入空操作状态,在空操作状态下: 1、 延时100us之后,进入到预充电状态。 当处于预充电状态的时候: 1、 如果处于初始化阶段,两个时钟周期之后,跳转到自刷新状态。 2、 如果不是初始化阶段,两个时钟周期之后,跳转到空闲状态。 当处于自刷新状态时: 1、 如果处于初始化状态,7个时钟周期之后,跳转到自刷新状态。 2、 如果处于初始化状态,并且已经进行过一次初始化,7个时钟周期之后,跳转到加载模式寄存器状态。 3、 如果不是初始化阶段,7个时钟周期之后,跳转到空闲状态。 当处于加载模式寄存器状态时: 1、 2个时钟周期之后,进入到空闲状态。 当处于空闲状态时: 1、 如果收到自刷新请求,则跳转到自刷新状态。 2、 如果自刷新请求无效,收到读/写请求,则跳转到激活状态。 当处于处于激活状态时: 1、 当读写请求不同时的时候,接收到读请求,则跳转到读状态。 2、 当读写请求不同时的时候,接收到写请求,则跳转到写状态 3、 当读写请求同时到达的时候,第一次来的时候,首先响应读请求,跳转到读状态 4、 当读写请求同时到达,但不是第一次同时有效的时候,则根据上一次执行的操作进行判断,如果上一次执行的读操作,则这次执行写操作,跳转到写状态;如果上一次执行的写操作,则这次执行读操作,跳转到读状态。 当处于写状态的时候: 1、 写数据完成,就进入到预充电状态。 当处于读状态的时候: 1、 读数据完成,就进入到预充电状态。 指令集信号conmand:该信号共4bit,从最高位到最低位分别表示cs、ras、cas、we。在空操作阶段,指令为4’b0111;在预充电阶段,指令为4’b0010;在自刷新阶段,指令为4’b0001;在加载模式寄存器阶段,指令为4’b0000;在激活阶段,指令为4’b0011;在读数据阶段,指令为4’b0101;在写数据阶段,指令为4’b0100。这些操作对应的指令码都是从图中的表格中查找得来。 数据掩码dqm:初始状态为2’b11,表示输入得两个字节数据无效。当初始化完成之后,变为2’b00,表示输入得两个字节数据有效。 时钟使能cke:复位时为0,表示输入时钟无效,复位结束之后为1,表示输入时钟有效。 Bank选择信号sd_bank:初始状态为2’b00,表示选择Bank0;在激活阶段、读阶段和写阶段,该信号由输入得bank信号决定。 SDRAM地址选择信号sd_addr:由于本工程采用的预充电模式为全Bnak自动预充电,该模式由地址线A10控制,因此在预充电得时候,地址指令为13’b001_0_00_000_0_000;在激活的时候提供行地址;在加载模式寄存器得时候,地址线提供运算码,这时每个地址表示得意思入下图所示,A9决定读模式,A6、A5、A4决定读数据得潜伏期,A3决定突发类型,A2、A1、A0决定突发长度。 由于MP801开发板使用得SDRAM有两种型号,一种是W9812G6KH,共4096行,自刷新周期为1562,另一种是H57V2562GTR,共8192行,自刷新周期为780。在使用得时候需要注意开发板型号,这里我们以H57V2562GTR为例。自刷新需要以下信号: 时钟计数器cnt_780:该计数器主要得作用是初始化结束之后,数自刷新得周期;加一条件为init_flag==0,表示初始化结束就开始计数;结束条件为数780个,数完就清零。 自刷新请求ref_req:初始状态为0,表示不需要进行自刷新,当时钟计数器cnt_780数完得时候,ref_req拉高,请求进行自刷新,如果当前处于空闲状态,则进行自刷新,如果不是,则等待。 可能有人会想,如果不是空闲状态,就要等待,这样会不会对数据保存造成影响?其实不会得,存储器要求64ms全部刷新一遍,但不需要每一行刷新得间隔都一样。当时钟计数器cnt_780数完之后,产生自刷新请求,同时时钟计数器又会开始计数,所以可能自刷新得间隔不同,但每一行肯定能在64ms内刷新1次。 写SDRAM数据信号dq_out:该信号直接等于写数据wdata(注意,需要用组合逻辑实现)。 三态门使能信号dq_out_en:初始状态为0,表示使能无效,在写数据期间,变为高电平,表示使能有效。 读SDRAM数据信号rdata:直接将sdram输出数据dq_in连接即可。 读数据有效指示信号rdata_vld:由于存在读数据潜伏期,根据设置得潜伏期得长度,将rdata_vld进行相应得延时。 1.5.4参考代码
1.6 效果和总结 该工程得上板效果使用signaltap进行捕捉来观测的,因此不同开发板的上板效果是一样,那么下面就只介绍mp801的上板现象。 下图是写数据的情况,Bank地址为0。写入SDRAM的数据为0~255。 下图是读数据的情况,Bank地址为0,潜伏期为2,读出的数据为0~255。 下图是读数据的情况,Bank地址为1,潜伏期为2,读出的数据不是0~255,这是因为我们写数据的地址是Bank0,而不是Bank1,Bank1中是没有数据,所以读出的数据就不是确定的。 感兴趣的朋友也可以访问明德扬论坛(http://www.fpgabbs.cn/)进行FPGA相关工程设计学习,也可以看一下我们往期的文章: 《基于FPGA的密码锁设计》 《波形相位频率可调DDS信号发生器》 《基于FPGA的曼彻斯特编码解码设计》 《基于FPGA的出租车计费系统》 《数电基础与Verilog设计》 《基于FPGA的频率、电压测量》 《基于FPGA的汉明码编码解码设计》 《关于锁存器问题的讨论》 《阻塞赋值与非阻塞赋值》 《参数例化时自动计算位宽的解决办法》 明德扬是一家专注于FPGA领域的专业性公司,公司主要业务包括开发板、教育培训、项目承接、人才服务等多个方向。点拨开发板——学习FPGA的入门之选。 MP801开发板——千兆网、ADDA、大容量SDRAM等,学习和项目需求一步到位。网络培训班——不管时间和空间,明德扬随时在你身边,助你快速学习FPGA。周末培训班——明天的你会感激现在的努力进取,升职加薪明德扬来助你。就业培训班——七大企业级项目实训,获得丰富的项目经验,高薪就业。专题课程——高手修炼课:提升设计能力;实用调试技巧课:提升定位和解决问题能力;FIFO架构设计课:助你快速成为架构设计师;时序约束、数字信号处理、PCIE、综合项目实践课等你来选。项目承接——承接企业FPGA研发项目。人才服务——提供人才推荐、人才代培、人才派遣等服务。 【设计教程下载】
至简设计系列案例_SDRAM读写控制器.pdf
(1.8 MB, 下载次数: 5
)
【代码下载】
01_sdram_top.zip
(19.57 KB, 下载次数: 5
)
|
|||
相关推荐
|
|||
潘老师压箱底的东西都拿出来了,必须顶一下!想学FPGA的可以关注一下潘老师!
|
|
|
|
|
|
1367 浏览 1 评论
助力AIoT应用:在米尔FPGA开发板上实现Tiny YOLO V4
1046 浏览 0 评论
2442 浏览 1 评论
2146 浏览 0 评论
矩阵4x4个按键,如何把识别结果按编号01-16(十进制)显示在两个七段数码管上?
2408 浏览 0 评论
1881 浏览 49 评论
6018 浏览 113 评论
浏览过的版块 |
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 11:51 , Processed in 0.581179 second(s), Total 41, Slave 31 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号