DDR3 AXI4 IP核读写仿真实验(2)
上篇blog中记录了DDR3 AXI4接口的IP配置详情,这一文章则是记录自己在项目工程以及学习中对于DDR3的读写测试。先讲一下大概的工程架构:产生16位的自加数写进写FIFO中,当FIFO中的数达到一次突发长度后将其全部读出写进DDR3中,再检测到DDR3中数达到1024之后全部读出写入到读FIFO中,最后在顶层的读使能信号作用下将读FIFO的数全部读出,查看写入的自加数与读出的数是否符一直,符合则实验成功。
可能有的读者最开始会疑问为什么会用到两个异步FIFO,这个自己在最开始学的时候也在想不用行不行,你不用FIFO直接写入数据再读出肯定也是可以的,但是考虑到实际项目需求以及IP核封装出的用户接口,用两个FIFO既可以解决数据位宽不同步以及突发传输的问题,并且复用性更强。比如我自己的一个项目就是数据采集相关,ADC是16位,转换出的数据存入DDR3之前先写进fifo,再读出128位的数据匹配ip 核的读写数据端口。读fifo也是同理。
工程结构
axi_test_ddr_top:顶层模块,主要为产生自加数、列化子模块、时钟生成和生成vio复位调试。
ax_ddr_top:封装好的DDR使用模块,可通过修改顶层参数实现突发长度、数据位宽、地址长度等参数的修改。
axi_fifo_ctrl:将读写fifo封装进子模块,引出fifo所需要相关信号。
axi_wr:axi4接口的写模块,实现AXI4相关写时序并且将数据写进DDR3。
axi_rd:axi4接口的读模块,实现AXI4相关读时序并且将数据从DDR3读出。
mig_7series_0:例化的ip核模板。
DDR型号为MT41K256M16XX-125,单片容量4Gb(512MB)。
![](/assets/blank.gif)
具体代码分析
axi_test_ddr_top:
首先我测试用的板卡自带的是200M的差分晶振时钟,为了方便测试,直接用锁相环生成clk_adc、clk_pci与clk_200m。clk_adc是产生自加数的时钟,也是写fifo的写时钟。clk_pci是读fifo的读时钟,读fifo的读使能采用的是当读fifo内可读个数达到900时拉高读使能信号将数据读出。
vio模块是为了产生复位信号(FPGA_RST_N)方便抓取信号时调试。
`timescale 1ns / 1ps
module axi_test_ddr_top
(input clk_200m_p, //50M input clk_200m_n, //50M
// input FPGA_RST_N,//ddr3相关 inout [15:0] ddr3_dq ,inout [1:0] ddr3_dqs_n ,inout [1:0] ddr3_dqs_p ,output [14:0] ddr3_addr , //hang地址线output [2:0] ddr3_ba , //bank线output ddr3_cas_n , // 列使能信号,低电平有效 output ddr3_ck_n , //差分时钟output ddr3_ck_p , //差分时钟output ddr3_cke , //ddr3时钟使能信号output ddr3_ras_n , // 行使能信号,低电平有效output ddr3_reset_n , //复位output ddr3_we_n , //写使能output ddr3_cs_n , //片选output [1:0] ddr3_dm , //掩码output ddr3_odt ); reg [15:0] ai_fifo_data_i ;
reg ai_fifo_wr ;
wire ai_fifo_full ;
reg ai_pcie_fifo_rd ;
wire [15:0] ai_pcie_fifo_data ;
wire [12:0] ai_pcie_fifo_rd_data_count ;
wire init_calib_complete ;
wire locked ;
wire clk_adc,clk_pci;wire clk_200m ; vio_0 u_vio_0 (.clk(clk_200m), // input wire clk.probe_out0(FPGA_RST_N) // output wire [0 : 0] probe_out0
); clk_wiz_0 clk_wiz_0_inst(// Clock out ports.c0(clk_200m), // output c0 200.c1(clk_adc), // output clk_out3.c2(clk_pci), // output clk_out4// Status and control signals.locked(locked), // output locked// Clock in ports.clk_in1_p(clk_200m_p), // input clk_in1_p.clk_in1_n(clk_200m_n)); // input clk_in1_n always@ (posedge clk_pci)beginif (!FPGA_RST_N) beginai_pcie_fifo_rd <= 1'b0;end else if(ai_pcie_fifo_rd_data_count >=13'd900) beginai_pcie_fifo_rd <= 1'b1;end else beginai_pcie_fifo_rd <= 1'b0;end
end always@ (posedge clk_adc)beginif (!FPGA_RST_N) beginai_fifo_data_i <= 64'd0;ai_fifo_wr <= 1'd0;end else beginif(init_calib_complete & !ai_fifo_full) beginai_fifo_data_i <= ai_fifo_data_i +1'b1;ai_fifo_wr <= 1'b1;end else beginai_fifo_data_i <= ai_fifo_data_i;ai_fifo_wr <= 1'b0;endend
end axi_ddr_top
#( . DDR_WR_LEN ( 10'd128 ),. DDR_RD_LEN ( 10'd128 ),. DATA_WIDTH ( 128 ),. DDR_COUNT ( 1024 ),. DDR_ADDR_LIMIT (32'h0fff_fff0),. DDR_CNT_LIMIT (32'h8000_0000 )
)
axi_ddr_top_inst
(. adc_clk_i (clk_adc ), . ddr3_clk_i (clk_200m), . pci_clk_i (clk_pci),. rst_n_i (FPGA_RST_N), .ai_fifo_data_i (ai_fifo_data_i ),.ai_fifo_wr (ai_fifo_wr ), .ai_fifo_full (ai_fifo_full ), .ai_pcie_fifo_rd (ai_pcie_fifo_rd ),.ai_pcie_fifo_data (ai_pcie_fifo_data ),.ai_pcie_fifo_rd_data_count (ai_pcie_fifo_rd_data_count ), .init_calib_complete (init_calib_complete ), // Output Ports - Single Bit.ddr3_cas_n (ddr3_cas_n), .ddr3_ck_n (ddr3_ck_n), .ddr3_ck_p (ddr3_ck_p), .ddr3_cke (ddr3_cke), .ddr3_cs_n (ddr3_cs_n), .ddr3_odt (ddr3_odt), .ddr3_ras_n (ddr3_ras_n), .ddr3_reset_n (ddr3_reset_n), .ddr3_we_n (ddr3_we_n), // Output Ports - Busses.ddr3_addr (ddr3_addr ),.ddr3_ba (ddr3_ba), .ddr3_dm (ddr3_dm), // InOut Ports - Single Bit// InOut Ports - Busses.ddr3_dq (ddr3_dq ),.ddr3_dqs_n (ddr3_dqs_n ),.ddr3_dqs_p (ddr3_dqs_p )
);
endmodule
axi_ddr_top:
此模块主要例化三个子模块,包括fifo控制模块、axi读与写模块以及ip核例化模板。
为了方便调试时控制IP核的工作,例化一个vio控制IP核的复位,方便在抓取信号时,先对IP核复位再产生数据写入fifo中。
总体顶层信号需要自己产生的就是自加数、写fifo的写使能与读fifo的读使能信号,其余相关联信号在fifo控制模块中引出。具体的可查看代码。
`timescale 1ns / 1ps
module axi_ddr_top #
(parameter DDR_WR_LEN = 8'd128, //写突发长度 最大128个128bitparameter DDR_RD_LEN = 8'd128, //写突发长度 最大128个128bit parameter DATA_WIDTH = 128, //读写数据位宽parameter DDR_COUNT = 1024, //DDR内部存在数据个数parameter DDR_ADDR_LIMIT = 32'h0fff_ffff , //2^10*2^15*2^3=2^28=268,435,456=32'h0fff_ffffparameter DDR_CNT_LIMIT = 32'h0fff_ffff // 4*1024^3bit / 16bit = 268,435,456 = 32'h0fff_ffff
)
(//50m的时钟与复位信号input ddr3_clk_i, //200m input adc_clk_i, //64Minput pci_clk_i, // input rst_n_i , //外部复位inout [15:0] ddr3_dq , //数据线inout [1:0] ddr3_dqs_n , //数据选取脉冲差分信号inout [1:0] ddr3_dqs_p , //数据选取脉冲差分信号output [14:0] ddr3_addr , //地址线output [2:0] ddr3_ba , //bank线output ddr3_ras_n , //行使能信号,低电平有效output ddr3_cas_n , //列使能信号,低电平有效output ddr3_we_n , //写使能信号,低电平有效output ddr3_reset_n , //ddr3复位output [0:0] ddr3_ck_p , //ddr3差分时钟output [0:0] ddr3_ck_n , //ddr3差分时钟output [0:0] ddr3_cke , //ddr3时钟使能信号output [0:0] ddr3_cs_n , //ddr3片选信号output [1:0] ddr3_dm , //ddr3掩码output [0:0] ddr3_odt , //odt阻抗input [15:0] ai_fifo_data_i,input ai_fifo_wr , output ai_fifo_full , input ai_pcie_fifo_rd ,output [15:0] ai_pcie_fifo_data,output [12:0] ai_pcie_fifo_rd_data_count,output init_calib_complete );
//wire define//axi写通道写地址
wire [3:0] M_AXI_WR_awid; //写地址ID,用来标志一组写信号
wire [28:0]M_AXI_WR_awaddr; //写地址,给出一次写突发传输的写地址
wire [7:0] M_AXI_WR_awlen; //突发长度,给出突发传输的次数
wire [2:0] M_AXI_WR_awsize; //突发大小,给出每次突发传输的字节数
wire [1:0] M_AXI_WR_awburst;//突发类型
wire [0:0] M_AXI_WR_awlock; //总线锁信号,可提供操作的原子性
wire [3:0] M_AXI_WR_awcache;//内存类型,表明一次传输是怎样通过系统的
wire [2:0] M_AXI_WR_awprot; //保护类型,表明一次传输的特权级及安全等级
wire [3:0] M_AXI_WR_awqos; //质量服务QoS
wire M_AXI_WR_awvalid;//有效信号,表明此通道的地址控制信号有效
wire M_AXI_WR_awready;//表明“从”可以接收地址和对应的控制信号
//axi写通道读数据
wire [DATA_WIDTH-1 :0]M_AXI_WR_wdata; //写数据
wire [DATA_WIDTH/8-1 :0] M_AXI_WR_wstrb; //写数据有效的字节线//用来表明哪8bits数据是有效的
wire M_AXI_WR_wlast; //表明此次传输是最后一个突发传输
wire M_AXI_WR_wvalid; //写有效,表明此次写有效
wire M_AXI_WR_wready; //表明从机可以接收写数据
//axi写通道读应答
wire [3:0] M_AXI_WR_bid ; //写响应ID TAG
wire [1:0] M_AXI_WR_bresp ; //写响应,表明写传输的状态
wire M_AXI_WR_bvalid ; //写响应有效
wire M_AXI_WR_bready ; //表明主机能够接收写响应//axi读通道写地址
wire [3:0] M_AXI_RD_arid; //读地址ID,用来标志一组写信号
wire [28:0]M_AXI_RD_araddr; //读地址,给出一次写突发传输的读地址
wire [7:0] M_AXI_RD_arlen; //突发长度,给出突发传输的次数
wire [2:0] M_AXI_RD_arsize; //突发大小,给出每次突发传输的字节数
wire [1:0] M_AXI_RD_arburst;//突发类型
wire [0:0] M_AXI_RD_arlock; //总线锁信号,可提供操作的原子性
wire [3:0] M_AXI_RD_arcache;//内存类型,表明一次传输是怎样通过系统的
wire [2:0] M_AXI_RD_arprot; //保护类型,表明一次传输的特权级及安全等级
wire [3:0] M_AXI_RD_arqos; //质量服务QOS
wire M_AXI_RD_arvalid;//有效信号,表明此通道的地址控制信号有效
wire M_AXI_RD_arready;//表明“从”可以接收地址和对应的控制信号
//axi读通道读数据
wire [3:0] M_AXI_RD_rid; //读ID tag
wire [DATA_WIDTH-1:0] M_AXI_RD_rdata; //读数据
wire [1:0] M_AXI_RD_rresp; //读响应,表明读传输的状态
wire M_AXI_RD_rlast; //表明读突发的最后一次传输
wire M_AXI_RD_rvalid; //表明此通道信号有效
wire M_AXI_RD_rready; //表明主机能够接收读数据和响应信息//
wire ui_clk ; //800 /4 = 200m
wire ui_rst ;
wire ddr3_rst_n;wire locked ;
wire ai_fifo_rd ;
wire ai_fifo_prog_full; wire [127:0]wr_fifo_data;
wire [127:0]rd_fifo_data;
wire [31:0] ddr_count ;
wire ddr_prog_full ;
wire ddr_cnt_full ;
wire [12:0]rd_data_count;
wire ai_pcie_fifo_prom_full;
wire [9:0] wr_fifo_rd_data_count;
/* ila_1 u_ila_1 (.clk(ddr3_clk_i), // input wire clk.probe0({ M_AXI_WR_awid, M_AXI_WR_wdata , M_AXI_WR_bid , M_AXI_RD_arid , M_AXI_RD_rid , M_AXI_WR_awaddr , M_AXI_WR_wstrb , M_AXI_WR_bresp, M_AXI_RD_araddr , M_AXI_RD_rdata ,M_AXI_WR_awlen , M_AXI_WR_bvalid, M_AXI_RD_arlen , M_AXI_RD_rresp ,M_AXI_WR_awsize , M_AXI_WR_wlast , M_AXI_WR_bready, M_AXI_RD_arsize , M_AXI_RD_rlast ,M_AXI_WR_awburst , M_AXI_WR_wvalid, M_AXI_RD_arburst , M_AXI_RD_rvalid,M_AXI_WR_awlock , M_AXI_WR_wready, M_AXI_RD_arlock , M_AXI_RD_rready,M_AXI_WR_awcache , ai_fifo_data_i, M_AXI_RD_arcache ,M_AXI_WR_awprot , ai_fifo_wr , M_AXI_RD_arprot ,M_AXI_WR_awqos , ai_fifo_full , M_AXI_RD_arqos ,M_AXI_WR_awvalid , init_calib_complete, M_AXI_RD_arvalid ,M_AXI_WR_awready , M_AXI_RD_arready }) // input wire [511:0] probe0
); vio_1 u_vio_1 (.clk(ddr3_clk_i), // input wire clk.probe_out0(ddr3_rst_n) // output wire [0 : 0] probe_out0
);axi_fifo_ctrl#
(.DDR_COUNT (DDR_COUNT ),//DDR内部存在数据个数.DDR_CNT_LIMIT (DDR_CNT_LIMIT) // 1024^3 *8 bit / 16bit = 536870912 = 32'h2000_0000
)(. ddr3_clk_i (ddr3_clk_i ) , //200m . adc_clk_i (adc_clk_i ) , //64M. pci_clk_i (pci_clk_i ) , // . rst_n_i ( rst_n_i ) , //外部复位. ai_fifo_data_i (ai_fifo_data_i ) ,. ai_fifo_rd (ai_fifo_rd ) ,. ai_fifo_wr (ai_fifo_wr ) , . ai_fifo_full (ai_fifo_full ) , . wr_fifo_data (wr_fifo_data ) ,. M_AXI_RD_rvalid (M_AXI_RD_rvalid ) ,. rd_fifo_data (rd_fifo_data ) ,. rd_fifo_we (rd_fifo_we ) ,. ai_pcie_fifo_rd (ai_pcie_fifo_rd ) ,. ai_pcie_fifo_data (ai_pcie_fifo_data ) ,. ai_pcie_fifo_rd_data_count (ai_pcie_fifo_rd_data_count ) ,. ai_pcie_fifo_prom_full (ai_pcie_fifo_prom_full ) ,. wr_fifo_rd_data_count (wr_fifo_rd_data_count ) ,. ddr_count (ddr_count ) ,. ddr_prog_full (ddr_prog_full ) , . ddr_cnt_full (ddr_cnt_full ) );axi_wr
#(.DATA_WIDTH(DATA_WIDTH),.DDR_ADDR_LIMIT(DDR_ADDR_LIMIT)
)
u_axi_wr
( .ARESETN (rst_n_i ), //axi复位.ACLK (ui_clk ), //axi总时钟.M_AXI_AWID (M_AXI_WR_awid ), //写地址ID.M_AXI_AWADDR (M_AXI_WR_awaddr ), //写地址.M_AXI_AWLEN (M_AXI_WR_awlen ), //突发长度 .M_AXI_AWSIZE (M_AXI_WR_awsize ), //突发大小 .M_AXI_AWBURST(M_AXI_WR_awburst), //突发类型 .M_AXI_AWLOCK (M_AXI_WR_awlock ), //总线锁信号 .M_AXI_AWCACHE(M_AXI_WR_awcache), //内存类型.M_AXI_AWPROT (M_AXI_WR_awprot ), //保护类型.M_AXI_AWQOS (M_AXI_WR_awqos ), //质量服务QoS .M_AXI_AWVALID(M_AXI_WR_awvalid), //有效信号.M_AXI_AWREADY(M_AXI_WR_awready), //握手信号awready.M_AXI_WDATA (M_AXI_WR_wdata ), //写数据.M_AXI_WSTRB (M_AXI_WR_wstrb ), //写数据有效的字节线.M_AXI_WLAST (M_AXI_WR_wlast ), //表明此次传输是最后一个突发传输.M_AXI_WVALID(M_AXI_WR_wvalid ), //写有效.M_AXI_WREADY(M_AXI_WR_wready ), //表明从机可以接收写数据 .M_AXI_BID (M_AXI_WR_bid ), //写响应ID TAG.M_AXI_BRESP (M_AXI_WR_bresp ), //写响应.M_AXI_BVALID(M_AXI_WR_bvalid ), //写响应有效.M_AXI_BREADY(M_AXI_WR_bready ), //表明主机能够接收写响应 .wr_len (DDR_WR_LEN ),.wr_fifo_rd_data_count( wr_fifo_rd_data_count),.wr_fifo_data (wr_fifo_data ),
// .ai_fifo_wr (wr_fifo_re ),.ai_fifo_prog_full(ai_fifo_prog_full),.ddr_cnt_full (ddr_cnt_full ),.ai_fifo_rd (ai_fifo_rd ), .wr_done ( )
);
axi_rd
#(.DATA_WIDTH(DATA_WIDTH),.DDR_ADDR_LIMIT(DDR_ADDR_LIMIT)
)
u_axi_rd
(. ARESETN (rst_n_i),. ACLK (ui_clk),. M_AXI_ARID (M_AXI_RD_arid ), //读地址ID. M_AXI_ARADDR (M_AXI_RD_araddr ), //读地址. M_AXI_ARLEN (M_AXI_RD_arlen ), //突发长度. M_AXI_ARSIZE (M_AXI_RD_arsize ), //突发大小. M_AXI_ARBURST(M_AXI_RD_arburst), //突发类型. M_AXI_ARLOCK (M_AXI_RD_arlock ), //总线锁信号. M_AXI_ARCACHE(M_AXI_RD_arcache), //内存类型. M_AXI_ARPROT (M_AXI_RD_arprot ), //保护类型. M_AXI_ARQOS (M_AXI_RD_arqos ), //质量服务QOS. M_AXI_ARVALID(M_AXI_RD_arvalid), //有效信号. M_AXI_ARREADY(M_AXI_RD_arready), //握手信号arready. M_AXI_RID (M_AXI_RD_rid ), //读ID tag. M_AXI_RDATA (M_AXI_RD_rdata ), //读数据. M_AXI_RRESP (M_AXI_RD_rresp ), //读响应,表明读传输的状态. M_AXI_RLAST (M_AXI_RD_rlast ), //表明读突发的最后一次传输. M_AXI_RVALID(M_AXI_RD_rvalid), //表明此通道信号有效. M_AXI_RREADY(M_AXI_RD_rready), //表明主机能够接收读数据和响应信息// . rd_start ( ), //读突发触发信号. rd_len (DDR_RD_LEN), //长度
// . rd_addr ( ), //地址. rd_fifo_we (rd_fifo_we ), //连接到读fifo的写使能 O. rd_fifo_data (rd_fifo_data ), //连接到读fifo的写数据. rd_done ( ), //完成一次突发. ddr_prog_full(ddr_prog_full ),. ddr_count(ddr_count),. ai_pcie_fifo_prom_full(ai_pcie_fifo_prom_full)
);
mig_7series_0 U_mig_7series_0
(.ddr3_dq (ddr3_dq ), //数据线.ddr3_dqs_n(ddr3_dqs_n), //数据选取脉冲差分信号.ddr3_dqs_p(ddr3_dqs_p), //数据选取脉冲差分信号.ddr3_addr (ddr3_addr ), //地址线.ddr3_ba (ddr3_ba ), //bank线.ddr3_ras_n(ddr3_ras_n), //行使能信号,低电平有效.ddr3_cas_n(ddr3_cas_n), //列使能信号,低电平有效.ddr3_we_n (ddr3_we_n ), //写使能信号,低电平有效.ddr3_reset_n(ddr3_reset_n), //ddr3复位.ddr3_ck_p (ddr3_ck_p ), //ddr3差分时钟.ddr3_ck_n (ddr3_ck_n ), //ddr3差分时钟.ddr3_cke (ddr3_cke ), //ddr3时钟使能信号.ddr3_cs_n (ddr3_cs_n ), //ddr3片选信号.ddr3_dm (ddr3_dm ), //ddr3掩码.ddr3_odt (ddr3_odt ), //odt阻抗.sys_clk_i (ddr3_clk_i), //ip核时钟200M.sys_rst (ddr3_rst_n), //ip核复位.ui_clk (ui_clk), //用户端口时钟200M.ui_clk_sync_rst (ui_rst), //复位.mmcm_locked ( ),.aresetn (ddr3_rst_n), //异步复位.app_sr_req ('b0),.app_ref_req ('b0),.app_zq_req ('b0),.app_sr_active (),.app_ref_ack (),.app_zq_ack (),//axi写通道地址与控制信号.s_axi_awid (M_AXI_WR_awid ), //写地址ID .s_axi_awaddr (M_AXI_WR_awaddr ), //写地址.s_axi_awlen (M_AXI_WR_awlen ), //突发长度.s_axi_awsize (M_AXI_WR_awsize ), //突发大小.s_axi_awburst (M_AXI_WR_awburst), //突发类型.s_axi_awlock (M_AXI_WR_awlock ), //总线锁信号.s_axi_awcache (M_AXI_WR_awcache), //内存类型.s_axi_awprot (M_AXI_WR_awprot ), //保护类型.s_axi_awqos (M_AXI_WR_awqos ), //质量服务QoS.s_axi_awvalid (M_AXI_WR_awvalid), //有效信号.s_axi_awready (M_AXI_WR_awready), //握手信号awready//axi写通道数据.s_axi_wdata (M_AXI_WR_wdata ), //写数据.s_axi_wstrb (M_AXI_WR_wstrb ), //写数据有效的字节线.s_axi_wlast (M_AXI_WR_wlast ), //表明此次传输是最后一个突发传输.s_axi_wvalid (M_AXI_WR_wvalid ), //写有效,表明此次写有效.s_axi_wready (M_AXI_WR_wready ), //表明从机可以接收写数据//axi写通道应答 .s_axi_bid (M_AXI_WR_bid ), //写响应ID TAG.s_axi_bresp (M_AXI_WR_bresp ), //写响应,表明写传输的状态.s_axi_bvalid (M_AXI_WR_bvalid ), //写响应有效.s_axi_bready (M_AXI_WR_bready ), //表明主机能够接收写响应//axi读通道地址与控制信号 .s_axi_arid (M_AXI_RD_arid ), //读地址ID.s_axi_araddr (M_AXI_RD_araddr ), //读地址.s_axi_arlen (M_AXI_RD_arlen ), //突发长度.s_axi_arsize (M_AXI_RD_arsize ), //突发大小.s_axi_arburst (M_AXI_RD_arburst), //突发类型.s_axi_arlock (M_AXI_RD_arlock ), //总线锁信号.s_axi_arcache (M_AXI_RD_arcache), //内存类型.s_axi_arprot (M_AXI_RD_arprot ), //保护类型.s_axi_arqos (M_AXI_RD_arqos ), //质量服务QOS.s_axi_arvalid (M_AXI_RD_arvalid), //有效信号.s_axi_arready (M_AXI_RD_arready), //握手信号arready//axi读通道数据,包括应答 .s_axi_rid (M_AXI_RD_rid ), //读ID tag.s_axi_rdata (M_AXI_RD_rdata ), //读数据.s_axi_rresp (M_AXI_RD_rresp ), //读响应,表明读传输的状态.s_axi_rlast (M_AXI_RD_rlast ), //表明读突发的最后一次传输.s_axi_rvalid (M_AXI_RD_rvalid ), //表明此通道信号有效.s_axi_rready (M_AXI_RD_rready ), //表明主机能够接收读数据.init_calib_complete(init_calib_complete) //ip核初始化完成
);
endmodule
axi_fifo_ctrl:
这里比较重要的是代码30-58行代码,这里需要引出三个信号:ddr_count、ddr_prog_full、ddr_cnt_full。分别为ddr内部存在的数据个数、超过1024的满标志信号、超出ddr内部最大极限个数的标志信号。
顺便提一下38、40行代码:在写fifo读使能有效之后ddr_count加8与DDR读出有效后减8的原因:前文提到的AXI4总线的位宽选择的是128 ,在每次axi握手成功后写入ddr内部的数据个数应该是(128/16=8),读出也是同理。
`timescale 1ns / 1ps
module axi_fifo_ctrl#
( parameter DATA_WIDTH = 128,parameter DDR_COUNT = 1024, //预设DDR存1024个数parameter DDR_CNT_LIMIT = 32'h0fff_ffff // 4*1024^3bit / 16bit = 268,435,456 = 32'h0fff_ffff
)(input ddr3_clk_i, //200m input adc_clk_i, //64Minput pci_clk_i, // input rst_n_i , //外部复位input [15:0] ai_fifo_data_i,input ai_fifo_rd ,input ai_fifo_wr , output ai_fifo_full , output [DATA_WIDTH-1 :0 ] wr_fifo_data ,input M_AXI_RD_rvalid,input [DATA_WIDTH-1 :0 ] rd_fifo_data,input rd_fifo_we,input ai_pcie_fifo_rd ,output [15:0] ai_pcie_fifo_data,output [12:0] ai_pcie_fifo_rd_data_count,output ai_pcie_fifo_prom_full,output [9:0] wr_fifo_rd_data_count,output reg [31:0] ddr_count , //DDR内部存在的数据个数output reg ddr_prog_full ,output reg ddr_cnt_full ); always@ (posedge ddr3_clk_i or negedge rst_n_i)beginif (!rst_n_i) beginddr_count <= 32'd0;ddr_prog_full <= 1'b0;ddr_cnt_full <= 1'b0;end else beginif(ai_fifo_rd)begin //fifo开始读出数据到ddr3ddr_count <= ddr_count + 32'd8;end else if(M_AXI_RD_rvalid) begin //DDR读出有效 && fifo非满 时ddr内的数据被读出ddr_count <= ddr_count - 32'd8;end else beginddr_count <= ddr_count;endif(ddr_count >= DDR_COUNT)begin // 超过1024满标志信号ddr_prog_full <= 1'b1;end else beginddr_prog_full <= 1'b0;endif(ddr_count > DDR_CNT_LIMIT)begin // 超过 ddr_cnt_limit 满标志信号ddr_cnt_full <= 1'b1;end else beginddr_cnt_full <= 1'b0;endend
end data_2_ddr3_16x64_8192 adc_2_ddr3_16x64_8192 (.rst (!rst_n_i), // input wire rst.wr_clk(adc_clk_i), // input wire wr_clk.rd_clk(ddr3_clk_i ), // input wire rd_clk.din (ai_fifo_data_i), // input wire [15 : 0] din.wr_en(ai_fifo_wr), // input wire wr_en.rd_en(ai_fifo_rd), // input wire rd_en.dout(wr_fifo_data), // output wire [127 : 0] dout 等于app_wdf_data.almost_full (ai_fifo_full), // output wire almost_full .full ( ), // output wire full.empty(ai_fifo_empty), // output wire empty.rd_data_count(wr_fifo_rd_data_count), // output wire [9 : 0] rd_data_count.prog_full(ai_fifo_prog_full) // output wire prog_full
);ddr3_2_pci_64x32_2048 ddr3_2_pci_64x16_8192 (.rst (!rst_n_i), // input wire rst.wr_clk(ddr3_clk_i), // input wire wr_clk.rd_clk(pci_clk_i), // input wire rd_clk.din (rd_fifo_data), // input wire [127 : 0] din.wr_en (rd_fifo_we), // input wire wr_en.rd_en (ai_pcie_fifo_rd), // input wire rd_en.dout (ai_pcie_fifo_data), // output wire [15: 0] dout.full (), // output wire full.almost_full( ), // output wire almost_full.empty( ), // output wire empty.rd_data_count(ai_pcie_fifo_rd_data_count), // output wire [12 : 0] rd_data_count.prog_full(ai_pcie_fifo_prom_full) // output wire prog_full
);
endmodule
axi_wr:
此为axi4的写时序模块,主要实现axi4的写时序。 主要将IP核输出的axi4写通道地址通道、写通道数据通道与写通道应答通道对应输入输出。
其中写突发触发信号设计的是当写fifo内部可读数据大于一次突发长度进入写地址等待状态((wr_fifo_rd_data_count+10'd2)>=wr_len );这里我在开始测试时写条件是当写fifo将满且ddr内部没满时进入写地址等待状态,但是由于进入到写数据循环状态还有三个状态,在这期间写fifo还在写入数据,这样最后读出的数据就不对。所以改为((wr_fifo_rd_data_count+10'd2)>=wr_len;感兴趣的读者可以试一下把将满信号(ai_fifo_prog_full)设置的小一点,只要保证fifo没有溢出数据,再接收到axi握手成功信号(ai_fifo_rd = M_AXI_WREADY & reg_wvalid) 后才能将数据正确读出并通过AXI4总线写入到DDR中。
代码注释较为详尽,状态机部分主要还是根据AXI4的读写时序图设计,具体可参考下图:主要关注AWADDR信号、ARVALID+ARREADY这一组握手信号;在每一次突发传输之前,先判断ARREADY信号,当该信号为高时,代表从机已经准备好接收新的地址信息,否则主机就不能发送地址信息给从机。
发送写数据时候主机必须在WREADY为高的时候,将WVALID信号拉高,同时将数据发送给从机,当主机发送最后一个数据时,将WLAST信号拉高一个周期,告诉从机这是最后一个数据,当从机收到WLAST信号为高时,就会将收到的数据按照指定的地址写入DDR。
当主机发送完写数据后的一个时钟周期,IP核会输出BVALID信号表示写响应有效,逻辑部分需要输出BREADY信号表明能够接收写响应。在实际代码中我直接将M_AXI_BREADY = M_AXI_BVALID,此时只需观察 Bresp信号有没有拉高。
时序部分主要是状态机控制,控制ARVALID信号的输出以及声明的一些寄存器变量,具体可查看代码注释。
AXI4的相关时序有空再写一下,网站上也有许多优秀的博主写了blog都可以参考。
突然想到还有一个关键的点没有说道:在对写地址的确定中为什么是加16(即wr_addr_reg <= wr_addr_reg + 16);首先要明确的一个点是AXI4总线只需要一个地址,最高可以突发传输256个字的数据。 每一个地址对于一个字节的数据,128位的数据位宽对于16字节,所以一组数据写入完成之后的地址增量=突发长度x16。
![](/assets/blank.gif)
`timescale 1ns / 1ps
module axi_wr
#(parameter DATA_WIDTH =128,parameter DDR_ADDR_LIMIT = 32'h0fff_ffff //2^10*2^15*2^3=2^28=268,435,456=32'h0fff_ffff
)
(input ARESETN , //axi复位input ACLK , //axi总时钟
//axi4写通道地址通道output [3:0] M_AXI_AWID , //写地址ID,用来标志一组写信号output [28:0] M_AXI_AWADDR , //写地址,给出一次写突发传输的写地址output [7:0] M_AXI_AWLEN , //突发长度,给出突发传输的次数 output [2:0] M_AXI_AWSIZE , //突发大小,给出每次突发传输的字节数output [1:0] M_AXI_AWBURST, //突发类型 output M_AXI_AWLOCK , //总线锁信号,可提供操作的原子性 output [3:0] M_AXI_AWCACHE, //内存类型,表明一次传输是怎样通过系统的 output [2:0] M_AXI_AWPROT , //保护类型,表明一次传输的特权级及安全等级 output [3:0] M_AXI_AWQOS , //质量服务QoS output M_AXI_AWVALID, //有效信号,表明此通道的地址控制信号有效input M_AXI_AWREADY, //表明“从”可以接收地址和对应的控制信号
//axi4写通道数据通道output [DATA_WIDTH-1 :0] M_AXI_WDATA , //写数据output [DATA_WIDTH/8-1:0] M_AXI_WSTRB , //写数据有效的字节线output M_AXI_WLAST , //表明此次传输是最后一个突发传输output M_AXI_WVALID , //写有效,表明此次写有效input M_AXI_WREADY , //表明从机可以接收写数据
//axi4写通道应答通道input [3:0] M_AXI_BID , //写响应ID TAGinput [1:0] M_AXI_BRESP , //写响应,表明写传输的状态input M_AXI_BVALID , //写响应有效output M_AXI_BREADY , //表明主机能够接收写响应//用户端信号input [9:0] wr_fifo_rd_data_count, //写突发触发信号input [7:0] wr_len , //写突发长度 input [DATA_WIDTH-1:0] wr_fifo_data , //连接到写fifo的读数据 input ai_fifo_prog_full, input ddr_cnt_full , output ai_fifo_rd //连接到写fifo的读使能
);localparam S_WR_IDLE = 3'd0;//写空闲
localparam S_WA_WAIT = 3'd1;//写地址等待
localparam S_WA_START = 3'd2;//写地址
localparam S_WD_WAIT = 3'd3;//写数据等待
localparam S_WD_PROC = 3'd4;//写数据循环
localparam S_WR_WAIT = 3'd5;//接受写应答
localparam S_WR_DONE = 3'd6;//写结束
localparam DATA_NUM = (DATA_WIDTH == 512) ? 6 : (DATA_WIDTH == 256) ? 5 : (DATA_WIDTH == 128) ? 4 :(DATA_WIDTH == 64) ? 3 : 2;
//reg define
reg [2:0] wr_state ; //状态寄存器
reg [28:0] reg_wr_adrs; //写地址寄存器
reg reg_awvalid; //地址有效握手信号
reg reg_wvalid ; //数据有效握手信号
reg reg_w_last ; //传输最后一个数据
reg [7:0] reg_w_len ; //突发长度128
reg [31:0] wr_addr_cnt; //写地址计数器
reg [31:0] wr_data_cnt; //写数据计数器
reg [31:0] wr_addr_reg; //写地址寄存器 //写fifo的读使能为axi握手成功 == M_AXI_WREADY + M_AXI_WVALID
assign ai_fifo_rd = M_AXI_WREADY & reg_wvalid
//只有一个主机,可随意设置
assign M_AXI_AWID = 4'b1111;
//把地址赋予总线
assign M_AXI_AWADDR = reg_wr_adrs ;
//一次突发传输1长度 (0 至 wr_len-1'd1)
assign M_AXI_AWLEN[7:0] = wr_len-'d1;
//表示AXI总线每个数据宽度是16字节,128位。 2^(4)=16byte
assign M_AXI_AWSIZE = DATA_NUM;
//01代表地址递增,10代表递减
assign M_AXI_AWBURST[1:0] = 2'b01; //突发类型递增,增量突发,后续数据的地址在初始地址的基础上进行递增,递增幅度与传输宽度相同。
assign M_AXI_AWLOCK = 1'b0;
assign M_AXI_AWCACHE[3:0] = 4'b0010;
assign M_AXI_AWPROT[2:0] = 3'b000;
assign M_AXI_AWQOS[3:0] = 4'b0000;
//地址握手信号AWVALID
assign M_AXI_AWVALID = reg_awvalid;
//写完成信号的写状态完成
assign wr_done = (wr_state == S_WR_DONE);
//fifo数据赋予总线
assign M_AXI_WDATA = wr_fifo_data;
assign M_AXI_WSTRB = 16'hFFFF; //写数据全部有效
//写到最后一个数据
//assign M_AXI_WLAST =(wr_addr_cnt == reg_w_len)? 'b1:'b0;
assign M_AXI_WLAST =reg_w_last;
//数据握手信号WVALID
assign M_AXI_WVALID = reg_wvalid;
//这个信号是告诉AXI我收到你的应答
assign M_AXI_BREADY = M_AXI_BVALID;//axi写过程状态机
always @(posedge ACLK ) begin if(!ARESETN) beginwr_state <= S_WR_IDLE;reg_wr_adrs <= 29'd0;reg_awvalid <= 1'b0; //地址reg_wvalid <= 1'b0; //数据reg_w_last <= 1'b0;reg_w_len <= 8'd0; wr_addr_cnt <= 32'd0;wr_data_cnt <= 32'd0;wr_addr_reg <= 32'd0;end else begincase(wr_state)S_WR_IDLE: begin //写空闲// if(ai_fifo_prog_full & !ddr_cnt_full) begin //写fifo将满且ddr内部没满时进入写地址等待状态if((wr_fifo_rd_data_count+10'd2)>=wr_len )begin//fifo数据长度大于一次突发长度wr_state <= S_WA_WAIT;reg_wr_adrs <= wr_addr_reg ;endreg_awvalid <= 1'b0;reg_wvalid <= 1'b0;reg_w_len <= 8'd0;endS_WA_WAIT :beginwr_state <= S_WA_START;endS_WA_START :begin //写地址开始拉高地址有效与数据有效wr_state <= S_WD_WAIT;//写数据等待一个时钟周期 reg_awvalid <= 1'b1; //拉高地址有效信号 endS_WD_WAIT :begin reg_wvalid <= 1'b1;//拉高数据有效信号 if(M_AXI_AWREADY) //等待AXI写地址就绪信号将对应地址发给从机 wr_state <= S_WD_PROC; reg_awvalid <= 1'b0; //ready有效后拉低valid信号reg_w_len <= wr_len-'d1; //127代表128个长度,0代表1个长度 endS_WD_PROC :begin if(M_AXI_WREADY)begin //等待写数据就绪if(wr_addr_cnt == reg_w_len)begin //突发写入完成reg_wvalid <= 1'b0; //写入完成后拉低数据有效信号;此信号告诉AXI总线我正在写数据有效 wr_state <= S_WR_WAIT;// reg_w_last <= 1'b1; //表示传输最后一个数据end else beginwr_addr_cnt <= wr_addr_cnt + 1'b1;endif(wr_addr_cnt == reg_w_len - 1)begin //突发写入完成reg_w_last <= 1'b1; //传输到最后一个数据时对应拉高end else beginreg_w_last <= 1'b0;endif(wr_addr_reg == DDR_ADDR_LIMIT)begin// reg_wr_adrs <= 29'd0;wr_addr_reg <= 32'd0;end else beginwr_addr_reg <= wr_addr_reg + 16;//一组数据写入完成之后的地址增量=突发长度x16,128位等于16字节//reg_wr_adrs <= reg_wr_adrs + 8;endend else begin//reg_wr_adrs <= reg_wr_adrs;wr_addr_reg <= wr_addr_reg;wr_addr_cnt <= wr_addr_cnt;endif(ai_fifo_rd)beginwr_data_cnt <= wr_data_cnt +1'b1;end else beginwr_data_cnt <= wr_data_cnt ;end endS_WR_WAIT :beginreg_w_last<='b0; //只持续一个时钟周期//M_AXI_BVALID拉高表示写成功,然后状态机完成一次突发传输if(M_AXI_BVALID) beginwr_state <= S_WR_DONE;endendS_WR_DONE :beginwr_state <= S_WR_IDLE;wr_addr_cnt<=32'd0;wr_data_cnt<=32'd0; enddefault: begin wr_state<= S_WR_IDLE;endendcaseend
end
endmodule
axi_rd:
此模块主要也是实现AXI4接口的读时序,先上时序图:
![](/assets/blank.gif)
读时序相对简单,重点也是关注读地址ARADDR与握手信号ARVALID+ARREADY。简单说一下就是当地址通道上ARVALID 和ARREADY 同时为高时,地址 A 被有效的传给设备,之后设备输出的数据将出现在读数据通道上。当RREADY 和 RVALID 同时为高的时候表明有效的数据传输。RLAST 信号表示最后一个被传输的数据。
`timescale 1ns / 1ps
module axi_rd
#(parameter DATA_WIDTH =128,parameter DDR_ADDR_LIMIT = 32'h0fff_ffff
)
(input ARESETN , //axi复位input ACLK , //axi总时钟
//axi4读通道地址通道output [3:0] M_AXI_ARID , //读地址ID,用来标志一组写信号output [28:0] M_AXI_ARADDR , //读地址,给出一次写突发传输的读地址output [7:0] M_AXI_ARLEN , //突发长度,给出突发传输的次数output [2:0] M_AXI_ARSIZE , //突发大小,给出每次突发传输的字节数output [1:0] M_AXI_ARBURST, //突发类型output M_AXI_ARLOCK , //总线锁信号,可提供操作的原子性output [3:0] M_AXI_ARCACHE, //内存类型,表明一次传输是怎样通过系统的output [2:0] M_AXI_ARPROT , //保护类型,表明一次传输的特权级及安全等级output [3:0] M_AXI_ARQOS , //质量服务QOSoutput M_AXI_ARVALID, //有效信号,表明此通道的地址控制信号有效input M_AXI_ARREADY, //表明“从”可以接收地址和对应的控制信号
//axi读通道读数据input [3:0] M_AXI_RID , //读ID taginput [DATA_WIDTH-1:0] M_AXI_RDATA , //读数据input [1:0] M_AXI_RRESP , //读响应,表明读传输的状态input M_AXI_RLAST , //表明读突发的最后一次传输input M_AXI_RVALID , //表明此通道信号有效output M_AXI_RREADY , //表明主机能够接收读数据和响应信息//用户端信号
// input rd_start , //读突发触发信号input [7:0] rd_len , //读突发长度
// input [31:0] rd_addr , //地址 output rd_fifo_we , //连接到读fifo的写使能output [DATA_WIDTH-1:0] rd_fifo_data , //连接到读fifo的写数据 output rd_done , //完成一次突发input [31:0] ddr_count,input ddr_prog_full,input ai_pcie_fifo_prom_full
);
localparam S_RD_IDLE = 3'd0; //读空闲
localparam S_RA_WAIT = 3'd1; //读地址等待
localparam S_RA_START = 3'd2; //读地址
localparam S_RD_WAIT = 3'd3; //读数据等待
localparam S_RD_PROC = 3'd4; //读数据循环
localparam S_RD_DONE = 3'd5; //写结束
localparam DATA_NUM = (DATA_WIDTH == 512) ? 6 : (DATA_WIDTH == 256) ? 5 : (DATA_WIDTH == 128) ? 4 :(DATA_WIDTH == 64) ? 3 : 2;
//reg define
reg [2:0] rd_state ; //状态寄存器
reg [28:0] reg_rd_adrs; //地址寄存器
reg reg_arvalid; //地址有效握手信号
reg [7:0] reg_rd_len ; //突发长度最大256,实测128最佳
reg [31:0] rd_addr_cnt; //读地址计数
reg [31:0] rd_data_cnt; //读数据计数
reg [31:0] rd_addr_reg; //读地址寄存器
//读fifo的写使能为axi准备好
assign rd_fifo_we = M_AXI_RVALID ; //ready + valid//只有一个主机,可随意设置
assign M_AXI_ARID = 4'b1111;
//把地址赋予总线
assign M_AXI_ARADDR = reg_rd_adrs ;
//一次突发传输1长度 (0 至 wr_len-1'd1)
assign M_AXI_ARLEN[7:0] = rd_len-'d1;
//表示AXI总线每个数据宽度是16字节,128位。 2^(4)=16byte
assign M_AXI_ARSIZE =DATA_NUM;
//01代表地址递增,10代表递减
assign M_AXI_ARBURST[1:0] = 2'b01;//地址递增方式传输
assign M_AXI_ARLOCK = 1'b0;
assign M_AXI_ARCACHE[3:0] = 4'b0011;
assign M_AXI_ARPROT[2:0] = 3'b000;
assign M_AXI_ARQOS[3:0] = 4'b0000;
//地址握手信号AWVALID
assign M_AXI_ARVALID = reg_arvalid;
//写完成信号的写状态完成
assign rd_done = (rd_state == S_RD_DONE);
//fifo数据赋予总线
assign rd_fifo_data = M_AXI_RDATA ;
//数据握手信号RREADY
assign M_AXI_RREADY = M_AXI_RVALID;//axi读过程状态机
always @(posedge ACLK ) beginif(!ARESETN) beginrd_state <= S_RD_IDLE;reg_rd_adrs <= 29'd0;rd_addr_cnt <= 32'd0;rd_data_cnt <= 32'd0;rd_addr_reg <= 32'd0;reg_arvalid <= 1'b0; //地址
// reg_rd_last <= 1'b0;reg_rd_len <= 8'd0; rd_addr_cnt <=32'd0;rd_data_cnt <=32'd0;rd_addr_reg <=32'd0;end else begincase(rd_state)S_RD_IDLE: begin //写空闲//if(rd_start)if( ddr_prog_full & !ai_pcie_fifo_prom_full) begin // ddr内部达到1024且读FIFO没满时rd_state <= S_RA_WAIT;reg_rd_adrs<= rd_addr_reg ;endreg_arvalid <= 1'b0;reg_rd_len <= 8'd0;endS_RA_WAIT :beginrd_state <= S_RA_START;endS_RA_START :begin //读地址 rd_state <= S_RD_WAIT; //读数据等待一个时钟周期 reg_arvalid <= 1'b1; //拉高地址有效信号 endS_RD_WAIT :begin if(M_AXI_ARREADY) //等待AXI写地址就绪信号将对应地址发给从机 rd_state <= S_RD_PROC; reg_arvalid <= 1'b0; //arready有效后拉低arvalid信号,结束写地址,进入到读取数据状态reg_rd_len <= rd_len-'d1; //127代表128个长度,0代表1个长度 endS_RD_PROC :begin if(M_AXI_RVALID & M_AXI_RLAST)begin //等待数据有效(M_AXI_RVALID)将对应数据发给从机 rd_state <= S_RD_DONE;end if(M_AXI_RVALID)beginif(rd_addr_reg == DDR_ADDR_LIMIT)begin// reg_rd_adrs <= 29'd0;rd_addr_reg <= 32'd0;end else begin// reg_rd_adrs <= reg_rd_adrs + 8;rd_addr_reg <= rd_addr_reg + 16;end if(rd_addr_cnt == reg_rd_len)beginrd_addr_cnt<= 32'd0;end else beginrd_addr_cnt<= rd_addr_cnt + 1'b1;// 地址每次+1 endend else begin// reg_rd_adrs <= reg_rd_adrs ; rd_addr_reg <= rd_addr_reg;rd_addr_cnt <= rd_addr_cnt;end if(M_AXI_RVALID)beginrd_data_cnt <= rd_data_cnt + 1'b1;end else beginrd_data_cnt <= rd_data_cnt;endend S_RD_DONE :beginrd_state <= S_RD_IDLE;enddefault: begin rd_state <= S_RD_IDLE;endendcaseend
end
endmodule
上板验证结果分析
图1为axi写模块写触发条件设置为if(ai_fifo_prog_full & !ddr_cnt_full) 时抓取的从写fifo读出的数据,可以看出数据有误。
![](/assets/blank.gif)
图1
图2为抓取的写时序的封面图,可以看出在 axi握手成功后即ai_fifo_rd拉高后写fifo数据连续读出并通过axi总线写进ddr。当时忘记截取写入与读出的数据对比图了,但是大概就是这个样子,最后只要写入与读出的自加数一致则实验成功。
只有后续有机会再继续补充验证结果图了。
![](/assets/blank.gif)
图2
欢迎大家一起交流,文中如有错误地方还请指出,大家一起讨论。另外本文逻辑代码有参考《升腾Pro《FPGA Verilog开发实战指南——基于Xilinx Artix7》,感谢观看!
源码我已上传我的主页,可以直接下载。
DDR3 AXI4 IP核读写仿真实验(2)相关推荐
- Xilinx DDR3 —— MIG IP核的读写仿真(APP接口)
在上一篇中Xilinx DDR3 -- MIG IP核的配置(APP接口),已经观看了Xilinx官方提供的MIG IP核读写例程仿真波形,本着学习的目的,本篇开始自己编写MIG IP核读写程序,用于 ...
- qq自定义diy名片代码复制_「正点原子FPGA连载」第六章自定义IP核-呼吸灯实验
1)摘自[正点原子]领航者 ZYNQ 之嵌入式开发指南 2)实验平台:正点原子领航者ZYNQ开发板 3)平台购买地址:https://item.taobao.com/item.htm?&id= ...
- 异步fifo_正点原子开拓者FPGA开发板资料连载第十五章 IP核之FIFO实验
1)实验平台:正点原子开拓者FPGA 开发板 2)摘自<开拓者FPGA开发指南>关注官方微信号公众号,获取更多资料:正点原子 3)全套实验源码+手册+视频下载地址:http://www.o ...
- 【正点原子FPGA连载】第十五章 IP核之FIFO实验 -摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0
1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...
- 【正点原子MP157连载】 第十四章 IP核之RAM实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7
1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...
- 【正点原子FPGA连载】第十四章 IP核之RAM实验 -摘自【正点原子】领航者ZYNQ之FPGA开发指南_V2.0
1)实验平台:正点原子领航者ZYNQ开发板 2)平台购买地址:https://item.taobao.com/item.htm?&id=606160108761 3)全套实验源码+手册+视频下 ...
- FPGA中DDR3 MIG ip核使用说明
此篇是我在学习中做的归纳与总结,其中如果存在版权或知识错误请直接联系我,欢迎留言. PS:本着知识共享的原则,此篇博客可以随意转载,但请标明出处! 目录 1.DDR3工作原理 简介: DDR基础操作步 ...
- 基于K7-325T的DDR3读写仿真实验
1. IP核设置注意事项 ⭐时钟选500MHz-即DQS频率为500MHz. ⭐Phy to controller clock ratio选择4:1-此处4代表的是DQS时钟,1代表逻辑收发时钟,此处 ...
- IP 核之RAM实验
目录: 1.IP核 RAM简介 2.实验1: 配置单端口 RAM 1)实验任务 2)创建工程并添加ram ip 3)编写ram_rw.v 4)编写顶层文件 5)编写激励文件 6)仿真测试 7)ILA测 ...
最新文章
- OpenCV 笔记(06)— Mat 结构、像素值存储方法、创建 Mat 对象各种方法、Mat 对象的运算
- php的封装继承多态,PHP面向对象深入理解之二(封装、继承、多态、克隆)
- 深入学习SAP UI5框架代码系列之三:HTML原生事件 VS UI5 Semantic事件
- 标准错误处理机制——error
- 【记录】jenkins 安装及环境配置(一)
- Drools 7.11 :入门程序
- SSH Mybatis 框架
- android 重新点击图标显示不出来了,android开发怎么弄成,点击图标后弹出一个消息框。主界面不显示...
- Normalize.css的使用及下载
- Linux字符设备驱动详解
- 非平衡电桥电阻计算_详解用非平衡电桥如何测量电阻
- android 程序控制开关飞行模式,android开关飞行模式的方法
- OSChina 周一乱弹 ——东京12G
- 李宏毅2022机器学习HW4解析
- 【科研记录】如何判断(你自己的)研究工作的价值
- 08-HTML5详解(二)
- 发现美,创造美,拥有美^_^.
- 类似京东淘宝历史搜索自适应长度搜索项超两行折叠功能实现
- CleanMyMac X真正好用的Mac电脑系统优化软件应用工具
- 【渝粤教育】电大中专Office办公软件 (14)作业 题库
热门文章
- java开发中Bean的Builder模式简析
- nessus的安装以及使用(带详细步骤)
- 关于计算机的一些的总结
- 线性SVM,线性可分SVM与核函数
- alv布局 sap_ABAP报表开发:ALV运用
- dp交换机命令_华为交换机配置命令解释
- 漫谈软件工程(1)——回顾十年软件开发经历
- python安装错80072ee2_更新80072EE2错误怎么办_win7报80072ee2原因是什么
- rrd.so更新导致rrd_fetch返回值变更,与旧版不兼容
- android gson解析封装,android之Gson解析json的封装