2022-05-15 22:42:00 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* File Name : stm32_si5351.h
|
|
|
|
* Description : STM32 library/driver for the Si5351 clock chip
|
|
|
|
* from Skyworks Solutions, Inc. (former SiLabs)
|
|
|
|
******************************************************************************
|
|
|
|
* @author: Thomas Kuschel KW4NZ, created 2022-05-11
|
|
|
|
*
|
|
|
|
* originally written by Petr Polasek, created Feb 16, 2018
|
|
|
|
******************************************************************************
|
|
|
|
* DO NOT EDIT THIS FILE FOR CONFIGURATION, USE THE FOLLOWING PROCEDURE:
|
|
|
|
*
|
|
|
|
* Inside your main.c program or within your STM32 code:
|
|
|
|
* Include this header to the the main.c: #include "stm32_si5351.h"
|
|
|
|
* You've to initialize the I2C functionality first (e.g. with STM32CubeIDE)
|
|
|
|
* Afterwards, when there is a handle like "I2C_HandleTypeDef hi2c1;",
|
|
|
|
* you simply initialize this stm32_si5351 library in your main.c ,
|
|
|
|
* just after the MX_I2C1_Init();
|
2022-05-24 08:01:52 +02:00
|
|
|
* so between the USER CODE like using the given i2c handle "hi2c1" with default values:
|
2022-05-15 22:42:00 +02:00
|
|
|
*
|
|
|
|
* /\* USER CODE BEGIN 2 *\/
|
2022-05-24 08:01:52 +02:00
|
|
|
*
|
|
|
|
* si5351_inst_t si5351_inst;
|
|
|
|
* si5351_initialize(&hi2c1);
|
2022-05-15 22:42:00 +02:00
|
|
|
* /\* USER CODE END 2 *\/
|
|
|
|
*
|
|
|
|
* The 7-bit device (slave) address of the Si5351 consist of a 6-bit fixed
|
|
|
|
* address plus a user selectable LSB bit as shown in Figure 6 of the datasheet.
|
|
|
|
* The LSB bit is selectable as 0 or 1 using the optional A0 pin which is useful
|
|
|
|
* for applications that require more than one Si5351 on a single I2C bus.
|
|
|
|
* Only the Si5351A 20-QFN and Si5351A 16-QFN have the A0 LSB pin option.
|
|
|
|
* If a part does not have the A0 pin, the default address is 0x60 with
|
|
|
|
* the A0 bit set to 0.
|
|
|
|
*
|
|
|
|
* So additionally you may drive more then one Si5351 at the same or
|
|
|
|
* another I2C bus when calling the init function with the given
|
|
|
|
* I2C bus address (default: 0x60)
|
|
|
|
* ( - internally this I2C address is shifted to the left
|
|
|
|
* for the proper usage of the I2C HAL driver i.e. it becomes 0xC0 )
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
* \\ Define handlers for the sum of three SI5351 clock generators:
|
|
|
|
* si5351_HandleTypeDef h_si5351[3];
|
|
|
|
*
|
|
|
|
* // 1st SI5351 chip and with an A0 = 0:
|
|
|
|
* h_si5351[0] = si5351_init(&hi2c1, 25000000, 0x60);
|
|
|
|
* // 2nd SI5351 chip on the same I2C bus "hi2c1" but address line A0 = 1
|
|
|
|
* h_si5351[1] = si5351_init(&hi2c1, 27000000, 0x61);
|
|
|
|
* // 3rd SI5351 chip on another IC2 bus with handle "hi2c2" *\/
|
|
|
|
* h_si5351[2] = si5351_init(&hi2c2, 25000000, 0x60);
|
|
|
|
*
|
|
|
|
* PROs:
|
|
|
|
* The library is preemptive and can be used within an operating system.
|
|
|
|
* All structures and used variables are dynamically allocated.
|
|
|
|
* CONs:
|
|
|
|
* Not fully tested, but used with FreeRTOS and with 2 I2C bus systems.
|
|
|
|
*
|
|
|
|
* CHANGES:
|
|
|
|
* - Removed several defines, enums, etc. from the header file, b/c we do not
|
|
|
|
* want to export them to other programs
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* The old simple example to get 50 kHz output with an 25 MHz crystal:
|
|
|
|
* Si5351_ConfigTypeDef Si5351_ConfigStruct;
|
|
|
|
* Si5351_StructInit(&Si5351_ConfigStruct); //initialize the structure with default "safe" values
|
|
|
|
* Si5351_ConfigStruct.OSC.OSC_XTAL_Load = XTAL_Load_8_pF; //use 8 pF load for crystal
|
|
|
|
* Si5351_ConfigStruct.PLL[0].PLL_Clock_Source = PLL_Clock_Source_XTAL; //select xrystal as clock input for the PLL
|
|
|
|
* Si5351_ConfigStruct.PLL[0].PLL_Multiplier_Integer = 32; //multiply the clock frequency by 32, this gets us 800 MHz clock
|
|
|
|
* Si5351_ConfigStruct.MS[0].MS_Clock_Source = MS_Clock_Source_PLLA; //select PLLA as clock source for MultiSynth 0
|
|
|
|
* Si5351_ConfigStruct.MS[0].MS_Divider_Integer = 250; //divide the 800 MHz by 250 this gets us 3.2 MHz
|
|
|
|
* Si5351_ConfigStruct.CLK[0].CLK_R_Div = CLK_R_Div64; //divide the MultiSynth output by 64, this gets us 50 kHz
|
|
|
|
* Si5351_ConfigStruct.CLK[0].CLK_Enable = ON; //turn on the output
|
|
|
|
* Si5351_Init(&Si5351_ConfigStruct); //apply the changes
|
|
|
|
*
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
/* Define to prevent recursive inclusion -------------------------------------*/
|
2022-05-24 08:01:52 +02:00
|
|
|
#ifndef _STM32_SI5351_H_
|
|
|
|
#define _STM32_SI5351_H_
|
2022-05-15 22:42:00 +02:00
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
|
|
#include <stdint.h>
|
2022-05-16 01:47:12 +02:00
|
|
|
#include <stm32_si5351_reg.h> /* register map of the Si5351 */
|
2022-05-24 08:01:52 +02:00
|
|
|
/* #include <errno.h> could also be included */
|
2022-05-15 22:42:00 +02:00
|
|
|
/* Private includes ----------------------------------------------------------*/
|
|
|
|
|
|
|
|
/* Exported types ------------------------------------------------------------*/
|
2022-05-24 08:01:52 +02:00
|
|
|
/*!< Si5351 instance typedef -- handle as pointer */
|
2022-05-15 22:42:00 +02:00
|
|
|
typedef struct __SI5351_HandleTypeDef *si5351_inst_t;
|
|
|
|
|
|
|
|
/* Exported constants --------------------------------------------------------*/
|
2022-05-16 01:47:12 +02:00
|
|
|
/** @enum errno_t Error Number Constants, @TODO could also errno.h included!!
|
2022-05-15 22:42:00 +02:00
|
|
|
*/
|
2022-07-15 12:42:42 +02:00
|
|
|
#if !defined _SYS_ERRNO_H_ && !defined __ERRNO_H__
|
2022-05-15 22:42:00 +02:00
|
|
|
typedef enum {
|
|
|
|
EPERM = 1, /*!< Operation not permitted */
|
2022-05-16 01:47:12 +02:00
|
|
|
EIO = 5, /*!< I/O error */
|
2022-05-15 22:42:00 +02:00
|
|
|
ENOMEM = 12, /*!< Out of memory */
|
2022-07-15 12:42:42 +02:00
|
|
|
EFAULT = 14, /*!< Bad address */
|
2022-05-16 01:47:12 +02:00
|
|
|
EBUSY = 16, /*!< Device or resource busy */
|
2022-07-15 12:42:42 +02:00
|
|
|
ENODEV = 19, /*!< No such device */
|
2022-05-15 22:42:00 +02:00
|
|
|
EINVAL = 22, /*!< Invalid argument */
|
2022-05-16 01:47:12 +02:00
|
|
|
EADDRINUSE = 98,/*!< Address already in use */
|
|
|
|
ETIMEDOUT = 116 /*!< Connection timed out */
|
2022-05-15 22:42:00 +02:00
|
|
|
} si5351_errno_t;
|
2022-05-24 08:01:52 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
SI5351_PLLA = 0,
|
|
|
|
SI5351_PLLB
|
|
|
|
}si5351_pll_t;
|
2022-05-15 22:42:00 +02:00
|
|
|
|
|
|
|
/* Exported variables --------------------------------------------------------*/
|
|
|
|
|
|
|
|
/* Exported macros -----------------------------------------------------------*/
|
2022-05-24 08:01:52 +02:00
|
|
|
#define __SI5351__ 1
|
|
|
|
#define __SI5351_MINOR__ 0
|
|
|
|
#define __SI5351_PATCHLEVEL__ 0
|
|
|
|
|
|
|
|
#define SI5351_VERSION (__SI5351__ * 10000 \
|
|
|
|
+ __SI5351_MINOR__ * 100 \
|
|
|
|
+ __SI5351_PATCHLEVEL__)
|
|
|
|
|
|
|
|
#ifndef SI5351_DEFAULTS
|
|
|
|
#define SI5351_DEFAULTS 1
|
|
|
|
#define SI5351_NUMBER_OF_OUTPUTS 8
|
|
|
|
#define SI5351_I2C_ADDRESS_DEFAULT 0x60
|
|
|
|
#define SI5351_XTAL_DEFAULT 25000000u // default xtal in [Hz]
|
2022-05-17 12:59:33 +02:00
|
|
|
#endif
|
|
|
|
|
2022-05-15 22:42:00 +02:00
|
|
|
/* Exported functions --------------------------------------------------------*/
|
2022-05-24 08:01:52 +02:00
|
|
|
si5351_inst_t si5351_init(void * i2c_handle, uint32_t xtal_frequency, uint8_t i2c_address, size_t datasize);
|
2022-05-15 22:42:00 +02:00
|
|
|
int si5351_deinit(si5351_inst_t si5351_handle);
|
2022-06-06 22:33:30 +02:00
|
|
|
int si5351_i2c_ready(si5351_inst_t inst);
|
2022-05-16 01:47:12 +02:00
|
|
|
int si5351_program(si5351_inst_t inst);
|
2022-05-24 08:01:52 +02:00
|
|
|
int si5351_enable_output(si5351_inst_t inst, uint8_t clk);
|
|
|
|
int si5351_disable_output(si5351_inst_t inst, uint8_t clk);
|
|
|
|
int si5351_set_clk0(si5351_inst_t inst, uint32_t frequency);
|
|
|
|
int si5351_set_clk(si5351_inst_t inst, uint32_t frequency, uint8_t clk, si5351_pll_t pll);
|
2022-06-06 22:33:30 +02:00
|
|
|
int si5351_set_clk_phase(si5351_inst_t inst, uint32_t frequency, double phase, uint8_t clk, si5351_pll_t pll);
|
|
|
|
int si5351_set_phase(si5351_inst_t inst, uint8_t phase, uint8_t clk);
|
|
|
|
|
2022-05-24 08:01:52 +02:00
|
|
|
|
|
|
|
#if SI5351_DEFAULTS
|
|
|
|
si5351_inst_t si5351_initialize(void * i2c_handle);
|
|
|
|
int si5351_deinitialize(void);
|
|
|
|
#endif
|
|
|
|
|
2022-05-17 01:28:20 +02:00
|
|
|
char * si5351_read_debug_msg(si5351_inst_t inst);
|
2022-05-17 12:59:33 +02:00
|
|
|
char * si5351_read_register_debug(si5351_inst_t inst, char *buf, size_t bufsize, uint8_t regaddr);
|
2022-05-15 22:42:00 +02:00
|
|
|
|
2022-05-24 08:01:52 +02:00
|
|
|
/* if initialized with data get a write and read functionality for data with: */
|
|
|
|
int si5351_write_data(si5351_inst_t inst, void * data);
|
|
|
|
int si5351_read_data(si5351_inst_t inst, void * data);
|
2022-05-15 22:42:00 +02:00
|
|
|
|
2022-05-24 08:01:52 +02:00
|
|
|
#ifdef __cplusplus
|
|
|
|
} /* extern "C" */
|
2022-05-15 22:42:00 +02:00
|
|
|
#endif
|
|
|
|
|
2022-05-24 08:01:52 +02:00
|
|
|
#endif // _STM32_SI5351_H_
|