CHG programming further investigation

This commit is contained in:
Tom Kuschel 2022-05-17 01:28:20 +02:00
parent acc0f0a5da
commit f4a61ee06f
4 changed files with 141 additions and 32 deletions

View File

@ -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" */

View File

@ -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 */

View File

@ -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, ... */

View File

@ -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 <stdlib.h>
// @TODO try to get rid off including the HAL here, using pointer to the specified functions
#if DEBUG
#include <stdio.h>
#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);
do {
/* Disable Outputs Set CLKx_DIS high, Reg. 3 = 0xFF */
data = 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 = 0x80;
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)
return 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;