Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This page describes the process to program the Si5381 clock device on the Xilinx ZCU670 board.

Table of Contents

Table of Contents
excludeTable of Contents

Introduction

The ZCU670 board incorporates a Si5381 device for clock generation and the device is currently only programmed using the System Controller. The ability to program the Si5381 from an application or FSBL allows users improved system integration. At this time, Linux user space for run-time configuration is not supported but is being considered for the future.

Si5381 Details

The Si5381 is a complex device with many registers to be programmed. The ClockBuilder Pro tool, https://pages.silabs.com/clockbuilder-pro-software.html, allows a user to set up all of the clocks of the device and then create an output file with the register settings in a C header file. This generated header file can then be integrated into an application running on MPSoC to program the device. A set of four example header files based on specific clock configurations are provided for user integration such that using the ClockBuilder Pro tool is not required.

...

Header File Details

The ClockBuilder Pro tool can create a number of different file formats including a C header file. The following code snippet illustrates the format of the generated header file.

Code Block
/*
 * Si5381A Rev E Configuration Register Export Header File
 *
 * This file represents a series of Skyworks Si5381A Rev E 
 * register writes that can be performed to load a single configuration 
 * on a device. It was created by a Skyworks ClockBuilder Pro
 * export tool.
 *
 * Part:		                                       Si5381A Rev E
 * Design ID:                                          test1
 * Includes Pre/Post Download Control Register Writes: Yes
 * Created By:                                         ClockBuilder Pro v4.4 [2022-03-30]
 * Timestamp:                                          2022-07-08 13:49:41 GMT-05:00
 *
 * A complete design report corresponding to this export is included at the end 
 * of this header file.
 *
 */

#ifndef SI5381A_REVE_REG_CONFIG_HEADER
#define SI5381A_REVE_REG_CONFIG_HEADER

#define SI5381A_REVE_REG_CONFIG_NUM_REGS				832

typedef struct
{
	unsigned int address; /* 16-bit register address */
	unsigned char value; /* 8-bit register data */

} si5381a_reve_register_t;

si5381a_reve_register_t const si5381a_reve_registers[SI5381A_REVE_REG_CONFIG_NUM_REGS] =
{
	/* Start configuration preamble */
	{ 0x0B24, 0xC0 },
	{ 0x0B25, 0x04 },
	{ 0x0540, 0x01 },
	/* End configuration preamble */

	/* Delay 625 msec */
	/*    Delay is worst case time for device to complete any calibration */
	/*    that is running due to device state change previous to this script */
	/*    being processed. */

	/* Start configuration registers */
	{ 0x0006, 0x00 },
	{ 0x0007, 0x00 },
	
    ...

   	{ 0x0C0C, 0x00 },
	/* End configuration registers */

	/* Start configuration postamble */
	{ 0x0514, 0x01 },
	{ 0x001C, 0x01 },
	{ 0x0540, 0x00 },
	{ 0x0B24, 0xC3 },
	{ 0x0B25, 0x06 },
	/* End configuration postamble */
};

ZCU670 Details

As with many Xilinx boards, the ZCU760 incorporates a complex I2C bus structure which incorporates an I2C switch (U20) referred to as a multiplexer (Mux).

The I2C Mux must be setup prior to programming the Si5381 device. The following schematic snippet illustrates the Si5381 being the 2nd device (SD1/SC1) on the I2C Mux and using I2C bus 1 from MPSoC.

...

The following snippet from the Si5381 Reference Manual illustrates the I2C configuration.

...

Programming the Si5381

A bare metal application is provided which can be used for bare metal projects or incorporated into the FSBL. The application includes the header file that can be generated from the ClockBuilder Pro tool.

...

The following sub-paragraphs describe some significant areas of the source code.

ClockBuilder Pro Header File Integration

The source code includes a set of four different header files for different clock configurations. The user must alter the C source file to include the appropriate header file or any other generated header files. The following illustrates the default header file which is included.

Code Block
/* The following header file is the output from the ClockBuilder Pro tool
 * and is a custom name which must be altered when using new generated output.
 */
#include "Si5381A-zcu670_DAC-ADC-REFCLK_122M88_03302021-Registers.h"

I2C Board Details

The following code snippet illustrates the I2C details that might need to change for a custom board.

...

Code Block
	/* Initialize the I2C mux to allow access to the Si5381 device
	 * on the board.
	 */
	WriteBuffer[0U] = SI5381_MUXVAL;
	SlaveAddr = I2C_MUXADDR;
	Status = XIicPs_MasterSendPolled(&I2cInstance,
			WriteBuffer, 1U, SlaveAddr);
	if (Status != XST_SUCCESS) {
		print("SI5381 set MUX failure\n\r");
		return XST_FAILURE;
	}
	while (XIicPs_BusIsBusy(&I2cInstance) == TRUE);

	print("Si5381 MUX is set\n\r");

Si5381 Registers and Pages

The Si5381 device utilizes a paging scheme to allow all registers to be addressed. The page must be set in a separate command prior to reading or writing to a specific register. The function which writes to a register takes care of converting a register address to the appropriate page and register address.

Code Block
	/* Set the device Current Page (if needed) using the page command
	 * and wait for it to complete
	 */
	if (Page != LastPage || SlaveAddr != LastSlaveAddr ) {

		Buffer[0U] = PAGE_CMD;
		Buffer[1U] = (u8)Page;

#ifdef DEBUG
		print("Si5381 0x%x setting page to 0x%x\n\r", SlaveAddr, Buffer[1U]);
#endif
		Status = XIicPs_MasterSendPolled(I2cInstPtr,
				Buffer, PAGE_CMD_LEN, SlaveAddr);
		if (Status != XST_SUCCESS) {
			print("Si5381 0x%x Setting page %d failed\n\r", SlaveAddr, Buffer[1U]);
			return XST_FAILURE;
		}
		while (XIicPs_BusIsBusy(I2cInstPtr) == TRUE);

		/* Keep track of the last page and slave address used so they
		 * can be set if they are different on the next pass
		 */
		LastPage = Page;
		LastSlaveAddr = SlaveAddr;
	}

Header File Data Processing

The ClockBuilder Pro header file included with the C source file provides the data structures that the function uses to read/write to the device registers. There is a point in the data where there is an expected time delay which is at a fixed location and handled as an exception to the normal flow.

...

Code Block
	for (i = 0; i < (sizeof(si5381a_reve_registers)/sizeof(si5381a_reve_register_t)); i++) {
#ifdef DEBUG
		print("Si5381 %d writing address 0x%x = 0x%x\n\r",
				i, si5381a_reve_registers[i].address, si5381a_reve_registers[i].value);
#endif
		Status = WriteSi538xRegister(&I2cInstance, SlaveAddr,
										si5381a_reve_registers[i].address,
										(u8 *)&si5381a_reve_registers[i].value,	1);
		if (Status != XST_SUCCESS) {
			print("Si5381 Register write failure\r\n");
			return XST_FAILURE;
		}

		/* Based on the comments in the header file a time delay is needed after the
		 * preamble
		 */
		if (i == PREAMBLE_SIZE - 1)
			usleep (625 * ONE_MS_IN_USEC);

	}

System Integration

The provided source code can be built into a bare metal application which is started by the FSBL or it can be incorporated into the FSBL. The FSBL can be built in Vitis as shown at Zynq UltraScale+ FSBL. The ProgramSi5381() function is called from the XFsbl_HookBeforeHandoff() function of the FSBL such that the code runs last in FSBL. The following code snippet illustrates the changes required to incorporate it into the xfsbl_hooks.c source file of the FSBL.

Code Block
u32 XFsbl_HookBeforeHandoff(u32 EarlyHandoff)
{
	u32 Status = XFSBL_SUCCESS;

	ProgramSi5381();

	return Status;
}

Source Code

The source code for this project is provided in the zcu670-si5381 directory of https://github.com/Xilinx-Wiki-Projects/software-prototypes.