首页 > 其他分享 >从SDRAM到DDR SDRAM

从SDRAM到DDR SDRAM

时间:2024-03-05 22:36:35浏览次数:20  
标签:SDRAM wire DDR FIFO WR output reg

内容: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
endmodule
View 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
endmodule
View 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
    end
View 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
    end
View 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
  /*------------------------------------------------------------------------*/
);
endmodule
View 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
end
View 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
    end
View 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-----------------------------*/
endmodule
View Code

DDR

基本知识:

这里不是我写的,我写的在最上面;

【DDR3】快速扫盲 - 知乎 (zhihu.com)

速度:

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.pdf
View Code

频率细节:

但是这里要特别注意!Zynq的HP口可以跑到150MHZ甚至200MHZ!!!

我实际使用200MHZ也能跑!但是会报五万多个ERROR,但是数据是正常的!!!

但是150MHZ就不报错了!!!

 

标签:SDRAM,wire,DDR,FIFO,WR,output,reg
From: https://www.cnblogs.com/VerweileDoch/p/18048123

相关文章

  • Five Key Changes Coming With DDR5 DIMMs
    https://semiengineering.com/five-key-changes-coming-with-ddr5-dimms/OnJuly14thoflastyear,JEDECannouncedthepublicationoftheDDR5SDRAMstandard.ThissignaledthenearingindustrytransitiontoDDR5serverdual-inlinememorymodules(DIMM).DDR......
  • Vivado DDR4, BRAM与定点数加法模块交互调试
    VivadoDDR4,BRAM与定点数加法模块交互调试一、实验目的在上一实验《VivadoDDR4和BRAM交互调试经验分享-George2024-博客园(cnblogs.com)》的基础上,加入定点数加法这一功能模块,搭建一个最小的系统,实现DDR4,BRAM和功能模块的交互。相关代码已经发布在《GeorgeLin200100/F......
  • DDR不同代技术更新
    DDR(DoubleDataRateSynchronousDynamicRandomAccessMemory),意为双倍速率同步动态随机存储器,是在SDRAM基础上发展而来的存储器。DDR分为DDR1、DDR2、DDR3、DDR4、DDR5。代数年份速率(MT/s)容量预取位数电压(V)DDR12000200~40064Mb~1Gb2n......
  • LPDDR与DDR区别
    在介绍LPDDR与DDR的区别前,首先叙述二者的发展历史。计算机的存储器分为两种:RAM和ROM。而RAM也分为两种:SRAM和DRAM。随着对CPU主频提高和RAM容量增大的需求,DRAM不断发展,从SDRAM到DDR。DDR一直更新换代,电压更低、速率翻倍、容量翻倍,最新已到DDR5。DDR适用于高性能计算设备等领域,......
  • 【记录】 unity插件 Addressables
    介绍Addressables是Unity官方推出的用于资源热更的系统,可在PackageManager里面下载。安装可在PackageManager里面下载、安装即可使用配置Addressables配置使用基础Addressables使用远程分发Addressables远程分发......
  • 【漏洞复现】用友NC-Cloud PMCloudDriveProjectStateServlet接口存在JNDI注入漏洞
    阅读须知花果山的技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。本......
  • ADI CCES ADSPI2156X UART DMA模式中,获取当前存到第几个数CurrXCount, 重新从头开始接
    关键的一些寄存器关键的寄存器pUARTDstDMARegstypedefstruct{uint32_tnTmrDevNum;/*TimerassosiatedtotheselectedUARTforAutobaud*/ADI_UART_TypeDef*constpUARTRegs;/*Pointertobaseadd......
  • 谷歌新版本跨域错误深度剖析与解决:request client is not a secure context and the
    原文地址:https://blog.csdn.net/Flywithdawn/article/details/128253604 快速解决: ======================================================最近在测试http服务时,谷歌浏览器报了以下错误“Therequestclientisnotasecurecontextandtheresourceisinmore-privat......
  • ds和[address]问题
    我在学习过程中dosbox运行效果与期望效果有出入;DS和[address]实际代码如下assumecs:codecodesegmentmovbx,0ffffhmovds,bxmoval,[0]movax,4c00hint21hcodeendsend寄存器AX并没有变为FFEA而是变为了FF00很明显这就是直接将0给到了AL[0]并没有作为偏移使用......
  • K8S 集群 apiserver-advertise-address实例节点IP切换VIP
    1.备份当前k8s集群配置文件(3个master都备份) cp-r/etc/kubernetes/etc/kubernetes.bak2.删除当前k8s集群的apiserver的cert和keyrm-rf/etc/kubernetes/pki/apiserver.*3.生成新的apiserver的cert和key,cd到pki目录下cd/etc/kubernetes/pki/---apiserver-advertise-......