From a3fcd0e57c7ac653651e5bace525d739bff5eee0 Mon Sep 17 00:00:00 2001 From: Thomas Kuschel Date: Mon, 6 Jun 2022 22:33:30 +0200 Subject: [PATCH] Test with phase diff b/w CLK0 and CLK2 --- Core/Inc/commands.h | 29 +++++++ Core/Inc/stm32_si5351.h | 5 +- Core/Inc/stm32_si5351_reg.h | 59 ++++++++++++++ Core/Src/commands.c | 49 ++++++++++++ Core/Src/main.c | 39 ++++++++- Core/Src/stm32_si5351.c | 133 ++++++++++++++++++++++++++++--- Core/Src/stm32l4xx_it.c | 2 +- stm32l4a6zg-f0x.at1 Debug.cfg | 42 ++++++++++ stm32l4a6zg-f0x.at1 Debug.launch | 16 +++- 9 files changed, 356 insertions(+), 18 deletions(-) create mode 100644 Core/Inc/commands.h create mode 100644 Core/Src/commands.c create mode 100644 stm32l4a6zg-f0x.at1 Debug.cfg diff --git a/Core/Inc/commands.h b/Core/Inc/commands.h new file mode 100644 index 0000000..9ede63e --- /dev/null +++ b/Core/Inc/commands.h @@ -0,0 +1,29 @@ +/** + ****************************************************************************** + * @file commands.h + * @brief Header for command.c file, the command interpreter, a generic one + ****************************************************************************** + * @author: Thomas Kuschel KW4NZ + * created 2022-06-04 + * + ******************************************************************************/ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __COMMANDS_H_ +#define __COMMANDS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//struct command_ctx_s *command_inst; +typedef struct command_ctx_s *command_inst_t; + +/* function prototypes */ +int not_implemented(command_inst_t inst, char *args); + + +#ifdef __cplusplus +} +#endif + +#endif /* __COMMANDS_H_ */ diff --git a/Core/Inc/stm32_si5351.h b/Core/Inc/stm32_si5351.h index 188ff22..a3659c8 100644 --- a/Core/Inc/stm32_si5351.h +++ b/Core/Inc/stm32_si5351.h @@ -133,12 +133,15 @@ typedef enum { /* Exported functions --------------------------------------------------------*/ 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_i2c_ready(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); +int si5351_set_clk_phase(si5351_inst_t inst, uint32_t frequency, double phase, uint8_t clk, si5351_pll_t pll); +int si5351_set_phase(si5351_inst_t inst, uint8_t phase, uint8_t clk); + #if SI5351_DEFAULTS si5351_inst_t si5351_initialize(void * i2c_handle); diff --git a/Core/Inc/stm32_si5351_reg.h b/Core/Inc/stm32_si5351_reg.h index 88aab4a..7bb818f 100644 --- a/Core/Inc/stm32_si5351_reg.h +++ b/Core/Inc/stm32_si5351_reg.h @@ -1073,6 +1073,65 @@ even integers greater than or equal to 6. All other divide values are invalid. * #define R6_DIV_0 (1u<<4) /* 110b: Divide by 64, 111b: Divide by 128 */ #define R6_DIV (7u<<4) +/* Spread Spectrum Parameters + * Registers 149 upto 161 + */ + +/* VCXO Parameters + * Registers 162 upto 164 + */ + +/* CLK0 Initial Phase Offset + * CLK0_PHOFF[6:0] is an unsigned integer with one LSB equivalent to a time delay of Tvco/4, where + * Tvco is the period of the VCO/PLL associated with this output. + */ +#define SI5351_CLK0_INITIAL_PHASE_OFFSET 165u /* R/W */ +#define CLKx_PHOFF_RESERVED (0u<<7) /* 0b: Only write 0 to this bit */ +#define CLKx_PHOFF_6 (1u<<6) +#define CLKx_PHOFF_5 (1u<<5) +#define CLKx_PHOFF_4 (1u<<4) +#define CLKx_PHOFF_3 (1u<<3) +#define CLKx_PHOFF_2 (1u<<2) +#define CLKx_PHOFF_1 (1u<<1) +#define CLKx_PHOFF_0 (1u<<0) +#define CLKx_PHOFF (0x7F) +#define CLK0_PHOFF CLKx_PHOFF + +/* CLK1 Initial Phase Offset + * CLK1_PHOFF[6:0] is an unsigned integer with one LSB equivalent to a time delay of Tvco/4, where + * Tvco is the period of the VCO/PLL associated with this output. + */ +#define SI5351_CLK1_INITIAL_PHASE_OFFSET 166u /* R/W */ +#define CLK1_PHOFF CLKx_PHOFF + +/* CLK2 Initial Phase Offset + * CLK2_PHOFF[6:0] is an unsigned integer with one LSB equivalent to a time delay of Tvco/4, where + * Tvco is the period of the VCO/PLL associated with this output. + */ +#define SI5351_CLK2_INITIAL_PHASE_OFFSET 167u /* R/W */ +#define CLK2_PHOFF CLKx_PHOFF + +/* CLK2 Initial Phase Offset + * CLK2_PHOFF[6:0] is an unsigned integer with one LSB equivalent to a time delay of Tvco/4, where + * Tvco is the period of the VCO/PLL associated with this output. + */ +#define SI5351_CLK3_INITIAL_PHASE_OFFSET 168u /* R/W */ +#define CLK3_PHOFF CLKx_PHOFF + +/* CLK3 Initial Phase Offset + * CLK3_PHOFF[6:0] is an unsigned integer with one LSB equivalent to a time delay of Tvco/4, where + * Tvco is the period of the VCO/PLL associated with this output. + */ +#define SI5351_CLK4_INITIAL_PHASE_OFFSET 169u /* R/W */ +#define CLK4_PHOFF CLKx_PHOFF + +/* CLK4 Initial Phase Offset + * CLK4_PHOFF[6:0] is an unsigned integer with one LSB equivalent to a time delay of Tvco/4, where + * Tvco is the period of the VCO/PLL associated with this output. + */ +#define SI5351_CLK5_INITIAL_PHASE_OFFSET 170u /* R/W */ +#define CLK5_PHOFF CLKx_PHOFF + /* PLL Reset * Resets the PLLA, PLLB when writing an 1 to the corresponding bit * Leave the reserved bits as default. diff --git a/Core/Src/commands.c b/Core/Src/commands.c new file mode 100644 index 0000000..d5bc8e4 --- /dev/null +++ b/Core/Src/commands.c @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * @file commands.c + * @brief command.c file, the command interpreter, a generic one + ****************************************************************************** + * @author: Thomas Kuschel KW4NZ + * created 2022-06-04 + * + ******************************************************************************/ +#include "cmsis_os.h" +#include + +#include "commands.h" + +typedef struct command_ctx_s { + osThreadId_t thread_id; + osMutexId_t mutex; + char *last_cmd; + size_t last_cmd_size; +} command_ctx_t; + + +typedef enum { + CMD_HIDDEN = 0x01, /*!< Not shown in help but listed with "help all" or with "?" */ + CMD_SECRET = 0x02, /*!< Not shown in help - hidden and secret commands */ + CMD_ADMIN = 0x04, /*!< Only an administrator or privileged person can use this command */ + CMD_NOT_IMPLEMENTED = 0x80 /*!< A command which is not implemented yet */ +} cmd_flags_t; + +#define CMD_LENGTH 16 + +typedef struct{ + const char name[CMD_LENGTH]; /*!< command name */ + const uint8_t significantlength; /*!< length of command for the compare function */ + const uint8_t flag; /*!< command flags, i.e. CMD_HIDDEN, CMD_SECRET, CMD_ADMIN, etc. */ + int(*func)(command_ctx_t *ctx, char *args); +} cmd_table_t; + +static const cmd_table_t cmd_table[] = { + {"altitude", 1, CMD_NOT_IMPLEMENTED, not_implemented }, + {"date", 1, CMD_NOT_IMPLEMENTED, not_implemented }, +}; + +int not_implemented(command_ctx_t *ctx, char *args) { + (void) *ctx; + (void) *args; + return 0; +} + diff --git a/Core/Src/main.c b/Core/Src/main.c index 3802e06..92a1acf 100644 --- a/Core/Src/main.c +++ b/Core/Src/main.c @@ -25,6 +25,7 @@ #include #include "at1_defines.h" #include "stm32_si5351.h" +#include "commands.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -145,8 +146,8 @@ int main(void) // 1st SI5351 chip at the I2C bus "hi2c1", address line A0 = 0 si5351_inst = si5351_init(&hi2c1, 25000000, 0x60, 0); { - int ready = si5351_isready(si5351_inst); - printf("Si5351 device is %s\n", (ready==0) ? "ready" : "N/A"); + int ready = si5351_i2c_ready(si5351_inst); + printf("Si5351 device is %s\n", (ready==1) ? "ready" : "N/A"); } #if 0 puts("Registers of Device No. 1"); @@ -178,7 +179,41 @@ int main(void) HAL_Delay(10000); #endif +#if 1 + si5351_set_clk0(si5351_inst, 3550000); + si5351_enable_output(si5351_inst,0); + + si5351_set_clk_phase(si5351_inst,3550000, 255-100, 0, SI5351_PLLA); + si5351_set_clk_phase(si5351_inst,3550000, 100, 2, SI5351_PLLA); + si5351_enable_output(si5351_inst,0); + si5351_enable_output(si5351_inst,2); + HAL_Delay(10000); + while(1) { + for (int i = 0; i< 128; i++) { + //HAL_Delay(0); + //printf("phase: %d\n", i); + si5351_set_clk_phase(si5351_inst,3550000, i, 2,SI5351_PLLA); + si5351_set_clk_phase(si5351_inst, 3550000,255-i, 0, SI5351_PLLA); + //si5351_set_clk(si5351_inst,3550001, 2, SI5351_PLLB); + si5351_enable_output(si5351_inst,0); + si5351_enable_output(si5351_inst,2); + } + for (int i = 127; i>=0; i--) { + //HAL_Delay(0); + //printf("phase: %d\n", i); + si5351_set_clk_phase(si5351_inst,3550000, i, 2,SI5351_PLLA); + si5351_set_clk_phase(si5351_inst, 3550000,255-i, 0, SI5351_PLLA); + //si5351_set_clk(si5351_inst,3550001, 2, SI5351_PLLB); + si5351_enable_output(si5351_inst,0); + si5351_enable_output(si5351_inst,2); + } + + } + + +#endif + HAL_Delay(60000); while (1) { HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET); diff --git a/Core/Src/stm32_si5351.c b/Core/Src/stm32_si5351.c index 7c78261..626066a 100644 --- a/Core/Src/stm32_si5351.c +++ b/Core/Src/stm32_si5351.c @@ -49,7 +49,8 @@ typedef struct __SI5351_HandleTypeDef { #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 clk_has_phase_shift; /*!< assignment of an output with a phase shift offset */ + 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 */ @@ -63,7 +64,7 @@ typedef struct { 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 */ + 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 { @@ -187,15 +188,15 @@ int si5351_write(si5351_inst_t instance, uint8_t regaddr, uint8_t *data, uint16_ /** @brief Check if there is any I2C device ready on the bus * @param si5351_instance Given si5351 device handle - * @return 0 on success + * @return 1 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 si5351_i2c_ready(si5351_inst_t inst) { - int status; + HAL_StatusTypeDef status; if(!inst && !(inst=first_handle)) return -EINVAL; @@ -203,7 +204,7 @@ int si5351_isready(si5351_inst_t inst) { /* 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); + return (status == HAL_OK) ? 1 : si5351_error_status_i2c(status); } /* End of wrapper functions receiving/transceiving bytes */ @@ -423,7 +424,7 @@ int si5351_program(si5351_inst_t inst) { */ int band_select(uint32_t frequency, band_t *band) { - static const band_t sband[] = { + static const band_t sband[] = { /* band in metres, frequ_lo, frequ_hi, multiplier, divider_bit */ { "80", 3000000, 4500000, 200, 0}, { "40", 5625000, 7500000, 120, 0}, { "30", 7500000,11250000, 80, 0}, @@ -580,7 +581,7 @@ int si5351_set_clk0(si5351_inst_t inst, uint32_t frequency) { do { if(!inst->programmed) { rv = si5351_program(inst); - if (!rv) + if (rv) break; } (void)calculation(frequency, inst->xtal_frequency, &synth); @@ -625,6 +626,112 @@ int si5351_set_clk(si5351_inst_t inst, uint32_t frequency, uint8_t clk, si5351_p return rv; } +/** @brief Sets the CLK_x output of the si5351 with phase + * @param si5351_instance Given si5351 device handle + * @param frequency + * @param phase in degree as double value + * @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_phase(si5351_inst_t inst, uint32_t frequency, double phase, 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 &= (uint8_t)~(1u << clk); /* delete the bit */ + else + inst->clk_is_pllb |= (uint8_t)(1u << clk); /* set the bit */ + + do { + + if(!inst->programmed) { + rv = si5351_program(inst); + if (rv) + break; + } + /* calculate the phase */ + if (phase > 0.0) { + inst->clk_has_phase_shift |= (uint8_t)(1u << clk); /* set phase shift */ + double pll_frequency, phaseoff; + //pll_frequency = ((double)synth.pll_multiplier + (double)(synth.pll_numerator / synth.pll_denominator)) * (double)inst->xtal_frequency; + //phaseoff = 4.0 * pll_frequency; + (void)phaseoff; + + } else { + inst->clk_has_phase_shift &= (uint8_t)~(1u << clk); /* reset phase shift */ + } + uint8_t ph = (uint8_t) phase; + rv = si5351_write(inst, SI5351_CLK0_INITIAL_PHASE_OFFSET + clk, &ph, 1); + + (void)calculation(frequency, inst->xtal_frequency, &synth); + rv = si5351_set_synthesis(inst, &synth, clk); + } while(0); + return rv; + +} + +/** @brief Resets the PLL of the si5351 (direct access to register) + * @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_reset_pll(si5351_inst_t inst, uint8_t clk) { + + /* internal function, no need to check inst nor clk */ + + uint8_t reset; + +#if 1 + reset = (inst->clk_is_pllb & (1< 5 || phase > CLKx_PHOFF) + return -EINVAL; + +/* if (phase) { + si5351_write(inst, ) + } +*/ + rv = si5351_write(inst, SI5351_CLK0_INITIAL_PHASE_OFFSET + clk, &phase, 1); + + si5351_reset_pll(inst, clk); + + return rv; +} + /** @brief Sets the MSNx and MSx parameter registers of the Si5351 * @param si5351_instance Given si5351 device handle * @param synth synthesis_t struct @@ -705,19 +812,19 @@ int si5351_set_synthesis(si5351_inst_t inst, synthesis_t *synth, uint8_t clk) { if (rv) return rv; - if ((synth->out_numerator == 0) && ((synth->out_multiplier & 0x01) == 0)) - MSx_INT = 1; + MSx_INT = ((synth->out_numerator == 0) && ((synth->out_multiplier & 0x01) == 0) && + !(inst->clk_has_phase_shift & (1<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; + ms_data[0] = (uint8_t)(MSx_INT << 6 | MSx_SRC << 5 | SI5351_CLK_SRC_MS0 | SI5351_CLK_2_MA); //SI5351_CLK_6_MA; //SI5351_CLK_4_MA; regaddr = SI5351_CLK0_CONTROL + clk; rv = si5351_write(inst, regaddr, ms_data, 1); if (rv) return rv; - ms_data[0] = SI5351_PLL_RESET_VALUE; - rv = si5351_write(inst, SI5351_PLL_RESET, ms_data, 1); + rv = si5351_reset_pll(inst, clk); if (rv) return rv; diff --git a/Core/Src/stm32l4xx_it.c b/Core/Src/stm32l4xx_it.c index cae32f2..d371ded 100644 --- a/Core/Src/stm32l4xx_it.c +++ b/Core/Src/stm32l4xx_it.c @@ -85,7 +85,7 @@ void NMI_Handler(void) void HardFault_Handler(void) { /* USER CODE BEGIN HardFault_IRQn 0 */ - printf("something went wrong -> HardFault_Handler called\n"); + //printf("something went wrong -> HardFault_Handler called\n"); /* USER CODE END HardFault_IRQn 0 */ while (1) { diff --git a/stm32l4a6zg-f0x.at1 Debug.cfg b/stm32l4a6zg-f0x.at1 Debug.cfg new file mode 100644 index 0000000..bbaa921 --- /dev/null +++ b/stm32l4a6zg-f0x.at1 Debug.cfg @@ -0,0 +1,42 @@ +# This is an NUCLEO-L4A6ZG board with a single STM32L4A6ZGTx chip +# +# Generated by STM32CubeIDE +# Take care that such file, as generated, may be overridden without any early notice. Please have a look to debug launch configuration setup(s) + +source [find interface/stlink-dap.cfg] + + +set WORKAREASIZE 0x8000 + +transport select "dapdirect_swd" + +set CHIPNAME STM32L4A6ZGTx +set BOARDNAME NUCLEO-L4A6ZG + +# Enable debug when in low power modes +set ENABLE_LOW_POWER 1 + +# Stop Watchdog counters when halt +set STOP_WATCHDOG 1 + +# STlink Debug clock frequency +set CLOCK_FREQ 8000 + +# Reset configuration +# use hardware reset, connect under reset +# connect_assert_srst needed if low power mode application running (WFI...) +reset_config srst_only srst_nogate connect_assert_srst +set CONNECT_UNDER_RESET 1 +set CORE_RESET 0 + +# ACCESS PORT NUMBER +set AP_NUM 0 +# GDB PORT +set GDB_PORT 3333 + + + +# BCTM CPU variables + +source [find target/stm32l4x.cfg] + diff --git a/stm32l4a6zg-f0x.at1 Debug.launch b/stm32l4a6zg-f0x.at1 Debug.launch index fa36eb1..b2deea8 100644 --- a/stm32l4a6zg-f0x.at1 Debug.launch +++ b/stm32l4a6zg-f0x.at1 Debug.launch @@ -20,6 +20,20 @@ + + + + + + + + + + + + + + @@ -33,7 +47,7 @@ - +