秦韵FPGA 转载或原创(八)
基于高云fpga ------ GW2A18
文章目录
1.DDR3控制器介绍
1.1 DDR3简介
DDR3 SDRAM:ddr3(转载),关于这部分的理论知识,直接在百度上搜索即可,想要了解具体的内存芯片,可以去自己板卡上使用的芯片官网去下载数据手册,上面会详细讲解操作…sdram的时序。
1.2 。。。
2.DDR3控制逻辑思路简单介绍
关于这部分的思路,相对来说比较简单,参考高云官网的ddr3 控制手册,(比较喜人的一点是完全中文的手册),参照时序图写代码,比较轻松了。
主要的控制逻辑是基于init_calib_complete为高的情况下来做的,否则没有意义。简单点的介绍就类似于valid ,ready总线。有ready拉高的情况下,我才可以给出valid信号。因此,在ddr3控制器的控制逻辑部分,简单可以分为三个通道:
命令地址通道
写数据通道
读数据通道
清楚了这部分,代码就好写了,直接用一个状态机(不论三段式还是一段式,哪个熟用哪个),分别将命令的数据写进ddr3就行了,其他的代码高云已经帮我们做完了。注:多看手册(中文的)。
做完这部分,你的外部控制逻辑的接口就出来了,后面的业务部分代码就需要你来添加了,不论是存储图像数据,adc数据,还是音频数据,都ok。
3.DDR3控制逻辑代码代码解释
简单的贴一些代码:(贴一个测试代码的顶层文件,可以做为参考)
WMP0015_V_DDR3_V001_D35(
input clk,
input rst_n,
output [14-1:0] DDR3_addr,
output [3-1:0] DDR3_bank,
output DDR3_cs,
output DDR3_ras,
output DDR3_cas,
output DDR3_we,
output DDR3_ck,
output DDR3_ck_n,
output DDR3_cke,
output DDR3_odt,
output DDR3_reset_n,
output [2-1:0] DDR3_dm,
inout [16-1:0] DDR3_dq,
inout [2-1:0] DDR3_dqs,
inout [2-1:0] DDR3_dqs_n,
output init_calib_complete,
output led
);
assign ddr_cs = 1'b0;
wire clk_ddr;
wire ddr_rst;
wire usr_wr_wren;
wire [16-1:0] usr_wr_mask;
wire usr_wr_end;
wire [128-1:0] usr_wr_data;
wire usr_en/* synthesis syn_keep=1 */;
wire [2:0] usr_cmd/* synthesis syn_keep=1 */;
wire [28-1:0] usr_addr/* synthesis syn_keep=1 */;
wire usr_sre_req;
wire usr_ref_req;
wire usr_burst;
wire usr_sre_act;
wire usr_ref_ack;
wire usr_wr_rdy/* synthesis syn_keep=1 */;
wire usr_rdy;
wire usr_rd_data_valid/* synthesis syn_keep=1 */;
wire usr_rd_data_end/* synthesis syn_keep=1 */;
wire [128-1:0] usr_rd_data/* synthesis syn_keep=1 */;
wire [5:0] usr_burst_number;
assign led = !init_calib_complete;
DDR3_Memory_Control#(
.ADDR_WIDTH (28),
.APP_DATA_WIDTH (128),
.APP_MASK_WIDTH (16)
)
(
.clk (clk_ddr ),
.rst (ddr_rst ),
.usr_rdy (usr_rdy),
.usr_rd_data_valid (usr_rd_data_valid),
.wr_data_rdy (usr_wr_rdy),
.usr_rd_data (usr_rd_data),
.init_calib_complete(init_calib_complete),
.usr_en (usr_en),
.usr_cmd (usr_cmd),
.usr_addr (usr_addr),
.usr_wr_data (usr_wr_data),
.usr_wr_wren (usr_wr_wren),
.usr_wr_end (usr_wr_end),
.usr_wr_mask (usr_wr_mask),
.usr_burst (usr_burst),
.sr_req (usr_sre_req),
.ref_req (usr_ref_req),
.usr_burst_number (usr_burst_number)
);
//添加一部分控制逻辑代码,仅作为参考,这部分代码
//数据位宽64bit
//数据掩码8bit
//
always@(posedge clk or posedge rst)
if(rst)
arbi_rw_cnt <= 3'd0;
else if( ((state_cs == ARBI_WRITE) | (state_cs == ARBI_READ)) && wr_data_rdy && init_calib_complete )
arbi_rw_cnt <= arbi_rw_cnt + 1;
else
arbi_rw_cnt <= 3'd0;
always@(posedge clk or posedge rst)
if(rst) begin
usr_en <= 1'b0;
usr_cmd <= 3'b000;
usr_addr <= 24'h0;
end
else if(state_cs == ARBI_WCMD) begin
usr_en <= 1'b1;
usr_cmd <= 3'b000;
usr_addr <= usr_wdf_addr;
end
else if(state_cs == ARBI_RCMD) begin
usr_en <= 1'b1;
usr_cmd <= 3'b001;
usr_addr <= usr_rdf_addr;
end
else begin
usr_en <= 1'b0;
usr_cmd <= 3'b000;
usr_addr <= 24'h0;
end
always@(posedge clk or posedge rst)
if(rst) begin
usr_wr_wren <= 1'b0;
usr_wr_mask <= 8'b00000000;
usr_wr_data <= 64'h0;
usr_wr_end <= 1'b0;
end
else if( (state_cs == ARBI_WRITE) && wr_data_rdy && init_calib_complete) begin
usr_wr_wren <= 1'b1;
usr_wr_mask <= 8'b00000000;
usr_wr_data <= usr_wdf_data;
if(&arbi_rw_cnt)
usr_wr_end <= 1'b1;
else
usr_wr_end <= 1'b0;
end
else begin
usr_wr_wren <= 1'b0;
usr_wr_mask <= 8'b00000000;
usr_wr_data <= 64'h0;
usr_wr_end <= 1'b0;
end
4.代码扩展(逻辑扩展)
这部分做为整体项目规划的来处理的,主要实现的是除了ddr3驱动部分以外的逻辑,包括数据的存储,怎样存储?封包还是单纯数据存储,是添加其他协议还是经过业务层的处理过后再存储?这边简单的画一个框图,有兴趣的可以写来测试一下。
简单的8路百兆数据写入,千兆吐出,不要求时时数据,每3s出1s的数据(1s中的1/n),具体业务处理方式就不做介绍了。写入ddr3之前,需要做分包处理,在写入ddr3之前添加缓存,写个简单的仲裁器。
贴个简单的图吧: