Post Go back to editing

ZCU102 + ADRV9009 HDL implementation fail

Category: Choose a category
Product Number: ADRV9009 with ZCU102
Software Version: 2021_r1

I have downloaded the latest HDL for ZCU102 attached with ADRV9008-1W. HDL version is for ADRV9009. I have only modified the design to have hierarchy blocks in it. After arranging the individual IP blocks into hierarchy, the design is giving critical error saying 

ERROR: [Constraints 18-851] Could not find an automatically derived clock matching the supplied criteria for renaming.

I have modified the system_contr.xdc file to have proper hierarchy block name so that the respective pins can be taken correctly.

My report_clocks 



Critical Warning list


Thank you and regards



Added critical warning after the implementation
[edited by: FPGA@noob at 12:25 PM (GMT -4) on 30 Sep 2022]
Parents
  • Hi, 

    From what I can see here it seems you have a naming inconsistency. I tried to build the project on my side and it was successful.

    I think you missed something when you added the hierarchy blocks. Try building it the way it without the modifications and then apply your changes, so we know where the problem comes from.

    Regards, 

    Liviu

  • Hi,
      
    Thanks for the reply. I have modified the design only after the make command(initial stage) have generated bit file. After that in vivado, I have changed. Could it be that the ooc parameter was on during make command but I want to generate the system design output as global and not ooc. If that is the reason, then how can I change the settings in the vivado itself or do I need to create clock in top level .xdc file?

    Thank you.

  • Hi, 

    As far as I know, timing violation error is the reason we are using ooc.

    Try to keep the default ooc setting (on) and open the implemented design. There you can find the path and the name of the clock associated with the pin you are looking for.

    However, this question is more about how Vivado handles connections and not as much about our design. Maybe take a look at some documentation from Xilinx regarding this problem if you want to learn more about the hierarchical blocks.

    Regards.

  • Hi  . I have implemented with ooc setting as on. As I don't need Tx and Rx OS blocks, I will delete them and then I can try to synthesize and implement the design as global and not as ooc .

    There is one more query for which I don't want to open a question. For DMA, I have modified the design to have ddr4_MIG and adi_adcfifo IP block attached to DMAC so that I can retrieve continuously large radio frames. Now, I want to extract, let's say 2 radio frames, from ddr4_MIG continuously and analyse it within FPGA against different parameters. Can you suggest me an IP block such as adi_dacfifio or util_dacfifo which can extract the said amount of radio frames from ddr4_MIG and fed it for analyzing again and again? During extraction of radio frames, there will be no irq request so the ddr4_MIG will have same data.

    Thank you for your time.

    Regards.

  • Hello,

    At this point we haven't added support for PL DDR on the ZCU102. We typically use ADC_FIFO or Data Offload Engine HDL IP Core [Analog Devices Wiki] to capture data if the bandwidth is higher than the PS DDR can handle, but after that we send it to the PS DDR for processing. I think you have something else in mind.

    I think the PS interface for ZCU102 should handle the bandwdith coming from ADRV9009 RX channel, so you should be able to capture more than 1 GB of data. Is that enough for your use case?

    If the processing is done in the fabric, you could probably use another DMA to take the data from memory and stream it to your processing IP.

    Regards,

    Adrian

  • Hi  , thank you for your reply. I was thinking of a interconnect IP connected to MIG at one end and as subordinates, I  can have axi_adcfifo+DMAC IP cores and as another subordinate ,a xyz IP core(axi_dacfifo or util_xyzfifo), which will get the data from the MIG according to the address. As address will always be from starting of what MIG has and will go till 2 radio frames samples, so the idea is to get a IP core which can generate address, give it to MIG and according deliver the data to for e.g a custom IP core.

    I hope, my problem is understandable. Thank you

    Here is a screenshot of my DMA hierarchy

  • I think the AXI_DMAC can read data from an AXI address and stream it to a custom core.

    AXI_DACFIFO is used to get data from a DMA, store it in an PL DDR and from there forward it to a stream. As you already have the data in the memory, you don't need that. Now that i'm thinking about it, instead of getting the data from the DMA you could get it from stream directly. You could try that, but I don't think we had this use case tested.

    UTIL_adc/dacFIFOs are used with BRAM and AXI_adc/dacFIFOs are used with DDR as intermediary storage.

    Regards,

    Adrian

  • I want to get the data from ddr4 RAM which is saved there by axi_adcfifio and not from DMAC. Now, I want to extract the data from ddr4 RAM but dont know which IP core can do that.

    Regards

  • The DMAC is an IP which can take data from a memory and send it to the stream, It will be an additional DMAC, on top of the one you are already using to move data from the ADC_FIFO to the PS DDR. Is there a reason you don't want to use it ?

    Regards,

    Adrian

  • Hi   and  , sorry for late reply.
    I am posting here a screenshot of DMA where I have added DDR4 MIG and adcfifo IP cores. To that I have added additionally AXI interconnect having 2 subordinate and 1 main.
    Main is DDR4 MIG and one of the subordinate is adcfifo which writes the data in the DDR4 and another subordinate is in the question which will retrieve the data from the DDR4 and will send it to a custom IP core.

    Now, the question: If there is IP core from ADI which can be used as second subordinate to the interconnect IP core which can retrieve the data from the DDR4 through MIG.

    Regards.

  • Hello  ,

    Sorry for the late reply, there are two possible options:

    1) You can keep the original connections of the axi_adrv9009_rx_dma(basically the source of your DMA will be a FIFO interface connected with the util_cpack) and then connect axi_adcfifo_0/dma_wdata stream to your custom IP where all the captured data will be continuously streamed and your IP should determine when the frame ends.

    2) The other option is to drop the axi_adcfifo_0 from the design and replace it with a DMA that can capture data to DDR4 memory(this DMA will be configured as the existent axi_adrv9009_rx_dma, the source interface is a FIFO interface connected to the util_cpack and destination interface is a Memory-Mapped AXI connected to S00_AXI from axi_interconnect_0) and in order to extract the data from the DDR4 to a stream you can use another DMA which will be configured as TX DMA(source interface is a Memory-Mapped AXI connected to S01_AXI from axi_interconnect_0 and destination interface can be a FIFO interface or Streaming AXI connected to your IP logic). 

    The second option is more flexible from the software perspective cause you can establish when the data is written to DDR4 and when is extracted from the DDR4.

    Best regards,

    Filip.

  • Hello  ,

    Do you have any updates on this topic?

    Regards,

    Filip.

Reply Children
  • Hello  

    Sorry for late reply. This was pushed under due to other ongoing projects.
    Thank you for your suggestions. According to our requirements, I have taken axi_dacfifo from library/xilinx folder and there I have modified the IP core in such a way that dacfifo_rd.v is applied. Here, the core will be initiated by one of my IP core which will again collect the data from dac_data port of the modified axi_dacfifio IP core. I am struggling with the control of the IP core and was hoping if you could help me with the signals which are coming from dacfifo_wr.v but are not used as I am only reading. With what value should I iniialize them? The increment of address is done by adding arincr value but let's assume that the arincr value is 80 (in decimal format) so how much data is delivered by in each incrememnt. is it axi_size multiplied by axi_length?

    Thanks.

    Reagrds,

  • Hello  , 

    Can you please send me the changes you did on those modules? It will help me a lot!

    Best regards

    Filip.

  • Hi   

    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. Here is the snip from my BD (For simplicity the modified IP core is named as AXI_Dataextractor) 

    I hope this will help you in providing a feedback.

    Thank you for your time.

    Regards,

  • Hello  ,

    1. It seems like axi_last_addr_s is initialized in axi_dac_fifo_wr.v with AXI_ADDREES=32'h00000000 so I think in your case it should be the first address you are reading from memory and axi_last_beats is initialized with 8'b0 in the same place.                                                                                         
    2. dma_last_beats should be initialized with 4'b0 as it is in the axi_dac_fifo_wr.v.                         
    3. And about axi_arincr_deb, I think it should respect AXI_ARINCR formula:                              

    Let me know if you already tried those values and if you did, what was the behaviour?

    Best regards

    Filip

  • Hello  

    I tried with the suggested settings and the in the ILA I can see that address was not incremented because the FSM in dacfifo_rd.v remains on XFER_PARTIAL_BURST which set the address again and again on the starting address. The FSM never goes in XFER_FULL_BURST state which is responsible for incrementing the address. 

    Moreover, when I configure the last address signal as DDR4 RAM last address value then my xfer signal, which remains HIGH so long the specified sample counter number is not reached, is not long enough to extract the required Data from MIG. This is strange because MIG is operating @300 MHz and my xfer signal is operating @122.88 MHz. 

    Regards, 

  • Ok that is strange, it is hard for me to debug based just on those infos, can you send me a print screen with all the signals you see on ILA and also I'm interested on seeing following signals: 

    • axi_araddr
    • axi_last_raddr,
    • axi_rready,
    • axi_rvalid,
    • axi_rlast,
    • axi_read_state 

    Have you checked the value of AXI_ARINCR?

    And it is not very clear how do you generate the xfer signal.

    Regards

  • Hello  

    Here is the snip from ILA

    AXi_ARINCR formula is untouched. So, for xfer signal following is done :-

    1. Through iio DMA is triggered which fills up the RAM through axi_adcfifo let's say with 4 radio frames.

    2. Then through PS, FSM in my custom IP core is triggered which reads saved radio frames through axi_dacfifo. So when FSM is in start phase then xfer signal is set to HIGH for the required radio frames/samples. 

    3. When counter in the FSM reaches to a required sample value then the xfer signal is set to low.

    This process can be repeated again and again according to the logic. As the samples is always to be read from starting address of the RAM, so xfer signal act as an ideal signal ,as it reset the FIFO_Reset signal in dacfifo_rd.v file. 

    Regards,