From b77e1d66802e0b7f9d95e567b11906493435c163 Mon Sep 17 00:00:00 2001 From: DiSlord Date: Thu, 5 Mar 2020 22:36:44 +0300 Subject: [PATCH 1/7] Big work around si5351 generator Improve sweep speed about 60% Stop generation on pause sweep Remove all hack for si5351 Reduce code size Fix integer overflow on big freq values Additional Change I2C Others: move marker_tracking variable to ui config move some definition to correct place reduce tlv320aic3204 code size Speedup marker move from lever (BUTTON_REPEAT_TICKS = 625) Need test stability --- main.c | 75 ++++++---- nanovna.h | 56 ++++---- plot.c | 1 - si5351.c | 353 ++++++++++++++++++++++++------------------------ si5351.h | 19 ++- tlv320aic3204.c | 159 ++++++++++------------ ui.c | 80 +++++------ 7 files changed, 372 insertions(+), 371 deletions(-) diff --git a/main.c b/main.c index bb5580b..4f35b24 100644 --- a/main.c +++ b/main.c @@ -69,10 +69,6 @@ static void transform_domain(void); static MUTEX_DECL(mutex); -#define DRIVE_STRENGTH_AUTO (-1) -#define FREQ_HARMONICS (config.harmonic_freq_threshold) -#define IS_HARMONIC_MODE(f) ((f) > FREQ_HARMONICS) - int32_t frequency_offset = 5000; uint32_t frequency = 10000000; int8_t drive_strength = DRIVE_STRENGTH_AUTO; @@ -101,6 +97,7 @@ static THD_FUNCTION(Thread1, arg) sweep_once = FALSE; chMtxUnlock(&mutex); } else { + si5351_disable_output(); __WFI(); } @@ -123,7 +120,7 @@ static THD_FUNCTION(Thread1, arg) plot_into_index(measured); redraw_request |= REDRAW_CELLS; - if (marker_tracking) { + if (uistat.marker_tracking) { int i = marker_search(); if (i != -1 && active_marker != -1) { markers[active_marker].index = i; @@ -316,7 +313,7 @@ const int8_t gain_table[] = { 95 // 2400MHz ~ }; -#define DELAY_GAIN_CHANGE 10 +#define DELAY_GAIN_CHANGE 2 static int adjust_gain(int newfreq) @@ -474,7 +471,7 @@ VNA_SHELL_FUNCTION(cmd_power) #ifdef ENABLE_TIME_COMMAND #if HAL_USE_RTC == FALSE -#error "Error cmd_time require ENABLE_TIME_COMMAND = TRUE in halconf.h" +#error "Error cmd_time require define HAL_USE_RTC = TRUE in halconf.h" #endif VNA_SHELL_FUNCTION(cmd_time) { @@ -745,7 +742,8 @@ static const marker_t def_markers[MARKERS_MAX] = { // Load propeties default settings void loadDefaultProps(void){ - current_props.magic = CONFIG_MAGIC; +//Magic add on caldata_save +//current_props.magic = CONFIG_MAGIC; current_props._frequency0 = 50000; // start = 50kHz current_props._frequency1 = 900000000; // end = 900MHz current_props._sweep_points = POINTS_COUNT; @@ -761,6 +759,8 @@ void loadDefaultProps(void){ current_props._active_marker = 0; current_props._domain_mode = 0; current_props._marker_smith_format = MS_RLC; +//Checksum add on caldata_save +//current_props.checksum = 0; } void @@ -775,7 +775,7 @@ ensure_edit_config(void) cal_status = 0; } -#define DELAY_CHANNEL_CHANGE 3 +#define DELAY_CHANNEL_CHANGE 2 // main loop for measurement bool sweep(bool break_on_operation) @@ -783,11 +783,17 @@ bool sweep(bool break_on_operation) int i; // 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(); tlv320aic3204_select(0); // 60 CH0:REFLECT - wait_dsp(delay); // 3270 + wait_dsp(delay+(i==0 ? 1 :0)); // 3270 // calculate reflection coefficient (*sample_func)(measured[0][i]); // 60 @@ -803,9 +809,11 @@ bool sweep(bool break_on_operation) apply_edelay_at(i); // back to toplevel to handle ui operation - if (operation_requested && break_on_operation) + if (operation_requested && 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; @@ -912,7 +920,7 @@ update_frequencies(void) } set_frequencies(start, stop, sweep_points); - operation_requested = OP_FREQCHANGE; +// operation_requested|= OP_FREQCHANGE; update_marker_index(); @@ -1430,6 +1438,7 @@ VNA_SHELL_FUNCTION(cmd_cal) shell_printf("\r\n"); return; } + redraw_request|=REDRAW_CAL_STATUS; // 0 1 2 3 4 5 6 7 8 9 10 static const char cmd_cal_list[] = "load|open|short|thru|isoln|done|on|off|reset|data|in"; switch (getStringIndex(argv[0], cmd_cal_list)){ @@ -1439,9 +1448,9 @@ VNA_SHELL_FUNCTION(cmd_cal) case 3:cal_collect(CAL_THRU ); return; case 4:cal_collect(CAL_ISOLN); return; case 5:cal_done(); return; - case 6:cal_status|= CALSTAT_APPLY;redraw_request|=REDRAW_CAL_STATUS; return; - case 7:cal_status&=~CALSTAT_APPLY;redraw_request|=REDRAW_CAL_STATUS; return; - case 8:cal_status = 0; redraw_request|=REDRAW_CAL_STATUS; return; + case 6:cal_status|= CALSTAT_APPLY;return; + case 7:cal_status&=~CALSTAT_APPLY;return; + case 8:cal_status = 0; return; case 9: shell_printf("%f %f\r\n", cal_data[CAL_LOAD ][0][0], cal_data[CAL_LOAD ][0][1]); shell_printf("%f %f\r\n", cal_data[CAL_OPEN ][0][0], cal_data[CAL_OPEN ][0][1]); @@ -1451,11 +1460,9 @@ VNA_SHELL_FUNCTION(cmd_cal) return; case 10: cal_interpolate((argc > 1) ? my_atoi(argv[1]) : 0); - redraw_request|=REDRAW_CAL_STATUS; return; default:break; } - shell_printf("usage: cal [%s]\r\n", cmd_cal_list); } @@ -1687,14 +1694,13 @@ VNA_SHELL_FUNCTION(cmd_marker) } return; } + redraw_request |= REDRAW_MARKER; if (strcmp(argv[0], "off") == 0) { active_marker = -1; for (t = 0; t < MARKERS_MAX; t++) markers[t].enabled = FALSE; - redraw_request |= REDRAW_MARKER; return; } - t = my_atoi(argv[0])-1; if (t < 0 || t >= MARKERS_MAX) goto usage; @@ -1703,13 +1709,12 @@ VNA_SHELL_FUNCTION(cmd_marker) active_marker = t; // select active marker markers[t].enabled = TRUE; - redraw_request |= REDRAW_MARKER; return; } static const char cmd_marker_list[] = "on|off"; switch (getStringIndex(argv[1], cmd_marker_list)){ - case 0: markers[t].enabled = TRUE; active_marker = t; redraw_request |= REDRAW_MARKER; return; - case 1: markers[t].enabled =FALSE; if (active_marker == t) active_marker = -1; redraw_request|=REDRAW_MARKER; return; + case 0: markers[t].enabled = TRUE; active_marker = t; return; + case 1: markers[t].enabled =FALSE; if (active_marker == t) active_marker = -1; return; default: // select active marker and move to index markers[t].enabled = TRUE; @@ -1717,7 +1722,6 @@ VNA_SHELL_FUNCTION(cmd_marker) markers[t].index = index; markers[t].frequency = frequencies[index]; active_marker = t; - redraw_request |= REDRAW_MARKER; return; } usage: @@ -1923,8 +1927,8 @@ VNA_SHELL_FUNCTION(cmd_stat) //shell_printf("interval cycle: %d\r\n", stat.interval_cycles); //shell_printf("busy cycle: %d\r\n", stat.busy_cycles); //shell_printf("load: %d\r\n", stat.busy_cycles * 100 / stat.interval_cycles); - extern int awd_count; - shell_printf("awd: %d\r\n", awd_count); +// extern int awd_count; +// shell_printf("awd: %d\r\n", awd_count); } @@ -2160,10 +2164,25 @@ 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 = { - 0x00300506, //voodoo magic 400kHz @ HSI 8MHz - 0, - 0 + // 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) + 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. }; static DACConfig dac1cfg1 = { diff --git a/nanovna.h b/nanovna.h index 524b2aa..ba87162 100644 --- a/nanovna.h +++ b/nanovna.h @@ -88,30 +88,6 @@ void loadDefaultProps(void); extern int8_t sweep_enabled; -/* - * flash.c - */ -#define SAVEAREA_MAX 5 -// Begin addr 0x08018000 -#define SAVE_CONFIG_AREA_SIZE 0x00008000 -// config save area -#define SAVE_CONFIG_ADDR 0x08018000 -// properties_t save area -#define SAVE_PROP_CONFIG_0_ADDR 0x08018800 -#define SAVE_PROP_CONFIG_1_ADDR 0x0801a000 -#define SAVE_PROP_CONFIG_2_ADDR 0x0801b800 -#define SAVE_PROP_CONFIG_3_ADDR 0x0801d000 -#define SAVE_PROP_CONFIG_4_ADDR 0x0801e800 - -/* - * ui.c - */ -extern void ui_init(void); -extern void ui_process(void); - -enum opreq { OP_NONE = 0, OP_LEVER, OP_TOUCH, OP_FREQCHANGE }; -extern uint8_t operation_requested; - /* * dsp.c */ @@ -134,9 +110,6 @@ void calculate_gamma(float *gamma); void fetch_amplitude(float *gamma); void fetch_amplitude_ref(float *gamma); -int si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength); - - /* * tlv320aic3204.c */ @@ -250,6 +223,10 @@ typedef struct config { extern config_t config; +#define DRIVE_STRENGTH_AUTO (-1) +#define FREQ_HARMONICS (config.harmonic_freq_threshold) +#define IS_HARMONIC_MODE(f) ((f) > FREQ_HARMONICS) + //extern trace_t trace[TRACES_MAX]; void set_trace_type(int t, int type); @@ -366,6 +343,16 @@ void show_logo(void); * flash.c */ #define SAVEAREA_MAX 5 +// Begin addr 0x08018000 +#define SAVE_CONFIG_AREA_SIZE 0x00008000 +// config save area +#define SAVE_CONFIG_ADDR 0x08018000 +// properties_t save area +#define SAVE_PROP_CONFIG_0_ADDR 0x08018800 +#define SAVE_PROP_CONFIG_1_ADDR 0x0801a000 +#define SAVE_PROP_CONFIG_2_ADDR 0x0801b800 +#define SAVE_PROP_CONFIG_3_ADDR 0x0801d000 +#define SAVE_PROP_CONFIG_4_ADDR 0x0801e800 typedef struct properties { uint32_t magic; @@ -432,6 +419,15 @@ void clear_all_config_prop_data(void); /* * ui.c */ +extern void ui_init(void); +extern void ui_process(void); + +// Irq operation process set +#define OP_NONE 0x00 +#define OP_LEVER 0x01 +#define OP_TOUCH 0x02 +//#define OP_FREQCHANGE 0x04 +extern volatile uint8_t operation_requested; // lever_mode enum lever_mode { @@ -448,13 +444,13 @@ typedef struct uistat { int8_t digit_mode; int8_t current_trace; /* 0..3 */ uint32_t value; // for editing at numeric input area - uint32_t previous_value; +// uint32_t previous_value; uint8_t lever_mode; - bool marker_delta; + uint8_t marker_delta; + uint8_t marker_tracking; } uistat_t; extern uistat_t uistat; - void ui_init(void); void ui_show(void); void ui_hide(void); diff --git a/plot.c b/plot.c index 70f5e31..d1762f0 100644 --- a/plot.c +++ b/plot.c @@ -1056,7 +1056,6 @@ static int greater(int x, int y) { return x > y; } static int lesser(int x, int y) { return x < y; } static int (*compare)(int x, int y) = lesser; -int8_t marker_tracking = false; int marker_search(void) diff --git a/si5351.c b/si5351.c index 56ba597..ace6af4 100644 --- a/si5351.c +++ b/si5351.c @@ -21,17 +21,18 @@ #include "nanovna.h" #include "si5351.h" +#define XTALFREQ 26000000L +// MCLK (processor clock, audio codec) frequency clock +#define CLK2_FREQUENCY 8000000L + +// Fixed PLL mode multiplier +#define PLL_N 32 + +// #define SI5351_I2C_ADDR (0x60<<1) -static void -si5351_write(uint8_t reg, uint8_t dat) -{ - int addr = SI5351_I2C_ADDR>>1; - uint8_t buf[] = { reg, dat }; - i2cAcquireBus(&I2CD1); - (void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, 2, NULL, 0, 1000); - i2cReleaseBus(&I2CD1); -} +static uint8_t current_band = 0; +static uint32_t current_freq = 0; static void si5351_bulk_write(const uint8_t *buf, int len) @@ -41,6 +42,22 @@ si5351_bulk_write(const uint8_t *buf, int len) (void)i2cMasterTransmitTimeout(&I2CD1, 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); +} +#endif + +static inline void +si5351_write(uint8_t reg, uint8_t dat) +{ + uint8_t buf[] = { reg, dat }; + si5351_bulk_write(buf, 2); +} // register addr, length, data, ... const uint8_t si5351_configs[] = { @@ -48,13 +65,14 @@ const uint8_t si5351_configs[] = { 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, // setup PLL (26MHz * 32 = 832MHz, 32/2-2=14) - 9, SI5351_REG_26_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, // RESET PLL - 2, SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B, + 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, 0 // sentinel }; @@ -71,26 +89,46 @@ si5351_init(void) static const uint8_t disable_output[] = { SI5351_REG_16_CLK0_CONTROL, - SI5351_CLK_POWERDOWN, - SI5351_CLK_POWERDOWN, - SI5351_CLK_POWERDOWN + SI5351_CLK_POWERDOWN, // CLK 0 + SI5351_CLK_POWERDOWN, // CLK 1 + SI5351_CLK_POWERDOWN // CLK 2 }; +/* Get the appropriate starting point for the PLL registers */ +static const uint8_t msreg_base[] = { + SI5351_REG_42_MULTISYNTH0, + SI5351_REG_50_MULTISYNTH1, + SI5351_REG_58_MULTISYNTH2, +}; +static const uint8_t clkctrl[] = { + SI5351_REG_16_CLK0_CONTROL, + SI5351_REG_17_CLK1_CONTROL, + SI5351_REG_18_CLK2_CONTROL +}; + +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_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); -} - -static void si5351_reset_pll(void) -{ - //si5351_write(SI5351_REG_177_PLL_RESET, SI5351_PLL_RESET_A | SI5351_PLL_RESET_B); - si5351_write(SI5351_REG_177_PLL_RESET, 0xAC); + current_freq = 0; + current_band = 0; } static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */ @@ -98,11 +136,6 @@ static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */ uint32_t num, uint32_t denom) { - /* Get the appropriate starting point for the PLL registers */ - static const uint8_t pllreg_base[] = { - SI5351_REG_26_PLL_A, - SI5351_REG_34_PLL_B - }; uint32_t P1; uint32_t P2; uint32_t P3; @@ -134,10 +167,17 @@ static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */ P2 = 128 * num - denom * ((128 * num) / denom); P3 = denom; } - - /* The datasheet is a nightmare of typos and inconsistencies here! */ +// 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]; - reg[0] = pllreg_base[pll]; + reg[0] = pll;//reg_base[pll]; reg[1] = (P3 & 0x0000FF00) >> 8; reg[2] = (P3 & 0x000000FF); reg[3] = (P1 & 0x00030000) >> 16; @@ -149,8 +189,9 @@ static void si5351_setupPLL(uint8_t pll, /* SI5351_PLL_A or SI5351_PLL_B */ si5351_bulk_write(reg, 9); } + static void -si5351_setupMultisynth(uint8_t output, +si5351_setupMultisynth(uint8_t channel, uint8_t pllSource, uint32_t div, // 4,6,8, 8+ ~ 900 uint32_t num, @@ -158,17 +199,6 @@ si5351_setupMultisynth(uint8_t output, uint32_t rdiv, // SI5351_R_DIV_1~128 uint8_t drive_strength) { - /* Get the appropriate starting point for the PLL registers */ - static const uint8_t msreg_base[] = { - SI5351_REG_42_MULTISYNTH0, - SI5351_REG_50_MULTISYNTH1, - SI5351_REG_58_MULTISYNTH2, - }; - static const uint8_t clkctrl[] = { - SI5351_REG_16_CLK0_CONTROL, - SI5351_REG_17_CLK1_CONTROL, - SI5351_REG_18_CLK2_CONTROL - }; uint8_t dat; uint32_t P1; @@ -204,7 +234,7 @@ si5351_setupMultisynth(uint8_t output, /* Set the MSx config registers */ uint8_t reg[9]; - reg[0] = msreg_base[output]; + reg[0] = msreg_base[channel]; reg[1] = (P3 & 0x0000FF00) >> 8; reg[2] = (P3 & 0x000000FF); reg[3] = ((P1 & 0x00030000) >> 16) | div4 | rdiv; @@ -217,86 +247,80 @@ si5351_setupMultisynth(uint8_t output, /* Configure the clk control and enable the output */ dat = drive_strength | SI5351_CLK_INPUT_MULTISYNTH_N; - if (pllSource == SI5351_PLL_B) + if (pllSource == SI5351_REG_PLL_B) dat |= SI5351_CLK_PLL_SELECT_B; if (num == 0) dat |= SI5351_CLK_INTEGER_MODE; - si5351_write(clkctrl[output], dat); + si5351_write(clkctrl[channel], dat); } -#define XTALFREQ 26000000L -#define PLL_N 32 -#define PLLFREQ (XTALFREQ * PLL_N) - static void -si5351_set_frequency_fixedpll(int channel, int pll, uint32_t pllfreq, uint32_t freq, - int rdiv, uint8_t drive_strength, int mul) +si5351_set_frequency_fixedpll(uint8_t channel, uint32_t pllSource, uint64_t pllfreq, uint32_t freq, uint32_t rdiv, uint8_t drive_strength) { - int denom = freq; - int div = (pllfreq * mul) / denom; // range: 8 ~ 1800 - int num = (pllfreq * mul) - denom * div; + 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 - int max_denominator = (1 << 20) - 1; + uint32_t max_denominator = (1 << 20) - 1; if (denom > max_denominator) { - int p0 = 0, q0 = 1, p1 = 1, q1 = 0; + uint32_t p0 = 0, q0 = 1, p1 = 1, q1 = 0; while (denom != 0) { - int a = num / denom; - int q2 = q0 + a*q1; + uint32_t a = num / denom; + uint32_t b = num % denom; + uint32_t q2 = q0 + a*q1; if (q2 > max_denominator) break; - int p2 = p0 + a*p1; - p0 = p1; q0 = q1; p1 = p2; q1 = q2; - int new_denom = num - a * denom; - num = denom; denom = new_denom; + 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, pll, div, num, denom, rdiv, drive_strength); + si5351_setupMultisynth(channel, pllSource, div, num, denom, rdiv, drive_strength); } -static void -si5351_set_frequency_fixeddiv(int channel, int pll, uint32_t freq, int div, - uint8_t drive_strength, int mul) -{ - int denom = XTALFREQ * mul; - int64_t pllfreq = (int64_t)freq * div; - int multi = pllfreq / denom; - int num = pllfreq - denom * multi; +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 - int max_denominator = (1 << 20) - 1; - if (denom > max_denominator) { - int p0 = 0, q0 = 1, p1 = 1, q1 = 0; - while (denom != 0) { - int a = num / denom; - int q2 = q0 + a*q1; - if (q2 > max_denominator) - break; - int p2 = p0 + a*p1; - p0 = p1; q0 = q1; p1 = p2; q1 = q2; - int new_denom = num - a * denom; - num = denom; denom = new_denom; - } - num = p1; - denom = q1; + // 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; } - - si5351_setupPLL(pll, multi, num, denom); - si5351_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength); + num = p1; + denom = q1; + } + si5351_setupPLL(pll, multi, num, denom); } -/* - * 1~100MHz fixed PLL 900MHz, fractional divider - * 100~150MHz fractional PLL 600-900MHz, fixed divider 6 - * 150~200MHz fractional PLL 600-900MHz, fixed divider 4 - */ #if 0 -void -si5351_set_frequency(int channel, int freq, uint8_t drive_strength) +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) { + si5351_setupPLL_freq(pll, freq, div, mul); + si5351_setupMultisynth(channel, pll, div, 0, 1, SI5351_R_DIV_1, drive_strength); +} + +void +si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength){ if (freq <= 100000000) { si5351_setupPLL(SI5351_PLL_B, 32, 0, 1); si5351_set_frequency_fixedpll(channel, SI5351_PLL_B, PLLFREQ, freq, SI5351_R_DIV_1, drive_strength, 1); @@ -308,11 +332,8 @@ si5351_set_frequency(int channel, int freq, uint8_t drive_strength) } #endif -int current_band = -1; - -#define DELAY_NORMAL 3 -#define DELAY_BANDCHANGE 1 -#define DELAY_LOWBAND 1 +#define DELAY_NORMAL 2 +#define DELAY_BANDCHANGE 2 /* * configure output as follows: @@ -320,105 +341,89 @@ int current_band = -1; * CLK1: frequency * CLK2: fixed 8MHz */ -#define CLK2_FREQUENCY 8000000L + int si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_strength) { - int band; + uint8_t band; int delay = DELAY_NORMAL; + if (freq == current_freq) + return delay; uint32_t ofreq = freq + offset; uint32_t mul = 1, omul = 1; uint32_t rdiv = SI5351_R_DIV_1; - if (freq >= config.harmonic_freq_threshold * 7U) { + uint32_t fdiv; + current_freq = freq; + if (freq >= FREQ_HARMONICS * 7U) { mul = 9; omul = 11; - } else if (freq >= config.harmonic_freq_threshold * 5U) { + } else if (freq >= FREQ_HARMONICS * 5U) { mul = 7; omul = 9; - } else if (freq >= config.harmonic_freq_threshold * 3U) { + } else if (freq >= FREQ_HARMONICS * 3U) { mul = 5; omul = 7; - } else if (freq >= config.harmonic_freq_threshold) { + } else if (freq >= FREQ_HARMONICS) { mul = 3; omul = 5; } - if ((freq / mul) < 100000000U) { - band = 0; - } else if ((freq / mul) < 150000000U) { - band = 1; - } else { - band = 2; - } - if (freq <= 500000U) { + else if (freq <= 500000U) { rdiv = SI5351_R_DIV_64; + freq *= 64; + ofreq *= 64; } 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; } - -#if 1 - if (current_band != band) - si5351_disable_output(); -#endif - switch (band) { - case 0: - // fractional divider mode. only PLL A is used. - if (current_band == 1 || current_band == 2) - si5351_setupPLL(SI5351_PLL_A, 32, 0, 1); - // Set PLL twice on changing from band 2 - if (current_band == 2) - si5351_setupPLL(SI5351_PLL_A, 32, 0, 1); - - if (rdiv == SI5351_R_DIV_8) { - freq *= 8; - ofreq *= 8; - } else if (rdiv == SI5351_R_DIV_64) { - freq *= 64; - ofreq *= 64; - } - - si5351_set_frequency_fixedpll(0, SI5351_PLL_A, PLLFREQ, ofreq, - rdiv, drive_strength, omul); - si5351_set_frequency_fixedpll(1, SI5351_PLL_A, PLLFREQ, freq, - rdiv, drive_strength, mul); - //if (current_band != 0) - si5351_set_frequency_fixedpll(2, SI5351_PLL_A, PLLFREQ, CLK2_FREQUENCY, - SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1); - break; - case 1: - // Set PLL twice on changing from band 2 - if (current_band == 2) { - si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul); - si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul); + // Setup CH0 and CH1 constant PLL 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); } - - // div by 6 mode. both PLL A and B are dedicated for CLK0, CLK1 - si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 6, drive_strength, omul); - si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 6, drive_strength, mul); - si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq / mul * 6, CLK2_FREQUENCY, - SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1); + // 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); break; - case 2: - // div by 4 mode. both PLL A and B are dedicated for CLK0, CLK1 - si5351_set_frequency_fixeddiv(0, SI5351_PLL_A, ofreq, 4, drive_strength, omul); - si5351_set_frequency_fixeddiv(1, SI5351_PLL_B, freq, 4, drive_strength, mul); - si5351_set_frequency_fixedpll(2, SI5351_PLL_B, freq / mul * 4, CLK2_FREQUENCY, - SI5351_R_DIV_1, SI5351_CLK_DRIVE_STRENGTH_2MA, 1); + case 3: + // 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); + } + // 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); break; } if (current_band != band) { - si5351_reset_pll(); -#if 1 - si5351_enable_output(); -#endif - delay += DELAY_BANDCHANGE; + si5351_reset_pll(SI5351_PLL_RESET_A|SI5351_PLL_RESET_B); + current_band = band; + delay+=DELAY_BANDCHANGE; } - if (band == 0) - delay += DELAY_LOWBAND; - - current_band = band; return delay; } diff --git a/si5351.h b/si5351.h index 0a10c96..4572dc8 100644 --- a/si5351.h +++ b/si5351.h @@ -17,8 +17,8 @@ * 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_PLL_A 0 +//#define SI5351_PLL_B 1 #define SI5351_MULTISYNTH_DIV_4 4 #define SI5351_MULTISYNTH_DIV_6 6 @@ -33,12 +33,16 @@ #define SI5351_R_DIV_128 (7<<4) #define SI5351_DIVBY4 (3<<2) -#define SI5351_REG_3_OUTPUT_ENABLE_CONTROL 3 +#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_26_PLL_A 26 -#define SI5351_REG_34_PLL_B 34 +#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 @@ -74,4 +78,7 @@ void si5351_init(void); -void si5351_set_frequency(int channel, int freq, uint8_t drive_strength); +void si5351_disable_output(void); +void si5351_enable_output(void); +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/tlv320aic3204.c b/tlv320aic3204.c index cb86ad5..c1b57b5 100644 --- a/tlv320aic3204.c +++ b/tlv320aic3204.c @@ -25,74 +25,78 @@ #define wait_ms(ms) chThdSleepMilliseconds(ms) -static const uint8_t conf_data_pll[] = { - // len, ( reg, data ), - 2, 0x00, 0x00, /* Initialize to Page 0 */ - 2, 0x01, 0x01, /* Initialize the device through software reset */ - 2, 0x04, 0x43, /* PLL Clock High, MCLK, PLL */ +static const uint8_t conf_data[] = { +// reg, data, +// PLL clock config + 0x00, 0x00, /* Initialize to Page 0 */ + 0x01, 0x01, /* Initialize the device through software reset */ + 0x04, 0x43, /* PLL Clock High, MCLK, PLL */ #ifdef REFCLK_8000KHZ /* 8.000MHz*10.7520 = 86.016MHz, 86.016MHz/(2*7*128) = 48kHz */ - 2, 0x05, 0x91, /* Power up PLL, P=1,R=1 */ - 2, 0x06, 0x0a, /* J=10 */ - 2, 0x07, 29, /* D=7520 = (29<<8) + 96 */ - 2, 0x08, 96, + 0x05, 0x91, /* Power up PLL, P=1,R=1 */ + 0x06, 0x0a, /* J=10 */ + 0x07, 29, /* D=7520 = (29<<8) + 96 */ + 0x08, 96, #endif - 0 // sentinel +// Clock config, default fs=48kHz + 0x0b, 0x82, /* Power up the NDAC divider with value 2 */ + 0x0c, 0x87, /* Power up the MDAC divider with value 7 */ + 0x0d, 0x00, /* Program the OSR of DAC to 128 */ + 0x0e, 0x80, + 0x3c, 0x08, /* Set the DAC Mode to PRB_P8 */ + //0x3c, 25, /* Set the DAC Mode to PRB_P25 */ + 0x1b, 0x0c, /* Set the BCLK,WCLK as output */ + 0x1e, 0x80 + 28, /* Enable the BCLKN divider with value 28 */ + 0x25, 0xee, /* DAC power up */ + + 0x12, 0x82, /* Power up the NADC divider with value 2 */ + 0x13, 0x87, /* Power up the MADC divider with value 7 */ + 0x14, 0x80, /* Program the OSR of ADC to 128 */ + 0x3d, 0x01, /* Select ADC PRB_R1 */ +// Data routing + 0x00, 0x01, /* Select Page 1 */ + 0x01, 0x08, /* Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO*/ + 0x02, 0x01, /* Enable Master Analog Power Control */ + 0x7b, 0x01, /* Set the REF charging time to 40ms */ + 0x14, 0x25, /* HP soft stepping settings for optimal pop performance at power up Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound. */ + 0x0a, 0x33, /* Set the Input Common Mode to 0.9V and Output Common Mode for Headphone to 1.65V */ + + 0x3d, 0x00, /* Select ADC PTM_R4 */ + 0x47, 0x32, /* Set MicPGA startup delay to 3.1ms */ + 0x7b, 0x01, /* Set the REF charging time to 40ms */ + 0x34, 0x10, /* Route IN2L to LEFT_P with 10K */ + 0x36, 0x10, /* Route IN2R to LEFT_N with 10K */ +//0x37, 0x04, /* Route IN3R to RIGHT_P with 10K */ +//0x39, 0x04, /* Route IN3L to RIGHT_N with 10K */ +//0x3b, 0x00, /* Unmute Left MICPGA, Gain selection of 32dB to make channel gain 0dB */ +//0x3c, 0x00, /* Unmute Right MICPGA, Gain selection of 32dB to make channel gain 0dB */ }; -// default fs=48kHz -static const uint8_t conf_data_clk[] = { - 2, 0x0b, 0x82, /* Power up the NDAC divider with value 2 */ - 2, 0x0c, 0x87, /* Power up the MDAC divider with value 7 */ - 2, 0x0d, 0x00, /* Program the OSR of DAC to 128 */ - 2, 0x0e, 0x80, - 2, 0x3c, 0x08, /* Set the DAC Mode to PRB_P8 */ - //2, 0x3c, 25, /* Set the DAC Mode to PRB_P25 */ - 2, 0x1b, 0x0c, /* Set the BCLK,WCLK as output */ - 2, 0x1e, 0x80 + 28, /* Enable the BCLKN divider with value 28 */ - 2, 0x25, 0xee, /* DAC power up */ - - 2, 0x12, 0x82, /* Power up the NADC divider with value 2 */ - 2, 0x13, 0x87, /* Power up the MADC divider with value 7 */ - 2, 0x14, 0x80, /* Program the OSR of ADC to 128 */ - 2, 0x3d, 0x01, /* Select ADC PRB_R1 */ - 0 // sentinel +static const uint8_t conf_data_unmute[] = { +// reg, data, + 0x00, 0x00, /* Select Page 0 */ + 0x51, 0xc0, /* Power up Left and Right ADC Channels */ + 0x52, 0x00, /* Unmute Left and Right ADC Digital Volume Control */ }; -static const uint8_t conf_data_routing[] = { - 2, 0x00, 0x01, /* Select Page 1 */ - 2, 0x01, 0x08, /* Disable Internal Crude AVdd in presence of external AVdd supply or before powering up internal AVdd LDO*/ - 2, 0x02, 0x01, /* Enable Master Analog Power Control */ - 2, 0x7b, 0x01, /* Set the REF charging time to 40ms */ - 2, 0x14, 0x25, /* HP soft stepping settings for optimal pop performance at power up Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound. */ - 2, 0x0a, 0x33, /* Set the Input Common Mode to 0.9V and Output Common Mode for Headphone to 1.65V */ - - 2, 0x3d, 0x00, /* Select ADC PTM_R4 */ - 2, 0x47, 0x32, /* Set MicPGA startup delay to 3.1ms */ - 2, 0x7b, 0x01, /* Set the REF charging time to 40ms */ - 2, 0x34, 0x10, /* Route IN2L to LEFT_P with 10K */ - 2, 0x36, 0x10, /* Route IN2R to LEFT_N with 10K */ - 2, 0x37, 0x04, /* Route IN3R to RIGHT_P with 10K */ - 2, 0x39, 0x04, /* Route IN3L to RIGHT_N with 10K */ - 2, 0x3b, 0, /* Unmute Left MICPGA, Gain selection of 32dB to make channel gain 0dB */ - 2, 0x3c, 0, /* Unmute Right MICPGA, Gain selection of 32dB to make channel gain 0dB */ - 0 // sentinel +static const uint8_t conf_data_ch3_select[] = { +// reg, data, + 0x00, 0x01, /* Select Page 1 */ + 0x37, 0x04, /* Route IN3R to RIGHT_P with input impedance of 10K */ + 0x39, 0x04, /* Route IN3L to RIGHT_N with input impedance of 10K */ }; -const uint8_t conf_data_unmute[] = { - 2, 0x00, 0x00, /* Select Page 0 */ - 2, 0x51, 0xc0, /* Power up Left and Right ADC Channels */ - 2, 0x52, 0x00, /* Unmute Left and Right ADC Digital Volume Control */ - 0 // sentinel +static const uint8_t conf_data_ch1_select[] = { +// reg, data, + 0x00, 0x01, /* Select Page 1 */ + 0x37, 0x40, /* Route IN1R to RIGHT_P with input impedance of 10K */ + 0x39, 0x10, /* Route IN1L to RIGHT_N with input impedance of 10K */ }; -static void +static inline void tlv320aic3204_bulk_write(const uint8_t *buf, int len) { - int addr = AIC3204_ADDR; - i2cAcquireBus(&I2CD1); - (void)i2cMasterTransmitTimeout(&I2CD1, addr, buf, len, NULL, 0, 1000); - i2cReleaseBus(&I2CD1); + (void)i2cMasterTransmitTimeout(&I2CD1, AIC3204_ADDR, buf, len, NULL, 0, 1000); } #if 0 @@ -109,49 +113,32 @@ tlv320aic3204_read(uint8_t d0) #endif static void -tlv320aic3204_config(const uint8_t *data) +tlv320aic3204_config(const uint8_t *data, int len) { - const uint8_t *p = data; - while (*p) { - uint8_t len = *p++; - tlv320aic3204_bulk_write(p, len); - p += len; - } + i2cAcquireBus(&I2CD1); + for (;len--;data+=2) + tlv320aic3204_bulk_write(data, 2); + i2cReleaseBus(&I2CD1); } void tlv320aic3204_init(void) { - tlv320aic3204_config(conf_data_pll); - tlv320aic3204_config(conf_data_clk); - tlv320aic3204_config(conf_data_routing); + tlv320aic3204_config(conf_data, sizeof(conf_data)/2); wait_ms(40); - tlv320aic3204_config(conf_data_unmute); + tlv320aic3204_config(conf_data_unmute, sizeof(conf_data_unmute)/2); } void tlv320aic3204_select(int channel) { - const uint8_t ch3[] = { - 2, 0x00, 0x01, /* Select Page 1 */ - 2, 0x37, 0x04, /* Route IN3R to RIGHT_P with input impedance of 10K */ - 2, 0x39, 0x04, /* Route IN3L to RIGHT_N with input impedance of 10K */ - 0 // sentinel - }; - const uint8_t ch1[] = { - 2, 0x00, 0x01, /* Select Page 1 */ - 2, 0x37, 0x40, /* Route IN1R to RIGHT_P with input impedance of 10K */ - 2, 0x39, 0x10, /* Route IN1L to RIGHT_N with input impedance of 10K */ - 0 // sentinel - }; - tlv320aic3204_config(channel ? ch1 : ch3); + tlv320aic3204_config(channel ? conf_data_ch1_select : conf_data_ch3_select, sizeof(conf_data_ch3_select)/2); } void tlv320aic3204_set_gain(int lgain, int rgain) { - uint8_t data[] = { - 2, 0x00, 0x01, /* Select Page 1 */ - 2, 0x3b, lgain, /* Unmute Left MICPGA, set gain */ - 2, 0x3c, rgain, /* Unmute Right MICPGA, set gain */ - 0 // sentinel - }; - tlv320aic3204_config(data); + uint8_t data[] = { + 0x00, 0x01, /* Select Page 1 */ + 0x3b, lgain, /* Unmute Left MICPGA, set gain */ + 0x3c, rgain, /* Unmute Right MICPGA, set gain */ + }; + tlv320aic3204_config(data, sizeof(data)/2); } diff --git a/ui.c b/ui.c index 681c8bb..562d0dd 100644 --- a/ui.c +++ b/ui.c @@ -25,12 +25,12 @@ //#include #include - uistat_t uistat = { digit: 6, current_trace: 0, lever_mode: LM_MARKER, marker_delta: FALSE, + marker_tracking : FALSE, }; #define NO_EVENT 0 @@ -41,9 +41,9 @@ uistat_t uistat = { #define EVT_DOWN 0x20 #define EVT_REPEAT 0x40 -#define BUTTON_DOWN_LONG_TICKS 5000 /* 1sec */ -#define BUTTON_DOUBLE_TICKS 5000 /* 500ms */ -#define BUTTON_REPEAT_TICKS 1000 /* 100ms */ +#define BUTTON_DOWN_LONG_TICKS 5000 /* 1sec */ +#define BUTTON_DOUBLE_TICKS 2500 /* 500ms */ +#define BUTTON_REPEAT_TICKS 625 /* 125ms */ #define BUTTON_DEBOUNCE_TICKS 200 /* lever switch assignment */ @@ -59,7 +59,7 @@ static uint32_t last_button_down_ticks; static uint32_t last_button_repeat_ticks; static int8_t inhibit_until_release = FALSE; -uint8_t operation_requested = OP_NONE; +volatile uint8_t operation_requested = OP_NONE; int8_t previous_marker = -1; @@ -71,8 +71,14 @@ enum { KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, KM_SCALE, KM_REFPOS, KM_EDELAY, KM_VELOCITY_FACTOR, KM_SCALEDELAY }; +#define NUMINPUT_LEN 10 + static uint8_t ui_mode = UI_NORMAL; static uint8_t keypad_mode; +static uint8_t keypads_last_index; +static char kp_buf[NUMINPUT_LEN+1]; +static int8_t kp_index = 0; +static uint8_t menu_current_level = 0; static int8_t selection = 0; // Set structure align as WORD (save flash memory) @@ -98,18 +104,13 @@ static int16_t last_touch_y; //int16_t touch_cal[4] = { 1000, 1000, 10*16, 12*16 }; //int16_t touch_cal[4] = { 620, 600, 130, 180 }; -int awd_count; +//int awd_count; //int touch_x, touch_y; -#define NUMINPUT_LEN 10 - #define KP_CONTINUE 0 #define KP_DONE 1 #define KP_CANCEL 2 -static char kp_buf[NUMINPUT_LEN+1]; -static int8_t kp_index = 0; - static void ui_mode_normal(void); static void ui_mode_menu(void); static void ui_mode_numeric(int _keypad_mode); @@ -130,33 +131,29 @@ static int btn_check(void) int status = 0; uint32_t ticks = chVTGetSystemTime(); if (changed & (1<= BUTTON_DEBOUNCE_TICKS) { - if (cur_button & (1<= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS) { + // button released + status |= EVT_BUTTON_SINGLE_CLICK; + if (inhibit_until_release) { + status = 0; + inhibit_until_release = FALSE; } - last_button_down_ticks = ticks; } } - if (changed & (1<= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS)) { status |= EVT_UP; } - last_button_down_ticks = ticks; } if (changed & (1<= last_button_down_ticks + BUTTON_DEBOUNCE_TICKS)) { status |= EVT_DOWN; } - last_button_down_ticks = ticks; } + last_button_down_ticks = ticks; last_button = cur_button; return status; @@ -169,15 +166,14 @@ static int btn_wait_release(void) int changed = last_button ^ cur_button; uint32_t ticks = chVTGetSystemTime(); int status = 0; - if (!inhibit_until_release) { if ((cur_button & (1<= BUTTON_DOWN_LONG_TICKS) { + && ticks >= last_button_down_ticks + BUTTON_DOWN_LONG_TICKS) { inhibit_until_release = TRUE; return EVT_BUTTON_DOWN_LONG; } if ((changed & (1<= BUTTON_DOWN_LONG_TICKS - && ticks - last_button_repeat_ticks >= BUTTON_REPEAT_TICKS) { - if (cur_button & (1<= last_button_down_ticks + BUTTON_DOWN_LONG_TICKS + && ticks >= last_button_repeat_ticks + BUTTON_REPEAT_TICKS) { + if (cur_button & (1< Date: Sat, 7 Mar 2020 14:54:51 +0300 Subject: [PATCH 2/7] 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) --- Makefile | 4 +- main.c | 152 +++++++++------------ mcuconf.h | 3 +- nanovna.h | 8 +- si5351.c | 384 ++++++++++++++++++++++++++---------------------------- si5351.h | 75 +++++------ ui.c | 4 +- 7 files changed, 289 insertions(+), 341 deletions(-) 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 From 12d53738bcaabb032af4673de513a2f2eb214154 Mon Sep 17 00:00:00 2001 From: DiSlord Date: Sat, 7 Mar 2020 17:19:43 +0300 Subject: [PATCH 3/7] Revert some changes: Start/stop generation feature (unstable on segment scan from CPU) Calibration on paused sweep (need more stack, need find better solution) Variable use optimization --- Makefile | 4 +-- main.c | 100 +++++++++++++++++++++++++++++++++--------------------- nanovna.h | 8 +---- si5351.c | 19 ++++++----- ui.c | 2 +- 5 files changed, 77 insertions(+), 56 deletions(-) diff --git a/Makefile b/Makefile index fc18d97..bd17844 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 = 0x300 + USE_PROCESS_STACKSIZE = 0x200 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 = 0x100 + USE_EXCEPTIONS_STACKSIZE = 0x200 endif # diff --git a/main.c b/main.c index 02ef10d..bb1a4bb 100644 --- a/main.c +++ b/main.c @@ -69,14 +69,17 @@ static void transform_domain(void); static MUTEX_DECL(mutex); -// Obsolete enable/disable calibration interpolation (always on) -#define cal_auto_interpolate TRUE +#define DRIVE_STRENGTH_AUTO (-1) +#define FREQ_HARMONICS (config.harmonic_freq_threshold) +#define IS_HARMONIC_MODE(f) ((f) > FREQ_HARMONICS) +// Obsolete, always use interpolate +#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; - +int8_t sweep_enabled = TRUE; +volatile int8_t sweep_once = FALSE; volatile uint8_t redraw_request = 0; // contains REDRAW_XXX flags int16_t vbat = 0; @@ -88,19 +91,19 @@ static THD_FUNCTION(Thread1, arg) while (1) { bool completed = false; - if (sweep_mode&(SWEEP_MODE_ENABLED|SWEEP_MODE_RUN_ONCE)) { + if (sweep_enabled || sweep_once) { chMtxLock(&mutex); completed = sweep(true); - sweep_mode&=~SWEEP_MODE_RUN_ONCE; + sweep_once = FALSE; chMtxUnlock(&mutex); } else { - si5351_disable_output(); __WFI(); } chMtxLock(&mutex); ui_process(); - if (sweep_mode&SWEEP_MODE_ENABLED) { + + if (sweep_enabled) { if (vbat != -1) { adc_stop(ADC1); vbat = adc_vbat_read(ADC1); @@ -130,10 +133,23 @@ static THD_FUNCTION(Thread1, arg) } } -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 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 float bessel0(float x) { @@ -723,8 +739,7 @@ static const marker_t def_markers[MARKERS_MAX] = { // Load propeties default settings void loadDefaultProps(void){ -//Magic add on caldata_save -//current_props.magic = CONFIG_MAGIC; + current_props.magic = CONFIG_MAGIC; current_props._frequency0 = 50000; // start = 50kHz current_props._frequency1 = 900000000; // end = 900MHz current_props._sweep_points = POINTS_COUNT; @@ -740,8 +755,6 @@ void loadDefaultProps(void){ current_props._active_marker = 0; current_props._domain_mode = 0; current_props._marker_smith_format = MS_RLC; -//Checksum add on caldata_save -//current_props.checksum = 0; } void @@ -759,23 +772,20 @@ ensure_edit_config(void) #define DELAY_CHANNEL_CHANGE 2 // main loop for measurement -static bool sweep(bool break_on_operation) +bool sweep(bool break_on_operation) { int i, delay; // blink LED while scanning palClearPad(GPIOC, GPIOC_LED); - si5351_enable_output(); - 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); // 1900 // calculate reflection coefficient (*sample_func)(measured[0][i]); // 60 tlv320aic3204_select(1); // 60 CH1:TRANSMISSION - wait_dsp(DELAY_CHANNEL_CHANGE); // 1800 + wait_dsp(DELAY_CHANNEL_CHANGE); // 1700 // calculate transmission coefficient (*sample_func)(measured[1][i]); // 60 // ======== 170 =========== @@ -786,9 +796,8 @@ static bool sweep(bool break_on_operation) apply_edelay_at(i); // back to toplevel to handle ui operation - if (operation_requested && break_on_operation){ + if (operation_requested && break_on_operation) return false; - } } // blink LED while scanning palSetPad(GPIOC, GPIOC_LED); @@ -825,11 +834,11 @@ VNA_SHELL_FUNCTION(cmd_scan) if (cal_auto_interpolate && (cal_status & CALSTAT_APPLY)) cal_interpolate(lastsaveid); - run_once_sweep(); + sweep_once = TRUE; chMtxUnlock(&mutex); // wait finishing sweep - while (sweep_mode&SWEEP_MODE_RUN_ONCE) + while (sweep_once) chThdSleepMilliseconds(10); } @@ -1270,21 +1279,36 @@ void cal_collect(int type) { ensure_edit_config(); - int dst, src; + switch (type) { - 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; + 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; } - // 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; + redraw_request |= REDRAW_CAL_STATUS; } void diff --git a/nanovna.h b/nanovna.h index 72753d1..b79d4c8 100644 --- a/nanovna.h +++ b/nanovna.h @@ -86,9 +86,7 @@ double my_atof(const char *p); void toggle_sweep(void); void loadDefaultProps(void); -#define SWEEP_MODE_ENABLED 0x01 -#define SWEEP_MODE_RUN_ONCE 0x02 -extern volatile int8_t sweep_mode; +extern int8_t sweep_enabled; /* * dsp.c @@ -225,10 +223,6 @@ typedef struct config { extern config_t config; -#define DRIVE_STRENGTH_AUTO (-1) -#define FREQ_HARMONICS (config.harmonic_freq_threshold) -#define IS_HARMONIC_MODE(f) ((f) > FREQ_HARMONICS) - //extern trace_t trace[TRACES_MAX]; void set_trace_type(int t, int type); diff --git a/si5351.c b/si5351.c index a08bfbe..6a8ad49 100644 --- a/si5351.c +++ b/si5351.c @@ -78,8 +78,8 @@ const uint8_t si5351_configs[] = { // 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, #endif + 2, SI5351_REG_3_OUTPUT_ENABLE_CONTROL, ~(SI5351_CLK0_EN|SI5351_CLK1_EN|SI5351_CLK2_EN), 0 // sentinel }; @@ -118,7 +118,7 @@ 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); + chThdSleepMicroseconds(400); si5351_write(SI5351_REG_177_PLL_RESET, mask | 0x0C); } @@ -126,6 +126,7 @@ void si5351_disable_output(void) { si5351_write(SI5351_REG_3_OUTPUT_ENABLE_CONTROL, 0xFF); si5351_bulk_write(disable_output, sizeof(disable_output)); + current_band = 0; } void si5351_enable_output(void) @@ -338,7 +339,8 @@ static inline uint8_t si5351_getBand(uint32_t freq){ // 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_1 3 +#define DELAY_BANDCHANGE_2 3 /* * Maximum supported frequency = FREQ_HARMONICS * 9U @@ -358,16 +360,16 @@ si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_streng uint32_t rdiv = SI5351_R_DIV_1; uint32_t fdiv; current_freq = freq; - if (freq >= FREQ_HARMONICS * 7U) { + if (freq >= config.harmonic_freq_threshold * 7U) { mul = 9; omul = 11; - } else if (freq >= FREQ_HARMONICS * 5U) { + } else if (freq >= config.harmonic_freq_threshold * 5U) { mul = 7; omul = 9; - } else if (freq >= FREQ_HARMONICS * 3U) { + } else if (freq >= config.harmonic_freq_threshold * 3U) { mul = 5; omul = 7; - } else if (freq >= FREQ_HARMONICS) { + } else if (freq >= config.harmonic_freq_threshold) { mul = 3; omul = 5; } @@ -388,6 +390,7 @@ si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_streng if (current_band != 1){ si5351_setupPLL(SI5351_REG_PLL_A, 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); + delay+=DELAY_BANDCHANGE_1; } // Calculate and set CH0 and CH1 divider si5351_set_frequency_fixedpll(0, (uint64_t)omul * XTALFREQ * PLL_N, ofreq, rdiv, drive_strength|SI5351_CLK_PLL_SELECT_A); @@ -401,6 +404,7 @@ si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_streng if (current_band != band){ 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); + delay+=DELAY_BANDCHANGE_2; } // Calculate and set CH0 and CH1 PLL freq si5351_setupPLL_freq(SI5351_REG_PLL_A, ofreq, fdiv, omul);// set PLLA freq = (ofreq/omul)*fdiv @@ -413,7 +417,6 @@ si5351_set_frequency_with_offset(uint32_t freq, int offset, uint8_t drive_streng if (current_band != band) { si5351_reset_pll(SI5351_PLL_RESET_A|SI5351_PLL_RESET_B); current_band = band; - delay+=DELAY_BANDCHANGE; } return delay; } diff --git a/ui.c b/ui.c index b73ef29..eaffa8d 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_mode&SWEEP_MODE_ENABLED)) { + if (item == 5 /* PAUSE */ && !sweep_enabled) { *bg = DEFAULT_MENU_TEXT_COLOR; *fg = config.menu_normal_color; } From e896f328033319059e69289bdcd58e0dc349cfb5 Mon Sep 17 00:00:00 2001 From: DiSlord Date: Sat, 7 Mar 2020 20:57:43 +0300 Subject: [PATCH 4/7] Replace function wait_dsp(delay) by definition: DSP_START(delay) //================================================ // Place some code thats need execute while delay //================================================ DSP_WAIT_READY Fix Band table description Add power stabilization delay on sweep start --- main.c | 38 +++++++++++++++++++++++--------------- si5351.c | 11 ++++++----- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/main.c b/main.c index bb1a4bb..8dc8c17 100644 --- a/main.c +++ b/main.c @@ -423,9 +423,9 @@ static int getStringIndex(char *v, const char *list){ } // Set new substring ptr while (1){ - // End of string, not found - if (*list == 0 ) return -1; - if (*list++ == '|') break; + // End of string, not found + if (*list == 0 ) return -1; + if (*list++ == '|') break; } i++; } @@ -553,15 +553,6 @@ volatile int16_t wait_count = 0; float measured[2][POINTS_COUNT][2]; -static void -wait_dsp(int count) -{ - wait_count = count; - //reset_dsp_accumerator(); - while (wait_count) - __WFI(); -} - #ifdef ENABLED_DUMP static void duplicate_buffer_to_dump(int16_t *p) @@ -739,7 +730,8 @@ static const marker_t def_markers[MARKERS_MAX] = { // Load propeties default settings void loadDefaultProps(void){ - current_props.magic = CONFIG_MAGIC; +//Magic add on caldata_save +//current_props.magic = CONFIG_MAGIC; current_props._frequency0 = 50000; // start = 50kHz current_props._frequency1 = 900000000; // end = 900MHz current_props._sweep_points = POINTS_COUNT; @@ -755,6 +747,8 @@ void loadDefaultProps(void){ current_props._active_marker = 0; current_props._domain_mode = 0; current_props._marker_smith_format = MS_RLC; +//Checksum add on caldata_save +//current_props.checksum = 0; } void @@ -769,6 +763,9 @@ ensure_edit_config(void) cal_status = 0; } +#define DSP_START(delay) wait_count = delay; +#define DSP_WAIT_READY while (wait_count) __WFI(); + #define DELAY_CHANNEL_CHANGE 2 // main loop for measurement @@ -777,15 +774,26 @@ bool sweep(bool break_on_operation) int i, delay; // blink LED while scanning palClearPad(GPIOC, GPIOC_LED); + // Power stabilization after LED off, also align timings + // Also touch made some + DSP_START(1); DSP_WAIT_READY; for (i = 0; i < sweep_points; i++) { // 5300 delay = set_frequency(frequencies[i]); // 700 tlv320aic3204_select(0); // 60 CH0:REFLECT - wait_dsp(delay); // 1900 + DSP_START(delay); // 1900 + //================================================ + // Place some code thats need execute while delay + //================================================ + DSP_WAIT_READY; // calculate reflection coefficient (*sample_func)(measured[0][i]); // 60 tlv320aic3204_select(1); // 60 CH1:TRANSMISSION - wait_dsp(DELAY_CHANNEL_CHANGE); // 1700 + DSP_START(DELAY_CHANNEL_CHANGE); // 1700 + //================================================ + // Place some code thats need execute while delay + //================================================ + DSP_WAIT_READY; // calculate transmission coefficient (*sample_func)(measured[1][i]); // 60 // ======== 170 =========== diff --git a/si5351.c b/si5351.c index 6a8ad49..92eeb8a 100644 --- a/si5351.c +++ b/si5351.c @@ -321,11 +321,12 @@ si5351_set_frequency(int channel, uint32_t freq, uint8_t drive_strength){ * +-----------------------------------------------------------------------------------------------------------------------+ * | 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 | + * | Direct mode x1 : x1 | 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 | + * | f = 50kHz-300MHz | f=100-150 | f=150-300 | f=150-300 | f=214-300 | f=233-300 | + * | of = 50kHz-300MHz |of= 60- 90 |of= 90-180 |of=128-215 |of=166-234 |of=190-246 | * +-----------------------------------------------------------------------------------------------------------------------+ */ static inline uint8_t si5351_getBand(uint32_t freq){ @@ -339,8 +340,8 @@ static inline uint8_t si5351_getBand(uint32_t freq){ // 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_1 3 -#define DELAY_BANDCHANGE_2 3 +#define DELAY_BANDCHANGE_1 2 +#define DELAY_BANDCHANGE_2 2 /* * Maximum supported frequency = FREQ_HARMONICS * 9U From bb7127fdd019159f1d53c738a9f3ddef072828af Mon Sep 17 00:00:00 2001 From: DiSlord Date: Sat, 7 Mar 2020 22:21:02 +0300 Subject: [PATCH 5/7] Remove variable, use speep_mode flag --- main.c | 20 ++++++++++---------- nanovna.h | 4 +++- ui.c | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/main.c b/main.c index 8dc8c17..008f30e 100644 --- a/main.c +++ b/main.c @@ -78,8 +78,8 @@ static MUTEX_DECL(mutex); static int32_t frequency_offset = 5000; static uint32_t frequency = 10000000; static int8_t drive_strength = DRIVE_STRENGTH_AUTO; -int8_t sweep_enabled = TRUE; -volatile int8_t sweep_once = FALSE; +int8_t sweep_mode = SWEEP_ENABLE; + volatile uint8_t redraw_request = 0; // contains REDRAW_XXX flags int16_t vbat = 0; @@ -91,10 +91,10 @@ static THD_FUNCTION(Thread1, arg) while (1) { bool completed = false; - if (sweep_enabled || sweep_once) { + if (sweep_mode&(SWEEP_ENABLE|SWEEP_ONCE)) { chMtxLock(&mutex); completed = sweep(true); - sweep_once = FALSE; + sweep_mode&=~SWEEP_ONCE; chMtxUnlock(&mutex); } else { __WFI(); @@ -103,7 +103,7 @@ static THD_FUNCTION(Thread1, arg) chMtxLock(&mutex); ui_process(); - if (sweep_enabled) { + if (sweep_mode&SWEEP_ENABLE) { if (vbat != -1) { adc_stop(ADC1); vbat = adc_vbat_read(ADC1); @@ -136,19 +136,19 @@ static THD_FUNCTION(Thread1, arg) static inline void pause_sweep(void) { - sweep_enabled = FALSE; + sweep_mode&=~SWEEP_ENABLE; } static inline void resume_sweep(void) { - sweep_enabled = TRUE; + sweep_mode|=SWEEP_ENABLE; } void toggle_sweep(void) { - sweep_enabled = !sweep_enabled; + sweep_mode^=SWEEP_ENABLE; } static float @@ -842,11 +842,11 @@ VNA_SHELL_FUNCTION(cmd_scan) if (cal_auto_interpolate && (cal_status & CALSTAT_APPLY)) cal_interpolate(lastsaveid); - sweep_once = TRUE; + sweep_mode|= SWEEP_ONCE; chMtxUnlock(&mutex); // wait finishing sweep - while (sweep_once) + while (sweep_mode&SWEEP_ONCE) chThdSleepMilliseconds(10); } diff --git a/nanovna.h b/nanovna.h index b79d4c8..f2b9721 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_ENABLE 0x01 +#define SWEEP_ONCE 0x02 +extern int8_t sweep_mode; /* * dsp.c diff --git a/ui.c b/ui.c index eaffa8d..93cc96d 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_ENABLE)) { *bg = DEFAULT_MENU_TEXT_COLOR; *fg = config.menu_normal_color; } From fc6e090595e35299db5acf309bee39f58dc1b6cd Mon Sep 17 00:00:00 2001 From: DiSlord Date: Sat, 7 Mar 2020 23:37:39 +0300 Subject: [PATCH 6/7] Add vbat_offset to config Implement vbat_offset command (if defined ENABLE_VBAT_OFFSET_COMMAND) Reduce code size --- adc.c | 121 +++++++++++++++++++++++++++--------------------------- main.c | 31 ++++++++------ nanovna.h | 18 ++++---- plot.c | 9 ++-- ui.c | 20 ++++----- 5 files changed, 103 insertions(+), 96 deletions(-) diff --git a/adc.c b/adc.c index 1da498d..2486210 100644 --- a/adc.c +++ b/adc.c @@ -28,80 +28,79 @@ #define ADC_SMPR_SMP_239P5 7U /**< @brief 252 cycles conversion time. */ #define ADC_CFGR1_RES_12BIT (0U << 3U) +#define VNA_ADC ADC1 + void adc_init(void) { rccEnableADC1(FALSE); /* Ensure flag states */ - ADC1->IER = 0; + VNA_ADC->IER = 0; /* Calibration procedure.*/ ADC->CCR = 0; - if (ADC1->CR & ADC_CR_ADEN) { - ADC1->CR |= ~ADC_CR_ADDIS; /* Disable ADC */ + if (VNA_ADC->CR & ADC_CR_ADEN) { + VNA_ADC->CR |= ~ADC_CR_ADDIS; /* Disable ADC */ } - while (ADC1->CR & ADC_CR_ADEN) + while (VNA_ADC->CR & ADC_CR_ADEN) ; - ADC1->CFGR1 &= ~ADC_CFGR1_DMAEN; - ADC1->CR |= ADC_CR_ADCAL; - while (ADC1->CR & ADC_CR_ADCAL) + VNA_ADC->CFGR1 &= ~ADC_CFGR1_DMAEN; + VNA_ADC->CR |= ADC_CR_ADCAL; + while (VNA_ADC->CR & ADC_CR_ADCAL) ; - if (ADC1->ISR & ADC_ISR_ADRDY) { - ADC1->ISR |= ADC_ISR_ADRDY; /* clear ADRDY */ + if (VNA_ADC->ISR & ADC_ISR_ADRDY) { + VNA_ADC->ISR |= ADC_ISR_ADRDY; /* clear ADRDY */ } /* Enable ADC */ - ADC1->CR |= ADC_CR_ADEN; - while (!(ADC1->ISR & ADC_ISR_ADRDY)) + VNA_ADC->CR |= ADC_CR_ADEN; + while (!(VNA_ADC->ISR & ADC_ISR_ADRDY)) ; } -uint16_t adc_single_read(ADC_TypeDef *adc, uint32_t chsel) +uint16_t adc_single_read(uint32_t chsel) { /* ADC setup */ - adc->ISR = adc->ISR; - adc->IER = 0; - adc->TR = ADC_TR(0, 0); - adc->SMPR = ADC_SMPR_SMP_239P5; - adc->CFGR1 = ADC_CFGR1_RES_12BIT; - adc->CHSELR = chsel; + VNA_ADC->ISR = VNA_ADC->ISR; + VNA_ADC->IER = 0; + VNA_ADC->TR = ADC_TR(0, 0); + VNA_ADC->SMPR = ADC_SMPR_SMP_239P5; + VNA_ADC->CFGR1 = ADC_CFGR1_RES_12BIT; + VNA_ADC->CHSELR = chsel; /* ADC conversion start.*/ - adc->CR |= ADC_CR_ADSTART; + VNA_ADC->CR |= ADC_CR_ADSTART; - while (adc->CR & ADC_CR_ADSTART) + while (VNA_ADC->CR & ADC_CR_ADSTART) ; - return adc->DR; + return VNA_ADC->DR; } -int16_t adc_vbat_read(ADC_TypeDef *adc) +int16_t adc_vbat_read(void) { #define ADC_FULL_SCALE 3300 -#define VBAT_DIODE_VF 500 #define VREFINT_CAL (*((uint16_t*)0x1FFFF7BA)) - float vbat = 0; - float vrefint = 0; - - ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_VBATEN; - // VREFINT == ADC_IN17 - vrefint = adc_single_read(adc, ADC_CHSELR_CHSEL17); - // VBAT == ADC_IN18 - // VBATEN enables resiter devider circuit. It consume vbat power. - vbat = adc_single_read(adc, ADC_CHSELR_CHSEL18); - ADC->CCR &= ~(ADC_CCR_VREFEN | ADC_CCR_VBATEN); - - uint16_t vbat_raw = (ADC_FULL_SCALE * VREFINT_CAL * vbat * 2 / (vrefint * ((1<<12)-1))); - if (vbat_raw < 100) { - // maybe D2 is not installed - return -1; - } - - return vbat_raw + VBAT_DIODE_VF; - + adc_stop(); + float vbat = 0; + float vrefint = 0; + ADC->CCR |= ADC_CCR_VREFEN | ADC_CCR_VBATEN; + // VREFINT == ADC_IN17 + vrefint = adc_single_read(ADC_CHSELR_CHSEL17); + // VBAT == ADC_IN18 + // VBATEN enables resiter devider circuit. It consume vbat power. + vbat = adc_single_read(ADC_CHSELR_CHSEL18); + ADC->CCR &= ~(ADC_CCR_VREFEN | ADC_CCR_VBATEN); + touch_start_watchdog(); + uint16_t vbat_raw = (ADC_FULL_SCALE * VREFINT_CAL * vbat * 2 / (vrefint * ((1<<12)-1))); + if (vbat_raw < 100) { + // maybe D2 is not installed + return -1; + } + return vbat_raw + config.vbat_offset; } -void adc_start_analog_watchdogd(ADC_TypeDef *adc, uint32_t chsel) +void adc_start_analog_watchdogd(uint32_t chsel) { uint32_t cfgr1; @@ -111,38 +110,38 @@ void adc_start_analog_watchdogd(ADC_TypeDef *adc, uint32_t chsel) /* ADC setup, if it is defined a callback for the analog watch dog then it is enabled.*/ - adc->ISR = adc->ISR; - adc->IER = ADC_IER_AWDIE; - adc->TR = ADC_TR(0, TOUCH_THRESHOLD); - adc->SMPR = ADC_SMPR_SMP_1P5; - adc->CHSELR = chsel; + VNA_ADC->ISR = VNA_ADC->ISR; + VNA_ADC->IER = ADC_IER_AWDIE; + VNA_ADC->TR = ADC_TR(0, TOUCH_THRESHOLD); + VNA_ADC->SMPR = ADC_SMPR_SMP_1P5; + VNA_ADC->CHSELR = chsel; /* ADC configuration and start.*/ - adc->CFGR1 = cfgr1; + VNA_ADC->CFGR1 = cfgr1; /* ADC conversion start.*/ - adc->CR |= ADC_CR_ADSTART; + VNA_ADC->CR |= ADC_CR_ADSTART; } -void adc_stop(ADC_TypeDef *adc) +void adc_stop(void) { - if (adc->CR & ADC_CR_ADEN) { - if (adc->CR & ADC_CR_ADSTART) { - adc->CR |= ADC_CR_ADSTP; - while (adc->CR & ADC_CR_ADSTP) + if (VNA_ADC->CR & ADC_CR_ADEN) { + if (VNA_ADC->CR & ADC_CR_ADSTART) { + VNA_ADC->CR |= ADC_CR_ADSTP; + while (VNA_ADC->CR & ADC_CR_ADSTP) ; } - /* adc->CR |= ADC_CR_ADDIS; - while (adc->CR & ADC_CR_ADDIS) + /* VNA_ADC->CR |= ADC_CR_ADDIS; + while (VNA_ADC->CR & ADC_CR_ADDIS) ;*/ } } -void adc_interrupt(ADC_TypeDef *adc) +void adc_interrupt(void) { - uint32_t isr = adc->ISR; - adc->ISR = isr; + uint32_t isr = VNA_ADC->ISR; + VNA_ADC->ISR = isr; if (isr & ADC_ISR_OVR) { /* ADC overflow condition, this could happen only if the DMA is unable @@ -159,7 +158,7 @@ OSAL_IRQ_HANDLER(STM32_ADC1_HANDLER) { OSAL_IRQ_PROLOGUE(); - adc_interrupt(ADC1); + adc_interrupt(); OSAL_IRQ_EPILOGUE(); } diff --git a/main.c b/main.c index 008f30e..bb13344 100644 --- a/main.c +++ b/main.c @@ -57,6 +57,7 @@ static char shell_line[VNA_SHELL_MAX_LENGTH]; //#define ENABLED_DUMP //#define ENABLE_THREADS_COMMAND //#define ENABLE_TIME_COMMAND +#define ENABLE_VBAT_OFFSET_COMMAND static void apply_error_term_at(int i); static void apply_edelay_at(int i); @@ -79,9 +80,7 @@ static int32_t frequency_offset = 5000; static uint32_t frequency = 10000000; static int8_t drive_strength = DRIVE_STRENGTH_AUTO; int8_t sweep_mode = SWEEP_ENABLE; - volatile uint8_t redraw_request = 0; // contains REDRAW_XXX flags -int16_t vbat = 0; static THD_WORKING_AREA(waThread1, 640); static THD_FUNCTION(Thread1, arg) @@ -104,19 +103,12 @@ static THD_FUNCTION(Thread1, arg) ui_process(); if (sweep_mode&SWEEP_ENABLE) { - if (vbat != -1) { - adc_stop(ADC1); - vbat = adc_vbat_read(ADC1); - touch_start_watchdog(); - draw_battery_status(); - } - // calculate trace coordinates and plot only if scan completed if (completed) { if ((domain_mode & DOMAIN_MODE) == DOMAIN_TIME) transform_domain(); plot_into_index(measured); - redraw_request |= REDRAW_CELLS; + redraw_request |= REDRAW_CELLS|REDRAW_BATTERY; if (uistat.marker_tracking) { int i = marker_search(); @@ -710,7 +702,8 @@ config_t config = { .trace_color = { DEFAULT_TRACE_1_COLOR, DEFAULT_TRACE_2_COLOR, DEFAULT_TRACE_3_COLOR, DEFAULT_TRACE_4_COLOR }, // .touch_cal = { 693, 605, 124, 171 }, // 2.4 inch LCD panel .touch_cal = { 338, 522, 153, 192 }, // 2.8 inch LCD panel - .harmonic_freq_threshold = 300000000 + .harmonic_freq_threshold = 300000000, + .vbat_offset = 500 }; properties_t current_props; @@ -1942,9 +1935,20 @@ VNA_SHELL_FUNCTION(cmd_vbat) { (void)argc; (void)argv; - shell_printf("%d mV\r\n", vbat); + shell_printf("%d mV\r\n", adc_vbat_read()); } +#ifdef ENABLE_VBAT_OFFSET_COMMAND +VNA_SHELL_FUNCTION(cmd_vbat_offset) +{ + if (argc != 1) { + shell_printf("%d\r\n", config.vbat_offset); + return; + } + config.vbat_offset = (int16_t)my_atoi(argv[0]); +} +#endif + #ifdef ENABLE_THREADS_COMMAND #if CH_CFG_USE_REGISTRY == FALSE #error "Threads Requite enabled CH_CFG_USE_REGISTRY in chconf.h" @@ -2028,6 +2032,9 @@ static const VNAShellCommand commands[] = {"edelay" , cmd_edelay , 0}, {"capture" , cmd_capture , CMD_WAIT_MUTEX}, {"vbat" , cmd_vbat , 0}, +#ifdef ENABLE_VBAT_OFFSET_COMMAND + {"vbat_offset" , cmd_vbat_offset , 0}, +#endif {"transform" , cmd_transform , 0}, {"threshold" , cmd_threshold , 0}, {"help" , cmd_help , 0}, diff --git a/nanovna.h b/nanovna.h index f2b9721..58e4e4c 100644 --- a/nanovna.h +++ b/nanovna.h @@ -218,8 +218,8 @@ typedef struct config { int16_t touch_cal[4]; int8_t reserved_1; uint32_t harmonic_freq_threshold; - - uint8_t _reserved[24]; + uint16_t vbat_offset; + uint8_t _reserved[22]; uint32_t checksum; } config_t; @@ -234,7 +234,6 @@ void set_trace_refpos(int t, float refpos); float get_trace_scale(int t); float get_trace_refpos(int t); const char *get_trace_typename(int t); -void draw_battery_status(void); void set_electrical_delay(float picoseconds); float get_electrical_delay(void); @@ -282,10 +281,9 @@ int marker_search_right(int from); #define REDRAW_FREQUENCY (1<<1) #define REDRAW_CAL_STATUS (1<<2) #define REDRAW_MARKER (1<<3) +#define REDRAW_BATTERY (1<<4) extern volatile uint8_t redraw_request; -extern int16_t vbat; - /* * ili9341.c */ @@ -468,11 +466,11 @@ void enter_dfu(void); */ void adc_init(void); -uint16_t adc_single_read(ADC_TypeDef *adc, uint32_t chsel); -void adc_start_analog_watchdogd(ADC_TypeDef *adc, uint32_t chsel); -void adc_stop(ADC_TypeDef *adc); -void adc_interrupt(ADC_TypeDef *adc); -int16_t adc_vbat_read(ADC_TypeDef *adc); +uint16_t adc_single_read(uint32_t chsel); +void adc_start_analog_watchdogd(uint32_t chsel); +void adc_stop(void); +void adc_interrupt(void); +int16_t adc_vbat_read(void); /* * misclinous diff --git a/plot.c b/plot.c index d1762f0..5d712a6 100644 --- a/plot.c +++ b/plot.c @@ -6,6 +6,7 @@ #include "nanovna.h" static void cell_draw_marker_info(int x0, int y0); +static void draw_battery_status(void); int16_t grid_offset; int16_t grid_width; @@ -1388,6 +1389,8 @@ draw_all(bool flush) draw_frequencies(); if (redraw_request & REDRAW_CAL_STATUS) draw_cal_status(); + if (redraw_request & REDRAW_BATTERY) + draw_battery_status(); redraw_request = 0; } @@ -1661,10 +1664,10 @@ draw_cal_status(void) #define BATTERY_BOTTOM_LEVEL 3100 #define BATTERY_WARNING_LEVEL 3300 -void -draw_battery_status(void) +static void draw_battery_status(void) { - if (vbat<=0) + int16_t vbat = adc_vbat_read(); + if (vbat <= 0) return; uint8_t string_buf[16]; // Set battery color diff --git a/ui.c b/ui.c index 93cc96d..a3ac007 100644 --- a/ui.c +++ b/ui.c @@ -212,7 +212,7 @@ touch_measure_y(void) palSetPad(GPIOA, 6); chThdSleepMilliseconds(2); - v = adc_single_read(ADC1, ADC_CHSELR_CHSEL7); + v = adc_single_read(ADC_CHSELR_CHSEL7); //chThdSleepMilliseconds(2); //v += adc_single_read(ADC1, ADC_CHSELR_CHSEL7); return v; @@ -232,7 +232,7 @@ touch_measure_x(void) palClearPad(GPIOA, 7); chThdSleepMilliseconds(2); - v = adc_single_read(ADC1, ADC_CHSELR_CHSEL6); + v = adc_single_read(ADC_CHSELR_CHSEL6); //chThdSleepMilliseconds(2); //v += adc_single_read(ADC1, ADC_CHSELR_CHSEL6); return v; @@ -255,14 +255,14 @@ void touch_start_watchdog(void) { touch_prepare_sense(); - adc_start_analog_watchdogd(ADC1, ADC_CHSELR_CHSEL7); + adc_start_analog_watchdogd(ADC_CHSELR_CHSEL7); } static int touch_status(void) { touch_prepare_sense(); - return adc_single_read(ADC1, ADC_CHSELR_CHSEL7) > TOUCH_THRESHOLD; + return adc_single_read(ADC_CHSELR_CHSEL7) > TOUCH_THRESHOLD; } static int @@ -302,7 +302,7 @@ touch_cal_exec(void) { int x1, x2, y1, y2; - adc_stop(ADC1); + adc_stop(); setForegroundColor(DEFAULT_FG_COLOR); setBackgroundColor(DEFAULT_BG_COLOR); clearScreen(); @@ -338,7 +338,7 @@ touch_draw_test(void) int x0, y0; int x1, y1; - adc_stop(ADC1); + adc_stop(); setForegroundColor(DEFAULT_FG_COLOR); setBackgroundColor(DEFAULT_BG_COLOR); @@ -372,7 +372,7 @@ void show_version(void) { int x = 5, y = 5; - adc_stop(ADC1); + adc_stop(); setForegroundColor(DEFAULT_FG_COLOR); setBackgroundColor(DEFAULT_BG_COLOR); @@ -404,7 +404,7 @@ show_version(void) void enter_dfu(void) { - adc_stop(ADC1); + adc_stop(); int x = 5, y = 5; setForegroundColor(DEFAULT_FG_COLOR); @@ -2003,7 +2003,7 @@ static void ui_process_keypad(void) { int status; - adc_stop(ADC1); + adc_stop(); kp_index = 0; while (TRUE) { @@ -2145,7 +2145,7 @@ static void ui_process_touch(void) { // awd_count++; - adc_stop(ADC1); + adc_stop(); int status = touch_check(); if (status == EVT_TOUCH_PRESSED || status == EVT_TOUCH_DOWN) { From 45f04420cbacc1420deaecdd3cd300b85a1208d3 Mon Sep 17 00:00:00 2001 From: DiSlord Date: Sun, 8 Mar 2020 08:32:38 +0300 Subject: [PATCH 7/7] Implement info command, move info_about[] to main.c Command enabled by default: ENABLE_INFO_COMMAND This feature not increase flash size --- main.c | 32 ++++++++++++++++++++++++++++++-- nanovna.h | 1 + ui.c | 23 +++++++---------------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/main.c b/main.c index bb13344..2593545 100644 --- a/main.c +++ b/main.c @@ -58,6 +58,7 @@ static char shell_line[VNA_SHELL_MAX_LENGTH]; //#define ENABLE_THREADS_COMMAND //#define ENABLE_TIME_COMMAND #define ENABLE_VBAT_OFFSET_COMMAND +#define ENABLE_INFO_COMMAND static void apply_error_term_at(int i); static void apply_edelay_at(int i); @@ -82,6 +83,21 @@ static int8_t drive_strength = DRIVE_STRENGTH_AUTO; int8_t sweep_mode = SWEEP_ENABLE; volatile uint8_t redraw_request = 0; // contains REDRAW_XXX flags +// Version text, displayed in Config->Version menu, also send by info command +const char *info_about[]={ + BOARD_NAME, + "2016-2020 Copyright @edy555", + "Licensed under GPL. See: https://github.com/ttrftech/NanoVNA", + "Version: " VERSION, + "Build Time: " __DATE__ " - " __TIME__, + "Kernel: " CH_KERNEL_VERSION, + "Compiler: " PORT_COMPILER_NAME, + "Architecture: " PORT_ARCHITECTURE_NAME " Core Variant: " PORT_CORE_VARIANT_NAME, + "Port Info: " PORT_INFO, + "Platform: " PLATFORM_NAME, + 0 // sentinel +}; + static THD_WORKING_AREA(waThread1, 640); static THD_FUNCTION(Thread1, arg) { @@ -1949,6 +1965,17 @@ VNA_SHELL_FUNCTION(cmd_vbat_offset) } #endif +#ifdef ENABLE_INFO_COMMAND +VNA_SHELL_FUNCTION(cmd_info) +{ + (void)argc; + (void)argv; + int i=0; + while (info_about[i]) + shell_printf("%s\r\n", info_about[i++]); +} +#endif + #ifdef ENABLE_THREADS_COMMAND #if CH_CFG_USE_REGISTRY == FALSE #error "Threads Requite enabled CH_CFG_USE_REGISTRY in chconf.h" @@ -1970,8 +1997,6 @@ VNA_SHELL_FUNCTION(cmd_threads) { #else uint32_t stklimit = 0U; #endif - - shell_printf("%08x|%08x|%08x|%08x|%4u|%4u|%9s|%12s"VNA_SHELL_NEWLINE_STR, stklimit, (uint32_t)tp->ctx.sp, max_stack_use, (uint32_t)tp, (uint32_t)tp->refs - 1, (uint32_t)tp->prio, states[tp->state], @@ -2038,6 +2063,9 @@ static const VNAShellCommand commands[] = {"transform" , cmd_transform , 0}, {"threshold" , cmd_threshold , 0}, {"help" , cmd_help , 0}, +#ifdef ENABLE_INFO_COMMAND + {"info" , cmd_info , 0}, +#endif #ifdef ENABLE_THREADS_COMMAND {"threads" , cmd_threads , 0}, #endif diff --git a/nanovna.h b/nanovna.h index 58e4e4c..d5d14cc 100644 --- a/nanovna.h +++ b/nanovna.h @@ -89,6 +89,7 @@ void loadDefaultProps(void); #define SWEEP_ENABLE 0x01 #define SWEEP_ONCE 0x02 extern int8_t sweep_mode; +extern const char *info_about[]; /* * dsp.c diff --git a/ui.c b/ui.c index a3ac007..a2267da 100644 --- a/ui.c +++ b/ui.c @@ -367,30 +367,21 @@ touch_position(int *x, int *y) *y = (last_touch_y - config.touch_cal[1]) * 16 / config.touch_cal[3]; } - void show_version(void) { - int x = 5, y = 5; + int x = 5, y = 5, i = 0; adc_stop(); setForegroundColor(DEFAULT_FG_COLOR); setBackgroundColor(DEFAULT_BG_COLOR); clearScreen(); - ili9341_drawstring_size(BOARD_NAME, x, y, 4); - y += 25; - - ili9341_drawstring("2016-2020 Copyright @edy555", x, y += 10); - ili9341_drawstring("Licensed under GPL. See: https://github.com/ttrftech/NanoVNA", x, y += 10); - ili9341_drawstring("Version: " VERSION, x, y += 10); - ili9341_drawstring("Build Time: " __DATE__ " - " __TIME__, x, y += 10); - y += 5; - ili9341_drawstring("Kernel: " CH_KERNEL_VERSION, x, y += 10); - ili9341_drawstring("Compiler: " PORT_COMPILER_NAME, x, y += 10); - ili9341_drawstring("Architecture: " PORT_ARCHITECTURE_NAME " Core Variant: " PORT_CORE_VARIANT_NAME, x, y += 10); - ili9341_drawstring("Port Info: " PORT_INFO, x, y += 10); - ili9341_drawstring("Platform: " PLATFORM_NAME, x, y += 10); - + uint16_t shift = 0b0000010000111110; + ili9341_drawstring_size(info_about[i++], x , y, 4); + while (info_about[i]){ + do {shift>>=1; y+=5;} while (shift&1); + ili9341_drawstring(info_about[i++], x, y+=5); + } while (true) { if (touch_check() == EVT_TOUCH_PRESSED) break;