Register Read/Write on RFSoC4x2 Hangs Entire Board

Hello, I’m currently studying the Xilinx example for RFSoC4x2 board, using the RFDC IP. Here is the link: RFSoC-PYNQ/boards/RFSoC4x2/base/notebooks/rfdc/01_rf_dataconverter_introduction.ipynb at master · Xilinx/RFSoC-PYNQ · GitHub

I’m using python 3.10 on the RFSoC4x2 board, and Vivado version 2022.1.
I tried to replicate the radio hierarchy and made the design from scratch. I developed my own HLS IPs for amplitude controller and packet generator.

Here are the .hwh, .bit and .ltx files:
base_ac_pgen.zip (2.1 MB)

Here is the snippet of the hwh file where amplitude controller is described.

When I run the python code on the board, it is able to recognize that AmplitudeController and PacketGenerator classes are driver classes of ac_0 and pgen_0 IPs respectively. When I run dir(base.radio.transmitter.channel[0].control), I can see that ‘gain’ and ‘enable’ are its attributes. I am using the template of the drivers provided in the example, and I have made necessary modifications (offset, bindto, etc.).

The issue is that when I try to run base.radio.transmitter.channel[0].control.gain (the getter function), the board hangs. In the design generated from the tcl script provided in the example on github, this command works as expected. But in my custom block design it causes the board to hang. The getter and setter for the attributes of packet generator are working as expected.

I even added ILAs to the design (.ltx file is attached), and surprisingly the slot connected to the inputs of the amplitude controllers doesn’t show up on Vivado when I run the ILA.

Please help me with what the potential issues could be.

I have also tried to directly read/write the registers of amplitude controller using the Register class, but that causes the board to hang too.

What function are you using to change the gain in your new amplitude controller?
Is it:
def set_transmitter_channel(channel, enable, gain, frequency):
channel.control.enable = enable
channel.control.gain = gain
channel.dac_block.MixerSettings[‘Freq’] = frequency

and
set_transmitter_channel(base.radio.transmitter.channel[0], True, 0.8, 900)
?

What do you have when you try help(base.radio.transmitter.channel[0]) in a notebook?

Is your board also freezing when you change the enable of your new transmitter block?

Did you change any of these codes?
(RFSoC-PYNQ/boards/RFSoC2x2/packages/rfsystem/package/rfsystem at master · Xilinx/RFSoC-PYNQ · GitHub)

Finally, did you check if the addresses of the new blocks in the address editor seem correct?

I am using the same drivers which are given in the github example, I only changed the read/write offset values for gain and enable registers, and the VLNV in bindto.

I’m using this driver code: RFSoC-PYNQ/boards/RFSoC4x2/packages/rfsystem/package/rfsystem/transmitter.py at master · Xilinx/RFSoC-PYNQ · GitHub

This is the command that causes the board to hang:
image

It also hangs when I try to read the gain and enable values.

I have not tried help command but I tried dir:

In this I could see that enable and gain are attributes of control.

I will have access to the board on Monday now so I’ll try help(base.radio.transmitter.channel[0]) command then.

The addresses seem to be alright. I’m using the M_HPM0 port.

The github example is using the M_HPM1 port so this is its address map:

Is your board also hanging when you try base.radio.transmitter.channel[0].control.enable=True?

Can you please send the notebook you are using? If it is this one (RFSoC-PYNQ/boards/RFSoC4x2/base/notebooks/rfdc/01_rf_dataconverter_introduction.ipynb at master · Xilinx/RFSoC-PYNQ · GitHub), did you change the .bit imported? Can you show the modifications you made? Because you cannot use base.bit, and the class BaseOverlay has to be modified.

Is your board also hanging when you try base.radio.transmitter.channel[0].control.enable=True?

yes

Can you please send the notebook you are using? If it is this one (RFSoC-PYNQ/boards/RFSoC4x2/base/notebooks/rfdc/01_rf_dataconverter_introduction.ipynb at master · Xilinx/RFSoC-PYNQ · GitHub), did you change the .bit imported? Can you show the modifications you made? Because you cannot use base.bit, and the class BaseOverlay has to be modified.

Yes, this is the notebook I’m using. The base.bit file has been modified, I’ve attached it in my first post. This is the new BaseOverlay class I’m using:

import os
os.environ['BOARD'] = 'RFSoC4x2' 
import xrfclk
import rfsystem
import pynq
import pynq.lib
from .constants import *

class BaseOverlay(pynq.Overlay):
def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

def init_rf_clks(self, lmk_freq=245.76, lmx_freq=491.52):
    """Initialise the LMK and LMX clocks for the radio hierarchy.

    The radio clocks are required to talk to the RF-DCs and only need
    to be initialised once per session.

    """        
    xrfclk.set_ref_clks(lmk_freq=lmk_freq, lmx_freq=lmx_freq)

When I get access to the board on Monday I’ll share all the modified driver codes.

Here is a snippet of my custom block design:

Transmitter:

Receiver:

In the notebook, how do you import the new overlay? Via base=BaseOverlay(‘base_ac_pgen.bit’)?

yes

And I have reason to believe that the problem does not lie in the HLS design of my custom IPs, because I’m getting the exact same issue even with the IPs provided in the github example.

help(base.radio.transmitter.channel[0])

Help on DacChannel in module hierarchies object:

class DacChannel(pynq.overlay.DefaultHierarchy)
 |  DacChannel(description, dac_tile=None, dac_block=None)
 |  
 |  Wrapper for the dac channel hierarchy.
 |  
 |  This wrapper assumes the following pipeline structure and naming
 |  
 |  amplitude_controller -> rfdc
 |  
 |  Attributes
 |  ----------
 |  dac_tile : xrfdc.dac_tile
 |      The channel's associated DAC Tile. Can be used by the user
 |      to directly control the tile.
 |      
 |  dac_block : xrfdc.dac_block
 |      The channel's associated DAC Block. Can be used by the user
 |      to directly control the block.
 |      
 |  control : transmitter.AmplitudeController
 |      The Amplitude Controller that enables/disables signal
 |      output gain.
 |  
 |  Method resolution order:
 |      DacChannel
 |      pynq.overlay.DefaultHierarchy
 |      pynq.overlay._IPMap
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __init__(self, description, dac_tile=None, dac_block=None)
 |      Initialise the driver for the dac channel hierarchy.
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  checkhierarchy(description)
 |      Function to check if the driver matches a particular hierarchy
 |      
 |      This function should be redefined in derived classes to return True
 |      if the description matches what is expected by the driver. The default
 |      implementation always returns False so that drivers that forget don't
 |      get loaded for hierarchies they don't expect.
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from pynq.overlay.DefaultHierarchy:
 |  
 |  download(self, bitfile_name, dtbo=None, program=True)
 |      Function to download a partial bitstream for the hierarchy block.
 |      
 |      Since it is hard to know which hierarchy is to be reconfigured by only
 |      looking at the metadata, we assume users will tell this information.
 |      Thus, this function should be called only when users are sure about
 |      the hierarchy name of the partial region.
 |      
 |      Parameters
 |      ----------
 |      bitfile_name : str
 |          The name of the partial bitstream.
 |      dtbo : str
 |          The relative or absolute path of the partial dtbo file.
 |      program : bool
 |          Whether the overlay should be downloaded.
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from pynq.overlay._IPMap:
 |  
 |  __dir__(self)
 |      Default dir() implementation.
 |  
 |  __getattr__(self, key)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from pynq.overlay._IPMap:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)

Hi @Riya_Sachdeva,

This issue is likely to be because when you try to read there is no response from the IP.
Also, if the ILA does not show the interface, it is likely that the logic is being optimized and not used. You will need to check the Vivado logs to understand why your logic is being optimized away.

Mario

Alright, thanks.