/* * si5351_driver.c * * Created on: 16. aug. 2024 * Author: Christian L. V. Madsen (OZ1CM) */ #include "si5351_driver.h" #include #include #include enum{ SI5351_I2C_GET = 0, SI5351_I2C_SET = 1, }; static int clear_buffer(si5351_driver *inst){ memset(inst->device_data,0, sizeof(inst->device_data)); } static int readRegister(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); // 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, uint32_t len){ // Set address inst->device_data[0] = data_addr; inst->i2c_transfer_evt(inst->i2c_transfer_inst,&inst->device_data[0],len+1, SI5351_I2C_SET); clear_buffer(inst); return 0; } static int writeRegisterbyte(si5351_driver *inst,uint8_t data_addr, uint8_t data){ // Set address uint8_t buff[2] = {data_addr,data}; inst->i2c_transfer_evt(inst->i2c_transfer_inst,&buff[0],2, SI5351_I2C_SET); clear_buffer(inst); return 0; } int cm_setPllParamRaw(si5351_driver *inst, si5351_PLLs sel_pll, uint32_t MSNx_P1, uint32_t MSNx_P2, uint32_t MSNx_P3){ si5351_multiSynthNxParameters_t *multiSynthNxParam = (void*)&inst->device_data[1]; multiSynthNxParam->MSNx_P1_17_16 = (MSNx_P1 >> 16) & 0x3; multiSynthNxParam->MSNx_P1_15_8 = (MSNx_P1 >> 8) & 0xff; multiSynthNxParam->MSNx_P1_7_0 = MSNx_P1 & 0xff; multiSynthNxParam->MSNx_P2_19_16 = (MSNx_P2 >> 16) & 0xf; multiSynthNxParam->MSNx_P2_15_8 = (MSNx_P2 >> 8) & 0xff; multiSynthNxParam->MSNx_P2_7_0 = MSNx_P2 & 0xff; multiSynthNxParam->MSNx_P3_19_16 = (MSNx_P3 >> 16) & 0xf; multiSynthNxParam->MSNx_P3_15_8 = (MSNx_P3 >> 8) & 0xff; multiSynthNxParam->MSNx_P3_7_0 = MSNx_P3 & 0xff; switch(sel_pll){ case SI5351_PLL_A: writeRegister(inst,SI5351_REG_MULTISYNTH_NA_0, sizeof(si5351_multiSynthNxParameters_t)); break; case SI5351_PLL_B: writeRegister(inst,SI5351_REG_MULTISYNTH_NB_0, sizeof(si5351_multiSynthNxParameters_t)); break; default: break; } // reset PLL's cm_resetPLLs(inst, 1,1); return 0; } int cm_setOutputMultiSynthRaw(si5351_driver *inst,si5351_Outputs clk_output, uint32_t MSx_P1, uint32_t MSx_P2, uint32_t MSx_P3){ si5351_multiSynthxParameters_t *multiSynthxParam = (void*)&inst->device_data[1]; multiSynthxParam->MSx_P1_17_16 = (MSx_P1 >> 16) & 0x3; // last division.. multiSynthxParam->MSx_P1_15_8 = (MSx_P1 >> 8) & 0xff; multiSynthxParam->MSx_P1_7_0 = MSx_P1 & 0xff; multiSynthxParam->MSx_P2_19_16 = (MSx_P2 >> 16) & 0xf; multiSynthxParam->MSx_P2_15_8 = (MSx_P2 >> 8) & 0xff; multiSynthxParam->MSx_P2_7_0 = MSx_P2 & 0xff; multiSynthxParam->MSx_P3_19_16 = (MSx_P3 >> 16) & 0xf; multiSynthxParam->MSx_P3_15_8 = (MSx_P3 >> 8) & 0xff; multiSynthxParam->MSx_P3_7_0 = MSx_P3 & 0xff; multiSynthxParam->MSx_DIVBY4 = 0; multiSynthxParam->Rx_DIV = 0; switch(clk_output){ case SI5351_OUTPUT_0: writeRegister(inst,SI5351_REG_MULTISYNTH_OUT_0, sizeof(si5351_multiSynthxParameters_t)); break; case SI5351_OUTPUT_1: writeRegister(inst,SI5351_REG_MULTISYNTH_OUT_1, sizeof(si5351_multiSynthxParameters_t)); break; case SI5351_OUTPUT_2: writeRegister(inst,SI5351_REG_MULTISYNTH_OUT_2, sizeof(si5351_multiSynthxParameters_t)); break; default: break; } return 0; } int cm_setOutputEnable(si5351_driver *inst,si5351_Outputs clk_output, si5351_Outputs_state outputState){ si5351_outputEnableControl_t *outputEnableControl = (void*)&inst->device_data[1]; switch (clk_output) { case SI5351_OUTPUT_0: outputEnableControl->CLK0_OEB = outputState; break; case SI5351_OUTPUT_1: outputEnableControl->CLK1_OEB = outputState; break; case SI5351_OUTPUT_2: outputEnableControl->CLK2_OEB = outputState; break; default: break; } writeRegister(inst,SI5351_REG_OUTPUT_ENABLE_CONTROL, sizeof(si5351_outputEnableControl_t)); return 0; } int cm_setCLKControl(si5351_driver *inst, si5351_Outputs clk_output, si5351_CLK_PDN clk_pdn){ si5351_CLK_Control_t *CLKx_control = (void*)&inst->device_data[1]; CLKx_control->CLK_PDN = clk_pdn; CLKx_control->CLK_INV = 0; CLKx_control->CLK_IDRV = SI5351_DRIVE_STRENGTH_8MA; switch (clk_output) { case SI5351_OUTPUT_0: CLKx_control->CLK_SRC = 0b11; CLKx_control->MSx_SRC = 0; CLKx_control->MSx_INT = 0; writeRegister(inst,SI5351_REG_CLK_0_CONTROL, sizeof(si5351_CLK_Control_t)); break; case SI5351_OUTPUT_1: CLKx_control->CLK_SRC = 0b11; CLKx_control->MSx_SRC = 1; CLKx_control->MSx_INT = 0; writeRegister(inst,SI5351_REG_CLK_1_CONTROL, sizeof(si5351_CLK_Control_t)); break; case SI5351_OUTPUT_2: CLKx_control->CLK_SRC = 0b00; CLKx_control->MSx_SRC = 0; CLKx_control->MSx_INT = 1; writeRegister(inst,SI5351_REG_CLK_2_CONTROL, sizeof(si5351_CLK_Control_t)); break; default: break; } return 0; } int cm_setInputSource(si5351_driver *inst, si5351_ClkSource clk_source){ si5351_PLLInputSource_t *pllInputSource = (void*)&inst->device_data[1]; switch(clk_source){ case SI5351_CLK_SOURCE_XTAL: pllInputSource->PLLA_SRC = 0; pllInputSource->PLLB_SRC = 0; break; case SI5351_CLK_SOURCE_CLOCKSOURCE: pllInputSource->PLLA_SRC = 1; break; default: break; } // Write to register: writeRegister(inst,SI5351_REG_PLL_INPUT_SOURCE, sizeof(si5351_PLLInputSource_t)); return 0; } int cm_resetPLLs(si5351_driver *inst, uint8_t reset_PLLA, uint8_t reset_PLLB){ si5351_PLL_Reset_t *PLL_Reset = (void*)&inst->device_data[1]; PLL_Reset->PLLA_RST = (reset_PLLA != 0)? 1 : 0; PLL_Reset->PLLB_RST = (reset_PLLB != 0)? 1 : 0; // Write to register: writeRegister(inst,SI5351_REG_PLL_RESET, sizeof(si5351_PLL_Reset_t)); return 0; } int cm_si5351_init(si5351_driver *inst, void *i2c_transfer_inst, setGet_I2C_Event_fpt i2c_transfer_evt){ if(inst == NULL)return -1; if(i2c_transfer_inst == NULL)return -1; if(i2c_transfer_evt == NULL)return -1; inst->i2c_transfer_inst = i2c_transfer_inst; inst->i2c_transfer_evt = i2c_transfer_evt; int ret = 0; //memset(&(inst->device_data),0x00,sizeof(si5351_data)); /* Disable all outputs setting CLKx_DIS high */ uint8_t temp = 0xff; writeRegisterbyte(inst,SI5351_REG_OUTPUT_ENABLE_CONTROL,temp); /* Power down all output drivers */ temp = 0x80; writeRegisterbyte(inst,SI5351_REG_CLK_0_CONTROL,temp); writeRegisterbyte(inst,SI5351_REG_CLK_1_CONTROL,temp); writeRegisterbyte(inst,SI5351_REG_CLK_2_CONTROL,temp); writeRegisterbyte(inst,SI5351_REG_CLK_3_CONTROL,temp); writeRegisterbyte(inst,SI5351_REG_CLK_4_CONTROL,temp); writeRegisterbyte(inst,SI5351_REG_CLK_5_CONTROL,temp); writeRegisterbyte(inst,SI5351_REG_CLK_6_CONTROL,temp); writeRegisterbyte(inst,SI5351_REG_CLK_7_CONTROL,temp); temp = SI5351_CRYSTAL_LOAD_10PF; writeRegisterbyte(inst,SI5351_REG_CRYSTAL_LOAD_CAPACITANCE,temp); // Enable xtal clk.. temp = 0b01000000; writeRegisterbyte(inst,SI5351_REG_FANOUT_ENABLE,temp); return ret; }