RFSoC DAC with Pynq


I am working with a firmware that uses the DAC on the ZCU111 RFSoC board. I have done a very simple design and tested it in bare metal. It has a counter feeding a DAC. It works in bare metal.

When I move to Pynq, it seems like I am able to load the .bit and read the .hwh file with the Overlay class. I can list the IPs and other stuff.

However, the DAC does not work. I have a couple of questions:

  1. In bare metal, the bitstream contains the configuration of the DAC tile. It does not seem to be the case when loading the bitstream using the Overlay class. Is this correct?
  2. I see there’s a library called xrfdc but I could not find a simple example on how to use it. I would like a very simple one, just configuring and using one simple ADC/DAC tile.

Thank you in advance,

The University of Strathclyde have an example design that uses the DAC and ADC blocks in a complete QPSK system. You can find it here.


The configuration of the DAC block should be contained within the hwh file and the xrfdc library should automatically configure itself from that - if not there is a bug somewhere.


Hi Leandro,

Just adding to Peter’s comments. Sounds like the DAC block might not be getting clocked correctly. Things to look out for:

  1. Remember to configure any LMK/LMX clocks that you use - the DAC won’t
    work without its reference clock. We’ve got a simple driver called xrfclk
    for this.
  2. If you use the DAC tile’s internal PLL, call the DynamicPLLConfig function.

Something like the following lines might be enough to get you up and running:

from pynq import Overlay
import xrfclk

ol = Overlay("my_bitstream.bit")

# Set up RF refrence clocks

# Optionally set up DAC tile's PLL
dac_tile = ol.usp_rf_data_converter_0.dac_tiles[YOUR_TILE_NUM]
dac_tile.DynamicPLLConfig(1, 409.6, 1228.8)

I agree that a very simple data converter demo would be useful, especially
for folks interested in instrumentation rather than comms. If you are in a
position to open source your counter design, perhaps this could become a good
example design?


Hi Craig,

Thank you all guys for your answers. One day after uploading the problem, I found the external PLL was not giving me the frequency so I fixed that and the example is working now.

I can share the project with you, it is just a counter with the only interesting thing that it has a “parellel” implementation, so that all outputs of the AXI Stream are driven to properly count at the maximum frequency of the DAC.



I am asking my question in reply to this post since it is very related. I hope someone can help me.
I am using the DAC on the ZCU111 RFSoC board and I am using pynq. I am trying to update the mixer setting using xrfdc lib. First, I can get the initial setting as:

ol = Overlay(“my overlay”)

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

In order to update the freq of the mixer, I use the following lines of code:

event = xrfdc.EVNT_SRC_TILE
mixersetting1 = {‘Freq’ : 1474.48, ‘PhaseOffset’ : 0.1, ‘EventSource’ : event}

However, I get the initial mixer setting again. It seems that the update did not happen. Do you have some experience to help me out?


Hi Reza,

Thanks for reporting this. I’ve added this as an issue on the GitHub repo.

The issue is that some of the ways that you can mutate dicts in Python (including .update) aren’t properly propagated to the underlying C driver.

In the meantime, there are two options to get your code working:

  1. Assign each value in the dict individually:
event = xrfdc.EVNT_SRC_TILE
ol.dac_block.MixerSettings['Freq'] = 1474.48
ol.dac_block.MixerSettings['PhaseOffset'] = 0.1
ol.dac_block.MixerSettings['EventSource'] = event
  1. Or make a copy of the MixerSettings dict, update it, then replace the original:
event = xrfdc.EVNT_SRC_TILE

# Make a copy of mixer settings dict
new_mixcfg = ol.dac_block.MixerSettings.copy()

# Update the copy
    'Freq' : 1474.48,
    'PhaseOffset' : 0.1,
    'EventSource' : event

# Now point mixer settings to our new copy
ol.dac_block.MixerSettings = new_mixcfg


Let me know if this helps!


Hi Craig,

Thanks for the response. I manage to update the settings using the second way that you recommended. This way, once can define multiple PLL settings and use them.


Hi Craig,

How would it be possible to configure LMK/LMX for other freq options through pynq? As far as I am concerned, by using “set_all_ref_clks” command, only the values from “get_freq_list” are allowed and for other freq options, one would need to use _write_lmk04208_regs() and _write_lmx2594_regs() functions with the register values.
Do you have an example that shows how to use those functions for other freq options? Specifically, I want to set the DAC reference clock to be integer multiple of 122.88 MHz.

Thanks in advance,

Hi Leoeltipo,

I have had exactly the same problems. Except I have been unable to fix the external PLL ( the LMX2594 PLL ) . In baremetal mode ( i.e. using the SDK drivers ) the xrfdc/xrfclk drivers seem to be able to reprogram the LMX2594 PLL . However using PYNQ I cannot get the drivers to start the LMX2594 PLL ) . You seem to have fixed this - can you help me!


Hi Reza,

Can you share your Pynq code you used to update the Pynq settings? I am not able to follow this, for example:

event = xrfdc.EVNT_SRC_TILE

Make a copy of mixer settings dict

new_mixcfg = ol.dac_block.MixerSettings. copy()

– In Pynq, I donot get copy option after MixerSettings.

Update the copy

‘Freq’ : 1474.48,
‘PhaseOffset’ : 0.1,
‘EventSource’ : event

– I do not see the update option after new_mixcfg.

I will really appreciate your help.