ZCU216 PYNQ Radio Receiver - Only Getting 2 Non-Zero Samples in DMA Buffer

I am trying to implement a simple radio receiver using the ZCU216 with PYNQ. The issue I’m encountering is that my output buffer only contains 2 non-zero samples, despite expecting continuous data.

Block Design: My design follows this data path: RF Data Converter (ADC) → AXI4-Stream FIFO → DMA → MPSoC. The attached PDF shows my complete block design.

Current Status:

  • Successfully generated bitstream and .hwh file
  • RFDC configuration completed in PYNQ
  • External 915MHz RF signal confirmed present via spectrum analyzer
  • DMA transfers complete without errors
  • I have a USRP sending a 915MHz signal very close by, confirmed by spectrum analyzer.

Problem: When I perform DMA transfers to capture RF data, I consistently get only 2 non-zero samples (at positions [0] and [2] in my buffer), while the rest remain zero. The non-zero values change with each transfer, indicating the RFDC is actively sampling, but the data stream appears to stop after just one AXI4-Stream beat.

Configuration Details:

  • FIFO depth: 512
  • DMA stream data width: 64-bit
  • RFDC output: I/Q mode, 64-bit TDATA
  • Buffer allocation: int16 arrays of various sizes (64 to 16384 samples tested)

Has anyone encountered similar AXI4-Stream flow control issues with RFDC → FIFO → DMA chains? Any suggestions for debugging this streaming bottleneck would be appreciated.

PYNQ Code to configure the RFDC

with open('LMK04828_300.txt', 'w') as f:
    f.write(register_values)
try:
    lmk_freq = 300   # Valid for LMK04828
    xrfclk.set_ref_clks(lmk_freq=lmk_freq)
except RuntimeError as e:
    print("Clock configuration failed:", e)

rfdc = xrfdc.RFdc(ol.ip_dict['usp_rf_data_converter_0'])
corrected_nco_freq = 915 
tile_type = 1 # 0 for DAC, 1 for ADC
tile_id = 2
block_id = 0
rfdc_core = xrfdc.RFdc(ol.ip_dict['usp_rf_data_converter_0'])
adc_block = rfdc_core.adc_tiles[tile_id].blocks[block_id]
settings = adc_block.MixerSettings
settings['MixerMode'] = xrfdc.MIXER_MODE_R2C
settings['CoarseMixFreq'] = xrfdc.COARSE_MIX_SAMPLE_FREQ_BY_FOUR
settings['MixerType'] = xrfdc.MIXER_TYPE_FINE
settings['Freq'] = corrected_nco_freq
adc_block.MixerSettings = settings
adc_block.UpdateEvent(EVENT_MIXER)
adc_tile = rfdc.adc_tiles[2]
adc_tile.SetupFIFO(True)

PYNQ printed:

{'Freq': 914.9999999999991, 'PhaseOffset': 0.0, 'EventSource': 2, 'CoarseMixFreq': 0, 'MixerMode': 3, 'FineMixerScale': 0, 'MixerType': 2}
ADC Tile 2 Status:
  IsEnabled: 1
  TileState: 15
  BlockStatusMask: 1
  PowerUpState: 1
  PLLState: 1

The frequency is correct (we want 915MHz) and as far as I know, tile state 15 is right.

PYNQ Code for DMA transfer and buffer print

dma = ol.AXI_DMA
num_samples = 512  # Start smaller for testing
input_buffer = allocate(shape=(num_samples,), dtype=np.int16)  # Use int16 for simplicity
# Read from memory
print("Memory contents BEFORE:")
for i in range(512):
    print(f"  [{i}]: {input_buffer[i]}")
dma.recvchannel.transfer(input_buffer) 
dma.recvchannel.wait()
print("\nMemory contents AFTER:")
for i in range(512):
    print(f"  [{i}]: {input_buffer[i]}")

Here is what got captured:

Memory contents AFTER:
  [0]: 2
  [1]: 0
  [2]: -15
  [3]: 0
  [4]: 0
  [5]: 0
  [6]: 0
  [7]: 0
  [8]: 0
  [9]: 0
...

So I see two problems: 1) Q channel is 0 since the data is IQ interleaved, and 2) for the I channel, only the first two have values. But I do not have enough knowledge on AXI data transfer to know why.

I am new to this. I want to ask if this is a block design problem? I made my FIFO depth 512 and DMA stream data width 64-bit, and my ADC outputs 4 samples per stream cycle – I suspect this might be the problem. Am I missing some mechanism? It seems like either the RFDC, DMA, or FIFO is just capturing 2 samples and then stopping.
TRX.pdf (87.7 KB)

Hi @Xingda_Chen,

Welcome to the PYNQ community.
I am not an expert in RFSoC, however, I can tell you that I see a few issues with the DMA. First, the tlast is set to a constant, which from the results, I assume may be one. This is not correct. Second, the tkeep is unconnected, which mean it is being tied to 0.

You will need to create extra logic to set tkeep to all ones, and only set tlast in the appropriate beat, this will be at 512 samples (16-bit) each.

I wrote an extensive DMA debug post.

Mario

1 Like