内容:SDRAM的操作和代码;DDR3的一些介绍(DDR3代码在其他地方)
之前的笔记:
存储器~Zynq book第九章_zynq存储数据-CSDN博客
SDRAM学习与实现串口传图_如何传输给sdram-CSDN博客
Zynq上的存储器接口与差分时钟与DDR3_zynq ddr3-CSDN博客
DDR3笔记 频率配置_ddr3在z系列芯片的设置-CSDN博客
XIlinx提供的DDR3 IP与 UG586_ug586官方文档-CSDN博客
FDMA 3.1 米联客的Axi-DDR3控制器及其配套的Dbuf_米联科fdma-CSDN博客
DDR3 MIG的仿真加速_modelsim仿真可以用bram代替ddr吗-CSDN博客
FPGA 借由DDR3 SDRAM视频传输可能的问题-CSDN博客
SDRAM:
参数列表:
//COMMAND = {CS_N,RAS_N,CAS_N,WE_N}; parameter COMMAND_MRS = 4'b0000 ; parameter COMMAND_ARF = 4'b0001 ; parameter COMMAND_PRE = 4'b0010 ; parameter COMMAND_ACT = 4'b0011 ; parameter COMMAND_WRITE = 4'b0100 ; parameter COMMAND_READ = 4'b0101 ; parameter COMMAND_interrupt = 4'b0110 ; parameter COMMAND_NOP = 4'b0111 ; //time_wait parameter TIME_WAIT_ABOVE_100US = 10000 ;//wait_time > 100us set:200us Power up wait time parameter TIME_PRE_CHARGE = 2 ;//tRP > 18ns set:40ns; Precharge cost time parameter TIME_Auto_refresh = 5 ;//tRFC=TRRC > 60ns set:100ns ARF cost time parameter TIME_MRS_done_wait = 2 ;//During 2CLK following this command, the SDRAM cannot accept any other commands. //ACT parameter TIME_RCD = 3;//tRCD > 20ns act RAS to CAS delay //MRS_OPCODE parameter INIT_OPMODE_Brust_Mode = 1'b0 ;//A9 parameter INIT_OPMODE_STANDRD = 2'b00 ;//A8 A7 parameter INIT_CAS_Latency = 3 ;//A6 A5 A4 ;CAS Latency ( 2 & 3 ) parameter INIT_Burst_type = 1'b0 ;//A3 0:Sequential 1:Interleave parameter INIT_Burst_length = 4 ;//A2 A1 A0 ;Burst Length ( 1, 2, 4, 8 & full page ) parameter INIT_OPMODE_Brust_Length = (INIT_Burst_length == 1)?(3'b000): (INIT_Burst_length == 2)?(3'b001): (INIT_Burst_length == 4)?(3'b010): (INIT_Burst_length == 8)?(3'b011):(3'b111);//( 1, 2, 4, 8 & full page ) parameter INIT_OPMODE_CL = (INIT_CAS_Latency == 2)?(3'b010):(3'b011);//A6 A5 A4 ; //auto refresh parameter ARF_PERIOD = 750;// ARF_period = Row_nums/64ms 64ms = 64_000us = 64_000_000ns = 3_200_000 cycles (1 ARF/782 cycles)View Code
初始化:
描述:
根据需求对Brust长度,类型;列选通时间等参数进行配置;
module SDRAM_INIT( input wire Sys_clk , input wire Rst_n , output reg [ 3:0] COMMAND_INIT ,//COMMAND = {CS_N,RAS_N,CAS_N,WE_N} output reg [11:0] INIT_A_ADDR , output reg [ 1:0] INIT_BANK_ADDR, output reg INIT_DONE ); `include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h" localparam TIME_TO_PRE = TIME_WAIT_ABOVE_100US; localparam TIME_TO_ARF = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE; localparam TIME_TO_ARF_2 = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE + TIME_Auto_refresh; localparam TIME_TO_MRS = TIME_WAIT_ABOVE_100US + TIME_PRE_CHARGE + TIME_Auto_refresh + TIME_Auto_refresh; localparam INIT_END = TIME_TO_MRS + TIME_MRS_done_wait ; reg [13:0] INIT_CNT ; reg INIT_DONE_NOW; always@(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin INIT_DONE <= 'd0; end else if(INIT_CNT == INIT_END) begin INIT_DONE <= 'd1; end else begin INIT_DONE <= 'd0; end end always@(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin INIT_DONE_NOW <= 1'b0; end else if(INIT_CNT == INIT_END) begin INIT_DONE_NOW <= 1'b1; end else begin INIT_DONE_NOW <= INIT_DONE_NOW; end end always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin INIT_CNT <= 'd0; end else if(INIT_DONE_NOW == 1'b0) begin if(INIT_CNT == INIT_END) begin INIT_CNT <= 'd0; end else begin INIT_CNT <= INIT_CNT + 1'b1; end end else begin INIT_CNT <= 'd0; end end always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin COMMAND_INIT <= COMMAND_NOP; INIT_A_ADDR <= 12'd0 ; INIT_BANK_ADDR <= 2'b00 ; end else begin case (INIT_CNT) TIME_TO_PRE: begin COMMAND_INIT <= COMMAND_PRE; INIT_A_ADDR[10] <= 1'b1; end TIME_TO_ARF: begin COMMAND_INIT <= COMMAND_ARF; end TIME_TO_ARF_2: begin COMMAND_INIT <= COMMAND_ARF; end TIME_TO_MRS: begin COMMAND_INIT <= COMMAND_MRS; INIT_A_ADDR <= { 2'b00 ,//A11 A10 INIT_OPMODE_Brust_Mode ,//A9 INIT_OPMODE_STANDRD ,//A8 A7 INIT_OPMODE_CL ,//A6 A5 A4 ;CAS Latency ( 2 & 3 ) INIT_Burst_type ,//A3 0:Sequential 1:Interleave INIT_OPMODE_Brust_Length //A2 A1 A0 ;Burst Length ( 1, 2, 4, 8 & full page ) }; end default:begin COMMAND_INIT <= COMMAND_NOP; INIT_A_ADDR <= 12'd0 ; INIT_BANK_ADDR <= 2'b00 ; end endcase end end endmoduleView Code
刷新:
描述:
1.刷新的目的是为了保障其中存储数据的电容不掉电;
2.每64ms,SDRAM都需要对他的每一行进行一次刷新,所以每64ms进行2^(行地址数目)次刷新;
3.每次刷新需要等待当前读写的brust结束,然后发送刷新指令等待刷新的完成;
刷新步骤:
1.仲裁模块收到刷新请求,当前的读写步骤结束,进行刷新状态;
2.发送刷新指令;
3.等待刷新需求周期的结束,仲裁回到空闲状态;
刷新模块:在满足周期需求以后发送刷新请求,仲裁模块通过仲裁并且通过刷新请求中止读写模块的操作,进入刷新状态,等待刷新完成以后发送完成信号;
刷新模块代码:
module SDRAM_ARF #( )( input wire Sys_clk, input wire Rst_n , //SDRAM input wire INIT_DONE , output reg [3:0] COMMAND_REF , output reg [11:0] ARF_A_ADDR , output reg [ 1:0] ARF_BANK_ADDR , output reg REF_DONE , output reg ARF_req , input wire ARF_access ); `include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h" localparam TIME_ARF_BEGIN = 1'b1 ; // localparam TIME_PRE_to_ARF = 1'b1 + TIME_PRE_CHARGE; // localparam TIME_ARF_to_done = 1'b1 + TIME_PRE_CHARGE + TIME_Auto_refresh; localparam TIME_ARF_to_done = 'd9; reg [9:0] ARF_CNT ; reg [3:0] COMMAND_CNT; //ARF_CNT always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin ARF_req <= 'd0; end else if(ARF_access == 1'b1) begin ARF_req <= 1'b0; end else if(ARF_CNT == ARF_PERIOD) begin ARF_req <= 1'b1; end end always@(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin ARF_CNT <= 'd0; end else if(INIT_DONE == 1'b1) begin ARF_CNT <= 'd1; end else if(ARF_CNT == ARF_PERIOD) begin ARF_CNT <= 'd1; end else if(ARF_CNT > 'd0) begin ARF_CNT <= ARF_CNT + 1'd1; end else begin ARF_CNT <= ARF_CNT; end end always@(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin REF_DONE <= 1'b0; end else if(COMMAND_CNT == TIME_ARF_to_done) begin REF_DONE <= 1'b1; end else begin REF_DONE <= 1'b0; end end //COMMAND_CNT always@(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin COMMAND_CNT <= 'd0; end else if(ARF_access == 1'b1) begin COMMAND_CNT <= 'd1; end else if(COMMAND_CNT == TIME_ARF_to_done) begin COMMAND_CNT <= 'd0; end else if(COMMAND_CNT > 'd0) begin COMMAND_CNT <= COMMAND_CNT + 1'b1; end else begin COMMAND_CNT <= COMMAND_CNT; end end //COMMAND always@(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin COMMAND_REF <= COMMAND_NOP; ARF_A_ADDR <= 12'd0 ; ARF_BANK_ADDR <= 2'b00 ; end else if(COMMAND_CNT == TIME_ARF_BEGIN) begin COMMAND_REF <= COMMAND_ARF; end else begin COMMAND_REF <= COMMAND_NOP; ARF_A_ADDR <= 12'd0 ; ARF_BANK_ADDR <= 2'b00 ; end end //COMMAND other SDRAM // always@(posedge Sys_clk or negedge Rst_n) begin // if(Rst_n == 'd0) begin // COMMAND_REF <= COMMAND_NOP; // ARF_A_ADDR <= 12'd0 ; // ARF_BANK_ADDR <= 2'b00 ; // end else begin // case (COMMAND_CNT) // TIME_ARF_BEGIN: begin // COMMAND_REF <= COMMAND_PRE; // ARF_A_ADDR[10] <= 1'b1 ; // end // TIME_PRE_to_ARF: begin // COMMAND_REF <= COMMAND_ARF; // end // default: begin // COMMAND_REF <= COMMAND_NOP; // ARF_A_ADDR <= 12'd0 ; // ARF_BANK_ADDR <= 2'b00 ; // end // endcase // end // end endmoduleView Code
写操作:
描述:
对指定的地址写入数据;
写操作步骤:
//COMMAND always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin COMMAND_WR <= COMMAND_NOP; WR_A_ADDR <= 12'd0 ; WR_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_WR_wait && WR_access == 1'b1) begin COMMAND_WR <= COMMAND_ACT; WR_A_ADDR <= CNT_SDRAM_ROWS;//row_addr WR_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_WR_NOW && CNT_Brust == 'd0) begin COMMAND_WR <= COMMAND_WRITE; WR_A_ADDR <= CNT_SDRAM_COLS<<2'd2; WR_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_Precharge && CNT_Precharge == 'd0) begin COMMAND_WR <= COMMAND_PRE; WR_A_ADDR[10]<= 1'b1 ; WR_BANK_ADDR <= 2'b00 ; end else begin COMMAND_WR <= COMMAND_NOP; WR_A_ADDR <= 12'd0 ; WR_BANK_ADDR <= 2'b00 ; end endView Code
1.等待写数据FIFO的数值达到Brust需求,得到写请求;
2.向仲裁模块发送请求,得到仲裁进入写状态;
3.发送激活命令,同时地址线发送需要激活的行地址,等待激活时间;
4.发送写命令,同时地址线发送需要写的列地址,此时需要调整数据对齐,在发送命令和地址后,从写数据FIFO中读出数据给数据线;
5.等待约定好的数据长度传输完成,发送预充电关闭列,结束。仲裁回到空闲状态;
细节:
1.激活列,完成数据操作(从FIFO中读出数据向SDRAM中发送);(SDRAM不需要等待写选通时间,但是DDR3中需要)
2.如果只发送单幅图像,最后一列数据被刷新打断,需要特殊处理;
3.下列代码是处理上述情况的解决方法,就是通知“这里被刷新打断过”;
//CNT_SDRAM_ROWS always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin CNT_SDRAM_ROWS <= 'd0; end else if(STATE == STATE_WR_NOW) begin if (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -1'b1)) begin CNT_SDRAM_ROWS <= 'd0; end else if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -1'b1)) begin CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS + 1'b1; end else begin CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS; end end else begin CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS; end endView Code
写代码:
//SDRAM SIZE = 8192X512X16 //8192ROWS 512COLS 16BITS module SDRAM_WR #( parameter SDRAM_COLS_MAX = 128, parameter IMAGE_NEED_ROW = 300, //300 = 640*480*8/16*512 parameter TIME_PRE_CHARGE_long = 8 )( input wire Sys_clk, input wire Rst_n , //FIFO input wire FIFO_WR_EN ,//8bits input wire [ 7:0] FIFO_WR_data , //SDRAM input wire INIT_DONE , output reg [ 3:0] COMMAND_WR , output reg [11:0] WR_A_ADDR , output reg [ 1:0] WR_BANK_ADDR , output wire WR_data_done , output reg WR_req , input wire ARF_req , output reg Break_WR_to_ARF, input wire WR_access , output wire [15:0] WRITE_SDRAM_DQ ); `include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h" localparam STATE_IDLE = 5'b0_0001; localparam STATE_WR_wait = 5'b0_0010; localparam STATE_ACT = 5'b0_0100; localparam STATE_WR_NOW = 5'b0_1000; localparam STATE_Precharge = 5'b1_0000; reg [ 4:0] STATE ; reg [ 1:0] CNT_ACT ; reg [ 9:0] CNT_SDRAM_COLS; reg [12:0] CNT_SDRAM_ROWS; wire ROWS_END_Flag ; reg [ 1:0] CNT_Brust ; reg [ 3:0] CNT_Precharge ; reg Done_image ; //FIFO wire FIFO_FULL ; wire FIFO_EMPTY ; wire [10:0] FIFO_RD_cnt ; reg FIFO_RD_EN ; wire [15:0] FIFO_RD_DATA ; assign WRITE_SDRAM_DQ = FIFO_RD_DATA; //FIFO_RD_EN always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin FIFO_RD_EN <= 'd0; end else if(STATE == STATE_WR_NOW) begin FIFO_RD_EN <= 1'b1; end else begin FIFO_RD_EN <= 'd0; end end //WR_req always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin WR_req <= 'd0; end else if(FIFO_RD_cnt >= 512 && STATE == STATE_WR_wait) begin WR_req <= 1'b1; end else if(Break_WR_to_ARF && CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 && ((FIFO_RD_cnt >>2'd2) >= (SDRAM_COLS_MAX - CNT_SDRAM_COLS))) begin WR_req <= 1'd1; end else if(Done_image == 1'b1 || WR_access == 1'b1 || STATE != STATE_WR_wait) begin WR_req <= 'd0; end else begin WR_req <= WR_req; end end //Done_image always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin Done_image <= 'd0; end else if(STATE == STATE_WR_NOW && (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 ) && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -2'd2)) begin Done_image <= 1'b1; end else if(STATE == STATE_Precharge && CNT_Precharge == TIME_PRE_CHARGE_long) begin Done_image <= 'd0; end else begin Done_image <= Done_image; end end //WR_data_done assign WR_data_done = (STATE == STATE_Precharge && CNT_Precharge == TIME_PRE_CHARGE_long && Done_image == 1'b1); //Break_WR_to_ARF always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin Break_WR_to_ARF <= 'd0; end else if(STATE == STATE_Precharge && CNT_Precharge == TIME_PRE_CHARGE_long && Done_image == 1'b0) begin Break_WR_to_ARF <= 'd1; end else if(WR_req == 1'b1)begin Break_WR_to_ARF <= 'd0; end else begin Break_WR_to_ARF <= Break_WR_to_ARF; end end //CNT_ACT always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin CNT_ACT <= 'd0; end else if(STATE == STATE_ACT) begin if(CNT_ACT == TIME_RCD) begin CNT_ACT <= 'd0; end else begin CNT_ACT <= CNT_ACT + 1'b1; end end else begin CNT_ACT <= 'd0; end end //CNT_Brust always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin CNT_Brust <= 'd0; end else if(STATE == STATE_WR_NOW) begin if(CNT_Brust == INIT_Burst_length -1'b1) begin CNT_Brust <= 'd0; end else begin CNT_Brust <= CNT_Brust + 1'b1; end end else begin CNT_Brust <= 'd0; end end //CNT_SDRAM_ROWS always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin CNT_SDRAM_ROWS <= 'd0; end else if(STATE == STATE_WR_NOW) begin if (CNT_SDRAM_ROWS == IMAGE_NEED_ROW - 1'b1 && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -1'b1)) begin CNT_SDRAM_ROWS <= 'd0; end else if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -1'b1)) begin CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS + 1'b1; end else begin CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS; end end else begin CNT_SDRAM_ROWS <= CNT_SDRAM_ROWS; end end //CNT_SDRAM_COLS always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin CNT_SDRAM_COLS <= 'd0; end else if(STATE == STATE_WR_NOW) begin if((CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -1'b1)) begin CNT_SDRAM_COLS <= 'd0; end else if(CNT_Brust == INIT_Burst_length -1'b1) begin CNT_SDRAM_COLS <= CNT_SDRAM_COLS + 1'b1; end else begin CNT_SDRAM_COLS <= CNT_SDRAM_COLS; end end else begin CNT_SDRAM_COLS <= CNT_SDRAM_COLS; end end assign ROWS_END_Flag = (STATE == STATE_WR_NOW) && (CNT_SDRAM_COLS == SDRAM_COLS_MAX - 1'b1) && (CNT_Brust == INIT_Burst_length -1'b1); //CNT_Precharge always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin CNT_Precharge <= 'd0; end else if(STATE == STATE_Precharge && CNT_Precharge == TIME_PRE_CHARGE_long) begin CNT_Precharge <= 'd0; end else if(STATE == STATE_Precharge) begin CNT_Precharge <= CNT_Precharge + 1'b1; end else begin CNT_Precharge <= CNT_Precharge; end end //COMMAND always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin COMMAND_WR <= COMMAND_NOP; WR_A_ADDR <= 12'd0 ; WR_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_WR_wait && WR_access == 1'b1) begin COMMAND_WR <= COMMAND_ACT; WR_A_ADDR <= CNT_SDRAM_ROWS;//row_addr WR_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_WR_NOW && CNT_Brust == 'd0) begin COMMAND_WR <= COMMAND_WRITE; WR_A_ADDR <= CNT_SDRAM_COLS<<2'd2; WR_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_Precharge && CNT_Precharge == 'd0) begin COMMAND_WR <= COMMAND_PRE; WR_A_ADDR[10]<= 1'b1 ; WR_BANK_ADDR <= 2'b00 ; end else begin COMMAND_WR <= COMMAND_NOP; WR_A_ADDR <= 12'd0 ; WR_BANK_ADDR <= 2'b00 ; end end //STATE always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin STATE <= STATE_IDLE; end else begin case (STATE) STATE_IDLE: begin if(INIT_DONE == 1'b1) begin STATE <= STATE_WR_wait; end else begin STATE <= STATE_IDLE; end end STATE_WR_wait: begin if(WR_access == 1'b1) begin STATE <= STATE_ACT; end else begin STATE <= STATE_WR_wait; end end STATE_ACT: begin if(ARF_req == 1'b1 && CNT_ACT == TIME_RCD) begin STATE <= STATE_Precharge; end else if(CNT_ACT == TIME_RCD) begin STATE <= STATE_WR_NOW; end else begin STATE <= STATE_ACT; end end STATE_WR_NOW:begin if(ARF_req == 1'b1 && CNT_Brust == INIT_Burst_length - 1'b1) begin STATE <= STATE_Precharge; end else if(ROWS_END_Flag == 1'b1) begin STATE <= STATE_Precharge; end else if(Done_image == 1'b1) begin STATE <= STATE_Precharge; end else begin STATE <= STATE_WR_NOW; end end STATE_Precharge: begin if(CNT_Precharge == TIME_PRE_CHARGE_long) begin STATE <= STATE_WR_wait; end else begin STATE <= STATE_Precharge; end end default: begin STATE <= STATE_IDLE; end endcase end end /*------------------------------------------------------------------------*/ AS_FIFO_w2048x8_r1024x16 INST0_AS_FIFO_w2048x8_r1024x16 ( .wr_clk ( Sys_clk ), // input wr_clk .rd_clk ( Sys_clk ), // input rd_clk .din ( FIFO_WR_data ), // input [7 : 0] din .wr_en ( FIFO_WR_EN ), // input wr_en .rd_en ( FIFO_RD_EN ), // input rd_en .dout ( FIFO_RD_DATA ), // output [15 : 0] dout .full ( FIFO_FULL ), // output full .empty ( FIFO_EMPTY ), // output empty .rd_data_count( FIFO_RD_cnt ) // output [9 : 0] rd_data_count /*------------------------------------------------------------------------*/ ); endmoduleView Code
读操作:
描述:
从指定地址读出连续的数据;
读操作步骤:
1.等待读数据FIFO的数值降低到一定程度,得到读请求;
2.向仲裁模块发送请求,得到仲裁进入读状态;
3.发送激活命令,同时地址线发送需要激活的行地址,等待激活时间;
4.发送读命令和地址,联系配置的列选通时间,等待并把到来数据存入FIFO;
//FIFO_WR_EN INIT_CAS_Latency = 3 always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin FIFO_WR_EN <= 'd0; end else if(STATE == STATE_RD_NOW) begin FIFO_WR_EN <= 1'b1; end else begin FIFO_WR_EN <= 'd0; end end always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin FIFO_WR_delay <= 'd0; end else begin FIFO_WR_delay <= {FIFO_WR_delay[2:0],FIFO_WR_EN}; end endView Code
AS_FIFO_w2048x16_r4096x8 Inst_AS_FIFO_w2048x16_r4096x8 ( .wr_clk ( Sys_clk ), // input wr_clk .rd_clk ( VGA_CLOCK ), // input rd_clk .din ( FIFO_WR_data ), // input [15 : 0] din .wr_en ( FIFO_WR_delay[3]), // input wr_en .rd_en ( VGA_FIFO_RD_EN ), // input rd_en .dout ( VGA_FIFO_RD_DATA), // output [7 : 0] dout .full ( FIFO_FULL ), // output full .empty ( FIFO_EMPTY ), // output empty .rd_data_count( FIFO_RD_cnt ), // output [11 : 0] rd_data_count .wr_data_count( FIFO_WR_cnt ) // output [10 : 0] wr_data_count );View Code
5.待读得指定长度,仲裁并回到空闲状态。
//COMMAND always @(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin COMMAND_RD <= COMMAND_NOP; RD_A_ADDR <= 12'd0 ; RD_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_RD_WAIT && RD_access == 1'b1) begin COMMAND_RD <= COMMAND_ACT; RD_A_ADDR <= CNT_SDRAM_ROWS;//row_addr RD_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_RD_NOW && CNT_Brust == 'd0 && ROWS_END_Flag == 'd0) begin COMMAND_RD <= COMMAND_READ; RD_A_ADDR <= CNT_SDRAM_COLS<<2'd2; RD_BANK_ADDR <= 2'b00 ; end else if(STATE == STATE_Precharge && CNT_Precharge == 'd2) begin COMMAND_RD <= COMMAND_PRE; RD_A_ADDR[10]<= 1'b1 ; RD_BANK_ADDR <= 2'b00 ; end else begin COMMAND_RD <= COMMAND_NOP; RD_A_ADDR <= 12'd0 ; RD_BANK_ADDR <= 2'b00 ; end endView Code
仲裁模块:
module SDRAM_CTRL_TOP #( parameter SDRAM_DATA_WIDTH = 16, parameter SDRAM_BANK_WIDTH = 2 , parameter SDRAM_ADDR_WIDTH = 12 )( input wire Sys_clk, input wire Rst_n , //PLL input wire VGA_CLOCK ,//25MHZ = 800X525X60 //SDRAM //COMMAND output wire SDRAM_CS_N , output wire SDRAM_RAS_N , output wire SDRAM_CAS_N , output wire SDRAM_WE_N , output wire SDRAM_CKE , output wire [1:0] SDRAM_DQM , output wire SDRAM_CLK , output reg [SDRAM_ADDR_WIDTH-1:0] SDRAM_A_ADDR , output reg [SDRAM_BANK_WIDTH-1:0] SDRAM_BANK_ADDR , //WR_FIFO input wire FIFO_WR_EN , input wire [7:0] FIFO_WR_data , //DATA inout [SDRAM_DATA_WIDTH-1:0] SDRAM_DQ , //VGA output wire [2:0] red_sign , output wire [2:0] grenn_sign , output wire [1:0] blue_sign , output wire H_Sync_sign , output wire V_Sync_sign ); `include "D:/three_verilog/SDRAM/SDRAM_init/rtl/sdram_param.h" localparam STATE_IDLE = 6'b00_0001; localparam STATE_INIT = 6'b00_0010; localparam STATE_ARB = 6'b00_0100; localparam STATE_ARF = 6'b00_1000; localparam STATE_RD = 6'b01_0000; localparam STATE_WE = 6'b10_0000; //Main reg [3:0] SDRAM_COMMAND_SEND; reg [5:0] STATE ; wire WR_avai ; wire [SDRAM_DATA_WIDTH-1:0] WR_SDRAM_DQ ; reg [SDRAM_DATA_WIDTH-1:0] READ_SDRAM_DQ ; //init wire INIT_DONE ; wire [3:0] COMMAND_INIT ; wire [SDRAM_ADDR_WIDTH-1:0] INIT_A_ADDR ; wire [SDRAM_BANK_WIDTH-1:0] INIT_BANK_ADDR ; //ARF wire ARF_access ; wire [3:0] COMMAND_REF ; wire [SDRAM_ADDR_WIDTH-1:0] ARF_A_ADDR ; wire [SDRAM_BANK_WIDTH-1:0] ARF_BANK_ADDR ; wire REF_DONE ; wire ARF_req ; //WR wire WR_req ; wire WR_access ; wire [3:0] COMMAND_RD ; wire [SDRAM_ADDR_WIDTH-1:0] RD_A_ADDR ; wire [SDRAM_BANK_WIDTH-1:0] RD_BANK_ADDR ; wire WR_data_done ; //RD wire RD_req ; wire RD_access ; wire RD_DATA_DONE ; wire [3:0] COMMAND_WR ; wire [SDRAM_ADDR_WIDTH-1:0] WR_A_ADDR ; wire [SDRAM_BANK_WIDTH-1:0] WR_BANK_ADDR ; //VGA wire VGA_START ; wire VGA_FIFO_RD_EN ; wire [7:0] VGA_FIFO_RD_DATA ; wire [9:0] H_addr ; wire [9:0] V_addr ; //break wire Break_WR_to_ARF ; wire Break_RD_other ; //DQ assign WR_avai = (STATE == STATE_WE)?1'b1:1'b0; always@(posedge Sys_clk) begin READ_SDRAM_DQ <= SDRAM_DQ; end assign SDRAM_DQ = (WR_avai == 1'b1)?WR_SDRAM_DQ :16'dz; assign SDRAM_DQM = 2'b00 ; assign SDRAM_CKE = 1'b1 ; assign SDRAM_CLK = Sys_clk; //COMMAND assign {SDRAM_CS_N, SDRAM_RAS_N, SDRAM_CAS_N, SDRAM_WE_N } = SDRAM_COMMAND_SEND; always@(*) begin if(STATE == STATE_INIT) begin SDRAM_COMMAND_SEND <= COMMAND_INIT ; SDRAM_A_ADDR <= INIT_A_ADDR ; SDRAM_BANK_ADDR <= INIT_BANK_ADDR; end else if(STATE == STATE_ARF) begin SDRAM_COMMAND_SEND <= COMMAND_REF ; SDRAM_A_ADDR <= ARF_A_ADDR ; SDRAM_BANK_ADDR <= ARF_BANK_ADDR ; end else if(STATE == STATE_WE) begin SDRAM_COMMAND_SEND <= COMMAND_WR ; SDRAM_A_ADDR <= WR_A_ADDR ; SDRAM_BANK_ADDR <= WR_BANK_ADDR ; end else if(STATE == STATE_RD) begin SDRAM_COMMAND_SEND <= COMMAND_RD ; SDRAM_A_ADDR <= RD_A_ADDR ; SDRAM_BANK_ADDR <= RD_BANK_ADDR ; end else begin SDRAM_COMMAND_SEND <= COMMAND_NOP ; SDRAM_A_ADDR <= 'd0 ; SDRAM_BANK_ADDR <= 'd0 ; end end //access assign ARF_access = (STATE == STATE_ARB) && (ARF_req == 1'b1); assign WR_access = (STATE == STATE_ARB) && (WR_req == 1'b1) && (ARF_req == 1'b0); assign RD_access = (STATE == STATE_ARB) && (RD_req == 1'b1) && (WR_req == 1'b0 ) && (ARF_req == 1'b0); //-------------------STATE MAIN-----------------------// always@(posedge Sys_clk or negedge Rst_n) begin if(Rst_n == 'd0) begin STATE <= STATE_IDLE; end else begin case (STATE) //ARG > WR > RD STATE_IDLE: begin STATE <= STATE_INIT; end STATE_INIT: begin if(INIT_DONE == 'd1) begin STATE <= STATE_ARB; end else begin STATE <= STATE_INIT; end end STATE_ARB: begin if(ARF_req == 1'b1) begin STATE <= STATE_ARF; end else if(WR_req == 1'b1 && ARF_req == 1'b0) begin STATE <= STATE_WE; end else if(RD_req == 1'b1 && WR_req == 1'b0 && ARF_req == 1'b0) begin STATE <= STATE_RD; end else begin STATE <= STATE_ARB; end end STATE_ARF: begin if(REF_DONE == 1'b1) begin STATE <= STATE_ARB; end else begin STATE <= STATE_ARF; end end STATE_WE: begin if(Break_WR_to_ARF == 1'b1) begin STATE <= STATE_ARB; end else if(WR_data_done == 1'b1) begin STATE <= STATE_ARB; end else begin STATE <= STATE_WE; end end STATE_RD: begin if(RD_DATA_DONE == 1'b1) begin STATE <= STATE_ARB; end else if(Break_RD_other == 1'b1) begin STATE <= STATE_ARB; end else begin STATE <= STATE_RD; end end default: begin STATE <= STATE_IDLE; end endcase end end //-------------------STATE END------------------------// /*-------------------instance begin---------------------------*/ SDRAM_INIT INST0_SDRAM_INIT( //input .Sys_clk ( Sys_clk ), .Rst_n ( Rst_n ), //output .COMMAND_INIT ( COMMAND_INIT ), .INIT_A_ADDR ( INIT_A_ADDR ), .INIT_BANK_ADDR ( INIT_BANK_ADDR ), .INIT_DONE ( INIT_DONE ) ); SDRAM_ARF INST0_SDRAM_ARF ( .Sys_clk ( Sys_clk ), .Rst_n ( Rst_n ), .INIT_DONE ( INIT_DONE ), .ARF_access ( ARF_access ), .COMMAND_REF ( COMMAND_REF ), .ARF_A_ADDR ( ARF_A_ADDR ), .ARF_BANK_ADDR ( ARF_BANK_ADDR ), .REF_DONE ( REF_DONE ), .ARF_req ( ARF_req ) ); SDRAM_WR INST0_SDRAM_WR( .Sys_clk ( Sys_clk ), .Rst_n ( Rst_n ), .FIFO_WR_EN ( FIFO_WR_EN ), .FIFO_WR_data ( FIFO_WR_data ), .INIT_DONE ( INIT_DONE ), .ARF_req ( ARF_req ), .WR_access ( WR_access ), .COMMAND_WR ( COMMAND_WR ), .WR_A_ADDR ( WR_A_ADDR ), .WR_BANK_ADDR ( WR_BANK_ADDR ), .WR_data_done ( WR_data_done ), .WR_req ( WR_req ), .Break_WR_to_ARF ( Break_WR_to_ARF ), .WRITE_SDRAM_DQ ( WR_SDRAM_DQ ) ); SDRAM_RD INST0_SDRAM_RD( .Sys_clk ( Sys_clk ), .Rst_n ( Rst_n ), .VGA_CLOCK ( VGA_CLOCK ), .VGA_FIFO_RD_EN ( VGA_FIFO_RD_EN ), .INIT_DONE ( INIT_DONE ), .WR_req ( WR_req ), .ARF_req ( ARF_req ), .RD_access ( RD_access ), .READ_SDRAM_DQ ( READ_SDRAM_DQ ), .WR_data_done ( WR_data_done ), .VGA_START ( VGA_START ), .VGA_FIFO_RD_DATA ( VGA_FIFO_RD_DATA ), .COMMAND_RD ( COMMAND_RD ), .RD_A_ADDR ( RD_A_ADDR ), .RD_BANK_ADDR ( RD_BANK_ADDR ), .RD_DATA_DONE ( RD_DATA_DONE ), .RD_req ( RD_req ), .Break_RD_other ( Break_RD_other ) ); vga_ctrl INST0_vga_ctrl( .Sys_clk ( VGA_CLOCK ), .Rst_n ( VGA_START ), .SDRAM_FIFO_RD_DATA ( VGA_FIFO_RD_DATA ), .red_sign ( red_sign ), .grenn_sign ( grenn_sign ), .blue_sign ( blue_sign ), .H_Sync_sign ( H_Sync_sign ), .V_Sync_sign ( V_Sync_sign ), .H_addr ( H_addr ), .V_addr ( V_addr ), .SDRAM_FIFO_RD_EN ( VGA_FIFO_RD_EN ) ); /*-------------------instance end-----------------------------*/ endmoduleView Code
DDR
基本知识:
这里不是我写的,我写的在最上面;
速度:
DDR SDRAM是Double 的 SDRAM(双沿发送)
DDR2是PLL内部倍频的DDR SDRAM
DDR3是PLL内部4倍频的DDR SDRAM
所以实际上DDR3是 SDRAM的八倍读写数据。
实际频率:
K7一般是800MHZ的DDR3内部频率,而PHY是200MHZ(4:1);
A7和Zynq则是400MHZ,PHY是100MHZ,这些在DS手册(Datasheet)中可以查到,链接是这几个:
DS180:7 Series FPGAs Data Sheet: Overview https://docs.xilinx.com/v/u/en-US/ds180_7Series_Overview DS191:Artix‐7 FPGAs Data Sheet https://docs.xilinx.com/v/u/en-US/ds181_Artix_7_Data_Sheet DS182:Kintex-7 https://xilinx.eetrend.com/files-eetrend-xilinx/download/201202/2343-4401-kintex7datasheet.pdfView Code
频率细节:
但是这里要特别注意!Zynq的HP口可以跑到150MHZ甚至200MHZ!!!
我实际使用200MHZ也能跑!但是会报五万多个ERROR,但是数据是正常的!!!
但是150MHZ就不报错了!!!
标签:SDRAM,wire,DDR,FIFO,WR,output,reg From: https://www.cnblogs.com/VerweileDoch/p/18048123