/* * si5351.h * * Created on: Feb 16, 2018 * Author: Petr Polasek * * To make this library useable on any other device than * STM32Fxxx Cortex Mx, please edit these parts of the library: * * DEFINES: * SI5351_I2C_PERIPHERAL - the I2C peripheral name according * to your devices HAL library * I2C_TIMEOUT - time for the communication to time out * * TYPEDEFS: * Si5351_ConfigTypeDef - the I2Cx parameter should be changed * so that its type corresponds to your HAL library * * FUNCTIONS: * Si5351_WriteRegister * Si5351_ReadRegister * You need to write your own I2C handlers here * */ #ifndef SI5351_H_ #define SI5351_H_ #include "stm32l4xx_hal.h" #define SI5351_I2C_ADDRESS 0xC0 //default I2C address of Si5351 #define SI5351_I2C_PERIPHERAL I2C1 //default I2C interface #define SI5351_XTAL_FREQ 25000000 // sets default value, 25000000 for 25 MHz, 27000000 for 27 MHz #define SI5351_CLKIN_FREQ 0 // set in Hz #ifdef I2C_TIMEOUT #undef I2C_TIMEOUT #endif #define I2C_TIMEOUT 100000 //I2C timeout for wait loops #define SI5351_TIMEOUT (I2C_TIMEOUT * 10) #ifndef ENABLESTATE #define ENABLESTATE typedef enum { OFF = 0, ON = 1 } EnableState; #endif /* * This section contains register addresses and bit masks for * the device status registers. */ #define REG_DEV_STATUS 0 #define DEV_SYS_INIT_MASK 0x80 #define DEV_LOL_B_MASK 0x40 #define DEV_LOL_A_MASK 0x20 #define DEV_LOS_CLKIN_MASK 0x10 #define DEV_LOS_XTAL_MASK 0x08 #define DEV_REVID_MASK 0x03 #define REG_DEV_STICKY 1 #define DEV_STKY_SYS_INIT_MASK 0x80 #define DEV_STKY_LOL_B_MASK 0x40 #define DEV_STKY_LOL_A_MASK 0x20 #define DEV_STKY_LOS_CLKIN_MASK 0x10 #define DEV_STKY_LOS_XTAL_MASK 0x08 #define REG_INT_MASK 2 #define INT_MASK_SYS_INIT_MASK 0x80 #define INT_MASK_LOL_B_MASK 0x40 #define INT_MASK_LOL_A_MASK 0x20 #define INT_MASK_LOS_CLKIN_MASK 0x10 #define INT_MASK_LOS_XTAL_MASK 0x08 /* * This section contains data structures for configuring the * oscillator, VCXO and CLKIN section. */ #define REG_XTAL_CL 183 #define XTAL_CL_MASK 0xC0 #define PLL_CL_MASK 0x36 //this sets the crystal load capacitance typedef enum { XTAL_Load_4_pF = 0x00, XTAL_Load_6_pF = 0x40, XTAL_Load_8_pF = 0x80, XTAL_Load_10_pF = 0xC0 } Si5351_XTALLoadTypeDef; //The following is an unexplained parameter. However someone from SiLabs called it "VCO load cap". //Lower settings seem to be more stable on higher frequencies, higher settings are more stable on lower frequencies allowing to tune the PLL to <200 MHz. typedef enum { PLL_Capacitive_Load_0 = 0, PLL_Capacitive_Load_1 = 1, PLL_Capacitive_Load_2 = 2 } Si5351_PLLCapacitiveLoadTypeDef; #define REG_CLKIN_DIV 15 #define CLKIN_MASK 0xC0 //this sets the CLKIN pre-divider, after division, CLKIN should //fall between 10-40 MHz typedef enum { CLKINDiv_Div1 = 0x00, CLKINDiv_Div2 = 0x40, CLKINDiv_Div4 = 0x80, CLKINDiv_Div8 = 0xC0 } Si5351_CLKINDivTypeDef; #define REG_FANOUT_EN 187 #define FANOUT_CLKIN_EN_MASK 0x80 #define FANOUT_XO_EN_MASK 0x40 #define FANOUT_MS_EN_MASK 0x10 #define REG_VCXO_PARAM_0_7 162 #define REG_VCXO_PARAM_8_15 163 #define REG_VCXO_PARAM_16_21 164 #define VCXO_PARAM_16_21_MASK 0x3F #define VCXO_PARAM_MASK 0x003FFFFF #define APR_MINIMUM 30 //minimum pull range #define APR_MAXIMUM 240 //maximum pull range #define CLKIN_MINIMUM 10000 //minimum CLKIN frequency after division in kHz #define CLKIN_MAXIMUM 40000 //maximum CLKIN frequency after division in kHz typedef struct { Si5351_XTALLoadTypeDef OSC_XTAL_Load; //capacitive load of XTAL, 10pF by default Si5351_CLKINDivTypeDef CLKIN_Div; //CLKIN predivision, input f to PLL must be 10-40 MHz uint8_t VCXO_Pull_Range_ppm; //can range from +-30 ppm to 240ppm } Si5351_OSCConfigTypeDef; /* * This section contains data structures for configuring the * PLL (PLLA and PLLB) */ #define REG_PLL_CLOCK_SOURCE 15 #define PLLA_CLOCK_SOURCE_MASK 0x04 #define PLLB_CLOCK_SOURCE_MASK 0x08 //this selects the clock source for the PLL typedef enum { PLL_Clock_Source_XTAL = 0x00, PLL_Clock_Source_CLKIN = 0x0C //0x04 for PLLA, 0x08 for PLLB, use mask! } Si5351_PLLClockSourceTypeDef; #define REG_FB_INT 22 #define FB_INT_MASK 0x40 #define REG_PLL_RESET 177 #define PLLA_RESET_MASK 0x20 #define PLLB_RESET_MASK 0x80 #define REG_MSN_P1_0_7 30 #define REG_MSN_P1_8_15 29 #define REG_MSN_P1_16_17 28 #define MSN_P1_16_17_MASK 0x03 #define REG_MSN_P2_0_7 33 #define REG_MSN_P2_8_15 32 #define REG_MSN_P2_16_19 31 #define MSN_P2_16_19_MASK 0x0F #define REG_MSN_P3_0_7 27 #define REG_MSN_P3_8_15 26 #define REG_MSN_P3_16_19 31 #define MSN_P3_16_19_MASK 0xF0 #define MSNA_MSNB_OFFSET 8 typedef struct { uint32_t PLL_Multiplier_Integer; uint32_t PLL_Multiplier_Numerator; uint32_t PLL_Multiplier_Denominator; Si5351_PLLClockSourceTypeDef PLL_Clock_Source; Si5351_PLLCapacitiveLoadTypeDef PLL_Capacitive_Load; } Si5351_PLLConfigTypeDef; /* * This section contains data structures for configuring the * Spread Spectrum feature. */ #define REG_SSC_MODE 151 #define SSC_MODE_MASK 0x80 //this selects the Spread Spectrum mode typedef enum { SS_Mode_DownSpread = 0x00, SS_Mode_CenterSpread = 0x80 } Si5351_SSModeTypeDef; typedef enum { SS_NCLK_0 = 0x00, SS_NCLK_1 = 0x10, SS_NCLK_2 = 0x20, SS_NCLK_3 = 0x30, SS_NCLK_4 = 0x40, SS_NCLK_5 = 0x50, SS_NCLK_6 = 0x60, SS_NCLK_7 = 0x70, SS_NCLK_8 = 0x80, SS_NCLK_9 = 0x90, SS_NCLK_10 = 0xA0, SS_NCLK_11 = 0xB0, SS_NCLK_12 = 0xC0, SS_NCLK_13 = 0xD0, SS_NCLK_14 = 0xE0, SS_NCLK_15 = 0xF0 } Si5351_SSNCLKTypeDef; #define REG_SSDN_P1_0_7 153 #define REG_SSDN_P1_8_11 154 #define SSDN_P1_8_11_MASK 0x0F #define REG_SSDN_P2_0_7 150 #define REG_SSDN_P2_8_14 149 #define SSDN_P2_8_14_MASK 0x7F #define REG_SSDN_P3_0_7 152 #define REG_SSDN_P3_8_14 151 #define SSDN_P3_8_14_MASK 0x7F #define REG_SSUDP_0_7 155 #define REG_SSUDP_8_11 154 #define SSUDP_8_11_MASK 0xF0 #define REG_SSUP_P1_0_7 160 #define REG_SSUP_P1_8_11 161 #define SSUP_P1_8_11_MASK 0x0F #define REG_SSUP_P2_0_7 157 #define REG_SSUP_P2_8_14 156 #define SSUP_P2_8_14_MASK 0x7F #define REG_SSUP_P3_0_7 159 #define REG_SSUP_P3_8_14 158 #define SSUP_P3_8_14_MASK 0x7F #define REG_SSC_EN 149 #define SSC_EN_MASK 0x80 #define REG_SS_NCLK 161 #define SS_NCLK_MASK 0xF0 typedef struct { uint32_t SS_Amplitude_ppm; //amplitude of the SS feature in ppm of center frequency EnableState SS_Enable; Si5351_SSModeTypeDef SS_Mode; Si5351_SSNCLKTypeDef SS_NCLK; } Si5351_SSConfigTypeDef; /* * This section contains data structures for configuring the * Output Multisynth. */ //this selects the Multisynth clock source typedef enum { MS_Clock_Source_PLLA = 0x00, MS_Clock_Source_PLLB = 0x20 } Si5351_MSClockSourceTypeDef; #define REG_MS_P1_0_7 46 #define REG_MS_P1_8_15 45 #define REG_MS_P1_16_17 44 #define MS_P1_16_17_MASK 0x03 #define REG_MS_P2_0_7 49 #define REG_MS_P2_8_15 48 #define REG_MS_P2_16_19 47 #define MS_P2_16_19_MASK 0x0F #define REG_MS_P3_0_7 43 #define REG_MS_P3_8_15 42 #define REG_MS_P3_16_19 47 #define MS_P3_16_19_MASK 0xF0 #define REG_MS67_P1 90 #define REG_MS_INT 16 #define MS_INT_MASK 0x40 #define REG_MS_DIVBY4 44 #define MS_DIVBY4_MASK 0x0C #define REG_MS_SRC 16 #define MS_SRC_MASK 0x20 #define MS_SETUP_STEP 1 #define MS_DIVIDER_STEP 8 typedef struct { Si5351_MSClockSourceTypeDef MS_Clock_Source; //select source on MS input uint32_t MS_Divider_Integer; //the integer part of divider, called "a" uint32_t MS_Divider_Numerator; //the numerator, called "b" uint32_t MS_Divider_Denominator; //the denominator, called "c" } Si5351_MSConfigTypeDef; //sets MS divider ( a+(b/c) ) and clock (PLLA/PLLB) /* * This section contains data structures for configuring the * CLK, R divider and output stage (joined together because they make * a tight block without any multiplexer). */ #define REG_CLK_SRC 16 #define CLK_SRC_MASK 0x0C //this sets the CLK source clock typedef enum { CLK_Clock_Source_XTAL = 0x00, CLK_Clock_Source_CLKIN = 0x04, CLK_Clock_Source_MS0_MS4 = 0x08, //this uses MS0 for CLK0..3 and MS4 for CLK4..7 CLK_Clock_Source_MS_Own = 0x0C //this uses MSx for CLKx } Si5351_CLKClockSourceTypeDef; //configures multiplexer on CLK input #define REG_CLK_R_DIV 44 #define CLK_R_DIV_MASK 0x70 #define REG_CLK_R67_DIV 92 #define CLK_R67_DIV_MASK 0x07 //this sets the R divider ratio typedef enum { CLK_R_Div1 = 0x00, CLK_R_Div2 = 0x10, CLK_R_Div4 = 0x20, CLK_R_Div8 = 0x30, CLK_R_Div16 = 0x40, CLK_R_Div32 = 0x50, CLK_R_Div64 = 0x60, CLK_R_Div128 = 0x70 } Si5351_CLKRDivTypeDef; #define REG_CLK_DIS_STATE 24 #define CLK_DIS_STATE_MASK 0x03 //this sets output buffer behaviour when disabled typedef enum { CLK_Disable_State_LOW = 0x00, CLK_Disable_State_HIGH = 0x01, CLK_Disable_State_HIGH_Z = 0x02, //three-stated when off CLK_Disable_State_ALWAYS_ON = 0x03 //cannot be disabled } Si5351_CLKDisableStateTypeDef; #define REG_CLK_IDRV 16 #define CLK_IDRV_MASK 0x03 //this sets current drive of the output buffer typedef enum { CLK_I_Drv_2mA = 0x00, CLK_I_Drv_4mA = 0x01, CLK_I_Drv_6mA = 0x02, CLK_I_Drv_8mA = 0x03 } Si5351_CLKIDrvTypeDef; #define REG_CLK_PHOFF 165 #define CLK_PHOFF_MASK 0x7F #define REG_CLK_EN 3 #define REG_CLK_INV 16 #define CLK_INV_MASK 0x10 #define REG_CLK_PDN 16 #define CLK_PDN_MASK 0x80 #define REG_CLK_OEB 9 #define CLK_PHOFF_STEP 1 #define CLK_SETUP_STEP 1 #define CLK_R_DIV_STEP 8 typedef struct { Si5351_CLKClockSourceTypeDef CLK_Clock_Source; //clock source /* this sets the time offset of the CLK channel, basic unit * is one quarter of the VCO period (90deg offset), * set it to 4*fVCO*toffset, the value is 7-bit, the max time offset * varies between 35 and 53 ns (1 cycle for 28 and 19 MHz, respectively) * according to the current frequency of the VCO */ uint8_t CLK_QuarterPeriod_Offset; Si5351_CLKRDivTypeDef CLK_R_Div; //R divider value (only powers of 2) EnableState CLK_Invert; //invert output clock EnableState CLK_Enable; //enable flag EnableState CLK_PowerDown; //powerdown flag Si5351_CLKDisableStateTypeDef CLK_Disable_State; //sets output behaviour when disabled Si5351_CLKIDrvTypeDef CLK_I_Drv; //output driver current drive strength EnableState CLK_Use_OEB_Pin; //allows using OEB pin to enable clock } Si5351_CLKConfigTypeDef; /* * This section contains main data structure for Si5351 configuration */ typedef struct { /* * These are frequencies of the input clocks, set it in Hz. */ uint32_t f_XTAL; uint32_t f_CLKIN; //Interrupt masking - enabling it disables the int source from pulling INTR low EnableState Interrupt_Mask_SysInit; EnableState Interrupt_Mask_PLLB; EnableState Interrupt_Mask_PLLA; EnableState Interrupt_Mask_CLKIN; EnableState Interrupt_Mask_XTAL; //Fanout enable - enables internal clock routing EnableState Fanout_MS_EN; EnableState Fanout_XO_EN; EnableState Fanout_CLKIN_EN; I2C_TypeDef *I2Cx; //the I2C interface that will be used uint8_t HW_I2C_Address; //I2C address of the Si5351 for the packages with A0 pin //(also, some duds with strange address reported) Si5351_OSCConfigTypeDef OSC; //Oscillator, CLKIN and VCXO settings Si5351_PLLConfigTypeDef PLL[2]; //PLL settings for PLLA and PLLB Si5351_MSConfigTypeDef MS[8]; //MultiSynth[0..7] settings Si5351_CLKConfigTypeDef CLK[8]; //CLK[0..7], R divider and output stage settings Si5351_SSConfigTypeDef SS; //spread spectrum settings } Si5351_ConfigTypeDef; /* * Typedefs for selecting PLL, MS and CLK to be used */ //this selects PLL channel typedef enum { PLL_A = 0, PLL_B = 1 } Si5351_PLLChannelTypeDef; //this selects Multisynth channel typedef enum { MS0 = 0, MS1 = 1, MS2 = 2, MS3 = 3, MS4 = 4, MS5 = 5, MS6 = 6, MS7 = 7 } Si5351_MSChannelTypeDef; //this selects CLK channel typedef enum { CLK0 = 0, CLK1 = 1, CLK2 = 2, CLK3 = 3, CLK4 = 4, CLK5 = 5, CLK6 = 6, CLK7 = 7 } Si5351_CLKChannelTypeDef; //this selects device status flag typedef enum { StatusBit_SysInit = DEV_SYS_INIT_MASK, StatusBit_PLLA = DEV_STKY_LOL_A_MASK, StatusBit_PLLB = DEV_LOL_B_MASK, StatusBit_CLKIN = DEV_LOS_CLKIN_MASK, StatusBit_XTAL = DEV_LOS_XTAL_MASK, } Si5351_StatusBitTypeDef; //these write to and read from a Si5351 register, for porting //purposes, these functions should be the only ones which should need edits int Si5351_WriteRegister(Si5351_ConfigTypeDef *Si5351_ConfigStruct, uint8_t reg_address, uint8_t reg_data); uint8_t Si5351_ReadRegister(Si5351_ConfigTypeDef *Si5351_ConfigStruct, uint8_t reg_address); void Si5351_StructInit(Si5351_ConfigTypeDef *Si5351_ConfigStruct); void Si5351_OSCConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct); EnableState Si5351_CheckStatusBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit); EnableState Si5351_CheckStickyBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit); void Si5351_InterruptConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct); void Si5351_ClearStickyBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit); void Si5351_PLLConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_PLLChannelTypeDef PLL_Channel); void Si5351_PLLReset(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_PLLChannelTypeDef PLL_Channel); void Si5351_PLLSimultaneousReset(Si5351_ConfigTypeDef *Si5351_ConfigStruct); void Si5351_SSConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct); void Si5351_MSConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_MSChannelTypeDef MS_Channel); void Si5351_CLKPowerCmd(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_CLKChannelTypeDef CLK_Channel); void Si5351_CLKConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_CLKChannelTypeDef CLK_Channel); int Si5351_Init(Si5351_ConfigTypeDef *Si5351_ConfigStruct); #endif /* SI5351_H_ */