Readback LMK Registers? (RFSoC4x2)


I’m trying to debug some strangeness with my LMK clock chip on my RFSoC4x2 and it would be really nice to be able to read back the registers from the chip to verify the programming and check for reported errors. I’ve been looking at the xrfclk package for inspiration and I was wondering if anyone has already found a way to extend xrfclk to do readback? I don’t have a lot of experience interacting with SPI devices. I naively tried to do something like this:

Clearly that didn’t work. If anyone has any tips or can point me to a good primer to learn how to do this I’d really appreciate it.


1 Like

Hi Jenny,

Reading back the LMX chips requires using the PS SPI interface. Note that the LMK is accessible via I2C interface and I would check if that is readable first. I believe the xrfclk is in need of modifications and I will have to take a deeper dive into it for the usage with the RFSoC4x2.

You are touching on an area that I was adjusting just recently. In the 4x2 base overlay, there is a file /boot/ that does a synthesizer reset, sets direction etc. I am working on improving things here with regards to the, but I can shed some light on access to the synthesizer chips.

From the RealDigital documentation one has to setup the following signals at the bottom left (all PS driven):

The LMX ADC and LMX DAC need to control their respective LVTTL_125 tristate buffers. The LMX needs to be set to drive its output signal (SDO/MISO) which turns of/off the buffer. From what you have shown, I believe both buffers are tri-state and you are just seeing the pull-up resistor (all-ones). The RealDigital schematic (page 18) shows that a CSB signal controls the tristate buffer (both active low), so to me it looks correct. You will want to probe J15 at pins 5, 6 and 7 to see that the CSB goes low and some outputs appear on 5. I’ll try to repeat this on my setup as well. But we can sync on this further along with the other broader topic of getting your TICs files setup to support MTS configurations.
If anyone else has feedback or experience getting the results please chime in too. I would be interested in first probing out that J15 of course.




Hi Nathan,

Thanks for reviewing. I am a little confused about what you are saying about SPI vs I2C. It looks like the xrfclk package is writing the programming files to both LMK and LMX chips using the SPI bus.

Here’s a snippet from the xrfclk package that came with my PYNQ3.0.1 RFSoC4x2 image

def _write_LMK_regs(reg_vals, lmk):

    """Write values to the LMK registers.

    This is an internal function.

    reg_vals: list
        A list of 32-bit register values (LMK clock dependant number of values).
        LMK04208 (ZCU111) = 32 registers, num_bytes = 4
        LMK04832 (RFSoC2x2) = 125 registers, num_bytes = 3
    lmk: dictionary
        An instance of lmk_devices
    This function opens spi_device at /dev/spidevB.C and writes the register values stored in reg_vals.
    Number of bytes written is board dependant. 

    with open(lmk['spi_device'], 'rb+', buffering=0) as f:
        for v in reg_vals:
            data = struct.pack('>I', v)
            if lmk['num_bytes'] == 3:

def _find_devices():
    Internal function to find lmk and lmx devices from the device tree and populate /dev/spidevB.C
    Also fills global variables lmk_devices and lmx_devices.
    global lmk_devices, lmx_devices

    # loop for each SPI device on the device tree
    for dev in Path('/sys/bus/spi/devices').glob('*'):
        # read the compatible string from the device tree, containing name of chip, e.g. 'ti,lmx2594'
        # strip the company name to store e.g. 'lmx2594'
        compatible = (dev / 'of_node' / 'compatible').read_text()[3:-1]

        # if not lmk/lmx, either non-clock SPI device or compatible is empty
        if compatible[:3] != 'lmk' and compatible[:3] != 'lmx':
            # call spidev_bind to bind /dev/spidevB.C
            if (dev / 'driver').exists():
                (dev / 'driver' / 'unbind').write_text(

            # sort devices into lmk_devices or lmx_devices
            if compatible[:3] == 'lmk':
                lmk_dict = {'spi_device' : _get_spidev_path(dev),
                            'compatible' : compatible,
                            'num_bytes' : struct.unpack('>I', (dev / 'of_node' / 'num_bytes').read_bytes())[0]}
                lmx_dict = {'spi_device' : _get_spidev_path(dev),
                            'compatible' : compatible}

    if lmk_devices == []:
        raise RuntimeError("SPI path not set. LMK not found on device tree. Issue with BSP.")
    if lmx_devices == []:
        raise RuntimeError("SPI path not set. LMX not found on device tree. Issue with BSP.") 

Right now I’m mostly focused on reading back the LMK. I looked at the LMK in the schematic (page 18) and it looks like it’s wired for SPI communication with RF_PLL_SDI, RF_PLL_SCLK, etc. My understanding is that chips are usually either on the SPI bus or on the I2C bus. How is the LMK accessible via I2C?

I searched my RFSoC4x2 for I2C devices and got this:

xilinx@pynq:/sys/bus$ i2cdetect -l
i2c-1	unknown   	Cadence I2C at ff030000         	N/A
i2c-2	unknown   	ZynqMP DP AUX                   	N/A
i2c-0	unknown   	Cadence I2C at ff020000         	N/A

Is one of those the LMK? Do you have a convenient way to read back these chips using either command line tools or Python packages?

I will check out J15 tomorrow during boot and programming and report back.


1 Like

Sorry Jenny.
All three chips are SPI. There is no I2C involved here. I was looking at a different schematic that did something like that. The LMK confused me because it does not have a dedicated MISO/SDO pin but instead uses one of its status pins.
I have been modifying the xrfclk package. I have added two functions that allow you to load from a specific file name instead of having to follow that chip_frequency.txt naming convention.
I plan on adding some readback capability so that one has the ability to do a _read_LMK_reg and _read_LMX_reg. We took a group vote that we’d still require power users to use TICs to make their files and limit our support to just writing and reading from the file for the synthesizers. If you want more fine grain than that, I would suggest a git repo that has enough functionality to replace the TICs file itself. This is the kit-ipq project and its repo is at:

I wish the TICs tool would have a solver feature so that I could give it the output frequencies I want and it would just solve all the other options for me or at least choose one with the least possible jitter and phase noise. The closest thing I have found is for the LMK04828B chip. It is to use the TI WebBench tool and it is located at this site:
You can tell the tool to only use the LMK04828B and LMX2594 and give it the set of frequencies you want to use. Then you have to go back and plug into TICs. However it seems to be very buggy, but at least the idea is promising.


1 Like

So from working with that TI WebBench Clock Architect, I have tried to put in to some output frequencies like 491.52 and 200MHz and 8 MHz and limit it to the LMK04828B so we handle that stage first. It is unable to find a VCO and settings that make that recipe. The RFSoC4x2 uses that 160MHz oscillator. One possibility is to use an external reference.
If I take the 8MHz out then it seems to find solutions so maybe that is just a limitation of the tool, but leads to a potential additional restriction on MTS usage because you have to be able to generate the PL_CLK and PL_SYSREFs from the LMK stage. Here is a screenshot of one solution the tool found:

So the tool will give you the VCO frequency you need and then the rest in TICs is just dividing it down from there in its various pull-down boxes and settings voltages etc. It won’t match our board exactly, but this is starting point to find a VCO frequency that will allow you to hit all the output frequencies you need. And it seems you have control of the status LEDs too so my TICs file has reversed it LOCKED status like you noticed earlier or that the LEDs go out. As you may notice by letting the tool choose from the latest parts, that there are better clock solutions now. So if a custom board is in the works, you would want to use this tool to find the best solution and even lower cost and power in the process.



1 Like

No worries–glad to confirm it’s all SPI. We have some code here to patch new clock files into the existing xrfclk infrastructure in case that’s of interest. We use that with a custom overlay loading function to set up the clocks.

def configure(bitstream, ignore_version=False, clocks=False, programming_key=False, download=True):
    import pynq

    if clocks:
        import mkidgen3.drivers.rfdc
        time.sleep(0.5)  # allow clocks to stabilize before loading overlay

    global _gen3_overlay
    ol = _gen3_overlay = pynq.Overlay(bitstream, ignore_version=ignore_version, download=download)
    getLogger(__name__).info(f"PL Bitfile: {pynq.PL.bitfile_name} ({ol.timestamp})  Loaded: {ol.is_loaded()}")

    return _gen3_overlay

Getting the config right in TICS pro can be challenging but I agree it’s totally appropriate to expect the user to create their own clock file. I have found you can change certain fields in TICs pro and it will propagate backwards but it’s not perfect. Thanks for that clock-tree-architect link–I have been looking for something like that! I started with just the LMK, requesting a 8 MHz SYSREF and 256 MHz clock (PL_CLK in MTS and the input for the LMX) and it seems able to solve it with a 2560 MHz VCO.

This agrees with what I have in TICs:

I also confirmed it can find a solution for the LMX to output the 409.6 MHz reference clocks configured in the RFDC given the 256 MHz input from the LMK

Despite all that I’m still seeing my LMK is outputting 7.69 - 7.8 MHz on the exposed clock and not 8 MHz… It will be great to use your readback capability in the next release so I can see if the chip is reporting anything unusual. I looked back in TICs and I didn’t see the LED config or where it was reversed in your file but that’s good to know. I’m still hopeful Texas Instruments is going to be able to find the issue but it’s nice to have as much debugging capability as possible on my end.



To address your original LMK read-back question, from the RFSoC 4x2 schematic

It looks like the SPI data out from the LMK chip isn’t connected to a data out pin, but to the LED. The two LMX chips seem to have some sort of SPI output properly connected.

From p97 of the LMK04828 datasheet it looks like the LD2 status led output could be configured for “SPI readback” rather than its default “PLL2 DLD” (digital lock detect). I haven’t gotten this to work yet, though.


I managed to get it working. I can read back the registers from SPI at the cost of turning the PLL2 LED into the SPI data readback and therefore mostly off. In the notebook below, I have a function to turn this readback on and then back off again at the end:

Toward the end of that notebook, I also managed to switch the default PYNQ xrfclk configuration to use an external 10 MHz input from a GPSDO. No TI TICS Pro windows programs requiring registration, download, install, and reboot.


Jason thanks for sharing these valuable insights.
If I may ask what is your purpose of feeding external 10MHz input to LMK04828?

My application is the calibration of radio telescope RF correlators and spectrometers. They are locked to a GPS-derived 10 MHz, so I’d like to lock to the same reference, especially at first for testing. Unlike in comms, I can’t rewrite the guts of the telescope back end to do any form of frequency offset correction.

I think I now managed to get the LMK to switch between the internal 10 MHz and my external 10 MHz GPSDO reference. It thinks it’s locked in both cases. However, I don’t see phase stability between the external 10 MHz reference and a computed 10 MHz signal that I transmit out of the DAC.

To get exactly 10 MHz out of the DAC, I made to make a small change to a parameter i in the MTS design. I don’t want to repeat myself for those following the RFSoC-MTS github issue 3, but I described what I did in a bit more detail there.


Great achievements! well done!