diff --git a/Core/Inc/FreeRTOSConfig.h b/Core/Inc/FreeRTOSConfig.h index 138572f..f64c06e 100644 --- a/Core/Inc/FreeRTOSConfig.h +++ b/Core/Inc/FreeRTOSConfig.h @@ -68,7 +68,7 @@ #define configTICK_RATE_HZ ((TickType_t)1000) #define configMAX_PRIORITIES ( 56 ) #define configMINIMAL_STACK_SIZE ((uint16_t)128) -#define configTOTAL_HEAP_SIZE ((size_t)3000) +#define configTOTAL_HEAP_SIZE ((size_t)30000) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 0 diff --git a/Core/Inc/main.h b/Core/Inc/main.h index 6a2f69a..4781d83 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -57,8 +57,6 @@ void Error_Handler(void); /* USER CODE END EFP */ /* Private defines -----------------------------------------------------------*/ -#define B1_Pin GPIO_PIN_13 -#define B1_GPIO_Port GPIOC #define LD3_Pin GPIO_PIN_14 #define LD3_GPIO_Port GPIOB #define USB_OverCurrent_Pin GPIO_PIN_5 diff --git a/Core/Inc/stm32_si5351.h b/Core/Inc/stm32_si5351.h index 81a9a80..e41943c 100644 --- a/Core/Inc/stm32_si5351.h +++ b/Core/Inc/stm32_si5351.h @@ -15,10 +15,12 @@ * 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(); - * so between the USER CODE like using the given i2c handle "hi2c1": + * so between the USER CODE like using the given i2c handle "hi2c1" with default values: * * /\* USER CODE BEGIN 2 *\/ - * si5351_init(&hi2c1); + * + * si5351_inst_t si5351_inst; + * si5351_initialize(&hi2c1); * /\* USER CODE END 2 *\/ * * The 7-bit device (slave) address of the Si5351 consist of a 6-bit fixed @@ -72,8 +74,8 @@ ******************************************************************************/ /* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef STM32_SI5351_H -#define STM32_SI5351_H +#ifndef _STM32_SI5351_H_ +#define _STM32_SI5351_H_ #ifdef __cplusplus extern "C" { @@ -82,15 +84,17 @@ extern "C" { /* Includes ------------------------------------------------------------------*/ #include #include /* register map of the Si5351 */ +/* #include could also be included */ /* Private includes ----------------------------------------------------------*/ /* Exported types ------------------------------------------------------------*/ -/* Si5351 instance typedef */ +/*!< Si5351 instance typedef -- handle as pointer */ typedef struct __SI5351_HandleTypeDef *si5351_inst_t; /* Exported constants --------------------------------------------------------*/ /** @enum errno_t Error Number Constants, @TODO could also errno.h included!! */ +#if !defined _SYS_ERRNO_H_ || !defined __ERRNO_H__ typedef enum { EPERM = 1, /*!< Operation not permitted */ EIO = 5, /*!< I/O error */ @@ -101,545 +105,56 @@ typedef enum { EADDRINUSE = 98,/*!< Address already in use */ ETIMEDOUT = 116 /*!< Connection timed out */ } si5351_errno_t; +#endif + +typedef enum { + SI5351_PLLA = 0, + SI5351_PLLB +}si5351_pll_t; /* Exported variables --------------------------------------------------------*/ /* Exported macros -----------------------------------------------------------*/ -#ifndef SI5351_NUMBER_OF_OUTPUTS -#define SI5351_NUMBER_OF_OUTPUTS 8 -#endif +#define __SI5351__ 1 +#define __SI5351_MINOR__ 0 +#define __SI5351_PATCHLEVEL__ 0 -#ifdef __arm__ -#ifdef __ARM_BIG_ENDIAN -#define for_endian(size) for (int i = 0; i < size; ++i) -#define last_loop_endian (i==size-1) -#else -#define for_endian(size) for (int i = size - 1; i >= 0; --i) -#define last_loop_endian (i==0) -#endif -#else -#error "Endianness not detected or another compiler" +#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] #endif /* Exported functions --------------------------------------------------------*/ -si5351_inst_t si5351_init(void * i2c_handle, uint32_t xtal_frequency, uint8_t i2c_address); +si5351_inst_t si5351_init(void * i2c_handle, uint32_t xtal_frequency, uint8_t i2c_address, size_t datasize); int si5351_deinit(si5351_inst_t si5351_handle); int si5351_isready(si5351_inst_t inst); int si5351_program(si5351_inst_t inst); +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); + +#if SI5351_DEFAULTS +si5351_inst_t si5351_initialize(void * i2c_handle); +int si5351_deinitialize(void); +#endif + char * si5351_read_debug_msg(si5351_inst_t inst); char * si5351_read_register_debug(si5351_inst_t inst, char *buf, size_t bufsize, uint8_t regaddr); +/* 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); + + #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* STM32_SI5351_H */ - -/* - * si5351.h - * - * Created on: Feb 16, 2018 - * Author: Petr Polasek - * - * To make this library useable on any other device than - * STM32Fxxx Cortex Mx, please edit these parts of the library: - * - * DEFINES: - * SI5351_I2C_PERIPHERAL - the I2C peripheral name according - * to your devices HAL library - * I2C_TIMEOUT - time for the communication to time out - * - * TYPEDEFS: - * Si5351_ConfigTypeDef - the I2Cx parameter should be changed - * so that its type corresponds to your HAL library - * - * FUNCTIONS: - * Si5351_WriteRegister - * Si5351_ReadRegister - * You need to write your own I2C handlers here - * - */ -#if 0 -#ifndef ENABLESTATE -#define ENABLESTATE -typedef enum - { - OFF = 0, - ON = 1 - } EnableState; -#endif - -/* - * This section contains register addresses and bit masks for - * the device status registers. - */ - -#define REG_DEV_STATUS 0 - #define DEV_SYS_INIT_MASK 0x80 - #define DEV_LOL_B_MASK 0x40 - #define DEV_LOL_A_MASK 0x20 - #define DEV_LOS_CLKIN_MASK 0x10 - #define DEV_LOS_XTAL_MASK 0x08 - #define DEV_REVID_MASK 0x03 - -#define REG_DEV_STICKY 1 - #define DEV_STKY_SYS_INIT_MASK 0x80 - #define DEV_STKY_LOL_B_MASK 0x40 - #define DEV_STKY_LOL_A_MASK 0x20 - #define DEV_STKY_LOS_CLKIN_MASK 0x10 - #define DEV_STKY_LOS_XTAL_MASK 0x08 - -#define REG_INT_MASK 2 - #define INT_MASK_SYS_INIT_MASK 0x80 - #define INT_MASK_LOL_B_MASK 0x40 - #define INT_MASK_LOL_A_MASK 0x20 - #define INT_MASK_LOS_CLKIN_MASK 0x10 - #define INT_MASK_LOS_XTAL_MASK 0x08 - -/* - * This section contains data structures for configuring the - * oscillator, VCXO and CLKIN section. - */ - -#define REG_XTAL_CL 183 -#define XTAL_CL_MASK 0xC0 -#define PLL_CL_MASK 0x36 - -//this sets the crystal load capacitance -typedef enum -{ - XTAL_Load_4_pF = 0x00, - XTAL_Load_6_pF = 0x40, - XTAL_Load_8_pF = 0x80, - XTAL_Load_10_pF = 0xC0 -} Si5351_XTALLoadTypeDef; - -//The following is an unexplained parameter. However someone from SiLabs called it "VCO load cap". -//Lower settings seem to be more stable on higher frequencies, higher settings are more stable on lower frequencies allowing to tune the PLL to <200 MHz. -typedef enum -{ - PLL_Capacitive_Load_0 = 0, - PLL_Capacitive_Load_1 = 1, - PLL_Capacitive_Load_2 = 2 -} Si5351_PLLCapacitiveLoadTypeDef; - -#define REG_CLKIN_DIV 15 -#define CLKIN_MASK 0xC0 - -//this sets the CLKIN pre-divider, after division, CLKIN should -//fall between 10-40 MHz -typedef enum -{ - CLKINDiv_Div1 = 0x00, - CLKINDiv_Div2 = 0x40, - CLKINDiv_Div4 = 0x80, - CLKINDiv_Div8 = 0xC0 -} Si5351_CLKINDivTypeDef; - -#define REG_FANOUT_EN 187 -#define FANOUT_CLKIN_EN_MASK 0x80 -#define FANOUT_XO_EN_MASK 0x40 -#define FANOUT_MS_EN_MASK 0x10 - -#define REG_VCXO_PARAM_0_7 162 -#define REG_VCXO_PARAM_8_15 163 -#define REG_VCXO_PARAM_16_21 164 -#define VCXO_PARAM_16_21_MASK 0x3F -#define VCXO_PARAM_MASK 0x003FFFFF - -#define APR_MINIMUM 30 //minimum pull range -#define APR_MAXIMUM 240 //maximum pull range - -#define CLKIN_MINIMUM 10000 //minimum CLKIN frequency after division in kHz -#define CLKIN_MAXIMUM 40000 //maximum CLKIN frequency after division in kHz - -typedef struct -{ - Si5351_XTALLoadTypeDef OSC_XTAL_Load; //capacitive load of XTAL, 10pF by default - Si5351_CLKINDivTypeDef CLKIN_Div; //CLKIN predivision, input f to PLL must be 10-40 MHz - uint8_t VCXO_Pull_Range_ppm; //can range from +-30 ppm to 240ppm -} Si5351_OSCConfigTypeDef; - -/* - * This section contains data structures for configuring the - * PLL (PLLA and PLLB) - */ - -#define REG_PLL_CLOCK_SOURCE 15 -#define PLLA_CLOCK_SOURCE_MASK 0x04 -#define PLLB_CLOCK_SOURCE_MASK 0x08 - -//this selects the clock source for the PLL -typedef enum -{ - PLL_Clock_Source_XTAL = 0x00, - PLL_Clock_Source_CLKIN = 0x0C //0x04 for PLLA, 0x08 for PLLB, use mask! -} Si5351_PLLClockSourceTypeDef; - -#define REG_FB_INT 22 -#define FB_INT_MASK 0x40 - -#define REG_PLL_RESET 177 -#define PLLA_RESET_MASK 0x20 -#define PLLB_RESET_MASK 0x80 - -#define REG_MSN_P1_0_7 30 -#define REG_MSN_P1_8_15 29 -#define REG_MSN_P1_16_17 28 -#define MSN_P1_16_17_MASK 0x03 - -#define REG_MSN_P2_0_7 33 -#define REG_MSN_P2_8_15 32 -#define REG_MSN_P2_16_19 31 -#define MSN_P2_16_19_MASK 0x0F - -#define REG_MSN_P3_0_7 27 -#define REG_MSN_P3_8_15 26 -#define REG_MSN_P3_16_19 31 -#define MSN_P3_16_19_MASK 0xF0 - -#define MSNA_MSNB_OFFSET 8 - -typedef struct -{ - uint32_t PLL_Multiplier_Integer; - uint32_t PLL_Multiplier_Numerator; - uint32_t PLL_Multiplier_Denominator; - Si5351_PLLClockSourceTypeDef PLL_Clock_Source; - Si5351_PLLCapacitiveLoadTypeDef PLL_Capacitive_Load; -} Si5351_PLLConfigTypeDef; - -/* - * This section contains data structures for configuring the - * Spread Spectrum feature. - */ - -#define REG_SSC_MODE 151 -#define SSC_MODE_MASK 0x80 - -//this selects the Spread Spectrum mode -typedef enum -{ - SS_Mode_DownSpread = 0x00, - SS_Mode_CenterSpread = 0x80 -} Si5351_SSModeTypeDef; - -typedef enum -{ - SS_NCLK_0 = 0x00, - SS_NCLK_1 = 0x10, - SS_NCLK_2 = 0x20, - SS_NCLK_3 = 0x30, - SS_NCLK_4 = 0x40, - SS_NCLK_5 = 0x50, - SS_NCLK_6 = 0x60, - SS_NCLK_7 = 0x70, - SS_NCLK_8 = 0x80, - SS_NCLK_9 = 0x90, - SS_NCLK_10 = 0xA0, - SS_NCLK_11 = 0xB0, - SS_NCLK_12 = 0xC0, - SS_NCLK_13 = 0xD0, - SS_NCLK_14 = 0xE0, - SS_NCLK_15 = 0xF0 -} Si5351_SSNCLKTypeDef; - -#define REG_SSDN_P1_0_7 153 -#define REG_SSDN_P1_8_11 154 -#define SSDN_P1_8_11_MASK 0x0F - -#define REG_SSDN_P2_0_7 150 -#define REG_SSDN_P2_8_14 149 -#define SSDN_P2_8_14_MASK 0x7F - -#define REG_SSDN_P3_0_7 152 -#define REG_SSDN_P3_8_14 151 -#define SSDN_P3_8_14_MASK 0x7F - -#define REG_SSUDP_0_7 155 -#define REG_SSUDP_8_11 154 -#define SSUDP_8_11_MASK 0xF0 - -#define REG_SSUP_P1_0_7 160 -#define REG_SSUP_P1_8_11 161 -#define SSUP_P1_8_11_MASK 0x0F - -#define REG_SSUP_P2_0_7 157 -#define REG_SSUP_P2_8_14 156 -#define SSUP_P2_8_14_MASK 0x7F - -#define REG_SSUP_P3_0_7 159 -#define REG_SSUP_P3_8_14 158 -#define SSUP_P3_8_14_MASK 0x7F - -#define REG_SSC_EN 149 -#define SSC_EN_MASK 0x80 - -#define REG_SS_NCLK 161 -#define SS_NCLK_MASK 0xF0 - -typedef struct -{ - uint32_t SS_Amplitude_ppm; //amplitude of the SS feature in ppm of center frequency - EnableState SS_Enable; - Si5351_SSModeTypeDef SS_Mode; - Si5351_SSNCLKTypeDef SS_NCLK; -} Si5351_SSConfigTypeDef; - -/* - * This section contains data structures for configuring the - * Output Multisynth. - */ - -//this selects the Multisynth clock source -typedef enum -{ - MS_Clock_Source_PLLA = 0x00, - MS_Clock_Source_PLLB = 0x20 -} Si5351_MSClockSourceTypeDef; - -#define REG_MS_P1_0_7 46 -#define REG_MS_P1_8_15 45 -#define REG_MS_P1_16_17 44 -#define MS_P1_16_17_MASK 0x03 - -#define REG_MS_P2_0_7 49 -#define REG_MS_P2_8_15 48 -#define REG_MS_P2_16_19 47 -#define MS_P2_16_19_MASK 0x0F - -#define REG_MS_P3_0_7 43 -#define REG_MS_P3_8_15 42 -#define REG_MS_P3_16_19 47 -#define MS_P3_16_19_MASK 0xF0 - -#define REG_MS67_P1 90 - -#define REG_MS_INT 16 -#define MS_INT_MASK 0x40 - -#define REG_MS_DIVBY4 44 -#define MS_DIVBY4_MASK 0x0C - -#define REG_MS_SRC 16 -#define MS_SRC_MASK 0x20 - -#define MS_SETUP_STEP 1 -#define MS_DIVIDER_STEP 8 - -typedef struct -{ - Si5351_MSClockSourceTypeDef MS_Clock_Source; //select source on MS input - uint32_t MS_Divider_Integer; //the integer part of divider, called "a" - uint32_t MS_Divider_Numerator; //the numerator, called "b" - uint32_t MS_Divider_Denominator; //the denominator, called "c" -} Si5351_MSConfigTypeDef; //sets MS divider ( a+(b/c) ) and clock (PLLA/PLLB) - -/* - * This section contains data structures for configuring the - * CLK, R divider and output stage (joined together because they make - * a tight block without any multiplexer). - */ - -#define REG_CLK_SRC 16 -#define CLK_SRC_MASK 0x0C - -//this sets the CLK source clock -typedef enum -{ - CLK_Clock_Source_XTAL = 0x00, - CLK_Clock_Source_CLKIN = 0x04, - CLK_Clock_Source_MS0_MS4 = 0x08, //this uses MS0 for CLK0..3 and MS4 for CLK4..7 - CLK_Clock_Source_MS_Own = 0x0C //this uses MSx for CLKx -} Si5351_CLKClockSourceTypeDef; //configures multiplexer on CLK input - -#define REG_CLK_R_DIV 44 -#define CLK_R_DIV_MASK 0x70 - -#define REG_CLK_R67_DIV 92 -#define CLK_R67_DIV_MASK 0x07 - -//this sets the R divider ratio -typedef enum -{ - CLK_R_Div1 = 0x00, - CLK_R_Div2 = 0x10, - CLK_R_Div4 = 0x20, - CLK_R_Div8 = 0x30, - CLK_R_Div16 = 0x40, - CLK_R_Div32 = 0x50, - CLK_R_Div64 = 0x60, - CLK_R_Div128 = 0x70 -} Si5351_CLKRDivTypeDef; - -#define REG_CLK_DIS_STATE 24 -#define CLK_DIS_STATE_MASK 0x03 - -//this sets output buffer behaviour when disabled -typedef enum -{ - CLK_Disable_State_LOW = 0x00, - CLK_Disable_State_HIGH = 0x01, - CLK_Disable_State_HIGH_Z = 0x02, //three-stated when off - CLK_Disable_State_ALWAYS_ON = 0x03 //cannot be disabled -} Si5351_CLKDisableStateTypeDef; - -#define REG_CLK_IDRV 16 -#define CLK_IDRV_MASK 0x03 - -//this sets current drive of the output buffer -typedef enum -{ - CLK_I_Drv_2mA = 0x00, - CLK_I_Drv_4mA = 0x01, - CLK_I_Drv_6mA = 0x02, - CLK_I_Drv_8mA = 0x03 -} Si5351_CLKIDrvTypeDef; - -#define REG_CLK_PHOFF 165 -#define CLK_PHOFF_MASK 0x7F - -#define REG_CLK_EN 3 - -#define REG_CLK_INV 16 -#define CLK_INV_MASK 0x10 - -#define REG_CLK_PDN 16 -#define CLK_PDN_MASK 0x80 - -#define REG_CLK_OEB 9 - -#define CLK_PHOFF_STEP 1 -#define CLK_SETUP_STEP 1 -#define CLK_R_DIV_STEP 8 - -typedef struct -{ - Si5351_CLKClockSourceTypeDef CLK_Clock_Source; //clock source - - /* this sets the time offset of the CLK channel, basic unit - * is one quarter of the VCO period (90deg offset), - * set it to 4*fVCO*toffset, the value is 7-bit, the max time offset - * varies between 35 and 53 ns (1 cycle for 28 and 19 MHz, respectively) - * according to the current frequency of the VCO - */ - uint8_t CLK_QuarterPeriod_Offset; - - Si5351_CLKRDivTypeDef CLK_R_Div; //R divider value (only powers of 2) - EnableState CLK_Invert; //invert output clock - EnableState CLK_Enable; //enable flag - EnableState CLK_PowerDown; //powerdown flag - Si5351_CLKDisableStateTypeDef CLK_Disable_State; //sets output behaviour when disabled - Si5351_CLKIDrvTypeDef CLK_I_Drv; //output driver current drive strength - EnableState CLK_Use_OEB_Pin; //allows using OEB pin to enable clock -} Si5351_CLKConfigTypeDef; - -/* - * This section contains main data structure for Si5351 configuration - */ - -typedef struct -{ - /* - * These are frequencies of the input clocks, set it in Hz. - */ - uint32_t f_XTAL; - uint32_t f_CLKIN; - - //Interrupt masking - enabling it disables the int source from pulling INTR low - EnableState Interrupt_Mask_SysInit; - EnableState Interrupt_Mask_PLLB; - EnableState Interrupt_Mask_PLLA; - EnableState Interrupt_Mask_CLKIN; - EnableState Interrupt_Mask_XTAL; - - //Fanout enable - enables internal clock routing - EnableState Fanout_MS_EN; - EnableState Fanout_XO_EN; - EnableState Fanout_CLKIN_EN; - - I2C_TypeDef *I2Cx; //the I2C interface that will be used - uint8_t HW_I2C_Address; //I2C address of the Si5351 for the packages with A0 pin - //(also, some duds with strange address reported) - Si5351_OSCConfigTypeDef OSC; //Oscillator, CLKIN and VCXO settings - Si5351_PLLConfigTypeDef PLL[2]; //PLL settings for PLLA and PLLB - Si5351_MSConfigTypeDef MS[8]; //MultiSynth[0..7] settings - Si5351_CLKConfigTypeDef CLK[8]; //CLK[0..7], R divider and output stage settings - Si5351_SSConfigTypeDef SS; //spread spectrum settings -} Si5351_ConfigTypeDef; - -/* - * Typedefs for selecting PLL, MS and CLK to be used - */ - -//this selects PLL channel -typedef enum -{ - PLL_A = 0, - PLL_B = 1 -} Si5351_PLLChannelTypeDef; - -//this selects Multisynth channel -typedef enum -{ - MS0 = 0, - MS1 = 1, - MS2 = 2, - MS3 = 3, - MS4 = 4, - MS5 = 5, - MS6 = 6, - MS7 = 7 -} Si5351_MSChannelTypeDef; - -//this selects CLK channel -typedef enum -{ - CLK0 = 0, - CLK1 = 1, - CLK2 = 2, - CLK3 = 3, - CLK4 = 4, - CLK5 = 5, - CLK6 = 6, - CLK7 = 7 -} Si5351_CLKChannelTypeDef; - -//this selects device status flag -typedef enum -{ - StatusBit_SysInit = DEV_SYS_INIT_MASK, - StatusBit_PLLA = DEV_STKY_LOL_A_MASK, - StatusBit_PLLB = DEV_LOL_B_MASK, - StatusBit_CLKIN = DEV_LOS_CLKIN_MASK, - StatusBit_XTAL = DEV_LOS_XTAL_MASK, -} Si5351_StatusBitTypeDef; - -//these write to and read from a Si5351 register, for porting -//purposes, these functions should be the only ones which should need edits -int Si5351_WriteRegister(Si5351_ConfigTypeDef *Si5351_ConfigStruct, uint8_t reg_address, uint8_t reg_data); -uint8_t Si5351_ReadRegister(Si5351_ConfigTypeDef *Si5351_ConfigStruct, uint8_t reg_address); - -void Si5351_StructInit(Si5351_ConfigTypeDef *Si5351_ConfigStruct); - -void Si5351_OSCConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct); - -EnableState Si5351_CheckStatusBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit); -EnableState Si5351_CheckStickyBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit); -void Si5351_InterruptConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct); -void Si5351_ClearStickyBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit); - -void Si5351_PLLConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_PLLChannelTypeDef PLL_Channel); -void Si5351_PLLReset(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_PLLChannelTypeDef PLL_Channel); -void Si5351_PLLSimultaneousReset(Si5351_ConfigTypeDef *Si5351_ConfigStruct); - -void Si5351_SSConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct); - -void Si5351_MSConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_MSChannelTypeDef MS_Channel); - -void Si5351_CLKPowerCmd(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_CLKChannelTypeDef CLK_Channel); -void Si5351_CLKConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_CLKChannelTypeDef CLK_Channel); - -int Si5351_Init(Si5351_ConfigTypeDef *Si5351_ConfigStruct); -#endif /* SI5351_H_ */ - +#endif // _STM32_SI5351_H_ diff --git a/Core/Inc/stm32_si5351_reg.h b/Core/Inc/stm32_si5351_reg.h index 727694e..88aab4a 100644 --- a/Core/Inc/stm32_si5351_reg.h +++ b/Core/Inc/stm32_si5351_reg.h @@ -60,6 +60,7 @@ #define SI5351_PLLA_SRC (1u<<2) /* Input Source Select for PLLA. */ #define SI5351_PLL_INPUT_SOURCE_RESET_VALUE 0x00 +/* CLK0 Control */ #define SI5351_CLK0_CONTROL 16u /* R/W */ #define SI5351_CLK0_PDN (1u<<7) /* Clock 0 Power Down. */ #define SI5351_MS0_INT (1u<<6) /* MultiSynth 0 Integer Mode. 1..MS0 operates in integer mode. */ @@ -70,8 +71,8 @@ #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_CLK_SRC_RESERVED (0x02<<2) /*!< DO NOT Select this option */ +#define SI5351_CLK_SRC_MS0 (0x03<<2) /*!< Select the MulitSynth 0 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 SI5351_CLK0_IDRV (3u<<0) /* 00: 2 mA, 01: 4 mA, 10: 6 mA, 11: 8 mA */ @@ -1081,6 +1082,7 @@ even integers greater than or equal to 6. All other divide values are invalid. * #define SI5351_PLLB_RST (1u<<7) /*!< PLLB_Reset, writing a 1 to this bit will reset PLLB. This is a self clearing bit */ #define SI5351_PLLA_RST (1u<<5) /*!< PLLA_Reset, writing a 1 to this bit will reset PLLA. This is a self clearing bit */ #define SI5351_PLL_RESET_RESERVED (0x5F) /*!< leave as default, not specified */ +#define SI5351_PLL_RESET_VALUE (0xAC) /*!< according to SI5351 datasheet Figure 10, page 21, applying PLLA, PLLB soft reset */ /* Crystal Internal Load Capacitance * Two bits determine the internal load capacitance value for the crystal. See the Crystal @@ -1092,7 +1094,18 @@ even integers greater than or equal to 6. All other divide values are invalid. * #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! */ +#define SI5351_XTAL_RESERVED (0x13) /*!< RESERVED bit[5:0] should be written! (0b010010) */ +/* There is some mystery about the value of these bits [5:0], in AN619 version 0.6, there are two values + * miscellaneous PLL parameters PLLA_CL and PLLB_CL which should be set each of them to 2, + * that could possibly be bits [5:4] and [2:1] ? + * Reg183 contains suspicious bits which are rather unexplained on page 60, where there is stated that reg183, bits [5:0] should + * be set to 010010b. Maybe it sets speed of the PLL loop? + * After a bit of experimentation, it seems to be like this: Bit [0]: does nothing; Bits [2:1]: Setting one of these bits causes + * the PLLA to become unstable. + * Setting both of them also causes the SysInit and PLLB to be stuck in failure for a long time, then they start. It seems that + * these bits allow you to tune the PLL to <200 MHz. Bit [3]: does nothing; Bits [5:4]: The same as [2:1], but for PLLB. + */ + /* Fanout Enable, set these bits to 1 for each fanout * note: the reset value of this SI5351 register is 0x00 */ diff --git a/Core/Inc/stm32l4xx_hal_conf.h b/Core/Inc/stm32l4xx_hal_conf.h index f628d67..0c4f756 100644 --- a/Core/Inc/stm32l4xx_hal_conf.h +++ b/Core/Inc/stm32l4xx_hal_conf.h @@ -68,7 +68,7 @@ /*#define HAL_QSPI_MODULE_ENABLED */ /*#define HAL_QSPI_MODULE_ENABLED */ /*#define HAL_RNG_MODULE_ENABLED */ -/*#define HAL_RTC_MODULE_ENABLED */ +#define HAL_RTC_MODULE_ENABLED /*#define HAL_SAI_MODULE_ENABLED */ /*#define HAL_SD_MODULE_ENABLED */ /*#define HAL_SMBUS_MODULE_ENABLED */ @@ -152,7 +152,7 @@ #endif /* LSE_VALUE */ #if !defined (LSE_STARTUP_TIMEOUT) - #define LSE_STARTUP_TIMEOUT 5000U /*!< Time out for LSE start up, in ms */ + #define LSE_STARTUP_TIMEOUT 50000U /*!< Time out for LSE start up, in ms */ #endif /* HSE_STARTUP_TIMEOUT */ /** diff --git a/Core/Inc/stm32l4xx_it.h b/Core/Inc/stm32l4xx_it.h index 49f364d..13dc2e9 100644 --- a/Core/Inc/stm32l4xx_it.h +++ b/Core/Inc/stm32l4xx_it.h @@ -52,7 +52,7 @@ void MemManage_Handler(void); void BusFault_Handler(void); void UsageFault_Handler(void); void DebugMon_Handler(void); -void TIM1_UP_TIM16_IRQHandler(void); +void TIM6_DAC_IRQHandler(void); void LPUART1_IRQHandler(void); /* USER CODE BEGIN EFP */ diff --git a/Core/Src/main.c b/Core/Src/main.c index 6d990a4..dbf21ee 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -46,6 +46,8 @@ UART_HandleTypeDef hlpuart1; +RTC_HandleTypeDef hrtc; + PCD_HandleTypeDef hpcd_USB_OTG_FS; /* Definitions for defaultTask */ @@ -62,12 +64,29 @@ const osThreadAttr_t terminalTask_attributes = { .stack_size = 128 * 4, .priority = (osPriority_t) osPriorityBelowNormal, }; -/* Definitions for idTask */ -osThreadId_t idTaskHandle; -const osThreadAttr_t idTask_attributes = { - .name = "idTask", +/* Definitions for morseTask */ +osThreadId_t morseTaskHandle; +const osThreadAttr_t morseTask_attributes = { + .name = "morseTask", .stack_size = 128 * 4, - .priority = (osPriority_t) osPriorityLow, + .priority = (osPriority_t) osPriorityNormal, +}; +/* Definitions for clk2Task */ +osThreadId_t clk2TaskHandle; +const osThreadAttr_t clk2Task_attributes = { + .name = "clk2Task", + .stack_size = 128 * 4, + .priority = (osPriority_t) osPriorityHigh, +}; +/* Definitions for morseQueue */ +osMessageQueueId_t morseQueueHandle; +const osMessageQueueAttr_t morseQueue_attributes = { + .name = "morseQueue" +}; +/* Definitions for data_access */ +osSemaphoreId_t data_accessHandle; +const osSemaphoreAttr_t data_access_attributes = { + .name = "data_access" }; /* USER CODE BEGIN PV */ @@ -79,9 +98,11 @@ static void MX_GPIO_Init(void); static void MX_LPUART1_UART_Init(void); static void MX_USB_OTG_FS_PCD_Init(void); static void MX_I2C1_Init(void); +static void MX_RTC_Init(void); void StartDefaultTask(void *argument); void start_terminal_task(void *argument); -void start_id_task(void *argument); +void start_morse_task(void *argument); +void start_clk2_task(void *argument); /* USER CODE BEGIN PFP */ // redirect the output of the printf function to the USART print function @@ -125,16 +146,20 @@ int main(void) MX_LPUART1_UART_Init(); MX_USB_OTG_FS_PCD_Init(); MX_I2C1_Init(); + MX_RTC_Init(); /* USER CODE BEGIN 2 */ si5351_inst_t instance_si5351[3] = {0}; + si5351_inst_t si5351_inst; // 1st SI5351 chip and with an A0 = 0: - instance_si5351[0] = si5351_init(&hi2c1, 27000000, 0x61); + /*instance_si5351[0] = si5351_init(&hi2c1, 27000000, 0x61, 0);*/ // 2nd SI5351 chip on the same I2C bus "hi2c1" but address line A0 = 1 - instance_si5351[1] = si5351_init(&hi2c1, 27000000, 0x60); + instance_si5351[1] = si5351_init(&hi2c1, 25000000, 0x60, 3 * sizeof(uint32_t)); // 3rd SI5351 chip on another IC2 bus with handle "hi2c2" *\/ - instance_si5351[2] = si5351_init(&hi2c1, 25000000, 0x60); + instance_si5351[2] = si5351_init(&hi2c1, 25000000, 0x60, 0); + + si5351_inst = instance_si5351[1]; for (int i=0; i<3 ;i++) { int ready; @@ -149,13 +174,44 @@ int main(void) puts(si5351_read_register_debug(instance_si5351[1], buf, sizeof(buf), i)); } - status = si5351_program(instance_si5351[1]); + // 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])); + //si5351_set_clk0(instance_si5351[1], 3579545); + // si5351_set_clk0(instance_si5351[1], 3580000); + // si5351_set_clk0(instance_si5351[1], 4000000); + si5351_set_clk0(instance_si5351[1], 3510000); + si5351_enable_output(instance_si5351[1],0); + HAL_Delay(1000); + si5351_set_clk0(instance_si5351[1], 6055000); + si5351_enable_output(instance_si5351[1],0); + HAL_Delay(1000); + si5351_set_clk0(instance_si5351[1], 99900000); + si5351_enable_output(instance_si5351[1],0); + HAL_Delay(5000); + si5351_set_clk0(instance_si5351[1], 144500000); + si5351_enable_output(instance_si5351[1],0); + HAL_Delay(10000); + + + /* World Youth ARDF Championship Romania 2022 */ + /* 80 m . RF power 3 W, QRG MOE-MO5: 3550 MHz, MO: 3600 MHz, Antenna 8m + * 80 m Sprint pwr 1 W, TX 1-5: MOE-MO5: 3530 MHz, S: 3550 MHz, TX 1F-5F MOE-MO5: 3570 MHz + * MO: 3600 MHz, Antenna: 8m + * 2 m RF power 1 W, MOE-MO5: 144.500, MO: 144.900 MHz, crossed dipole + */ + si5351_set_clk0(si5351_inst, 3550000); + + si5351_set_clk(si5351_inst, 3570000, 2, SI5351_PLLB); + si5351_enable_output(NULL,2); + + +/* for (int i=2; i>=0; i--) { si5351_deinit(instance_si5351[i]); } +*/ /* USER CODE END 2 */ /* Init scheduler */ @@ -165,6 +221,10 @@ int main(void) /* add mutexes, ... */ /* USER CODE END RTOS_MUTEX */ + /* Create the semaphores(s) */ + /* creation of data_access */ + data_accessHandle = osSemaphoreNew(1, 1, &data_access_attributes); + /* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ /* USER CODE END RTOS_SEMAPHORES */ @@ -173,6 +233,10 @@ int main(void) /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */ + /* Create the queue(s) */ + /* creation of morseQueue */ + morseQueueHandle = osMessageQueueNew (16, sizeof(uint16_t), &morseQueue_attributes); + /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ @@ -184,8 +248,11 @@ int main(void) /* creation of terminalTask */ terminalTaskHandle = osThreadNew(start_terminal_task, NULL, &terminalTask_attributes); - /* creation of idTask */ - // idTaskHandle = osThreadNew(start_id_task, NULL, &idTask_attributes); + /* creation of morseTask */ + morseTaskHandle = osThreadNew(start_morse_task, (void*) si5351_inst, &morseTask_attributes); + + /* creation of clk2Task */ + clk2TaskHandle = osThreadNew(start_clk2_task, (void*) si5351_inst, &clk2Task_attributes); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ @@ -230,13 +297,15 @@ void SystemClock_Config(void) /** Configure LSE Drive Capability */ HAL_PWR_EnableBkUpAccess(); - __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); + __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_HIGH); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE|RCC_OSCILLATORTYPE_MSI; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_LSE + |RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.LSEState = RCC_LSE_ON; + RCC_OscInitStruct.LSIState = RCC_LSI_ON; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = 0; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; @@ -265,6 +334,7 @@ void SystemClock_Config(void) { Error_Handler(); } + HAL_RCCEx_EnableLSCO(RCC_LSCOSOURCE_LSI); /** Enable MSI Auto calibration */ @@ -353,6 +423,70 @@ static void MX_LPUART1_UART_Init(void) } +/** + * @brief RTC Initialization Function + * @param None + * @retval None + */ +static void MX_RTC_Init(void) +{ + + /* USER CODE BEGIN RTC_Init 0 */ + + /* USER CODE END RTC_Init 0 */ + + RTC_TimeTypeDef sTime = {0}; + RTC_DateTypeDef sDate = {0}; + + /* USER CODE BEGIN RTC_Init 1 */ + + /* USER CODE END RTC_Init 1 */ + + /** Initialize RTC Only + */ + hrtc.Instance = RTC; + hrtc.Init.HourFormat = RTC_HOURFORMAT_24; + hrtc.Init.AsynchPrediv = 127; + hrtc.Init.SynchPrediv = 255; + hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; + hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE; + hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; + hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; + if (HAL_RTC_Init(&hrtc) != HAL_OK) + { + Error_Handler(); + } + + /* USER CODE BEGIN Check_RTC_BKUP */ + + /* USER CODE END Check_RTC_BKUP */ + + /** Initialize RTC and set the Time and Date + */ + sTime.Hours = 0x12; + sTime.Minutes = 0x30; + sTime.Seconds = 0x0; + sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; + sTime.StoreOperation = RTC_STOREOPERATION_RESET; + if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK) + { + Error_Handler(); + } + sDate.WeekDay = RTC_WEEKDAY_MONDAY; + sDate.Month = RTC_MONTH_MAY; + sDate.Date = 0x23; + sDate.Year = 0x22; + + if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN RTC_Init 2 */ + + /* USER CODE END RTC_Init 2 */ + +} + /** * @brief USB_OTG_FS Initialization Function * @param None @@ -429,11 +563,17 @@ static void MX_GPIO_Init(void) GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); - /*Configure GPIO pin : B1_Pin */ - GPIO_InitStruct.Pin = B1_Pin; - GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; + /*Configure GPIO pins : PC13 PC0 PC1 PC2 + PC3 PC4 PC5 PC6 + PC8 PC9 PC10 PC11 + PC12 */ + GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2 + |GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6 + |GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 + |GPIO_PIN_12; + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct); + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /*Configure GPIO pins : PF0 PF1 PF2 PF3 PF4 PF5 PF6 PF7 @@ -453,16 +593,6 @@ static void MX_GPIO_Init(void) GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); - /*Configure GPIO pins : PC0 PC1 PC2 PC3 - PC4 PC5 PC6 PC8 - PC9 PC10 PC11 PC12 */ - GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 - |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_8 - |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12; - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); - /*Configure GPIO pins : PA0 PA1 PA2 PA3 PA4 PA5 PA6 PA7 PA15 */ @@ -548,6 +678,91 @@ PUTCHAR_PROTOTYPE return ch; } +void make_di_dah(si5351_inst_t inst, uint8_t clk, unsigned int dah, uint32_t delay) { + + /* inner function, no need to check inst */ + if(!delay) + return; + + HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET); + (void) si5351_enable_output(inst, clk); + osDelay(dah ? 3*delay : delay); // dit: 1 unit; dah 3 units length + HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET); + (void) si5351_disable_output(inst, clk); + osDelay(delay); // one unit of inter character space (gap b/w dits and dahs within a character) +} + + +void morse(si5351_inst_t inst, uint8_t clk, char * s) { + + const uint8_t mcode[] = {0x0d,0x57,0x77,0x17,0x01,0x75,0x1f,0x55,0x05,0xfd, + 0x37,0x5d,0x0f,0x07,0x3f,0x7d,0xdf,0x1d,0x15,0x03, + 0x35,0xd5,0x3d,0xd7,0xf7,0x5f, + 0xf0,0xe0,0xc0,0x80,0x00,0x08,0x18,0x38,0x78,0xF8, + 0xAA}; + uint32_t delay[3]; + uint8_t ch; + if(clk >= 3) + return; + + osSemaphoreAcquire(data_accessHandle,osWaitForever); + (void) si5351_read_data(inst, delay); + osSemaphoreRelease(data_accessHandle); + + while ((ch = *s++)) { + /* ascii code: numbers b/w 0x30 - 0x39 chars b/w 0x41 - 0x5A and 0x61 - 0x7A */ + if ((ch > 0x40 && ch < 0x5B) || (ch > 0x60 && ch < 0x7A)) { + ch &= 0xDF; // make uppercase + ch -= 0x41; // index 0 for 'A' + } else if (ch > 0x2F && ch < 0x3A) { + ch -= 49-26; + } + + if (ch != 0x20 && ch < sizeof(mcode)) { //when space add an additional pause (do nothing) + + switch(ch) { + case '.': ch = 0x37; + break; + default: + ch = mcode[ch]; //from the given array morse code + } + if (ch & 0x01) { // character coding + for (int i=4; i>0; i--) { + switch ((ch & 0x03)) { + case 0: /* the end */ + i = 0; + break; + case 1: /* did */ + make_di_dah(inst, clk, 0, delay[clk]); + break; + case 3: /* dah */ + make_di_dah(inst, clk, 1, delay[clk]); + break; + case 2: /* failure */ + default: + i = -1; + break; + } + ch >>= 2; + } + } else if ((ch & 0x07) == 0) { // number coding + ch >>= 3; + for (int i= 5; i>0; i--) { + make_di_dah(inst, clk, ch & 0x01, delay[clk]); + ch >>= 1; + } + } else if ((ch & 0x03) == 2) { // special characters + ch >>= 2; + for (int i=6; i>0; i--) { + make_di_dah(inst, clk, ch & 0x01, delay[clk]); + ch >>= 1; + } + } + } + osDelay(3 * delay[clk]); //word inter character space (gap b/w the characters of a word) 3 units + } +} + /* USER CODE END 4 */ /* USER CODE BEGIN Header_StartDefaultTask */ @@ -559,17 +774,17 @@ PUTCHAR_PROTOTYPE /* USER CODE END Header_StartDefaultTask */ void StartDefaultTask(void *argument) { - /* USER CODE BEGIN 5 */ + /* USER CODE BEGIN 5 */ (void) argument; //unused argument /* Infinite loop */ for(;;) { // HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin); HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET); - osDelay(1); + osDelay(10); HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_RESET); - osDelay(1999); + osDelay(1000); } - /* USER CODE END 5 */ + /* USER CODE END 5 */ } /* USER CODE BEGIN Header_start_terminal_task */ @@ -581,48 +796,122 @@ void StartDefaultTask(void *argument) /* USER CODE END Header_start_terminal_task */ void start_terminal_task(void *argument) { - /* USER CODE BEGIN start_terminal_task */ + /* USER CODE BEGIN start_terminal_task */ (void)argument; + + HAL_StatusTypeDef status; + RTC_TimeTypeDef time; + RTC_DateTypeDef date; + /* Infinite loop */ for(;;) { - osDelay(1); + status = HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN); + if (status != HAL_OK) + puts("HAL_RTC_GetTime problem..."); + status = HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN); + printf("Date/Time: %02d%02d-%02d-%02d %02d:%02d:%02d\n", (date.Year < 22) ? 21 : 20, date.Year, date.Month, date.Date, time.Hours, time.Minutes, time.Seconds); + osDelay(999); } - /* USER CODE END start_terminal_task */ + /* USER CODE END start_terminal_task */ } -/* USER CODE BEGIN Header_start_id_task */ +/* USER CODE BEGIN Header_start_morse_task */ /** -* @brief Function implementing the idTask thread. +* @brief Function implementing the morseTask thread. * @param argument: Not used * @retval None */ -/* USER CODE END Header_start_id_task */ -void start_id_task(void *argument) +/* USER CODE END Header_start_morse_task */ +void start_morse_task(void *argument) { - /* USER CODE BEGIN start_id_task */ - (void)argument; //unused argument - //uint8_t tx_buf[80]; - //int tx_buf_len; - /* check if the SI5351 is present */ - int status = HAL_I2C_IsDeviceReady(&hi2c1, SI5351_I2C_ADDR, 3, 10 /*HAL_MAX_DELAY*/ ); // HAL_MAX_DELAY is blocking, use 10 ms + /* USER CODE BEGIN start_morse_task */ + static const uint32_t delay = 120; + static const uint8_t clk = 0; + si5351_inst_t inst = argument; + int i = 0; + uint32_t morsedelay[3]; // words per minute ? + + si5351_set_clk0(inst, 3550000); + + osSemaphoreAcquire(data_accessHandle,osWaitForever); + si5351_read_data(inst, morsedelay); + morsedelay[clk] = delay; + si5351_write_data(inst, morsedelay); + osSemaphoreRelease(data_accessHandle); /* Infinite loop */ - for(;;) { - printf("\n" PROGRAM_ID "\n"); - printf(AUTHOR_STRING "\n"); - if (status == HAL_OK) - printf("Si5351 device found.\n"); - else - printf("Error: Could not detect Si5351 device.\n"); + for (;;) { + // check clock RTC for e.g. cycle of 1 minutes TX with 4 minutes pause period + morse(inst, 0, "MO"); + osDelay(7*morsedelay[clk]); + if((++i % 8)==0) { + osSemaphoreAcquire(data_accessHandle,osWaitForever); + si5351_read_data(inst, morsedelay); + morsedelay[clk] = delay/4; + si5351_write_data(inst, morsedelay); + osSemaphoreRelease(data_accessHandle); + morse(inst, clk, " f0x.at1 de oe3tkt "); + osSemaphoreAcquire(data_accessHandle,osWaitForever); + si5351_read_data(inst, morsedelay); + morsedelay[clk] = delay; + si5351_write_data(inst, morsedelay); + osSemaphoreRelease(data_accessHandle); + osDelay(7*morsedelay[clk]); + } + } + /* USER CODE END start_morse_task */ +} - osDelay(30*60); - } - /* USER CODE END start_id_task */ +/* USER CODE BEGIN Header_start_clk2_task */ +/** +* @brief Function implementing the clk2Task thread. +* @param argument: Not used +* @retval None +*/ +/* USER CODE END Header_start_clk2_task */ +void start_clk2_task(void *argument) +{ + /* USER CODE BEGIN start_clk2_task */ + static const uint32_t delay = 100; + static const uint8_t clk =2; + si5351_inst_t inst = argument; + int i = 0; + uint32_t morsedelay[3]; // words per minute ? + + si5351_set_clk(inst, 3570000, clk, SI5351_PLLB); + + osSemaphoreAcquire(data_accessHandle,osWaitForever); + si5351_read_data(inst, morsedelay); + morsedelay[clk] = delay; + si5351_write_data(inst, morsedelay); + osSemaphoreRelease(data_accessHandle); + + /* Infinite loop */ + for (;;) { + // check clock RTC for e.g. cycle of 1 minutes TX with 4 minutes pause period + morse(inst, 0, "MOs"); + osDelay(7*morsedelay[clk]); + if((++i % 8)==0) { + osSemaphoreAcquire(data_accessHandle,osWaitForever); + si5351_read_data(inst, morsedelay); + morsedelay[clk] = delay/4; + si5351_write_data(inst, morsedelay); + osSemaphoreRelease(data_accessHandle); + morse(inst, clk, " f0x.at1 de oe3tkt "); + osSemaphoreAcquire(data_accessHandle,osWaitForever); + si5351_read_data(inst, morsedelay); + morsedelay[clk] = delay; + si5351_write_data(inst, morsedelay); + osSemaphoreRelease(data_accessHandle); + osDelay(7*morsedelay[clk]); + } + } + /* USER CODE END start_clk2_task */ } /** * @brief Period elapsed callback in non blocking mode - * @note This function is called when TIM16 interrupt took place, inside + * @note This function is called when TIM6 interrupt took place, inside * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment * a global variable "uwTick" used as application time base. * @param htim : TIM handle @@ -633,7 +922,7 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) /* USER CODE BEGIN Callback 0 */ /* USER CODE END Callback 0 */ - if (htim->Instance == TIM16) { + if (htim->Instance == TIM6) { HAL_IncTick(); } /* USER CODE BEGIN Callback 1 */ @@ -669,6 +958,7 @@ void assert_failed(uint8_t *file, uint32_t line) /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + printf("Wrong parameters value: file %s on line %d\r\n", file, line); /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ diff --git a/Core/Src/stm32_si5351.c b/Core/Src/stm32_si5351.c index 9cbb6e5..0d95d7d 100644 --- a/Core/Src/stm32_si5351.c +++ b/Core/Src/stm32_si5351.c @@ -7,63 +7,134 @@ * @author: Thomas Kuschel KW4NZ * created 2022-05-11 * - * adapted, idea and much information from Petr Polasek, created Feb 16, 2018 + * adapted, idea and much information from Petr Polasek + * thanks also to Aleksander Alekseev alias afiskon for his stm32 drivers + * + * A simple description can be found in the header file stm32_si5351.h, for + * more details read the supported README.md file ******************************************************************************/ /* Defines for compilation ---------------------------------------------------*/ +/* if you want to automatically enable the clk output after setting synthesis */ +#define AUTOMATICALLY_ENABLE_OUTPUT 0 +/* enable some optimizing, usually set to 1 */ #define OPTIMIZED 1 /* Includes ------------------------------------------------------------------*/ #include -// @TODO try to get rid off including the HAL here, using pointer to the specified functions #ifdef DEBUG +#define SI5351_DEBUG 0 #include #include #endif +#include +/* including the HAL here */ #include "stm32l4xx_hal.h" - +/* Include the header file */ #include "stm32_si5351.h" + /* Private typedef -----------------------------------------------------------*/ -/* @brief Si5351 handle structure definition +/* @brief Si5351 handle structure definition, private */ typedef struct __SI5351_HandleTypeDef { - void * i2c_handle; + void * i2c_handle; /*!< the I2C handle, must not be unique */ uint32_t xtal_frequency; /*!< XTAL or CLKIN frequency */ - int si5351_num; - struct __SI5351_HandleTypeDef *next; - char debug_msg[1000]; + void * data; /*!< data variable (dummy) for additional usage, set to NULL if not used */ + size_t datasize; /*!< size of data, set to 0 if not used */ + struct __SI5351_HandleTypeDef *next; /*!< next pointer to the following structure when there are several instances */ +#ifdef SI5351_DEBUG + char debug_msg[1000]; /*!< debugging messages for extesive tests of the Si5351 chip, not required */ +#endif + uint8_t clk_is_pllb; /*!< assignment of PLLA or PLLB per CLK #, if bit set to 1 ...PLLB */ + uint8_t clk_is_disabled; /*!< assignment of Output Enable Control, app. Register 3 */ uint8_t i2c_address; /*!< I2C address of the datasheet */ uint8_t interrupt_status_mask; /*!< Reg 2: Interrupt Status Mask */ uint8_t initialized:1; /*!< mark the driver initialized */ + uint8_t programmed:1; /*!< mark the chip is programmed */ } si5351_HandleTypeDef; -#ifndef __GNUC__ /*__arm__*/ /* Keil ARM compiler does not support typeof */ -#define snprintb(buf, n, value) __fprintb(buf, n, (uint32_t *)&value, sizeof(uint32_t)) -#define snprintb16(buf, n, value) __fprintb(buf, n, (uint16_t *)&value, sizeof(uint16_t)) -#define snprintb8(buf, n, value) __fprintb(buf, n, (uint8_t *)&value, sizeof(uint8_t)) -#else /* for gcc, clang compilers */ -#define snprintb(buf, n, value) \ -({ \ - typeof(value) _v = value; \ - __snprintb(buf, n, (typeof(_v) *) &_v, sizeof(_v)); \ -}) -#endif +/* @brief SI5351 synthesis settings */ +typedef struct { + uint32_t pll_multiplier; /*!< in datasheet this value corresponds to feedback multisynth (N) a */ + uint32_t pll_numerator; /*!< in datasheet this value corresponds to feedback multisynth (N) b */ + uint32_t pll_denominator; /*!< in datasheet this value corresponds to feedback multisynth (N) c */ + uint32_t out_multiplier; /*!< in datasheet this value corresponds to multisynth (M) a */ + uint32_t out_numerator; /*!< in datasheet this value corresponds to multisynth (M) b */ + uint32_t out_denominator; /*!< in datasheet this value corresponds to multisynth (M) c */ + uint8_t out_r_divider; /*!< R divider, log2 value bit set to 1; 2,4,8,...,128; for frequencies < 500 kHz, otherwise set to 1 i.e. bit 0 */ +} synthesis_t; + +typedef struct { + char band[4]; + uint32_t qrg_min; + uint32_t qrg_max; + uint32_t multiplier; + uint8_t divider_bit; +} band_t; + /* Private define ------------------------------------------------------------*/ -#define SI5351_VERSION 1 +#define SI5351_FREQUENCY_MIN 8000u +#define SI5351_FREQUENCY_MAX 160000000u + + +#define _80M_BAND_MIN 3000000u +#define _80M_BAND_MAX 4500000u +#define _80M_BAND_OUT_MULT 200u +#define _80M_BAND_R_DIV 0u /* 2^0 value */ /* Private macro -------------------------------------------------------------*/ +#ifdef __arm__ +#ifdef __ARM_BIG_ENDIAN +#define for_endian(size) for (int i = 0; i < size; ++i) +#define last_loop_endian (i==size-1) +#else +#define for_endian(size) for (int i = size - 1; i >= 0; --i) +#define last_loop_endian (i==0) +#endif +#else +#error "Endianness not detected or another compiler" +#endif + +#ifndef __GNUC__ /*__arm__*/ /* Keil ARM compiler does not support typeof */ +#define snprintb(buf, n, value) __snprintb(buf, n, (uint32_t *)&value, sizeof(uint32_t)) +#define snprintb16(buf, n, value) __snprintb(buf, n, (uint16_t *)&value, sizeof(uint16_t)) +#define snprintb8(buf, n, value) __snprintb(buf, n, (uint8_t *)&value, sizeof(uint8_t)) +#else /* for gcc, clang compilers */ +#define snprintb(buf, n, value) \ +({ \ + typeof(value) _v = value; \ + __snprintb(buf, n, (typeof(_v) *) &_v, sizeof(_v)); \ +}) +#endif + /* Private variables ---------------------------------------------------------*/ -si5351_HandleTypeDef * first_handle = NULL; /* pointer to the first instancee */ +si5351_HandleTypeDef * first_handle = NULL; /* pointer to the first instance */ int si5351_errno = 0; /* error_number for functions whith return == NULL */ + /* Private function prototypes -----------------------------------------------*/ int __fprintb(FILE *stream, void *value, size_t size); +int si5351_read(si5351_inst_t instance, uint8_t regaddr, uint8_t *data, uint16_t size); +int si5351_write(si5351_inst_t instance, uint8_t regaddr, uint8_t *data, uint16_t size); +int calculation(uint32_t frequency, uint32_t xtal, synthesis_t *synth); +int si5351_set_pll(si5351_inst_t inst, synthesis_t *synth); +int si5351_set_output(si5351_inst_t inst, synthesis_t *synth); +int si5351_set_synthesis(si5351_inst_t inst, synthesis_t *synth, uint8_t clk); + /* Private functions ---------------------------------------------------------*/ -/* wrapper function for receiving bytes from I2C bus +/** Wrapper functions for receiving/transceiving bytes from I2C bus (HAL function set) */ +/** @brief Give better error numbers based on the Linux error_no.h + * @param i2c_handle the handle of the I2C bus from HAL function, e.g. hi2c1 + * @param xtal_frequency either the XTAL frequency (25/27 MHz) or CLock-In + * from 10 MHz to 100 MHz entered in Hz + * @param i2c_address I2C bus address of the device from datasheet typically 0x60 (or 0x61) + * @param datasize reserve an extra area of data space in bytes, access with function si5351_read_data() and si5351_write_data() + * @return si5351_handle Pointer to the si5351 handle, NULL if error, see si5351_errno + */ static int si5351_error_status_i2c(HAL_StatusTypeDef status) { switch (status) { case HAL_TIMEOUT: return -ETIMEDOUT; break; @@ -74,44 +145,104 @@ static int si5351_error_status_i2c(HAL_StatusTypeDef status) { } } +/** @brief Read (blocking mode) one ore more data bytes from the I2C bus starting at the regaddr register address + * @param instance instance (handle) of the SI5351 driver + * @param regaddr starting register address of the SI5351 + * @param data pointer to the first byte of data + * @param datasize datasize of the reading data, sizeof (data), when reading only one register (byte), set to 1 + * @return errno 0 on success, see si5351_errno_t + * @retval -EINVAL when given a NULL handle + * @retval -ETIMEDOUT when HAL_TIMEOUT + * @retval -EIO when HAL_ERROR + * @retval -EBUSY when HAL_BUSY + * if applicable use interrupt controlled HAL functions + */ int si5351_read(si5351_inst_t instance, uint8_t regaddr, uint8_t *data, uint16_t size) { HAL_StatusTypeDef status; - status = HAL_I2C_Mem_Read(instance->i2c_handle, instance->i2c_address<<1, + status = HAL_I2C_Mem_Read(instance->i2c_handle, instance->i2c_address, (uint16_t)regaddr, I2C_MEMADD_SIZE_8BIT, data, size, 0xffff); return si5351_error_status_i2c(status); } +/** @brief Write (blocking mode) one ore more data bytes to the I2C bus starting at the regaddr register address + * @param instance instance (handle) of the SI5351 driver + * @param regaddr starting register address of the SI5351 + * @param data pointer to the first byte of data + * @param datasize datasize of the writing data, sizeof (data), when writing to one register (byte), set to 1 + * @return errno 0 on success, see si5351_errno_t + * @retval -EINVAL when given a NULL handle + * @retval -ETIMEDOUT when HAL_TIMEOUT + * @retval -EIO when HAL_ERROR + * @retval -EBUSY when HAL_BUSY + * if applicable use interrupt controlled HAL functions + */ int si5351_write(si5351_inst_t instance, uint8_t regaddr, uint8_t *data, uint16_t size) { HAL_StatusTypeDef status; - status = HAL_I2C_Mem_Write(instance->i2c_handle, instance->i2c_address<<1, + status = HAL_I2C_Mem_Write(instance->i2c_handle, instance->i2c_address, (uint16_t)regaddr, I2C_MEMADD_SIZE_8BIT, data, size, 0xffff); return si5351_error_status_i2c(status); } +/** @brief Check if there is any I2C device ready on the bus + * @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_isready(si5351_inst_t inst) { + + int status; + + if(!inst && !(inst=first_handle)) + return -EINVAL; + + /* call HAL function for device ready check */ + status = HAL_I2C_IsDeviceReady(inst->i2c_handle, inst->i2c_address, 3, 100 /*HAL_MAX_DELAY*/ ); // HAL_MAX_DELAY is blocking, use 100 ms + /* maybe create a pointer to that function for more flexiblity using other tools as HAL */ + return si5351_error_status_i2c(status); +} + +/* End of wrapper functions receiving/transceiving bytes */ + + +/** @brief Wrapper of init with default values: xtal set to 25 MHz, i2c_address set to 0x60 + * @param i2c_handle the handle of the I2C bus from HAL function, e.g. hi2c1 + * @return si5351_handle Pointer to the si5351 handle, NULL if error, see si5351_errno + */ +si5351_HandleTypeDef *si5351_initialize(void * i2c_handle) { + + return si5351_init(i2c_handle, SI5351_XTAL_DEFAULT, SI5351_I2C_ADDRESS_DEFAULT, 0); +} + /** @brief Initialize the device Si5351 with the main parameters * @param i2c_handle the handle of the I2C bus from HAL function, e.g. hi2c1 * @param xtal_frequency either the XTAL frequency (25/27 MHz) or CLock-In * from 10 MHz to 100 MHz entered in Hz * @param i2c_address I2C bus address of the device from datasheet typically 0x60 (or 0x61) + * @param datasize reserve an extra area of data space in bytes, access with function si5351_read_data() and si5351_write_data() * @return si5351_handle Pointer to the si5351 handle, NULL if error, see si5351_errno */ -si5351_HandleTypeDef *si5351_init(void * i2c_handle, uint32_t xtal_frequency, uint8_t i2c_address) { +si5351_HandleTypeDef *si5351_init(void * i2c_handle, uint32_t xtal_frequency, uint8_t i2c_address, size_t datasize) { si5351_HandleTypeDef *si5351_handle, *handle; - // xtal frequency from 25000000 upto 27000000, clkin frequ range from 10000000 to 100000000 Hz - // i2c_address range up to 0x7F + /* xtal frequency from 25000000 upto 27000000, clkin frequ range from 10000000 to 100000000 Hz */ + /* i2c_address range up to 0x7F */ if (!i2c_handle || xtal_frequency < 10000000 || xtal_frequency > 100000000 || i2c_address > 0x7f) { si5351_errno = EINVAL; return NULL; } - si5351_handle = calloc(1, sizeof(*si5351_handle)); if (si5351_handle == NULL) { si5351_errno = ENOMEM; // cannot allocate any memory return NULL; } + /* shift the given address to HAL conformity (shift one bit left) */ + i2c_address <<= 1; + /* check if there is already a handle with same i2c_handle and i2c_address */ if (first_handle == NULL) { first_handle = si5351_handle; @@ -119,9 +250,9 @@ si5351_HandleTypeDef *si5351_init(void * i2c_handle, uint32_t xtal_frequency, ui handle = first_handle; while (handle) { if ((handle->i2c_address == i2c_address) && (handle->i2c_handle == i2c_handle)) { - // the device is already set up, we have to free the memory, exit with NULL! + /* the device is already set up, we have to free the memory, exit with NULL */ free(si5351_handle); - si5351_errno = EADDRINUSE; // handle address already in use + si5351_errno = EADDRINUSE; /* handle address already in use */ return NULL; } if (handle->next == NULL) { @@ -137,6 +268,14 @@ si5351_HandleTypeDef *si5351_init(void * i2c_handle, uint32_t xtal_frequency, ui /* 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; + /* now allocate some memory for the data area given */ + if (datasize > 0) { + si5351_handle->data = calloc(1, datasize); + if (si5351_handle->data == NULL) { + si5351_errno = ENOMEM; /* cannot allocate memory for data */ + /* we just leave it to NULL, do nothing more with this behavior */ + } + } si5351_handle->initialized = 1; return si5351_handle; } @@ -171,29 +310,22 @@ int si5351_deinit(si5351_HandleTypeDef * si5351_handle) { return -ENODEV; // no such device } + if (si5351_handle->data) { + free(si5351_handle->data); + } free(si5351_handle); return 0; } -/** @brief Check if there is any I2C device ready on the bus - * @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 +/** @brief Deinitialize the first Si5351 device (wrapper function), for simplification + * @return 0 on success + * @retval -ENODEV if device handle not found */ -int si5351_isready(si5351_inst_t inst) { +int si5351_deinitialize(void) { - int status; - - if(!inst) - return -EINVAL; - - /* call HAL function for device ready check */ - status = HAL_I2C_IsDeviceReady(inst->i2c_handle, inst->i2c_address << 1, 3, 100 /*HAL_MAX_DELAY*/ ); // HAL_MAX_DELAY is blocking, use 10 ms - /* @TODO: create a pointer to that function for more flexiblity using other tools as HAL */ - return status; + if (!first_handle) + return -ENODEV; + return si5351_deinit(first_handle); } @@ -209,9 +341,10 @@ int si5351_program(si5351_inst_t inst) { uint8_t data; int status = 0; +#if SI5351_DEBUG int cx = 0; - - if(!inst) +#endif + if(!inst && !(inst=first_handle)) return -EINVAL; do { @@ -228,6 +361,7 @@ int si5351_program(si5351_inst_t inst) { status = si5351_write(inst, SI5351_OUTPUT_ENABLE_CONTROL, &data, 1); if (status) break; + inst->clk_is_disabled = data; /* power down all output drivers reg 16 -- 23 */ data = SI5351_CLK0_PDN; // 0x80 @@ -243,14 +377,12 @@ int si5351_program(si5351_inst_t inst) { 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 */ -#ifdef DEBUG +#if SI5351_DEBUG status = si5351_read(inst, SI5351_FANOUT_ENABLE, &data, 1); if (status) break; @@ -261,38 +393,361 @@ int si5351_program(si5351_inst_t inst) { status = si5351_write(inst, SI5351_FANOUT_ENABLE, &data, 1); if (status) break; -#ifdef DEBUG +#if SI5351_DEBUG status = si5351_read(inst, SI5351_FANOUT_ENABLE, &data, 1); if (status) break; cx += snprintf(inst->debug_msg + cx, sizeof(inst->debug_msg) - (size_t)cx, "(%d) FANOUT_ENABLE 0x%x\n", cx, data); cx += snprintf(inst->debug_msg + cx, sizeof(inst->debug_msg) - (size_t)cx, "(%d) FANOUT_ENABLE %d\n", cx, data); #endif - /* Crystal Internal Load Capacitance */ -#ifdef DEBUG - status = si5351_read(inst, SI5351_CRYSTAL_INTERNAL_LOAD_CAPACITANCE, &data, 1); +#if SI5351_DEBUG + data = SI5351_XTAL_CL_10_PF | SI5351_XTAL_RESERVED; + status = si5351_write(inst, SI5351_CRYSTAL_INTERNAL_LOAD_CAPACITANCE, &data, 1); if (status) break; cx += snprintf(inst->debug_msg + cx, sizeof(inst->debug_msg) - (size_t)cx, "(%d) XTAL int. Load Cap: 0x%x (%dd)\n", cx, data, data); #endif - + inst->programmed = 1; /* the device is programmed */ } while(0); - - return status; } +/** @brief Select the right band to calculate even divisors for the output + * @param frequency + * @param band pointer of band_t return parameters as a structure min, max, divisor for each band + * @return 1 on success, when a frequency band is found + * @retval 0 when frequency not found + */ +int band_select(uint32_t frequency, band_t *band) { + + static const band_t sband[] = { { "80", 3000000, 4500000, 200, 0}, + { "40", 5625000, 7500000, 120, 0}, + { "30", 7500000,11250000, 80, 0}, + { "20",11250000,15000000, 60, 0}, + { "15",15000000,22500000, 40, 0}, + { "10",22500000,32142000, 28, 0}, + { "8",32142000,45000000, 20, 0}, + { "6",45000000,64285000, 14, 0}, + { "4",64285000,76000000, 10, 0}, + { "3",76000000,11250000, 8, 0}, + { "2",11250000,15000000, 6, 0}, + {"180", 1500000, 2250000, 400, 0}, + {"120", 2250000, 3000000, 300, 0}, + { "60", 4500000, 5625000, 160, 0}, + }; + + for (uint32_t i = 0; i < (sizeof(sband) / sizeof(sband[0])); i++) { + if (frequency > sband[i].qrg_min && frequency <= sband[i].qrg_max) { + memcpy(band, &sband[i], sizeof(*band)); + return 1; + } + } + return 0; +} + +/** @brief Calculate all parameters for the synthesis of the si5351 + * @param frequency selected + * @param xtal the crystal driving the Si5351 + * @param synth pointer to a structure snythesis_t will be set with the calculated values + * @return 0 on success + */ +int calculation(uint32_t frequency, uint32_t xtal, synthesis_t *synth) { + + uint32_t t; + band_t band; + + if (frequency < SI5351_FREQUENCY_MIN || frequency > SI5351_FREQUENCY_MAX) + return -EINVAL; + + /* e.g. 80-m-Band 3.5 -- 4.0 MHz */ + if (band_select(frequency, &band)) { + synth->out_r_divider = band.divider_bit; + synth->out_multiplier = band.multiplier; + synth->out_numerator = 0; + synth->out_denominator = 1; + synth->pll_multiplier = (band.multiplier * frequency) / xtal; + // t = (xtal >> 20) + 1; + t = xtal / 1000000; // even divider and 1 Hz grid + synth->pll_numerator = (band.multiplier * frequency) % xtal; + synth->pll_numerator /= t; + synth->pll_denominator = xtal / t; + return 0; + } + synth->out_r_divider = 0; + if (frequency < 81000000) { + // Valid for frequ in 0.5..112.5 MHz range 9000 + // However an error is > 6 Hz above 81 MHz + // synth->pll_multiplier = 36; // PLL runs @ 900 MHz with XTAL 25 MHz, more flexible using the formular: + // making an even integer multiplier with + synth->pll_multiplier = (900000000 / xtal); + synth->pll_multiplier &= ~0x01u; // make it even + synth->pll_numerator = 0; + synth->pll_denominator = 1; + uint32_t Fpll = synth->pll_multiplier * xtal; // this was set to 900000000 + synth->out_multiplier = Fpll / frequency; + t = (frequency >> 20) + 1; + synth->out_numerator = (Fpll % frequency) / t; + synth->out_denominator = frequency / t; + } else { + // Valid for Fclk in 75..160 MHz range + if(frequency >= 150000000) { + synth->out_multiplier = 4; + } else if (frequency >= 100000000) { + synth->out_multiplier = 6; + } else { + synth->out_multiplier = 8; + } + synth->out_numerator = 0; + synth->out_denominator = 1; + + uint32_t numerator = synth->out_multiplier*frequency; + synth->pll_multiplier = numerator / xtal; + t = (xtal >> 20) + 1; + synth->pll_numerator = (numerator % xtal) / t; + synth->pll_denominator = xtal / t; + } + return 0; +} + +/** @brief Enables the CLK output of the si5351 (after programming and setting the synthesis) + * @param si5351_instance Given si5351 device handle + * @param clk The CLK ouput to drive and enable 0...CLK0, 1...CLK1, 2...CLK2, ... + * @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_enable_output(si5351_inst_t inst, uint8_t clk) { + + int rv = 0; + + if((!inst && !(inst=first_handle)) || clk > 7) + return -EINVAL; + + // check if this clock is already enabled + if (inst->clk_is_disabled & (1 << clk)) { + inst->clk_is_disabled &= (uint8_t)~(1 << clk); // clear the bit + rv = si5351_write(inst, SI5351_OUTPUT_ENABLE_CONTROL, &inst->clk_is_disabled, 1); + } + return rv; +} + +/** @brief Disables the CLK output of the si5351 (after programming and setting the synthesis) + * @param si5351_instance Given si5351 device handle + * @param clk The CLK ouput to drive and disable 0...CLK0, 1...CLK1, 2...CLK2, ... + * @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_disable_output(si5351_inst_t inst, uint8_t clk) { + + int rv = 0; + + if((!inst && !(inst=first_handle)) || clk > 7) + return -EINVAL; + + if (!(inst->clk_is_disabled & (1 << clk))) { + inst->clk_is_disabled |= (uint8_t)(1 << clk); // set the bit + rv = si5351_write(inst, SI5351_OUTPUT_ENABLE_CONTROL, &inst->clk_is_disabled, 1); + } + return rv; +} + +/** @brief Sets the CLK_0 output of the si5351 (simplified API) + * @param si5351_instance Given si5351 device handle + * @param frequency + * @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_set_clk0(si5351_inst_t inst, uint32_t frequency) { + + int rv = 0; + synthesis_t synth; + + if(!inst && !(inst=first_handle)) + return -EINVAL; + + do { + if(!inst->programmed) { + rv = si5351_program(inst); + if (!rv) + break; + } + (void)calculation(frequency, inst->xtal_frequency, &synth); + rv = si5351_set_synthesis(inst, &synth, 0); + } while(0); + return rv; +} + +/** @brief Sets the CLK_x output of the si5351 + * @param si5351_instance Given si5351 device handle + * @param frequency + * @param clk The CLK ouput to drive and disable 0...CLK0, 1...CLK1, 2...CLK2, ... + * @param pll the used PLL, either PLLA or PLLB + * @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_set_clk(si5351_inst_t inst, uint32_t frequency, uint8_t clk, si5351_pll_t pll) { + + int rv = 0; + synthesis_t synth; + + if((!inst && !(inst=first_handle)) || clk > 7) + return -EINVAL; + + if (!pll) + inst->clk_is_pllb &= ~(1 << clk); /* delete the bit */ + else + inst->clk_is_pllb |= (1 << clk); /* set the bit */ + + do { + if(!inst->programmed) { + rv = si5351_program(inst); + if (!rv) + break; + } + (void)calculation(frequency, inst->xtal_frequency, &synth); + rv = si5351_set_synthesis(inst, &synth, clk); + } while(0); + return rv; +} + + + +int si5351_set_synthesis(si5351_inst_t inst, synthesis_t *synth, uint8_t clk) { + + uint32_t MSNx_P1, MSNx_P2, MSNx_P3; + uint32_t MSx_P1, MSx_P2, MSx_P3; + int rv = 0; + uint8_t ms_data[8]; + uint8_t regaddr; + uint8_t divby4 = 0; + uint8_t MSx_INT = 0; + uint8_t MSx_SRC = 0; + + if(!inst && !(inst=first_handle)) + return -EINVAL; + + assert(clk < 8); + assert(synth->out_r_divider < 8); /* the divider is stored in 3 bits and the value is 2^out_r_divider */ + assert(synth->pll_multiplier >= 4u && synth->pll_multiplier <= 2048u && synth->pll_multiplier != 5u && synth->pll_multiplier != 7u); + assert(synth->pll_denominator != 0u && synth->pll_denominator < (1u << 20)); // MSNx_P3 maximum of 1048575 + assert(synth->out_multiplier >= 4u && synth->out_multiplier <= 2048u && synth->out_multiplier != 5u && synth->out_multiplier != 7u); + assert(synth->out_denominator != 0u && synth->out_denominator < (1u << 20)); + + /* PLL registers */ + MSNx_P1 = 128 * synth->pll_multiplier + 128 * synth->pll_numerator / synth->pll_denominator - 512; + // MSNx_P2 = 128 * synth->pll_numerator - synth->pll_denominator * (128 * synth->pll_numerator / synth->pll_denominator); + MSNx_P2 = (128 * synth->pll_numerator) % synth->pll_denominator; + MSNx_P3 = synth->pll_denominator; + + assert(MSNx_P1 < (1u << 18)); + assert(MSNx_P2 < (1u << 20)); + + /* OUTPUT (M) registers */ + MSx_P1 = 128 * synth->out_multiplier + 128 * synth->out_numerator / synth->out_denominator - 512; + // MSx_P2 = 128 * synth->out_numerator - synth->out_denominator * (128 * synth->out_numerator / synth->out_denominator); + MSx_P2 = (128 * synth->out_numerator) % synth->out_denominator; + MSx_P3 = synth->out_denominator; + if (synth->out_r_divider == 2) /* 2^2 = 4, see 4.1.3 in AN619 special case */ + divby4 = 0x03; + + assert(MSx_P1 < (1u << 18)); + assert(MSx_P2 < (1u << 20)); + + /* distribute these registers to 8 bytes of the SI5351 */ + /* start with MSNx values */ + ms_data[0] = (uint8_t) (MSNx_P3 >> 8); + ms_data[1] = (uint8_t) MSNx_P3; + ms_data[2] = (uint8_t) ((MSNx_P1 >> 16) & 0x03); + ms_data[3] = (uint8_t) (MSNx_P1 >> 8); + ms_data[4] = (uint8_t) MSNx_P1; + ms_data[5] = (uint8_t) ((((MSNx_P3 >> 16) & 0x0F) << 4) | ((MSNx_P2 >> 16) & 0x0F)); + ms_data[6] = (uint8_t) (MSNx_P2 >> 8); + ms_data[7] = (uint8_t) MSNx_P2; + /* write MSNx registers dependent of SI5351_PLLA or SI5351_PLLB */ + regaddr = (inst->clk_is_pllb & (1u << clk)) ? SI5351_MULTISYNTH_NB_PARAMETER_3_HI : SI5351_MULTISYNTH_NA_PARAMETER_3_HI; + rv = si5351_write(inst, regaddr, ms_data, sizeof(ms_data) / sizeof(ms_data[0])); + if (rv != 0) + return rv; + /* write MSx registers dependent of CLK # */ + ms_data[0] = (uint8_t) (MSx_P3 >> 8); + ms_data[1] = (uint8_t) MSx_P3; + ms_data[2] = (uint8_t) (((MSx_P1 >> 16) & 0x03) | ((synth->out_r_divider & 0x07) << 4) | (divby4 << 2)); + ms_data[3] = (uint8_t) (MSx_P1 >> 8); + ms_data[4] = (uint8_t) MSx_P1; + ms_data[5] = (uint8_t) ((((MSx_P3 >> 16) & 0x0F) << 4) | ((MSx_P2 >> 16) & 0x0F)); + ms_data[6] = (uint8_t) (MSx_P2 >> 8); + ms_data[7] = (uint8_t) MSx_P2; + regaddr = SI5351_MULTISYNTH0_PARAMETER_3_HI + (uint8_t)(clk * sizeof(ms_data) / sizeof(ms_data[0])); + rv = si5351_write(inst, regaddr, ms_data, sizeof(ms_data) / sizeof(ms_data[0])); + if (rv != 0) + return rv; + + if ((synth->out_numerator == 0) && ((synth->out_multiplier & 0x01) == 0)) + MSx_INT = 1; + + MSx_SRC = !!(inst->clk_is_pllb & (1 << clk)); + + ms_data[0] = (uint8_t)(MSx_INT << 6 | MSx_SRC << 5 | SI5351_CLK_SRC_MS0 | SI5351_CLK_8_MA); //SI5351_CLK_6_MA; //SI5351_CLK_4_MA; + regaddr = SI5351_CLK0_CONTROL + clk; + rv = si5351_write(inst, regaddr, ms_data, 1); + if (rv!=0) + return rv; + + ms_data[0] = SI5351_PLL_RESET_VALUE; + rv = si5351_write(inst, SI5351_PLL_RESET, ms_data, 1); + if (rv != 0) + return rv; + +#if AUTOMATICALLY_ENABLE_OUTPUT + rv = si5351_enable_output(inst, clk); +#endif + + return rv; +} + char * si5351_read_debug_msg(si5351_inst_t inst) { - if (!inst) + if (!inst && !(inst=first_handle)) return NULL; return inst->debug_msg; } +int si5351_write_data(si5351_inst_t inst, void * data) { + + if (!inst && !(inst=first_handle)) + return -EINVAL; + + memcpy(inst->data, data, inst->datasize); + return (int)inst->datasize; +} + + + +int si5351_read_data(si5351_inst_t inst, void * data) { + + if(!inst && !(inst=first_handle)) + return -EINVAL; + + memcpy(data, inst->data, inst->datasize); + return (int)inst->datasize; +} + + /*! * @brief Output the value in binary representation and in groups of * bytes @@ -324,8 +779,6 @@ int __snprintb(char *buf, size_t n, void *value, size_t size) return cx; } - - char * si5351_read_register_debug(si5351_inst_t inst, char *buf, size_t bufsize, uint8_t regaddr) { uint8_t data; @@ -345,881 +798,3 @@ char * si5351_read_register_debug(si5351_inst_t inst, char *buf, size_t bufsize, return buf; } -#if 0 - -int Si5351_WriteRegister(Si5351_ConfigTypeDef *Si5351_ConfigStruct, uint8_t reg_address, uint8_t reg_data) -{ - uint32_t error_wait; - - error_wait = I2C_TIMEOUT; - while (I2C_GetFlagStatus(Si5351_ConfigStruct->I2Cx, I2C_FLAG_BUSY) == SET) - { - error_wait--; - if (error_wait==0) - { - I2C_SoftwareResetCmd(Si5351_ConfigStruct->I2Cx, ENABLE); - I2C_SoftwareResetCmd(Si5351_ConfigStruct->I2Cx, DISABLE); - return 1; - } - } - //wait for I2C to get ready, if not ready in time, reset I2C and return - - I2C_GenerateSTART(Si5351_ConfigStruct->I2Cx, ENABLE); - //send START condition - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_MODE_SELECT) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for START to be sent, if not sent in time, return - - I2C_Send7bitAddress(Si5351_ConfigStruct->I2Cx, Si5351_ConfigStruct->HW_I2C_Address, I2C_Direction_Transmitter); - //send address+RW bit - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for address to be sent, if not sent in time, return - - I2C_SendData(Si5351_ConfigStruct->I2Cx, reg_address); - //send reg address - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for reg address to be sent - - I2C_SendData(Si5351_ConfigStruct->I2Cx, reg_data); - //send reg data - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for data to be sent, if not sent in time, return - - I2C_GenerateSTOP(Si5351_ConfigStruct->I2Cx, ENABLE); - //generate STOP condition - - error_wait = I2C_TIMEOUT; - while (I2C_GetFlagStatus(Si5351_ConfigStruct->I2Cx, I2C_FLAG_STOPF)) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait until STOP is cleared - - return 0; -} - -uint8_t Si5351_ReadRegister(Si5351_ConfigTypeDef *Si5351_ConfigStruct, uint8_t reg_address) -{ - uint32_t error_wait; - - error_wait = I2C_TIMEOUT; - while (I2C_GetFlagStatus(Si5351_ConfigStruct->I2Cx, I2C_FLAG_BUSY) == SET) - { - error_wait--; - if (error_wait==0) - { - I2C_SoftwareResetCmd(Si5351_ConfigStruct->I2Cx, ENABLE); - I2C_SoftwareResetCmd(Si5351_ConfigStruct->I2Cx, DISABLE); - return 1; - } - } - //wait for I2C to get ready, if not ready in time, reset I2C and return - - I2C_GenerateSTART(Si5351_ConfigStruct->I2Cx, ENABLE); - //send START condition - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_MODE_SELECT) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for START to be sent, if not sent in time, return - - I2C_Send7bitAddress(Si5351_ConfigStruct->I2Cx, Si5351_ConfigStruct->HW_I2C_Address, I2C_Direction_Transmitter); - //send address+RW bit - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for address to be sent, if not sent in time, return - - I2C_SendData(Si5351_ConfigStruct->I2Cx, reg_address); - //send reg address - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for reg address to be sent - - I2C_GenerateSTOP(Si5351_ConfigStruct->I2Cx, ENABLE); - //generate STOP condition - - error_wait = I2C_TIMEOUT; - while (I2C_GetFlagStatus(Si5351_ConfigStruct->I2Cx, I2C_FLAG_STOPF)) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait until STOP is cleared - - - error_wait = I2C_TIMEOUT; - while (I2C_GetFlagStatus(Si5351_ConfigStruct->I2Cx, I2C_FLAG_BUSY) == SET) - { - error_wait--; - if (error_wait==0) - { - I2C_SoftwareResetCmd(Si5351_ConfigStruct->I2Cx, ENABLE); - I2C_SoftwareResetCmd(Si5351_ConfigStruct->I2Cx, DISABLE); - return 1; - } - } - //wait for I2C to get ready, if not ready in time, reset I2C and return - - I2C_GenerateSTART(Si5351_ConfigStruct->I2Cx, ENABLE); - //send START condition - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_MODE_SELECT) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for START to be sent, if not sent in time, return - - I2C_Send7bitAddress(Si5351_ConfigStruct->I2Cx, Si5351_ConfigStruct->HW_I2C_Address, I2C_Direction_Receiver); - //send address+RW bit - - error_wait = I2C_TIMEOUT; - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for address to be sent, if not sent in time, return - - while (I2C_CheckEvent(Si5351_ConfigStruct->I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait for data - - uint8_t reg_data; - reg_data = I2C_ReceiveData(Si5351_ConfigStruct->I2Cx); - //receive reg data - - I2C_GenerateSTOP(Si5351_ConfigStruct->I2Cx, ENABLE); - //generate STOP condition - - error_wait = I2C_TIMEOUT; - while (I2C_GetFlagStatus(Si5351_ConfigStruct->I2Cx, I2C_FLAG_STOPF)) - { - error_wait--; - if (error_wait==0) return 1; - } - //wait until STOP is cleared - - return reg_data; -} - -/* - * To make this library useable on any other device than - * STM32Fxxx Cortex Mx, please edit these parts of the library: - * - * DEFINES: - * SI5351_I2C_PERIPHERAL - the I2C peripheral name according - * to your devices HAL library - * I2C_TIMEOUT - time for the communication to time out - * - * TYPEDEFS: - * Si5351_ConfigTypeDef - the I2Cx parameter should be changed - * so that its type corresponds to your HAL library - * - * FUNCTIONS: - * Si5351_WriteRegister - * Si5351_ReadRegister - * You need to write your own I2C handlers here - * - */ - -//set safe values in the config structure -void Si5351_StructInit(Si5351_ConfigTypeDef *Si5351_ConfigStruct) -{ - uint8_t i; - - Si5351_ConfigStruct->HW_I2C_Address = SI5351_I2C_ADDRESS; - Si5351_ConfigStruct->I2Cx = SI5351_I2C_PERIPHERAL; - - Si5351_ConfigStruct->f_CLKIN = SI5351_CLKIN_FREQ; - Si5351_ConfigStruct->f_XTAL = SI5351_XTAL_FREQ; - - Si5351_ConfigStruct->Interrupt_Mask_CLKIN = ON; - Si5351_ConfigStruct->Interrupt_Mask_PLLA = ON; - Si5351_ConfigStruct->Interrupt_Mask_PLLB = ON; - Si5351_ConfigStruct->Interrupt_Mask_SysInit = ON; - Si5351_ConfigStruct->Interrupt_Mask_XTAL = ON; - - Si5351_ConfigStruct->Fanout_CLKIN_EN = ON; - Si5351_ConfigStruct->Fanout_MS_EN = ON; - Si5351_ConfigStruct->Fanout_XO_EN = ON; - - Si5351_ConfigStruct->OSC.CLKIN_Div = CLKINDiv_Div1; - Si5351_ConfigStruct->OSC.OSC_XTAL_Load = XTAL_Load_10_pF; - Si5351_ConfigStruct->OSC.VCXO_Pull_Range_ppm = 0; //maybe should be set to 30 ppm, not clear from the AN-619 - - for (i=0; i<=1; i++) - { - Si5351_ConfigStruct->PLL[i].PLL_Clock_Source = PLL_Clock_Source_XTAL; - Si5351_ConfigStruct->PLL[i].PLL_Multiplier_Integer = 32; //range 24..36 for 25 MHz clock - Si5351_ConfigStruct->PLL[i].PLL_Multiplier_Numerator = 0; //range 0..1048575 - Si5351_ConfigStruct->PLL[i].PLL_Multiplier_Denominator = 1; //range 1..1048575 - Si5351_ConfigStruct->PLL[i].PLL_Capacitive_Load = PLL_Capacitive_Load_0; //select 0, unless you want to tune the PLL to <200 MHZ - } - - Si5351_ConfigStruct->SS.SS_Amplitude_ppm = 0; //1.5% modulation = 15000 - Si5351_ConfigStruct->SS.SS_Enable = OFF; - Si5351_ConfigStruct->SS.SS_Mode = SS_Mode_CenterSpread; - Si5351_ConfigStruct->SS.SS_NCLK = SS_NCLK_0; //default value, this parameter is unexplained in documentation - - for (i=0; i<=7; i++) - { - Si5351_ConfigStruct->MS[i].MS_Clock_Source = MS_Clock_Source_PLLA; - Si5351_ConfigStruct->MS[i].MS_Divider_Integer = 4; - Si5351_ConfigStruct->MS[i].MS_Divider_Numerator = 0; - Si5351_ConfigStruct->MS[i].MS_Divider_Denominator = 1; - - Si5351_ConfigStruct->CLK[i].CLK_Clock_Source = CLK_Clock_Source_MS_Own; - Si5351_ConfigStruct->CLK[i].CLK_Disable_State = CLK_Disable_State_HIGH_Z; - Si5351_ConfigStruct->CLK[i].CLK_Enable = OFF; - Si5351_ConfigStruct->CLK[i].CLK_I_Drv = CLK_I_Drv_8mA; - Si5351_ConfigStruct->CLK[i].CLK_Invert = OFF; - Si5351_ConfigStruct->CLK[i].CLK_PowerDown = OFF; - Si5351_ConfigStruct->CLK[i].CLK_QuarterPeriod_Offset = 0; - Si5351_ConfigStruct->CLK[i].CLK_R_Div = CLK_R_Div1; - Si5351_ConfigStruct->CLK[i].CLK_Use_OEB_Pin = OFF; - } -} - -void Si5351_OSCConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct) -{ - uint8_t tmp; - uint32_t VCXO_Param; - - //set XTAL capacitive load and PLL VCO load capacitance - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_XTAL_CL); - tmp &= ~(XTAL_CL_MASK | PLL_CL_MASK); - tmp |= (XTAL_CL_MASK & (Si5351_ConfigStruct->OSC.OSC_XTAL_Load)) | (PLL_CL_MASK & ((Si5351_ConfigStruct->PLL[0].PLL_Capacitive_Load) << 1)) | (PLL_CL_MASK & ((Si5351_ConfigStruct->PLL[1].PLL_Capacitive_Load) << 4)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_XTAL_CL, tmp); - - //set CLKIN pre-divider - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLKIN_DIV); - tmp &= ~CLKIN_MASK; - tmp |= CLKIN_MASK & Si5351_ConfigStruct->OSC.CLKIN_Div; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLKIN_DIV, tmp); - - //set fanout of XO, MS0, MS4 and CLKIN - should be always on unless you - //need to reduce power consumption - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_FANOUT_EN); - tmp &= ~(FANOUT_CLKIN_EN_MASK | FANOUT_MS_EN_MASK | FANOUT_XO_EN_MASK); - if (Si5351_ConfigStruct->Fanout_CLKIN_EN == ON) tmp |= FANOUT_CLKIN_EN_MASK; - if (Si5351_ConfigStruct->Fanout_MS_EN == ON) tmp |= FANOUT_MS_EN_MASK; - if (Si5351_ConfigStruct->Fanout_XO_EN == ON) tmp |= FANOUT_XO_EN_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_FANOUT_EN, tmp); - - //if "b" in PLLB set to 10^6, set VCXO parameter - if (Si5351_ConfigStruct->PLL[1].PLL_Multiplier_Denominator == 1000000) - { - VCXO_Param = VCXO_PARAM_MASK & (uint32_t) - ((103 * Si5351_ConfigStruct->OSC.VCXO_Pull_Range_ppm - * ((uint64_t)128000000 * Si5351_ConfigStruct->PLL[1].PLL_Multiplier_Integer + - Si5351_ConfigStruct->PLL[1].PLL_Multiplier_Numerator))/100000000); - } else { - VCXO_Param = 0; - } - - tmp = (uint8_t) VCXO_Param; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_VCXO_PARAM_0_7, tmp); - tmp = (uint8_t)(VCXO_Param>>8); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_VCXO_PARAM_8_15, tmp); - tmp = (uint8_t)((VCXO_Param>>16) & VCXO_PARAM_16_21_MASK); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_VCXO_PARAM_16_21, tmp); -} - -EnableState Si5351_CheckStatusBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit) -{ - uint8_t tmp; - - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_DEV_STATUS); - tmp &= StatusBit; - return tmp; -} - -EnableState Si5351_CheckStickyBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit) -{ - uint8_t tmp; - - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_DEV_STICKY); - tmp &= StatusBit; - return tmp; -} - -void Si5351_InterruptConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct) -{ - uint8_t tmp; - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_INT_MASK); - - tmp &= ~INT_MASK_LOS_XTAL_MASK; - if (Si5351_ConfigStruct->Interrupt_Mask_XTAL == ON) - { - tmp |= INT_MASK_LOS_XTAL_MASK; - } - - tmp &= ~INT_MASK_LOS_CLKIN_MASK; - if (Si5351_ConfigStruct->Interrupt_Mask_CLKIN == ON) - { - tmp |= INT_MASK_LOS_CLKIN_MASK; - } - - tmp &= ~INT_MASK_LOL_A_MASK; - if (Si5351_ConfigStruct->Interrupt_Mask_PLLA == ON) - { - tmp |= INT_MASK_LOL_A_MASK; - } - - tmp &= ~INT_MASK_LOL_B_MASK; - if (Si5351_ConfigStruct->Interrupt_Mask_PLLB == ON) - { - tmp |= INT_MASK_LOL_B_MASK; - } - - tmp &= ~INT_MASK_SYS_INIT_MASK; - if (Si5351_ConfigStruct->Interrupt_Mask_SysInit == ON) - { - tmp |= INT_MASK_SYS_INIT_MASK; - } - - Si5351_WriteRegister(Si5351_ConfigStruct, REG_INT_MASK, tmp); -} - -void Si5351_ClearStickyBit(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_StatusBitTypeDef StatusBit) -{ - uint8_t tmp; - - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_DEV_STICKY); - tmp &= ~StatusBit; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_DEV_STICKY, tmp); -} - -void Si5351_PLLConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_PLLChannelTypeDef PLL_Channel) -{ - uint8_t tmp, tmp_mask; - uint32_t MSN_P1, MSN_P2, MSN_P3; - - //set PLL clock source - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_PLL_CLOCK_SOURCE); - tmp_mask = PLLA_CLOCK_SOURCE_MASK << PLL_Channel; - tmp &= ~tmp_mask; - tmp |= tmp_mask & Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Clock_Source; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_PLL_CLOCK_SOURCE, tmp); - - //if new multiplier not even integer, disable the integer mode - if ((Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Numerator != 0) | ((Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Integer & 0x01) != 0 )) - { - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_FB_INT + PLL_Channel); - tmp &= ~FB_INT_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_FB_INT + PLL_Channel, tmp); - } - - //configure the PLL multiplier - MSN_P1 = 128 * Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Integer + ((128 * Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Numerator) / Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Denominator) - 512; - MSN_P2 = 128 * Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Numerator - Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Denominator * ((128 * Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Numerator) / Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Denominator); - MSN_P3 = Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Denominator; - - tmp = (uint8_t) MSN_P1; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P1_0_7 + 8 * PLL_Channel, tmp); - tmp = (uint8_t) (MSN_P1 >> 8); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P1_8_15 + 8 * PLL_Channel, tmp); - tmp = (uint8_t) (MSN_P1_16_17_MASK & (MSN_P1 >> 16)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P1_16_17 + 8 * PLL_Channel, tmp); - - tmp = (uint8_t) MSN_P2; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P2_0_7 + 8 * PLL_Channel, tmp); - tmp = (uint8_t) (MSN_P2 >> 8); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P2_8_15 + 8 * PLL_Channel, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MSN_P2_16_19); - tmp &= ~MSN_P2_16_19_MASK; - tmp |= (uint8_t) (MSN_P2_16_19_MASK & (MSN_P2 >> 16)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P2_16_19 + 8 * PLL_Channel, tmp); - - tmp = (uint8_t) MSN_P3; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P3_0_7 + 8 * PLL_Channel, tmp); - tmp = (uint8_t) (MSN_P3 >> 8); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P3_8_15 + 8 * PLL_Channel, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MSN_P3_16_19); - tmp &= ~MSN_P3_16_19_MASK; - tmp |= (uint8_t) (MSN_P3_16_19_MASK & ((MSN_P3 >> 16) << 4)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MSN_P3_16_19 + 8 * PLL_Channel, tmp); - - //if new multiplier is an even integer, enable integer mode - if ((Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Numerator == 0) & ((Si5351_ConfigStruct->PLL[PLL_Channel].PLL_Multiplier_Integer & 0x01) == 0 )) - { - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_FB_INT + PLL_Channel); - tmp |= FB_INT_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_FB_INT + PLL_Channel, tmp); - } -} - -void Si5351_PLLReset(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_PLLChannelTypeDef PLL_Channel) -{ - uint8_t tmp; - - //reset PLL - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_PLL_RESET); - if (PLL_Channel == PLL_A) - { - tmp |= PLLA_RESET_MASK; - } else { - tmp |= PLLB_RESET_MASK; - } - Si5351_WriteRegister(Si5351_ConfigStruct, REG_PLL_RESET, tmp); -} - -void Si5351_PLLSimultaneousReset(Si5351_ConfigTypeDef *Si5351_ConfigStruct) -{ - uint8_t tmp; - - //reset PLL - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_PLL_RESET); - tmp |= PLLA_RESET_MASK | PLLB_RESET_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_PLL_RESET, tmp); -} - -void Si5351_SSConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct) -{ - uint8_t tmp; - uint32_t SSUDP, SSUP_P1, SSUP_P2, SSUP_P3, SSDN_P1, SSDN_P2, SSDN_P3; - uint64_t SSDN, SSUP; - - //turn off SS if it should be disabled - if ((Si5351_ConfigStruct->SS.SS_Enable == OFF)| - (((Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Integer & 0x01) == 0) - & (Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Numerator == 0)) ) - { - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSC_EN); - tmp &= ~SSC_EN_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSC_EN, tmp); - } - - //set default value of SS_NCLK - spread spectrum reserved register - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SS_NCLK); - tmp &= ~SS_NCLK_MASK; - tmp |= SS_NCLK_MASK & (Si5351_ConfigStruct->SS.SS_NCLK); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SS_NCLK, tmp); - - //set SS mode - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSC_MODE); - tmp &= ~SSC_MODE_MASK; - tmp |= SSC_MODE_MASK & Si5351_ConfigStruct->SS.SS_Mode; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSC_MODE, tmp); - - //set SSUDP parameter - if (Si5351_ConfigStruct->PLL[0].PLL_Clock_Source == PLL_Clock_Source_CLKIN) - { - SSUDP = (Si5351_ConfigStruct->f_CLKIN)/(4*31500); - } else { - SSUDP = (Si5351_ConfigStruct->f_XTAL)/(4*31500); - } - - //set SSUDP parameter - tmp = (uint8_t) SSUDP; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSUDP_0_7, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSUDP_8_11); - tmp &= ~SSUDP_8_11_MASK; - tmp |= (uint8_t) (SSUDP_8_11_MASK & ((SSUDP >> 8) << 4)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSUDP_8_11, tmp); - - //calculate SSUP and SSDN parameters - if (Si5351_ConfigStruct->SS.SS_Mode == SS_Mode_CenterSpread) - { - SSUP = ((uint64_t)(64000000*Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Integer - + (64000000*Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Numerator)/(Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Denominator) - ) * Si5351_ConfigStruct->SS.SS_Amplitude_ppm - ) / ((1000000 - Si5351_ConfigStruct->SS.SS_Amplitude_ppm) * SSUDP); - - SSDN = ((uint64_t)(64000000*Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Integer - + (64000000*Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Numerator)/(Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Denominator) - ) * Si5351_ConfigStruct->SS.SS_Amplitude_ppm - ) / ((1000000 + Si5351_ConfigStruct->SS.SS_Amplitude_ppm) * SSUDP); - - SSUP_P1 = (uint32_t) (SSUP/1000000); - SSUP_P2 = (uint32_t)(32767*(SSUP/1000000-SSUP_P1)); - SSUP_P3 = 0x7FFF; - - } else { - - SSDN = ((uint64_t)(64000000*Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Integer - + (64000000*Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Numerator)/(Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Denominator) - ) * Si5351_ConfigStruct->SS.SS_Amplitude_ppm - ) / ((1000000 + Si5351_ConfigStruct->SS.SS_Amplitude_ppm) * SSUDP); - - SSUP_P1 = 0; - SSUP_P2 = 0; - SSUP_P3 = 1; - - } - - //set SSDN parameter - SSDN_P1 = (uint32_t) (SSDN/1000000); - SSDN_P2 = (uint32_t)(32767*(SSDN/1000000-SSDN_P1)); - SSDN_P3 = 0x7FFF; - - //write SSUP parameter P1 - tmp = (uint8_t) SSUP_P1; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSUP_P1_0_7, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSUP_P1_8_11); - tmp &= ~SSUP_P1_8_11_MASK; - tmp |= (uint8_t)(SSUP_P1_8_11_MASK & (SSUP_P1 >> 8)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSUP_P1_8_11, tmp); - - //write SSUP parameter P2 - tmp = (uint8_t) SSUP_P2; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSUP_P2_0_7, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSUP_P2_8_14); - tmp &= ~SSUP_P2_8_14_MASK; - tmp |= (uint8_t)(SSUP_P2_8_14_MASK & (SSUP_P2 >> 8)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSUP_P2_8_14, tmp); - - //write SSUP parameter P3 - tmp = (uint8_t) SSUP_P3; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSUP_P3_0_7, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSUP_P3_8_14); - tmp &= ~SSUP_P3_8_14_MASK; - tmp |= (uint8_t)(SSUP_P3_8_14_MASK & (SSUP_P3 >> 8)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSUP_P3_8_14, tmp); - - //write SSDN parameter P1 - tmp = (uint8_t) SSDN_P1; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSDN_P1_0_7, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSDN_P1_8_11); - tmp &= ~SSDN_P1_8_11_MASK; - tmp |= (uint8_t)(SSDN_P1_8_11_MASK & (SSDN_P1 >> 8)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSDN_P1_8_11, tmp); - - //write SSDN parameter P2 - tmp = (uint8_t) SSDN_P2; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSDN_P2_0_7, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSDN_P2_8_14); - tmp &= ~SSDN_P2_8_14_MASK; - tmp |= (uint8_t)(SSDN_P2_8_14_MASK & (SSDN_P2 >> 8)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSDN_P2_8_14, tmp); - - //write SSDN parameter P3 - tmp = (uint8_t) SSDN_P3; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSDN_P3_0_7, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSDN_P3_8_14); - tmp &= ~SSDN_P3_8_14_MASK; - tmp |= (uint8_t)(SSDN_P3_8_14_MASK & (SSDN_P3 >> 8)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSDN_P3_8_14, tmp); - - //turn on SS if it should be enabled - if ((Si5351_ConfigStruct->SS.SS_Enable == ON) - & (((Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Integer & 0x01) != 0) - | (Si5351_ConfigStruct->PLL[0].PLL_Multiplier_Numerator != 0))) - { - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_SSC_EN); - tmp |= SSC_EN_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_SSC_EN, tmp); - } -} - -void Si5351_MSConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_MSChannelTypeDef MS_Channel) -{ - uint8_t tmp; - uint32_t MS_P1, MS_P2, MS_P3; - - //configure MultiSynth clock source - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MS_SRC + MS_Channel); - tmp &= ~MS_SRC_MASK; - if (Si5351_ConfigStruct->MS[MS_Channel].MS_Clock_Source == MS_Clock_Source_PLLB) - { - tmp |= MS_SRC_MASK; - } - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_SRC + MS_Channel, tmp); - - if (MS_Channel <= MS5) //configuration is simpler for MS6 and 7 since they are integer-only - { - //if next value not in even integer mode or if divider is not equal to 4, disable DIVBY4 - if ((Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Integer != 4)|(Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Numerator != 0)) - { - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MS_DIVBY4 + 8 * MS_Channel); - tmp &= ~MS_DIVBY4_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_DIVBY4 + 8 * MS_Channel, tmp); - } - - //if next value not in even integer mode or SS enabled, disable integer mode - if ((Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Numerator != 0)|((Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Integer & 0x01) != 0)|(Si5351_ConfigStruct->SS.SS_Enable == ON)) - { - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MS_INT + MS_Channel); - tmp &= ~MS_INT_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_INT + MS_Channel, tmp); - } - - //set new divider value - MS_P1 = 128 * Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Integer - + ((128 * Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Numerator) / Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Denominator) - - 512; - MS_P2 = 128 * Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Numerator - - Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Denominator - * ((128 * Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Numerator) / Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Denominator); - MS_P3 = Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Denominator; - - tmp = (uint8_t) MS_P1; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P1_0_7 + 8 * MS_Channel, tmp); - tmp = (uint8_t) (MS_P1 >> 8); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P1_8_15 + 8 * MS_Channel, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MS_P1_16_17); - tmp &= ~MS_P1_16_17_MASK; - tmp |= (uint8_t) (MS_P1_16_17_MASK & (MS_P1 >> 16)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P1_16_17 + 8 * MS_Channel, tmp); - - tmp = (uint8_t) MS_P2; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P2_0_7 + 8 * MS_Channel, tmp); - tmp = (uint8_t) (MS_P2 >> 8); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P2_8_15 + 8 * MS_Channel, tmp); - Si5351_ReadRegister(Si5351_ConfigStruct, REG_MS_P2_16_19 + 8 * MS_Channel); - tmp &= ~MS_P2_16_19_MASK; - tmp |= (uint8_t) (MS_P2_16_19_MASK & (MS_P2 >> 16)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P2_16_19 + 8 * MS_Channel, tmp); - - tmp = (uint8_t) MS_P3; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P3_0_7 + 8 * MS_Channel, tmp); - tmp = (uint8_t) (MS_P3 >> 8); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P3_8_15 + 8 * MS_Channel, tmp); - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MS_P3_16_19 + 8 * MS_Channel); - tmp &= ~MS_P3_16_19_MASK; - tmp |= (uint8_t) (MS_P3_16_19_MASK & ((MS_P3 >> 16) << 4)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_P3_16_19 + 8 * MS_Channel, tmp); - - //if next value is even integer and SS not enabled, enable integer mode - if ((Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Numerator == 0) & ((Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Integer & 0x01) == 0) & (Si5351_ConfigStruct->SS.SS_Enable == OFF)) - { - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MS_INT + MS_Channel); - tmp |= MS_INT_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_INT + MS_Channel, tmp); - - //if next value in integer mode and if divider is equal to 4, enable DIVBY4 - if (Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Integer == 4) - { - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_MS_DIVBY4 + 8 * MS_Channel); - tmp |= MS_DIVBY4_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS_DIVBY4 + 8 * MS_Channel, tmp); - } - } - } else { - //configure divider of Multisynth 6 and 7 - Si5351_WriteRegister(Si5351_ConfigStruct, REG_MS67_P1 + (MS_Channel - MS6), (uint8_t)(Si5351_ConfigStruct->MS[MS_Channel].MS_Divider_Integer)); - //can be only even integers between 6 and 254, inclusive - } -} - -void Si5351_CLKPowerCmd(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_CLKChannelTypeDef CLK_Channel) -{ - uint8_t tmp, tmp_mask; - - //set CLK disable state - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_DIS_STATE + (CLK_Channel >> 2)); //increment the address by 1 if CLKx>=CLK4 - tmp_mask = CLK_DIS_STATE_MASK << ((CLK_Channel & 0x03)<<1); //shift the mask according to the selected channel - tmp &= ~tmp_mask; - tmp |= tmp_mask & ((Si5351_ConfigStruct->CLK[CLK_Channel].CLK_Disable_State) << ((CLK_Channel & 0x03)<<1)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_DIS_STATE + (CLK_Channel >> 2), tmp); - - //set OEB pin - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_OEB); - tmp_mask = 1 << CLK_Channel; - tmp &= ~tmp_mask; - if (Si5351_ConfigStruct->CLK[CLK_Channel].CLK_Use_OEB_Pin == OFF) - { - tmp |= tmp_mask; - } - - if (Si5351_ConfigStruct->CLK[CLK_Channel].CLK_Enable == OFF) //disable clock - { - //power down the clock - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_EN); - tmp |= 1 << CLK_Channel; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_EN, tmp); - } - - if (Si5351_ConfigStruct->CLK[CLK_Channel].CLK_PowerDown == ON) //power down clock - { - //power down output driver - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_PDN + CLK_Channel); - tmp |= CLK_PDN_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_PDN + CLK_Channel, tmp); - } - - if (Si5351_ConfigStruct->CLK[CLK_Channel].CLK_PowerDown == OFF) //power up clock - { - //power up output driver - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_PDN + CLK_Channel); - tmp &= ~CLK_PDN_MASK; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_PDN + CLK_Channel, tmp); - } - - if (Si5351_ConfigStruct->CLK[CLK_Channel].CLK_Enable == ON) //enable clock - { - //power up the clock - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_EN); - tmp &= ~(1 << CLK_Channel); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_EN, tmp); - } -} - -void Si5351_CLKConfig(Si5351_ConfigTypeDef *Si5351_ConfigStruct, Si5351_CLKChannelTypeDef CLK_Channel) -{ - uint8_t tmp, tmp_mask; - - //set CLK source clock - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_SRC + CLK_Channel); - tmp &= ~CLK_SRC_MASK; - tmp |= CLK_SRC_MASK & Si5351_ConfigStruct->CLK[CLK_Channel].CLK_Clock_Source; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_SRC + CLK_Channel, tmp); - - //set CLK inversion - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_INV + CLK_Channel); - tmp &= ~CLK_INV_MASK; - if (Si5351_ConfigStruct->CLK[CLK_Channel].CLK_Invert == ON) - { - tmp |= CLK_INV_MASK; - } - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_INV + CLK_Channel, tmp); - - //set CLK current drive - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_IDRV + CLK_Channel); - tmp &= ~CLK_IDRV_MASK; - tmp |= CLK_IDRV_MASK & Si5351_ConfigStruct->CLK[CLK_Channel].CLK_I_Drv; - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_IDRV + CLK_Channel, tmp); - - if (CLK_Channel <= CLK5) //CLK6 and 7 are integer only, which causes several limitations - { - //set CLK phase offset - tmp = CLK_PHOFF_MASK & (Si5351_ConfigStruct->CLK[CLK_Channel].CLK_QuarterPeriod_Offset); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_PHOFF + CLK_Channel, tmp); - //set Rx divider - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_R_DIV + CLK_Channel * CLK_R_DIV_STEP); - tmp &= ~CLK_R_DIV_MASK; - tmp |= CLK_R_DIV_MASK & (Si5351_ConfigStruct->CLK[CLK_Channel].CLK_R_Div); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_R_DIV + CLK_Channel * CLK_R_DIV_STEP, tmp); - } else { - //CLK6 and CLK7 have no fractional mode, so they lack the phase offset function - - //set Rx divider - tmp_mask = CLK_R67_DIV_MASK << ((CLK_Channel-CLK6) << 2); //shift mask left by 4 if CLK7 - tmp = Si5351_ReadRegister(Si5351_ConfigStruct, REG_CLK_R67_DIV); - tmp &= ~tmp_mask; - tmp |= tmp_mask & ((Si5351_ConfigStruct->CLK[CLK_Channel].CLK_R_Div >> 4) << ((CLK_Channel-CLK6) << 2)); - Si5351_WriteRegister(Si5351_ConfigStruct, REG_CLK_R67_DIV, tmp); - } -} - -int Si5351_Init(Si5351_ConfigTypeDef *Si5351_ConfigStruct) -{ - uint32_t timeout = SI5351_TIMEOUT; - uint8_t i; - - //wait for the 5351 to initialize - while (Si5351_CheckStatusBit(Si5351_ConfigStruct, StatusBit_SysInit)) - { - timeout--; - if (timeout==0) return 1; //return 1 if initialization timed out - } - - //configure oscillator, fanout, interrupts, VCXO - Si5351_OSCConfig(Si5351_ConfigStruct); - Si5351_InterruptConfig(Si5351_ConfigStruct); - - //configure PLLs - for (i=PLL_A; i<=PLL_B; i++) - { - Si5351_PLLConfig(Si5351_ConfigStruct, i); - Si5351_PLLReset(Si5351_ConfigStruct, i); - } - - //configure Spread Spectrum - Si5351_SSConfig(Si5351_ConfigStruct); - - //Configure Multisynths - for (i=MS0; i<=MS7; i++) - { - Si5351_MSConfig(Si5351_ConfigStruct, i); - } - - //configure outputs - for (i=CLK0; i<=CLK7; i++) - { - Si5351_CLKConfig(Si5351_ConfigStruct, i); - } - - //wait for PLLs to lock - while (Si5351_CheckStatusBit(Si5351_ConfigStruct, StatusBit_SysInit | StatusBit_PLLA | StatusBit_PLLB)) - { - timeout--; - if (timeout==0) return 1; //return 1 if problem with any PLL - } - - //clear sticky bits - Si5351_ClearStickyBit(Si5351_ConfigStruct, StatusBit_SysInit | StatusBit_PLLA | StatusBit_PLLB); - - if (Si5351_ConfigStruct->f_CLKIN != 0) //if CLKIN used, check it as well - { - while (Si5351_CheckStatusBit(Si5351_ConfigStruct, StatusBit_CLKIN)) - { - timeout--; - if (timeout==0) return 1; //return 1 if initialization timed out - } - //clear CLKIN sticky bit - Si5351_ClearStickyBit(Si5351_ConfigStruct, StatusBit_CLKIN); - } - - if (Si5351_ConfigStruct->f_XTAL != 0) //if XTAL used, check it as well - { - while (Si5351_CheckStatusBit(Si5351_ConfigStruct, StatusBit_XTAL)) - { - timeout--; - if (timeout==0) return 1; //return 1 if initialization timed out - } - //clear XTAL sticky bit - Si5351_ClearStickyBit(Si5351_ConfigStruct, StatusBit_XTAL); - } - - //power on or off the outputs - for (i=CLK0; i<=CLK7; i++) - { - Si5351_CLKPowerCmd(Si5351_ConfigStruct, i); - } - - return 0; -} -#endif diff --git a/Core/Src/stm32l4xx_hal_msp.c b/Core/Src/stm32l4xx_hal_msp.c index 3ce4332..61d3f57 100644 --- a/Core/Src/stm32l4xx_hal_msp.c +++ b/Core/Src/stm32l4xx_hal_msp.c @@ -237,6 +237,61 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) } +/** +* @brief RTC MSP Initialization +* This function configures the hardware resources used in this example +* @param hrtc: RTC handle pointer +* @retval None +*/ +void HAL_RTC_MspInit(RTC_HandleTypeDef* hrtc) +{ + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + if(hrtc->Instance==RTC) + { + /* USER CODE BEGIN RTC_MspInit 0 */ + + /* USER CODE END RTC_MspInit 0 */ + + /** Initializes the peripherals clock + */ + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC; + PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) + { + Error_Handler(); + } + + /* Peripheral clock enable */ + __HAL_RCC_RTC_ENABLE(); + /* USER CODE BEGIN RTC_MspInit 1 */ + + /* USER CODE END RTC_MspInit 1 */ + } + +} + +/** +* @brief RTC MSP De-Initialization +* This function freeze the hardware resources used in this example +* @param hrtc: RTC handle pointer +* @retval None +*/ +void HAL_RTC_MspDeInit(RTC_HandleTypeDef* hrtc) +{ + if(hrtc->Instance==RTC) + { + /* USER CODE BEGIN RTC_MspDeInit 0 */ + + /* USER CODE END RTC_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_RTC_DISABLE(); + /* USER CODE BEGIN RTC_MspDeInit 1 */ + + /* USER CODE END RTC_MspDeInit 1 */ + } + +} + /** * @brief PCD MSP Initialization * This function configures the hardware resources used in this example diff --git a/Core/Src/stm32l4xx_hal_timebase_tim.c b/Core/Src/stm32l4xx_hal_timebase_tim.c index 2836767..c3e7789 100644 --- a/Core/Src/stm32l4xx_hal_timebase_tim.c +++ b/Core/Src/stm32l4xx_hal_timebase_tim.c @@ -25,12 +25,12 @@ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ -TIM_HandleTypeDef htim16; +TIM_HandleTypeDef htim6; /* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ /** - * @brief This function configures the TIM16 as a time base source. + * @brief This function configures the TIM6 as a time base source. * The time source is configured to have 1ms time base with a dedicated * Tick interrupt priority. * @note This function is called automatically at the beginning of program after @@ -44,41 +44,41 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) uint32_t uwTimclock = 0; uint32_t uwPrescalerValue = 0; uint32_t pFLatency; - /*Configure the TIM16 IRQ priority */ - HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, TickPriority ,0); + /*Configure the TIM6 IRQ priority */ + HAL_NVIC_SetPriority(TIM6_DAC_IRQn, TickPriority ,0); - /* Enable the TIM16 global Interrupt */ - HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn); + /* Enable the TIM6 global Interrupt */ + HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn); - /* Enable TIM16 clock */ - __HAL_RCC_TIM16_CLK_ENABLE(); + /* Enable TIM6 clock */ + __HAL_RCC_TIM6_CLK_ENABLE(); /* Get clock configuration */ HAL_RCC_GetClockConfig(&clkconfig, &pFLatency); - /* Compute TIM16 clock */ - uwTimclock = HAL_RCC_GetPCLK2Freq(); - /* Compute the prescaler value to have TIM16 counter clock equal to 1MHz */ + /* Compute TIM6 clock */ + uwTimclock = 2*HAL_RCC_GetPCLK1Freq(); + /* Compute the prescaler value to have TIM6 counter clock equal to 1MHz */ uwPrescalerValue = (uint32_t) ((uwTimclock / 1000000U) - 1U); - /* Initialize TIM16 */ - htim16.Instance = TIM16; + /* Initialize TIM6 */ + htim6.Instance = TIM6; /* Initialize TIMx peripheral as follow: - + Period = [(TIM16CLK/1000) - 1]. to have a (1/1000) s time base. + + Period = [(TIM6CLK/1000) - 1]. to have a (1/1000) s time base. + Prescaler = (uwTimclock/1000000 - 1) to have a 1MHz counter clock. + ClockDivision = 0 + Counter direction = Up */ - htim16.Init.Period = (1000000U / 1000U) - 1U; - htim16.Init.Prescaler = uwPrescalerValue; - htim16.Init.ClockDivision = 0; - htim16.Init.CounterMode = TIM_COUNTERMODE_UP; + htim6.Init.Period = (1000000U / 1000U) - 1U; + htim6.Init.Prescaler = uwPrescalerValue; + htim6.Init.ClockDivision = 0; + htim6.Init.CounterMode = TIM_COUNTERMODE_UP; - if(HAL_TIM_Base_Init(&htim16) == HAL_OK) + if(HAL_TIM_Base_Init(&htim6) == HAL_OK) { /* Start the TIM time Base generation in interrupt mode */ - return HAL_TIM_Base_Start_IT(&htim16); + return HAL_TIM_Base_Start_IT(&htim6); } /* Return function status */ @@ -87,25 +87,25 @@ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) /** * @brief Suspend Tick increment. - * @note Disable the tick increment by disabling TIM16 update interrupt. + * @note Disable the tick increment by disabling TIM6 update interrupt. * @param None * @retval None */ void HAL_SuspendTick(void) { - /* Disable TIM16 update Interrupt */ - __HAL_TIM_DISABLE_IT(&htim16, TIM_IT_UPDATE); + /* Disable TIM6 update Interrupt */ + __HAL_TIM_DISABLE_IT(&htim6, TIM_IT_UPDATE); } /** * @brief Resume Tick increment. - * @note Enable the tick increment by Enabling TIM16 update interrupt. + * @note Enable the tick increment by Enabling TIM6 update interrupt. * @param None * @retval None */ void HAL_ResumeTick(void) { - /* Enable TIM16 Update interrupt */ - __HAL_TIM_ENABLE_IT(&htim16, TIM_IT_UPDATE); + /* Enable TIM6 Update interrupt */ + __HAL_TIM_ENABLE_IT(&htim6, TIM_IT_UPDATE); } diff --git a/Core/Src/stm32l4xx_it.c b/Core/Src/stm32l4xx_it.c index af4afe1..814bda5 100644 --- a/Core/Src/stm32l4xx_it.c +++ b/Core/Src/stm32l4xx_it.c @@ -56,7 +56,7 @@ /* External variables --------------------------------------------------------*/ extern UART_HandleTypeDef hlpuart1; -extern TIM_HandleTypeDef htim16; +extern TIM_HandleTypeDef htim6; /* USER CODE BEGIN EV */ @@ -86,7 +86,8 @@ void NMI_Handler(void) void HardFault_Handler(void) { /* USER CODE BEGIN HardFault_IRQn 0 */ - + // printf("something went wrong -> HardFault_Handler called\n"); + return; /* USER CODE END HardFault_IRQn 0 */ while (1) { @@ -161,17 +162,17 @@ void DebugMon_Handler(void) /******************************************************************************/ /** - * @brief This function handles TIM1 update interrupt and TIM16 global interrupt. + * @brief This function handles TIM6 global interrupt, DAC channel1 and channel2 underrun error interrupts. */ -void TIM1_UP_TIM16_IRQHandler(void) +void TIM6_DAC_IRQHandler(void) { - /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 0 */ + /* USER CODE BEGIN TIM6_DAC_IRQn 0 */ - /* USER CODE END TIM1_UP_TIM16_IRQn 0 */ - HAL_TIM_IRQHandler(&htim16); - /* USER CODE BEGIN TIM1_UP_TIM16_IRQn 1 */ + /* USER CODE END TIM6_DAC_IRQn 0 */ + HAL_TIM_IRQHandler(&htim6); + /* USER CODE BEGIN TIM6_DAC_IRQn 1 */ - /* USER CODE END TIM1_UP_TIM16_IRQn 1 */ + /* USER CODE END TIM6_DAC_IRQn 1 */ } /** diff --git a/stm32l4a6zg-f0x.at1 Debug.launch b/stm32l4a6zg-f0x.at1 Debug.launch index 93be68a..fa36eb1 100644 --- a/stm32l4a6zg-f0x.at1 Debug.launch +++ b/stm32l4a6zg-f0x.at1 Debug.launch @@ -33,7 +33,7 @@ - + @@ -75,6 +75,6 @@ - + diff --git a/stm32l4a6zg-f0x.at1.ioc b/stm32l4a6zg-f0x.at1.ioc index 9542fa2..d082e01 100644 --- a/stm32l4a6zg-f0x.at1.ioc +++ b/stm32l4a6zg-f0x.at1.ioc @@ -1,10 +1,13 @@ #MicroXplorer Configuration settings - do not modify +FREERTOS.BinarySemaphores01=data_access,Dynamic,NULL FREERTOS.FootprintOK=true -FREERTOS.IPParameters=Tasks01,configUSE_NEWLIB_REENTRANT,FootprintOK -FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;terminalTask,16,128,start_terminal_task,Default,NULL,Dynamic,NULL,NULL;idTask,8,128,start_id_task,Default,NULL,Dynamic,NULL,NULL +FREERTOS.IPParameters=Tasks01,configUSE_NEWLIB_REENTRANT,FootprintOK,Queues01,configTOTAL_HEAP_SIZE,BinarySemaphores01 +FREERTOS.Queues01=morseQueue,16,uint16_t,0,Dynamic,NULL,NULL +FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL;terminalTask,16,128,start_terminal_task,Default,NULL,Dynamic,NULL,NULL;morseTask,24,128,start_morse_task,Default,si5351_inst,Dynamic,NULL,NULL;clk2Task,40,128,start_clk2_task,Default,si5351_inst,Dynamic,NULL,NULL +FREERTOS.configTOTAL_HEAP_SIZE=30000 FREERTOS.configUSE_NEWLIB_REENTRANT=1 File.Version=6 -GPIO.groupedBy= +GPIO.groupedBy=Group By Peripherals I2C1.IPParameters=Timing I2C1.Timing=0x00505B89 KeepUserPlacement=false @@ -30,13 +33,14 @@ Mcu.IP1=I2C1 Mcu.IP2=LPUART1 Mcu.IP3=NVIC Mcu.IP4=RCC -Mcu.IP5=SYS -Mcu.IP6=USB_OTG_FS -Mcu.IPNb=7 +Mcu.IP5=RTC +Mcu.IP6=SYS +Mcu.IP7=USB_OTG_FS +Mcu.IPNb=8 Mcu.Name=STM32L4A6ZGTx Mcu.Package=LQFP144 -Mcu.Pin0=PC13 -Mcu.Pin1=PC14-OSC32_IN (PC14) +Mcu.Pin0=PC14-OSC32_IN (PC14) +Mcu.Pin1=PC15-OSC32_OUT (PC15) Mcu.Pin10=PA8 Mcu.Pin11=PA9 Mcu.Pin12=PA10 @@ -47,18 +51,20 @@ Mcu.Pin16=PA14 (JTCK/SWCLK) Mcu.Pin17=PB3 (JTDO/TRACESWO) Mcu.Pin18=PB7 Mcu.Pin19=PB8 -Mcu.Pin2=PC15-OSC32_OUT (PC15) +Mcu.Pin2=PH1-OSC_OUT (PH1) Mcu.Pin20=PB9 Mcu.Pin21=VP_FREERTOS_VS_CMSIS_V2 -Mcu.Pin22=VP_SYS_VS_tim16 -Mcu.Pin3=PH1-OSC_OUT (PH1) +Mcu.Pin22=VP_RTC_VS_RTC_Activate +Mcu.Pin23=VP_RTC_VS_RTC_Calendar +Mcu.Pin24=VP_SYS_VS_tim6 +Mcu.Pin3=PA2 Mcu.Pin4=PB14 Mcu.Pin5=PG5 Mcu.Pin6=PG6 Mcu.Pin7=PG7 Mcu.Pin8=PG8 Mcu.Pin9=PC7 -Mcu.PinsNb=23 +Mcu.PinsNb=25 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32L4A6ZGTx @@ -78,9 +84,9 @@ NVIC.SavedPendsvIrqHandlerGenerated=true NVIC.SavedSvcallIrqHandlerGenerated=true NVIC.SavedSystickIrqHandlerGenerated=true NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:false\:true\:true\:true\:true -NVIC.TIM1_UP_TIM16_IRQn=true\:15\:0\:false\:false\:true\:false\:false\:true\:true -NVIC.TimeBase=TIM1_UP_TIM16_IRQn -NVIC.TimeBaseIP=TIM16 +NVIC.TIM6_DAC_IRQn=true\:15\:0\:false\:false\:true\:false\:false\:true\:true +NVIC.TimeBase=TIM6_DAC_IRQn +NVIC.TimeBaseIP=TIM6 NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:true\:false\:true PA10.GPIOParameters=GPIO_Label PA10.GPIO_Label=USB_ID @@ -106,6 +112,8 @@ PA14\ (JTCK/SWCLK).GPIO_Label=TCK PA14\ (JTCK/SWCLK).Locked=true PA14\ (JTCK/SWCLK).Mode=Trace_Asynchronous_SW PA14\ (JTCK/SWCLK).Signal=SYS_JTCK-SWCLK +PA2.Mode=Clock-out-LSCO +PA2.Signal=RCC_LSCO PA8.GPIOParameters=GPIO_Label PA8.GPIO_Label=USB_SOF [TP1] PA8.Locked=true @@ -139,10 +147,6 @@ PB9.GPIO_Pu=GPIO_PULLUP PB9.Locked=true PB9.Mode=I2C PB9.Signal=I2C1_SDA -PC13.GPIOParameters=GPIO_Label -PC13.GPIO_Label=B1 -PC13.Locked=true -PC13.Signal=GPXTI13 PC14-OSC32_IN\ (PC14).Locked=true PC14-OSC32_IN\ (PC14).Mode=LSE-External-Oscillator PC14-OSC32_IN\ (PC14).Signal=RCC_OSC32_IN @@ -203,7 +207,7 @@ ProjectManager.StackSize=0x400 ProjectManager.TargetToolchain=STM32CubeIDE ProjectManager.ToolChainLocation= ProjectManager.UnderRoot=true -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_LPUART1_UART_Init-LPUART1-false-HAL-true,4-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true,5-MX_I2C1_Init-I2C1-false-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_LPUART1_UART_Init-LPUART1-false-HAL-true,4-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true,5-MX_I2C1_Init-I2C1-false-HAL-true,6-MX_RTC_Init-RTC-false-HAL-true RCC.ADCFreq_Value=48000000 RCC.AHBFreq_Value=47333333.333333336 RCC.APB1CLKDivider=RCC_HCLK_DIV2 @@ -214,7 +218,6 @@ RCC.APB2TimFreq_Value=47333333.333333336 RCC.CortexFreq_Value=47333333.333333336 RCC.DFSDMFreq_Value=23666666.666666668 RCC.FCLKCortexFreq_Value=47333333.333333336 -RCC.FLatency=FLASH_LATENCY_2 RCC.FamilyName=M RCC.HCLKFreq_Value=47333333.333333336 RCC.HSE_VALUE=8000000 @@ -224,11 +227,14 @@ RCC.I2C1Freq_Value=23666666.666666668 RCC.I2C2Freq_Value=23666666.666666668 RCC.I2C3Freq_Value=23666666.666666668 RCC.I2C4Freq_Value=23666666.666666668 -RCC.IPParameters=ADCFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,DFSDMFreq_Value,FCLKCortexFreq_Value,FLatency,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSI_VALUE,MCO1PinFreq_Value,MSI_VALUE,PLLN,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLR,PLLRCLKFreq_Value,PLLSAI1N,PLLSAI1PoutputFreq_Value,PLLSAI1QoutputFreq_Value,PLLSAI1RoutputFreq_Value,PLLSAI2PoutputFreq_Value,PLLSAI2RoutputFreq_Value,PWRFreq_Value,RNGFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMCFreq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAI1OutputFreq_Value,VCOSAI2OutputFreq_Value +RCC.IPParameters=ADCFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,DFSDMFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI48_VALUE,HSI_VALUE,I2C1Freq_Value,I2C2Freq_Value,I2C3Freq_Value,I2C4Freq_Value,LCDFreq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPUART1Freq_Value,LSCOPinFreq_Value,LSE_Drive_Capability,LSE_Timout,LSI_VALUE,MCO1PinFreq_Value,MSI_VALUE,PLLN,PLLPoutputFreq_Value,PLLQoutputFreq_Value,PLLR,PLLRCLKFreq_Value,PLLSAI1N,PLLSAI1PoutputFreq_Value,PLLSAI1QoutputFreq_Value,PLLSAI1RoutputFreq_Value,PLLSAI2PoutputFreq_Value,PLLSAI2RoutputFreq_Value,PWRFreq_Value,RNGFreq_Value,RTCClockSelection,RTCFreq_Value,SAI1Freq_Value,SAI2Freq_Value,SDMMCFreq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,UART4Freq_Value,UART5Freq_Value,USART1Freq_Value,USART2Freq_Value,USART3Freq_Value,USBFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VCOSAI1OutputFreq_Value,VCOSAI2OutputFreq_Value +RCC.LCDFreq_Value=32768 RCC.LPTIM1Freq_Value=23666666.666666668 RCC.LPTIM2Freq_Value=23666666.666666668 RCC.LPUART1Freq_Value=23666666.666666668 RCC.LSCOPinFreq_Value=32000 +RCC.LSE_Drive_Capability=RCC_LSEDRIVE_HIGH +RCC.LSE_Timout=50000 RCC.LSI_VALUE=32000 RCC.MCO1PinFreq_Value=47333333.333333336 RCC.MSI_VALUE=4000000 @@ -245,6 +251,8 @@ RCC.PLLSAI2PoutputFreq_Value=16000000 RCC.PLLSAI2RoutputFreq_Value=16000000 RCC.PWRFreq_Value=47333333.333333336 RCC.RNGFreq_Value=48000000 +RCC.RTCClockSelection=RCC_RTCCLKSOURCE_LSE +RCC.RTCFreq_Value=32768 RCC.SAI1Freq_Value=48000000 RCC.SAI2Freq_Value=48000000 RCC.SDMMCFreq_Value=48000000 @@ -261,8 +269,13 @@ RCC.VCOInputFreq_Value=4000000 RCC.VCOOutputFreq_Value=284000000 RCC.VCOSAI1OutputFreq_Value=96000000 RCC.VCOSAI2OutputFreq_Value=32000000 -SH.GPXTI13.0=GPIO_EXTI13 -SH.GPXTI13.ConfNb=1 +RTC.Date=23 +RTC.Hours=12 +RTC.IPParameters=Hours,Minutes,Month,Date,Year,StoreOperation +RTC.Minutes=30 +RTC.Month=RTC_MONTH_MAY +RTC.StoreOperation=RTC_STOREOPERATION_RESET +RTC.Year=22 USB_OTG_FS.IPParameters=low_power_enable,battery_charging_enable,lpm_enable,use_dedicated_ep1,vbus_sensing_enable,Sof_enable,VirtualMode USB_OTG_FS.Sof_enable=ENABLE USB_OTG_FS.VirtualMode=Device_Only @@ -273,8 +286,12 @@ USB_OTG_FS.use_dedicated_ep1=DISABLE USB_OTG_FS.vbus_sensing_enable=ENABLE VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2 VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2 -VP_SYS_VS_tim16.Mode=TIM16 -VP_SYS_VS_tim16.Signal=SYS_VS_tim16 +VP_RTC_VS_RTC_Activate.Mode=RTC_Enabled +VP_RTC_VS_RTC_Activate.Signal=RTC_VS_RTC_Activate +VP_RTC_VS_RTC_Calendar.Mode=RTC_Calendar +VP_RTC_VS_RTC_Calendar.Signal=RTC_VS_RTC_Calendar +VP_SYS_VS_tim6.Mode=TIM6 +VP_SYS_VS_tim6.Signal=SYS_VS_tim6 board=NUCLEO-L4A6ZG boardIOC=true isbadioc=false