Post Go back to editing

Functionality of AXI_ADCFIFO and AXI_DACFIFO with MIG Controller

Category: Hardware
Product Number: ADRV9008-1W + ZCU102
Software Version: 2021_r1

Hello   and Team ,

I am using ADI product ADRV9008-1W with ZCU102 and 2021_r1 HDL design. According to our need the design is modified in such a way that AXI_ADCFIFO and MIG controller is added so that DMA can have continous RF data from the RF frontend. Now, as the design advances we need to extract the saved data in a repetitive manner from DDR4 through MIG controller and direct to one of our IP core. The custom IP core will control when the frame ends and after that should start again from starting base address.For this purpose modified AXI_DACFIFIO is desgined, where only *_rd.v is used. Smartconnect from xilinx is used to which connects AXI_ADCFIFO and modified AXI_DACFIFO to the MIG Controller. Now the data can be successfully retrieved from AXI_ADCFIFO and sent to axi_dmac. From there the MATLAB can verify the correctness of data. The problem arises where the modified AXI_DACFIFO(AXI_DATAEXTACTOR in fig.) tries to read the data. The IQ samples at the end of the data (seen in ILA) does not verify with MATLAB. MATLAB and ILA shows the same RF data at the time. For this particular problem I want to ask


1. In AXI_ADCFIFO IP core this formula is used AXI_AWINCR = AXI_LENGTH * AXI_BYTE_WIDTH whereas in AXI_DACFIFO this formula is used AXI_AWINCR = (AXI_LENGTH + 1) * AXI_BYTE_WIDTH. I concur that ADCFIFO IP utilizes AXI3 protocol and DACFIFIO AXI4. Does this difference could arise the wrong reading of data from modified AXI_DACFIFIO IP core?

2. AXI_SIZE is the size of data to be transferred. DDR4 in ZCU102 has 128 bits. This translates to 2^n where n in this case is 4. In Axi_ADCFIFO AXI_LENGTH is configured as 4. So that means that in a burst it writes 4*(2^4) bytes in the memory(DDR4). Should modified AXI_DACFIO also have the same axi_length config. or it can also be configured for more , for e.g 32 or 64?
How AXI_Length impacts the buffer memory composed of BRAM in DACFIFO?
How one can calculate ideal AXI_LENGTH?

3. Here is the modified code

`timescale 1ns/100ps

module axi_dataextractor #(

  parameter   DAC_DATA_WIDTH = 64,
  parameter   AXI_DATA_WIDTH = 128,
  parameter   AXI_SIZE = 4,
  parameter   AXI_LENGTH = 4,
  parameter   AXI_ADDRESS = 32'h80000000,
  parameter   AXI_ADDRESS_LIMIT = 32'h9fffffff,
  parameter   AXI_LAST_ADDR = 32'h80012C50 
) (

// dac interface

  input                   dac_clk,
  input                   dac_rst,
  input                   dac_valid,
  input                   axi_xfer_req_s,
  output  reg [(DAC_DATA_WIDTH-1):0]  dac_data,
  output  reg             dac_dunf,
  output  reg             dac_xfer_out,

  // axi interface

  input                   axi_clk,
  input                   axi_resetn,
  output                  axi_awvalid,
  output      [ 3:0]      axi_awid,
  output      [ 1:0]      axi_awburst,
  output                  axi_awlock,
  output      [ 3:0]      axi_awcache,
  output      [ 2:0]      axi_awprot,
  output      [ 3:0]      axi_awqos,
  output      [ 7:0]      axi_awlen,
  output      [ 2:0]      axi_awsize,
  output      [ 31:0]     axi_awaddr,
  input                   axi_awready,
  output                  axi_wvalid,
  output      [(AXI_DATA_WIDTH-1):0]  axi_wdata,
  output      [(AXI_DATA_WIDTH/8-1):0]  axi_wstrb,
  output                  axi_wlast,
  input                   axi_wready,
  input                   axi_bvalid,
  input       [ 3:0]      axi_bid,
  input       [ 1:0]      axi_bresp,
  output                  axi_bready,
  output                  axi_arvalid,
  output      [ 3:0]      axi_arid,
  output      [ 1:0]      axi_arburst,
  output                  axi_arlock,
  output      [ 3:0]      axi_arcache,
  output      [ 2:0]      axi_arprot,
  output      [ 3:0]      axi_arqos,
  output      [ 7:0]      axi_arlen,
  output      [ 2:0]      axi_arsize,
  output      [ 31:0]     axi_araddr,
  input                   axi_arready,
  input                   axi_rvalid,
  input       [ 3:0]      axi_rid,
  input       [ 1:0]      axi_rresp,
  input                   axi_rlast,
  input       [(AXI_DATA_WIDTH-1):0]  axi_rdata,
  output                  axi_rready,
  output                  axi_rerror,
                
  // Debug output
  output      [4:0]       fsm_dacfifio_deb,  
  output      [31:0]      last_raddr_deb,
  output      [31:0]      axi_araddr_deb,
  output      [8:0]       axi_arincr_deb,
  output                  axi_rready_deb,
  output                  axi_rrvalid_deb,
  output                  axi_rrlast_deb,
  output reg              axi_xfer_req_deb,
  output                  axi_fifo_rst_deb                           
);

  reg                                axi_xfer_req_m_s1;
  reg                                axi_xfer_req_m;
  (* dont_touch = "true" *) wire    [31:0]                      axi_last_addr_s ;
  (* dont_touch = "true" *) wire    [ 7:0]                      axi_last_beats_s;
  reg    [ 3:0]                       dma_last_beats_s  = 4'b0000;
  wire    [(DAC_DATA_WIDTH-1):0]      dac_data_fifo_s;
  wire    [(DAC_DATA_WIDTH-1):0]      dac_data_bypass_s;
  wire                                dac_xfer_fifo_out_s;
  wire                                dac_dunf_fifo_s;
  wire                                dac_dunf_bypass_s;

  localparam  AXI_BYTE_WIDTH = AXI_DATA_WIDTH/8;
  localparam  AXI_ARINCR = (AXI_LENGTH + 1) * AXI_BYTE_WIDTH;
  
  assign axi_last_addr_s = AXI_LAST_ADDR & (~AXI_ARINCR + 1);
  assign axi_last_beats_s = AXI_LENGTH;
  
  // setting deafult values for Write channel. In our case,
  // the write channel should be disabled.
  
  assign axi_awvalid = 1'b0;
  assign axi_awid    = 4'b0000;
  assign axi_awburst = 2'b01;             // INCR (Incrementing address burst)
  assign axi_awlock  = 1'b0;              // Normal access
  assign axi_awcache = 4'b0010;           // Cacheable, but not allocate
  assign axi_awprot  = 3'b000;            // Normal, secure, data access
  assign axi_awqos   = 4'b0000;           // Not used
  assign axi_awlen   = AXI_LENGTH;
  assign axi_awsize  = AXI_SIZE;
  assign axi_awaddr  = AXI_ADDRESS;
  assign axi_wvalid  = 1'b0;
  assign axi_wdata   = {128{1'b0}};
  assign axi_wstrb   = {AXI_BYTE_WIDTH{1'b1}};
  assign axi_wlast   = 1'b0;
  assign axi_bready  = 1'b0;

  axi_dataextractor_rd #(
    .AXI_DATA_WIDTH (AXI_DATA_WIDTH),
    .AXI_SIZE (AXI_SIZE),
    .AXI_LENGTH (AXI_LENGTH),
    .AXI_ADDRESS (AXI_ADDRESS),
    .DAC_DATA_WIDTH (DAC_DATA_WIDTH),
    .DAC_MEM_ADDRESS_WIDTH (12)
  ) i_rd (
    .axi_xfer_req (axi_xfer_req_m_s1),
    .axi_last_raddr (axi_last_addr_s),
    .axi_last_beats (axi_last_beats_s),
    .axi_clk (axi_clk),
    .axi_resetn (axi_resetn),
    .axi_arvalid (axi_arvalid),
    .axi_arid (axi_arid),
    .axi_arburst (axi_arburst),
    .axi_arlock (axi_arlock),
    .axi_arcache (axi_arcache),
    .axi_arprot (axi_arprot),
    .axi_arqos (axi_arqos),
    .axi_arlen (axi_arlen),
    .axi_arsize (axi_arsize),
    .axi_araddr (axi_araddr),
    .axi_arready (axi_arready),
    .axi_rvalid (axi_rvalid),
    .axi_rid (axi_rid),
    .axi_rresp (axi_rresp),
    .axi_rlast (axi_rlast),
    .axi_rdata (axi_rdata),
    .axi_rready (axi_rready),
    .axi_rerror (axi_rerror),
    .dma_last_beats (dma_last_beats_s),
    .dac_clk (dac_clk),
    .dac_rst (dac_rst),
    .dac_valid (dac_valid),
    .dac_data (dac_data_fifo_s),
    .dac_xfer_out (dac_xfer_fifo_out_s),
    .dac_dunf (dac_dunf_fifo_s),
    .fsm_dacfifio_deb(fsm_dacfifio_deb),
    .last_raddr_deb(last_raddr_deb),
    .axi_araddr_deb(axi_araddr_deb),
    .axi_arincr_deb(axi_arincr_deb),
    .axi_rready_deb(axi_rready_deb),
    .axi_rrvalid_deb(axi_rrvalid_deb),
    .axi_rrlast_deb(axi_rrlast_deb),
    .axi_fifo_rst_deb(axi_fifo_rst_deb)   
    );
   /* if (~FIFO_BYPASS) */
    
    always @(posedge dac_clk) begin
      
      if (dac_valid) begin
        
        dac_data <= dac_data_fifo_s;
      
      end
      
      dac_xfer_out <= dac_xfer_fifo_out_s;
      dac_dunf     <= dac_dunf_fifo_s;
    
    end
    
    always @(posedge axi_clk) begin
    
        axi_xfer_req_m    <= axi_xfer_req_s;
        axi_xfer_req_m_s1 <= axi_xfer_req_m;
        axi_xfer_req_deb  <= axi_xfer_req_m_s1;
    
    end

endmodule


In this I have removed DMA and dacfifo_wr.v logic as I am only interested in reading from MM part and then sending the readed Data through a different lower clock. The axi_xfer_req_s signal comes from my custom IP core @122.88 MHz and as a result CDC so that it can register to AXI clock which is connected to MIG UI clk port. Other than that dacfifo_rd.v is untouched and no modification is done there. I am having trouble with three signals namely : axi_last_addr_s, axi_last_beats_s and dma_last_beats_s. With which deafult value should I initialize them? In my custom IP core I control axi_xfer_req_s in such a way that when counter reaches a demanded IQ samples value then the signal is put to LOW for a single clock and then again to HIGH so that I can again read the same value from starting address of the RAM.

4. If AXI_ADCFIFO only operates on AXI3 then how AXI_DMAC gets the right IQ samples and MATLAB decodes it correct whereas modified AXI_DACFIFO is not able to?

Thank you in advance.

With regards,



Added former thread members
[edited by: FPGA@noob at 8:52 AM (GMT -4) on 24 Mar 2023]