赞
踩
此篇是我在学习中做的归纳与总结,其中如果存在版权或知识错误请直接联系我,欢迎留言。
PS:本着知识共享的原则,此篇博客可以随意转载,但请标明出处!
目录
DDR3(全称:double-data-rate 3 synchronous dynamic RAM),即第三代双倍速率同步动态随机存储器。
1、同步是指DDR3数据的读取写入是按时钟同步的;
2、动态是指DDR3中的数据掉电无法保存,且需要周期性的刷新,才能保持数据;
3、随机存取即可以随机操作任一地址的数据;
4、double-data-rate,即时钟的上升沿和下降沿都发生数据传输。
micron的MT41K128M16TW;MT41K为型号,128M16表示DDR3容量大小为128M*16 = 2Gb;
该DDR3是8Bank配置,即BA[2:0];数据位宽配置为16bit;行地址A[13:0],列地址BA[2:0],那么算下来正好2Gb。
1、控制器单元:包括输入命令解析,模式配置&控制部分;
2、行地址选通单元:行激活通过此处操作;
3、Bank控制逻辑:行/列地址解码用到bank选通
4、列地址选择单元,读写操作同时在打开列地址的时候送到1;
5、锁存与控制逻辑:刷新与预充电用到该模块;
6、内部存储阵列,此处分8个bank,每个bank分16384行,128列;
7、读写数据缓存及接口驱动; dq数据在此变换位宽后内外交互;
启动:上电->解复位->初始化->ZQCL->LEVELING->IDLE(READY)
读:IDLE—>行激活—>读数据(1次或多次突发)—>预充电—>IDLE
写:IDLE—>行激活—>写数据(1次或多次突发)—>预充电—>IDLE
刷新:IDLE->REF->IDLE
自刷新的进入与退出:IDLE->SFR->IDLE
定期校正:IDLE—>ZQCS—>IDLE,一般外部温度或电压改变时操作
动态更改配置:IDLE->MRS/MPR->IDLE
ddr发起一次读的过程包含有:
1、Active命令—含带地址位,以选择Bank和Row地址(BAO-BA2选择BANK、AO-A13选择Row)。用于打开一个工作行。
2、Read命令—含带突发操作的起始Column地址和bank号,打开对应gating的列;
3、数据经过特定的延时(CL+AL);将数据传出IO;
4、完成数据传出后,需将当前cache的数据刷回存储整列并关闭当前工作行(携带命令和BA信息);[是否发布自动预充电命令(通过A10)]
(第三步与读操作不同,其他与读操作一致)
1、Active命令—含带地址位,以选择Bank和Row地址(BAO-BA2选择BANK、AO-A13选择Row)。用于打开一个工作行。
2、Write命令—含带突发操作的起始Column地址和bank号,打开对应gating的列;
3、数据经过特定的延时(CL+AL);将数据传入IO;
4、完成数据传出后,需将当前cache的数据刷回存储整列并关闭当前工作行(携带命令和BA信息);[是否发布自动预充电命令(通过A10)]
由于SDRAM的寻址具体独占性,所以在进行完读写操作后,如果要对同—L-Bank的另一行进行寻址,就要将原来有效(工作)的L行关闭,重新发送行/列地址。
L-Bank关闭现有工作行,准备打开新行的操作就是预充电(Precharge)。
预充电可以通过单独的命令控制,也可以通过辅助设定让芯片在每次读写操作之后自动进行预充电。(A10)
预充电的本质是一种对工作行中所有存储体进行数据重写,并对行地址进行复位,同时释放S-AMP。
上海勤谋电子科技有限公司推出的QM_XC7A35T开发板,采用Xilinx最新推出的7系列的XC7A35T-1FTG256C作为主控FPGA。
选择DDR3控制器的类型为“DDR3 SDRAM”
选择DDR3颗粒的工作频率为400MHz,1系列的最高支持频率为400MHz,所以测试时不要采用更高的测试工作频率,内存型号为:MT41J128M16HA-15E,实际上的DDR3数据率是时钟频率的2倍,单击Next:
配置“Controller Chip Select Pin”为“Disable”,这是为了在硬件设计时节省了一个FPGA的IO引脚资源,直接将DDR3 SDRAM的Chip Select引脚拉低保持片选信号一直有效
System Clock和Reference Clock时钟输入,Internal Vref等配置如下图所示
选择“Fixed Pin Out”
单击“Read XDC/UCF”按钮,然后跳出 “Load your UCF” 对话框,选择资料包里提供或者网上的“DDR3.ucf”文件。
DDR3.ucf 文件:
- NET "ddr3_dq[0]" LOC = "F15" ;
- NET "ddr3_dq[1]" LOC = "F13" ;
- NET "ddr3_dq[2]" LOC = "E16" ;
- NET "ddr3_dq[3]" LOC = "D11" ;
- NET "ddr3_dq[4]" LOC = "E12" ;
- NET "ddr3_dq[5]" LOC = "E13" ;
- NET "ddr3_dq[6]" LOC = "D16" ;
- NET "ddr3_dq[7]" LOC = "E11" ;
- NET "ddr3_dq[8]" LOC = "G12" ;
- NET "ddr3_dq[9]" LOC = "J16" ;
- NET "ddr3_dq[10]" LOC = "G16" ;
- NET "ddr3_dq[11]" LOC = "J15" ;
- NET "ddr3_dq[12]" LOC = "H14" ;
- NET "ddr3_dq[13]" LOC = "H12" ;
- NET "ddr3_dq[14]" LOC = "H16" ;
- NET "ddr3_dq[15]" LOC = "H13" ;
- NET "ddr3_dm[0]" LOC = "F12" ;
- NET "ddr3_dm[1]" LOC = "H11" ;
- NET "ddr3_dqs_p[0]" LOC = "D14" ;
- NET "ddr3_dqs_n[0]" LOC = "D15" ;
- NET "ddr3_dqs_p[1]" LOC = "G14" ;
- NET "ddr3_dqs_n[1]" LOC = "F14" ;
- NET "ddr3_addr[13]" LOC = "B11" ;
- NET "ddr3_addr[12]" LOC = "A8" ;
- NET "ddr3_addr[11]" LOC = "A9" ;
- NET "ddr3_addr[10]" LOC = "B12" ;
- NET "ddr3_addr[9]" LOC = "A13" ;
- NET "ddr3_addr[8]" LOC = "D8" ;
- NET "ddr3_addr[7]" LOC = "A12" ;
- NET "ddr3_addr[6]" LOC = "D9" ;
- NET "ddr3_addr[5]" LOC = "B10" ;
- NET "ddr3_addr[4]" LOC = "C9" ;
- NET "ddr3_addr[3]" LOC = "C14" ;
- NET "ddr3_addr[2]" LOC = "A14" ;
- NET "ddr3_addr[1]" LOC = "C8" ;
- NET "ddr3_addr[0]" LOC = "B14" ;
- NET "ddr3_ba[2]" LOC = "B15" ;
- NET "ddr3_ba[1]" LOC = "A15" ;
- NET "ddr3_ba[0]" LOC = "C16" ;
- NET "ddr3_ck_p[0]" LOC = "B9" ;
- NET "ddr3_ck_n[0]" LOC = "A10" ;
- NET "ddr3_ras_n" LOC = "B16" ;
- NET "ddr3_cas_n" LOC = "C11" ;
- NET "ddr3_we_n" LOC = "C12" ;
- NET "ddr3_reset_n" LOC = "E15" ;
- NET "ddr3_cke[0]" LOC = "D13" ;
- NET "ddr3_odt[0]" LOC = "C13" ;
然后完成IP核配置,MIG IP核例化如下所示:
- assign app_wdf_wren = app_en & app_wdf_rdy & app_rdy & (app_cmd == 3'd0);
- assign app_wdf_end = app_wdf_wren;
- assign app_addr = ( app_cmd == 3'd1 ) ? read_addr : write_addr ;
-
- mig_7series_0 u_mig_7series_0 (
- // Memory interface ports
- .ddr3_addr (ddr3_addr), // output [13:0] ddr3_addr
- .ddr3_ba (ddr3_ba), // output [2:0] ddr3_ba
- .ddr3_cas_n (ddr3_cas_n), // output ddr3_cas_n
- .ddr3_ck_n (ddr3_ck_n), // output [0:0] ddr3_ck_n
- .ddr3_ck_p (ddr3_ck_p), // output [0:0] ddr3_ck_p
- .ddr3_cke (ddr3_cke), // output [0:0] ddr3_cke
- .ddr3_ras_n (ddr3_ras_n), // output ddr3_ras_n
- .ddr3_reset_n (ddr3_reset_n), // output ddr3_reset_n
- .ddr3_we_n (ddr3_we_n), // output ddr3_we_n
- .ddr3_dq (ddr3_dq), // inout [15:0] ddr3_dq
- .ddr3_dqs_n (ddr3_dqs_n), // inout [1:0] ddr3_dqs_n
- .ddr3_dqs_p (ddr3_dqs_p), // inout [1:0] ddr3_dqs_p
- .init_calib_complete (init_calib_complete), // output init_calib_complete
- .ddr3_dm (ddr3_dm), // output [1:0] ddr3_dm
- .ddr3_odt (ddr3_odt), // output [0:0] ddr3_odt
- // Application interface ports
- .app_addr (app_addr), // input [27:0] app_addr
- .app_cmd (app_cmd), // input [2:0] app_cmd
- .app_en (app_en), // input app_en
- .app_wdf_data (app_wdf_data), // input [127:0] app_wdf_data
- .app_wdf_end (app_wdf_end), // input app_wdf_end
- .app_wdf_wren (app_wdf_wren), // input app_wdf_wren
- .app_rd_data (app_rd_data), // output [127:0] app_rd_data
- .app_rd_data_end (app_rd_data_end), // output app_rd_data_end
- .app_rd_data_valid (app_rd_data_valid), // output app_rd_data_valid
- .app_rdy (app_rdy), // output app_rdy
- .app_wdf_rdy (app_wdf_rdy), // output app_wdf_rdy
- .app_sr_req (1'b0), // input app_sr_req
- .app_ref_req (1'b0), // input app_ref_req
- .app_zq_req (1'b0), // input app_zq_req
- .app_sr_active (app_sr_active), // output app_sr_active
- .app_ref_ack (app_ref_ack), // output app_ref_ack
- .app_zq_ack (app_zq_ack), // output app_zq_ack
- .ui_clk (ui_clk), // output ui_clk
- .ui_clk_sync_rst (ui_clk_sync_rst), // output ui_clk_sync_rst
- .app_wdf_mask ( 16'd0 ), // input [15:0] app_wdf_mask
- // System Clock Ports
- .sys_clk_i (ddrclk_200Mhz),
- .sys_rst (~ ddr_rst_n) // input sys_rst
- );
本文阐述的DDR3应用场景为,首先读取SPI-Flash中数据,然后存储至DDR3中,最后读取DDR3中数据输出。
Verilog SPI-Flash读写总线控制模块程序:https://blog.csdn.net/m0_37779673/article/details/118033580
- always @(posedge ui_clk ) begin //DDR_output_clk is 200MHz
- if (!sys_rst_n) begin
- /// DDR3
- app_en <= 1'b0 ;
- app_cmd <= 3'd0 ;
- write_addr <= 28'd0 ;
- read_addr <= 28'd0 ;
- app_wdf_data <= 128'd0 ;
- end else begin
- case(top_state)
- 4'd0: begin // begin state
- if ( app_wdf_rdy & app_rdy ) begin // DDR3 is ready
- led_0 <= 0 ;
- flash_state <= 4'd0 ; //read flash ID
- end else
- led_0 <= 1;
- if ( flash_flag > 4'd0 ) //已读出一批数据
- top_state <= 4'd1 ;
- end
- 4'd1: begin // read Flash_data
- if ( rd_flash_data_cnt < 23'd8000000 ) begin //判断读取flash中数据数量
- cnt_rd_flash_data <= 3'd1 ;
- rd_flash_data_cnt <= rd_flash_data_cnt + 23'd4 ;
- flash_state <= 4'd1 ; //read flash 4bytes data
- flash_addr <= flash_addr + 24'd32 ;
- top_state <= 4'd2 ;
- end else begin
- rd_flash_data_cnt <= 0 ;
- flash_addr <= 0 ;
- top_state <= 4'd4 ;
- end
- end
- 4'd2: begin // build up DDR3 128bit save data
- flag_read_byte0 <= flag_read_byte ;
- l2h_flag_read_byte <= ( ~ flag_read_byte0 ) & flag_read_byte ;
- if ( l2h_flag_read_byte && (cnt_rd_flash_data == 1) ) begin
- cnt_rd_flash_data <= cnt_rd_flash_data + 3'd1 ;
- if ( flash_flag[0] == 1 ) begin
- app_wdf_data [ 7 : 0 ] <= read_flash_data0 ;
- end else begin
- app_wdf_data [ 7 : 0 ] <= 8'b0 ;
- end
-
- if ( flash_flag[1] == 1 ) begin
- app_wdf_data [ 15 : 8 ] <= read_flash_data1 ;
- end else begin
- app_wdf_data [ 15 : 8 ] <= 8'b0 ;
- end
- if ( flash_flag[2] == 1 ) begin
- app_wdf_data [ 23 : 16 ] <= read_flash_data2 ;
- end else begin
- app_wdf_data [ 23 : 16 ] <= 8'b0 ;
- end
-
- if ( flash_flag[3] == 1 ) begin
- app_wdf_data [ 31 : 24 ] <= read_flash_data3 ;
- end else begin
- app_wdf_data [ 31 : 24 ] <= 8'b0 ;
- end
- end
- if ( l2h_flag_read_byte && (cnt_rd_flash_data == 2) ) begin
- cnt_rd_flash_data <= cnt_rd_flash_data + 3'd1 ;
- if ( flash_flag[0] == 1 ) begin
- app_wdf_data [ 39 : 32 ] <= read_flash_data0 ;
- end else begin
- app_wdf_data [ 39 : 32 ] <= 8'b0 ;
- end
- if ( flash_flag[1] == 1 ) begin
- app_wdf_data [ 47 : 40 ] <= read_flash_data1 ;
- end else begin
- app_wdf_data [ 47 : 40 ] <= 8'b0 ;
- end
-
- if ( flash_flag[2] == 1 ) begin
- app_wdf_data [ 55 : 48 ] <= read_flash_data2 ;
- end else begin
- app_wdf_data [ 55 : 48 ] <= 8'b0 ;
- end
- if ( flash_flag[3] == 1 ) begin
- app_wdf_data [ 63 : 56 ] <= read_flash_data3 ;
- end else begin
- app_wdf_data [ 63 : 56 ] <= 8'b0 ;
- end
- end
- if ( l2h_flag_read_byte && (cnt_rd_flash_data == 3) ) begin
- cnt_rd_flash_data <= cnt_rd_flash_data + 3'd1 ;
- if ( flash_flag[0] == 1 ) begin
- app_wdf_data [ 71 : 64 ] <= read_flash_data0 ;
- end else begin
- app_wdf_data [ 71 : 64 ] <= 8'b0 ;
- end
-
- if ( flash_flag[1] == 1 ) begin
- app_wdf_data [ 79 : 72 ] <= read_flash_data1 ;
- end else begin
- app_wdf_data [ 79 : 72 ] <= 8'b0 ;
- end
- if ( flash_flag[2] == 1 ) begin
- app_wdf_data [ 87 : 80 ] <= read_flash_data2 ;
- end else begin
- app_wdf_data [ 87 : 80 ] <= 8'b0 ;
- end
-
- if ( flash_flag[3] == 1 ) begin
- app_wdf_data [ 95 : 88 ] <= read_flash_data3 ;
- end else begin
- app_wdf_data [ 95 : 88 ] <= 8'b0 ;
- end
- end
- if ( l2h_flag_read_byte && (cnt_rd_flash_data == 4) ) begin
- if ( flash_flag[0] == 1 ) begin
- app_wdf_data [ 103 : 96 ] <= read_flash_data0 ;
- end else begin
- app_wdf_data [ 103 : 96 ] <= 8'b0 ;
- end
-
- if ( flash_flag[1] == 1 ) begin
- app_wdf_data [ 111 : 104 ] <= read_flash_data1 ;
- end else begin
- app_wdf_data [ 111 : 104 ] <= 8'b0 ;
- end
- if ( flash_flag[2] == 1 ) begin
- app_wdf_data [ 119 : 112 ] <= read_flash_data2 ;
- end else begin
- app_wdf_data [ 119 : 112 ] <= 8'b0 ;
- end
-
- if ( flash_flag[3] == 1 ) begin
- app_wdf_data [ 127 : 120 ] <= read_flash_data3 ;
- end else begin
- app_wdf_data [ 127 : 120 ] <= 8'b0 ;
- end
- end
- if ( (l2h_flag_read_byte == 0 ) && ( cnt_rd_flash_data == 3'd4 )) begin
- top_state <= 4'd3 ;
- flash_state <= 4'd2 ;
- once_data_flag <= 1 ;
- end
- end
- 4'd3: begin // read 4bytes Flash data end --> DDR3 trans_end
- if ( init_calib_complete ) begin //DD3 loading finished
- if( app_rdy & app_wdf_rdy ) begin//等待这两个信号拉高就使命令有效
- if ( once_data_flag ) begin
- once_data_flag <= 0 ;
- app_cmd <= 3'd0 ; // write commend
- app_en <= 1'b1 ;
- write_addr <= write_addr + 28'd8;
- end else begin
- top_state <= 4'd1 ;
- app_en <= 1'b0 ;
- end
- end
- end
- end
- 4'd4: begin // DDR3 --> 输出数据
- end
- default : ;
- endcase
- end
- end
参考文献:
1、ug586_7Series_MIS.pdf
2、MT41J128M16JT-125K.pdf
3、ug470_7Series_Config.pdf
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。