From f4a61ee06f3a7101c33d8a56542b366e39734a08 Mon Sep 17 00:00:00 2001 From: Tom Kuschel Date: Tue, 17 May 2022 01:28:20 +0200 Subject: [PATCH] CHG programming further investigation --- Core/Inc/stm32_si5351.h | 5 +- Core/Inc/stm32_si5351_reg.h | 48 ++++++++++++--- Core/Src/main.c | 3 +- Core/Src/stm32_si5351.c | 117 ++++++++++++++++++++++++++++++------ 4 files changed, 141 insertions(+), 32 deletions(-) diff --git a/Core/Inc/stm32_si5351.h b/Core/Inc/stm32_si5351.h index 4fc4a4c..ca78632 100644 --- a/Core/Inc/stm32_si5351.h +++ b/Core/Inc/stm32_si5351.h @@ -105,12 +105,15 @@ typedef enum { /* Exported variables --------------------------------------------------------*/ /* Exported macros -----------------------------------------------------------*/ - +#ifndef SI5351_NUMBER_OF_OUTPUTS +#define SI5351_NUMBER_OF_OUTPUTS 8 +#endif /* Exported functions --------------------------------------------------------*/ si5351_inst_t si5351_init(void * i2c_handle, uint32_t xtal_frequency, uint8_t i2c_address); int si5351_deinit(si5351_inst_t si5351_handle); int si5351_isready(si5351_inst_t inst); int si5351_program(si5351_inst_t inst); +char * si5351_read_debug_msg(si5351_inst_t inst); #ifdef __cplusplus } /* extern "C" */ diff --git a/Core/Inc/stm32_si5351_reg.h b/Core/Inc/stm32_si5351_reg.h index 674fcf3..e995efa 100644 --- a/Core/Inc/stm32_si5351_reg.h +++ b/Core/Inc/stm32_si5351_reg.h @@ -68,9 +68,17 @@ #define SI5351_CLK0_SRC_1 (1u<<3) /* Output Clock 0 Input Source */ #define SI5351_CLK0_SRC_0 (1u<<2) /* 00: Select the XTAL as the clock source for CLK0. By-pass both synthesis stages (PLL/VCXO & MultiSynth) */ #define SI5351_CLK0_SRC (3u<<2) /* and connects CLK0 directly to the oscillator which generates an output freq determined by the XTAL freq. */ +#define SI5351_CLK_SRC_XTAL (0x00<<2) /*!< Select the XTAL as the clock source for CLKx */ +#define SI5351_CLK_SRC_CLKIN (0x01<<2) /*!< Select the CLKIN as the clock source for CLKx */ +#define SI5351_CLK_SRC_MS0 (0x02<<2) /*!< Select the MulitSynth 0 as the clock source for CLKx */ +#define SI5351_CLK_SRC_MS1 (0x03<<2) /*!< Select the MulitSynth 1 as the clock source for CLKx */ #define SI5351_CLK0_IDRV_1 (1u<<1) /* 01: CLKIN as clock source for CLK0. By-pass both synthesis stages. 10: N/A. 11: Select MultiSynth 0 as source for CLK0 */ #define SI5351_CLK0_IDRV_0 (1u<<0) /* CLK0 Output Rise and Fall time / Drive Strength Control */ -#define SI5551_CLK0_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK0_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK_2_MA (0x00) /*!< 2 mA output rise and fall time / drive strength control */ +#define SI5351_CLK_4_MA (0x01) /*!< 4 mA output rise and fall time / drive strength control */ +#define SI5351_CLK_6_MA (0x02) /*!< 6 mA output rise and fall time / drive strength control */ +#define SI5351_CLK_8_MA (0x03) /*!< 8 mA output rise and fall time / drive strength control */ #define SI5351_CLK0_CONTROL_RESET_VALUE 0x00 #define SI5351_CLK1_CONTROL 17u /* R/W */ @@ -83,7 +91,7 @@ #define SI5351_CLK1_SRC (3u<<2) /* and connects CLK1 directly to the oscillator which generates an output freq determined by the XTAL freq. */ #define SI5351_CLK1_IDRV_1 (1u<<1) /* 01: CLKIN as clock source for CLK1. By-pass both synthesis stages. 10: N/A. 11: Select MultiSynth 1 as source for CLK1 */ #define SI5351_CLK1_IDRV_0 (1u<<0) /* CLK1 Output Rise and Fall time / Drive Strength Control */ -#define SI5551_CLK1_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK1_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ #define SI5351_CLK1_CONTROL_RESET_VALUE 0x00 #define SI5351_CLK2_CONTROL 18u /* R/W */ @@ -96,7 +104,7 @@ #define SI5351_CLK2_SRC (3u<<2) /* and connects CLK2 directly to the oscillator which generates an output freq determined by the XTAL freq. */ #define SI5351_CLK2_IDRV_1 (1u<<1) /* 01: CLKIN as clock source for CLK2. By-pass both synthesis stages. 10: N/A. 11: Select MultiSynth 2 as source for CLK2 */ #define SI5351_CLK2_IDRV_0 (1u<<0) /* CLK2 Output Rise and Fall time / Drive Strength Control */ -#define SI5551_CLK2_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK2_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ #define SI5351_CLK2_CONTROL_RESET_VALUE 0x00 #define SI5351_CLK3_CONTROL 19u /* R/W */ @@ -109,7 +117,7 @@ #define SI5351_CLK3_SRC (3u<<2) /* and connects CLK3 directly to the oscillator which generates an output freq determined by the XTAL freq. */ #define SI5351_CLK3_IDRV_1 (1u<<1) /* 01: CLKIN as clock source for CLK3. By-pass both synthesis stages. 10: N/A. 11: Select MultiSynth 3 as source for CLK3 */ #define SI5351_CLK3_IDRV_0 (1u<<0) /* CLK3 Output Rise and Fall time / Drive Strength Control */ -#define SI5551_CLK3_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK3_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ #define SI5351_CLK3_CONTROL_RESET_VALUE 0x00 #define SI5351_CLK4_CONTROL 20u /* R/W */ @@ -122,7 +130,7 @@ #define SI5351_CLK4_SRC (3u<<2) /* and connects CLK4 directly to the oscillator which generates an output freq determined by the XTAL freq. */ #define SI5351_CLK4_IDRV_1 (1u<<1) /* 01: CLKIN as clock source for CLK4. By-pass both synthesis stages. 10: N/A. 11: Select MultiSynth 4 as source for CLK4 */ #define SI5351_CLK4_IDRV_0 (1u<<0) /* CLK4 Output Rise and Fall time / Drive Strength Control */ -#define SI5551_CLK4_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK4_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ #define SI5351_CLK4_CONTROL_RESET_VALUE 0x00 #define SI5351_CLK5_CONTROL 21u /* R/W */ @@ -135,12 +143,13 @@ #define SI5351_CLK5_SRC (3u<<2) /* and connects CLK5 directly to the oscillator which generates an output freq determined by the XTAL freq. */ #define SI5351_CLK5_IDRV_1 (1u<<1) /* 01: CLKIN as clock source for CLK5. By-pass both synthesis stages. 10: N/A. 11: Select MultiSynth 5 as source for CLK5 */ #define SI5351_CLK5_IDRV_0 (1u<<0) /* CLK5 Output Rise and Fall time / Drive Strength Control */ -#define SI5551_CLK5_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK5_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ #define SI5351_CLK5_CONTROL_RESET_VALUE 0x00 #define SI5351_CLK6_CONTROL 22u /* R/W */ #define SI5351_CLK6_PDN (1u<<7) /* Clock 6 Power Down. */ -#define SI5351_MS6_INT (1u<<6) /* MultiSynth 6 Integer Mode. 1..MS6 operates in integer mode. */ +/* #define SI5351_MS6_INT (1u<<6) */ +#define SI5351_FBA_INT (1u<<6) /*!< FBA MultiSynth Integer Mode. 1..MSNA operates in integer mode */ #define SI5351_MS6_SRC (1u<<5) /* MultiSynth Source Select for CLK6 */ #define SI5351_CLK6_INV (1u<<4) /* Output Clock 6 Invert. */ #define SI5351_CLK6_SRC_1 (1u<<3) /* Output Clock 6 Input Source */ @@ -148,12 +157,13 @@ #define SI5351_CLK6_SRC (3u<<2) /* and connects CLK6 directly to the oscillator which generates an output freq determined by the XTAL freq. */ #define SI5351_CLK6_IDRV_1 (1u<<1) /* 01: CLKIN as clock source for CLK6. By-pass both synthesis stages. 10: N/A. 11: Select MultiSynth 6 as source for CLK6 */ #define SI5351_CLK6_IDRV_0 (1u<<0) /* CLK6 Output Rise and Fall time / Drive Strength Control */ -#define SI5551_CLK6_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK6_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ #define SI5351_CLK6_CONTROL_RESET_VALUE 0x00 #define SI5351_CLK7_CONTROL 23u /* R/W */ #define SI5351_CLK7_PDN (1u<<7) /* Clock 7 Power Down. */ -#define SI5351_MS7_INT (1u<<6) /* MultiSynth 7 Integer Mode. 1..MS7 operates in integer mode. */ +/* #define SI5351_MS7_INT (1u<<6) */ +#define SI5351_FBB_INT (1u<<6) /*!< FBB Multisynth Integer Mode. 1..MSNB operates in integer mode */ #define SI5351_MS7_SRC (1u<<5) /* MultiSynth Source Select for CLK7 */ #define SI5351_CLK7_INV (1u<<4) /* Output Clock 7 Invert. */ #define SI5351_CLK7_SRC_1 (1u<<3) /* Output Clock 7 Input Source */ @@ -161,7 +171,7 @@ #define SI5351_CLK7_SRC (3u<<2) /* and connects CLK7 directly to the oscillator which generates an output freq determined by the XTAL freq. */ #define SI5351_CLK7_IDRV_1 (1u<<1) /* 01: CLKIN as clock source for CLK7. By-pass both synthesis stages. 10: N/A. 11: Select MultiSynth 7 as source for CLK7 */ #define SI5351_CLK7_IDRV_0 (1u<<0) /* CLK7 Output Rise and Fall time / Drive Strength Control */ -#define SI5551_CLK7_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ +#define SI5351_CLK7_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ #define SI5351_CLK7_CONTROL_RESET_VALUE 0x00 #define SI5351_CLK3_0_DISABLE_STATE 24u /* R/W */ @@ -1079,3 +1089,21 @@ even integers greater than or equal to 6. All other divide values are invalid. * #define R6_DIV (7u<<4) +/* Crystal Internal Load Capacitance + * Two bits determine the internal load capacitance value for the crystal. See the Crystal + * Inputs section in the Si5351 data sheet + * Default: SI5351_XTAL_CL_10_PF (10 pF load capacitors) + */ +#define SI5351_CRYSTAL_INTERNAL_LOAD_CAPACITANCE 183u /* R/W */ +#define SI5351_XTAL_CL_6_PF (1u<<6) /*!< Internal CL = 6 pF */ +#define SI5351_XTAL_CL_8_PF (2u<<6) /*!< Internal CL = 8 pF */ +#define SI5351_XTAL_CL_10_PF (3u<<6) /*!< Internal CL = 10 pF */ +#define SI5351_XTAL_CL_MASK (3u<<6) /*!< Mask of the load capacitance */ +#define SI5351_XTAL_RESERVED (0x13) /*!< RESERVED bit[5:0] should be written! */ +/* Fanout Enable, set these bits to 1 for each fanout + * note: the reset value of this SI5351 register is 0x00 */ + +#define SI5351_FANOUT_ENABLE 187u /* R/W */ +#define SI5351_CLKIN_FANOUT_EN (1u<<7) /*!< Enable fanout of CLKIN to clock output multiplexers. Set it to 1 */ +#define SI5351_XO_FANOUT_EN (1u<<6) /*!< Enable fanout of XO to clock output multiplexers. Set it to 1 */ +#define SI5351_MS_FANOUT_EN (1u<<4) /*!< Enable fanout of Multisynth0 & Multisynth4 to all output multiplexers. Set it to 1 */ diff --git a/Core/Src/main.c b/Core/Src/main.c index ed71520..152e5e2 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -145,6 +145,7 @@ int main(void) status = si5351_program(instance_si5351[1]); printf("Device #1 gets status %d\n", status); + printf("Debug:\n%s", si5351_read_debug_msg(instance_si5351[1])); for (int i=2; i>=0; i--) { si5351_deinit(instance_si5351[i]); @@ -178,7 +179,7 @@ int main(void) terminalTaskHandle = osThreadNew(start_terminal_task, NULL, &terminalTask_attributes); /* creation of idTask */ - idTaskHandle = osThreadNew(start_id_task, NULL, &idTask_attributes); + // idTaskHandle = osThreadNew(start_id_task, NULL, &idTask_attributes); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ diff --git a/Core/Src/stm32_si5351.c b/Core/Src/stm32_si5351.c index 6d28b6c..7931fd9 100644 --- a/Core/Src/stm32_si5351.c +++ b/Core/Src/stm32_si5351.c @@ -10,14 +10,21 @@ * adapted, idea and much information from Petr Polasek, created Feb 16, 2018 ******************************************************************************/ +/* Defines for compilation ---------------------------------------------------*/ +#define DEBUG 1 +#define OPTIMIZED 1 + /* Includes ------------------------------------------------------------------*/ #include // @TODO try to get rid off including the HAL here, using pointer to the specified functions +#if DEBUG +#include +#endif + #include "stm32l4xx_hal.h" #include "stm32_si5351.h" /* Private typedef -----------------------------------------------------------*/ -#define SI5351_VERSION 1 /* @brief Si5351 handle structure definition */ @@ -26,12 +33,15 @@ typedef struct __SI5351_HandleTypeDef { uint32_t xtal_frequency; /*!< XTAL or CLKIN frequency */ int si5351_num; struct __SI5351_HandleTypeDef *next; + char debug_msg[1000]; uint8_t i2c_address; /*!< I2C address of the datasheet */ - // uint8_t interrupt_status_mask; /*!< Reg 2: Interrupt Status Mask */ + uint8_t interrupt_status_mask; /*!< Reg 2: Interrupt Status Mask */ uint8_t initialized:1; /*!< mark the driver initialized */ } si5351_HandleTypeDef; /* Private define ------------------------------------------------------------*/ +#define SI5351_VERSION 1 + /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ si5351_HandleTypeDef * first_handle = NULL; /* pointer to the first instancee */ @@ -111,6 +121,9 @@ si5351_HandleTypeDef *si5351_init(void * i2c_handle, uint32_t xtal_frequency, ui si5351_handle->i2c_handle = i2c_handle; si5351_handle->i2c_address = i2c_address; si5351_handle->xtal_frequency = xtal_frequency; + /* disable all interrupts (Si5351C only) */ + si5351_handle->interrupt_status_mask = SI5351_SYS_INIT_MASK | SI5351_LOL_B_MASK | + SI5351_LOL_A_MASK | SI5351_LOS_CLKIN_MASK | SI5351_LOS_XTAL_MASK; si5351_handle->initialized = 1; return si5351_handle; } @@ -151,10 +164,11 @@ int si5351_deinit(si5351_HandleTypeDef * si5351_handle) { /** @brief Check if there is any I2C device ready on the bus * @param si5351_instance Given si5351 device handle - * @return 0 on success (HAL_StatusTypeDef) - * @retval HAL_ERROR = 0x01 - * @retval HAL_BUSY = 0x02 - * @retval HAL_TIMEOUT = 0x03 + * @return 0 on success + * @retval -EINVAL when given a NULL handle + * @retval -ETIMEDOUT when HAL_TIMEOUT + * @retval -EIO when HAL_ERROR + * @retval -EBUSY when HAL_BUSY */ int si5351_isready(si5351_inst_t inst) { @@ -169,10 +183,20 @@ int si5351_isready(si5351_inst_t inst) { return status; } + +/** @brief Program the si5351 with the already set values according to Figure 10 of the datasheet + * @param si5351_instance Given si5351 device handle + * @return 0 on success + * @retval -EINVAL when given a NULL handle + * @retval -ETIMEDOUT when HAL_TIMEOUT + * @retval -EIO when HAL_ERROR + * @retval -EBUSY when HAL_BUSY + */ int si5351_program(si5351_inst_t inst) { uint8_t data; int status = 0; + int cx = 0; if(!inst) return -EINVAL; @@ -184,29 +208,82 @@ int si5351_program(si5351_inst_t inst) { } while(data & SI5351_SYS_INIT); - /* Disable Outputs Set CLKx_DIS high, Reg. 3 = 0xFF */ - data = 0xff; - status = si5351_write(inst, SI5351_OUTPUT_ENABLE_CONTROL, &data, 1); - if (status) - return status; - - /* power down all output drivers reg 16 -- 23 */ - data = 0x80; - for(int i = SI5351_CLK0_CONTROL; i <= SI5351_CLK7_CONTROL; i++) { - status = si5351_write(inst, i, &data, 1); + do { + /* Disable Outputs Set CLKx_DIS high, Reg. 3 = 0xFF */ + data = SI5351_CLK7_OEB | SI5351_CLK6_OEB | SI5351_CLK5_OEB | SI5351_CLK4_OEB | + SI5351_CLK3_OEB | SI5351_CLK2_OEB | SI5351_CLK1_OEB | SI5351_CLK0_OEB; + status = si5351_write(inst, SI5351_OUTPUT_ENABLE_CONTROL, &data, 1); if (status) - return status; - } + break; + + /* power down all output drivers reg 16 -- 23 */ + data = SI5351_CLKx_PDN; // 0x80 +#if OPTIMIZED + status = si5351_write(inst, SI5351_CLK0_CONTROL, &data, SI5351_NUMBER_OF_OUTPUTS); + if (status) + break; +#else + for(int i = SI5351_CLK0_CONTROL; i <= SI5351_CLK7_CONTROL; i++) { + status = si5351_write(inst, i, &data, 1); + + if (status) + break; + } +#endif + + /* set interrupt masks (see register 2 description) */ + status = si5351_write(inst, SI5351_INTERRUPT_STATUS_MASK, &inst->interrupt_status_mask, 1); + if (status) + break; + + /* for debugging purpose, read out fanout enable register */ +#if DEBUG + status = si5351_read(inst, SI5351_FANOUT_ENABLE, &data, 1); + if (status) + break; + cx += snprintf(inst->debug_msg + cx, sizeof(inst->debug_msg) - cx, "(%d) FANOUT_ENABLE 0x%x\n", cx, data); + cx += snprintf(inst->debug_msg + cx, sizeof(inst->debug_msg) - cx, "(%d) FANOUT_ENABLE %d\n", cx, data); +#endif + data = SI5351_CLKIN_FANOUT_EN | SI5351_XO_FANOUT_EN | SI5351_MS_FANOUT_EN; // set them to 1b + status = si5351_write(inst, SI5351_FANOUT_ENABLE, &data, 1); + if (status) + break; +#if DEBUG + status = si5351_read(inst, SI5351_FANOUT_ENABLE, &data, 1); + if (status) + break; + cx += snprintf(inst->debug_msg + cx, sizeof(inst->debug_msg) - cx, "(%d) FANOUT_ENABLE 0x%x\n", cx, data); + cx += snprintf(inst->debug_msg + cx, sizeof(inst->debug_msg) - cx, "(%d) FANOUT_ENABLE %d\n", cx, data); +#endif + + /* Crystal Internal Load Capacitance */ + +#if DEBUG + status = si5351_read(inst, SI5351_CRYSTAL_INTERNAL_LOAD_CAPACITANCE, &data, 1); + if (status) + break; + cx += snprintf(inst->debug_msg + cx, sizeof(inst->debug_msg) - cx, "(%d) XTAL int. Load Cap: 0x%x (%dd)\n", cx, data, data); +#endif + } while(0); - return 0; + + + return status; +} + +char * si5351_read_debug_msg(si5351_inst_t inst) { + + if (!inst) + return NULL; + + return inst->debug_msg; } #if 0 - int Si5351_WriteRegister(Si5351_ConfigTypeDef *Si5351_ConfigStruct, uint8_t reg_address, uint8_t reg_data) { uint32_t error_wait;