zoukankan      html  css  js  c++  java
  • 简易sdram控制1

    跟着开源骚客的教程写的sdram程序,前后调了大约5天,今天晚上能实现简单的读写数据了,如果以后用到摄像头,再在这个基础上加些功能吧。

    整个程序框架就如图品所示,一共有五个模块还有初始化模块,图片上没有显示呢。

    初始化模块

    初始化模块  1上电    2 等待200us  3 给所有bank充电 4 八次自刷新 5 设置模式寄存器

    初始化模块代码

    /*-----------------------------------------------------------------------
    
    Date                :        2017-08-29
    Description            :        Design for sdram_init .
    
    -----------------------------------------------------------------------*/
    
    module sdram_init
    (
        //global clock
        input                    clk,            //system clock
        input                    rst_n,             //sync reset
        
        //sdram_init interface
        output    reg        [3:0]    init_cmd,        //sdram 命令寄存器
        output    reg        [12:0]    init_addr,        //地址线
    //    output            [1:0]    init_bank,
        //user interface
        output    reg                flag_init_end    //sdram初始化标志
        
    ); 
    
    //--------------------------------
    //Funtion :   参数定义
    parameter    NOP            =    4'b0111,
                PRECGE        =    4'b0010,
                AUTO_REF    =    4'b0001,
                MODE_SET    =    4'b0000,
                CMD_END        =    6'd35,
                DELAY_200US    =    10000;
    //200us delay
    reg                [13:0]        cnt_200us;
    wire                        flag_200us;
    
    //初始化标志
    reg                            flag_init;    
    
    //cmd指令计数
    reg                [5:0]        cnt_cmd;
    
    
    
    //--------------------------------
    //Funtion :    200us                       
    
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            cnt_200us <= 1'd0;
        else if(flag_200us == 1'b0)
            cnt_200us <= cnt_200us + 1'b1;
    end
    
    assign        flag_200us        =        (cnt_200us >= DELAY_200US - 1'b1) ? 1'b1 : 1'b0;
    
    //--------------------------------
    //Funtion :   sdram    初始化标志位是否结束
        
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            flag_init <= 1'b1;
        else if(cnt_cmd == CMD_END)        //auto refresh结束标志位
            flag_init <= 1'b0;
    end    
       
    //--------------------------------
    //Funtion :   cnt_cmd 200us延时后计数
    
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            cnt_cmd <= 1'd0;
        else if(flag_200us == 1'b1 && flag_init == 1'b1)
            cnt_cmd <= cnt_cmd + 1'b1;
    end
    
    //--------------------------------
    //Funtion :   初始化结束标志
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            flag_init_end <= 1'b0;
        else if(cnt_cmd >= CMD_END)
            flag_init_end <= 1'b1;
        else
            flag_init_end <= 1'b0;
    end
    
    
                
    //--------------------------------
    //Funtion :   cmd_reg
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            init_cmd <= NOP;
        else if(cnt_200us == DELAY_200US - 2'd3)
            init_cmd <= PRECGE;
        else if(flag_200us)
        begin
            case(cnt_cmd)
                //8 auto refresh 
                6'd0 , 6'd6 , 6'd10 , 6'd14 , 6'd18 , 6'd22 , 6'd26 , 6'd30: 
                    init_cmd <= AUTO_REF;
                //mode    set
                6'd34 :
                    init_cmd <= MODE_SET;
                    
                default :
                    init_cmd <= NOP;
                
            endcase
        end
    end            
                
    //--------------------------------
    //Funtion :   sdram_addr
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            init_addr <= 13'd0;
        else if(cnt_200us == DELAY_200US - 2'd3) //预充电
            init_addr <= 13'b0_0100_0000_0000;
        else if(cnt_cmd == 6'd34)          //模式寄存器设置
            init_addr <= 13'b0_0000_0011_0010;
        else
            init_addr <= 13'd0;
    end
    
    //--------------------------------
    //Funtion :   init_bank
    
    //assign        init_bank    =    2'd0;
    
    endmodule
        

    write 模块

    1、给一个激活命令同时选中行和列 2、然后给一个写命令 同事给定列地址,此时需要写第一个数据了 3、如果需要换行需要进行预充电指令

    write模块代码

    /*-----------------------------------------------------------------------
    
    Date                :        2017-08-29
    Description            :        Design for sdram write .
    
    -----------------------------------------------------------------------*/
    
    module sdram_write
    (
        //global clock
        input                    clk,            //system clock
        input                    rst_n,             //sync reset
        
        //sdram_write interface
        input                    wr_en,            //写使能
        output    reg                wr_req,            //写请求
        output    reg                flag_wr_end,    //写结束
        input                    wr_trig,        //写触发
    
        //sdram interface
        output    reg        [3:0]    wr_cmd,
        output    reg        [12:0]    wr_addr,
        //output            [1:0]    wr_bank,
        output    reg        [15:0]    wr_dq,
        //afresh interface
        //input                    ref_req  
        input            [4:0]    state
    ); 
    
    
    //--------------------------------
    //Funtion :    参数定义
    
    /* localparam        S_IDLE        =        5'b0_0001;
    localparam        S_REQ        =        5'b0_0010;
    localparam        S_ACT        =        5'b0_0100;
    localparam        S_WR        =        5'b0_1000;
    localparam        S_PRE        =        5'b1_0000;
    
    reg                            flag_wr;
    reg            [4:)]            state; */
    
    parameter        NOP        =        4'b0111,
                    ACT        =        4'b0011,
                    WR        =        4'b0100,
                    PRE        =        4'b0010,
                    CMD_END    =        4'd8,        //指令delay
                    COL_END    =        10'd1020,    //列地址最后四个地址
                    ROW_END    =        13'd8191,    //行地址结束
                    AREF    =        5'b0_0100,
                    WRITE    =        5'b0_1000;
    
    
    reg                        flag_pre;        //换行时需要预充电指令
    reg        [9:0]            col_addr;
    reg                        flag_act;
    reg        [12:0]            row_addr;
    reg        [12:0]            row_addr_reg;
    reg        [3:0]            cmd_cnt;
    //--------------------------------
    //Funtion :    flag_pre
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            flag_pre <= 1'd0;
        else if(col_addr == 1'd0 && flag_wr_end )
            flag_pre <= 1'd1;
        else if(flag_wr_end)
            flag_pre <= 1'd0;
    end
    
    //--------------------------------
    //Funtion :    flag_act            没刷新一次写一次数据
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            flag_act <= 1'd0;
        else if(flag_wr_end)
            flag_act <= 1'd0;
        else if(state == AREF)
            flag_act <= 1'd1;
    end
    
    
    //--------------------------------
    //Funtion :    wr_req
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            wr_req <= 1'd0;
        else if(wr_en)
            wr_req <= 1'd0;
        else if(state != WRITE && wr_trig)
            wr_req <= 1'd1;
    end
    
    //--------------------------------
    //Funtion :    flag_wr_end
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            flag_wr_end <= 1'd0;
        else if(cmd_cnt == CMD_END)
            flag_wr_end <= 1'd1;
        else
            flag_wr_end <= 1'd0;
    end
    
    //--------------------------------
    //Funtion :    cmd_cnt
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            cmd_cnt <= 1'd0;
        else if(state == WRITE)
            cmd_cnt <= cmd_cnt + 1'b1;
        else
            cmd_cnt <= 1'd0;
    end
    
    //--------------------------------
    //Funtion :    wr_cmd
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            wr_cmd <= 1'd0;
        else case(cmd_cnt)
            //预充电 或者 nop
            3'd1 :
            begin
                if(flag_pre)
                    wr_cmd <= PRE;
                else
                    wr_cmd <= NOP;
            end
            //act
            3'd2 :
            begin
                if(flag_act || col_addr == 9'd0)
                    wr_cmd <= ACT;
                else
                    wr_cmd <= NOP;
            end
            //write
            3'd3 :
            begin
                wr_cmd <= WR;
            end
            default : wr_cmd <= NOP;
        
        endcase
    end
    
    //--------------------------------
    //Funtion :    wr_dq
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            wr_dq <= 1'd0;
        else case(cmd_cnt)
            3'd3 :
                wr_dq <= 16'd1000;
            3'd4 :
                wr_dq <= 16'd2000;
            3'd5 :
                wr_dq <= 16'd3000;
            3'd6 :
                wr_dq <= 16'd4000;
            default : 
                wr_dq <= 1'd0;
        endcase
    end
    
    //--------------------------------
    //Funtion :    row_addr_reg
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            row_addr_reg <= 1'd0;
        else if(row_addr_reg == ROW_END && col_addr == COL_END && flag_wr_end)
            row_addr_reg <= 1'd0;
        else if(col_addr == COL_END && flag_wr_end)
            row_addr_reg <= row_addr_reg + 1'b1;
    end
    
    //--------------------------------
    //Funtion :    row_addr
    ///--------------------------------------------------------??????
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            row_addr <= 1'd0;
        else case(cmd_cnt)
            //prechage A10
            3'd1 ,3'd2:        //    测试
                row_addr <= 1'd0;
                
            default : 
                row_addr <= row_addr_reg;
        endcase
    end
    
    //--------------------------------
    //Funtion :        col_addr
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            col_addr <= 1'd0;
        else if(col_addr == COL_END && flag_wr_end)
            col_addr <= 1'd0;
        else if(cmd_cnt == CMD_END)
            col_addr <= col_addr + 3'd4;
    end
    
    
    
    //--------------------------------
    //Funtion :        wr_addr
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            wr_addr <= 1'd0;
        else case(cmd_cnt)
            // 3'd2 :
                // wr_addr <= row_addr;
            
            3'd3 :
                wr_addr  <= {3'd0 , col_addr};
                
            default :
                wr_addr <= row_addr;
        endcase
    end
    
    
    
    //--------------------------------
    //Funtion :        wr_bank
    
    //assign            wr_bank  = 2'd0;
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    endmodule
        

    3、read模块

    read时序图跟write差不多,不同的时read数据出来的时候,需要等待几个周期才可以,这个时间由模式寄存器确定

    /*-----------------------------------------------------------------------
    
    Date                :        2017-08-30
    Description            :        Design for sdram_read .
    
    -----------------------------------------------------------------------*/
    
    module sdram_read
    (
        //global clock
        input                    clk,            //system clock
        input                    rst_n,             //sync reset
        
        //read interface
        output    reg                rd_req,           //读请求
        output    reg                flag_rd_end,    //读结束标志
        input                    rd_wrig,
        input                    rd_en,
        
        //sdram    interface
        output    reg        [3:0]    rd_cmd,
        output    reg        [12:0]    rd_addr,
    //    output            [1:0]    rd_bank,
        input            [15:0]    sdram_dq,
        output            [15:0]    rd_dq,
        
        //
        input            [4:0]    state
    
        
    ); 
    
    
    //--------------------------------
    //Funtion :  参数化定义
    parameter            NOP        =        4'b0111,
                        PRE        =        4'b0010,
                        ACT        =        4'b0011,
                        RD        =        4'b0101,
                        
                        CMD_END    =        4'd12,
                        COL_END    =        10'd1020,
                        ROW_END    =        13'd8191,
                        AREF    =        5'b0_0100,
                        READ    =        5'b1_0000;
    
    reg        [12:0]        row_addr;
    reg        [9:0]        col_addr;
    reg        [3:0]        cmd_cnt;
    reg                    flag_act;
    
    
    //--------------------------------
    //Funtion :    flag_act            每刷新一次读一次数据
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            flag_act <= 1'd0;
        else if(flag_rd_end)
            flag_act <= 1'd0;
        else if(state == AREF)
            flag_act <= 1'd1;
    end
    
    //--------------------------------
    //Funtion :    rd_req
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            rd_req <= 1'b0;
        else if(rd_en)
            rd_req <= 1'b0;
        else if(rd_wrig && state != READ)
            rd_req <= 1'b1;
    end
    
    //--------------------------------
    //Funtion :    cmd_cnt
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            cmd_cnt <= 1'd0;
        else if(state == READ)
            cmd_cnt <= cmd_cnt + 1'b1;
        else
            cmd_cnt <=    1'd0;
    end
    
    //--------------------------------
    //Funtion :    flag_rd_end
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            flag_rd_end <= 1'd0;
        else if(cmd_cnt == CMD_END)
            flag_rd_end <= 1'd1;
        else
            flag_rd_end <= 1'd0;
    end
    
    
    //--------------------------------
    //Funtion :    row_addr
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            row_addr <= 1'd0;
        else if(row_addr == ROW_END && col_addr == COL_END && flag_rd_end)
            row_addr <= 1'd0;
        else if(col_addr == COL_END && flag_rd_end)
            row_addr <= row_addr + 1'b1;
    end
    
    //--------------------------------
    //Funtion :    col_addr
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            col_addr <= 1'd0;
        else if(col_addr == COL_END && flag_rd_end)
            col_addr <= 1'd0;
        else if(flag_rd_end)
            col_addr <= col_addr + 3'd4;
    end
    
    
    //--------------------------------
    //Funtion :    rd_cmd
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            rd_cmd <= NOP;
        else case(cmd_cnt)
            
            4'd1 :
                if(col_addr == 1'd0)
                    rd_cmd <= PRE;
                else
                    rd_cmd <= NOP;
            
            4'd2 :
                if(flag_act || col_addr == 1'd0)
        //        rd_cmd <= NOP;    //测试
                    rd_cmd <= ACT;
                else
                    rd_cmd <= NOP;
            
            4'd3 :
                rd_cmd <= RD;
                
            default : 
                rd_cmd <= NOP;
        
        endcase
    end
    
    //--------------------------------
    //Funtion :    rd_addr
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            rd_addr <= 1'd0;
        else case(cmd_cnt)
            
            4'd3 :
                rd_addr <= {3'd0 , col_addr};
            
            default : 
                rd_addr <= row_addr;
        endcase
    end
    
    
    
    //--------------------------------
    //Funtion :    rd_bank
    
    //assign            rd_bank = 2'd0;
    
    assign        rd_dq = sdram_dq;
    
    
    
    endmodule
        

    待续。。。。。。。

  • 相关阅读:
    袁创:如何成为黄金程序猿
    划重点!新版电子病历评级标准讲解会上6大核心要点
    台湾医院信息化见闻录
    2500行代码实现高性能数值表达式引擎
    HIT创业感言:只有长寿的企业才有持续价值
    袁创:寂静的战争
    相约南湖,南京都昌信息亮相南湖HIT论坛
    我们是谁?南京都昌信息科技有限公司!
    医疗链的系列谈 第一篇 基本概念研究
    论电子病历控件的现状和发展方向
  • 原文地址:https://www.cnblogs.com/bixiaopengblog/p/7460415.html
Copyright © 2011-2022 走看看