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)