Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(一)

 Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(前导)

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(二)

Zynq—AD9238数据采集DDR3缓存千兆以太网发送实验(三)


  四、AXI转FIFO接口模块设计

1.AXI接口知识

AXI协议是基于 burst的传输,并且定义了以下 5 个独立的传输通道:

  • 读地址通道(Read Address Channel, AR)
  • 读数据通道(Read Data Channel, R)
  • 写地址通道(Write Address Channel, AW)
  • 写数据通道(Write Data Channel, W)
  • 写响应通道(Write Response Channel, B)

  • 这 5 条独立的通道都包含一个双路的 VALD、 READY 握手机制。信息源通过 VALID 信号来指示通道中的数据和控制信息什么时候有效。目地源用READY 信号来表示何时准备好接收数据。传输地址信息和数据都是在 VALID和 READY 同时为高时有效。
  • 读数据和写数据通道都包括一个 LAST 信号,用来指明一个事物传输的最后一个数据
  • 读/写事务都有自己的地址通道,地址通道携带着传输事务所必需的地址和控制信息
  • 读数据通道传送着从设备到主机的读数据和读响应信息。读响应信息指明读事务的完成状态
  • 写数据通路传送着主机向从设备的写数据。写响应通道提供了设备响应写事务的一种方式。在每一次突发式写会产生一个完成信号

写事务时序

读事务时序

AXI 协议支持乱序传输。每一个通过接口的事务有一个 IDtag。协议要求相同 ID tag 的事务必须有序完成,而不同 ID tag 可以乱序完成


1.1写地址通道信号

1.2写数据通道信号

1.3写响应通道信号

1.4读地址通道信号

1.5读数据通道信号

2.ZynqAXI接口

红绿蓝三种颜色的箭头代表了几种不同位宽的 AXI 总线。 红色线条框是 PL 端访问 DDR控制器的路径,其中, High Performamce AXI 32/64b Slave Ports 便是我们所说的HP 接口, 该接口为 AXI 接口,通常用于大量数据的高速传输。

PS 端通过硬件电路实现 AXI 总线,而 PL 端则需要用户通过逻辑资源搭建 AXI 总线

3.AXI转换模块设计(fifo_axi4_adapter)

目的:为了解决上下游模块常常处于不同时钟域的问题。

fifo_axi4_adapter 负责FIFO接口到AXI4接口的转换,FIFO中的数据可以通过该模块写入PS端,PS端的数据也可以由该模块接收写入FIFO。通过这种方式,用户只需要操作FIFO,就能实现PL端数据对PS端DDR的读写。

wr_ddr3_fifo rd_ddr3_fifo 为上文中我们提到的读写 FIFO,用于存储读写数据,同时解决时钟域等问题。fifo2axi4 为 AXI4 接口转换模块,负责fifo 与 axi4 接口间的转换, 将写侧 FIFO 里的数据读出然后存储在 DDR 存储器以及将 DDR 存储器读出的数据存放到读侧 FIFO 缓存。

3.1接口转换模块设计(fifo2axi4)

写流程:主机向写地址通道写入地址和控制信息→写数据通道突发写入数据→收到设备的写数据响应。

读流程:主机向读地址通道写入地址和控制信息→ 收到设备的读数据响应和读的数据。

根据时序进行状态机设计:

//写信号状态机
always@(posedge clk or posedge reset)
begin
    if(reset)
        curr_wr_state <= S_IDLE;
    else
        curr_wr_state <= next_wr_state;
    end

always@(*)
begin
    case(curr_wr_state)
        S_IDLE:
        begin
            if(wr_ddr3_req == 1'b1)
                next_wr_state = S_WR_ADDR;
            else
                next_wr_state = S_IDLE;
        end
        S_WR_ADDR:
        begin
            if(m_axi_awready && m_axi_awvalid)
                next_wr_state = S_WR_DATA;
            else
                next_wr_state = S_WR_ADDR;
        end
        S_WR_DATA:
        begin
            if(m_axi_wready && m_axi_wvalid && m_axi_wlast)
                next_wr_state = S_WR_RESP;
            else
                next_wr_state = S_WR_DATA;
        end
        S_WR_RESP:
        begin
            if(m_axi_bready && m_axi_bvalid && (m_axi_bresp == 2'b00) &&(m_axi_bid == AXI_ID[AXI_ID_WIDTH-1:0]))
                next_wr_state = S_IDLE;
            else
                next_wr_state = S_WR_RESP;
        end


    endcase
end




//awaddr信号
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
    else if(wr_addr_clr || axi_awaddr_clr)
        m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
    else if(m_axi_awaddr >= WR_AXI_BYTE_ADDR_END)
        m_axi_awaddr <= WR_AXI_BYTE_ADDR_BEGIN;
    else if((curr_wr_state == S_WR_RESP) && m_axi_bready && m_axi_bvalid && (m_axi_bresp == 2'b00) && (m_axi_bid == AXI_ID[AXI_ID_WIDTH-1:0]))
        //每次地址增加量应该是突发写数据个数*每个数据的字节数
        m_axi_awaddr <= m_axi_awaddr + ((m_axi_awlen + 1'b1)*(AXI_DATA_WIDTH/8));
    else
        m_axi_awaddr <= m_axi_awaddr;
end


//awvalid信号
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_awvalid <= 1'b0;
    else if((curr_wr_state == S_WR_ADDR) && m_axi_awready && m_axi_awvalid)
        m_axi_awvalid <= 1'b0;
    else if(curr_wr_state == S_WR_ADDR)
        m_axi_awvalid <= 1'b1;
    else
        m_axi_awvalid <= m_axi_awvalid;
end

//wvalid信号
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_wvalid <= 1'b0;
    else if((curr_wr_state == S_WR_DATA) && m_axi_wready && m_axi_wvalid && m_axi_wlast)
m_axi_wvalid <= 1'b0;
    else if(curr_wr_state == S_WR_DATA)
        m_axi_wvalid <= 1'b1;
    else
        m_axi_wvalid <= m_axi_wvalid;
end

//传输计数
always@(posedge clk or posedge reset)
begin
    if(reset)
        wr_data_cnt <= 1'b0;
    else if(curr_wr_state == S_IDLE)
        wr_data_cnt <= 1'b0;
    else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid)
        wr_data_cnt <= wr_data_cnt + 1'b1;
    else
        wr_data_cnt <= wr_data_cnt;
end

//wlast信号:
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_wlast <= 1'b0;
    else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid && m_axi_wlast)
        m_axi_wlast <= 1'b0;
    else if(curr_wr_state == S_WR_DATA && m_axi_awlen == 8'd0)
        //数据个数为1
        m_axi_wlast <= 1'b1;
    else if(curr_wr_state == S_WR_DATA && m_axi_wready && m_axi_wvalid && (wr_data_cnt == m_axi_awlen -1'b1))
        //传输完倒数第二个数
        m_axi_wlast <= 1'b1;
    else
        m_axi_wlast <= m_axi_wlast;
end

根据时序进行状态机设计:

//读状态机
always@(posedge clk or posedge reset)
begin
    if(reset)
        curr_rd_state <= S_IDLE;
    else
        curr_rd_state <= next_rd_state;
end
always@(*)
begin
    case(curr_rd_state)
        S_IDLE:
        begin
            if(rd_ddr3_req == 1'b1)
                next_rd_state = S_RD_ADDR;
            else
                next_rd_state = S_IDLE;
        end
        S_RD_ADDR:
        begin
            if(m_axi_arready && m_axi_arvalid)
                next_rd_state = S_RD_RESP;
            else
                next_rd_state = S_RD_ADDR;
        end
        S_RD_RESP:
        begin
            if(m_axi_rready && m_axi_rvalid && m_axi_rlast && (m_axi_rresp == 2'b00)&& (m_axi_rid == AXI_ID[AXI_ID_WIDTH-1:0]))
                next_rd_state = S_IDLE;
            else
                next_rd_state = S_RD_RESP;
        end
    endcase
end

//araddr
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
    else if(rd_addr_clr || axi_araddr_clr)
        m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
    else if(m_axi_araddr >= RD_AXI_BYTE_ADDR_END)
        m_axi_araddr <= RD_AXI_BYTE_ADDR_BEGIN;
    else if((curr_rd_state == S_RD_RESP) && m_axi_rready && m_axi_rvalid && m_axi_rlast && (m_axi_rresp == 2'b00) && (m_axi_rid == AXI_ID[AXI_ID_WIDTH-1:0]))
        m_axi_araddr <= m_axi_araddr + ((m_axi_arlen + 1'b1)*(AXI_DATA_WIDTH/8));
    else
        m_axi_araddr <= m_axi_araddr;
end

//m_axi_arvalid
always@(posedge clk or posedge reset)
begin
    if(reset)
        m_axi_arvalid <= 1'b0;
    else if((curr_rd_state == S_RD_ADDR) && m_axi_arready && m_axi_arvalid)
        m_axi_arvalid <= 1'b0;
    else if(curr_rd_state == S_RD_ADDR)
        m_axi_arvalid <= 1'b1;
    else
    m_axi_arvalid <= m_axi_arvalid;
end

其他信号定义:

assign m_axi_awid = AXI_ID[AXI_ID_WIDTH-1:0];
assign m_axi_awsize = DATA_SIZE;
assign m_axi_awburst = 2'b01;
assign m_axi_awlock = 1'b0;
assign m_axi_awcache = 4'b0000;
assign m_axi_awprot = 3'b000;
assign m_axi_awqos = 4'b0000;
assign m_axi_awregion= 4'b0000;
assign m_axi_awlen = AXI_BURST_LEN[7:0];
assign m_axi_wstrb = 16'hffff;
assign m_axi_wdata = wr_fifo_rddata;
assign m_axi_bready = 1'b1;
assign m_axi_arid = AXI_ID[AXI_ID_WIDTH-1:0];
assign m_axi_arsize = DATA_SIZE;
assign m_axi_arburst = 2'b01;
assign m_axi_arlock = 1'b0;
assign m_axi_arcache = 4'b0000;
assign m_axi_arprot = 3'b000;
assign m_axi_arqos = 4'b0000;
assign m_axi_arregion= 4'b0000;
assign m_axi_arlen = AXI_BURST_LEN[7:0];
assign m_axi_rready = ~rd_fifo_alfull;

assign wr_fifo_rdreq = (~axi_awaddr_clr) && m_axi_wvalid && m_axi_wready;
assign rd_fifo_wrreq = (~axi_araddr_clr) && m_axi_rvalid && m_axi_rready;
assign rd_fifo_wrdata = m_axi_rdata;

assign wr_req_cnt_thresh = (m_axi_awlen == 'd0)? 1'b1 : (AXI_BURST_LEN[7:0]+1'b1-2'd2);//计数比实际数量少 2
assign rd_req_cnt_thresh = AXI_BURST_LEN[7:0];
assign wr_ddr3_req = (wr_fifo_rst_busy == 1'b0) && (wr_fifo_rd_cnt >= wr_req_cnt_thresh) ? 1'b1:1'b0;
assign rd_ddr3_req = (rd_fifo_rst_busy == 1'b0) && (rd_fifo_wr_cnt <= rd_req_cnt_thresh) ? 1'b1:1'b0;

3.2FIFO IP创建(wr_ddr3_fifo、rd_ddr3_fifo)

wr_ddr3_fifo: 

设置写FIFO接口类型,写入和读出的时钟不一致, 所以这里需要创建一个独立时钟 FIFO。

设置写FIFO端口

rd_ddr3_fifo:

设置读FIFO接口类型,写入和读出的时钟不一致, 所以这里需要创建一个独立时钟 FIFO。

设置读 FIFO 端口

设置读FIFO数据计数

 3.3 封装接口转换模块

module fifo_axi4_adapter #(
    parameter FIFO_DW = 16 ,
    parameter WR_AXI_BYTE_ADDR_BEGIN = 0 ,
    parameter WR_AXI_BYTE_ADDR_END = 1023 ,
    parameter RD_AXI_BYTE_ADDR_BEGIN = 0 ,
    parameter RD_AXI_BYTE_ADDR_END = 1023 ,
    parameter AXI_DATA_WIDTH = 128 ,
    parameter AXI_ADDR_WIDTH = 29 ,
    parameter AXI_ID_WIDTH = 4 ,
    parameter AXI_ID = 4'b0000,
    parameter AXI_BURST_LEN = 8'd31 //burst length = 32
) 
(
// clock reset
input                     clk ,
input                     reset ,

// wr_fifo wr Interface
input                     wrfifo_clr ,
input                     wrfifo_clk ,
input                     wrfifo_wren ,
input [FIFO_DW-1:0]       wrfifo_din ,
output                    wrfifo_full ,
output [15:0]             wrfifo_wr_cnt ,

// rd_fifo rd Interface
input                     rdfifo_clr ,
input                     rdfifo_clk ,
input                     rdfifo_rden ,
output [FIFO_DW-1:0]      rdfifo_dout ,
output                    rdfifo_empty ,
output [15:0]             rdfifo_rd_cnt ,

// Master Interface Write Address Ports
output [AXI_ID_WIDTH-1:0]        m_axi_awid ,
output [AXI_ADDR_WIDTH-1:0]      m_axi_awaddr ,
output [7:0]                     m_axi_awlen ,
output [2:0]                     m_axi_awsize ,
output [1:0]                     m_axi_awburst ,
output [0:0]                     m_axi_awlock ,
output [3:0]                     m_axi_awcache ,
output [2:0]                     m_axi_awprot ,
output [3:0]                     m_axi_awqos ,
output [3:0]                     m_axi_awregion,
output                           m_axi_awvalid ,
input                            m_axi_awready ,

// Master Interface Write Data Ports
output [AXI_DATA_WIDTH-1:0]           m_axi_wdata ,
output [AXI_DATA_WIDTH/8-1:0]         m_axi_wstrb ,
output                                m_axi_wlast ,
output                                m_axi_wvalid ,
input                                 m_axi_wready ,

// Master Interface Write Response Ports
input [AXI_ID_WIDTH-1:0]            m_axi_bid ,
input [1:0]                         m_axi_bresp ,
input                               m_axi_bvalid ,
output                              m_axi_bready ,

// Master Interface Read Address Ports
output [AXI_ID_WIDTH-1:0]            m_axi_arid ,
output [AXI_ADDR_WIDTH-1:0]          m_axi_araddr ,
output [7:0]                         m_axi_arlen ,
output [2:0]                         m_axi_arsize ,
output [1:0]                         m_axi_arburst ,
output [0:0]                         m_axi_arlock ,
output [3:0]                         m_axi_arcache ,
output [2:0]                         m_axi_arprot ,
output [3:0]                         m_axi_arqos ,
output [3:0]                         m_axi_arregion,
output                               m_axi_arvalid ,
input                                m_axi_arready ,

// Master Interface Read Data Ports
input [AXI_ID_WIDTH-1:0]              m_axi_rid ,
input [AXI_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
);

wire                                 wrfifo_rden;
wire [AXI_DATA_WIDTH-1:0]            wrfifo_dout;
wire [5 : 0]                         wrfifo_rd_cnt;
wire                                 wrfifo_empty;
wire                                 wrfifo_wr_rst_busy;
wire                                 wrfifo_rd_rst_busy;
wire                                 rdfifo_wren;
wire [AXI_DATA_WIDTH-1:0]            rdfifo_din;
wire [5 : 0]                         rdfifo_wr_cnt;
wire                                 rdfifo_full;
wire                                 rdfifo_wr_rst_busy;
wire                                 rdfifo_rd_rst_busy;
reg                                  wrfifo_clr_sync_clk;
reg                                  wr_addr_clr;
reg                                  rdfifo_clr_sync_clk;
reg                                  rd_addr_clr;

wr_ddr3_fifo wr_ddr3_fifo
(
    .rst (wrfifo_clr ),
    .wr_clk (wrfifo_clk ),
    .rd_clk (clk ),
    .din (wrfifo_din ),
    .wr_en (wrfifo_wren ),
    .rd_en (wrfifo_rden ),
    .dout (wrfifo_dout ),
    .full (wrfifo_full ),
    .empty (wrfifo_empty ),
    .rd_data_count (wrfifo_rd_cnt ),
    .wr_data_count (wrfifo_wr_cnt ),
    .wr_rst_busy (wrfifo_wr_rst_busy ),
    .rd_rst_busy (wrfifo_rd_rst_busy )
);

rd_ddr3_fifo rd_ddr3_fifo
(
    .rst (rdfifo_clr ),
    .wr_clk (clk ),
    .rd_clk (rdfifo_clk ),
    .din (rdfifo_din ),
    .wr_en (rdfifo_wren ),
    .rd_en (rdfifo_rden ),
    .dout (rdfifo_dout ),
    .full (rdfifo_full ),
    .empty (rdfifo_empty ),
    .rd_data_count (rdfifo_rd_cnt ),
    .wr_data_count (rdfifo_wr_cnt ),
    .wr_rst_busy (rdfifo_wr_rst_busy ),
    .rd_rst_busy (rdfifo_rd_rst_busy )
);

always@(posedge clk)
begin
    wrfifo_clr_sync_clk <= wrfifo_clr;
    wr_addr_clr <= wrfifo_clr_sync_clk;
end

always@(posedge clk)
begin
    rdfifo_clr_sync_clk <= rdfifo_clr;
    rd_addr_clr <= rdfifo_clr_sync_clk;
end

fifo2axi4
#(
    .WR_AXI_BYTE_ADDR_BEGIN (WR_AXI_BYTE_ADDR_BEGIN ),
    .WR_AXI_BYTE_ADDR_END (WR_AXI_BYTE_ADDR_END ),
    .RD_AXI_BYTE_ADDR_BEGIN (RD_AXI_BYTE_ADDR_BEGIN ),
    .RD_AXI_BYTE_ADDR_END (RD_AXI_BYTE_ADDR_END ),
    .AXI_DATA_WIDTH (AXI_DATA_WIDTH ),
    .AXI_ADDR_WIDTH (AXI_ADDR_WIDTH ),
    .AXI_ID_WIDTH (AXI_ID_WIDTH ),
    .AXI_ID (AXI_ID ),
    .AXI_BURST_LEN (AXI_BURST_LEN )//burst length = 32
)fifo2axi4_inst
(
//clock reset
    .clk (clk ),
    .reset (reset ),

//FIFO Interface ports
    .wr_addr_clr (wr_addr_clr ), //1:clear, sync clk
    .wr_fifo_rdreq (wrfifo_rden ),
    .wr_fifo_rddata (wrfifo_dout ),
    .wr_fifo_empty (wrfifo_empty ),
    .wr_fifo_rd_cnt (wrfifo_rd_cnt ),
    .wr_fifo_rst_busy (wrfifo_rd_rst_busy ),
    .rd_addr_clr (rd_addr_clr ), //1:clear, sync clk
    .rd_fifo_wrreq (rdfifo_wren ),
    .rd_fifo_wrdata (rdfifo_din ),
    .rd_fifo_alfull (rdfifo_full ),
    .rd_fifo_wr_cnt (rdfifo_wr_cnt ),
    .rd_fifo_rst_busy (rdfifo_wr_rst_busy ),

// Slave Interface Write Address Ports
    .m_axi_awid (m_axi_awid ),
    .m_axi_awaddr (m_axi_awaddr ),
    .m_axi_awlen (m_axi_awlen ),
    .m_axi_awsize (m_axi_awsize ),
    .m_axi_awburst (m_axi_awburst ),
    .m_axi_awlock (m_axi_awlock ),
    .m_axi_awcache (m_axi_awcache ),
    .m_axi_awprot (m_axi_awprot ),
    .m_axi_awqos (m_axi_awqos ),
    .m_axi_awregion (m_axi_awregion ),
    .m_axi_awvalid (m_axi_awvalid ),
    .m_axi_awready (m_axi_awready ),

// Slave Interface Write Data Ports
    .m_axi_wdata (m_axi_wdata ),
    .m_axi_wstrb (m_axi_wstrb ),
    .m_axi_wlast (m_axi_wlast ),
    .m_axi_wvalid (m_axi_wvalid ),
    .m_axi_wready (m_axi_wready ),

// Slave Interface Write Response Ports
    .m_axi_bid (m_axi_bid ),
    .m_axi_bresp (m_axi_bresp ),
    .m_axi_bvalid (m_axi_bvalid ),
    .m_axi_bready (m_axi_bready ),

// Slave Interface Read Address Ports
    .m_axi_arid (m_axi_arid ),
    .m_axi_araddr (m_axi_araddr ),
    .m_axi_arlen (m_axi_arlen ),
    .m_axi_arsize (m_axi_arsize ),
    .m_axi_arburst (m_axi_arburst ),
    .m_axi_arlock (m_axi_arlock ),
    .m_axi_arcache (m_axi_arcache ),
    .m_axi_arprot (m_axi_arprot ),
    .m_axi_arqos (m_axi_arqos ),
    .m_axi_arregion (m_axi_arregion ),
    .m_axi_arvalid (m_axi_arvalid ),
    .m_axi_arready (m_axi_arready ),

// Slave Interface Read Data Ports
    .m_axi_rid (m_axi_rid ),
    .m_axi_rdata (m_axi_rdata ),
    .m_axi_rresp (m_axi_rresp ),
    .m_axi_rlast (m_axi_rlast ),
    .m_axi_rvalid (m_axi_rvalid ),
    .m_axi_rready (m_axi_rready )
);
endmodule

4.AXI 接口转换模块仿真

1.仿真设计结构

2.DDR控制器(MIG IP)创建

1、配置MIG IP

DDR3存储器驱动的时钟周期(Clock Period)设置为2500ps(即400MHz),这个时钟是用于 FPGA 输出给到 DDR 存储器时钟管脚的时钟。注意这里根据实际情况是有设置区间范围的,并非可以设置任意值,这里的区间范围为 2500~3300ps(即 300~400MHz)。


TMD(Time DivisionMultiplexing),该设置读写优先级相同,读写交替进行。



仿真选New Design,上板测试选Fixed Pin Out。


在 Vivado 的 Source 窗口中,出现了新配置生成的 IP 核文件mig_7series_0(mig_7series_0.xci)。

在上面窗口的 IP Sources 一栏,可以找到 IP 例化模板文件(mig_7series_0.veo)。

3.产生时钟和复位、数据产生和数据读取的激励

DDR控制器时钟200MHz(T=5ns,每2.5ns翻转一次)

wr_ddr3_fifo、rd_ddr3_fifo时钟100MHz(T=10ns,每5ns翻转一次)

fifo_axi4_adapter模块时钟使用DDR控制器输出的供用户侧使用的ui_clk。

仿真的时间单位1ns,精度100ps。具体可以看一下Verilog(未完待续)里面的编译指令timescale部分。每2.5ns翻转一次,它的最低精度就是0.1ns=100ps,时间单位就是1ns。

`timescale 1ns/100ps
initial sys_clk_i = 1'b1;
always #2.5 sys_clk_i = ~sys_clk_i;
initial wrfifo_clk = 1'b1;
always #2.5 wrfifo_clk = ~wrfifo_clk;
initial rdfifo_clk = 1'b1;
always #2.5 rdfifo_clk = ~rdfifo_clk;

数据产生和读取的激励设计上将其封装成任务 task 形式,方便调用。

//向 wr_ddr3_fifo 中写入以起始数据 data_begin 开始递增的wr_data_cnt 个数据。
task wr_data;
input [15:0]data_begin;
input [15:0]wr_data_cnt;
begin
    wrfifo_wren = 1'b0;
    wrfifo_din = data_begin;
    @(posedge wrfifo_clk);
    #1 wrfifo_wren = 1'b1;
    repeat(wr_data_cnt)
    begin
        @(posedge wrfifo_clk);
        wrfifo_din = wrfifo_din + 1'b1;
    end
    #1 wrfifo_wren = 1'b0;
end
endtask



//向 rd_ddr3_fifo 中读出个 rd_data_cnt 数据
task rd_data;
input [15:0]data_begin;
input [15:0]rd_data_cnt;
begin
    rdfifo_rden = 1'b0;
    expect_rd_data = data_begin;
    @(posedge rdfifo_clk);
    #1 rdfifo_rden = 1'b1;
    repeat(rd_data_cnt)
    begin
        @(posedge rdfifo_clk);
        if(rdfifo_dout != expect_rd_data)
        begin
            $display("SIM is failed");
            $finish;
        end
        expect_rd_data = expect_rd_data + 1'b1;
    end
    #1 rdfifo_rden = 1'b0;
end
endtask

/*
先产生 DDR 控制器的复位以及 FIFO 的复位。
等 DDR 控制器内部锁相环锁定后,延时 200ns 后对 FIFO 解复位。
等待 DDR 初始化校准完成后,延时 200n 往 wr_ddr3_fifo 写入 1024 个数据,
数据写完后,对rd_ddr3_fifo 进行复位,清空里面的缓存,
等 FIFO 复位结束一段时间后,等待rd_ddr3_fifo 非空后开始对 rd_ddr3_fifo 进行读取数据,
读取 1024 个数据。整个仿真结束后打印“SIM is successfully”信息
*/


initial begin
    sys_rst = 1'b0;
    aresetn = 1'b0;
    expect_rd_data = 16'd0;
    wrfifo_clr = 1'b1;
    wrfifo_wren = 1'b0;
    wrfifo_din = 16'd0;
    rdfifo_clr = 1'b1;
    rdfifo_rden = 1'b0;
    #201;
    sys_rst = 1'b1;
    aresetn = 1'b1;
    @(posedge mmcm_locked);
    #200;
    wrfifo_clr = 1'b0;
    rdfifo_clr = 1'b0;
    @(posedge init_calib_complete);
    #200;
    wr_data(SIM_DATA_BEGIN,SIM_DATA_CNT);
    #2000;
    rdfifo_clr = 1'b1;
    #20;
    rdfifo_clr = 1'b0;
    #2000;
    wait(rdfifo_empty == 1'b0)
    rd_data(SIM_DATA_BEGIN,SIM_DATA_CNT);
    #5000;
    $display("SIM is successfully");
    $stop;
end

4.运行仿真

  • 21
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
Fanuc CNC数据采集是指通过Fanuc数控机床系统进行数据采集的过程。Fanuc数控机床系统是一种高精度、高效率的数控机床系统,并且具有丰富的功能和灵活的操作界面。 在Fanuc CNC数据采集过程中,首先需要将数据采集设备与Fanuc数控机床系统进行连接。这些数据采集设备可以是传感器、监控设备或者其他类型的数据采集设备。通过与Fanuc数控机床系统的连接,可以实现实时数据的采集和传输。 接下来,在Fanuc CNC数据采集过程中,需要设定数据采集的参数和条件。根据具体的应用需求,可以设定需要采集的数据类型,如温度、压力、速度等,以及采集的时间间隔和采集的持续时间等。 开始数据采集后,Fanuc CNC系统会根据设定的参数和条件自动进行数据的采集。采集的数据会被传输到数据采集设备的存储器中,以便后续的数据处理和分析。 在Fanuc CNC数据采集过程中,还可以进行实时监控和数据处理。通过连接的监控设备,可以实时监测和显示采集的数据,以便对机床运行状态进行实时监控和调整。 最后,在Fanuc CNC数据采集过程中,采集到的数据可以用于进行数据分析和优化。通过对采集的数据进行分析,可以了解机床运行状态、故障诊断和性能优化等。 总的来说,Fanuc CNC数据采集是一个重要的过程,通过采集和处理数据,可以实现对数控机床系统的监控和优化,提高机床的运行效率和生产质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chinalihuanyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值