使用FPGA读写SDRAM,SDRAM跑100M时钟
author:ANGRY_KUA_MAX
QQ :2518383357
Time :2018-07-23
淘宝 : https://item.taobao.com/item.htm?spm=a230r.1.14.19.19b35e63Ew9sFv&id=574113974305&ns=1&abbucket=14#detail
作者承接FPGA工程项目,单片机项目开发,付费解决各种疑难杂症。
作者亲自调试编写,并进行长时间测试,无Bug,Sdram为256Mbit,HY57V281620ETP-H,也可以兼容128Mbit,管脚变更后直接使用即可;
程序读写均采用Fifo方式,读写完均可以通过状态查看,速度基本可以保证100M*16bit速度。
工程模块接口如下:
module SDRAM_Project
(
//global clock 50MHz
input clk, //50MHz
input rst_n, //global reset
input key1,
output led,
//sdram control
output sdram_clk, //sdram clock
output sdram_cke, //sdram clock enable
output sdram_cs_n, //sdram chip select
output sdram_we_n, //sdram write enable
output sdram_cas_n, //sdram column address strobe
output sdram_ras_n, //sdram row address strobe
output [1:0] sdram_dqm, //sdram data enable
output [1:0] sdram_ba, //sdram bank address
output [12:0] sdram_addr, //sdram address
inout [15:0] sdram_data, //sdram data
);
工程测试,从指定地址写入数据,然后读出来,若读写数据不一样,则停止操作,并将将状态变更为错误状态:
always @(posedge clk_ref or negedge sys_rst_n)
if(!sys_rst_n) begin
sdram_wrdata <= 0;
sdram_wrreq <= 0;
sdram_wrstate <= 0;
sdram_wrcount <= 0;
sdram_teststate <= 0;
sdram_rdreq <= 0;
RD_ENABLE <= 0;
RD_ADDR <= 0;
WR_ADDR <= 0;
end
else begin
if((!key1)& (sdram_teststate == STATE_IDLE)) begin
sdram_teststate <= STATE_WR;
sdram_wrdata <= 0;
sdram_wrcount <= 0;
WR_ADDR <= 10;
RD_ADDR <= 10;
end
else begin
case (sdram_teststate)
STATE_WR: begin
sdram_teststate <= sys_empty?STATE_WREND:sdram_teststate;
sdram_wrcount <= 0;
RD_ENABLE <= 0;
end
STATE_WREND: begin
if(sdram_wrcount == WRLEN) begin
sdram_wrreq <= 1'd0;
if(WR_FINISHED) begin
sdram_teststate <= STATE_RD;
RD_ENABLE <= 1'd1;
sdram_rdcount <= 0;
sdram_wrdata <= 0;
end
end
else begin
sdram_wrreq <= 1'd1;
sdram_wrcount <= sdram_wrcount + 1'd1;
sdram_wrdata <= sdram_wrdata + 1'd1;
end
end
STATE_RD: begin
RD_ENABLE <= (RD_USIZE != 0)?1'd0:RD_ENABLE;
sdram_teststate <= (RD_USIZE != 0)?STATE_RDEND:sdram_teststate;
end
STATE_RDEND: begin
if(sdram_rdcount == WRLEN) begin
if(RD_USIZE == 0) begin
sdram_teststate <= STATE_WR;
end
sdram_rdreq <= 1'd0;
end
else begin
sdram_rdreq <= 1'd1;
sdram_rdcount <= sdram_rdcount + 1'd1;
if((sdram_rdcount != sys_data_out) && sdram_rdreq) begin
sdram_teststate <= STATE_ERR;
end
end
end
default:;
endcase
end
end
SDRAM例化的模块接口
Sdram_Control_2Port u_Sdram_Control_2Port
(
// HOST Side
.REF_CLK (clk_ref), //100M,sdram module clock
.OUT_CLK (clk_refout), //100M,sdram clock input
.RESET_N (sys_rst_n), //sdram module reset
// SDRAM Side,管脚接口
.SDR_CLK (sdram_clk), //sdram clock
.CKE (sdram_cke), //sdram clock enable
.CS_N (sdram_cs_n), //sdram chip select
.WE_N (sdram_we_n), //sdram write enable
.CAS_N (sdram_cas_n), //sdram column address strobe
.RAS_N (sdram_ras_n), //sdram row address strobe
.DQM (sdram_dqm), //sdram data output enable
.BA (sdram_ba), //sdram bank address
.SA (sdram_addr), //sdram address
.DQ (sdram_data), //sdram data
.Sdram_Init_Done (sdram_init_done) //SDRAM init done signal
// FIFO Write Side
.WR_CLK (clk_write), //write fifo clock
.WR_RESET (!sys_rst_n), //write register load & fifo clear
.WR_DATA (sys_data_in), //write data input
.WR (sys_we), //write data request
.WR_ADDR (WR_ADDR), //write start address
.WR_LENGTH (WRLEN), //write burst length
.WR_EMPTY (sys_empty),
.WR_FINISHED (WR_FINISHED),
// FIFO Read Side
.RD_CLK (clk_read), //read fifo clock
.RD_ENABLE (RD_ENABLE),
.RD_RESET (!sys_rst_n), //read fifo clear
.RD_DATA (sys_data_out), //read data output
.RD (sys_rd), //read request
.RD_ADDR (RD_ADDR), //read start address
.RD_LENGTH (WRLEN), //read length
.RD_USIZE (RD_USIZE) //
);
//状态指示灯/
reg [26:0] led_count;
reg led_run;
always @(posedge clk_ref or negedge sys_rst_n)
if(!sys_rst_n) begin
led_count <= 0;
led_run <= 0;
end
else begin
if((led_count >= 99999999 && sdram_teststate != STATE_IDLE) || (sdram_teststate == STATE_ERR && led_count >= 4999999)) begin
led_count <= 0;
led_run <= !led_run;
end
else begin
led_count <= led_count + 1'd1;
end
end
assign led = led_run;
***********华丽风隔线******************
对初次使用SDRAM的工程师或者学生,可以具有非常不错的参考价值,作者可以手把手教使用signal tap抓取程序读写数据,分析程序逻辑。