ZCU216 Gen3 Stream Tone to DAC230 (Misformated Data / Missing RFDC Initialization?)

Hello,

Following up on another topic I posted recently on configuring the LMK clocks using the xrfclk driver, now I’m stuck on actually streaming data to the DAC.

By that I mean I can’t observe anything at the output of DAC230, via the XM655, using an oscilloscope.

My setup (TCL attached), with clock domains highlighted:

RF config:

The PL clock is 100Mhz.

(Sidenote: I tried without DMA before, as I posted on the topic I linked).

And what I’m running via Jupyter, with some output omitted for brevity (also attached):

import xrfclk
import xrfdc
import pynq.lib.dma
from pynq import allocate
import numpy as np
import matplotlib.pylab as plt

xrfclk.set_ref_clks(245.76)

from pynq import Overlay
ol = Overlay("/home/xilinx/overlays/zcu216_nmcp_dma2/zcu216_nmcp88.bit")
ol?


axi_dma_0 : pynq.lib.dma.DMA
usp_rf_data_converter_0 : xrfdc.RFdc
zynq_ultra_ps_e_0 : pynq.overlay.DefaultIP

rf = ol.usp_rf_data_converter_0
rf.IPStatus

{‘DACTileStatus’: [{‘IsEnabled’: 0,
‘TileState’: 0,
‘BlockStatusMask’: 0,
‘PowerUpState’: 0,
‘PLLState’: 0},
{‘IsEnabled’: 0,
‘TileState’: 0,
‘BlockStatusMask’: 0,
‘PowerUpState’: 0,
‘PLLState’: 0},
> {‘IsEnabled’: 1,
> ‘TileState’: 15,
> ‘BlockStatusMask’: 1,
> ‘PowerUpState’: 1,
> ‘PLLState’: 1},
{‘IsEnabled’: 0,
‘TileState’: 0,
‘BlockStatusMask’: 0,
‘PowerUpState’: 0,
‘PLLState’: 0}],

tile2 = rf.dac_tiles[2]
tile2.PLLConfig
tile2.SetupFIFO(True)
dac_block = tile2.blocks[0]
dac_block.BlockStatus
dac_block.MixerSettings

{‘Freq’: 0.0,
‘PhaseOffset’: 0.0,
‘EventSource’: 2,
‘CoarseMixFreq’: 4,
‘MixerMode’: 1,
‘FineMixerScale’: 0,
‘MixerType’: 1}

# Adapted from: https://repositorio.uam.es/handle/10486/697509
def sine_gen(a, f, fs, n):
    w = 2 * np.pi * f
    dt = 1 / fs
    t = np.arange(0, n, 1) * dt
    return a * np.exp(1j * w * t)

def to_fp(data):
    # split into real and img
    data_real = np.multiply(np.real(data), np.power(2, 15)).astype(np.int32)
    data_imag = np.multiply(np.imag(data), np.power(2, 15)).astype(np.int32)
    data_real = np.where((data_real >= 32768), 32767, data_real)
    data_imag = np.where((data_imag >= 32768), 32767, data_imag)    
    
    # pack into uint32
    data_iq = np.zeros(len(data_real), dtype=np.uint32)
    data_imag_shifted = np.uint32(np.bitwise_and((data_imag << 16), 0xFFFF0000))
    data_real_shifted = np.uint32(np.bitwise_and((data_real << 0), 0x0000FFFF))
    data_iq = np.bitwise_or(data_imag_shifted, data_real_shifted)
    
    return [data_iq, data_real, data_imag]

def DMAWave(freq):
    a = 1                # Amplitude
    f = freq * 1e6       # Desired frequency (Mhz)
    fs = 786.432e6       # Sampling rate
    n = 8 * 786.432      # nr samples (?)
    signal_gen = sine_gen(a, f, fs, n)
    array_fp = to_fp(signal_gen)
    return array_fp;

def toDMABuf(array_fp):
    n = len(array_fp)
    in_buffer = allocate(shape=(n,), dtype=np.int32)
    for i in range(n):
        in_buffer[i] = array_fp[i]       
    return in_buffer
f = 20          # Desired frequency (Mhz) (?)
wav = DMAWave(f)

# check the wave(s)
plt.plot(wav[1][:100])
plt.plot(wav[2][:100])
plt.show()

# put into "allocate" type buffer for DMA
buf = toDMABuf(wav[0])

image

# send forever
dmatx = ol.axi_dma_0.sendchannel
while(1):
    dmatx.transfer(buf)
    dmatx.wait()

This last cell runs until I stop it (or eventually the board stops responding entirely, either via ssh, via ttyUSB, or Jupyter… and I have to power cycle it).

I suspect I’m missing some initialization on the Data converter at the Notebook/Python level? I’m not sure if calling tile2.SetupFIFO(True) is enough to “initialize” the tile (?). I’m not even quite sure what this call does, as I’m going by existing RFSoC-Book examples (e.g., rfscoc_qpsk, rfsoc_sam, etc).

I’ve also tried in Real → Real mode (generating a uint32 sine wave and sending that via DMA), without success.

Any help would be appreciated, regards,
Nuno
zcu216_nmcp_dma2.ipynb (38.3 KB)
zcu216_nmcp_dma2.tcl (109.3 KB)

2 Likes