diff --git a/Makefile b/Makefile index bd17844..fc18d97 100644 --- a/Makefile +++ b/Makefile @@ -64,13 +64,13 @@ endif # Stack size to be allocated to the Cortex-M process stack. This stack is # the stack used by the main() thread. ifeq ($(USE_PROCESS_STACKSIZE),) - USE_PROCESS_STACKSIZE = 0x200 + USE_PROCESS_STACKSIZE = 0x300 endif # Stack size to the allocated to the Cortex-M main/exceptions stack. This # stack is used for processing interrupts and exceptions. ifeq ($(USE_EXCEPTIONS_STACKSIZE),) - USE_EXCEPTIONS_STACKSIZE = 0x200 + USE_EXCEPTIONS_STACKSIZE = 0x100 endif # diff --git a/main.c b/main.c index 4f35b24..02ef10d 100644 --- a/main.c +++ b/main.c @@ -69,19 +69,17 @@ static void transform_domain(void); static MUTEX_DECL(mutex); -int32_t frequency_offset = 5000; -uint32_t frequency = 10000000; -int8_t drive_strength = DRIVE_STRENGTH_AUTO; -int8_t sweep_enabled = TRUE; -volatile int8_t sweep_once = FALSE; -int8_t cal_auto_interpolate = TRUE; -uint16_t redraw_request = 0; // contains REDRAW_XXX flags +// Obsolete enable/disable calibration interpolation (always on) +#define cal_auto_interpolate TRUE + +static int32_t frequency_offset = 5000; +static uint32_t frequency = 10000000; +static int8_t drive_strength = DRIVE_STRENGTH_AUTO; +volatile int8_t sweep_mode = SWEEP_MODE_ENABLED; + +volatile uint8_t redraw_request = 0; // contains REDRAW_XXX flags 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_FUNCTION(Thread1, arg) { @@ -90,11 +88,10 @@ static THD_FUNCTION(Thread1, arg) while (1) { bool completed = false; - if (sweep_enabled || sweep_once) { + if (sweep_mode&(SWEEP_MODE_ENABLED|SWEEP_MODE_RUN_ONCE)) { chMtxLock(&mutex); - // Sweep require 8367 system tick completed = sweep(true); - sweep_once = FALSE; + sweep_mode&=~SWEEP_MODE_RUN_ONCE; chMtxUnlock(&mutex); } else { si5351_disable_output(); @@ -102,10 +99,8 @@ static THD_FUNCTION(Thread1, arg) } chMtxLock(&mutex); - // Ui and render require 800 system tick ui_process(); - - if (sweep_enabled) { + if (sweep_mode&SWEEP_MODE_ENABLED) { if (vbat != -1) { adc_stop(ADC1); vbat = adc_vbat_read(ADC1); @@ -135,23 +130,10 @@ static THD_FUNCTION(Thread1, arg) } } -static inline void -pause_sweep(void) -{ - sweep_enabled = FALSE; -} - -static inline void -resume_sweep(void) -{ - sweep_enabled = TRUE; -} - -void -toggle_sweep(void) -{ - sweep_enabled = !sweep_enabled; -} +static inline void run_once_sweep(void) {sweep_mode|=SWEEP_MODE_RUN_ONCE;} +static inline void pause_sweep(void) {sweep_mode&=~SWEEP_MODE_ENABLED;} +static inline void resume_sweep(void){sweep_mode|= SWEEP_MODE_ENABLED;} +void toggle_sweep(void){sweep_mode^= SWEEP_MODE_ENABLED;} static float bessel0(float x) { @@ -316,16 +298,15 @@ const int8_t gain_table[] = { #define DELAY_GAIN_CHANGE 2 static int -adjust_gain(int newfreq) +adjust_gain(uint32_t newfreq) { - int delay = 0; int new_order = newfreq / FREQ_HARMONICS; int old_order = frequency / FREQ_HARMONICS; if (new_order != old_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) @@ -778,27 +759,23 @@ ensure_edit_config(void) #define DELAY_CHANNEL_CHANGE 2 // 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 palClearPad(GPIOC, GPIOC_LED); - systime_t time = chVTGetSystemTimeX(); - systime_t sweep_t = 0; si5351_enable_output(); - // On CW set freq once, and run - for (i = 0; i < sweep_points; i++) { // 8365 - sweep_t-= chVTGetSystemTimeX(); - int delay = set_frequency(frequencies[i]); // 1560 - sweep_t+= chVTGetSystemTimeX(); + wait_dsp(1); // Wait for get optimal timings + for (i = 0; i < sweep_points; i++) { // 5300 + delay = set_frequency(frequencies[i]); // 700 tlv320aic3204_select(0); // 60 CH0:REFLECT - wait_dsp(delay+(i==0 ? 1 :0)); // 3270 + wait_dsp(delay); // 1900 // calculate reflection coefficient (*sample_func)(measured[0][i]); // 60 tlv320aic3204_select(1); // 60 CH1:TRANSMISSION - wait_dsp(DELAY_CHANNEL_CHANGE); // 2700 + wait_dsp(DELAY_CHANNEL_CHANGE); // 1800 // calculate transmission coefficient (*sample_func)(measured[1][i]); // 60 // ======== 170 =========== @@ -813,7 +790,6 @@ bool sweep(bool break_on_operation) 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 palSetPad(GPIOC, GPIOC_LED); return true; @@ -849,11 +825,11 @@ VNA_SHELL_FUNCTION(cmd_scan) if (cal_auto_interpolate && (cal_status & CALSTAT_APPLY)) cal_interpolate(lastsaveid); - sweep_once = TRUE; + run_once_sweep(); chMtxUnlock(&mutex); // wait finishing sweep - while (sweep_once) + while (sweep_mode&SWEEP_MODE_RUN_ONCE) chThdSleepMilliseconds(10); } @@ -1294,36 +1270,21 @@ void cal_collect(int type) { ensure_edit_config(); - + int dst, src; switch (type) { - case CAL_LOAD: - cal_status |= CALSTAT_LOAD; - memcpy(cal_data[CAL_LOAD], measured[0], sizeof measured[0]); - break; - - case CAL_OPEN: - cal_status |= CALSTAT_OPEN; - 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; + case CAL_LOAD: cal_status|= CALSTAT_LOAD; dst = CAL_LOAD; src = 0; break; + case CAL_OPEN: cal_status|= CALSTAT_OPEN; dst = CAL_OPEN; src = 0; cal_status&= ~(CALSTAT_ES|CALSTAT_APPLY); break; + case CAL_SHORT: cal_status|= CALSTAT_SHORT; dst = CAL_SHORT; src = 0; cal_status&= ~(CALSTAT_ER|CALSTAT_APPLY); 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; + default: + return; } - 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 @@ -2165,24 +2126,27 @@ THD_FUNCTION(myshellThread, p) { #endif // 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 = { - // 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) -// STM32_TIMINGR_PRESC(5U) | -// STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(3U) | -// 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) + .timingr = // TIMINGR register initialization. (use I2C timing configuration tool for STM32F3xx and STM32F0xx microcontrollers (AN4235)) +#if STM32_I2C1SW == STM32_I2C1SW_HSI + // STM32_I2C1SW == STM32_I2C1SW_HSI (HSI=8MHz) + // 400kHz @ HSI 8MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual) STM32_TIMINGR_PRESC(0U) | STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(1U) | STM32_TIMINGR_SCLH(3U) | STM32_TIMINGR_SCLL(9U), -// Old values voodoo magic 400kHz @ HSI 8MHz -// STM32_TIMINGR_PRESC(0U) | -// STM32_TIMINGR_SCLDEL(3U) | STM32_TIMINGR_SDADEL(0U) | -// STM32_TIMINGR_SCLH(5U) | STM32_TIMINGR_SCLL(6U), - 0, // CR1 register initialization. - 0 // CR2 register initialization. + // Old values voodoo magic 400kHz @ HSI 8MHz + //0x00300506, +#elif STM32_I2C1SW == STM32_I2C1SW_SYSCLK + // STM32_I2C1SW == STM32_I2C1SW_SYSCLK (SYSCLK = 48MHz) + // 400kHz @ SYSCLK 48MHz (Use 26.4.10 I2C_TIMINGR register configuration examples from STM32 RM0091 Reference manual) + 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 = { diff --git a/mcuconf.h b/mcuconf.h index 3db6404..9021c85 100644 --- a/mcuconf.h +++ b/mcuconf.h @@ -58,7 +58,8 @@ #define STM32_ADCSW STM32_ADCSW_HSI14 #define STM32_USBSW STM32_USBSW_HSI48 #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_RTCSEL STM32_RTCSEL_LSI diff --git a/nanovna.h b/nanovna.h index ba87162..72753d1 100644 --- a/nanovna.h +++ b/nanovna.h @@ -86,7 +86,9 @@ double my_atof(const char *p); void toggle_sweep(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 @@ -279,12 +281,12 @@ int marker_search(void); int marker_search_left(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_FREQUENCY (1<<1) #define REDRAW_CAL_STATUS (1<<2) #define REDRAW_MARKER (1<<3) +extern volatile uint8_t redraw_request; extern int16_t vbat; diff --git a/si5351.c b/si5351.c index ace6af4..a08bfbe 100644 --- a/si5351.c +++ b/si5351.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2015, TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com + * Modified by DiSlord dislordlive@gmail.com * All rights reserved. * * This is free software; you can redistribute it and/or modify @@ -21,15 +22,19 @@ #include "nanovna.h" #include "si5351.h" -#define XTALFREQ 26000000L -// MCLK (processor clock, audio codec) frequency clock -#define CLK2_FREQUENCY 8000000L +// Enable cache for SI5351 CLKX_CONTROL register, little speedup exchange +#define USE_CLK_CONTROL_CACHE TRUE -// 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 SI5351_I2C_ADDR (0x60<<1) +// I2C address on bus (only 0x60 for Si5351A in 10-Pin MSOP) +#define SI5351_I2C_ADDR 0x60 static uint8_t current_band = 0; static uint32_t current_freq = 0; @@ -37,18 +42,17 @@ static uint32_t current_freq = 0; static void si5351_bulk_write(const uint8_t *buf, int len) { - int addr = SI5351_I2C_ADDR>>1; i2cAcquireBus(&I2CD1); - (void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, len, NULL, 0, 1000); + (void)i2cMasterTransmitTimeout(&I2CD1, SI5351_I2C_ADDR, buf, len, NULL, 0, 1000); i2cReleaseBus(&I2CD1); } #if 0 static void si5351_bulk_read(uint8_t reg, uint8_t* buf, int len) { - int addr = SI5351_I2C_ADDR>>1; - i2cAcquireBus(&I2CD1); - msg_t mr = i2cMasterTransmitTimeout(&I2CD1, addr, ®, 1, buf, len, 1000); - i2cReleaseBus(&I2CD1); + int addr = SI5351_I2C_ADDR>>1; + i2cAcquireBus(&I2CD1); + msg_t mr = i2cMasterTransmitTimeout(&I2CD1, addr, ®, 1, buf, len, 1000); + i2cReleaseBus(&I2CD1); } #endif @@ -64,15 +68,18 @@ const uint8_t si5351_configs[] = { 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xff, 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, +// All of this init code run late on sweep +#if 0 // 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_B, /*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, // RESET PLL 2, SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B | 0x0C, // // 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, -// 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, + 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_3_OUTPUT_ENABLE_CONTROL, 0, +#endif 0 // sentinel }; @@ -106,217 +113,185 @@ static const uint8_t clkctrl[] = { SI5351_REG_18_CLK2_CONTROL }; +// Reset PLL need then band changes 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. // !!! Need delay before reset PLL for apply PLL freq changes before chThdSleepMicroseconds(200); si5351_write(SI5351_REG_177_PLL_RESET, mask | 0x0C); -// chThdSleepMicroseconds(250); } 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)); } 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, 0x00); + 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); current_freq = 0; current_band = 0; } -static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */ - uint8_t mult, - uint32_t num, - uint32_t denom) +// Set PLL freq = XTALFREQ * (mult + num/denom) +static void si5351_setupPLL(uint8_t pllSource, /* SI5351_REG_PLL_A or SI5351_REG_PLL_B */ + uint32_t mult, + uint32_t num, + uint32_t denom) { - uint32_t P1; - uint32_t P2; - uint32_t P3; - /* Feedback Multisynth Divider Equation * where: a = mult, b = num and c = denom * 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[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[19:0] = denom */ - /* Set the main PLL config registers */ - if (num == 0) - { - /* Integer mode */ - P1 = 128 * mult - 512; - P2 = 0; - P3 = 1; - } - else - { - /* 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); + mult<<=7; + num<<=7; + uint32_t P1 = mult - 512; // Integer mode + uint32_t P2 = 0; + uint32_t P3 = 1; + if (num){ // Fractional mode + P1+= num / denom; + P2 = num % denom; P3 = denom; } -// 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] + // Pll MSN(A|B) registers Datasheet uint8_t reg[9]; - reg[0] = pll;//reg_base[pll]; - reg[1] = (P3 & 0x0000FF00) >> 8; - reg[2] = (P3 & 0x000000FF); - reg[3] = (P1 & 0x00030000) >> 16; - reg[4] = (P1 & 0x0000FF00) >> 8; - reg[5] = (P1 & 0x000000FF); - reg[6] = ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16); - reg[7] = (P2 & 0x0000FF00) >> 8; - reg[8] = (P2 & 0x000000FF); + reg[0]= pllSource; // SI5351_REG_PLL_A or SI5351_REG_PLL_B + reg[1]=( P3 & 0x0FF00)>> 8; // MSN_P3[15: 8] + reg[2]=( P3 & 0x000FF); // MSN_P3[ 7: 0] + reg[3]=( P1 & 0x30000)>>16; // MSN_P1[17:16] + reg[4]=( P1 & 0x0FF00)>> 8; // MSN_P1[15: 8] + reg[5]=( P1 & 0x000FF); // MSN_P1[ 7: 0] + reg[6]=((P3 & 0xF0000)>>12)|((P2 & 0xF0000)>>16); // MSN_P3[19:16] | MSN_P2[19:16] + reg[7]=( P2 & 0x0FF00)>> 8; // MSN_P2[15: 8] + reg[8]=( P2 & 0x000FF); // MSN_P2[ 7: 0] si5351_bulk_write(reg, 9); } - +// Set Multisynth divider = (div + num/denom) * rdiv static void -si5351_setupMultisynth(uint8_t channel, - uint8_t pllSource, - uint32_t div, // 4,6,8, 8+ ~ 900 - uint32_t num, - uint32_t denom, - uint32_t rdiv, // SI5351_R_DIV_1~128 - uint8_t drive_strength) +si5351_setupMultisynth(uint8_t channel, + uint32_t div, // 4,6,8, 8+ ~ 900 + uint32_t num, + uint32_t denom, + uint32_t rdiv, // SI5351_R_DIV_1~128 + 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 * where: a = div, b = num and c = denom * 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[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[19:0] = c + * P3[19:0] = c */ /* Set the main PLL config registers */ - if (div == 4) { - div4 = SI5351_DIVBY4; - P1 = P2 = 0; - P3 = 1; - } else if (num == 0) { - /* Integer mode */ - P1 = 128 * div - 512; - P2 = 0; - P3 = 1; - } else { - /* Fractional mode */ - P1 = 128 * div + ((128 * num) / denom) - 512; - P2 = 128 * num - denom * ((128 * num) / denom); - P3 = denom; + uint32_t P1 = 0; + uint32_t P2 = 0; + uint32_t P3 = 1; + if (div == 4) + rdiv|= SI5351_DIVBY4; + else { + num<<=7; + div<<=7; + P1 = div - 512; // Integer mode + if (num){ // Fractional mode + P1+= num / denom; + P2 = num % denom; + P3 = denom; + } } - /* Set the MSx config registers */ uint8_t reg[9]; - reg[0] = msreg_base[channel]; - reg[1] = (P3 & 0x0000FF00) >> 8; - reg[2] = (P3 & 0x000000FF); - reg[3] = ((P1 & 0x00030000) >> 16) | div4 | rdiv; - reg[4] = (P1 & 0x0000FF00) >> 8; - reg[5] = (P1 & 0x000000FF); - reg[6] = ((P3 & 0x000F0000) >> 12) | ((P2 & 0x000F0000) >> 16); - reg[7] = (P2 & 0x0000FF00) >> 8; - reg[8] = (P2 & 0x000000FF); + reg[0]= msreg_base[channel]; // SI5351_REG_42_MULTISYNTH0, SI5351_REG_50_MULTISYNTH1, SI5351_REG_58_MULTISYNTH2 + reg[1]=( P3 & 0x0FF00)>>8; // MSx_P3[15: 8] + reg[2]=( P3 & 0x000FF); // MSx_P3[ 7: 0] + reg[3]=((P1 & 0x30000)>>16)| rdiv; // Rx_DIV[2:0] | MSx_DIVBY4[1:0] | MSx_P1[17:16] + reg[4]=( P1 & 0x0FF00)>> 8; // MSx_P1[15: 8] + reg[5]=( P1 & 0x000FF); // MSx_P1[ 7: 0] + reg[6]=((P3 & 0xF0000)>>12)|((P2 & 0xF0000)>>16); // MSx_P3[19:16] | MSx_P2[19:16] + reg[7]=( P2 & 0x0FF00)>>8; // MSx_P2[15: 8] + reg[8]=( P2 & 0x000FF); // MSx_P2[ 7: 0] si5351_bulk_write(reg, 9); /* Configure the clk control and enable the output */ - dat = drive_strength | SI5351_CLK_INPUT_MULTISYNTH_N; - if (pllSource == SI5351_REG_PLL_B) - dat |= SI5351_CLK_PLL_SELECT_B; + uint8_t dat = chctrl | SI5351_CLK_INPUT_MULTISYNTH_N; if (num == 0) 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); + clk_cache[channel]=dat; + } +#else si5351_write(clkctrl[channel], dat); +#endif } -static void -si5351_set_frequency_fixedpll(uint8_t channel, uint32_t pllSource, uint64_t pllfreq, uint32_t freq, uint32_t rdiv, uint8_t drive_strength) -{ - 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 - 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; - 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; - +// Find better approximate values for n/d +#define MAX_DENOMINATOR ((1 << 20) - 1) +static inline void fractionalSolve(uint32_t *n, uint32_t *d){ // 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 denom = *d; + if (denom > MAX_DENOMINATOR) { + uint32_t num = *n; 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) + uint32_t a = num / denom; + uint32_t b = num % denom; + uint32_t q2 = q0 + a*q1; + 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; + *n = p1; + *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 static void 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_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength); + si5351_setupMultisynth(channel, div, 0, 1, SI5351_R_DIV_1, chctrl); } void @@ -332,91 +307,106 @@ si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength){ } #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 +// 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 /* + * Maximum supported frequency = FREQ_HARMONICS * 9U * configure output as follows: * CLK0: frequency + offset * CLK1: frequency * CLK2: fixed 8MHz */ - 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; int delay = DELAY_NORMAL; if (freq == current_freq) - return delay; + return delay; uint32_t ofreq = freq + offset; uint32_t mul = 1, omul = 1; uint32_t rdiv = SI5351_R_DIV_1; uint32_t fdiv; current_freq = freq; if (freq >= FREQ_HARMONICS * 7U) { - mul = 9; + mul = 9; omul = 11; } else if (freq >= FREQ_HARMONICS * 5U) { - mul = 7; + mul = 7; omul = 9; } else if (freq >= FREQ_HARMONICS * 3U) { - mul = 5; + mul = 5; omul = 7; } else if (freq >= FREQ_HARMONICS) { - mul = 3; + mul = 3; omul = 5; } else if (freq <= 500000U) { rdiv = SI5351_R_DIV_64; - freq *= 64; - ofreq *= 64; + freq<<= 6; + ofreq<<= 6; } else if (freq <= 4000000U) { rdiv = SI5351_R_DIV_8; - freq *= 8; - ofreq *= 8; - } - /* - * 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; + freq<<= 3; + ofreq<<= 3; } + + band = si5351_getBand(freq/mul); switch (band) { 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){ 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, SI5351_REG_PLL_B, XTALFREQ * PLL_N, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA); + si5351_set_frequency_fixedpll(2, XTALFREQ * PLL_N, CLK2_FREQUENCY, SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA|SI5351_CLK_PLL_SELECT_A); } // 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(1, SI5351_REG_PLL_A, XTALFREQ * PLL_N * mul, freq, 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, (uint64_t) mul * XTALFREQ * PLL_N, freq, rdiv, drive_strength|SI5351_CLK_PLL_SELECT_A); + delay+=DELAY_BAND_1; break; - case 2: - case 3: + case 2:// fdiv = 6 + case 3:// fdiv = 4; + fdiv = (band == 2) ? 6 : 4; // Setup CH0 and CH1 constant fdiv divider at change if (current_band != band){ - si5351_setupMultisynth(0, SI5351_REG_PLL_A, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength); - si5351_setupMultisynth(1, SI5351_REG_PLL_B, 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, fdiv, 0, 1, SI5351_R_DIV_1, drive_strength|SI5351_CLK_PLL_SELECT_B); } // 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_B, freq, fdiv, mul);// set PLLB freq = ( 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; } diff --git a/si5351.h b/si5351.h index 4572dc8..6b5bdf5 100644 --- a/si5351.h +++ b/si5351.h @@ -17,12 +17,39 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -//#define SI5351_PLL_A 0 -//#define SI5351_PLL_B 1 -#define SI5351_MULTISYNTH_DIV_4 4 -#define SI5351_MULTISYNTH_DIV_6 6 -#define SI5351_MULTISYNTH_DIV_8 8 +#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3 +#define SI5351_CLK0_EN (1<<0) +#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_2 (1<<4) #define SI5351_R_DIV_4 (2<<4) @@ -31,39 +58,6 @@ #define SI5351_R_DIV_32 (5<<4) #define SI5351_R_DIV_64 (6<<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_PLL_RESET_B (1<<7) @@ -74,11 +68,8 @@ #define SI5351_CRYSTAL_LOAD_8PF (2<<6) #define SI5351_CRYSTAL_LOAD_10PF (3<<6) -#define SI5351_CRYSTAL_FREQ_25MHZ 25000000 - void si5351_init(void); - void si5351_disable_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); diff --git a/ui.c b/ui.c index 562d0dd..b73ef29 100644 --- a/ui.c +++ b/ui.c @@ -1358,7 +1358,7 @@ menu_item_modify_attribute(const menuitem_t *menu, int item, *fg = config.menu_normal_color; } } 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; *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); return TRUE; } - if (touch_y < 15) { + if (touch_y < 25) { if (touch_x < FREQUENCIES_XPOS2 && get_electrical_delay() != 0.0) { select_lever_mode(LM_EDELAY); } else