diff --git a/include/si5351_driver.h b/include/si5351_driver.h index 05f7b53..6424e05 100644 --- a/include/si5351_driver.h +++ b/include/si5351_driver.h @@ -52,24 +52,72 @@ typedef enum { SI5351_CLK_SOURCE_XTAL = 0, SI5351_CLK_SOURCE_CLOCKSOURCE = 1, - - }si5351_ClkSource; +typedef enum { + + SI5351_CRYSTAL_LOAD_6PF = (1 << 6), + SI5351_CRYSTAL_LOAD_8PF = (2 << 6), + SI5351_CRYSTAL_LOAD_10PF = (3 << 6) + +}si5351_Xtal_Cload; + typedef enum { SI5351_PLL_A = 0, SI5351_PLL_B = 1, - - }si5351_PLLs; typedef enum { + SI5351_OUTPUT_0 = 0, + SI5351_OUTPUT_1 = 1, + SI5351_OUTPUT_2 = 2, + SI5351_OUTPUT_3 = 3, + SI5351_OUTPUT_4 = 4, + SI5351_OUTPUT_5 = 5, + SI5351_OUTPUT_6 = 6, + SI5351_OUTPUT_7 = 7, + +}si5351_Outputs; + +typedef enum { + + SI5351_OUTPUT_ENABLE = 0, + SI5351_OUTPUT_DISABLE = 1, + + +}si5351_Outputs_state; + +typedef enum { + SI5351_CLK_POWER_UP = 0, + SI5351_CLK_POWER_DWN = 1, + + +}si5351_CLK_PDN; + +typedef enum { + + SI5351_REG_OUTPUT_ENABLE_CONTROL = 3, SI5351_REG_PLL_INPUT_SOURCE = 0xf0, // Reg 15 - SI5351_REG_MULTISYNTH_NA_0 = 29, + SI5351_REG_CLK_0_CONTROL = 16, + SI5351_REG_CLK_1_CONTROL = 17, + SI5351_REG_CLK_2_CONTROL = 18, + SI5351_REG_CLK_3_CONTROL = 19, + SI5351_REG_CLK_4_CONTROL = 20, + SI5351_REG_CLK_5_CONTROL = 21, + SI5351_REG_CLK_6_CONTROL = 22, + SI5351_REG_CLK_7_CONTROL = 23, + + SI5351_REG_MULTISYNTH_NA_0 = 26, SI5351_REG_MULTISYNTH_NB_0 = 34, + SI5351_REG_MULTISYNTH_OUT_0 = 42, + SI5351_REG_MULTISYNTH_OUT_1 = 50, + SI5351_REG_PLL_RESET = 177, + + SI5351_REG_CRYSTAL_LOAD_CAPACITANCE = 183, + @@ -216,6 +264,14 @@ typedef struct { uint8_t MS7_P1; } __attribute__((packed))si5351_multiSynth7Parameters_t; +typedef struct { + uint8_t Reserved_0 : 5; + uint8_t PLLA_RST : 1; + uint8_t Reserved_1 : 1; + uint8_t PLLB_RST : 1; + +} __attribute__((packed))si5351_PLL_Reset_t; + typedef struct{ si5351_deviceStat_t deviceStatus; // 0x00 @@ -255,6 +311,10 @@ typedef struct{ si5351_OutputDivide R7_DIV : 3; uint8_t Reserved_1 : 1; + si5351_PLL_Reset_t PLL_Reset; + + + @@ -274,7 +334,13 @@ int cm_si5351_init(si5351_driver *inst, void *i2c_transfer_inst, setGet_I2C_Even uint8_t cm_si5351_getRevisionNumber(si5351_driver *inst); int cm_setInputSource(si5351_driver *inst, si5351_ClkSource clk_source); int cm_setPLLParameters(si5351_driver *inst,si5351_PLLs sel_pll, uint32_t a, uint32_t b, uint32_t c); +int cm_setOutputMultiSynth(si5351_driver *inst,si5351_Outputs clk_output, uint32_t d, uint32_t e, uint32_t f); +int cm_setOutputEnable(si5351_driver *inst,si5351_Outputs clk_output, si5351_Outputs_state outputState); +int cm_setCLKControl(si5351_driver *inst, si5351_Outputs clk_output, si5351_CLK_PDN clk_pdn); +int cm_resetPLLs(si5351_driver *inst, uint8_t reset_PLLA, uint8_t reset_PLLB); +int cm_setPllParamRaw(si5351_driver *inst, si5351_PLLs sel_pll, uint32_t MSNx_P1, uint32_t MSNx_P2, uint32_t MSNx_P3); #endif /* SI5351_DRIVER_INCLUDE_SI5351_DRIVER_H_ */ + diff --git a/si5351_driver.c b/si5351_driver.c index 81457e1..73b31b0 100644 --- a/si5351_driver.c +++ b/si5351_driver.c @@ -2,9 +2,12 @@ * si5351_driver.c * * Created on: 16. aug. 2024 - * Author: Christian Lind Vie Madsen - OZ1CM - */ -#include "include/si5351_driver.h" + * Author: Christian L. V. Madsen (OZ1CM) + */ +#include "include/si5351_driver.h" +#include +#include +#include enum{ SI5351_I2C_GET = 0, @@ -20,17 +23,88 @@ static int readRegister(si5351_driver *inst,uint8_t data_addr, uint8_t *data, ui // Read data: inst->i2c_transfer_evt(inst->i2c_transfer_inst,data,len, SI5351_I2C_GET); + //HAL_Delay(1); return 0; } static int writeRegister(si5351_driver *inst,uint8_t data_addr, uint8_t *data, uint32_t len){ - // Write what kind of addr we would like to read from: - inst->i2c_transfer_evt(inst->i2c_transfer_inst,&data_addr,1, SI5351_I2C_SET); - + uint8_t *data_ptr = malloc(len+1); + + *data_ptr = data_addr; + + + // Copy data + memcpy(&data_ptr[1],data,len); // Write data: - inst->i2c_transfer_evt(inst->i2c_transfer_inst,data,len, SI5351_I2C_SET); + inst->i2c_transfer_evt(inst->i2c_transfer_inst,data_ptr,len+1, SI5351_I2C_SET); + + + + + + free(data_ptr); +/* uint8_t txBuf[512] = {data_addr}; + + uint8_t *txBuf_ptr = &txBuf[1]; + + // add register addr to data: + memcpy(txBuf_ptr,data,len); + // Write data: + inst->i2c_transfer_evt(inst->i2c_transfer_inst,txBuf,len+1, SI5351_I2C_SET); + + //HAL_Delay(1);*/ + return 0; +} + +int cm_setPllParamRaw(si5351_driver *inst, si5351_PLLs sel_pll, uint32_t MSNx_P1, uint32_t MSNx_P2, uint32_t MSNx_P3){ + + switch(sel_pll){ + + case SI5351_PLL_A: + + inst->device_data.multiSynthNAParam.MSNx_P1_17_16 = (MSNx_P1 >> 16) & 0x2; + inst->device_data.multiSynthNAParam.MSNx_P1_15_8 = (MSNx_P1 >> 8) & 0xff; + inst->device_data.multiSynthNAParam.MSNx_P1_7_0 = MSNx_P1 & 0xff; + + inst->device_data.multiSynthNAParam.MSNx_P2_19_16 = ((MSNx_P2 & 0x000F0000) >> 16); + inst->device_data.multiSynthNAParam.MSNx_P2_15_8 = (MSNx_P2 >> 8) & 0xff; + inst->device_data.multiSynthNAParam.MSNx_P2_7_0 = MSNx_P2 & 0xff; + + inst->device_data.multiSynthNAParam.MSNx_P3_19_16 = ((MSNx_P3 & 0x000F0000) >> 12); + inst->device_data.multiSynthNAParam.MSNx_P3_15_8 = (MSNx_P3 >> 8) & 0xff; + inst->device_data.multiSynthNAParam.MSNx_P3_7_0 = MSNx_P3 & 0xff; + + writeRegister(inst,SI5351_REG_MULTISYNTH_NA_0, (uint8_t*) &inst->device_data.multiSynthNAParam, sizeof(si5351_multiSynthNxParameters_t)); + + break; + + case SI5351_PLL_B: + + inst->device_data.multiSynthNBParam.MSNx_P1_17_16 = (MSNx_P1 >> 16) & 0x2; + inst->device_data.multiSynthNBParam.MSNx_P1_15_8 = (MSNx_P1 >> 8) & 0xff; + inst->device_data.multiSynthNBParam.MSNx_P1_7_0 = MSNx_P1 & 0xff; + + inst->device_data.multiSynthNBParam.MSNx_P2_19_16 = ((MSNx_P2 & 0x000F0000) >> 16); + inst->device_data.multiSynthNBParam.MSNx_P2_15_8 = (MSNx_P2 >> 8) & 0xff; + inst->device_data.multiSynthNBParam.MSNx_P2_7_0 = MSNx_P2 & 0xff; + + inst->device_data.multiSynthNBParam.MSNx_P3_19_16 = ((MSNx_P3 & 0x000F0000) >> 12); + inst->device_data.multiSynthNBParam.MSNx_P3_15_8 = (MSNx_P3 >> 8) & 0xff; + inst->device_data.multiSynthNBParam.MSNx_P3_7_0 = MSNx_P3 & 0xff; + + writeRegister(inst,SI5351_REG_MULTISYNTH_NB_0, (uint8_t*) &inst->device_data.multiSynthNBParam, sizeof(si5351_multiSynthNxParameters_t)); + break; + + default: + break; + + } + + // reset PLL's + cm_resetPLLs(inst, 1,1); + return 0; } @@ -44,20 +118,20 @@ int cm_setPLLParameters(si5351_driver *inst,si5351_PLLs sel_pll, uint32_t a, uin temp_val = (float)128 * (float)a + ((float)128 * ((float)b/(float)c)) - (float)512; - inst->device_data.multiSynthNAParam.MSNx_P1_17_16 = (temp_val >> 15) & 0x2; + inst->device_data.multiSynthNAParam.MSNx_P1_17_16 = (temp_val >> 16) & 0x2; inst->device_data.multiSynthNAParam.MSNx_P1_15_8 = (temp_val >> 8) & 0xff; inst->device_data.multiSynthNAParam.MSNx_P1_7_0 = temp_val & 0xff; temp_val = 0; - temp_val = (float)128 * (float)b - (float)c * (float)128 * ((float)b/(float)c); + temp_val = (uint32_t)(128 * b - c * floor(128 * ((float)b / (float)c))); - inst->device_data.multiSynthNAParam.MSNx_P2_19_16 = (temp_val >> 15) & 0x4; - inst->device_data.multiSynthNAParam.MSNx_P2_15_8 = (temp_val >> 7) & 0xff; + inst->device_data.multiSynthNAParam.MSNx_P2_19_16 = ((temp_val & 0x000F0000) >> 16); + inst->device_data.multiSynthNAParam.MSNx_P2_15_8 = (temp_val >> 8) & 0xff; inst->device_data.multiSynthNAParam.MSNx_P2_7_0 = temp_val & 0xff; - inst->device_data.multiSynthNAParam.MSNx_P3_19_16 = (c >> 15) & 0x4; - inst->device_data.multiSynthNAParam.MSNx_P3_15_8 = (c >> 7) & 0xff; + inst->device_data.multiSynthNAParam.MSNx_P3_19_16 = ((c & 0x000F0000) >> 12); + inst->device_data.multiSynthNAParam.MSNx_P3_15_8 = (c >> 8) & 0xff; inst->device_data.multiSynthNAParam.MSNx_P3_7_0 = c & 0xff; writeRegister(inst,SI5351_REG_MULTISYNTH_NA_0, (uint8_t*) &inst->device_data.multiSynthNAParam, sizeof(si5351_multiSynthNxParameters_t)); @@ -87,6 +161,125 @@ int cm_setPLLParameters(si5351_driver *inst,si5351_PLLs sel_pll, uint32_t a, uin break; } + + // reset PLL's + cm_resetPLLs(inst, 1,1); + + + return 0; +} + +int cm_setOutputMultiSynth(si5351_driver *inst,si5351_Outputs clk_output, uint32_t d, uint32_t e, uint32_t f){ + + /* Integer mode */ + uint32_t P1 = 128 * d - 512; + uint32_t P2 = e; + uint32_t P3 = f; + + switch(clk_output){ + + case SI5351_OUTPUT_0: + inst->device_data.multiSynth0Param.MSx_P1_17_16 = (P1 >> 16) & 0x3; // last division.. + inst->device_data.multiSynth0Param.MSx_P1_15_8 = (P1 >> 8) & 0xff; + inst->device_data.multiSynth0Param.MSx_P1_7_0 = P1 & 0xff; + + inst->device_data.multiSynth0Param.MSx_P2_19_16 = (P2 >> 16) & 0x3; + inst->device_data.multiSynth0Param.MSx_P2_15_8 = (P2 >> 8) & 0xff; + inst->device_data.multiSynth0Param.MSx_P2_7_0 = P2 & 0xff; + + inst->device_data.multiSynth0Param.MSx_P3_19_16 = (P3 >> 12) & 0x3; + inst->device_data.multiSynth0Param.MSx_P3_15_8 = (P3 >> 8) & 0xff; + inst->device_data.multiSynth0Param.MSx_P3_7_0 = P3 & 0xff; + + writeRegister(inst,SI5351_REG_MULTISYNTH_OUT_0, (uint8_t*) &inst->device_data.multiSynth0Param, sizeof(si5351_multiSynthxParameters_t)); + + break; + + case SI5351_OUTPUT_1: + inst->device_data.multiSynth1Param.MSx_P1_17_16 = (P1 >> 16) & 0x3; // last division.. + inst->device_data.multiSynth1Param.MSx_P1_15_8 = (P1 >> 8) & 0xff; + inst->device_data.multiSynth1Param.MSx_P1_7_0 = P1 & 0xff; + + inst->device_data.multiSynth1Param.MSx_P2_19_16 = (P2 >> 16) & 0x3; + inst->device_data.multiSynth1Param.MSx_P2_15_8 = (P2 >> 8) & 0xff; + inst->device_data.multiSynth1Param.MSx_P2_7_0 = P2 & 0xff; + + inst->device_data.multiSynth1Param.MSx_P3_19_16 = (P3 >> 12) & 0x3; + inst->device_data.multiSynth1Param.MSx_P3_15_8 = (P3 >> 8) & 0xff; + inst->device_data.multiSynth1Param.MSx_P3_7_0 = P3 & 0xff; + + writeRegister(inst,SI5351_REG_MULTISYNTH_OUT_1, (uint8_t*) &inst->device_data.multiSynth1Param, sizeof(si5351_multiSynthxParameters_t)); + break; + + default: + break; + + + } + + return 0; + +} + +int cm_setOutputEnable(si5351_driver *inst,si5351_Outputs clk_output, si5351_Outputs_state outputState){ + + + switch (clk_output) + { + + case SI5351_OUTPUT_0: + inst->device_data.outputEnableControl.CLK0_OEB = outputState; + break; + + case SI5351_OUTPUT_1: + inst->device_data.outputEnableControl.CLK1_OEB = outputState; + break; + + default: + break; + + } + + + + writeRegister(inst,SI5351_REG_OUTPUT_ENABLE_CONTROL, (uint8_t*) &inst->device_data.outputEnableControl, sizeof(si5351_outputEnableControl_t)); + + + return 0; +} + +int cm_setCLKControl(si5351_driver *inst, si5351_Outputs clk_output, si5351_CLK_PDN clk_pdn){ + + switch (clk_output) + { + + case SI5351_OUTPUT_0: + inst->device_data.CLK0_control.CLK_PDN = clk_pdn; + inst->device_data.CLK0_control.MSx_INT = 1; + inst->device_data.CLK0_control.CLK_SRC = 0b11; + inst->device_data.CLK1_control.MSx_SRC = 0; + inst->device_data.CLK0_control.CLK_IDRV = SI5351_DRIVE_STRENGTH_8MA; + writeRegister(inst,SI5351_REG_CLK_0_CONTROL, (uint8_t*) &inst->device_data.CLK0_control, sizeof(si5351_CLK_Control_t)); + break; + + case SI5351_OUTPUT_1: + inst->device_data.CLK1_control.CLK_PDN = clk_pdn; + inst->device_data.CLK1_control.MSx_INT = 1; + inst->device_data.CLK1_control.MSx_SRC = 1; + inst->device_data.CLK1_control.CLK_SRC = 0b11; + inst->device_data.CLK1_control.CLK_IDRV = SI5351_DRIVE_STRENGTH_8MA; + writeRegister(inst,SI5351_REG_CLK_1_CONTROL, (uint8_t*) &inst->device_data.CLK1_control, sizeof(si5351_CLK_Control_t)); + break; + + default: + break; + + + } + + + + return 0; } @@ -95,11 +288,12 @@ int cm_setInputSource(si5351_driver *inst, si5351_ClkSource clk_source){ switch(clk_source){ case SI5351_CLK_SOURCE_XTAL: - inst->device_data.pllInputSource.PLLA_SRC = 1; + inst->device_data.pllInputSource.PLLA_SRC = 0; + inst->device_data.pllInputSource.PLLB_SRC = 0; break; case SI5351_CLK_SOURCE_CLOCKSOURCE: - inst->device_data.pllInputSource.PLLA_SRC = 0; + inst->device_data.pllInputSource.PLLA_SRC = 1; break; default: @@ -113,6 +307,18 @@ int cm_setInputSource(si5351_driver *inst, si5351_ClkSource clk_source){ return 0; } +int cm_resetPLLs(si5351_driver *inst, uint8_t reset_PLLA, uint8_t reset_PLLB){ + + inst->device_data.PLL_Reset.PLLA_RST = (reset_PLLA != 0)? 1 : 0; + inst->device_data.PLL_Reset.PLLB_RST = (reset_PLLB != 0)? 1 : 0; + + // Write to register: + writeRegister(inst,SI5351_REG_PLL_RESET, (uint8_t*) &inst->device_data.PLL_Reset, sizeof(si5351_PLL_Reset_t)); + + + return 0; +} + uint8_t cm_si5351_getRevisionNumber(si5351_driver *inst){ // Read Device Status register: @@ -132,14 +338,30 @@ int cm_si5351_init(si5351_driver *inst, void *i2c_transfer_inst, setGet_I2C_Even int ret = 0; - // SW Reset device. - //ret = cm_ltr390_SWreset(inst); + memset(&(inst->device_data),0x00,sizeof(si5351_data)); -// ret = ltr390_readAllReg(inst); + /* Disable all outputs setting CLKx_DIS high */ + uint8_t temp = 0xff; + writeRegister(inst,SI5351_REG_OUTPUT_ENABLE_CONTROL,&temp,1); + /* Power down all output drivers */ + temp = 0x80; + writeRegister(inst,SI5351_REG_CLK_0_CONTROL,&temp,1); + writeRegister(inst,SI5351_REG_CLK_1_CONTROL,&temp,1); + writeRegister(inst,SI5351_REG_CLK_2_CONTROL,&temp,1); + writeRegister(inst,SI5351_REG_CLK_3_CONTROL,&temp,1); + writeRegister(inst,SI5351_REG_CLK_4_CONTROL,&temp,1); + writeRegister(inst,SI5351_REG_CLK_5_CONTROL,&temp,1); + writeRegister(inst,SI5351_REG_CLK_6_CONTROL,&temp,1); + writeRegister(inst,SI5351_REG_CLK_7_CONTROL,&temp,1); + + temp = SI5351_CRYSTAL_LOAD_10PF; + + writeRegister(inst,SI5351_REG_CRYSTAL_LOAD_CAPACITANCE,&temp,1); return ret; } +