This article introduces how to configure the LMK04828 chip using the SPI bus on the ARM core of the Zynq platform. The basic steps are: first establish a Zynq project, configure the SPI bus constraints, then use the LMK04828_Config_Cal program to calculate register values, and finally use the SPI bus to download the register values into the LMK04828 chip. The following will use IW-RFSOC-2T2R as an example to demonstrate the configuration process.
Create a new Vivado project and add a "Zynq UltraScale+ MPSoC" instance to the "Block Design". First configure DDR and other settings according to the documentation. If you are using the IW-RFSOC-2T2R board, you can refer to the "Quick Start" tutorial for basic configuration.
After configuration, enable a SPI interface as shown in the figure below. If LMK04828 is directly connected to the PS side, please make the corresponding configuration. The board used here connects SPI to the PL side, so I choose "EMIO".

Export the "SPI_0" interface as shown in the figure.

Add corresponding constraints. Here we use the IW-RFSOC-2T2R board as an example.
set_property PACKAGE_PIN A10 [get_ports lmk_spi_ss_io]
set_property PACKAGE_PIN G11 [get_ports lmk_spi_sck_io]
set_property PACKAGE_PIN B11 [get_ports lmk_spi_io0_io]
set_property PACKAGE_PIN E12 [get_ports lmk_spi_io1_io]
set_property IOSTANDARD LVCMOS33 [get_ports lmk_spi_io0_io]
set_property IOSTANDARD LVCMOS33 [get_ports lmk_spi_io1_io]
set_property IOSTANDARD LVCMOS33 [get_ports lmk_spi_sck_io]
set_property IOSTANDARD LVCMOS33 [get_ports lmk_spi_ss_io]
set_property SLEW FAST [get_ports lmk_spi_io0_io]
set_property SLEW FAST [get_ports lmk_spi_io1_io]
set_property SLEW FAST [get_ports lmk_spi_sck_io]
set_property SLEW FAST [get_ports lmk_spi_ss_io]
Use the project generated above, create an initial project using the "Hello World" template in Vitis, and copy all files from LMK04828_Config_Cal into the "src" folder.
Before the "main" function, add header files, function and variable definitions.
#include "xspips.h"
#include "LMK_ClockTree.h"
static XSpiPs SPI_inst;
#define SPI_DEVICE_ID XPAR_XSPIPS_0_DEVICE_ID
static int SpiPsInit(XSpiPs *SpiInstancePtr, u16 SpiDeviceId);
Add the SPI interface initialization function:
int SpiPsInit(XSpiPs *SpiInstancePtr, u16 SpiDeviceId)
{
int Status;
XSpiPs_Config *SpiConfig;
/*
* Initialize the SPI driver so that it's ready to use
*/
SpiConfig = XSpiPs_LookupConfig(SpiDeviceId);
if (NULL == SpiConfig) {
return XST_FAILURE;
}
Status = XSpiPs_CfgInitialize(SpiInstancePtr, SpiConfig,
SpiConfig->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Perform a self-test to check hardware build
*/
Status = XSpiPs_SelfTest(SpiInstancePtr);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Set the Spi device as a master. External loopback is required.
*/
XSpiPs_SetOptions(SpiInstancePtr, XSPIPS_MASTER_OPTION |
XSPIPS_FORCE_SSELECT_OPTION);
XSpiPs_SetClkPrescaler(SpiInstancePtr, XSPIPS_CLK_PRESCALE_64);
return XST_SUCCESS;
}
In the "main" function, add the SPI interface initialization code as follows:
int Status;
Status = SpiPsInit(&SPI_inst, SPI_DEVICE_ID);
if (Status != XST_SUCCESS)
{
return XST_FAILURE;
}
For the IW-RFSOC-2T2R board, you can first modify the configuration in "LMK_Preset.h" as shown below. The corresponding fixed configuration has been preset.
//#define LMK_PRESET_NONE
#define LMK_PRESET_IW_RFSOC_2T2R_INTERNAL
//#define LMK_PRESET_IW_RFSOC_2T2R_EXTERNAL
Add the following content in the "main" function to implement configuration calculation and configuration.
LMK_Config LMK_inst;
LMK_Simple LMK_simple;
// Set reference clock rate
LMK_simple.RefClockRate = 30720000;
// Set expected VCO clock rate
LMK_simple.VCOXClockRate = 122880000;
// Set SYSREF
LMK_simple.SYSREFRate = 7680000;
// DClockRate[n] for DCLKout(2n), the SDCLKout(2n+1) are all set to SYSREF
LMK_simple.DClockRate[0] = 491520000;
LMK_simple.DClockRate[1] = 491520000;
LMK_simple.DClockRate[2] = 491520000;
LMK_simple.DClockRate[3] = 0;
LMK_simple.DClockRate[4] = 0;
LMK_simple.DClockRate[5] = 0;
LMK_simple.DClockRate[6] = 0;
// Config the interface instance for LMK
LMK_simple.InterfaceInst = &SPI_inst;
// Generate config using LMK_simple
LMK_ConfigMake(&LMK_inst, &LMK_simple);
// Download to LMK
LMK_Init(&LMK_inst);