ZCU111 - Sending data through DDR4 from PS

Hi all!

I am trying to implement the equivalent of the RFSoC-MTS repo ( GitHub - Xilinx/RFSoC-MTS: A PYNQ overlay demonstrating AMD RFSoC Multi-Tile Synchronization (MTS). · GitHub ) but on the ZCU111. I don’t really care about the MTS feature, I just need basically the ADC with some BRAMs and also the DeepCapture feature (using the DDR4 to capture data).

That has worked fine, I am able to capture data with the DDR4 and see it in Pynq, working as expected. Now I would like to extend the design a bit, and instead send data from the PS to the PL through the DDR4. I am going this direction since I need to send in a single command 32 Mb of data, which is too much for the BRAMs to handle. To do so, my first naive try was to enable the Write Channel within the DMA IP and connect the stream output to a FIFO, and then to a system ILA to debug.

Then, on the Pynq side I am able to use the DDR4 data capture with the function provided by the RFSoC-MTS repo

    def dram_capture(self, buffer):
        """ Captures ADC samples to the PL-DRAM memory notebook provided buffer """
        if type(buffer) != pynq.buffer.PynqBuffer:
            raise Exception("A PYNQ allocated buffer is required!")

        if not np.issubdtype(buffer.dtype, np.int16):
            raise Exception("buffer not defined or np.int16")
        
        self.adc_dma.register_map.S2MM_DMACR.Reset = 1
        self.adc_dma.recvchannel.stop()
        self.fifo_flush.off() # clear FIFO
        # because TLAST is not used, we must soft-reset the S2MM/recvchannel
        self.adc_dma.register_map.S2MM_DMACR.Reset = 0
        self.adc_dma.recvchannel.start()
        self.adc_dma.recvchannel.transfer(buffer)
        self.fifo_flush.on() # enable FIFO and samples will start flowing

I defined a naive function to transfer data

    def dram_playback(self, buffer):
        """Stream a waveform from PL-DRAM to the DAC via MM2S DMA"""
        if type(buffer) != pynq.buffer.PynqBuffer:
            raise Exception("A PYNQ allocated buffer is required!")
        if not np.issubdtype(buffer.dtype, np.int16):
            raise Exception("buffer must be np.int16")

        self.adc_dma.sendchannel.transfer(buffer)

which I call with:

from pynq import allocate
import numpy as np

num_samples = 4 * 1024 * 1024
tx_buffer = allocate(num_samples, dtype='i2', target=ol.ddr4_0)

t = np.arange(num_samples)
tx_buffer[:] = t
ol.dram_playback(tx_buffer)

However, when I do that I see on the probes that tdata is changed but to very weird and constant values.

Any hint on what I am doing wrong?

Thanks!

Hi @bmatias.ruben,

From the waveform you can see that TREADY is always 0, so no transaction is valid.

I cannot fully distinguish the colors in the diagram, but one reset is unconnected. Not sure about was is the source of the axis_data_fifo_0 reset. Also, where is the ILA connected?

Hi @marioruiz, you raised a good point, indeed one reset was disconnected, and one was connected to the wrong port. This is the full block design now, just tested again and still TREADY was constant at 0 on the System ILA.

However, I also included debug probes in the input and output of the FIFO, which does trigger TREADY, but gets that weird values that don’t match what I expect, since the data that I am sending should be a counter from 0 to to 0x400000, I don’t expect to get that constant 0xDEC0DEE3 sequence.

Could it be a wrong memory map?

There are a few things happening as I can see it without going very deep as some of the issues are outside the scope of this forum.

TREADY issue: fundamentally, the axis_data_fifo_0/M_AXIS is tied to 0. The ILA just monitors the interface, it does not drive any signal. You need to have an IP to consume from this interface or tie TREADY to 1.

TDATA value: each of your samples is 16-bit wide, however, you are seeing 32 samples packed together. So, you are seeing a 512-bit number and you need to look at particular bits in that number to match your samples. There are ways were you can subdivide this bus into the chunks you’re interested but this is outside the scope of this forum. Also, I would not pay attention to those values until the AXI4-Stream interface is working correctly.

Python code: for readability, I would suggest you use np.int16 or np.uint16 as datatype. I would also suggest you cast the output of np.arange to the datatype you’re using for tx_buffer, you can do this by providing the dtype as argument.

Mario