mirror of
https://github.com/ttrftech/NanoVNA.git
synced 2025-12-06 03:31:59 +01:00
si5351.c and si5351.h
Cleanup and optimize code Add comments, fix definitions Fix rounding errors Fix band 1 stability mcuconf.h Set I2C bus clock to SYSCLK (more fast) Apply 400kHz bus I2C clock timings for 8MHz and 48Mhz clock main.c Remove and reset some variables Add separate sweep for calibration (allow calibrate if sweep paused) Increase main thread stack (need for run calibrate, possibly need execute some commands in sweep threads for reduce stack usage)
This commit is contained in:
parent
b77e1d6680
commit
a43b6e3acc
4
Makefile
4
Makefile
|
|
@ -64,13 +64,13 @@ endif
|
||||||
# Stack size to be allocated to the Cortex-M process stack. This stack is
|
# Stack size to be allocated to the Cortex-M process stack. This stack is
|
||||||
# the stack used by the main() thread.
|
# the stack used by the main() thread.
|
||||||
ifeq ($(USE_PROCESS_STACKSIZE),)
|
ifeq ($(USE_PROCESS_STACKSIZE),)
|
||||||
USE_PROCESS_STACKSIZE = 0x200
|
USE_PROCESS_STACKSIZE = 0x300
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Stack size to the allocated to the Cortex-M main/exceptions stack. This
|
# Stack size to the allocated to the Cortex-M main/exceptions stack. This
|
||||||
# stack is used for processing interrupts and exceptions.
|
# stack is used for processing interrupts and exceptions.
|
||||||
ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
|
ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
|
||||||
USE_EXCEPTIONS_STACKSIZE = 0x200
|
USE_EXCEPTIONS_STACKSIZE = 0x100
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
||||||
152
main.c
152
main.c
|
|
@ -69,19 +69,17 @@ static void transform_domain(void);
|
||||||
|
|
||||||
static MUTEX_DECL(mutex);
|
static MUTEX_DECL(mutex);
|
||||||
|
|
||||||
int32_t frequency_offset = 5000;
|
// Obsolete enable/disable calibration interpolation (always on)
|
||||||
uint32_t frequency = 10000000;
|
#define cal_auto_interpolate TRUE
|
||||||
int8_t drive_strength = DRIVE_STRENGTH_AUTO;
|
|
||||||
int8_t sweep_enabled = TRUE;
|
static int32_t frequency_offset = 5000;
|
||||||
volatile int8_t sweep_once = FALSE;
|
static uint32_t frequency = 10000000;
|
||||||
int8_t cal_auto_interpolate = TRUE;
|
static int8_t drive_strength = DRIVE_STRENGTH_AUTO;
|
||||||
uint16_t redraw_request = 0; // contains REDRAW_XXX flags
|
volatile int8_t sweep_mode = SWEEP_MODE_ENABLED;
|
||||||
|
|
||||||
|
volatile uint8_t redraw_request = 0; // contains REDRAW_XXX flags
|
||||||
int16_t vbat = 0;
|
int16_t vbat = 0;
|
||||||
|
|
||||||
//
|
|
||||||
// Profile stack usage (enable threads command by def ENABLE_THREADS_COMMAND) show:
|
|
||||||
// Stack maximum usage = 576 bytes, free stack = 64 bytes
|
|
||||||
//
|
|
||||||
static THD_WORKING_AREA(waThread1, 640);
|
static THD_WORKING_AREA(waThread1, 640);
|
||||||
static THD_FUNCTION(Thread1, arg)
|
static THD_FUNCTION(Thread1, arg)
|
||||||
{
|
{
|
||||||
|
|
@ -90,11 +88,10 @@ static THD_FUNCTION(Thread1, arg)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
bool completed = false;
|
bool completed = false;
|
||||||
if (sweep_enabled || sweep_once) {
|
if (sweep_mode&(SWEEP_MODE_ENABLED|SWEEP_MODE_RUN_ONCE)) {
|
||||||
chMtxLock(&mutex);
|
chMtxLock(&mutex);
|
||||||
// Sweep require 8367 system tick
|
|
||||||
completed = sweep(true);
|
completed = sweep(true);
|
||||||
sweep_once = FALSE;
|
sweep_mode&=~SWEEP_MODE_RUN_ONCE;
|
||||||
chMtxUnlock(&mutex);
|
chMtxUnlock(&mutex);
|
||||||
} else {
|
} else {
|
||||||
si5351_disable_output();
|
si5351_disable_output();
|
||||||
|
|
@ -102,10 +99,8 @@ static THD_FUNCTION(Thread1, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
chMtxLock(&mutex);
|
chMtxLock(&mutex);
|
||||||
// Ui and render require 800 system tick
|
|
||||||
ui_process();
|
ui_process();
|
||||||
|
if (sweep_mode&SWEEP_MODE_ENABLED) {
|
||||||
if (sweep_enabled) {
|
|
||||||
if (vbat != -1) {
|
if (vbat != -1) {
|
||||||
adc_stop(ADC1);
|
adc_stop(ADC1);
|
||||||
vbat = adc_vbat_read(ADC1);
|
vbat = adc_vbat_read(ADC1);
|
||||||
|
|
@ -135,23 +130,10 @@ static THD_FUNCTION(Thread1, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void run_once_sweep(void) {sweep_mode|=SWEEP_MODE_RUN_ONCE;}
|
||||||
pause_sweep(void)
|
static inline void pause_sweep(void) {sweep_mode&=~SWEEP_MODE_ENABLED;}
|
||||||
{
|
static inline void resume_sweep(void){sweep_mode|= SWEEP_MODE_ENABLED;}
|
||||||
sweep_enabled = FALSE;
|
void toggle_sweep(void){sweep_mode^= SWEEP_MODE_ENABLED;}
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
resume_sweep(void)
|
|
||||||
{
|
|
||||||
sweep_enabled = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
toggle_sweep(void)
|
|
||||||
{
|
|
||||||
sweep_enabled = !sweep_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float
|
static float
|
||||||
bessel0(float x) {
|
bessel0(float x) {
|
||||||
|
|
@ -316,16 +298,15 @@ const int8_t gain_table[] = {
|
||||||
#define DELAY_GAIN_CHANGE 2
|
#define DELAY_GAIN_CHANGE 2
|
||||||
|
|
||||||
static int
|
static int
|
||||||
adjust_gain(int newfreq)
|
adjust_gain(uint32_t newfreq)
|
||||||
{
|
{
|
||||||
int delay = 0;
|
|
||||||
int new_order = newfreq / FREQ_HARMONICS;
|
int new_order = newfreq / FREQ_HARMONICS;
|
||||||
int old_order = frequency / FREQ_HARMONICS;
|
int old_order = frequency / FREQ_HARMONICS;
|
||||||
if (new_order != old_order) {
|
if (new_order != old_order) {
|
||||||
tlv320aic3204_set_gain(gain_table[new_order], gain_table[new_order]);
|
tlv320aic3204_set_gain(gain_table[new_order], gain_table[new_order]);
|
||||||
delay += DELAY_GAIN_CHANGE;
|
return DELAY_GAIN_CHANGE;
|
||||||
}
|
}
|
||||||
return delay;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_frequency(uint32_t freq)
|
int set_frequency(uint32_t freq)
|
||||||
|
|
@ -778,27 +759,23 @@ ensure_edit_config(void)
|
||||||
#define DELAY_CHANNEL_CHANGE 2
|
#define DELAY_CHANNEL_CHANGE 2
|
||||||
|
|
||||||
// main loop for measurement
|
// main loop for measurement
|
||||||
bool sweep(bool break_on_operation)
|
static bool sweep(bool break_on_operation)
|
||||||
{
|
{
|
||||||
int i;
|
int i, delay;
|
||||||
// blink LED while scanning
|
// blink LED while scanning
|
||||||
palClearPad(GPIOC, GPIOC_LED);
|
palClearPad(GPIOC, GPIOC_LED);
|
||||||
systime_t time = chVTGetSystemTimeX();
|
|
||||||
systime_t sweep_t = 0;
|
|
||||||
si5351_enable_output();
|
si5351_enable_output();
|
||||||
// On CW set freq once, and run
|
wait_dsp(1); // Wait for get optimal timings
|
||||||
for (i = 0; i < sweep_points; i++) { // 8365
|
for (i = 0; i < sweep_points; i++) { // 5300
|
||||||
sweep_t-= chVTGetSystemTimeX();
|
delay = set_frequency(frequencies[i]); // 700
|
||||||
int delay = set_frequency(frequencies[i]); // 1560
|
|
||||||
sweep_t+= chVTGetSystemTimeX();
|
|
||||||
tlv320aic3204_select(0); // 60 CH0:REFLECT
|
tlv320aic3204_select(0); // 60 CH0:REFLECT
|
||||||
|
|
||||||
wait_dsp(delay+(i==0 ? 1 :0)); // 3270
|
wait_dsp(delay); // 1900
|
||||||
// calculate reflection coefficient
|
// calculate reflection coefficient
|
||||||
(*sample_func)(measured[0][i]); // 60
|
(*sample_func)(measured[0][i]); // 60
|
||||||
|
|
||||||
tlv320aic3204_select(1); // 60 CH1:TRANSMISSION
|
tlv320aic3204_select(1); // 60 CH1:TRANSMISSION
|
||||||
wait_dsp(DELAY_CHANNEL_CHANGE); // 2700
|
wait_dsp(DELAY_CHANNEL_CHANGE); // 1800
|
||||||
// calculate transmission coefficient
|
// calculate transmission coefficient
|
||||||
(*sample_func)(measured[1][i]); // 60
|
(*sample_func)(measured[1][i]); // 60
|
||||||
// ======== 170 ===========
|
// ======== 170 ===========
|
||||||
|
|
@ -813,7 +790,6 @@ bool sweep(bool break_on_operation)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{char string_buf[18];plot_printf(string_buf, sizeof string_buf, "T:%06d:%06d", chVTGetSystemTimeX() - time, sweep_t);ili9341_drawstringV(string_buf, 1, 90);}
|
|
||||||
// blink LED while scanning
|
// blink LED while scanning
|
||||||
palSetPad(GPIOC, GPIOC_LED);
|
palSetPad(GPIOC, GPIOC_LED);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -849,11 +825,11 @@ VNA_SHELL_FUNCTION(cmd_scan)
|
||||||
if (cal_auto_interpolate && (cal_status & CALSTAT_APPLY))
|
if (cal_auto_interpolate && (cal_status & CALSTAT_APPLY))
|
||||||
cal_interpolate(lastsaveid);
|
cal_interpolate(lastsaveid);
|
||||||
|
|
||||||
sweep_once = TRUE;
|
run_once_sweep();
|
||||||
chMtxUnlock(&mutex);
|
chMtxUnlock(&mutex);
|
||||||
|
|
||||||
// wait finishing sweep
|
// wait finishing sweep
|
||||||
while (sweep_once)
|
while (sweep_mode&SWEEP_MODE_RUN_ONCE)
|
||||||
chThdSleepMilliseconds(10);
|
chThdSleepMilliseconds(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1294,36 +1270,21 @@ void
|
||||||
cal_collect(int type)
|
cal_collect(int type)
|
||||||
{
|
{
|
||||||
ensure_edit_config();
|
ensure_edit_config();
|
||||||
|
int dst, src;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case CAL_LOAD:
|
case CAL_LOAD: cal_status|= CALSTAT_LOAD; dst = CAL_LOAD; src = 0; break;
|
||||||
cal_status |= CALSTAT_LOAD;
|
case CAL_OPEN: cal_status|= CALSTAT_OPEN; dst = CAL_OPEN; src = 0; cal_status&= ~(CALSTAT_ES|CALSTAT_APPLY); break;
|
||||||
memcpy(cal_data[CAL_LOAD], measured[0], sizeof measured[0]);
|
case CAL_SHORT: cal_status|= CALSTAT_SHORT; dst = CAL_SHORT; src = 0; cal_status&= ~(CALSTAT_ER|CALSTAT_APPLY); break;
|
||||||
break;
|
case CAL_THRU: cal_status|= CALSTAT_THRU; dst = CAL_THRU; src = 1; break;
|
||||||
|
case CAL_ISOLN: cal_status|= CALSTAT_ISOLN; dst = CAL_ISOLN; src = 1; break;
|
||||||
case CAL_OPEN:
|
default:
|
||||||
cal_status |= CALSTAT_OPEN;
|
return;
|
||||||
cal_status &= ~(CALSTAT_ES|CALSTAT_APPLY);
|
|
||||||
memcpy(cal_data[CAL_OPEN], measured[0], sizeof measured[0]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAL_SHORT:
|
|
||||||
cal_status |= CALSTAT_SHORT;
|
|
||||||
cal_status &= ~(CALSTAT_ER|CALSTAT_APPLY);
|
|
||||||
memcpy(cal_data[CAL_SHORT], measured[0], sizeof measured[0]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAL_THRU:
|
|
||||||
cal_status |= CALSTAT_THRU;
|
|
||||||
memcpy(cal_data[CAL_THRU], measured[1], sizeof measured[0]);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CAL_ISOLN:
|
|
||||||
cal_status |= CALSTAT_ISOLN;
|
|
||||||
memcpy(cal_data[CAL_ISOLN], measured[1], sizeof measured[0]);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
redraw_request |= REDRAW_CAL_STATUS;
|
// Made sweep operation for collect calibration data
|
||||||
|
sweep(false);
|
||||||
|
// Copy calibration data
|
||||||
|
memcpy(cal_data[dst], measured[src], sizeof measured[0]);
|
||||||
|
redraw_request|= REDRAW_CAL_STATUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2165,24 +2126,27 @@ THD_FUNCTION(myshellThread, p) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// I2C clock bus setting: depend from STM32_I2C1SW in mcuconf.h
|
// I2C clock bus setting: depend from STM32_I2C1SW in mcuconf.h
|
||||||
// STM32_I2C1SW = STM32_I2C1SW_HSI (HSI=8MHz)
|
|
||||||
// STM32_I2C1SW = STM32_I2C1SW_SYSCLK (SYSCLK = 48MHz)
|
|
||||||
static const I2CConfig i2ccfg = {
|
static const I2CConfig i2ccfg = {
|
||||||
// TIMINGR register initialization. (use I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers (AN4235))
|
.timingr = // TIMINGR register initialization. (use I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers (AN4235))
|
||||||
// 400kHz @ SYSCLK 48MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
|
#if STM32_I2C1SW == STM32_I2C1SW_HSI
|
||||||
// STM32_TIMINGR_PRESC(5U) |
|
// STM32_I2C1SW == STM32_I2C1SW_HSI (HSI=8MHz)
|
||||||
// STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(3U) |
|
// 400kHz @ HSI 8MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
|
||||||
// STM32_TIMINGR_SCLH(3U) | STM32_TIMINGR_SCLL(9U),
|
|
||||||
// 400kHz @ HSI 8MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
|
|
||||||
STM32_TIMINGR_PRESC(0U) |
|
STM32_TIMINGR_PRESC(0U) |
|
||||||
STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(1U) |
|
STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(1U) |
|
||||||
STM32_TIMINGR_SCLH(3U) | STM32_TIMINGR_SCLL(9U),
|
STM32_TIMINGR_SCLH(3U) | STM32_TIMINGR_SCLL(9U),
|
||||||
// Old values voodoo magic 400kHz @ HSI 8MHz
|
// Old values voodoo magic 400kHz @ HSI 8MHz
|
||||||
// STM32_TIMINGR_PRESC(0U) |
|
//0x00300506,
|
||||||
// STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(0U) |
|
#elif STM32_I2C1SW == STM32_I2C1SW_SYSCLK
|
||||||
// STM32_TIMINGR_SCLH(5U) | STM32_TIMINGR_SCLL(6U),
|
// STM32_I2C1SW == STM32_I2C1SW_SYSCLK (SYSCLK = 48MHz)
|
||||||
0, // CR1 register initialization.
|
// 400kHz @ SYSCLK 48MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual)
|
||||||
0 // CR2 register initialization.
|
STM32_TIMINGR_PRESC(5U) |
|
||||||
|
STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(3U) |
|
||||||
|
STM32_TIMINGR_SCLH(3U) | STM32_TIMINGR_SCLL(9U),
|
||||||
|
#else
|
||||||
|
#error "Need Define STM32_I2C1SW and set correct TIMINGR settings"
|
||||||
|
#endif
|
||||||
|
.cr1 = 0, // CR1 register initialization.
|
||||||
|
.cr2 = 0 // CR2 register initialization.
|
||||||
};
|
};
|
||||||
|
|
||||||
static DACConfig dac1cfg1 = {
|
static DACConfig dac1cfg1 = {
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@
|
||||||
#define STM32_ADCSW STM32_ADCSW_HSI14
|
#define STM32_ADCSW STM32_ADCSW_HSI14
|
||||||
#define STM32_USBSW STM32_USBSW_HSI48
|
#define STM32_USBSW STM32_USBSW_HSI48
|
||||||
#define STM32_CECSW STM32_CECSW_HSI
|
#define STM32_CECSW STM32_CECSW_HSI
|
||||||
#define STM32_I2C1SW STM32_I2C1SW_HSI
|
//#define STM32_I2C1SW STM32_I2C1SW_HSI
|
||||||
|
#define STM32_I2C1SW STM32_I2C1SW_SYSCLK
|
||||||
#define STM32_USART1SW STM32_USART1SW_PCLK
|
#define STM32_USART1SW STM32_USART1SW_PCLK
|
||||||
#define STM32_RTCSEL STM32_RTCSEL_LSI
|
#define STM32_RTCSEL STM32_RTCSEL_LSI
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,9 @@ double my_atof(const char *p);
|
||||||
void toggle_sweep(void);
|
void toggle_sweep(void);
|
||||||
void loadDefaultProps(void);
|
void loadDefaultProps(void);
|
||||||
|
|
||||||
extern int8_t sweep_enabled;
|
#define SWEEP_MODE_ENABLED 0x01
|
||||||
|
#define SWEEP_MODE_RUN_ONCE 0x02
|
||||||
|
extern volatile int8_t sweep_mode;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dsp.c
|
* dsp.c
|
||||||
|
|
@ -279,12 +281,12 @@ int marker_search(void);
|
||||||
int marker_search_left(int from);
|
int marker_search_left(int from);
|
||||||
int marker_search_right(int from);
|
int marker_search_right(int from);
|
||||||
|
|
||||||
extern uint16_t redraw_request;
|
// _request flag for update screen
|
||||||
|
|
||||||
#define REDRAW_CELLS (1<<0)
|
#define REDRAW_CELLS (1<<0)
|
||||||
#define REDRAW_FREQUENCY (1<<1)
|
#define REDRAW_FREQUENCY (1<<1)
|
||||||
#define REDRAW_CAL_STATUS (1<<2)
|
#define REDRAW_CAL_STATUS (1<<2)
|
||||||
#define REDRAW_MARKER (1<<3)
|
#define REDRAW_MARKER (1<<3)
|
||||||
|
extern volatile uint8_t redraw_request;
|
||||||
|
|
||||||
extern int16_t vbat;
|
extern int16_t vbat;
|
||||||
|
|
||||||
|
|
|
||||||
342
si5351.c
342
si5351.c
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com
|
* Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com
|
||||||
|
* Modified by DiSlord dislordlive@gmail.com
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* This is free software; you can redistribute it and/or modify
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
|
@ -21,15 +22,19 @@
|
||||||
#include "nanovna.h"
|
#include "nanovna.h"
|
||||||
#include "si5351.h"
|
#include "si5351.h"
|
||||||
|
|
||||||
#define XTALFREQ 26000000L
|
// Enable cache for SI5351 CLKX_CONTROL register, little speedup exchange
|
||||||
// MCLK (processor clock, audio codec) frequency clock
|
#define USE_CLK_CONTROL_CACHE TRUE
|
||||||
#define CLK2_FREQUENCY 8000000L
|
|
||||||
|
|
||||||
// Fixed PLL mode multiplier
|
// XTAL frequency on si5351
|
||||||
|
#define XTALFREQ 26000000U
|
||||||
|
// MCLK (processor clock if set, audio codec) frequency clock
|
||||||
|
#define CLK2_FREQUENCY 8000000U
|
||||||
|
|
||||||
|
// Fixed PLL mode multiplier (used in band 1)
|
||||||
#define PLL_N 32
|
#define PLL_N 32
|
||||||
|
|
||||||
//
|
// I2C address on bus (only 0x60 for Si5351A in 10-Pin MSOP)
|
||||||
#define SI5351_I2C_ADDR (0x60<<1)
|
#define SI5351_I2C_ADDR 0x60
|
||||||
|
|
||||||
static uint8_t current_band = 0;
|
static uint8_t current_band = 0;
|
||||||
static uint32_t current_freq = 0;
|
static uint32_t current_freq = 0;
|
||||||
|
|
@ -37,9 +42,8 @@ static uint32_t current_freq = 0;
|
||||||
static void
|
static void
|
||||||
si5351_bulk_write(const uint8_t *buf, int len)
|
si5351_bulk_write(const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
int addr = SI5351_I2C_ADDR>>1;
|
|
||||||
i2cAcquireBus(&I2CD1);
|
i2cAcquireBus(&I2CD1);
|
||||||
(void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, len, NULL, 0, 1000);
|
(void)i2cMasterTransmitTimeout(&I2CD1, SI5351_I2C_ADDR, buf, len, NULL, 0, 1000);
|
||||||
i2cReleaseBus(&I2CD1);
|
i2cReleaseBus(&I2CD1);
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
|
|
@ -64,15 +68,18 @@ const uint8_t si5351_configs[] = {
|
||||||
2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff,
|
2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff,
|
||||||
4, SI5351_REG_16_CLK0_CONTROL, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN,
|
4, SI5351_REG_16_CLK0_CONTROL, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN, SI5351_CLK_POWERDOWN,
|
||||||
2, SI5351_REG_183_CRYSTAL_LOAD, SI5351_CRYSTAL_LOAD_8PF,
|
2, SI5351_REG_183_CRYSTAL_LOAD, SI5351_CRYSTAL_LOAD_8PF,
|
||||||
|
// All of this init code run late on sweep
|
||||||
|
#if 0
|
||||||
// setup PLL (26MHz * 32 = 832MHz, 32/2-2=14)
|
// setup PLL (26MHz * 32 = 832MHz, 32/2-2=14)
|
||||||
// 9, SI5351_REG_PLL_A, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0,
|
9, SI5351_REG_PLL_A, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0,
|
||||||
// 9, SI5351_REG_PLL_B, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0,
|
9, SI5351_REG_PLL_B, /*P3*/0, 1, /*P1*/0, 14, 0, /*P3/P2*/0, 0, 0,
|
||||||
// RESET PLL
|
// RESET PLL
|
||||||
2, SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B | 0x0C, //
|
2, SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B | 0x0C, //
|
||||||
// setup multisynth (832MHz / 104 = 8MHz, 104/2-2=50)
|
// setup multisynth (832MHz / 104 = 8MHz, 104/2-2=50)
|
||||||
// 9, SI5351_REG_58_MULTISYNTH2, /*P3*/0, 1, /*P1*/0, 50, 0, /*P2|P3*/0, 0, 0,
|
9, SI5351_REG_58_MULTISYNTH2, /*P3*/0, 1, /*P1*/0, 50, 0, /*P2|P3*/0, 0, 0,
|
||||||
// 2, SI5351_REG_18_CLK2_CONTROL, SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_INPUT_MULTISYNTH_N | SI5351_CLK_INTEGER_MODE,
|
2, SI5351_REG_18_CLK2_CONTROL, SI5351_CLK_DRIVE_STRENGTH_2MA | SI5351_CLK_INPUT_MULTISYNTH_N | SI5351_CLK_INTEGER_MODE,
|
||||||
// 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0,
|
2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0,
|
||||||
|
#endif
|
||||||
0 // sentinel
|
0 // sentinel
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -106,217 +113,185 @@ static const uint8_t clkctrl[] = {
|
||||||
SI5351_REG_18_CLK2_CONTROL
|
SI5351_REG_18_CLK2_CONTROL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Reset PLL need then band changes
|
||||||
static void si5351_reset_pll(uint8_t mask)
|
static void si5351_reset_pll(uint8_t mask)
|
||||||
{
|
{
|
||||||
// Writing a 1<<5 will reset PLLA, 1<<7 reset PLLB, this is a self clearing bits.
|
// Writing a 1<<5 will reset PLLA, 1<<7 reset PLLB, this is a self clearing bits.
|
||||||
// !!! Need delay before reset PLL for apply PLL freq changes before
|
// !!! Need delay before reset PLL for apply PLL freq changes before
|
||||||
chThdSleepMicroseconds(200);
|
chThdSleepMicroseconds(200);
|
||||||
si5351_write(SI5351_REG_177_PLL_RESET, mask | 0x0C);
|
si5351_write(SI5351_REG_177_PLL_RESET, mask | 0x0C);
|
||||||
// chThdSleepMicroseconds(250);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void si5351_disable_output(void)
|
void si5351_disable_output(void)
|
||||||
{
|
{
|
||||||
// si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, (SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN));
|
si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xFF);
|
||||||
si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff);
|
|
||||||
si5351_bulk_write(disable_output, sizeof(disable_output));
|
si5351_bulk_write(disable_output, sizeof(disable_output));
|
||||||
}
|
}
|
||||||
|
|
||||||
void si5351_enable_output(void)
|
void si5351_enable_output(void)
|
||||||
{
|
{
|
||||||
si5351_reset_pll( SI5351_PLL_RESET_A | SI5351_PLL_RESET_B );
|
si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, ~(SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN));
|
||||||
// si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, ~(SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN));
|
//si5351_reset_pll(SI5351_PLL_RESET_A | SI5351_PLL_RESET_B);
|
||||||
si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0x00);
|
|
||||||
current_freq = 0;
|
current_freq = 0;
|
||||||
current_band = 0;
|
current_band = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */
|
// Set PLL freq = XTALFREQ * (mult + num/denom)
|
||||||
uint8_t mult,
|
static void si5351_setupPLL(uint8_t pllSource, /* SI5351_REG_PLL_A or SI5351_REG_PLL_B */
|
||||||
|
uint32_t mult,
|
||||||
uint32_t num,
|
uint32_t num,
|
||||||
uint32_t denom)
|
uint32_t denom)
|
||||||
{
|
{
|
||||||
uint32_t P1;
|
|
||||||
uint32_t P2;
|
|
||||||
uint32_t P3;
|
|
||||||
|
|
||||||
/* Feedback Multisynth Divider Equation
|
/* Feedback Multisynth Divider Equation
|
||||||
* where: a = mult, b = num and c = denom
|
* where: a = mult, b = num and c = denom
|
||||||
* P1 register is an 18-bit value using following formula:
|
* P1 register is an 18-bit value using following formula:
|
||||||
* P1[17:0] = 128 * mult + floor(128*(num/denom)) - 512
|
* P1[17:0] = 128 * mult + int((128*num)/denom) - 512
|
||||||
* P2 register is a 20-bit value using the following formula:
|
* P2 register is a 20-bit value using the following formula:
|
||||||
* P2[19:0] = 128 * num - denom * floor(128*(num/denom))
|
* P2[19:0] = (128 * num) % denom
|
||||||
* P3 register is a 20-bit value using the following formula:
|
* P3 register is a 20-bit value using the following formula:
|
||||||
* P3[19:0] = denom
|
* P3[19:0] = denom
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Set the main PLL config registers */
|
/* Set the main PLL config registers */
|
||||||
if (num == 0)
|
mult<<=7;
|
||||||
{
|
num<<=7;
|
||||||
/* Integer mode */
|
uint32_t P1 = mult - 512; // Integer mode
|
||||||
P1 = 128 * mult - 512;
|
uint32_t P2 = 0;
|
||||||
P2 = 0;
|
uint32_t P3 = 1;
|
||||||
P3 = 1;
|
if (num){ // Fractional mode
|
||||||
}
|
P1+= num / denom;
|
||||||
else
|
P2 = num % denom;
|
||||||
{
|
|
||||||
/* Fractional mode */
|
|
||||||
//P1 = (uint32_t)(128 * mult + floor(128 * ((float)num/(float)denom)) - 512);
|
|
||||||
P1 = 128 * mult + ((128 * num) / denom) - 512;
|
|
||||||
//P2 = (uint32_t)(128 * num - denom * floor(128 * ((float)num/(float)denom)));
|
|
||||||
P2 = 128 * num - denom * ((128 * num) / denom);
|
|
||||||
P3 = denom;
|
P3 = denom;
|
||||||
}
|
}
|
||||||
// Pll MSN(A|B) registers Datasheet
|
// Pll MSN(A|B) registers Datasheet
|
||||||
// MSN_P3[15:8]
|
|
||||||
// MSN_P3[ 7:0]
|
|
||||||
// Reserved | MSN_P1[17:16]
|
|
||||||
// MSN_P1[15:8]
|
|
||||||
// MSN_P1[ 7:0]
|
|
||||||
// MSN_P3[19:16] | MSN_P2[19:16]
|
|
||||||
// MSN_P2[15:8]
|
|
||||||
// MSN_P2[ 7:0]
|
|
||||||
uint8_t reg[9];
|
uint8_t reg[9];
|
||||||
reg[0] = pll;//reg_base[pll];
|
reg[0]= pllSource; // SI5351_REG_PLL_A or SI5351_REG_PLL_B
|
||||||
reg[1] = (P3 & 0x0000FF00) >> 8;
|
reg[1]=( P3 & 0x0FF00)>> 8; // MSN_P3[15: 8]
|
||||||
reg[2] = (P3 & 0x000000FF);
|
reg[2]=( P3 & 0x000FF); // MSN_P3[ 7: 0]
|
||||||
reg[3] = (P1 & 0x00030000) >> 16;
|
reg[3]=( P1 & 0x30000)>>16; // MSN_P1[17:16]
|
||||||
reg[4] = (P1 & 0x0000FF00) >> 8;
|
reg[4]=( P1 & 0x0FF00)>> 8; // MSN_P1[15: 8]
|
||||||
reg[5] = (P1 & 0x000000FF);
|
reg[5]=( P1 & 0x000FF); // MSN_P1[ 7: 0]
|
||||||
reg[6] = ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16);
|
reg[6]=((P3 & 0xF0000)>>12)|((P2 & 0xF0000)>>16); // MSN_P3[19:16] | MSN_P2[19:16]
|
||||||
reg[7] = (P2 & 0x0000FF00) >> 8;
|
reg[7]=( P2 & 0x0FF00)>> 8; // MSN_P2[15: 8]
|
||||||
reg[8] = (P2 & 0x000000FF);
|
reg[8]=( P2 & 0x000FF); // MSN_P2[ 7: 0]
|
||||||
si5351_bulk_write(reg, 9);
|
si5351_bulk_write(reg, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set Multisynth divider = (div + num/denom) * rdiv
|
||||||
static void
|
static void
|
||||||
si5351_setupMultisynth(uint8_t channel,
|
si5351_setupMultisynth(uint8_t channel,
|
||||||
uint8_t pllSource,
|
|
||||||
uint32_t div, // 4,6,8, 8+ ~ 900
|
uint32_t div, // 4,6,8, 8+ ~ 900
|
||||||
uint32_t num,
|
uint32_t num,
|
||||||
uint32_t denom,
|
uint32_t denom,
|
||||||
uint32_t rdiv, // SI5351_R_DIV_1~128
|
uint32_t rdiv, // SI5351_R_DIV_1~128
|
||||||
uint8_t drive_strength)
|
uint8_t chctrl) // SI5351_REG_16_CLKX_CONTROL settings
|
||||||
{
|
{
|
||||||
uint8_t dat;
|
|
||||||
|
|
||||||
uint32_t P1;
|
|
||||||
uint32_t P2;
|
|
||||||
uint32_t P3;
|
|
||||||
uint32_t div4 = 0;
|
|
||||||
|
|
||||||
/* Output Multisynth Divider Equations
|
/* Output Multisynth Divider Equations
|
||||||
* where: a = div, b = num and c = denom
|
* where: a = div, b = num and c = denom
|
||||||
* P1 register is an 18-bit value using following formula:
|
* P1 register is an 18-bit value using following formula:
|
||||||
* P1[17:0] = 128 * a + floor(128*(b/c)) - 512
|
* P1[17:0] = 128 * a + int((128*b)/c) - 512
|
||||||
* P2 register is a 20-bit value using the following formula:
|
* P2 register is a 20-bit value using the following formula:
|
||||||
* P2[19:0] = 128 * b - c * floor(128*(b/c))
|
* P2[19:0] = (128 * b) % c
|
||||||
* P3 register is a 20-bit value using the following formula:
|
* P3 register is a 20-bit value using the following formula:
|
||||||
* P3[19:0] = c
|
* P3[19:0] = c
|
||||||
*/
|
*/
|
||||||
/* Set the main PLL config registers */
|
/* Set the main PLL config registers */
|
||||||
if (div == 4) {
|
uint32_t P1 = 0;
|
||||||
div4 = SI5351_DIVBY4;
|
uint32_t P2 = 0;
|
||||||
P1 = P2 = 0;
|
uint32_t P3 = 1;
|
||||||
P3 = 1;
|
if (div == 4)
|
||||||
} else if (num == 0) {
|
rdiv|= SI5351_DIVBY4;
|
||||||
/* Integer mode */
|
else {
|
||||||
P1 = 128 * div - 512;
|
num<<=7;
|
||||||
P2 = 0;
|
div<<=7;
|
||||||
P3 = 1;
|
P1 = div - 512; // Integer mode
|
||||||
} else {
|
if (num){ // Fractional mode
|
||||||
/* Fractional mode */
|
P1+= num / denom;
|
||||||
P1 = 128 * div + ((128 * num) / denom) - 512;
|
P2 = num % denom;
|
||||||
P2 = 128 * num - denom * ((128 * num) / denom);
|
|
||||||
P3 = denom;
|
P3 = denom;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* Set the MSx config registers */
|
/* Set the MSx config registers */
|
||||||
uint8_t reg[9];
|
uint8_t reg[9];
|
||||||
reg[0] = msreg_base[channel];
|
reg[0]= msreg_base[channel]; // SI5351_REG_42_MULTISYNTH0, SI5351_REG_50_MULTISYNTH1, SI5351_REG_58_MULTISYNTH2
|
||||||
reg[1] = (P3 & 0x0000FF00) >> 8;
|
reg[1]=( P3 & 0x0FF00)>>8; // MSx_P3[15: 8]
|
||||||
reg[2] = (P3 & 0x000000FF);
|
reg[2]=( P3 & 0x000FF); // MSx_P3[ 7: 0]
|
||||||
reg[3] = ((P1 & 0x00030000) >> 16) | div4 | rdiv;
|
reg[3]=((P1 & 0x30000)>>16)| rdiv; // Rx_DIV[2:0] | MSx_DIVBY4[1:0] | MSx_P1[17:16]
|
||||||
reg[4] = (P1 & 0x0000FF00) >> 8;
|
reg[4]=( P1 & 0x0FF00)>> 8; // MSx_P1[15: 8]
|
||||||
reg[5] = (P1 & 0x000000FF);
|
reg[5]=( P1 & 0x000FF); // MSx_P1[ 7: 0]
|
||||||
reg[6] = ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16);
|
reg[6]=((P3 & 0xF0000)>>12)|((P2 & 0xF0000)>>16); // MSx_P3[19:16] | MSx_P2[19:16]
|
||||||
reg[7] = (P2 & 0x0000FF00) >> 8;
|
reg[7]=( P2 & 0x0FF00)>>8; // MSx_P2[15: 8]
|
||||||
reg[8] = (P2 & 0x000000FF);
|
reg[8]=( P2 & 0x000FF); // MSx_P2[ 7: 0]
|
||||||
si5351_bulk_write(reg, 9);
|
si5351_bulk_write(reg, 9);
|
||||||
|
|
||||||
/* Configure the clk control and enable the output */
|
/* Configure the clk control and enable the output */
|
||||||
dat = drive_strength | SI5351_CLK_INPUT_MULTISYNTH_N;
|
uint8_t dat = chctrl | SI5351_CLK_INPUT_MULTISYNTH_N;
|
||||||
if (pllSource == SI5351_REG_PLL_B)
|
|
||||||
dat |= SI5351_CLK_PLL_SELECT_B;
|
|
||||||
if (num == 0)
|
if (num == 0)
|
||||||
dat |= SI5351_CLK_INTEGER_MODE;
|
dat |= SI5351_CLK_INTEGER_MODE;
|
||||||
|
|
||||||
|
#if USE_CLK_CONTROL_CACHE == TRUE
|
||||||
|
// Use cache for this reg, not update if not change
|
||||||
|
static uint8_t clk_cache[3];
|
||||||
|
if (clk_cache[channel]!=dat){
|
||||||
si5351_write(clkctrl[channel], dat);
|
si5351_write(clkctrl[channel], dat);
|
||||||
|
clk_cache[channel]=dat;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
si5351_write(clkctrl[channel], dat);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
// Find better approximate values for n/d
|
||||||
si5351_set_frequency_fixedpll(uint8_t channel, uint32_t pllSource, uint64_t pllfreq, uint32_t freq, uint32_t rdiv, uint8_t drive_strength)
|
#define MAX_DENOMINATOR ((1 << 20) - 1)
|
||||||
{
|
static inline void fractionalSolve(uint32_t *n, uint32_t *d){
|
||||||
uint32_t denom = freq;
|
|
||||||
uint32_t div = pllfreq / denom; // range: 8 ~ 1800
|
|
||||||
uint32_t num = pllfreq % denom;
|
|
||||||
|
|
||||||
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
|
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
|
||||||
uint32_t max_denominator = (1 << 20) - 1;
|
uint32_t denom = *d;
|
||||||
if (denom > max_denominator) {
|
if (denom > MAX_DENOMINATOR) {
|
||||||
|
uint32_t num = *n;
|
||||||
uint32_t p0 = 0, q0 = 1, p1 = 1, q1 = 0;
|
uint32_t p0 = 0, q0 = 1, p1 = 1, q1 = 0;
|
||||||
while (denom != 0) {
|
while (denom != 0) {
|
||||||
uint32_t a = num / denom;
|
uint32_t a = num / denom;
|
||||||
uint32_t b = num % denom;
|
uint32_t b = num % denom;
|
||||||
uint32_t q2 = q0 + a*q1;
|
uint32_t q2 = q0 + a*q1;
|
||||||
if (q2 > max_denominator)
|
if (q2 > MAX_DENOMINATOR)
|
||||||
break;
|
|
||||||
uint32_t p2 = p0 + a*p1;
|
|
||||||
p0 = p1;
|
|
||||||
q0 = q1;
|
|
||||||
p1 = p2;
|
|
||||||
q1 = q2;
|
|
||||||
num = denom; denom = b;
|
|
||||||
}
|
|
||||||
num = p1;
|
|
||||||
denom = q1;
|
|
||||||
}
|
|
||||||
si5351_setupMultisynth(channel, pllSource, div, num, denom, rdiv, drive_strength);
|
|
||||||
}
|
|
||||||
|
|
||||||
void si5351_setupPLL_freq(uint32_t pll, uint32_t freq, uint32_t div, uint32_t mul){
|
|
||||||
uint32_t denom = XTALFREQ * mul;
|
|
||||||
uint64_t pllfreq = (uint64_t)freq * div;
|
|
||||||
uint32_t multi = pllfreq / denom;
|
|
||||||
uint32_t num = pllfreq % denom;
|
|
||||||
|
|
||||||
// cf. https://github.com/python/cpython/blob/master/Lib/fractions.py#L227
|
|
||||||
uint32_t max_denominator = (1 << 20) - 1;
|
|
||||||
if (denom > max_denominator) {
|
|
||||||
uint32_t p0 = 0, q0 = 1, p1 = 1, q1 = 0;
|
|
||||||
while (denom != 0) {
|
|
||||||
uint32_t a = num / denom;
|
|
||||||
uint32_t b = num % denom;
|
|
||||||
uint32_t q2 = q0 + a*q1;
|
|
||||||
if (q2 > max_denominator)
|
|
||||||
break;
|
break;
|
||||||
uint32_t p2 = p0 + a*p1;
|
uint32_t p2 = p0 + a*p1;
|
||||||
p0 = p1; q0 = q1; p1 = p2; q1 = q2;
|
p0 = p1; q0 = q1; p1 = p2; q1 = q2;
|
||||||
num = denom; denom = b;
|
num = denom; denom = b;
|
||||||
}
|
}
|
||||||
num = p1;
|
*n = p1;
|
||||||
denom = q1;
|
*d = q1;
|
||||||
}
|
}
|
||||||
si5351_setupPLL(pll, multi, num, denom);
|
}
|
||||||
|
|
||||||
|
// Setup Multisynth divider for get correct output freq if fixed PLL = pllfreq
|
||||||
|
static void
|
||||||
|
si5351_set_frequency_fixedpll(uint8_t channel, uint64_t pllfreq, uint32_t freq, uint32_t rdiv, uint8_t chctrl)
|
||||||
|
{
|
||||||
|
uint32_t denom = freq;
|
||||||
|
uint32_t div = pllfreq / denom; // range: 8 ~ 1800
|
||||||
|
uint32_t num = pllfreq % denom;
|
||||||
|
fractionalSolve(&num, &denom);
|
||||||
|
si5351_setupMultisynth(channel, div, num, denom, rdiv, chctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup PLL freq if Multisynth divider fixed = div (need get output = freq/mul)
|
||||||
|
static void
|
||||||
|
si5351_setupPLL_freq(uint32_t pllSource, uint32_t freq, uint32_t div, uint32_t mul){
|
||||||
|
uint32_t denom = XTALFREQ * mul;
|
||||||
|
uint64_t pllfreq = (uint64_t)freq * div;
|
||||||
|
uint32_t multi = pllfreq / denom;
|
||||||
|
uint32_t num = pllfreq % denom;
|
||||||
|
fractionalSolve(&num, &denom);
|
||||||
|
si5351_setupPLL(pllSource, multi, num, denom);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static void
|
static void
|
||||||
si5351_set_frequency_fixeddiv(uint8_t channel, uint32_t pll, uint32_t freq, uint32_t div,
|
si5351_set_frequency_fixeddiv(uint8_t channel, uint32_t pll, uint32_t freq, uint32_t div,
|
||||||
uint8_t drive_strength, uint32_t mul)
|
uint8_t chctrl, uint32_t mul)
|
||||||
{
|
{
|
||||||
si5351_setupPLL_freq(pll, freq, div, mul);
|
si5351_setupPLL_freq(pll, freq, div, mul);
|
||||||
si5351_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength);
|
si5351_setupMultisynth(channel, div, 0, 1, SI5351_R_DIV_1, chctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -332,19 +307,48 @@ si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength){
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frequency generation divide on 3 band
|
||||||
|
* Band 1
|
||||||
|
* 1~100MHz fixed PLL = XTALFREQ * PLL_N, fractional divider
|
||||||
|
* Band 2
|
||||||
|
* 100~150MHz fractional PLL = 600- 900MHz, fixed divider 'fdiv = 6'
|
||||||
|
* Band 3
|
||||||
|
* 150~300MHz fractional PLL = 600-1200MHz, fixed divider 'fdiv = 4'
|
||||||
|
*
|
||||||
|
* For FREQ_HARMONICS = 300MHz - band range is:
|
||||||
|
* +-----------------------------------------------------------------------------------------------------------------------+
|
||||||
|
* | Band 1 | Band 2 | Band 3 | Band 2 | Band 3 |
|
||||||
|
* +-----------------------------------------------------------------------------------------------------------------------+
|
||||||
|
* | x1 : x1 | x1 : x1 | x1 : x1 | x3 : x5 | x3 : x5 | x5-x7 | x7-x9 | x9-x11 |
|
||||||
|
* | 50kHz - 100MHz | 100 - 150MHz | 150 - 300MHz | 300-450MHz | 450-900MHz | 900-1500MHz | 1500-2100MHz | 2100-2700MHz |
|
||||||
|
* +-----------------------------------------------------------------------------------------------------------------------+
|
||||||
|
* | f = 50kHz-100MHz | f=100-150 | f=150-300 | f=150-300 | f=214-300 | f=233-300 |
|
||||||
|
* | of = 50kHz-100MHz |of= 60- 90 |of= 90-180 |of=128-215 |of=166-234 |of=190-246 |
|
||||||
|
* +-----------------------------------------------------------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
static inline uint8_t si5351_getBand(uint32_t freq){
|
||||||
|
if (freq < 100000000U) return 1;
|
||||||
|
if (freq < 150000000U) return 2;
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimum value is 2, freq change apply at next dsp measure, and need skip it
|
||||||
#define DELAY_NORMAL 2
|
#define DELAY_NORMAL 2
|
||||||
|
// Additional delay for band 1 (remove unstable generation at begin)
|
||||||
|
#define DELAY_BAND_1 1
|
||||||
|
// Band changes need additional delay after reset PLL
|
||||||
#define DELAY_BANDCHANGE 2
|
#define DELAY_BANDCHANGE 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Maximum supported frequency = FREQ_HARMONICS * 9U
|
||||||
* configure output as follows:
|
* configure output as follows:
|
||||||
* CLK0: frequency + offset
|
* CLK0: frequency + offset
|
||||||
* CLK1: frequency
|
* CLK1: frequency
|
||||||
* CLK2: fixed 8MHz
|
* CLK2: fixed 8MHz
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength)
|
si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength){
|
||||||
{
|
|
||||||
uint8_t band;
|
uint8_t band;
|
||||||
int delay = DELAY_NORMAL;
|
int delay = DELAY_NORMAL;
|
||||||
if (freq == current_freq)
|
if (freq == current_freq)
|
||||||
|
|
@ -369,54 +373,40 @@ si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_streng
|
||||||
}
|
}
|
||||||
else if (freq <= 500000U) {
|
else if (freq <= 500000U) {
|
||||||
rdiv = SI5351_R_DIV_64;
|
rdiv = SI5351_R_DIV_64;
|
||||||
freq *= 64;
|
freq<<= 6;
|
||||||
ofreq *= 64;
|
ofreq<<= 6;
|
||||||
} else if (freq <= 4000000U) {
|
} else if (freq <= 4000000U) {
|
||||||
rdiv = SI5351_R_DIV_8;
|
rdiv = SI5351_R_DIV_8;
|
||||||
freq *= 8;
|
freq<<= 3;
|
||||||
ofreq *= 8;
|
ofreq<<= 3;
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Band 0
|
|
||||||
* 1~100MHz fixed PLL = XTALFREQ * PLL_N, fractional divider
|
|
||||||
* Band 1
|
|
||||||
* 100~150MHz fractional PLL = 600- 900MHz, fixed divider 6
|
|
||||||
* Band 2
|
|
||||||
* 150~300MHz fractional PLL = 600-1200MHz, fixed divider 4
|
|
||||||
*/
|
|
||||||
if ((freq / mul) < 100000000U) {
|
|
||||||
band = 1;
|
|
||||||
} else if ((freq / mul) < 150000000U) {
|
|
||||||
band = 2;
|
|
||||||
fdiv = 6;
|
|
||||||
} else {
|
|
||||||
band = 3;
|
|
||||||
fdiv = 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
band = si5351_getBand(freq/mul);
|
||||||
switch (band) {
|
switch (band) {
|
||||||
case 1:
|
case 1:
|
||||||
// Setup CH0 and CH1 constant PLL freq at band change, and set CH2 freq = CLK2_FREQUENCY
|
// Setup CH0 and CH1 constant PLLA freq at band change, and set CH2 freq = CLK2_FREQUENCY
|
||||||
if (current_band != 1){
|
if (current_band != 1){
|
||||||
si5351_setupPLL(SI5351_REG_PLL_A, PLL_N, 0, 1);
|
si5351_setupPLL(SI5351_REG_PLL_A, PLL_N, 0, 1);
|
||||||
si5351_setupPLL(SI5351_REG_PLL_B, PLL_N, 0, 1);
|
si5351_set_frequency_fixedpll(2, XTALFREQ * PLL_N, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA|SI5351_CLK_PLL_SELECT_A);
|
||||||
si5351_set_frequency_fixedpll(2, SI5351_REG_PLL_B, XTALFREQ * PLL_N, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
|
|
||||||
}
|
}
|
||||||
// Calculate and set CH0 and CH1 divider
|
// Calculate and set CH0 and CH1 divider
|
||||||
si5351_set_frequency_fixedpll(0, SI5351_REG_PLL_A, XTALFREQ * PLL_N * omul, ofreq, rdiv, drive_strength);
|
si5351_set_frequency_fixedpll(0, (uint64_t)omul * XTALFREQ * PLL_N, ofreq, rdiv, drive_strength|SI5351_CLK_PLL_SELECT_A);
|
||||||
si5351_set_frequency_fixedpll(1, SI5351_REG_PLL_A, XTALFREQ * PLL_N * mul, freq, rdiv, drive_strength);
|
si5351_set_frequency_fixedpll(1, (uint64_t) mul * XTALFREQ * PLL_N, freq, rdiv, drive_strength|SI5351_CLK_PLL_SELECT_A);
|
||||||
|
delay+=DELAY_BAND_1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:// fdiv = 6
|
||||||
case 3:
|
case 3:// fdiv = 4;
|
||||||
|
fdiv = (band == 2) ? 6 : 4;
|
||||||
// Setup CH0 and CH1 constant fdiv divider at change
|
// Setup CH0 and CH1 constant fdiv divider at change
|
||||||
if (current_band != band){
|
if (current_band != band){
|
||||||
si5351_setupMultisynth(0, SI5351_REG_PLL_A, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength);
|
si5351_setupMultisynth(0, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength|SI5351_CLK_PLL_SELECT_A);
|
||||||
si5351_setupMultisynth(1, SI5351_REG_PLL_B, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength);
|
si5351_setupMultisynth(1, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength|SI5351_CLK_PLL_SELECT_B);
|
||||||
}
|
}
|
||||||
// Calculate and set CH0 and CH1 PLL freq
|
// Calculate and set CH0 and CH1 PLL freq
|
||||||
si5351_setupPLL_freq(SI5351_REG_PLL_A, ofreq, fdiv, omul);// set PLLA freq = (ofreq/omul)*fdiv
|
si5351_setupPLL_freq(SI5351_REG_PLL_A, ofreq, fdiv, omul);// set PLLA freq = (ofreq/omul)*fdiv
|
||||||
si5351_setupPLL_freq(SI5351_REG_PLL_B, freq, fdiv, mul);// set PLLB freq = ( freq/ mul)*fdiv
|
si5351_setupPLL_freq(SI5351_REG_PLL_B, freq, fdiv, mul);// set PLLB freq = ( freq/ mul)*fdiv
|
||||||
// Calculate CH2 freq = CLK2_FREQUENCY, depend from calculated before CH1 PLLB = (freq/mul)*fdiv
|
// Calculate CH2 freq = CLK2_FREQUENCY, depend from calculated before CH1 PLLB = (freq/mul)*fdiv
|
||||||
si5351_set_frequency_fixedpll(2, SI5351_REG_PLL_B, (freq/mul)*fdiv, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA);
|
si5351_set_frequency_fixedpll(2, (uint64_t)freq*fdiv, CLK2_FREQUENCY*mul, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA|SI5351_CLK_PLL_SELECT_B);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
75
si5351.h
75
si5351.h
|
|
@ -17,12 +17,39 @@
|
||||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||||
* Boston, MA 02110-1301, USA.
|
* Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
//#define SI5351_PLL_A 0
|
|
||||||
//#define SI5351_PLL_B 1
|
|
||||||
|
|
||||||
#define SI5351_MULTISYNTH_DIV_4 4
|
#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3
|
||||||
#define SI5351_MULTISYNTH_DIV_6 6
|
#define SI5351_CLK0_EN (1<<0)
|
||||||
#define SI5351_MULTISYNTH_DIV_8 8
|
#define SI5351_CLK1_EN (1<<1)
|
||||||
|
#define SI5351_CLK2_EN (1<<2)
|
||||||
|
|
||||||
|
// Reg 16-18 CLKX_CONTROL
|
||||||
|
#define SI5351_REG_16_CLK0_CONTROL 16
|
||||||
|
#define SI5351_REG_17_CLK1_CONTROL 17
|
||||||
|
#define SI5351_REG_18_CLK2_CONTROL 18
|
||||||
|
#define SI5351_CLK_POWERDOWN (1<<7)
|
||||||
|
#define SI5351_CLK_INTEGER_MODE (1<<6)
|
||||||
|
#define SI5351_CLK_PLL_SELECT_A (0<<5)
|
||||||
|
#define SI5351_CLK_PLL_SELECT_B (1<<5)
|
||||||
|
#define SI5351_CLK_INVERT (1<<4)
|
||||||
|
#define SI5351_CLK_INPUT_MASK (3<<2)
|
||||||
|
#define SI5351_CLK_INPUT_XTAL (0<<2)
|
||||||
|
#define SI5351_CLK_INPUT_CLKIN (1<<2)
|
||||||
|
#define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2)
|
||||||
|
#define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2)
|
||||||
|
#define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0)
|
||||||
|
#define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0)
|
||||||
|
#define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0)
|
||||||
|
#define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0)
|
||||||
|
#define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0)
|
||||||
|
|
||||||
|
#define SI5351_REG_PLL_A 26
|
||||||
|
#define SI5351_REG_PLL_B 34
|
||||||
|
|
||||||
|
#define SI5351_REG_42_MULTISYNTH0 42
|
||||||
|
#define SI5351_REG_50_MULTISYNTH1 50
|
||||||
|
#define SI5351_REG_58_MULTISYNTH2 58
|
||||||
|
#define SI5351_DIVBY4 (3<<2)
|
||||||
#define SI5351_R_DIV_1 (0<<4)
|
#define SI5351_R_DIV_1 (0<<4)
|
||||||
#define SI5351_R_DIV_2 (1<<4)
|
#define SI5351_R_DIV_2 (1<<4)
|
||||||
#define SI5351_R_DIV_4 (2<<4)
|
#define SI5351_R_DIV_4 (2<<4)
|
||||||
|
|
@ -31,39 +58,6 @@
|
||||||
#define SI5351_R_DIV_32 (5<<4)
|
#define SI5351_R_DIV_32 (5<<4)
|
||||||
#define SI5351_R_DIV_64 (6<<4)
|
#define SI5351_R_DIV_64 (6<<4)
|
||||||
#define SI5351_R_DIV_128 (7<<4)
|
#define SI5351_R_DIV_128 (7<<4)
|
||||||
#define SI5351_DIVBY4 (3<<2)
|
|
||||||
|
|
||||||
#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3
|
|
||||||
#define SI5351_CLK0_EN (1<<0)
|
|
||||||
#define SI5351_CLK1_EN (1<<2)
|
|
||||||
#define SI5351_CLK2_EN (1<<3)
|
|
||||||
|
|
||||||
#define SI5351_REG_16_CLK0_CONTROL 16
|
|
||||||
#define SI5351_REG_17_CLK1_CONTROL 17
|
|
||||||
#define SI5351_REG_18_CLK2_CONTROL 18
|
|
||||||
#define SI5351_REG_PLL_A 26
|
|
||||||
#define SI5351_REG_PLL_B 34
|
|
||||||
#define SI5351_REG_42_MULTISYNTH0 42
|
|
||||||
#define SI5351_REG_50_MULTISYNTH1 50
|
|
||||||
#define SI5351_REG_58_MULTISYNTH2 58
|
|
||||||
|
|
||||||
#define SI5351_CLK_POWERDOWN (1<<7)
|
|
||||||
#define SI5351_CLK_INTEGER_MODE (1<<6)
|
|
||||||
#define SI5351_CLK_PLL_SELECT_B (1<<5)
|
|
||||||
#define SI5351_CLK_INVERT (1<<4)
|
|
||||||
|
|
||||||
#define SI5351_CLK_INPUT_MASK (3<<2)
|
|
||||||
#define SI5351_CLK_INPUT_XTAL (0<<2)
|
|
||||||
#define SI5351_CLK_INPUT_CLKIN (1<<2)
|
|
||||||
#define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2)
|
|
||||||
#define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2)
|
|
||||||
|
|
||||||
#define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0)
|
|
||||||
#define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0)
|
|
||||||
#define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0)
|
|
||||||
#define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0)
|
|
||||||
#define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0)
|
|
||||||
|
|
||||||
|
|
||||||
#define SI5351_REG_177_PLL_RESET 177
|
#define SI5351_REG_177_PLL_RESET 177
|
||||||
#define SI5351_PLL_RESET_B (1<<7)
|
#define SI5351_PLL_RESET_B (1<<7)
|
||||||
|
|
@ -74,11 +68,8 @@
|
||||||
#define SI5351_CRYSTAL_LOAD_8PF (2<<6)
|
#define SI5351_CRYSTAL_LOAD_8PF (2<<6)
|
||||||
#define SI5351_CRYSTAL_LOAD_10PF (3<<6)
|
#define SI5351_CRYSTAL_LOAD_10PF (3<<6)
|
||||||
|
|
||||||
#define SI5351_CRYSTAL_FREQ_25MHZ 25000000
|
|
||||||
|
|
||||||
void si5351_init(void);
|
void si5351_init(void);
|
||||||
|
|
||||||
void si5351_disable_output(void);
|
void si5351_disable_output(void);
|
||||||
void si5351_enable_output(void);
|
void si5351_enable_output(void);
|
||||||
void si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength);
|
//void si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength);
|
||||||
int si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength);
|
int si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength);
|
||||||
|
|
|
||||||
4
ui.c
4
ui.c
|
|
@ -1358,7 +1358,7 @@ menu_item_modify_attribute(const menuitem_t *menu, int item,
|
||||||
*fg = config.menu_normal_color;
|
*fg = config.menu_normal_color;
|
||||||
}
|
}
|
||||||
} else if (menu == menu_stimulus) {
|
} else if (menu == menu_stimulus) {
|
||||||
if (item == 5 /* PAUSE */ && !sweep_enabled) {
|
if (item == 5 /* PAUSE */ && !(sweep_mode&SWEEP_MODE_ENABLED)) {
|
||||||
*bg = DEFAULT_MENU_TEXT_COLOR;
|
*bg = DEFAULT_MENU_TEXT_COLOR;
|
||||||
*fg = config.menu_normal_color;
|
*fg = config.menu_normal_color;
|
||||||
}
|
}
|
||||||
|
|
@ -2131,7 +2131,7 @@ touch_lever_mode_select(void)
|
||||||
select_lever_mode(touch_x < FREQUENCIES_XPOS2 ? LM_CENTER : LM_SPAN);
|
select_lever_mode(touch_x < FREQUENCIES_XPOS2 ? LM_CENTER : LM_SPAN);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (touch_y < 15) {
|
if (touch_y < 25) {
|
||||||
if (touch_x < FREQUENCIES_XPOS2 && get_electrical_delay() != 0.0) {
|
if (touch_x < FREQUENCIES_XPOS2 && get_electrical_delay() != 0.0) {
|
||||||
select_lever_mode(LM_EDELAY);
|
select_lever_mode(LM_EDELAY);
|
||||||
} else
|
} else
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue