/****************************************************************************** * File Name : si5351.h * Description : STM32 library/driver for the Si5351 clock chip * from Skyworks Solutions, Inc. (former SiLabs) ****************************************************************************** * @author: Thomas Kuschel KW4NZ, created 2022-05-11 * * originally written by Petr Polasek, created Feb 16, 2018 ****************************************************************************** * DO NOT EDIT THIS FILE FOR CONFIGURATION, USE THE FOLLOWING PROCEDURE: * * Inside your main.c program or within your STM32 code: * Include this header to the the main.c: #include "si5351.h" * You've to initialize the I2C functionality first (e.g. with STM32CubeIDE) * Afterwards, when there is a handle like "I2C_HandleTypeDef hi2c1;", * you simply initialize this si5351 library in your main.c , * just after the MX_I2C1_Init(); * so between the USER CODE like using the given i2c handle "hi2c1" with default values: * * /\* USER CODE BEGIN 2 *\/ * * si5351_inst_t si5351_inst; * si5351_initialize(&hi2c1); * * /\* USER CODE END 2 *\/ * * The 7-bit device (slave) address of the Si5351 consist of a 6-bit fixed * address plus a user selectable LSB bit as shown in Figure 6 of the datasheet. * The LSB bit is selectable as 0 or 1 using the optional A0 pin which is useful * for applications that require more than one Si5351 on a single I2C bus. * Only the Si5351A 20-QFN and Si5351A 16-QFN have the A0 LSB pin option. * If a part does not have the A0 pin, the default address is 0x60 with * the A0 bit set to 0. * * So additionally you may drive more then one Si5351 at the same or * another I2C bus when calling the init function with the given * I2C bus address (default: 0x60) * ( - internally this I2C address is shifted to the left * for the proper usage of the I2C HAL driver i.e. it becomes 0xC0 ) * * Example: * /\* Define handlers for the sum of three SI5351 clock generators: *\/ * si5351_HandleTypeDef hsi5351[3]; * * /\* 1st SI5351 chip and with an A0 = 0: *\/ * hsi5351[0] = si5351_init(&hi2c1, 0x60, 25000000); * /\* 2nd SI5351 chip on the same I2C bus "hi2c1" but address line A0 = 1 *\/ * hsi5351[1] = si5351_init(&hi2c1, 0x61, 27000000); * /\* 3rd SI5351 chip on another IC2 bus with handle "hi2c2" *\/ * hsi5351[2] = si5351_init(&hi2c2, 0x60, 25000000); * * PROs: * The library is preemptive and can be used within an operating system. * All structures and used variables are dynamically allocated. * CONs: * Not fully tested. * Tested with FreeRTOS and with 2 I2C bus systems. * * CHANGES: * - Removed several defines, enums, etc. from the header file, b/c we do not * want to export them to other programs ******************************************************************************/ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __SI5351_H__ #define __SI5351_H__ #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ /* #include could also be included */ /* Private includes ----------------------------------------------------------*/ /* @brief SI5351 synthesis settings */ typedef struct { uint32_t pll_multiplier; /*!< corresponds to feedback multisynth (N) a */ uint32_t pll_numerator; /*!< corresponds to feedback multisynth (N) b */ uint32_t pll_denominator; /*!< corresponds to feedback multisynth (N) c */ uint32_t out_multiplier; /*!< corresponds to multisynth (M) a */ uint32_t out_numerator; /*!< corresponds to multisynth (M) b */ uint32_t out_denominator; /*!< corresponds to multisynth (M) c */ uint8_t out_r_divider; /*!< R divider, log2 value bit set to 1; 2,4,8,...,128; for frequencies < 500 kHz, otherwise set to 1 i.e. bit 0 */ } synthesis_t; /* Exported types ------------------------------------------------------------*/ /*!< Si5351 instance typedef -- handle as pointer */ typedef struct __SI5351_HandleTypeDef *si5351_inst_t; /* Exported constants --------------------------------------------------------*/ /** @enum errno_t Error Number Constants, @TODO you can also include */ #if !defined _SYS_ERRNO_H_ && !defined __ERRNO_H__ && !defined __AT1_ERROR_NUMBERS__ typedef enum { EPERM = 1, /*!< Operation not permitted */ EIO = 5, /*!< I/O error */ ENOMEM = 12, /*!< Out of memory */ EFAULT = 14, /*!< Bad address */ EBUSY = 16, /*!< Device or resource busy */ ENODEV = 19, /*!< No such device */ EINVAL = 22, /*!< Invalid argument */ EADDRINUSE = 98,/*!< Address already in use */ ETIMEDOUT = 116 /*!< Connection timed out */ } si5351_errno_t; #endif typedef enum { SI5351_PLLA = 0, SI5351_PLLB }si5351_pll_t; /* Exported variables --------------------------------------------------------*/ /* Exported macros -----------------------------------------------------------*/ #define __SI5351__ 1 #define __SI5351_MINOR__ 2 #define __SI5351_PATCHLEVEL__ 0 #define SI5351_VERSION (__SI5351__ * 10000 \ + __SI5351_MINOR__ * 100 \ + __SI5351_PATCHLEVEL__) #ifndef SI5351_DEFAULTS #define SI5351_DEFAULTS 1 #define SI5351_I2C_ADDR_DEFAULT 0x60 #define SI5351_XTAL_DEFAULT 25000000u /* default xtal frequency in [Hz] */ #define SI5351_NUMBER_OF_OUTPUTS 8 #endif /* Exported functions --------------------------------------------------------*/ #if SI5351_DEFAULTS si5351_inst_t si5351_initialize(void * i2c_handle); int si5351_deinitialize(void); #endif si5351_inst_t si5351_init(void * i2c_handle, uint8_t i2c_address, uint32_t xtal_frequency); int si5351_deinit(si5351_inst_t si5351_handle); int si5351_i2c_ready(si5351_inst_t inst); int si5351_enable_output(si5351_inst_t inst, uint8_t clk); int si5351_disable_output(si5351_inst_t inst, uint8_t clk); int si5351_set_clk0(si5351_inst_t inst, uint32_t frequency); int si5351_set_clk(si5351_inst_t inst, uint8_t clk, uint32_t frequency, si5351_pll_t pll); int si5351_set_frequency(si5351_inst_t inst, uint32_t frequency); char * si5351_read_debug_msg(si5351_inst_t inst); char * si5351_read_register_debug(si5351_inst_t inst, char *buf, size_t bufsize, uint8_t regaddr); /* some functions for getting information */ int si5351_get_instance(si5351_inst_t *inst); int si5351_get_i2c_address(si5351_inst_t inst); void* si5351_get_i2c_handle(si5351_inst_t inst); uint32_t si5351_get_frequency(si5351_inst_t inst); uint32_t si5351_get_xtal(si5351_inst_t inst); synthesis_t si5351_calculation(uint32_t frequency, uint32_t xtal); /* under development */ int si5351_set_clk_phase(si5351_inst_t inst, uint8_t clk, uint32_t frequency, double phase, si5351_pll_t pll); int si5351_set_phase(si5351_inst_t inst, uint8_t clk, uint8_t phase); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* __SI5351_H__ */