sdram控制2

芯片手册要求sdram需要在64ms内刷新8K次,否则里面的数据会丢失,因此在64ms分成8192次,每次刷新充一次电,然后给两次自动刷新命令即可。

/*-----------------------------------------------------------------------

Date                :        2017-08-29
Description            :        Design for auto refresh.

-----------------------------------------------------------------------*/

module sdram_afreh
(
    //global clock
    input                    clk,            //system clock
    input                    rst_n,             //sync reset
    
    //init        interface
    input                    flag_init_end,
    
    //auto_freh interface
    input                    ref_en,
    output    reg                ref_req,
    output    reg                flag_ref_end,
    
    //sdram        interface
    output    reg        [3:0]    aref_cmd,
    output    reg        [12:0]    aref_addr
//    output            [1:0]    aref_bank
    
); 

//--------------------------------
//Funtion : 
    parameter        CMD_END        =    4'd10,
                    DELAY_7US    =    9'd350,
                    NOP            =    4'b0111,
                    PRECHARGE    =    4'b0010,
                    AREF        =    4'b0001;
    
    reg            [8:0]        cnt_7us;
    reg                        flag_ref;        //处于自刷新阶段标志
    reg                        flag_start;        //自刷新启动标志
    reg            [3:0]        cnt_cmd;



//--------------------------------
//Funtion :     flag_start              

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        flag_start <= 1'd0;
    else if(flag_init_end)
        flag_start <= 1'd1;
end

//--------------------------------
//Funtion :     7us

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        cnt_7us <= 1'd0;
    else if(cnt_7us == DELAY_7US)
        cnt_7us <= 1'd0;
    else if(flag_start)
        cnt_7us <= cnt_7us + 1'b1;
end

//--------------------------------
//Funtion : flag_ref

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        flag_ref <= 1'd0;
    else if(cnt_cmd == CMD_END)
        flag_ref <= 1'd0;
    else if(ref_en)
        flag_ref <= 1'd1;
end

//--------------------------------
//Funtion : cnt_cmd

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        cnt_cmd <= 1'd0;
    else if(flag_ref)
        cnt_cmd <= cnt_cmd + 1'b1;
    else
        cnt_cmd <= 1'd0;
end

//--------------------------------
//Funtion : flag_ref_end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        flag_ref_end <= 1'd0;
    else if(cnt_cmd == CMD_END)
        flag_ref_end <= 1'd1;
    else
        flag_ref_end <= 1'd0;
end


//--------------------------------
//Funtion : cmd_reg

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        aref_cmd <= NOP;
    else case(cnt_cmd)
        3'd0 :
        begin
            if(flag_ref)
                aref_cmd <= PRECHARGE;
            else
                aref_cmd <= NOP;
        end
        
        3'd1 :
        begin
            aref_cmd <= AREF;
        end
        
        3'd5 :
        begin
            aref_cmd <= AREF;
        end
        
        
        
        default : 
            aref_cmd <= NOP;
    
    endcase
end

//--------------------------------
//Funtion : sdram_addr

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        aref_addr <= 1'd0;
    else case(cnt_cmd)
        
        4'd0 :
        begin
            if(flag_ref)
                aref_addr <= 13'b0_0100_0000_0000;
            else
                aref_addr <= 1'd0;
        end
        
        default : aref_addr <= 1'd0;
    endcase
end

//--------------------------------
//Funtion : ref_req

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)    
        ref_req <= 1'b0;
    else if(ref_en)
        ref_req <= 1'd0;
    else if(cnt_7us == DELAY_7US)
        ref_req <= 1'b1;
end


//--------------------------------
//Funtion : bank

//assign        aref_bank    =    2'd0;




endmodule
    

最重要的时仲裁模块,它负责各个模块之间的协调,模块之间控制有三个信号,分别是请求信号requst ,使能信号en ,还有结束标志信号flag_end

flag_end   : 结束信号,负责一个状态的结束,比如写模块结束后,该信号就会拉高,时间很短暂,由计数器控制,自己会归0,当结束信号置1时,仲裁模块

里面的状态机就会跳转到仲裁模块,然后跳到下一个模块。

request     :请求模块,当该模块里面的数据已经准备好,并且现在的状态机在执行别的状态时,该模块就可以向状态机发送请求,不过当多个模块向状态机发送

请求时这时候就需要一个优先级的概念,在该程序中设定的优先级 刷新  》  写模块  》 读模块

en             :使能模块 , 当请求模块发挥作用时,仲裁模块把使能寄存器拉高,代表已经工作在该状态,同时把请求模块置0

 

地址和命令寄存器在三个模块是通用的,所以就要i用case语句进行选择,考虑时序逻辑有延时,所以用的组合逻辑

 

sdram_dq是双向端口:当不对该端口赋值的时候需要将该端口变成高阻态

 

代码

/*-----------------------------------------------------------------------

Date                :        2017-08-29
Description            :        Design for sdram_manage .

-----------------------------------------------------------------------*/

module sdram_manage
(
    //global clock
    input                    clk,            //system clock
    input                    rst_n,             //sync reset
    
    //sdram interface
    output                    sdram_clk,
    output                    sdram_cke,
    output                    sdram_cas_n,
    output                    sdram_cs_n,
    output            [1:0]    sdram_dqm,
    output            [1:0]    sdram_bank,
    output                    sdram_ras_n,
    output                    sdram_we_n,
    output    reg        [12:0]    sdram_addr,
    inout            [15:0]    sdram_dq,

    //afresh interface
    input                    ref_req,
    output    reg                ref_en ,
    input                    flag_ref_end,
    input            [3:0]    aref_cmd,
    input            [12:0]    aref_addr,
//    input            [1:0]    aref_bank,
    
    //init    interface    
    input            [3:0]    init_cmd,
    input            [12:0]    init_addr,
//    input            [1:0]    init_bank,
    input                    flag_init_end,
    
    //write    interface
    output    reg                wr_en,
    input                    wr_req,
    input                    flag_wr_end,
    input            [3:0]    wr_cmd,
    input            [12:0]    wr_addr,
//    input            [1:0]    wr_bank,
    input            [15:0]    wr_dq,
    output    reg                wr_wrig,
    
    //read    interface
    output    reg                rd_en,
    input                    rd_req,
    input                    flag_rd_end,
    input            [3:0]    rd_cmd,
    input            [12:0]    rd_addr,
//    input            [1:0]    rd_bank,
    output    reg                rd_wrig,
    output    reg        [4:0]    state
    
    
); 


//--------------------------------
//Funtion :   参数定义
localparam      IDLE            =       5'b0_0001;
localparam      ARBIT           =       5'b0_0010;
localparam      AREF            =       5'b0_0100;
localparam      WRITE           =       5'b0_1000;
localparam      READ            =       5'b1_0000;

parameter        DELAY_10US        =        10'd500;
//reg                [4:0]            state;
reg                [9:0]            cnt_10us;
reg                [3:0]            cmd_reg;

//--------------------------------
//Funtion :    读触发 和 写触发

//delay
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        cnt_10us <= 1'd0;
    else if(cnt_10us == DELAY_10US - 1'b1)
        cnt_10us <= 1'd0;
    else
        cnt_10us <= cnt_10us + 1'b1;
end

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)    
        wr_wrig <= 1'd0;
    else if(cnt_10us == DELAY_10US - 1'b1)
        wr_wrig <= ~wr_wrig;
end

always @(posedge clk)
begin
    rd_wrig <= ~wr_wrig;
end

//--------------------------------
//Funtion wr_en

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        wr_en <= 1'b0;
    else if(state == ARBIT && ref_req == 1'b0 && wr_req)
        wr_en <= 1'b1;
    else
        wr_en <= 1'b0;
end


//--------------------------------
//Funtion ref_en

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        ref_en <= 1'b0;
    else if(state == ARBIT && ref_req)
        ref_en <= 1'b1;
    else
        ref_en <= 1'b0;
end

//--------------------------------
//Funtion rd_en        优先级 刷新 > 写请求 > 读请求

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        rd_en <= 1'b0;
    else if(state == ARBIT && ref_req == 1'b0 && wr_req == 1'b0 && rd_req == 1'b1)
        rd_en <= 1'b1;
    else
        rd_en <= 1'b0;
end



//--------------------------------
//Funtion :    仲裁状态机

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        state <= IDLE;
    else
        case(state)
            
            IDLE :
            begin
                if(flag_init_end)
                    state <= ARBIT;
                else
                    state <= IDLE;
            end
            //仲裁
            ARBIT :
            begin
                if(ref_en)
                    state <= AREF;
                else if(wr_en)
                    state <= WRITE;
                else if(rd_en)
                    state <= READ;
                else
                    state <= ARBIT;
            end
            //刷新
            AREF :
            begin
                if(flag_ref_end)
                    state <= ARBIT;
                else
                    state <= AREF;
            end
            //write
            WRITE :
            begin
                if(flag_wr_end)
                    state <= ARBIT;
                else
                    state <= WRITE;
            end
            //read
            READ :
            begin
                if(flag_rd_end)
                    state <= ARBIT;
                else
                    state <= READ;
            end
            
            default :
                state <= IDLE;
        endcase
end


//--------------------------------
//Funtion :    cmd addr 组合逻辑不会有延时

always @(*)
begin
    case(state)
        IDLE :
        begin
            cmd_reg    = init_cmd;
            sdram_addr = init_addr;
        end
        
        AREF :
        begin
            cmd_reg    = aref_cmd;
            sdram_addr = aref_addr;
        end
        
        WRITE :
        begin
            cmd_reg       = wr_cmd;
            sdram_addr = wr_addr;
        end
        
        READ  :
        begin
            cmd_reg    = rd_cmd;
            sdram_addr = rd_addr;
        end
        
        default :
        begin
            cmd_reg    = 4'b0111;
            sdram_addr = 1'd0;
        end
        
    endcase
end




//--------------------------------
//Funtion :    others


assign                    sdram_clk =~ clk;
assign                    sdram_cke = 1'b1;
assign                    sdram_dqm = 2'd0;
assign                    {sdram_cs_n , sdram_ras_n , sdram_cas_n , sdram_we_n} = cmd_reg;            
assign                    sdram_dq   = (state == WRITE) ? wr_dq : {16{1'bz}};
assign                    sdram_bank = 2'd0;     



endmodule
    

 

最后把sigtab的图片贴上来

 

在写数据写的是1000 - 4000 然后把它读出来

 

posted @ 2017-08-31 21:07  peng_blog  阅读(322)  评论(0编辑  收藏  举报