第1节 SDRAM读写控制器
--作者:小黑同学 本文为明德扬原创及录用**,转载请注明出处!
1.1 总体设计1.1.1 概述同步动态随机存取内存(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.4模块功能
按键检测模块实现功能1、 将外来异步信号打两拍处理,将异步信号同步化。 2、 实现20ms按键消抖功能。 3、 实现矩阵键盘或者普通案件的检测功能,并输出有效按键信号。
锁相环1、产生工程所需要的100M时钟。
数据产生模块实现功能
1、 通过按键控制产生读/写请求。 2、 通过按键控制Bank地址选择。 3、 产生地址和写数据。
SDRAM接口模块实现功能
1、 接收上游模块发送的读/写请求、Bank地址、行地址和写数据,产生SDRAM的控制时序。
1.1.5顶层信号 信号名 | | | | | | | | | | | | | | | 4位按键信号,开发板按键为矩阵键盘时,不需要该信号 | | | | 4位矩阵键盘列信号,默认高电平,开发板按键为普通按键时,不需要该信号 | | | | 4位矩阵键盘行信号,默认低电平,开发板按键为普通按键时,不需要该信号 | | | | SDRAM数据总线,既能作为数据输出,也能作为数据输入。 | | | | SDRAM时钟使能信号,决定是否启用clk输入,为高电平时,时钟有效。 | | | | SDRAM片选信号,决定设备内是否启用命令输入,当cs为低时启用,当cs为高时禁用命令输入。 | | | | | | | | | | | | | | | | 数据掩码,控制I/O的高低字节,低电平有效。例如:2’b10,表示数据高字节无效,低字节有效。 | | | | | | | | Bank地址选择信号,通过该信号决定哪个Bank正处于激活、读、写、预充电等命令期间。 | | | | SDRAM输入时钟,除cke外,SDRAM的所有输入与该引脚的上升沿同步获得。 |
1.1.6三态门
由于SDRAM只有一条数据总线,虽然可以既当作输入,又当作输出来用,但是输入和输出是不能同时进行的,因此需要在工程的顶层设计中采用三态门。关于三态门详细的介绍可以看明德扬《FPGA至简设计原理与应用》书中的第一篇第三章5.2.4高阻态一节。 【FPGA至简设计原理与应用】书籍连载03第一篇FPGA基础知识第三章硬件描述语言Verilog
1.1.7参考代码下面是使用工程的顶层代码: - module sdram_top(
- clk ,
- rst_n ,
- key ,
- dq ,
- cke ,
- cs ,
- ras ,
- cas ,
- we ,
- dqm ,
- sd_addr ,
- sd_bank ,
- sd_clk
- );
- input clk ;
- input rst_n ;
- input [3:0] key ;
- inout [15:0] dq ;
- output cke ;
- output cs ;
- output ras ;
- output cas ;
- output we ;
- output [1 :0] dqm ;
- output [12:0] sd_addr ;
- output [1 :0] sd_bank ;
- output sd_clk ;
- wire cke ;
- wire cs ;
- wire ras ;
- wire cas ;
- wire we ;
- wire [1 :0] dqm ;
- wire [12:0] sd_addr ;
- wire [1 :0] sd_bank ;
- wire sd_clk ;
- wire clk_100m ;
- wire wr_ack ;
- wire rd_ack ;
- wire wr_req ;
- wire rd_req ;
- wire [1 :0] bank ;
- wire [12:0] addr ;
- wire [15:0] wdata ;
- wire [15:0] rdata ;
- wire rdata_vld;
- wire [3:0 ] key_vld ;
- wire [15:0] dq_in ;
- wire [15:0] dq_out ;
- wire dq_out_en;
- assign dq_in = dq;
- assign dq = dq_out_en?dq_out:16'hzzzz;
- pll_100m uut_pll(
- .inclk0 (clk ),
- .c0 (clk_100m )
- );
- key_module uut_key(
- .clk (clk_100m ),
- .rst_n (rst_n ),
- .key_in (key ),
- .key_vld (key_vld ),
- );
- data_ctrl uut_ctrl(
- .clk (clk_100m ),
- .rst_n (rst_n ),
- .key_vld (key_vld ),
- .wr_ack (wr_ack ),
- .rd_ack (rd_ack ),
- .wr_req (wr_req ),
- .rd_req (rd_req ),
- .bank (bank ),
- .addr (addr ),
- .wdata (wdata )
- );
- sdram_intf uut_sdram(
- .clk (clk_100m ),
- .rst_n (rst_n ),
- .wr_req (wr_req ),
- .rd_req (rd_req ),
- .bank (bank ),
- .addr (addr ),
- .wdata (wdata ),
- .dq_in (dq_in ),
- .dq_out (dq_out ),
- .dq_out_en (dq_out_en),
- .wr_ack (wr_ack ),
- .rd_ack (rd_ack ),
- .rdata (rdata ),
- .rdata_vld (rdata_vld),
- .cke (cke ),
- .cs (cs ),
- .ras (ras ),
- .cas (cas ),
- .we (we ),
- .dqm (dqm ),
- .sd_addr (sd_addr ),
- .sd_bank (sd_bank ),
- .sd_clk (sd_clk )
- );
- endmodule
[color=rgb(51, 102, 153) !important]复制代码
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接口信号
|