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 然后把它读出来